FFT

    快速傅里叶变换就是通过计算机运行离散傅里叶变换,将时域信号通过频域展示出来,什么是时域,对连续的信号进行采集,以时间为基础的幅值变化,我们可以使用FFT将时域信号转换为频域信号,在音频处理中最常使用:每段时间内的信号都可以看做成是不同频率不同赋值的正弦信号叠加而来,我们是用的音频灯就是一个很典型的例子,可以实时显示音频的频率与幅值信息。

    如何使用:在STM32上,官方已经给出了FFT库,我们拿过来使用就可以,但是最近的STM32价格已经不推荐个人DIY使用,相比于现在的国产芯片,ESP32更适合与个人DIY玩家,双核240Mhz,性价比极高。

    在使用FFT时,我们有几个需要注意的数值:
1、采样频率,通常来说,人耳能听到的得最高频率为20Khz,采样频率通常设置为音频信号的二倍,也就是40KHz,
2、采样点数,我们将采样点数设置为N,N通常为2的整数次方,便于计算处理,N个采样点数得到N个FFT结果。

    通过公式可以知道,采样点数越多,结果得到的分辨率越高,f=采样频率、采样点数;但是与此带来的是计算量的增长,经过实测512个点在ESP32超频240MHz下,单次计算需要消耗8MS,1024个点就需要24MS了,我们可以根据自己的需求去设定点数,还有一个需要注意的是,得到的FFT结果是具有对称性的,所以只用取得前N/2个结果进行显示即可。

    实践:采用ESP32-Arduino开发环境,ADC采集使用I2S进行采集,频率设置40KHz,DMA进行采集,FFT库使用arduinoFFT.h,使用512个点,输出时舍弃后一半,我只用显示32个点,所以我们可以每隔8个点取最大值,显示方面我使用屏幕进行显示,一个点10个像素刚好占满Y轴。

    测试方法:我们在没有显示设备可是有需要对其进行测试时,可以自己模拟ADC采集函数对数据进行填充,例如:

    for(int i=0; i<ADC_SAMPLE_COUNT; i++)
{
    double f1 = 50;                     //0Hz,幅值50
    double f2 = fn(2048,5*1024,0,i);        //10KHz,幅值1024,相位0度
    double f3 = fn(4096,10*1024,0,i);        //20KHz,幅值4096,相位0度

    vReal[i] = f1 + f2 + f3;    
    vImag[i] = 0;    
}

    然后可以尝试将所有处理后的数据打印出来,经过测试,打印出来的结果符合目标预期,在对应频率上具有对应的相位。
后期对实物进行补充。