Один из лучших способов создать синусоидальную волну - использовать сложный вектор с рекурсивным обновлением. Т.е.
z[n+1]=z[n]Ω
где z [n] - вектор, , где - угловая частота осциллятора в радианах, а - индекс выборки. И действительная, и мнимая части являются синусоидальными, они сдвинуты по фазе на 90 градусов. Очень удобно, если вам нужны как синус, так и косинус. Для расчета одной выборки требуется только 4 умножения и 4 сложения, и оно НАМНОГО дешевле, чем что-либо, содержащее sin () cos () или справочные таблицы. Потенциальная проблема заключается в том, что амплитуда может дрейфовать со временем из-за проблем с числовой точностью. Однако есть довольно простой способ исправить это. Допустим, что . Мы знаем, что должен иметь единичную величину, т.е. Ω=exp(jω)ωnz[n]z[n]=a+jbz[n]
a⋅a+b⋅b=1
Таким образом, мы можем проверять время от времени, если это все еще так и исправить соответственно. Точная коррекция будет
z′[n]=z[n]a⋅a+b⋅b−−−−−−−−−√
Это неуклюжий расчет, но так как очень близок к единице, вы можете аппроксимировать с помощью разложения Тейлора около и мы получаемa⋅a+b⋅b1/x−−√x=1
1x−−√≅3−x2
поэтому коррекция упрощается до
z′[n]=z[n]3−a2−b22
Применяя эту простую коррекцию каждые несколько сотен сэмплов, генератор будет стабильно работать вечно.
Для непрерывного изменения частоты множитель W необходимо соответствующим образом обновить. Даже непостоянное изменение множителя будет поддерживать функцию непрерывного генератора. Если требуется линейное изменение частоты, обновление может быть разбито на несколько шагов, или вы можете использовать тот же алгоритм осциллятора для обновления самого множителя (так как это также комплексный вектор с единичным усилением).