资讯动态

【嵌入式算法】实战解析:七种数字滤波算法的C语言实现与性能对比

发布时间:2026/8/27 4:26:01 来源:尧图企业网站定制
1. 数字滤波算法入门指南第一次接触数字滤波是在大三的智能车竞赛上当时我们的光电编码器信号总是跳变导师轻描淡写地说加个滤波就好了。结果我翻遍图书馆发现数字滤波这个看似简单的概念竟然藏着这么多门道。简单来说数字滤波就是用数学方法对采集到的信号去伪存真就像给数据做SPA去掉杂质保留精华。在实际嵌入式开发中AD采集到的信号总会带着各种噪音礼物可能是电机火花带来的突发干扰我们叫它毛刺干扰也可能是传感器本身的热噪声随机干扰。有次我用STM32测水温明明室温25度采样值却在20-30度之间上蹿下跳活像在跳迪斯科。这时候就需要数字滤波算法来稳定军心了。数字滤波最大的优势就是灵活。硬件滤波要换电阻电容软件滤波改个参数就行。记得有次比赛前夜发现滤波效果不好硬件队友还在翻找贴片电容时我已经通过改两行代码解决了问题。不过要注意滤波算法会占用CPU时间对于高频信号比如音频处理普通的MCU可能就力不从心了。2. 七种滤波算法实战详解2.1 限幅滤波防突变保镖限幅滤波就像个严格的保安规定相邻两次采样值的最大允许变化幅度D。去年做无人机项目时我用它来过滤气压计数据的异常跳变。具体实现是这样的#define D 5 // 允许最大变化值 int last_value 0; int limit_filter(int new_value) { if(abs(new_value - last_value) D) { return last_value; // 超出限幅就用上次值 } last_value new_value; return new_value; }实测中发现当物理量真实变化较快时比如突然加速的电机限幅滤波会把真实变化也过滤掉。后来我改进成动态调整D值根据信号变化率自动调节阈值效果就好多了。2.2 中值滤波投票选靠谱值中值滤波特别适合处理少数派报告——当干扰数据少于一半时。我在智能家居温控系统中就用它来过滤偶尔的传感器误报int median_filter(int buffer[], int size) { // 先排序 for(int i0; isize-1; i) { for(int j0; jsize-i-1; j) { if(buffer[j] buffer[j1]) { int temp buffer[j]; buffer[j] buffer[j1]; buffer[j1] temp; } } } return buffer[size/2]; // 取中值 }注意采样次数最好用奇数3/5/7这样不用处理偶数情况下的中间两数平均。有个坑要注意排序算法别用冒泡数据量大时改用快速排序我曾在STM32上因为这个问题把采样率拖慢了十倍。2.3 算术平均滤波人多力量大这个算法深谙集体智慧的道理我在光照传感器上应用时发现它对高斯分布的随机噪声特别有效float average_filter(float buffer[], int size) { float sum 0; for(int i0; isize; i) { sum buffer[i]; } return sum/size; }但遇到突发干扰就傻眼了——有一次车间电焊导致所有采样值都偏大平均值自然也不准。后来我给它加了个队友组合成去极值平均滤波抗干扰能力直接上了一个台阶。3. 进阶滤波技术解析3.1 滑动窗口的妙用传统平均滤波要等N次采样才能输出实时性太差。滑动平均滤波像是个移动的观察窗口我在电机转速测量中就用了这种方法float moving_buffer[5] {0}; int pos 0; float moving_average(float new_value) { moving_buffer[pos] new_value; pos (pos1)%5; float sum 0; for(int i0; i5; i) { sum moving_buffer[i]; } return sum/5; }这个实现用了环形缓冲区来避免数据搬移。在STM32F103上测试处理时间从原来的58us降到了12us。不过要注意窗口大小选择太大导致响应迟钝太小滤波效果差。3.2 加权滤波的艺术滑动加权滤波让我想起老师改试卷——最近的表现更重要。在电池电量预估中我这样分配权重float weights[5] {0.1,0.15,0.2,0.25,0.3}; // 越新权重越大 float weighted_average(float buffer[]) { float sum 0, weight_sum 0; for(int i0; i5; i) { sum buffer[i]*weights[i]; weight_sum weights[i]; } return sum/weight_sum; }权重的选择有讲究我试过指数加权0.5,0.25,0.125...但对突变响应还是不够快。后来根据系统响应时间用MATLAB优化了权重曲线效果提升明显。4. 滤波算法性能对决4.1 耗时对比测试在STM32F407平台测试168MHz主频处理1000个数据点的时间限幅滤波1.2ms中值滤波(5点)8.7ms滑动平均(5点)2.3ms一阶滞后1.5ms中值滤波因为要排序所以最耗时在资源紧张的8位MCU上要慎用。一阶滞后计算量小但效果取决于参数选择。4.2 抗干扰能力实测用信号发生器注入干扰对比输出波动幅度白噪声(10%)算术平均滤波效果最好能将波动减小到2%脉冲干扰(20ms)中值滤波完全免疫周期性干扰滑动加权滤波表现最优有个意外发现对于周期性干扰将滑动平均窗口大小设为干扰周期的1/2能取得最佳滤波效果。5. 参数调优经验谈5.1 采样周期的选择采样周期T要满足香农定理T1/(2fmax)但实际还要考虑干扰持续时间要保证T大于干扰持续时间物理量变化率比如温度变化慢T可以大些CPU负载综合计算所有任务的执行时间我在电机控制中这样确定采样周期T max(干扰持续时间, 1/(10*控制频率))5.2 一阶滞后滤波的系数选择系数a的选择就像走钢丝a太大接近1响应快但滤波效果差a太小平稳性好但响应迟钝我的调参秘诀先设a0.5观察输出曲线若波动大则减小a若响应慢则增大a每次调整幅度不超过0.1有个快速验证方法用Excel模拟不同a值的效果比直接在硬件上试错高效多了。6. 组合滤波实战案例在工业流量计项目中我开发了三级滤波方案硬件端RC低通滤波截止频率100Hz驱动层限幅滤波D10%量程应用层滑动加权滤波权重0.4,0.3,0.2,0.1float flow_sensor_filter(float raw) { static float last 0; // 限幅滤波 if(fabs(raw - last) MAX_DELTA) { raw last; } // 滑动窗口更新 update_window(raw); // 加权平均 return weighted_average(); }这种组合将测量波动从±5%降到了±0.8%而且响应时间控制在200ms以内。关键是要合理安排滤波顺序把计算量小的放前面。7. 特殊场景处理技巧7.1 启动时的滤波策略系统刚上电时滤波窗口还没填满直接使用会出问题。我的处理方法是if(startup_cnt WINDOW_SIZE) { startup_cnt; return raw_value; // 前几次直接返回原始值 } else { return filter_value(); // 正常滤波 }等窗口填满后再启用完整滤波避免启动时的无效数据影响系统。7.2 动态调整滤波强度根据信号变化率自动调节滤波参数float delta fabs(current - last); if(delta THRESHOLD) { a 0.8; // 变化大时减弱滤波 } else { a 0.3; // 稳定时加强滤波 }这套算法用在了智能手环的心率检测上既能捕捉剧烈运动时的心率变化又能过滤日常测量中的噪声。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价