我尝试使用 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 等等?谁有其他库的经验并愿意与我分享?任何建议都受到高度赞赏。