适合单片机和嵌入式系统的 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 格式不对
相关推荐
葫芦和十三10 小时前
图解 MongoDB 15|journal 与持久化:写入怎么不丢,崩溃怎么恢复
后端·mongodb·面试
葫芦和十三10 小时前
图解 MongoDB 16|压缩:snappy、zstd 和 zlib 的取舍
后端·mongodb·面试
葫芦和十三1 天前
图解 MongoDB 13|WiredTiger 存储引擎:B-tree、页和 checkpoint 三件套
后端·mongodb·agent
葫芦和十三1 天前
图解 MongoDB 14|Cache 与淘汰:WiredTiger 的内存治理
后端·mongodb·面试
葫芦和十三3 天前
图解 MongoDB 12|索引与查询优化地图:一条主线,三个判断轴
后端·mongodb·agent
葫芦和十三3 天前
图解 MongoDB 11|慢查询排查闭环:从 Profile 到 explain 的分层路径
后端·mongodb·agent
葫芦和十三3 天前
图解 MongoDB 09|explain 再读:从 queryPlanner 到 executionStats
后端·mongodb·agent
葫芦和十三3 天前
图解 MongoDB 10|覆盖查询:让索引把活干完,根本不用回表
后端·mongodb·agent
葫芦和十三5 天前
图解 MongoDB 08|ESR 原则:复合索引的字段顺序怎么定
后端·mongodb·agent
葫芦和十三5 天前
图解 MongoDB 07|索引类型:七种索引,七种访问形状
后端·mongodb·agent