Mam zmiennoprzecinkowy system cyfrowego przetwarzania sygnałów, który działa ze stałą częstotliwością próbkowania próbek na sekundę, zaimplementowany przy użyciu procesora x86-64. Zakładając, że system DSP jest synchronicznie zablokowany na czymkolwiek, co jest najlepszym sposobem na wdrożenie oscylatora cyfrowego przy jakiejś częstotliwości ?f
W szczególności chcę wygenerować sygnał: gdzie dla próbki o numerze .t = n / f s n
Jednym z pomysłów jest śledzenie wektora który obracamy o kąt w każdym cyklu zegara.Δ ϕ = 2 π f / f s
Jako implementacja pseudokodu Matlab (rzeczywista implementacja znajduje się w 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)]
Następnie, w każdym cyklu zegara, obracamy nieco wektor wokół:
%% 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
Pozwala to na obliczenie oscylatora tylko przy 4 multiplikacjach na cykl. Martwię się jednak o błąd fazy i stabilność amplitudy. (W prostych testach zdziwiłem się, że amplituda nie umarła ani nie wybuchła natychmiast - być może sincos
instrukcja gwarantuje ?).
Jak to zrobić?
sincos
różni się od garstki mnożeń? Czy są jakieś pułapki, na które należy uważać podczasmod
operacji?To, co masz, to bardzo dobry i wydajny oscylator. Potencjalny problem dryfu numerycznego można faktycznie rozwiązać. Twoja zmienna stanu v składa się z dwóch części, z których jedna jest częścią rzeczywistą, a druga częścią urojoną. Zadzwońmy wtedy ri ja. Wiemy, że r ^ 2 + i ^ 2 = 1. Z czasem może to dryfować w górę i w dół, jednak można to łatwo skorygować przez pomnożenie przez współczynnik korekcji wzmocnienia taki jakg=1r2+i2−−−−−−√
Oczywiście jest to bardzo kosztowne, jednak wiemy, że korekcja wzmocnienia jest bardzo bliska jedności i możemy to przybliżyć za pomocą zwykłego rozszerzenia Taylora dog=1r2+i2−−−−−−√≈12⋅(3−(r2+i2))
Co więcej, nie musimy tego robić na każdej pojedynczej próbce, ale raz na każde 100 lub 1000 próbek wystarczy, aby utrzymać tę stabilność. Jest to szczególnie przydatne, jeśli wykonujesz przetwarzanie oparte na ramkach. Aktualizacja raz na klatkę jest w porządku. Oto szybki Matlab oblicza 10 000 000 próbek.
źródło
Możesz uniknąć niestabilnego dryfu wielkości, jeśli nie sprawisz, że rekursywnie zaktualizujesz wektor v. Zamiast tego obróć prototypowy wektor v do bieżącej fazy wyjściowej. Nadal wymaga to niektórych funkcji wyzwalania, ale tylko raz na bufor.
Brak dryfu wielkości i arbitralnej częstotliwości
pseudo kod:
Możesz zrezygnować z mnożenia, funkcji wyzwalania wymaganych przez cexp, a moduł pozostanie powyżej 2pi, jeśli możesz tolerować kwantowane tłumaczenie częstotliwości. np. fs / 1024 dla 1024 próbnego bufora fazorów.
źródło