DSP库 - RFFT - 奇怪的结果

时间:2017-02-17 14:08:09

标签: c arm fft cortex-m

最近,我一直试图在我的STM32F4-Discovery评估板上进行FFT计算,然后将其发送到PC。我已经研究了我的问题 - 我认为我做错了制造商提供的FFT功能。

我正在使用CMSIS-DSP库。 目前我已经使用代码生成样本(如果工作正常,我将通过麦克风进行采样)。

我使用 arm_rfft_fast_f32 ,因为我的数据将来会浮动,但我在输出数组中获得的结果是疯狂的(我认为) - 我&# 39; m使频率低于0.

number_of_samples = 512; (l_probek in code)
dt = 1/freq/number_of_samples

这是我的代码

float32_t buffer_input[l_probek];
uint16_t i;
uint8_t mode;
float32_t dt;
float32_t freq;
bool DoFlag = false;
bool UBFlag = false;
uint32_t rozmiar = 4*l_probek;

union
{
    float32_t f[l_probek];
    uint8_t b[4*l_probek];
}data_out;


union
{
    float32_t f[l_probek];
    uint8_t b[4*l_probek];
}data_mag;

union
{
    float32_t f;
    uint8_t b[4];
}czest_rozdz;


/* Pointers ------------------------------------------------------------------*/
arm_rfft_fast_instance_f32 S;
arm_cfft_radix4_instance_f32 S_CFFT;
uint16_t output;
/* ---------------------------------------------------------------------------*/
int main(void)
{
    freq = 5000;
    dt = 0.000000390625;


    _GPIO();
    _LED();
    _NVIC();    
    _EXTI(0);

    arm_rfft_fast_init_f32(&S, l_probek);
    GPIO_SetBits(GPIOD, LED_Green);

    mode = 2;


    //----------------- Infinite loop
  while (1)
    {
        if(true)//(UBFlag == true)

                    for(i=0; i<l_probek; ++i)
                    {
                        buffer_input[i] = (float32_t) 15*sin(2*PI*freq*i*dt);
                    }

            //Obliczanie FFT
            arm_rfft_fast_f32(&S, buffer_input, data_out.f, 0);
            //Obliczanie modulow
            arm_cmplx_mag_f32(data_out.f, data_mag.f, l_probek);

            USART_putdata(USART1, data_out.b, data_mag.b, rozmiar);
            //USART_putdata(USART1, czest_rozdz.b, data_mag.b, rozmiar);
            GPIO_ToggleBits(GPIOD, LED_Orange);
            //mode++;
            //UBFlag = false;

        }

    }
}

2 个答案:

答案 0 :(得分:3)

  

我正在使用 arm_rfft_fast_f32 ,因为我的数据将来会浮动,但我在输出数组中获得的结果是疯狂的(我想) - 我得到了频率低于0.

arm_rfft_fast_f32函数不返回频率,而是返回使用Fast Fourier Transform (FFT)计算的复值系数。因此,这些系数是负的是完全合理的。更具体地说,幅度为15的单周期sin测试音调输入的预期系数为:

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]

请注意,如documentation中所示,前两个输出对应于纯实数系数X[0]X[N/2](在随后的调用中,您应特别注意这一特殊情况arm_cmplx_mag_f32;请参阅下面的最后一点。)

每个频率成分的频率由k*fs/N给出,其中N是样本数(在您的情况下为l_probek),fs = 1/dt是抽样率(在您的情况下为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
...

最后,由于前两个值的特殊打包,在计算N/2+1量级时需要小心:

// 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];

答案 1 :(得分:1)

作为上述答案的补充(很棒),一些进一步的澄清使我花了很多时间才弄清楚。

  • 频率段以目标频率为中心,因此例如在上面的示例中,X [0]表示-2500Hz至2500Hz,以零为中心,X [1]是2500Hz至7500Hz,以5000Hz为中心,依此类推在

  • 通常会通过查看相邻仓的能量来对仓内的频率进行插值(请参见https://dspguru.com/dsp/howtos/how-to-interpolate-fft-peak/),如果这样做,则需要确保幅度数组足够大bins + Nyquist,并且Nyquist上方的bin为0,但请注意,许多内插技术都需要复杂值(eq Quinn,Jacobson),因此请确保在找到幅度之前进行内插。

  • 上面的特殊情况代码之所以有效,是因为DC和Nyquist值没有复杂的组成部分,因此幅度只是实数部分

  • 但是,上面的代码中有一个错误-尽管DC和Nyquist分量的虚部始终为零,但实部仍可能为负,因此您需要取绝对值来获取幅度:

// Handle special cases
data_mag.f[0]          = fabs(data_out.f[0]);
data_mag.f[l_probek/2] = fabs(data_out.f[1]);