DSP libraries - RFFT - strange results

放肆的年华 提交于 2019-12-06 08:26:03

I'm using arm_rfft_fast_f32 as my data are going to be floats in the future, but results I get in my output array are insane (I think) - I'm getting frequencies below 0.

The arm_rfft_fast_f32 function does not return frequencies, but rather complex-valued coefficients computed using the Fast Fourier Transform (FFT). It is thus perfectly reasonable for those coefficients to be negative. More specifically, the expected coefficients for your single-cycle sin test tone input with an amplitude of 15 would be:

0.0,     0.0; // special case packing real-valued X[0] and X[N/2]
0.0, -3840.0; // X[1]
0.0,     0.0; // X[2]
0.0,     0.0; // X[3]
...
0.0,     0.0; // X[255]

Note that as indicated in the documentation the first two outputs correspond to the purely real coefficients X[0] and X[N/2] (you should be particularly careful about this special case in your subsequent call to arm_cmplx_mag_f32; see last point below).

The frequency of each of those frequency components are given by k*fs/N, where N is the number of samples (in your case l_probek) and fs = 1/dt is the sampling rate (in your case freq*l_probek):

X[0] -> 0*freq*l_probek/l_probek =              0
X[1] -> 1*freq*l_probek/l_probek =   freq =  5000
X[2] -> 2*freq*l_probek/l_probek = 2*freq = 10000
X[3] -> 3*freq*l_probek/l_probek = 2*freq = 15000
...

Finally, due to the special packing of the first two values, you need to be careful when computing the N/2+1 magnitudes:

// General case for the magnitudes
arm_cmplx_mag_f32(data_out.f+2, data_mag.f+1, l_probek/2 - 1);
// Handle special cases
data_mag.f[0]          = data_out.f[0];
data_mag.f[l_probek/2] = data_out.f[1];

As a follow-up to the above answer, which is awesome, some further clarifications which took me an age to figure out.

  • The frequency bins are centered on the target frequency, so for instance in the example above X[0] represents -2500Hz to 2500Hz, centered on zero, X[1] is 2500Hz to 7500Hz centered on 5000Hz and so on

  • It's common to interpolate frequencies within the bin by looking at the energy of the adjacent bins (see https://dspguru.com/dsp/howtos/how-to-interpolate-fft-peak/) if you do this you will need to make sure that your magnitude array is large enough for the bins + Nyquist and that the bin above Nyquist is 0, but note many interpolation techniques require the complex values (e.q. Quinn, Jacobson) so make sure you interpolate before finding the magnitudes.

  • The special case code above works because there is no complex component of the DC and Nyquist values and thus the magnitude is simply the real part

  • There is a bug in the code above however - although the imaginary parts of the DC and Nyquist components is always zero, the real part could still be negative, so you need to take the absolute value to get the magnitude:

// Handle special cases
data_mag.f[0]          = fabs(data_out.f[0]);
data_mag.f[l_probek/2] = fabs(data_out.f[1]);
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!