J'ai un système de traitement du signal numérique à virgule flottante qui fonctionne à un taux d'échantillonnage fixe de échantillons par seconde implémenté à l'aide d'un processeur x86-64. En supposant que le système DSP est verrouillé de manière synchrone sur tout ce qui compte, quelle est la meilleure façon de mettre en œuvre un oscillateur numérique à une fréquence ?
Plus précisément, je veux générer le signal:
Une idée est de garder une trace d'un vecteur que nous faisons tourner d'un angle à chaque cycle d'horloge.
En tant qu'implémentation de pseudocode Matlab (l'implémentation réelle est en 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)]
Ensuite, à chaque cycle d'horloge, nous faisons tourner un peu le vecteur:
%% 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
Cela permet à l'oscillateur d'être calculé avec seulement 4 multiplications par cycle. Cependant, je m'inquiéterais de l'erreur de phase et de la stabilité de l'amplitude. (Dans des tests simples, j'ai été surpris que l'amplitude ne meure pas ou n'explose pas immédiatement - peut-être que l' sincos
instruction garantit ?).
Quel est le bon moyen de le faire?
sincos
compare-t-il à une poignée de multiplications? Y a-t-il des pièges possibles à surveiller lors de l'mod
opération?Ce que vous avez est un oscillateur très bon et efficace. Le problème potentiel de dérive numérique peut en fait être résolu. Votre variable d'état v comporte deux parties, l'une est essentiellement la partie réelle et l'autre la partie imaginaire. Appelons alors r et i. Nous savons que r ^ 2 + i ^ 2 = 1. Au fil du temps, cela peut dériver de haut en bas, mais cela peut facilement être corrigé par multiplication avec un facteur de correction de gain comme celui-cig=1r2+i2−−−−−−√
Évidemment, cela coûte très cher, mais nous savons que la correction de gain est très proche de l'unité et nous pouvons l'approcher avec une simple expansion de Taylor àg=1r2+i2−−−−−−√≈12⋅(3−(r2+i2))
De plus, nous n'avons pas besoin de le faire sur chaque échantillon, mais une fois tous les 100 ou 1000 échantillons est plus que suffisant pour maintenir cette stabilité. Ceci est particulièrement utile si vous effectuez un traitement basé sur les trames. La mise à jour une fois par image est très bien. Voici un rapide Matlab calcule 10 000 000 d'échantillons.
la source
Vous pouvez éviter la dérive d'amplitude instable si vous ne le faites pas mettre à jour récursivement le vecteur v. Au lieu de cela, faites pivoter votre vecteur prototype v vers la phase de sortie actuelle. Cela nécessite toujours certaines fonctions trigonométriques, mais une seule fois par tampon.
Aucune dérive d'amplitude et fréquence arbitraire
pseudocode:
Vous pouvez supprimer la multiplication, les fonctions trigonométriques requises par cexp et le module restant sur 2pi si vous pouvez tolérer une translation de fréquence quantifiée. par exemple, fs / 1024 pour un tampon de phaseur de 1024 échantillons.
la source