9、数据滤波基础:为什么需要滤波,简单的低频滤波实现

各位同学,欢迎来到第九章。

前面几章我们讲了怎么读陀螺仪的数据,怎么把原始数据转换成角度。但不知道你有没有发现——你拿到的数据,其实并不干净。

嗯,这里我要先泼一盆冷水:传感器数据天生就是脏的

9.1 为什么需要滤波?

先说说我自己的经历。几年前我做了一个手机姿态跟踪的小项目,陀螺仪数据直接拿来用,结果呢?手机明明放在桌上不动,屏幕上那个小飞机却在疯狂抖动。我当时差点以为是传感器坏了。

后来一查,不是硬件问题。是噪声。

陀螺仪的噪声来源主要有这几个:

  • 电子热噪声——芯片内部电子热运动产生的随机波动
  • 量化噪声——ADC把模拟信号转成数字时,精度有限
  • 机械振动——你手拿手机时,肌肉微颤也会被捕捉到
  • 电源纹波——供电不稳定,数据就会跳

说白了,你读到的每一个数值,都是「真实信号 + 噪声」的混合体。如果不做处理,你的应用就会跟着噪声一起抽风。

核心结论:滤波的目的不是消除噪声——那做不到。滤波的目的是抑制噪声,保留有用信号

9.2 滤波的分类,简单了解一下

滤波方法很多,但入门阶段你只需要知道两大类:

类型 特点 适用场景
低通滤波 允许低频信号通过,抑制高频噪声 陀螺仪、加速度计数据平滑
高通滤波 允许高频信号通过,抑制低频漂移 去除重力分量、检测快速动作
带通滤波 只保留某个频率范围的信号 特定频率检测(如步频)
卡尔曼滤波 融合多传感器,最优估计 姿态解算、导航定位

对于陀螺仪入门,低通滤波是你第一个要掌握的。为什么?因为陀螺仪的噪声主要在高频段,而你要的姿态变化是低频的。一刀切下去,噪声就没了大半。

9.3 最简单的低通滤波——一阶RC低通滤波

你可能会想:滤波是不是要学一堆傅里叶变换、拉普拉斯变换?

别怕。最简单的低通滤波,只需要一行代码。

它的数学原理其实就是一个加权平均:

output = alpha * input + (1 - alpha) * last_output

其中 alpha 是一个0到1之间的系数,决定了滤波的强弱。

  • alpha 越大,滤波越弱,响应越快,但噪声也多
  • alpha 越小,滤波越强,数据越平滑,但响应变慢

我个人的习惯是:alpha 取 0.1 ~ 0.3 之间。这个范围对大多数陀螺仪应用都够用。

9.4 Android 代码实现

下面是一个完整的低通滤波实现。你直接复制就能用:

public class LowPassFilter {
    private float lastValue = 0f;
    private boolean isFirst = true;

    /**
     * 对陀螺仪数据进行低通滤波
     * @param input     当前原始数据
     * @param alpha     滤波系数,推荐 0.1 ~ 0.3
     * @return          滤波后的数据
     */
    public float filter(float input, float alpha) {
        if (isFirst) {
            lastValue = input;
            isFirst = false;
            return input;
        }
        lastValue = alpha * input + (1 - alpha) * lastValue;
        return lastValue;
    }

    // 重置滤波器(比如传感器断开重连时)
    public void reset() {
        isFirst = true;
        lastValue = 0f;
    }
}

用法也很简单:

LowPassFilter filterX = new LowPassFilter();
LowPassFilter filterY = new LowPassFilter();
LowPassFilter filterZ = new LowPassFilter();

// 在 onSensorChanged 里
float filteredX = filterX.filter(rawX, 0.2f);
float filteredY = filterY.filter(rawY, 0.2f);
float filteredZ = filterZ.filter(rawZ, 0.2f);

小技巧:三个轴最好各自用一个滤波器实例。不要共用一个,否则数据会串。

9.5 滤波效果对比

我曾经在调试时做过一个对比测试。手机静止放在桌上,分别采集原始数据和滤波后的数据:

指标 原始数据 滤波后 (alpha=0.2)
均值 0.02 rad/s 0.01 rad/s
标准差 0.15 rad/s 0.04 rad/s
最大跳变 0.45 rad/s 0.12 rad/s

看到没?标准差从0.15降到了0.04,噪声抑制了将近4倍。而均值几乎没有变化——说明有用信号被保留下来了。

9.6 避坑指南

我曾经踩过的一个坑:alpha值设得太小(比如0.01),结果数据是平滑了,但手机转了个90度,滤波后的角度要等两三秒才跟上来。这种延迟在交互式应用里是完全不能接受的。

所以记住:滤波不是越强越好。你要在「平滑」和「响应速度」之间找平衡。

另外还有几点要注意:

  • 滤波器要重置——传感器断开重连时,记得调用 reset(),否则初始值会污染新数据
  • 不要对角度做滤波——如果你已经把角速度积分成了角度,再去滤波,会引入额外的相位延迟。滤波应该在原始数据上做
  • alpha值可以动态调整——检测到剧烈运动时增大alpha,静止时减小alpha。这个技巧叫「自适应滤波」,后面章节会讲

9.7 本章知识结构图

下面这张图帮你理清本章的核心逻辑:

数据滤波基础 · 知识结构 为什么需要滤波? 噪声污染真实信号 滤波分类 低通 / 高通 / 带通 / 卡尔曼 低通滤波 入门首选 一阶RC低通滤波 output = alpha * input + (1-alpha) * last_output Android 实现与注意事项 三轴独立滤波 · 重置机制 · alpha动态调整 在原始数据上滤波 · 平衡平滑与响应速度

9.8 小结

这一章我们聊了:

  • 为什么陀螺仪数据需要滤波——噪声无处不在
  • 滤波的分类——低通滤波是入门首选
  • 一阶RC低通滤波的原理——就是一个加权平均
  • Android代码实现——三行核心代码搞定
  • 避坑指南——alpha值别设太小,滤波器要重置

说实话,低通滤波看起来简单,但它是所有高级滤波算法的基础。你把这个搞明白了,后面学卡尔曼滤波、互补滤波都会轻松很多。

下一章我们会聊一个更实际的问题:如何用陀螺仪数据计算设备的姿态角。到时候你会看到,滤波只是第一步,真正的挑战还在后面。


公众号:蓝海资料掘金营,微信deep3321