Ich habe ein digitales Gleitkomma-Signalverarbeitungssystem, das mit einer festen Abtastrate von Abtastungen pro Sekunde arbeitet und mit einem x86-64-Prozessor implementiert ist. Unter der Annahme, dass das DSP-System synchron zu allen wichtigen Punkten verriegelt ist, wie lässt sich ein digitaler Oszillator mit einer bestimmten Frequenz am besten implementieren ?f
Insbesondere möchte ich das Signal erzeugen: wobei für die .t = n / f s n
Eine Idee ist, einen Vektor zu verfolgen den wir in jedem Taktzyklus um einen Winkel drehen .Δ ϕ = 2 π f / f s
Als Matlab-Pseudocode-Implementierung (die eigentliche Implementierung befindet sich in 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)]
Dann drehen wir den Vektor bei jedem Taktzyklus ein wenig:
%% 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
Dadurch kann der Oszillator mit nur 4 Multiplikationen pro Zyklus berechnet werden. Ich würde mir jedoch Sorgen um Phasenfehler und Amplitudenstabilität machen. (In einfachen Tests war ich überrascht, dass die Amplitude nicht sofort starb oder explodierte - vielleicht sincos
garantiert der Befehl ?).
Was ist der richtige Weg, um dies zu tun?
sincos
mit einer Handvoll Multiplikationen? Gibt es mögliche Fallstricke, auf die Sie bei dermod
Operation achten müssen?Was Sie haben, ist ein sehr guter und effizienter Oszillator. Das potenzielle numerische Driftproblem kann tatsächlich gelöst werden. Ihre Zustandsvariable v besteht aus zwei Teilen, wobei einer im Wesentlichen der Realteil und der andere der Imaginärteil ist. Nennen wir dann r und ich. Wir wissen, dass r ^ 2 + i ^ 2 = 1. Im Laufe der Zeit kann dies auf und ab driften, dies kann jedoch leicht durch Multiplikation mit einem Verstärkungskorrekturfaktor wie diesem korrigiert werden:g=1r2+i2−−−−−−√
Offensichtlich ist dies sehr teuer, aber wir wissen, dass die Verstärkungskorrektur sehr nahe bei Eins liegt, und wir können dies mit einer einfachen Taylor-Erweiterung auf approximiereng=1r2+i2−−−−−−√≈12⋅(3−(r2+i2))
Darüber hinaus müssen wir dies nicht bei jeder einzelnen Probe tun, aber einmal alle 100 oder 1000 Proben ist mehr als genug, um diese stabil zu halten. Dies ist besonders nützlich, wenn Sie eine rahmenbasierte Verarbeitung durchführen. Einmal pro Frame zu aktualisieren ist in Ordnung. Hier ist eine kurze Beschreibung, mit der Matlab 10.000.000 Proben berechnet.
quelle
Sie können die Drift der instabilen Größe vermeiden, wenn Sie den Vektor v nicht rekursiv aktualisieren. Drehen Sie stattdessen den Prototypvektor v in die aktuelle Ausgabephase. Dies erfordert immer noch einige Triggerfunktionen, jedoch nur einmal pro Puffer.
Keine Magnitudendrift und willkürliche Frequenz
Pseudocode:
Sie können die Multiplikation, die Triggerfunktionen, die für cexp erforderlich sind, und den Restmodul über 2 pi beseitigen, wenn Sie eine quantisierte Frequenzumsetzung tolerieren können. zB fs / 1024 für einen 1024-Beispiel-Zeigerpuffer.
quelle