公司动态
C 语言工业级通用组件手写 19:中位平均复合滤波
目录前言一、复合滤波核心本质与应用场景1. 什么是中位平均复合滤波2. 解决的核心痛点3. 典型工业落地场景二、核心实现原理1. 两级滤波架构2. 去极值机制3. 增量平滑机制4. 工程适配逻辑三、工业级设计规范1. 封装设计2. 接口设计3. 鲁棒约束4. 线程安全四、完整可复用源码filter_mid_avg.hfilter_mid_avg.c五、实战演示六、进阶优化方向七、面试考点与易错坑点面试问答常见坑点总结前言单纯滑动平均滤波无法剔除瞬时高压尖峰干扰单纯中位值滤波平滑度不足、小幅抖动无法消除。 工业现场电磁干扰复杂既有偶然脉冲毛刺又有持续小幅采样抖动单一滤波算法无法兼顾。本篇实现中位值 滑动平均复合滤波先去极值、再做平滑融合两种算法优点互相弥补短板是嵌入式设备量产最稳、使用率最高的通用降噪算法。一、复合滤波核心本质与应用场景1. 什么是中位平均复合滤波复合滤波是工程级融合算法第一步采样多组数据排序取中位值彻底剔除突发尖峰、极值干扰第二步将中值结果送入滑动窗口增量平均平滑小幅抖动同时具备中值滤波抗脉冲能力、平均滤波高平滑特性。核心特性双重降噪滤除尖峰干扰 抹平小幅纹波稳态精度高动态响应适中无复杂运算单片机零压力多实例独立对象支持多路传感器纯静态内存无堆碎片、无依赖2. 解决的核心痛点解决单一平均滤波怕尖峰、易被异常值带偏的问题。解决单一中值滤波平滑度差、小幅抖动残留问题。解决工业复杂电磁环境采样数据跳变、波动问题。解决设备量产数据漂移、阈值误触发、显示跳动问题。解决多场景适配难一套算法兼容稳态、微动态采集。3. 典型工业落地场景工业强干扰环境 ADC 电压、电流采集。称重、压力、重力高精度采样降噪。电池电量、电压稳态监测。智能设备温湿度高精度采集。工控模拟量输入、闭环控制反馈滤波。二、核心实现原理1. 两级滤波架构一级滤波N 点中位值滤波剔除脉冲尖峰、异常极值。二级滤波滑动增量平均平滑残留小幅高频抖动。2. 去极值机制对单次采样组排序舍弃最大、最小干扰值保留真实稳态数据。3. 增量平滑机制中值结果进入滑动窗口采用总和增量更新O (1) 极速运算不卡顿、无滞后堆积。4. 工程适配逻辑复杂工业噪声 脉冲噪声 高斯小幅噪声单一算法只能处理一种复合算法全覆盖。三、工业级设计规范1. 封装设计结构体完整封装缓存、累加值、索引、窗口参数。支持多设备、多通道独立滤波互不干扰。全程静态内存支持裸机、RTOS 全平台。2. 接口设计接口功能说明filter_mid_avg_init初始化复合滤波参数filter_mid_avg_calc输入原始采样输出最终滤波值filter_mid_avg_clear重置滤波缓存与状态3. 鲁棒约束中位窗口强制奇数避免歧义。参数越界、空指针全部安全拦截。未满窗口渐进输出启动无突变。4. 线程安全单任务天然安全多任务 / 中断需外部加锁保护。四、完整可复用源码filter_mid_avg.h#ifndef FILTER_MID_AVG_H #define FILTER_MID_AVG_H #include stdint.h #include stdbool.h #ifdef __cplusplus extern C { #endif // 中值滤波最大窗口 #define MID_WIN_MAX 9 // 滑动平均最大窗口 #define AVG_WIN_MAX 8 typedef struct { // 中值滤波缓存 int32_t mid_buf[MID_WIN_MAX]; uint8_t mid_idx; uint8_t mid_win; // 滑动平均滤波缓存 int32_t avg_buf[AVG_WIN_MAX]; int32_t avg_sum; uint8_t avg_idx; uint8_t avg_win; bool avg_init; } filter_mid_avg_t; /** * brief 复合滤波初始化 * param filter 滤波句柄 * param mid_win 中值窗口(奇数) * param avg_win 平均窗口 */ void filter_mid_avg_init(filter_mid_avg_t *filter, uint8_t mid_win, uint8_t avg_win); /** * brief 复合滤波计算 * param filter 滤波句柄 * param val 原始采样值 * return 最终滤波输出值 */ int32_t filter_mid_avg_calc(filter_mid_avg_t *filter, int32_t val); /** * brief 清空复位滤波状态 * param filter 滤波句柄 */ void filter_mid_avg_clear(filter_mid_avg_t *filter); #ifdef __cplusplus } #endif #endiffilter_mid_avg.c#include filter_mid_avg.h static void data_sort(int32_t *buf, uint8_t len) { for(uint8_t i 0; i len - 1; i) { for(uint8_t j 0; j len - 1 - i; j) { if(buf[j] buf[j 1]) { int32_t temp buf[j]; buf[j] buf[j 1]; buf[j 1] temp; } } } } void filter_mid_avg_init(filter_mid_avg_t *filter, uint8_t mid_win, uint8_t avg_win) { if(filter NULL) return; // 限制中值窗口强制奇数 if(mid_win MID_WIN_MAX || mid_win 3) mid_win 3; if(mid_win % 2 0) mid_win 1; // 限制平均窗口 if(avg_win AVG_WIN_MAX || avg_win 1) avg_win 4; filter-mid_win mid_win; filter-mid_idx 0; filter-avg_win avg_win; filter-avg_idx 0; filter-avg_sum 0; filter-avg_init false; // 清空缓存 for(uint8_t i 0; i MID_WIN_MAX; i) filter-mid_buf[i] 0; for(uint8_t i 0; i AVG_WIN_MAX; i) filter-avg_buf[i] 0; } int32_t filter_mid_avg_calc(filter_mid_avg_t *filter, int32_t val) { if(filter NULL) return val; // 一级填充中值滤波缓冲区 filter-mid_buf[filter-mid_idx] val; // 中值窗口未攒满直接输出不处理 if(filter-mid_idx filter-mid_win) { return val; } // 中值窗口攒满排序取中值 data_sort(filter-mid_buf, filter-mid_win); uint8_t mid_pos filter-mid_win / 2; int32_t mid_val filter-mid_buf[mid_pos]; // 清空索引开启下一轮中值采样 filter-mid_idx 0; // 二级滑动平均滤波 if(!filter-avg_init) { filter-avg_sum mid_val; filter-avg_buf[filter-avg_idx] mid_val; if(filter-avg_idx filter-avg_win) { filter-avg_init true; } return filter-avg_sum / filter-avg_idx; } // 增量滑动平均计算 filter-avg_sum - filter-avg_buf[filter-avg_idx]; filter-avg_sum mid_val; filter-avg_buf[filter-avg_idx] mid_val; filter-avg_idx; if(filter-avg_idx filter-avg_win) { filter-avg_idx 0; } return filter-avg_sum / filter-avg_win; } void filter_mid_avg_clear(filter_mid_avg_t *filter) { if(filter NULL) return; filter-mid_idx 0; filter-avg_idx 0; filter-avg_sum 0; filter-avg_init false; for(uint8_t i 0; i MID_WIN_MAX; i) filter-mid_buf[i] 0; for(uint8_t i 0; i AVG_WIN_MAX; i) filter-avg_buf[i] 0; }五、实战演示#include stdio.h #include filter_mid_avg.h int main(void) { filter_mid_avg_t adc_filter; // 5点中值 4点平均 复合滤波 filter_mid_avg_init(adc_filter, 5, 4); // 模拟包含尖峰小幅抖动的工业干扰数据 int32_t raw_data[] {310, 312, 600, 309, 311, 308, 50, 310, 313, 307, 311}; for(int i 0; i sizeof(raw_data)/sizeof(raw_data[0]); i) { int32_t out filter_mid_avg_calc(adc_filter, raw_data[i]); printf(原始值%d \t滤波输出%d\r\n, raw_data[i], out); } return 0; }六、进阶优化方向动态自适应复合滤波根据数据波动幅度自动切换大小窗口兼顾响应速度与稳态精度。限幅预筛选机制新增前后帧差值阈值超大幅跳变直接丢弃不进入滤波队列。滑动中值优化替换整组刷新中值改为滑动缓存大幅降低数据滞后。多级加权复合对平均窗口新增加权系数新数据权重更高提升动态跟随能力。七、面试考点与易错坑点面试问答Q1复合中位平均滤波相比单一滤波有什么优势答整合两种算法优势中值滤波干掉突发尖峰脉冲干扰滑动平均抹平小幅周期性抖动。既能抗强电磁干扰又能保证数据极致平滑是工业量产最优通用方案。Q2三种滤波平均 / 中值 / 复合如何工程选型答只有小幅抖动、无尖峰 → 滑动平均只有偶然跳变、脉冲干扰 → 中位值滤波干扰复杂、量产稳定性要求高 → 中位平均复合滤波Q3复合滤波的缺点是什么如何优化答两级计算存在轻微滞后响应速度慢于单级滤波。 优化减小窗口、滑动式中值、动态窗口自适应。Q4为什么中值窗口必须奇数平均窗口可以任意答中值需要唯一中间值奇数无歧义平均是总和除法任意窗口大小均可正常计算。Q5复合滤波为什么能覆盖 90% 工业采集场景答工业噪声只有两类突发脉冲噪声、高斯小幅噪声复合算法刚好全覆盖无死角降噪。Q6多实例滤波设计的工程意义答不同传感器干扰特性不同可单独配置中值窗口、平均窗口独立降噪、参数互不影响工程可维护性极高。常见坑点两级窗口设置过大导致数据严重滞后。中值窗口设为偶数导致滤波结果偏移。多通道共用同一个滤波句柄数据覆盖错乱。未做参数校验非法窗口导致数组越界。忽略启动未满窗口初始数据跳动严重。总结中位平均复合滤波是嵌入式工业降噪终极通用方案完美弥补单一滤波算法缺陷。抗尖峰、稳波形、低抖动、高可靠适配所有模拟量采集场景是设备量产、高精度采样、强电磁环境下的首选滤波组件代码工业级稳健可直接商用落地。创作不易如果对你有帮助欢迎点赞、收藏、转发。