目标:C语言实现对ADC采集的带有杂波信号的正弦波进行FFT滤波,实现有效的数字滤波功能
方法:
-
ADC通过DMA采集,将数据传入SourceBuf[N];
-
FFT变换:直接调用void ProcessADCData(unsigned short *SourceBuf, float *DestBuf) ,将逆变换的结果传入DestBuf[N]
实测可用,以下为代码:
cpp
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "platform_config.h"
#define PI 3.141592653589793f
#define N 256 // 采样点数
#define V_REF 3.3
#define V_AMP 7.5
extern unsigned short ADC_ConvertedBuffer[];
extern char GlgStr[];
extern void DbgTextOutput(char *ShowMsg);
extern void DbgInfoOutput(unsigned short sts, char *Title, unsigned char IsText, unsigned char *lpInfo, unsigned short InfoLen);
unsigned short SourceBuf[N];
float DestBuf[N];
typedef struct {
float real;
float imag;
} Complex;
// 优化版位反转函数
void bit_reverse(Complex *x, int n) {
unsigned int target = 0;
for (unsigned int source = 0; source < n; source++) {
// 计算目标索引 (位反转)
if (source < target) {
// 交换源和目标位置
Complex temp = x[source];
x[source] = x[target];
x[target] = temp;
}
// 计算下一个目标索引 (位反转算法)
unsigned int mask = n >> 1;
while (target & mask) {
target &= ~mask;
mask >>= 1;
}
target |= mask;
}
}
// FFT函数修改为接受长度参数
void fft(Complex *x, int n) {
bit_reverse(x, n); // 传递长度n
for (int stage = 2; stage <= n; stage <<= 1) {
int half = stage >> 1;
float angle = -2 * PI / stage;
Complex w = {cosf(angle), sinf(angle)};
for (int k = 0; k < n; k += stage) {
Complex v = {1.0f, 0.0f};
for (int j = 0; j < half; j++) {
Complex a = x[k + j];
Complex b = x[k + j + half];
// 优化复数乘法
float b_real = b.real * v.real - b.imag * v.imag;
float b_imag = b.real * v.imag + b.imag * v.real;
x[k + j].real = a.real + b_real;
x[k + j].imag = a.imag + b_imag;
x[k + j + half].real = a.real - b_real;
x[k + j + half].imag = a.imag - b_imag;
// 更新旋转因子
float v_real = v.real * w.real - v.imag * w.imag;
v.imag = v.real * w.imag + v.imag * w.real;
v.real = v_real;
}
}
}
}
// IFFT逆变换函数,增加参数n
void ifft(Complex *x, int n) {
// 取共轭
for (int i = 0; i < n; i++) {
x[i].imag = -x[i].imag;
}
// FFT变换
fft(x, n);
// 再次取共轭并归一化
for (int i = 0; i < n; i++) {
x[i].real = x[i].real / n;
x[i].imag = -x[i].imag / n;
}
}
// 主处理函数
void ProcessADCData(unsigned short *SourceBuf, float *DestBuf) {
// 使用静态存储,避免栈溢出
static Complex fft_buf[N];
float sum = 0.0f;
// 1. 去直流分量 (时域去均值)
for (int i = 0; i < N; i++) {
sum += SourceBuf[i];
}
float mean = sum / N;
// 2. 转换到复数域并去直流
for (int i = 0; i < N; i++) {
fft_buf[i].real = (float)SourceBuf[i] - mean;
fft_buf[i].imag = 0.0f;
}
// 3. 执行FFT (传递N)
fft(fft_buf, N);
// 4. 频域滤波 (仅保留90Hz分量)
int target_bin = 1; // 90Hz对应bin=1 (23040Hz采样率/256点)
for (int i = 0; i < N; i++) {
if (i != target_bin && i != (N - target_bin)) {
fft_buf[i].real = 0.0f;
fft_buf[i].imag = 0.0f;
}
}
// 5. 执行IFFT (传递N)
ifft(fft_buf, N);
// 6. 存储实部结果
for (int i = 0; i < N; i++) {
DestBuf[i] = fft_buf[i].real;
}
}
float calculate_rms(float *buffer, int len) {
double sum_sq = 0.0;
for (int i = 0; i < len; i++) {
sum_sq += (double)buffer[i] * (double)buffer[i];
}
return (float)sqrt(sum_sq / len);
}
float calculate_vpp(float *buffer, int len) {
float min = 4096;
float max = -4096;
for (int i = 0; i < len; i++) {
if(min>buffer[i]) min = buffer[i];
if(max<buffer[i]) max = buffer[i];
}
return (max-min);
}
int fft2_main() {
int i;
float v_rms;
float v_vpp;
float v_input;
for(i=0; i<N; i++) {
SourceBuf[i] = ADC_ConvertedBuffer[i];
}
sprintf(GlgStr,"FFT_IN:\r\n");
for(i=0;i<256;i++){
sprintf(&GlgStr[strlen(GlgStr)], "%d,",SourceBuf[i]);
}
sprintf(&GlgStr[strlen(GlgStr)], "\r\nend\r\n");
DbgInfoOutput(FftDbgInfo+1, "fft input", 1, (unsigned char*)GlgStr, strlen(GlgStr));
//
ProcessADCData(SourceBuf, DestBuf);
sprintf(GlgStr,"FFT_OUT:\r\n");
for(i=0;i<256;i++){
sprintf(&GlgStr[strlen(GlgStr)], "%0.1f,",DestBuf[i]);
}
sprintf(&GlgStr[strlen(GlgStr)], "\r\nend\r\n");
DbgInfoOutput(FftDbgInfo+1, "fft output", 1, (unsigned char*)GlgStr, strlen(GlgStr));
v_rms = calculate_rms(DestBuf, N);
v_rms = (v_rms/4095)*V_REF;
v_vpp = calculate_vpp(DestBuf, N);
v_vpp = (v_vpp/4095)*V_REF;
v_input = v_vpp*V_AMP;
sprintf(GlgStr,"ADC,rms=%0.5f, vpp=%0.5f, vin=%0.5f\r\n", v_rms,v_vpp, v_input);
DbgTextOutput(GlgStr);
return -1;
}