适合单片机和嵌入式系统的 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 格式不对
相关推荐
三佛科技-134163842122 小时前
LP2601可以用PL3380替代吗?PL3380与LP2601对比分析 (参数、管脚、典型应用电路)
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
luj_17682 小时前
马克思的跨学科学术体系
c语言·开发语言·c++·经验分享·算法
聚能芯半导体LOLO2 小时前
【HTR3218S I2C 呼吸灯驱动替代 SN3218/IS31FL3218 聚能芯禾润代理】
单片机·嵌入式硬件
Kent Gu2 小时前
MCU & FPGA调试
单片机·嵌入式硬件·fpga开发
F137298015573 小时前
WD5081,85V转5V,1A异步降压芯片
stm32·单片机·嵌入式硬件·51单片机
傻童:CPU3 小时前
如何快速阅读芯片数据手册
单片机·嵌入式硬件
iCxhust3 小时前
如何查看一个51单片机的库文件内容
单片机·嵌入式硬件·51单片机
Byte Wizard4 小时前
C语言文件操作
c语言·开发语言