适合单片机和嵌入式系统的 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 格式不对
相关推荐
芯片设计-曾工7 小时前
当精准脉冲遇上清晰视界——CH2205E模块与YL1621的“黄金搭档“
驱动开发·stm32·单片机·51单片机·硬件工程
命运之光10 小时前
【C语言完整代码】就诊信息管理系统
java·c语言·开发语言
命运之光10 小时前
【C语言完整代码】图书管理系统:图书馆场景下的增删改查实战
c语言·开发语言
沫璃染墨12 小时前
《从零入门Linux系统篇(十五):系统工具篇·六——GDB调试器详解:从程序执行控制到高级调试技巧》
linux·运维·服务器·c语言·c++
LCG元12 小时前
STM32 硬件 SPI + DMA 驱动 OLED 显示屏(SSD1306):从原理到 112fps 高速刷新全流程
stm32·单片机·嵌入式硬件
天吾cc13 小时前
RTT-ADC
单片机·嵌入式硬件·学习
qq_4480111613 小时前
C语言中的野指针和空指针
c语言·开发语言·单片机
崇山峻岭之间14 小时前
STM32F407的FOC驱动01
stm32·单片机·嵌入式硬件
en.en..15 小时前
C 语言嵌入式事件驱动状态机完整教程(枚举配套)
c语言·开发语言
Yyyyyy~16 小时前
[C语言]break和continue作业
c语言·开发语言