1

我尝试使用 CMSIS DSP 库在 STM32F407 上实现 FFT。我的项目基于Tilen MaJerle 库。我使用板载 ADC 对数据进行采样,并使用函数 TM_FFT_AddToBuffer(TM_FFT_F32_t* FFT, float32_t sampleValue) 填充输入缓冲区。此后,我使用函数 TM_FFT_Process_F32(TM_FFT_F32_t* FFT) 处理数据。

uint8_t TM_FFT_AddToBuffer(TM_FFT_F32_t* FFT, float32_t sampleValue) {
/* Check if memory available */
if (FFT->Count < FFT->FFT_Size) {
    /* Add to buffer, real part */
    FFT->Input[2 * FFT->Count] = sampleValue;
    /* Imaginary part set to 0 */
    FFT->Input[2 * FFT->Count + 1] = 0;

    /* Increase count */
    FFT->Count++;
}

/* Check if buffer full */
if (FFT->Count >= FFT->FFT_Size) {
    /* Buffer full, samples ready to be calculated */
    return 1;
}

/* Buffer not full yet */
return 0;
}

void TM_FFT_Process_F32(TM_FFT_F32_t* FFT) {
uint16_t iCntr = 0;
float coeff = 2.0*0.7071067812/(float)(FFT->FFT_Size);

/* Process FFT input data */
arm_cfft_f32(FFT->S, FFT->Input, 0, 1);

/* Process the data through the Complex Magniture Module for calculating the magnitude at each bin */
arm_cmplx_mag_f32(FFT->Input, FFT->Output, FFT->FFT_Size);  

for (iCntr = 1; iCntr < (FFT->FFT_Size); iCntr++) 
    FFT->Output[iCntr] *= coeff; //high-order harmonics values - magnitude

FFT->Output[0] /= (float)FFT->FFT_Size; //dc component value 

/* Reset count */   
FFT->Count = 0;
}

我在 TM_FFT_Process_F32(...) 函数中添加了一些简单的转换,旨在调整谐波电平。当然,当我排除它们并使用原始 Tilen 代码时,我会得到相同的结果。

如您所见,我尝试了 arm_cfft_f32(...) 和 arm_cmplx_mag_f32(...) 函数。为了我的目的,我还尝试了 arm_rfft_fast_f32(...) 函数并得到了相同的结果。

我的问题是幅度计算的准确性。我的任务期望获得预定谐波的准确电平计算。我用电压表在 ADC 输入上测量带有直流偏移的清晰正弦交流信号。然后我用 FFT lib 测量信号频率,并随着频率的增加得到信号电平的下降。我考虑到对给定采样率的最大测量频率的限制,事实上,CMSIS DSP FFT 不能使用超过 4096 个样本。我还需要小频率步长,例如 1 Hz 用于 100 到 1000 Hz 之间的范围。

在给定的图片中,我向您展示了结果。顺便说一句,频率测量有一些误差。100 Hz 定义为 101Hz,800 Hz – 定义为 808Hz。但这并没有让我很困惑。

蓝线用交流电压表测量。红线是我使用 FFT 库进行的测量。采样率 4096 Hz,样本数 – 4096

对于其他频率范围和采样率,也获得了相同的画面。

现在我看到唯一的正面决定是在数学上将我的结果调整为实际测量值。但这不是一个优雅的解决方案。我很可能忽略了 DSP FFT 分析的一些重要特性,并且缺乏对数学算法的理解。其他 FFT 实现对我来说不是很清楚。使用其他库真的有意义吗,例如,kissFFT 等等?谁有其他库的经验并愿意与我分享?任何建议都受到高度赞赏。

4

1 回答 1

3

非常感谢你的回答。但最后我自己解决了我的问题。我花了大约半年的时间坐下来在这里写下解决方案。

就我自己而言,这是对 FFT 工作原理的疏忽误解。有一个特征在于,给定信号的能量分布在给定频率和一些附近频率之间。因此,如果我们从DSP库傅里叶计算的结果中获取给定频率下的信号幅度,当然,我们会得到在给定采样率下随着工作频率的增加而增加的信号损耗。但是,如果我们取给定频率和一些附近频率的幅度的均方根值,我们将不会有信号损失。

我在实践中研究了 DSP 精度能力——针对不同的采样率和 30 Hz 到 32 kHz 之间的频率范围。有一个可计算的频率色散,我们应该将我们的信号幅度计算为色散内频率幅度的均方根值。并且存在可计算的频率定义误差。采样率越高,信号频率的计算值越远。通过计算的信号频率,我们指的是我们看到幅度最大值的频率(当观察到清晰的正弦信号时)。但是频移是可以预测的,不会造成任何问题。更重要的特性是信号扩展。如果我们将其考虑在内并更彻底地计算信号幅度,它将给我们带来出色的结果。我的是,现在我的计算与以 dBm 为单位的电压表 GVT 测量值非常吻合。对于频率 (30Hz…32kHz),差异在 -40 … +22 dBm 范围内不超过 2%。

这里有一些通过电压电平为 0.2Vrms 的宽频率范围进行幅度计算的结果。蓝线用交流电压表测量。红线是我使用 FFT 库进行的测量。样本数 – 4096 和采样率因特殊频率子范围而异。F=(30…1024)Hz 为 4096 Hz,F=(1024…4096)Hz 为 20480 Hz,F=(4096…8192)Hz 为 40960 Hz,F=(8192…32000)Hz 为 81920 Hz。如您所见,结果非常令人满意。

Vrms 与频率

我相信对于最擅长傅里叶变换数学基础的人来说,我的情况是一项非常简单的任务。但也许我没有一次掌握基础知识,过多地考虑了 DSP 库的计算能力,所以我在所描述的问题上浪费了一些时间和精力。但现在一切正常,我对 DSP FFT 实现深感满意

于 2020-04-21T19:32:49.810 回答