STM32F单片机实现ADC采集正弦波的FFT变换和逆变换

目标:C语言实现对ADC采集的带有杂波信号的正弦波进行FFT滤波,实现有效的数字滤波功能

方法:

  1. ADC通过DMA采集,将数据传入SourceBuf[N];

  2. 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;
}
相关推荐
国科安芯2 小时前
空间辐射环境下抗辐射 MCU 可靠性机理及航空安全应用研究综述
单片机·嵌入式硬件·macos·无人机·cocos2d·risc-v
雾削木2 小时前
STM32简介与选型
stm32·单片机·嵌入式硬件
m0_377108142 小时前
【无标题】
单片机·嵌入式硬件
szxinmai主板定制专家2 小时前
基于ZYNQ MPSOC多通道声音振动采集方案,替代NI9234和B&K
arm开发·人工智能·嵌入式硬件·fpga开发
zmj3203242 小时前
浮空、开漏、推挽、上拉 / 下拉--单片机 /芯片引脚模式
单片机·嵌入式硬件·芯片引脚
振南的单片机世界3 小时前
MSP与PSP:中断和任务各走各的“栈道”,互不干扰
stm32·单片机·嵌入式硬件
死了都要AI3 小时前
3、winform控件进阶
stm32·单片机·嵌入式硬件
木子单片机3 小时前
基于51单片机的数字钟设计 数码管显示
stm32·单片机·嵌入式硬件·51单片机·keil
国科安芯3 小时前
航空安全关键系统抗辐射 MCU 加固技术、工程实现与典型应用
单片机·嵌入式硬件·无人机·cocos2d·risc-v