STM32嵌入式常用数字滤波算法详解与实战
在嵌入式系统中,AD采集的数据往往夹杂着各种噪声——白噪声、脉冲干扰、周期性波动等。如何从这些“脏数据”中提取出真实信号,是每个嵌入式工程师必须面对的课题。本文基于一份典型的STM32工程代码,详细剖析10种经典数字滤波算法的原理、实现及适用场景,并指出常见实现误区,助你轻松应对不同噪声环境。
一、为什么需要数字滤波?
模拟电路硬件滤波(RC、LC)固然简单,但参数固定、无法自适应,且占用PCB面积。数字滤波则可通过软件灵活调整系数,实现复杂算法,且不增加硬件成本。尤其在STM32这类Cortex-M平台上,利用CPU空闲时间做滤波计算,性价比极高。
本文所有算法均围绕一个预先生成的正弦波查找表(ftable[255])展开,模拟连续采样的数据流,通过串口输出滤波前后的数值,便于在PC端绘制波形对比。
二、10种经典数字滤波算法
1. 限幅滤波法(又称程序判断滤波)
原理:根据经验设定两次采样允许的最大偏差值 A。若当前采样值与上次有效值之差超过 A,则判定本次值为干扰,予以丢弃,仍用上次值;否则采用本次值。
代码实现:
#define A 51
u16 Value1; // 上一次有效值
u16 filter1() {
u16 NewValue = ftable[b]; // 本次采样
b++; if(b==255) b=1;
// 判断差值是否超限
if ((NewValue > Value1 ? NewValue - Value1 : Value1 - NewValue) > A)
return Value1; // 超限,保持旧值
else {
Value1 = NewValue; // 更新有效值
return NewValue;
}
}
优点:有效克服偶然脉冲干扰(如雷击、开关噪声)。
缺点:无法抑制周期性干扰,平滑度差;阈值 A 需凭经验设定,不当则效果打折。
适用场景:压力、液位等变化缓慢的物理量。
2. 中位值滤波法
原理:连续采样 N 次(N 取奇数),将采样值排序,取中间值作为本次有效值。
代码片段:
#define N 5
u16 filter2() {
u16 buf[N], i, j, temp;
for (i=0; i<N; i++) {
buf[i] = ftable[a++]; if(a==255) a=0;
}
// 冒泡排序(从小到大)
for (i=0; i<N-1; i++)
for (j=0; j<N-1-i; j++)
if (buf[j] > buf[j+1]) { temp = buf[j]; buf[j]=buf[j+1]; buf[j+1]=temp; }
return buf[(N-1)/2];
}
优点:对偶然脉冲干扰有极强抑制作用(因为极值不会落在中位)。
缺点:对快速变化的信号(如流量、速度)反应迟钝;排序耗时,N不宜过大。
适用场景:温度、液位等变化缓慢且伴有偶发尖峰噪声的场合。
3. 算术平均滤波法
原理:连续采样 N 个值,计算算术平均值。
代码:
#define N 5
u16 filter3() {
u32 sum = 0;
for (u8 i=0; i<N; i++) {
sum += ftable[a++]; if(a==255) a=0;
}
return sum / N;
}
优点:平滑随机噪声,信号平滑度随 N 增大而提高。
缺点:占用RAM存储N个数据;响应慢,N过大时实时性差;不能有效滤除脉冲干扰。
适用场景:随机噪声占主导的信号,如压力传感器(N=4)或流量传感器(N=12)。
4. 递推平均滤波法(滑动平均)
原理:维护一个长度为 N 的队列,每次采样到新数据入队,同时丢弃队首最旧数据,然后计算队列平均值。相当于“先进先出”的算术平均。
代码:
#define N 3
u16 buf[N+1];
u16 filter4() {
u16 sum = 0;
buf[N] = ftable[a++]; if(a==255) a=0;
for (i=0; i<N; i++) {
buf[i] = buf[i+1]; // 左移
sum += buf[i];
}
return sum / N;
}
优点:对周期性干扰有良好抑制,平滑度高,适用于高频振荡系统。
缺点:对偶发脉冲干扰抑制较差;占用RAM较多。
适用场景:交流信号整流后的平滑、电机电流采样等。
5. 中位值平均滤波法(防脉冲干扰平均滤波)
原理:先采样 N 个数据,去掉一个最大值和一个最小值,再对剩余 N-2 个求平均。融合了中位值滤波和算术平均的优点。
代码:
#define N 5
u16 filter5() {
u16 buf[N], sum=0;
// 采集并排序(同中位值滤波)
// 然后从 index=1 到 N-2 累加
for (i=1; i<N-1; i++) sum += buf[i];
return sum / (N-2);
}
优点:抑制脉冲干扰,同时平滑随机噪声,平滑度高。
缺点:排序耗时,N取3~14为宜;实时性欠佳。
适用场景:工业现场强干扰环境下的慢变信号。
6. 限幅平均滤波法
原理:先对采样值进行限幅处理(同方法1),然后再送入滑动平均队列。
代码:
#define N 3
#define A 51
u16 buf[N];
u16 filter6() {
u16 new = ftable[a++]; if(a==255) a=0;
if (abs(new - buf[N-1]) > A) new = buf[N-1]; // 限幅
// 滑动平均(略)
}
优点:兼备限幅和平均滤波的优点,有效抑制脉冲和周期干扰。
缺点:消耗两倍RAM(限幅需保存上次值,平均需队列)。
适用场景:既有尖峰脉冲又有周期性噪声的恶劣环境。
7. 一阶滞后滤波法
原理:本次输出 = (1-α) × 本次采样值 + α × 上次输出值,α 为0~1之间的系数。相当于一个数字低通滤波器。
代码:
#define ALPHA 0.1f
u16 Value;
u16 filter7() {
u16 new = ftable[b++]; if(b==255) b=1;
Value = (u16)((1-ALPHA) * new + ALPHA * Value);
return Value;
}
优点:对周期性干扰抑制效果好,平滑度高,代码量极小(无需队列)。
缺点:相位滞后,灵敏度低;α 调优困难。
适用场景:高频振荡信号、电源纹波滤除。
8. 加权递推平均滤波法
原理:对滑动平均进行改进,不同时刻的数据赋予不同权重,越新的数据权重越大。
代码:
#define N 12
const u8 coe[N] = {1,2,3,4,5,6,7,8,9,10,11,12};
u16 sum_coe = 78;
u16 buf[N+1];
u16 filter8() {
u32 sum=0;
buf[N] = ftable[a++]; if(a==255) a=0;
for (i=0; i<N; i++) {
buf[i] = buf[i+1];
sum += buf[i] * coe[i];
}
return sum / sum_coe;
}
优点:提高系统响应灵敏度,适用于大滞后对象。
缺点:权重系数需根据实际对象调优;计算量稍大。
适用场景:温度控制系统、压力缓慢变化但需快速反映突变的场合。
9. 消抖滤波法
原理:设置一个计数器,若采样值持续与当前有效值不同,计数器累加,当超过上限 N 时,才更新有效值。相当于“去抖”处理。
代码:
#define N 5
u16 Value, cnt=0;
u16 filter9() {
u16 new = ftable[b++]; if(b==255) b=1;
if (Value != new) {
cnt++;
if (cnt > N) { cnt=0; Value = new; }
} else cnt = 0;
return Value;
}
优点:避免临界值附近的反复跳动,显示稳定。
缺点:对快速变化信号响应迟钝;若计数器溢出时恰巧为干扰值,则会误更新。
适用场景:按键消抖、开关量信号处理、仪表显示防抖。
10. 限幅消抖滤波法
原理:先限幅,再消抖。结合方法1和方法9。
代码:
#define A 51
#define N 5
u16 Value, cnt;
u16 filter10() {
u16 new = ftable[b++]; if(b==255) b=1;
if (abs(new - Value) > A) new = Value; // 限幅
// 消抖逻辑(同方法9)
...
return Value;
}
优点:继承限幅和消抖的双重优势,避免干扰值被误导入。
缺点:对快速变化信号不适用。
适用场景:极慢变化且需杜绝跳变显示的场合。
三、如何选择合适的滤波算法?
| 噪声类型 | 推荐算法 |
|---|---|
| 偶发脉冲尖峰 | 限幅滤波、中位值滤波 |
| 随机白噪声 | 算术平均、滑动平均 |
| 周期性干扰(工频等) | 滑动平均、一阶滞后 |
| 既有脉冲又有周期噪声 | 限幅平均、中位值平均 |
| 显示防抖动 | 消抖滤波、限幅消抖 |
| 实时性要求高 | 限幅滤波、一阶滞后(计算快) |
| RAM资源紧张 | 限幅滤波、一阶滞后(无队列) |
通常在实际项目中,会组合使用多种滤波(如先限幅再滑动平均),以达到最佳效果。
四、总结
数字滤波是嵌入式信号处理的基本功。本文列举的10种方法覆盖了绝大多数工程需求,它们各有优劣,无绝对“最佳”,只有“最适合”。开发者应根据信号特征、实时性、资源限制综合评估。
最后,建议在实际调试时,将原始值和滤波值同时通过串口上传至上位机绘制曲线,直观对比不同算法的效果,这是最快的学习和调优途径。
希望本文能帮助你在STM32项目中轻松驾驭噪声,还原纯净信号!
延伸阅读:卡尔曼滤波、自适应滤波、FFT频域滤波等高级算法,适用于更高要求的应用,可进一步深入研究。
更多推荐
所有评论(0)