嵌入式C语言实现10种常用滤波算法:从原理到代码移植
简介这份资源面向嵌入式开发、单片机应用及信号采集方向的工程师与学生系统整理了10种常用软件滤波算法的C语言实现帮助解决传感器采样中随机干扰、周期性波动与脉冲噪声等实际问题。压缩包共3个文件包含1个C源码文件、1个Word说明文档和1个PDF研究资料整体约198KB体积轻巧便于随工程携带与查阅。内容覆盖限幅滤波、中位值滤波、算术平均、递推平均、中位值平均、限幅平均、一阶滞后、加权递推平均、消抖及限幅消抖等算法每种均给出方法原理、优缺点与适用参数取值如流量取N12、压力取N4等经验值可直接对照移植到实际项目中。目前已有3190人学习下载适合需要快速选型、对比滤波效果并落地C代码的开发者参考。1. 从一段“数据抖动”说起这套滤波算法C代码到底能干什么如果你做过单片机采集、传感器数据处理或者嵌入式信号调理大概率遇到过这种情况ADC采回来的数值像心电图一样上下乱跳明明传感器手册标称精度够用实际读出来就是不稳。很多人第一反应是加电容、改PCB布局硬件折腾一圈之后发现改善有限最后才意识到问题出在软件端——没有做数字滤波。这份“10种常用的滤波算法(C代码)”就是冲着这个场景来的它把嵌入式开发中最常用的十种滤波算法用C语言实现了一遍每个算法独立成文件接口清晰可以直接移植到STM32、GD32、ESP32或者任何带C编译器的平台上。适合谁刚入行的嵌入式软件工程师、做毕业设计需要处理传感器数据的学生、以及想给现有采集系统加一层软件滤波但不想从零推导公式的开发者。它不涉及复杂的自适应滤波理论也不依赖任何第三方库纯C实现拿到手改改宏定义就能用。2. 项目结构拆解十个算法文件怎么组织、怎么选2.1 目录布局与文件职责这份代码的组织方式很“嵌入式”——没有花哨的构建系统就是一组.c和.h文件平铺在src目录下外加一个main.c做演示。常见做法是每个算法一对文件比如filter_moving_average.c配filter_moving_average.h头文件里放函数声明和必要的宏源文件里放具体实现。这样做的目的是让使用者按需取用不需要把十个算法全编译进去。我一般会在项目里建一个filters文件夹把这十个文件丢进去然后在IDE里只添加实际用到的那几个。从功能维度看这十个算法大致可以分成三类第一类是时域平均类包括算术平均滤波、滑动平均滤波、加权平均滤波、中位值滤波第二类是动态响应类包括一阶滞后滤波、限幅滤波、限速滤波第三类是组合与统计类包括防脉冲干扰平均滤波、中位值平均滤波、以及一个简单的卡尔曼滤波实现。分类的意义在于选型采样慢、要求平滑的用平均类采样快、要求跟随的用滞后或限幅类有脉冲噪声的用中位值或防脉冲组合。2.2 统一接口设计为什么每个算法都长一个样这份代码最值得借鉴的地方是接口统一。每个滤波算法都暴露一个初始化函数和一个滤波函数命名遵循xxx_filter_init和xxx_filter_update的格式。初始化函数负责设置窗口大小、初始值等参数滤波函数接收一个新采样值返回滤波后的值。下面是一个典型的滑动平均滤波实现// filter_moving_average.h #ifndef FILTER_MOVING_AVERAGE_H #define FILTER_MOVING_AVERAGE_H #define MOVING_AVG_WINDOW_SIZE 10 typedef struct { float buffer[MOVING_AVG_WINDOW_SIZE]; float sum; unsigned char index; unsigned char count; } moving_avg_t; void moving_avg_init(moving_avg_t *filter); float moving_avg_update(moving_avg_t *filter, float new_value); #endif// filter_moving_average.c #include filter_moving_average.h void moving_avg_init(moving_avg_t *filter) { unsigned char i; for (i 0; i MOVING_AVG_WINDOW_SIZE; i) { filter-buffer[i] 0.0f; } filter-sum 0.0f; filter-index 0; filter-count 0; } float moving_avg_update(moving_avg_t *filter, float new_value) { // 减去最旧的值加上最新的值保持窗口内总和 filter-sum - filter-buffer[filter-index]; filter-buffer[filter-index] new_value; filter-sum new_value; filter-index; if (filter-index MOVING_AVG_WINDOW_SIZE) { filter-index 0; } // 窗口未填满时按实际数量平均避免初始阶段被零值拉低 if (filter-count MOVING_AVG_WINDOW_SIZE) { filter-count; } return filter-sum / (float)filter-count; }这段代码的逻辑说明buffer是一个环形缓冲区index指向下一个要覆盖的位置sum维护窗口内所有值的累加和。每次更新时先减去被覆盖的旧值再写入新值并累加这样避免了每次遍历窗口求和把时间复杂度从O(n)降到O(1)。count变量用来处理启动阶段窗口未填满的情况否则前几个采样值会被缓冲区里的初始零值稀释导致输出偏小。参数说明MOVING_AVG_WINDOW_SIZE决定平滑程度值越大输出越稳但滞后越明显一般取8到20之间float类型可以根据平台换成double或定点数。2.3 中位值与防脉冲对付尖峰干扰的两种思路中位值滤波的核心是排序后取中间值对偶发的脉冲干扰特别有效。这份代码里用了一个简单的冒泡排序窗口大小通常取5或7。防脉冲干扰平均滤波则是“先去掉一个最大值和一个最小值再对剩下的求平均”相当于中位值和平均值的折中。下面看中位值滤波的关键片段// filter_median.c 核心部分 float median_filter_update(median_filter_t *filter, float new_value) { float temp[MEDIAN_WINDOW_SIZE]; unsigned char i, j; float swap; // 滑动窗口搬移旧数据存入新值 for (i 0; i MEDIAN_WINDOW_SIZE - 1; i) { filter-buffer[i] filter-buffer[i 1]; } filter-buffer[MEDIAN_WINDOW_SIZE - 1] new_value; // 复制到临时数组进行排序不破坏原始缓冲区顺序 for (i 0; i MEDIAN_WINDOW_SIZE; i) { temp[i] filter-buffer[i]; } // 冒泡排序窗口小开销可接受 for (i 0; i MEDIAN_WINDOW_SIZE - 1; i) { for (j 0; j MEDIAN_WINDOW_SIZE - 1 - i; j) { if (temp[j] temp[j 1]) { swap temp[j]; temp[j] temp[j 1]; temp[j 1] swap; } } } // 取中间值窗口为偶数时取中间两个的平均 if (MEDIAN_WINDOW_SIZE % 2 1) { return temp[MEDIAN_WINDOW_SIZE / 2]; } else { return (temp[MEDIAN_WINDOW_SIZE / 2 - 1] temp[MEDIAN_WINDOW_SIZE / 2]) / 2.0f; } }逻辑说明每次更新时先把缓冲区整体左移腾出最后一个位置放新值这样缓冲区里始终保存最近N个采样。排序在临时数组上进行不影响缓冲区的时序。参数说明MEDIAN_WINDOW_SIZE建议取奇数5或7在多数场景下够用如果采样率很高而MCU主频较低冒泡排序可能成为瓶颈常见做法是改用插入排序或直接维护一个有序链表。注意中位值滤波对缓变信号会引入额外滞后不适合快速跟随的场景。3. 编译与运行从裸机到PC验证的完整步骤3.1 在PC上先跑通用gcc验证算法行为拿到一份嵌入式C代码我习惯先在PC上编译运行用打印的方式观察滤波效果确认算法逻辑没问题再往MCU上搬。这份代码的main.c里通常包含一个演示函数生成一段带噪声的正弦波或阶跃信号分别喂给各个滤波器打印原始值和滤波值。编译命令很简单# 在项目根目录下执行假设源文件在src目录 gcc -o filter_demo src/main.c src/filter_moving_average.c src/filter_median.c src/filter_limiter.c -lm ./filter_demo参数说明-lm是链接数学库如果代码里用了sinf、fabsf等函数就需要加如果只编译部分算法按实际用到的.c文件替换即可。运行后会看到类似raw: 1023.4, filtered: 1018.7的输出观察滤波后的曲线是否更平滑、滞后是否可接受。这一步能帮你快速排除数组越界、初始值未清零之类的低级错误。3.2 移植到MCU需要改哪些地方移植到STM32或其他MCU时主要改三个地方。第一把main.c里的演示代码替换成你的ADC读取和串口打印逻辑第二如果MCU不支持硬件浮点把float换成double或定点int32_t同时调整除法运算第三根据实际采样率调整窗口大小和滤波系数。以STM32 HAL库为例在ADC转换完成回调里调用滤波函数// 在ADC中断回调中调用 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { uint16_t raw HAL_ADC_GetValue(hadc); float filtered moving_avg_update(g_moving_avg, (float)raw); // 将filtered用于后续控制或显示 g_sensor_value filtered; }注意滤波函数本身不是线程安全的如果同时在中断和主循环里调用同一个滤波器实例需要加临界区保护或者用双缓冲。常见做法是只在中断里做原始值采集和滤波主循环读取滤波结果。3.3 参数整定窗口大小和滤波系数的经验值窗口大小和系数没有万能公式但有一些经验范围。滑动平均窗口取8到20对应截止频率约为采样率的1/10到1/20一阶滞后滤波的系数α取0.1到0.3α越小越平滑但响应越慢限幅滤波的阈值取传感器最大允许跳变量的1.5到2倍。我一般会先用一个可调参数跑一遍实际数据把原始值和滤波值同时打到串口用上位机画曲线对比调到自己满意为止。别指望一次调好这是个反复试的过程。4. 避坑与排查五个实际调试中踩过的坑4.1 现象滤波后数值一直偏小稳定后也不对原因滑动平均或算术平均在启动阶段缓冲区里全是初始零值前几个输出被零值拉低。如果初始化时没有把count置零或者没有做窗口未满时的特殊处理就会一直偏小。解决像2.2节代码那样用count变量记录实际有效样本数窗口未满时除以count而不是窗口大小。或者初始化时用第一个采样值填满整个缓冲区。4.2 现象中位值滤波输出偶尔跳变和原始值一样原因窗口大小取了偶数中间两个值相差较大时取平均反而引入了一个“人造”的中间值。解决把窗口大小改成奇数5或7最常用。如果必须用偶数窗口考虑取中间两个中更接近上一次输出的那个而不是简单平均。4.3 现象一阶滞后滤波在阶跃响应时爬升太慢控制环路振荡原因α取得太小滤波器的相位滞后超过了控制环路的相位裕度。解决先确定控制环路的带宽要求再反推α的下限。经验公式是α ≥ 2π × 控制带宽 / 采样率。如果还是不够快换用限幅滤波或卡尔曼滤波。4.4 现象移植到MCU后输出全是零或乱码原因结构体没有对齐或者栈空间不足导致局部数组溢出。解决检查结构体定义是否用了__attribute__((packed))导致非对齐访问把大数组从栈上移到全局或静态区确认编译器的浮点ABI设置和库文件匹配。4.5 现象多个滤波器串联后输出振荡原因两个滤波器各自引入相位滞后串联后总滞后叠加在闭环系统中可能引发振荡。解决不要盲目串联多个滤波器。如果一级滤波不够优先调整参数或换算法而不是级联。确实需要级联时把响应快、滞后小的放在前面。5. 二次开发与改造从能用到好用5.1 把浮点改成定点省下硬件浮点单元很多低成本MCU没有FPU用float会拖慢速度、增大代码体积。改造思路是把所有浮点运算转成Q格式定点数。以滑动平均为例把float换成int32_t窗口大小取2的幂次除法用右移代替// 定点滑动平均窗口大小16Q12格式 #define FIXED_SHIFT 12 #define FIXED_ONE (1 FIXED_SHIFT) int32_t fixed_moving_avg_update(fixed_moving_avg_t *f, int32_t new_value) { f-sum - f-buffer[f-index]; f-buffer[f-index] new_value; f-sum new_value; f-index (f-index 1) (FIXED_WINDOW_SIZE - 1); // 窗口大小为16右移4位完成除法 return f-sum 4; }注意定点数加法可能溢出sum要用int64_t或者确保窗口大小和采样位宽不会导致溢出。改造后运算速度通常能提升3到5倍代码体积减少约30%。5.2 加一层参数配置接口方便上位机在线调整实际项目中滤波参数经常需要根据工况调整。我一般会给每个滤波器加一个set_param函数通过串口协议接收上位机下发的参数。比如滑动平均的窗口大小、一阶滞后的α值。这样不用重新烧录就能调参省下大量时间。实现时注意参数范围校验窗口大小不能超过缓冲区数组长度α必须在0到1之间。5.3 用表格对比选型别凭感觉挑算法下面这张表是我在实际项目中总结的选型参考列了五种最常用算法的适用场景和代价算法适用场景滞后程度计算开销抗脉冲能力滑动平均缓变信号、ADC去噪中等低弱中位值有偶发尖峰干扰较大中强一阶滞后快速跟随、闭环控制小极低弱限幅滤波剔除明显异常值无极低中防脉冲平均既要平滑又要抗脉冲中等中较强选型时先问自己三个问题信号变化快不快干扰是持续噪声还是偶发脉冲MCU还剩多少算力答案清楚了算法基本就定了。5.4 验证方法用阶跃响应和噪声注入测一遍改完代码别急着上系统先做两个测试。第一个是阶跃响应给滤波器输入一个从0跳到100的阶跃信号观察输出爬到63.2%和90%需要多少个采样周期这能直观反映滞后。第二个是噪声注入在原始信号上叠加高斯白噪声和随机脉冲看滤波后的信噪比改善和脉冲抑制效果。我习惯把这两组数据打到串口用Python画出来对比比盯着数字看靠谱得多。从那以后我每次改滤波参数都强制走一遍阶跃响应和噪声注入测试不再凭感觉调。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

10种常用滤波算法C代码实现:从限幅到卡尔曼的选型指南

10种常用滤波算法C代码实现:从限幅到卡尔曼的选型指南

简介:这是一份面向嵌入式开发、单片机应用及信号采集方向的滤波算法实践资料,围绕C语言实现展开,适合需要处理传感器数据、抑制随机干扰的工程师与学生参考。资源系统整理了限幅、中位值、算术平均、递推平均、中位值平均、限幅平均、一阶滞后…

2026/10/18 23:27:29 阅读更多 →
微信小程序AI聊天源码:流式输出与LLM对接实战

微信小程序AI聊天源码:流式输出与LLM对接实战

简介:这份资源是一套微信小程序AI聊天页面的完整前端源码,面向希望快速上手小程序对接大语言模型的开发者与学习者,尤其适合想体验AI对话能力、验证人设设定效果的入门到中级人员。压缩包共6个文件,约386KB,包含wxml页…

2026/10/18 23:26:29 阅读更多 →
artcraft:降低创作门槛的数字化工具技术路线与实战经验

artcraft:降低创作门槛的数字化工具技术路线与实战经验

1. 从“artcraft”这个名字说起:它到底想解决什么问题第一次看到“artcraft”这个词,我脑子里蹦出来的第一反应是“艺术”加“手艺”的组合。这不是一个随便拼凑的名字,它背后指向的是一类非常具体的需求:把艺术创作和手工制作这两…

2026/10/18 23:26:29 阅读更多 →

最新新闻

CANfestival嵌入式CANopen协议栈深度解析与STM32实战

CANfestival嵌入式CANopen协议栈深度解析与STM32实战

简介:CANfestival 是一个轻量级、模块化的开源 CANopen 协议栈实现,面向嵌入式开发者、工业通信初学者及汽车电子/自动化领域工程师,用于快速构建符合 CANopen 标准的节点设备或学习协议底层机制。资源包共 50 个文件,以 30 个头文…

2026/10/19 0:27:02 阅读更多 →
STM32F407VE硬接W5500:HAL库驱动移植与TCP通信实战

STM32F407VE硬接W5500:HAL库驱动移植与TCP通信实战

简介:这是一份基于STM32F407VE的W5500以太网通信工程,采用HAL库并集成WIZnet最新驱动,面向嵌入式开发者及物联网、工业控制场景,已配置好时钟、GPIO、SPI、中断与协议栈基础,可直接编译运行以验证TCP/UDP通信&#xff…

2026/10/19 0:27:02 阅读更多 →
STM32F103C8T6串口IAP升级:Bootloader分区与跳转避坑指南

STM32F103C8T6串口IAP升级:Bootloader分区与跳转避坑指南

简介:面向STM32F103C8T6开发者的串口IAP升级固件源码包,完整解决单片机通过串口实现在线固件升级与跳转执行的需求,适合需要掌握Bootloader原理或正在调试在线升级方案的嵌入式工程师,也适合为仪器仪表、物联网节点等设备增加远程…

2026/10/19 0:27:02 阅读更多 →
硅基流动评测:150+ 模型免费试用,国产 MaaS 第一梯队到底能不能打(2026)

硅基流动评测:150+ 模型免费试用,国产 MaaS 第一梯队到底能不能打(2026)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:27:02 阅读更多 →
JavaWeb学生管理系统:JSP+Servlet+JDBC项目部署与避坑指南

JavaWeb学生管理系统:JSP+Servlet+JDBC项目部署与避坑指南

简介:一份基于原生Java的JavaWeb学生管理系统源码包,面向JavaWeb初学者以及需要课程实训或毕业设计参考的开发者,系统围绕学生信息、班级分配、教师任课、课程设置四大核心模块,实现了完整的增删改查操作。项目采用MVC分层架构&am…

2026/10/19 0:27:02 阅读更多 →
PlantUML驱动的可执行架构图设计方法论

PlantUML驱动的可执行架构图设计方法论

1. 项目概述:这不是画图,是构建可执行的逻辑骨架“diagram-design”这个词组乍一看像美术课作业,但在我过去十年带过的几十个跨领域项目里,它从来不是PPT里的装饰性插图,而是系统落地前最关键的“可执行蓝图”。我见过…

2026/10/19 0:26:02 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →