У меня есть система цифровой обработки сигналов с плавающей запятой, которая работает с фиксированной частотой дискретизации отсчетов в секунду, реализованная с использованием процессора x86-64. Предполагая, что система DSP синхронно связана с любыми вопросами, каков наилучший способ реализовать цифровой генератор на некоторой частоте ?f
В частности, я хочу сгенерировать сигнал: где для номера выборки .t = n / f s n
Одна идея состоит в том, чтобы отслеживать вектор который мы поворачиваем на угол на каждом тактовом цикле.Δ ϕ = 2 π f / f s
В качестве реализации псевдокода Matlab (реальная реализация находится в C):
%% Initialization code
f_s = 32768; % sample rate [Hz]
f = 19.875; % some constant frequency [Hz]
v = [1 0]; % initial condition
d_phi = 2*pi * f / f_s; % change in angle per clock cycle
% initialize the rotation matrix (only once):
R = [cos(d_phi), -sin(d_phi) ; ...
sin(d_phi), cos(d_phi)]
Затем в каждом такте мы немного вращаем вектор:
%% in-loop code
while (forever),
v = R*v; % rotate the vector by d_phi
y = v(1); % this is the sine wave we're generating
output(y);
end
Это позволяет вычислять генератор только с 4 умножениями за цикл. Тем не менее, я бы беспокоился о фазовой ошибке и стабильности амплитуды. (В простых тестах я был удивлен, что амплитуда не умерла или взорвалась немедленно - возможно, sincos
инструкция гарантирует ?).
Как правильно это сделать?
sincos
сравнивается с несколькими умножениями? Есть ли какие-либо возможные подводные камни, на которые стоит обратить внимание во времяmod
операции?То, что у вас есть, это очень хороший и эффективный генератор. Проблема потенциального численного дрейфа действительно может быть решена. Ваша переменная состояния v состоит из двух частей, одна из которых является реальной частью, а другая - мнимой частью. Давайте назовем тогда г и я. Мы знаем, что r ^ 2 + i ^ 2 = 1. Со временем это может сместиться вверх и вниз, однако это можно легко исправить путем умножения с использованием коэффициента коррекции усиления, напримерграмм= 1р2+ я2------√
Очевидно, что это очень дорого, однако мы знаем, что коррекция усиления очень близка к единице, и мы можем аппроксимировать это простым разложением Тейлора награмм= 1р2+ я2------√≈ 12⋅ ( 3 - ( р2+ я2) )
Более того, нам не нужно делать это на каждом отдельном образце, но один раз на каждые 100 или 1000 образцов более чем достаточно для поддержания стабильности. Это особенно полезно, если вы делаете обработку на основе кадров. Обновление один раз за кадр просто отлично. Вот быстрый Matlab рассчитывает 10 000 000 образцов.
источник
Вы можете избежать нестабильного смещения величины, если не заставите его рекурсивно обновлять вектор v. Вместо этого поверните вектор-прототип v к текущей фазе вывода. Это все еще требует некоторых функций триггера, но только один раз для каждого буфера.
Нет дрейфа величины и произвольной частоты
псевдокод:
Вы можете избавиться от умножения, функций триггера, требуемых для cexp, и от остатка модуля более 2pi, если вы можете допустить квантованное преобразование частоты. например, fs / 1024 для векторного буфера 1024 образца.
источник