23、传感器数据滤波算法:简单移动平均滤波、卡尔曼滤波入门
各位同学,今天我们来聊聊传感器数据里一个绕不开的话题——滤波。
你想想看,霍尔传感器虽然皮实,但读回来的数据从来都不是“干干净净”的。噪声、抖动、偶尔的毛刺,这些都是家常便饭。我刚开始做项目那会儿,就吃过这个亏。直接拿原始数据去算转速,结果数值跳得像心电图,根本没法用。
所以,滤波不是“锦上添花”,而是“雪中送炭”。今天我会带大家入门两种最实用的滤波方法:简单移动平均滤波和卡尔曼滤波。一个简单粗暴,一个优雅精准。咱们一个一个来。
23.1 为什么霍尔传感器数据需要滤波?
霍尔传感器输出的信号,本质上是一个数字电平(高/低)或者模拟电压。但实际场景中,电机转动带来的电磁干扰、机械振动、电源纹波,都会让信号产生“毛刺”。
举个例子:你测量一个稳定的磁场,理想情况下读数应该是固定的。但实际读出来可能是:512, 515, 508, 520, 511……这种小幅波动,如果不处理,后续计算出来的位置或速度就会忽高忽低。
核心观点:滤波的目的不是“消除真实变化”,而是“抑制噪声,保留真实信号”。
23.2 简单移动平均滤波(SMA)
这是我最喜欢给新手推荐的算法。为什么?因为它够简单,够直观,而且效果立竿见影。
23.2.1 原理一句话
把最近 N 次采样值存起来,每次取平均值作为当前输出。说白了,就是“取个平均数,把抖动抹平”。
23.2.2 数学公式
假设当前时刻为 k,采样值为 x(k),滤波输出为 y(k),窗口大小为 N:
y(k) = ( x(k) + x(k-1) + ... + x(k-N+1) ) / N
23.2.3 代码实现(C语言风格)
#define WINDOW_SIZE 5
int buffer[WINDOW_SIZE] = {0};
int index = 0;
int sum = 0;
int moving_average(int new_sample) {
sum -= buffer[index]; // 去掉最旧的值
buffer[index] = new_sample; // 存入新值
sum += buffer[index]; // 更新总和
index = (index + 1) % WINDOW_SIZE;
return sum / WINDOW_SIZE; // 返回平均值
}
我的经验:窗口 N 不要选太大。我见过有人为了“更平滑”把 N 设成 50,结果传感器动半天了,输出还在慢慢爬。N 一般取 3~10 就够用了。具体多大,看你系统的采样率和噪声频率。
23.2.4 优缺点
| 优点 | 缺点 |
|---|---|
| 实现简单,计算量小 | 有延迟,N越大延迟越大 |
| 对周期性噪声抑制效果好 | 对突发性毛刺抑制一般 |
| 不需要复杂的数学背景 | 无法区分噪声和真实变化 |
23.3 卡尔曼滤波入门
如果说移动平均是“大刀”,那卡尔曼滤波就是“手术刀”。它不仅能滤除噪声,还能根据模型预测下一时刻的值,做到“边预测边修正”。
嗯,我知道一提到卡尔曼,很多人就头大。别怕,咱们只讲入门,不推公式。我当年第一次看卡尔曼的论文,也是云里雾里。后来发现,其实核心思想就五个字:预测 + 修正。
23.3.1 核心思想
卡尔曼滤波假设系统是线性的,噪声是高斯白噪声。它用两个步骤循环:
- 预测:根据上一时刻的状态,预测当前时刻的状态和误差。
- 更新:用当前测量值,修正预测值,得到最优估计。
23.3.2 简化版公式(一维情况)
对于霍尔传感器这种一维数据(比如角度、磁场强度),我们可以用简化版本:
// 预测
x_pred = x_last; // 状态预测(假设不变)
p_pred = p_last + Q; // 误差协方差预测
// 更新
K = p_pred / (p_pred + R); // 卡尔曼增益
x_est = x_pred + K * (measurement - x_pred); // 最优估计
p_est = (1 - K) * p_pred; // 更新误差协方差
// 为下一轮做准备
x_last = x_est;
p_last = p_est;
其中:
Q:过程噪声协方差(模型的不确定性)R:测量噪声协方差(传感器的噪声水平)K:卡尔曼增益(决定相信预测还是测量)
注意:Q 和 R 是调参关键。我曾经在一个项目中,把 R 设得太小,结果卡尔曼完全跟着测量值跑,滤波等于没开。后来把 R 调大了一点,效果才出来。记住:R 越大,越相信预测;R 越小,越相信测量。
23.3.3 卡尔曼滤波 vs 移动平均
| 对比项 | 移动平均 | 卡尔曼滤波 |
|---|---|---|
| 计算量 | 极低 | 中等(需要浮点运算) |
| 延迟 | 固定延迟(N/2个采样周期) | 延迟小,自适应 |
| 对突变响应 | 慢 | 快(通过调整Q/R可控制) |
| 适用场景 | 噪声平稳、对延迟不敏感 | 噪声变化、需要实时跟踪 |
23.4 知识体系与选择逻辑
下面这张图,是我自己总结的滤波算法选择逻辑。你一看就明白什么时候该用谁。
23.5 实战避坑指南
最后,分享几个我踩过的坑,希望能帮你省点时间。
- 移动平均的边界处理:刚开始采集时,buffer 还没填满。我建议前 N 次直接返回原始值,或者用已采集到的数据做平均,不要补0,否则前几个输出会严重偏低。
- 卡尔曼的初始值:p_last 初始值不要设0。我一般设一个较大的数(比如100),这样卡尔曼一开始会快速收敛。设0的话,它可能永远不相信测量值。
- 数据类型:移动平均用整数运算就够了,但卡尔曼最好用浮点数。如果MCU没有FPU,可以用定点数模拟,但要注意精度损失。
- 调试技巧:我曾经把原始数据和滤波后的数据同时通过串口打印出来,用串口绘图工具(比如Serial Plotter)看波形。一眼就能看出滤波效果好不好,比看数字直观多了。
总结一下:移动平均滤波适合“稳、准、不着急”的场景;卡尔曼滤波适合“快、变、有要求”的场景。两种算法都不难,关键是要理解它们的适用边界。动手写一遍代码,跑一跑数据,比看十遍理论都管用。
好了,今天的内容就到这里。滤波算法是传感器应用的基石,掌握好了,后面的项目会顺手很多。
公众号:蓝海资料掘金营,微信deep3321