适合单片机和嵌入式系统的 C 语言 FIR 滤波器实现

代码不依赖任何库,只用到标准 C,可直接用在 STM32 / 51 / DSP / PC 上。


一、FIR 滤波器原理

输出 = 输入 × 系数 的加权和

yn=∑k=0N−1hk⋅xn−kyn = \sum_{k=0}^{N-1} hk \cdot xn-kyn=∑k=0N−1hk⋅xn−k

  • h[k]:FIR 滤波器系数(固定)
  • x[n-k]:输入的历史数据
  • N:滤波器阶数 + 1

二、最常用结构:直接型(适合单片机 )

特点

结构简单

无递归(稳定)

易移植

阶数高时计算量大


三、C 语言实现

1、FIR 结构体定义

c 复制代码
#ifndef FIR_FILTER_H
#define FIR_FILTER_H

#include <stdint.h>

typedef struct
{
    const float *coeff;   // 滤波器系数
    float *buffer;        // 输入缓冲
    uint16_t order;       // 阶数
    uint16_t index;       // 环形缓冲索引
} FIR_Filter_t;

#endif

2、FIR 初始化

c 复制代码
#include "fir_filter.h"
#include <string.h>

void FIR_Init(FIR_Filter_t *fir,
              const float *coeff,
              float *buffer,
              uint16_t order)
{
    fir->coeff  = coeff;
    fir->buffer = buffer;
    fir->order  = order;
    fir->index  = 0;

    memset(buffer, 0, order * sizeof(float));
}

3、FIR 单点滤波(核心函数)

c 复制代码
float FIR_Process(FIR_Filter_t *fir, float input)
{
    uint16_t i;
    float output = 0.0f;

    // 存入新输入(环形缓冲)
    fir->buffer[fir->index] = input;

    // 卷积计算
    for (i = 0; i < fir->order; i++)
    {
        int buf_idx = (fir->index - i + fir->order) % fir->order;
        output += fir->coeff[i] * fir->buffer[buf_idx];
    }

    // 更新索引
    fir->index = (fir->index + 1) % fir->order;

    return output;
}

四、使用示例(低通 FIR)

1、定义滤波器系数(示例:16 阶低通)

c 复制代码
#define FIR_ORDER 16

// 示例系数(截止频率 ≈ 0.2 * Fs)
const float fir_coeff[FIR_ORDER] = {
     0.0044,  0.0168,  0.0378,  0.0635,
     0.0885,  0.1065,  0.1134,  0.1076,
     0.0900,  0.0635,  0.0323,  0.0010,
    -0.0266, -0.0467, -0.0569, -0.0561
};

float fir_buffer[FIR_ORDER];
FIR_Filter_t fir;

2、主循环中使用

c 复制代码
int main(void)
{
    float raw, filtered;

    FIR_Init(&fir, fir_coeff, fir_buffer, FIR_ORDER);

    while (1)
    {
        raw = read_adc();              // 读取采样数据
        filtered = FIR_Process(&fir, raw);
        output_dac(filtered);          // 输出滤波后数据
    }
}

五、整数版本(适合 STM32 / 51,无浮点)

1、Q15 定点 FIR

c 复制代码
typedef struct
{
    const int16_t *coeff;
    int16_t *buffer;
    uint16_t order;
    uint16_t index;
} FIR_Q15_t;

int16_t FIR_Q15_Process(FIR_Q15_t *fir, int16_t input)
{
    int32_t acc = 0;
    uint16_t i;

    fir->buffer[fir->index] = input;

    for (i = 0; i < fir->order; i++)
    {
        int buf_idx = (fir->index - i + fir->order) % fir->order;
        acc += (int32_t)fir->coeff[i] * fir->buffer[buf_idx];
    }

    fir->index = (fir->index + 1) % fir->order;

    return (int16_t)(acc >> 15);  // Q15 缩放
}

说明:

  • 系数用 Q15 格式(−32768 ~ 32767)
  • 适合 无 FPU 的 MCU

参考代码 用c语言实现的fir滤波器 www.youwenfan.com/contentcsv/103571.html

六、FIR 滤波器设计速查表

参数 建议值
阶数 16 / 32 / 64
窗函数 Hamming / Hanning
截止频率 0.1 ~ 0.4 × Fs
类型 低通 / 高通 / 带通

七、常见问题

问题 原因
输出失真 阶数太低
延迟大 FIR 本身线性相位
计算慢 阶数过高
整数溢出 Q 格式不对
相关推荐
学逆向的9 小时前
C 堆区内存管理
c语言·开发语言·网络安全
zhangrelay10 小时前
新版|-|单片机原理与接口技术-2026持续改进优化-从MEGA2560-ESP32与Wokwi到ROS2-Lyrical与具身智能栈
笔记·单片机·嵌入式硬件·学习
comyccccc10 小时前
STM32F103C8T6最小系统板设计全解析学习笔记
单片机·1024程序员节
en.en..11 小时前
STM32 GPIO ODR 与 BSRR 寄存器完整对比详解
单片机·嵌入式硬件
阿尼卡~12 小时前
VS Code 配置 C 语言开发环境(Windows 10/11):从 GCC 安装到运行、断点调试,一篇搞定
c语言·开发语言·windows
LCG米15 小时前
STM32硬件SPI驱动SSD1306 OLED实测:上电黑屏排查、页寻址模式与取模扫描方向陷阱
stm32·单片机·嵌入式硬件·嵌入式
深圳老胡16 小时前
STM32C5A3ZG 网络调试总结:从启动失败到连续 Ping 稳定
笔记·stm32·单片机·代码规范
简单电磁炮16 小时前
关于adc采集
stm32·单片机
意法半导体STM3217 小时前
【官方原创】如何在STM32CubeMX2中使用UART
stm32·单片机·嵌入式硬件
白搞电子19 小时前
ESP-Mosaico 轮滑动画编排台:拍点吸附、完整动作编辑与工程保存
单片机·嵌入式硬件·电脑