基于《数字滤波常用的软件方法代码实例》《数字滤波与卡尔曼滤波》等技术资料,按干扰类型给出10种经典数字滤波算法的C代码、参数整定与一维卡尔曼滤波数值算例
传感器数字滤波没有"万能算法",正确的做法是按干扰类型选算法:脉冲型干扰(毛刺、误触发)选限幅、中值、消抖类滤波;随机噪声(热噪声、量化噪声)选算术平均、滑动平均、加权滑动平均;慢变信号叠加高频噪声选一阶滞后滤波;需要动态估计运动状态或连续量时选卡尔曼滤波。本文基于《数字滤波常用的软件方法代码实例》与《数字滤波与卡尔曼滤波》技术资料,给出 10 种经典算法的 C 代码、参数整定原则,以及一维卡尔曼滤波的完整数值算例,可直接用于嵌入式数据采集、RTU 模拟量通道与物联网终端的信号预处理。
现场传感器信号中的干扰大致分三类:一是脉冲型干扰,来自变频器启停、继电器吸合、静电放电等瞬态事件,表现为信号上叠加大幅值尖峰;二是随机噪声,来自器件热噪声、AD 量化噪声与工频耦合,表现为围绕真值的上下抖动;三是误触发抖动,常见于开关量、液位、接近传感器输出。三类干扰的统计特征完全不同,对应的滤波手段也不同,这是选型的总纲。
| 算法 | 针对干扰 | 原理 | 特点与代价 |
|---|---|---|---|
| 限幅滤波 | 脉冲毛刺 | 与上次值偏差超限则丢弃 | 最简单,无法滤随机噪声 |
| 中值滤波 | 脉冲毛刺 | N 点排序取中值 | 抗脉冲强,需缓存并排序 |
| 消抖滤波 | 误触发抖动 | 连续 N 次采样一致才采纳 | 适合开关量,有响应延迟 |
| 算术平均滤波 | 随机噪声 | 连续 N 点求和取平均 | 平滑好,实时性差 |
| 滑动平均滤波 | 随机噪声 | 固定窗口滚动平均 | 实时性好,占 N 点 RAM |
| 加权滑动平均 | 随机噪声 | 近时刻权重更大 | 灵敏度高于等权平均 |
| 中位值平均滤波 | 脉冲+随机 | 排序去极值后平均 | 综合最强,耗时较长 |
| 限幅平均滤波 | 脉冲+随机 | 先限幅剔除毛刺再平均 | 组合算法,折中方案 |
| 一阶滞后滤波 | 高频噪声 | 惯性平滑 y=(1-a)y+a·z | 参数单一,响应可调 |
| 限幅消抖滤波 | 脉冲+抖动 | 先限幅再消抖 | 组合算法,双重防护 |
限幅滤波(又称程序判断滤波)的核心是设定最大允许偏差 A,本次采样与上次有效值偏差超过 A 就判定为干扰并丢弃,直接输出上次值。它实现成本最低,适合保护后续算法不被单个毛刺污染。
#define A 10 /* 最大允许偏差,按信号变化率整定 */
char value; /* 上次有效采样值 */
char limit_filter(void) {
char new_value = get_ad(); /* 本次采样 */
if ((new_value - value > A) || (value - new_value > A))
return value; /* 超限:判为干扰,保持上次值 */
return new_value;
}
中值滤波连续采样 N 点(取奇数)排序后输出中值,对脉冲干扰的抑制能力很强,但会引入 N 次采样的延迟。消抖滤波则要求连续 N 次采样与当前值一致才更新输出,是开关量、按键、液位信号的标配,代价是响应存在 N 个采样周期的滞后。
#define N 11 /* 采样点数(取奇数) */
char median_filter(void) {
char value_buf[N], count, i, j, temp;
for (count = 0; count < N; count++) {
value_buf[count] = get_ad();
delay();
}
for (j = 0; j < N - 1; j++) /* 冒泡排序 */
for (i = 0; i < N - 1 - j; i++)
if (value_buf[i] > value_buf[i + 1]) {
temp = value_buf[i];
value_buf[i] = value_buf[i + 1];
value_buf[i + 1] = temp;
}
return value_buf[(N - 1) / 2]; /* 取中值 */
}
#define N 12 /* 连续一致次数 */
char debounce_filter(void) {
char count = 0;
char new_value = get_ad();
while (value != new_value) {
count++;
if (count >= N) return new_value; /* 连续 N 次一致才采纳 */
delay();
new_value = get_ad();
}
return value;
}
算术平均滤波把连续 N 次采样求和取平均,N 越大平滑越强、噪声方差降至 1/N,但每次输出都要等 N 次采样,实时性差。滑动平均滤波维护一个长度为 N 的窗口,每次采样先进先出再求平均,实时性优于算术平均,是 RTU 模拟量通道最常用的方案。
#define N 12
char value_buf[N];
char i = 0;
char slide_average_filter(void) {
char count;
int sum = 0;
value_buf[i++] = get_ad(); /* 新值入队 */
if (i == N) i = 0; /* 环形队列回绕 */
for (count = 0; count < N; count++)
sum += value_buf[count];
return (char)(sum / N);
}
加权滑动平均给越接近当前时刻的采样分配越大权重,在同样平滑程度下响应更快,但需额外保存权重表。中位值平均滤波(防脉冲干扰平均)先把 N 点排序,去掉最大最小值后再平均,同时抑制脉冲与随机噪声,是工业采集的"组合拳",代价是计算量最大。
#define N 12
char code coe[N] = {1,2,3,4,5,6,7,8,9,10,11,12}; /* 权重递增 */
#define SUM_COE 78 /* 权重和 1+...+12 */
char weight_average_filter(void) {
char count;
char value_buf[N];
int sum = 0;
for (count = 0; count < N; count++) {
value_buf[count] = get_ad();
delay();
}
for (count = 0; count < N; count++)
sum += value_buf[count] * coe[count];
return (char)(sum / SUM_COE);
}
一阶滞后滤波输出 y = (1-a)·y + a·z,其中 a 在 0~100 之间(资料中示例 a=50),a 越大对新采样越敏感、响应越快但滤波越弱;a 越小越平滑但滞后越明显。它只用两个变量、无数组缓存,非常适合温度、液位等慢变模拟量在 MCU 中做轻量平滑,工程实现时注意用整型运算避免溢出(原资料示例未除 100,实际实现须补除以 100):
#define a 50 /* 0~100,越大对新值越敏感 */
char value; /* 上次滤波输出 */
char lag_filter(void) {
char new_value = get_ad();
return (char)(((100 - a) * value + a * new_value) / 100);
}
卡尔曼滤波针对的是"既有噪声又需要跟踪动态变化"的场景,它以状态空间模型为基础,通过"预测-更新"两步递推给出最小均方误差意义下的最优估计。一维恒定模型的五个公式为:预测阶段 x̂(k|k-1)=x̂(k-1)、P(k|k-1)=P(k-1)+Q;更新阶段 K=P(k|k-1)/(P(k|k-1)+R)、x̂(k)=x̂(k|k-1)+K·(z(k)-x̂(k|k-1))、P(k)=(1-K)·P(k|k-1)。其中 Q 为过程噪声方差(反映模型不确定度),R 为测量噪声方差(可由传感器噪声统计标定)。
typedef struct {
float x; /* 状态估计值 */
float p; /* 估计方差 */
float q; /* 过程噪声方差 Q */
float r; /* 测量噪声方差 R */
} kalman_1d_t;
float kalman_1d_update(kalman_1d_t *k, float z) {
float kg; /* 卡尔曼增益 */
k->p += k->q; /* 预测:方差增大 */
kg = k->p / (k->p + k->r); /* 计算增益 */
k->x += kg * (z - k->x); /* 更新:按增益修正 */
k->p *= (1.0f - kg); /* 更新:方差收缩 */
return k->x;
}
以一维恒温估计为例验证收敛特性:标称 25.0℃ 的恒温箱,传感器读数叠加标准差 0.5℃ 的高斯噪声(R=0.25),取 Q=0.001,初值 x=24.0、P=1.0。逐次递推 20 步的结果节选如下(固定随机种子可复现):
| 步数 | 测量值 z(℃) | 卡尔曼增益 K | 估计值 x(℃) | 估计方差 P |
|---|---|---|---|---|
| 1 | 24.928 | 0.800 | 24.743 | 0.200 |
| 2 | 24.914 | 0.446 | 24.819 | 0.111 |
| 5 | 24.936 | 0.196 | 24.968 | 0.049 |
| 10 | 25.058 | 0.109 | 24.909 | 0.027 |
| 15 | 24.631 | 0.083 | 24.993 | 0.021 |
| 20 | 24.947 | 0.072 | 25.013 | 0.018 |
可见卡尔曼增益从初期的 0.8 快速衰减到 0.07 附近,估计值从初值 24.0 收敛并稳定在 25.0 附近,估计方差从 1.0 收缩到 0.018。与一阶滞后(a=0.5)对比,同样 20 步内一阶滞后输出在 24.46~25.31 之间波动,而卡尔曼估计的最大偏差不超过 0.2℃,收敛更快且稳态更稳。Q/R 整定原则:R 取传感器实测噪声方差;Q 反映过程模型的可信度,跟踪快速变化时适当增大 Q(如 0.01~0.1),恒温缓变场景取小 Q(如 0.001)。
把算法与现场场景对应起来,可按下表快速决策。需要说明的是,多数工程现场并非单一干扰,组合使用(如限幅前置+滑动平均后置)比单一算法更可靠;滤波器引入的相位延迟与响应速度需要在系统层面权衡。
| 应用场景 | 信号特征 | 推荐滤波组合 |
|---|---|---|
| RTU 模拟量采集(4-20mA) | 工频耦合+随机噪声 | 滑动平均 或 加权滑动平均 |
| 称重/力传感器 | 冲击+机械振动 | 中位值平均滤波 |
| 温度采集(慢变) | 高频噪声 | 一阶滞后 或 算术平均 |
| 液位/接近/按键开关量 | 抖动误触发 | 消抖滤波 或 限幅消抖 |
| 变频器环境下的信号 | 强脉冲群干扰 | 限幅+中值组合 |
| IMU 姿态/运动估计 | 动态变化+噪声 | 卡尔曼滤波 |
最后给出三点工程建议:一是滤波参数(限幅阈值 A、窗口 N、权重 a、Q/R)必须按被测信号的实际带宽与现场干扰强度标定,不能照抄;二是滤波放在 AD 采样后、控制/上传前,且要统一采样周期;三是若系统已有其他滤波环节(如硬件 RC 低通),数字滤波应与其配合而非叠加,避免过度滤波造成响应迟钝。站内《中值滤波分析》一文对中值滤波的窗口选择有更细致的讨论,可与本文互相印证。
数字滤波的工程本质是"以延迟换平滑、以复杂度换抗扰":脉冲干扰用限幅/中值/消抖,随机噪声用平均族,慢变信号用一阶滞后,动态估计用卡尔曼滤波。卡尔曼滤波通过 Q/R 两个参数即可在平滑度与跟踪速度之间连续调节,是嵌入式端性价比最高的动态滤波手段。本文基于《数字滤波常用的软件方法代码实例》《数字滤波与卡尔曼滤波》等资料整理优化。
沧州艾诺威电子 — 国家高新技术企业,20+项国家专利
嵌入式系统开发 · 物联网方案 · AI智能硬件 · 一站式交付
电话:13930711029 | 邮箱:tech@czinv.com | 24小时内响应