Tengo un sistema de procesamiento de señal digital de punto flotante que funciona a una frecuencia de muestreo fija de muestras por segundo implementado utilizando un procesador x86-64. Suponiendo que el sistema DSP está bloqueado sincrónicamente para lo que sea que importe, ¿cuál es la mejor manera de implementar un oscilador digital a alguna frecuencia ?
Específicamente, quiero generar la señal:
Una idea es hacer un seguimiento de un vector que rotamos en un ángulo en cada ciclo de reloj.
Como una implementación de pseudocódigo de Matlab (la implementación real 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)]
Luego, en cada ciclo de reloj, giramos el vector un poco:
%% 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
Esto permite que el oscilador se calcule con solo 4 multiplicaciones por ciclo. Sin embargo, me preocuparía el error de fase y la estabilidad de la amplitud. (En pruebas simples me sorprendió que la amplitud no muriera o explotara de inmediato, ¿tal vez la sincos
instrucción garantiza ?).
¿Cuál es la forma correcta de hacer esto?
sincos
compara el tiempo de ejecución de un puñado de multiplicaciones? ¿Hay posibles dificultades a tener en cuenta con lamod
operación?Obviously this is very expensive, however we know that the gain correction is very close to unity and we can approximate this with a simple Taylor expansion tog=1r2+i2−−−−−−√≈12⋅(3−(r2+i2))
Moreover we don't need to do this on every single sample, but once every 100 or 1000 samples is more than enough to keep this stable. This is particularly useful if you do frame based processing. Updating once per frame is just fine. Here is a quick Matlab calculates 10,000,000 samples.
fuente
You can avoid the unstable magnitude drift if you do not make it recursively update the vector v. Instead, rotate your prototype vector v to the current output phase. This still requires some trig functions, but only once per buffer.
No magnitude drift and arbitrary frequency
pseudocode:
You can do away with the multiply, the trig functions required by cexp, and the modulus remainder over 2pi if you can tolerate a quantized frequency translation. e.g. fs/1024 for a 1024 sample phasor buffer.
fuente