4、数字滤波技术:移动平均滤波、中值滤波、低通滤波(FIR/IIR)、卡尔曼滤波入门
各位工程师朋友,咱们接着聊。上一节讲了硬件层面的抗干扰,但说实话,很多时候干扰已经混进信号里了,靠硬件硬扛成本高、效果也有限。这时候,就该数字滤波上场了。
数字滤波,说白了就是用软件算法把有用的信号从噪声里“捞”出来。我这些年调试力控系统,最深的体会就是:不会用数字滤波,你都不好意思说自己搞过工业控制。今天咱们就把四种最常用的滤波技术掰开揉碎了讲清楚。
4.1 移动平均滤波:最简单,也最容易被低估
移动平均滤波的原理,说白了就是“取最近N个采样值的平均数”。你想想看,噪声通常是随机抖动的,一平均,正负抵消,信号自然就平滑了。
核心公式:
y[n] = (x[n] + x[n-1] + ... + x[n-N+1]) / N
其中N是窗口长度,x是原始采样值,y是滤波后的值。
我在项目中遇到过一种情况:一个压力传感器,采样值在4.95MPa到5.05MPa之间来回跳,控制系统跟着频繁调节阀门,搞得执行器寿命大减。我加了个4点移动平均,波形立马稳了,阀门动作频率降了70%。
我的经验:窗口N怎么选?N太小,滤波效果差;N太大,信号延迟大。一般工业现场,N取4到16之间比较合适。如果采样率是100Hz,N取8,延迟也就80ms,大多数力控系统都能接受。
// 移动平均滤波实现(C语言)
#define WINDOW_SIZE 8
float buffer[WINDOW_SIZE] = {0};
int index = 0;
float sum = 0;
float moving_average(float new_sample) {
sum -= buffer[index]; // 减去最旧的值
buffer[index] = new_sample; // 存入新值
sum += new_sample; // 加上新值
index = (index + 1) % WINDOW_SIZE;
return sum / WINDOW_SIZE;
}
注意:移动平均滤波对周期性干扰(比如50Hz工频干扰)效果很差。我曾经在一个变频器附近调试,50Hz干扰死活滤不掉,后来才发现是移动平均的锅——它对固定频率的噪声基本没辙。
4.2 中值滤波:对付“野点”的利器
什么叫“野点”?就是采样值突然蹦出一个离谱的数,比如正常5MPa的压力,突然跳成50MPa。这种干扰通常是传感器瞬间受冲击、或者通信丢包造成的。
中值滤波的思路很简单:把最近N个采样值排序,取中间那个。这样一来,不管野点有多大,只要它不占多数,就被直接扔掉了。
适用场景:
- 传感器受机械冲击(比如压机突然撞击)
- 通信偶尔丢包或错包
- ADC采样偶尔出现毛刺
我个人习惯把中值滤波和移动平均配合着用。先过一遍中值滤波把野点干掉,再过一遍移动平均把随机噪声平滑掉。嗯,这个组合在力控系统里非常实用。
// 中值滤波实现(C语言,冒泡排序版)
#define MEDIAN_WINDOW 5
float median_filter(float new_sample) {
static float window[MEDIAN_WINDOW] = {0};
static int idx = 0;
float temp[MEDIAN_WINDOW];
int i, j;
window[idx] = new_sample;
idx = (idx + 1) % MEDIAN_WINDOW;
// 复制并排序
for(i = 0; i < MEDIAN_WINDOW; i++) temp[i] = window[i];
for(i = 0; i < MEDIAN_WINDOW - 1; i++) {
for(j = 0; j < MEDIAN_WINDOW - 1 - i; j++) {
if(temp[j] > temp[j+1]) {
float t = temp[j];
temp[j] = temp[j+1];
temp[j+1] = t;
}
}
}
return temp[MEDIAN_WINDOW / 2]; // 取中间值
}
避坑指南:我曾经在一个高速力控系统里用中值滤波,窗口取了9个点,结果发现系统响应慢了一拍。后来才意识到——中值滤波涉及排序,窗口越大,计算耗时越长。高速系统里窗口别超过5个点,否则实时性堪忧。
4.3 低通滤波:FIR与IIR的抉择
低通滤波,就是让低频信号通过,把高频噪声滤掉。在力控系统里,力信号变化通常比较慢(几Hz到几十Hz),而噪声往往是高频的(几百Hz甚至更高),所以低通滤波非常对路。
4.3.1 FIR滤波器:稳定,但计算量大
FIR(有限脉冲响应)滤波器,说白了就是加权移动平均。每个采样值乘以一个系数,然后加起来。它的优点是绝对稳定,不会出现发散的情况。
FIR滤波公式:
y[n] = b₀·x[n] + b₁·x[n-1] + ... + bₙ₋₁·x[n-N+1]
其中b₀到bₙ₋₁是滤波器系数,也叫“抽头系数”。
我记得刚入行时,带我的老师傅说:“FIR滤波器就像个老实人,干活稳当,就是有点慢。” 确实,要获得好的滤波效果,FIR需要很多个抽头(比如64阶、128阶),计算量不小。
4.3.2 IIR滤波器:效率高,但要小心
IIR(无限脉冲响应)滤波器引入了反馈,用更少的计算量就能达到和FIR类似的滤波效果。但代价是——可能不稳定。
我曾经踩过的坑:在一个液压伺服系统里,我用IIR低通滤波,参数调得有点激进,结果系统在某个频率点自激振荡了,力信号越滤越大,差点把执行器搞坏。从那以后,我对IIR的稳定性就格外小心。
最常用的IIR滤波器是巴特沃斯滤波器,它的特点是通带内最平坦,没有纹波。对于力控系统来说,这通常是最合适的选择。
// 一阶IIR低通滤波(最简形式)
float alpha = 0.1; // 滤波系数,0~1之间,越小滤波越强
float y_prev = 0;
float iir_lowpass(float x) {
float y = alpha * x + (1 - alpha) * y_prev;
y_prev = y;
return y;
}
我的建议:如果MCU性能够用,优先用FIR,稳定可靠。如果MCU资源紧张(比如8位单片机),用一阶或二阶IIR。记住一个原则:能用低阶就别用高阶,阶数越高,越容易出问题。
4.4 卡尔曼滤波入门:力控系统的“预测大师”
前面几种滤波都是“事后诸葛亮”——等数据来了再处理。卡尔曼滤波不一样,它能预测下一时刻的值,然后用实际测量值来修正预测。
你想想看,在力控系统里,力信号的变化是有规律的(比如按某个斜率上升或下降)。卡尔曼滤波正是利用了这种规律,所以效果比普通滤波好得多。
卡尔曼滤波的核心思想:
- 预测:根据上一时刻的状态,预测当前时刻的状态
- 更新:用当前时刻的测量值,修正预测值
- 迭代:重复以上两步,不断逼近真实值
说实话,卡尔曼滤波的数学推导挺复杂的,涉及矩阵运算、协方差矩阵什么的。但在实际工程里,我们不需要从头推导,直接用现成的公式就行。
// 一维卡尔曼滤波(简化版,适用于力控系统)
float Q = 0.01; // 过程噪声协方差
float R = 0.1; // 测量噪声协方差
float x_est = 0; // 估计值
float P = 1; // 估计误差协方差
float K; // 卡尔曼增益
float kalman_filter(float z) {
// 预测
P = P + Q;
// 更新
K = P / (P + R);
x_est = x_est + K * (z - x_est);
P = (1 - K) * P;
return x_est;
}
参数调优经验:Q和R是两个关键参数。Q越大,说明系统变化快,滤波器响应快但噪声大;R越大,说明测量噪声大,滤波器平滑但响应慢。我一般先设R=0.1,然后根据实际波形调整Q。如果信号抖动大,就减小Q;如果响应太慢,就增大Q。
4.5 四种滤波技术的对比与选择
说了这么多,到底该用哪种?我整理了一个表格,方便你对照选择。
| 滤波类型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 移动平均 | 简单、计算量小 | 对周期性干扰无效 | 随机噪声、信号平滑 |
| 中值滤波 | 抗野点能力强 | 计算量随窗口增大 | 传感器冲击、通信错误 |
| FIR低通 | 绝对稳定、线性相位 | 计算量大、延迟高 | 对稳定性要求高的系统 |
| IIR低通 | 效率高、延迟小 | 可能不稳定 | 资源受限的嵌入式系统 |
| 卡尔曼滤波 | 预测能力强、精度高 | 参数调优复杂 | 高精度力控、动态跟踪 |
我个人习惯是:先简单后复杂。先试试移动平均,不行再加中值滤波,还不行上FIR,最后才考虑卡尔曼。别一上来就整卡尔曼,杀鸡用牛刀不说,参数调不好反而坏事。
最后说一句:数字滤波不是万能的。如果信号的信噪比太低(比如噪声比信号还大),再好的滤波算法也救不了。这时候还是得回头检查硬件——屏蔽、接地、差分传输,把基础打牢了,数字滤波才能发挥最大作用。