第四章 信号处理与滤波:低通滤波、卡尔曼滤波入门,传感器噪声处理

各位同学,今天我们来聊聊信号处理。说实话,做车辆控制这几年,我最大的体会就是:控制算法再牛,信号不好也是白搭。传感器噪声处理不好,你的PID参数调得再漂亮,车跑起来照样抖得像筛糠。

我记得刚入行那会儿,有个项目让我印象特别深。一辆试验车,低速行驶时方向盘左右摆动,幅度不大但频率很高。我折腾了三天,调参数、改策略,都没用。最后发现——是转向角传感器的噪声没滤干净。从那以后,我养成了一个习惯:先看信号质量,再谈控制算法

4.1 传感器噪声从哪来?

车辆上的传感器,说白了就是暴露在各种干扰环境下的。你想想看,发动机振动、电磁干扰、路面颠簸、温度变化……这些都会在传感器输出上叠加噪声。

常见的噪声类型有这么几种:

  • 白噪声:频率分布均匀,像收音机里的沙沙声
  • 低频漂移:传感器受温度影响,输出缓慢变化
  • 脉冲噪声:瞬间的尖峰,比如电磁干扰
  • 高频振动噪声:发动机或路面激励引起的

我个人的经验是,先搞清楚噪声的频率范围,再决定用什么滤波器。这就像看病,得先诊断再开药。

核心原则:滤波器的截止频率,要高于你关心的信号频率,低于噪声的主要频率。留出安全余量,一般取中间值的1/3到1/2。

4.2 低通滤波:最简单也最实用

低通滤波,说白了就是让低频信号通过,把高频噪声滤掉。在车辆控制里,这是用得最多的滤波器。

最经典的就是一阶RC低通滤波,离散化之后长这样:

y[n] = α * x[n] + (1-α) * y[n-1]

其中:

  • y[n] 是当前滤波后的值
  • x[n] 是当前原始采样值
  • y[n-1] 是上一次滤波后的值
  • α 是滤波系数,范围0到1

α 怎么取?这里有个公式:

α = 1 / (1 + 2π * f_c * T)

其中 f_c 是截止频率(Hz),T 是采样周期(秒)。

我的小技巧:α 越小,滤波效果越强,但延迟也越大。α 取0.1到0.3之间,一般够用。我曾经在ESP项目中,把α设成0.05,结果信号平滑了,但车辆响应慢了半拍,差点出问题。嗯,滤波不是越强越好

实际代码实现很简单:

// 一阶低通滤波
float lowpass_filter(float input, float prev_output, float alpha) {
    return alpha * input + (1.0f - alpha) * prev_output;
}

// 使用示例
float filtered_speed = lowpass_filter(raw_speed, prev_filtered_speed, 0.15f);
prev_filtered_speed = filtered_speed;

为什么说它实用?因为计算量极小,在嵌入式MCU上跑毫无压力。我做过一个项目,用8位单片机,采样率1000Hz,跑这个滤波只占不到1%的CPU。

4.3 卡尔曼滤波入门

低通滤波虽然好用,但有个硬伤——它只考虑当前值,不考虑系统模型。说白了,它不知道你的信号应该怎么变化。

卡尔曼滤波就不一样了。它结合了系统模型观测数据,给出最优估计。听起来高大上,其实核心思想就一句话:预测 + 修正

我举个例子。你开车时想估计车速,有两种信息来源:

  1. 模型预测:根据上一时刻车速和加速度,估算当前车速
  2. 传感器测量:轮速传感器直接测到的车速

两个都不完美。模型有误差,传感器有噪声。卡尔曼滤波做的就是加权平均——谁的置信度高,就多信谁。

卡尔曼滤波的五个核心公式:

// 预测步骤
x_pred = A * x_est + B * u          // 状态预测
P_pred = A * P_est * A^T + Q        // 协方差预测

// 更新步骤
K = P_pred * H^T * (H * P_pred * H^T + R)^(-1)  // 卡尔曼增益
x_est = x_pred + K * (z - H * x_pred)           // 状态更新
P_est = (I - K * H) * P_pred                    // 协方差更新

看着复杂?别怕。我拆开讲:

  • x:你要估计的状态(比如车速、位置)
  • P:估计的不确定性(协方差)
  • Q:模型噪声(你有多相信模型)
  • R:测量噪声(你有多相信传感器)
  • K:卡尔曼增益(加权系数)

调参口诀:Q大R小,相信传感器;Q小R大,相信模型。我一般先设Q和R为对角矩阵,然后根据实际效果微调。

一个简单的车速估计例子:

// 一维卡尔曼滤波(车速估计)
typedef struct {
    float x;  // 估计值
    float P;  // 估计协方差
    float Q;  // 过程噪声
    float R;  // 测量噪声
} Kalman1D;

float kalman_update(Kalman1D *kf, float measurement) {
    // 预测
    float x_pred = kf->x;
    float P_pred = kf->P + kf->Q;
    
    // 更新
    float K = P_pred / (P_pred + kf->R);
    kf->x = x_pred + K * (measurement - x_pred);
    kf->P = (1.0f - K) * P_pred;
    
    return kf->x;
}

注意:卡尔曼滤波假设噪声是高斯分布。如果你的传感器噪声不是高斯分布(比如有脉冲干扰),需要先做预处理。我曾经在项目中遇到过GPS信号跳变,卡尔曼滤波直接发散,后来加了中值滤波做预处理才解决。

4.4 实际工程中的噪声处理策略

讲完了理论,说说实际怎么干。我总结了一套三层滤波策略

层级 方法 适用场景 计算开销
第一层 硬件滤波(RC电路) 高频噪声,如电源纹波
第二层 软件低通/中值滤波 常规噪声,如传感器白噪声
第三层 卡尔曼滤波 需要融合多传感器,或需要状态估计

具体到车辆控制,我常用的组合是:

  • 轮速信号:一阶低通滤波,α取0.2-0.3
  • 加速度信号:先中值滤波去脉冲,再低通滤波
  • GPS/IMU融合:卡尔曼滤波,Q和R根据车速动态调整
  • 转向角信号:低通滤波 + 限幅处理

避坑指南:我曾经在某个项目中,把所有传感器都用同样的滤波器参数。结果低速时信号延迟太大,高速时噪声又没滤干净。后来我学乖了——滤波参数要随工况变化。低速时α大一点(响应快),高速时α小一点(平滑好)。

4.5 滤波器选型决策树

最后,我给大家一个实用的决策思路。当你面对一个传感器信号时,按这个顺序问自己:

  1. 噪声频率高吗? → 是 → 低通滤波
  2. 有脉冲干扰吗? → 是 → 先中值滤波,再低通
  3. 需要融合多个传感器? → 是 → 卡尔曼滤波
  4. 计算资源紧张? → 是 → 一阶低通就够了
  5. 信号延迟敏感? → 是 → 用高阶滤波器或自适应滤波

说实话,80%的工程问题,一个一阶低通滤波就能解决。剩下的20%,才需要上卡尔曼滤波。别一上来就整复杂的,简单有效才是王道

好了,这一章就到这里。下一章我们讲状态观测器,到时候你会看到,卡尔曼滤波其实只是观测器的一种特例。嗯,保持期待。