基于手机 IMU 的 PDR 算法学习:四阶巴特沃斯低通滤波到底在做什么?

一、前言

在手机 IMU 的 PDR 算法中,步伐检测并不是直接拿原始加速度数据来判断的。

手机加速度计采集到的数据通常非常"脏",里面既有真实走路带来的周期性波动,也有手部抖动、传感器噪声、手机姿态变化、瞬时冲击等干扰。

如果直接用原始加速度去做波峰、波谷检测,很容易出现误计步。

所以,在当前 PDR 算法中,会先对加速度信号做一层预处理,其中非常关键的一步就是:

四阶巴特沃斯低通滤波

它的作用不是直接算步长,也不是直接算位置,而是把原始加速度曲线变得更加平滑,让后面的峰谷检测更稳定。

本文就围绕这个问题展开:

当前 PDR 算法里的四阶巴特沃斯低通滤波到底是怎么做的?

它为什么要放在峰谷检测之前?

它在整个 PDR 流程中到底起什么作用?


二、 PDR 算法中滤波的位置

在PDR 算法中,加速度处理的大致流程是:

复制代码
手机 IMU 原始数据
ax, ay, az
        ↓
计算三轴加速度模长
sqrt(ax² + ay² + az²)
        ↓
减去重力 g
acc_norm = sqrt(ax² + ay² + az²) - g
        ↓
四阶巴特沃斯低通滤波
fil_Acc
        ↓
峰谷检测
peak / valley
        ↓
步伐质量门控
StepEvent
        ↓
步长估计
step.length
        ↓
结合航向 yaw_nav
        ↓
输出 PDR 位移增量 dx / dy

可以看到,四阶巴特沃斯低通滤波处在:

复制代码
加速度模长减重力之后
峰谷检测之前

也就是说,它处理的不是三轴原始加速度,而是已经变成一维的加速度波动信号:

滤波之后得到:

后续算法真正用来找波峰、波谷的,就是这个滤波后的:


三、为什么不能直接用原始加速度做步伐检测?

手机加速度计输出的是三个方向的数据:

但是用户拿手机的姿态不固定。

比如:

  • 手机可能竖着拿
  • 可能横着拿
  • 可能斜着拿
  • 也可能边走边转手机

如果直接看某一个轴,比如只看 aza_zaz​,那么手机姿态一变,数据就会明显变化。

所以当前算法先计算三轴模长:

这样不管手机横着、竖着、斜着,三轴合成后的总强度相对更稳定。

但是手机静止时,加速度模长也不是 0,而是接近重力加速度:

所以还要减去重力:

这样静止时信号会接近 0,走路时信号会围绕 0 上下波动。


四、减去重力后,为什么还要滤波?

减去重力之后,得到的是一条加速度波动曲线。

理想情况下,用户走路时,这条曲线应该是比较规律的波浪形:

复制代码
上升 → 到达波峰 → 下降 → 到达波谷 → 再次上升

但是实际手机采集的数据不会这么干净。

它可能包含:

干扰来源 表现
传感器噪声 小幅随机抖动
手部轻微晃动 额外的小波峰、小波谷
手机瞬间甩动 突然出现尖峰
姿态变化 整体曲线发生偏移
采样误差 相邻点之间不够平滑

如果不滤波,曲线可能会变成这样:

复制代码
上升、下降、上升、下降、上升、下降......

算法会误以为出现了很多波峰和波谷。

而 PDR 的步伐检测正是依赖波峰波谷的。

所以必须先滤波,让曲线更像真实走路波形,而不是一堆杂乱的小抖动。


五、什么是低通滤波?

低通滤波可以简单理解为:

低频信号通过,高频信号被削弱。

在人走路这个场景里,正常步态变化通常是比较慢的、有节奏的。

比如正常人走路,大概每秒 1 到 2 步左右,对应的信号频率通常集中在较低频率范围内。

而传感器噪声、手抖、小毛刺,往往变化很快,属于高频成分。

所以低通滤波的目的就是:

复制代码
保留:正常走路带来的低频周期波动
削弱:高频噪声、手部小抖动、瞬时尖峰

可以把低通滤波理解成一个筛子:

信号类型 是否保留
正常走路的周期性波动 尽量保留
高频小抖动 削弱
瞬时尖峰 削弱
传感器毛刺 削弱

六、为什么截止频率设置为 2 Hz?

当前算法中,采样频率大约是:

也就是说,手机每秒采集大约 100 个 IMU 数据点。

低通滤波的截止频率大约是:

这个参数的意思是:

2 Hz 以下的信号更可能是正常走路节奏,需要保留;

2 Hz 以上的快速变化,更可能是噪声或者抖动,需要压制。

人正常走路不会像机器震动一样一秒高频抖几十次。

所以对于步伐检测来说,2 Hz 左右的截止频率是一个偏稳的设置。

数字滤波器中还会用到归一化截止频率:

其中 s​/2 是奈奎斯特频率。

代入当前参数:

也就是说,在数字滤波器设计中,当前低通截止点大约是:

0.04

这个数值比较低,说明算法主要想保留慢速步态变化,把快速抖动压掉。


七、什么是巴特沃斯滤波器?

巴特沃斯滤波器是一种经典滤波器。

它最重要的特点是:

通带内非常平滑。

所谓通带,就是允许通过的频率范围。

对于当前 PDR 来说,低频步态信号就是希望保留下来的部分。

巴特沃斯滤波器不会在通带内产生明显波纹,也就是说,它不会一会儿把某些低频放大,一会儿又把另一些低频压低。

它的风格是:

复制代码
平滑、稳定、不过分改变低频信号形状

这对于步伐检测很重要。

因为我们希望滤波之后,走路波形仍然保持比较自然的峰谷结构,而不是被滤波器扭曲得太厉害。


八、为什么不用简单平均滤波?

有人可能会问:

直接用滑动平均不行吗?为什么要用巴特沃斯?

滑动平均当然也能让曲线变平滑,但它比较粗糙。

比如滑动平均可能带来:

  • 峰值被明显压低
  • 波峰位置发生延迟
  • 对不同频率的抑制不够精细
  • 窗口大小不好选

而巴特沃斯低通滤波器是从频率角度设计的。

它可以更明确地表达:

哪些频率要保留,哪些频率要削弱。

所以在 PDR 步态检测中,巴特沃斯低通比简单平均更适合做稳定的信号预处理。


九、四阶是什么意思?

"四阶"可以理解为滤波器的强度等级。

阶数越高,对高频信号的压制越强。

简单理解:

阶数 滤波特点
一阶 比较温和
二阶 滤波效果明显
四阶 对高频噪声压制更强
八阶 更强,但可能带来更大延迟和稳定性问题

当前算法使用的是四阶巴特沃斯低通滤波,说明它不是轻轻平滑一下,而是比较认真地压制高频噪声。

对于 PDR 来说,这是合理的。

因为步伐检测对波峰波谷比较敏感,如果高频抖动太多,很容易误判。


十、四阶滤波器通常怎么实现?

工程上,四阶巴特沃斯低通滤波器通常有两种实现方式。

一种是直接使用四阶差分公式。

另一种更常见、更稳定的方式是:

两个二阶滤波器串联。

也可以理解成:

复制代码
acc_norm
   ↓
二阶巴特沃斯滤波器 1
   ↓
中间输出 stage1
   ↓
二阶巴特沃斯滤波器 2
   ↓
最终输出 fil_Acc

写成公式就是:

两个二阶滤波器串起来,就形成了四阶滤波效果。

也就是说:

复制代码
二阶滤一遍,曲线已经变平滑;
再经过第二个二阶滤波器,噪声进一步被压制;
最终得到四阶低通滤波后的步态信号。

十一、二阶滤波器内部到底怎么算?

一个典型的二阶 IIR 滤波器公式是:

这个公式看起来复杂,但它的意思很简单:

当前输出不只由当前输入决定,还要参考之前的输入和之前的输出。

其中:

符号 含义
xn 当前输入
xn−1 上一次输入
xn−2 上上次输入
yn 当前输出
yn−1 上一次滤波输出
yn−2 上上次滤波输出
a1,a2,b0,b1,b2a_1,a_2,b_0,b_1,b_2a1​,a2​,b0​,b1​,b2​ 滤波器系数

这说明它是一个带记忆的滤波器

它不是只看当前这一个采样点,而是结合历史数据一起计算。

这也是它能把曲线变平滑的原因。


十二、滤波器为什么需要历史状态?

假设当前输入突然出现一个尖峰。

如果只看当前点,算法可能会认为这就是一个真实波峰。

但是滤波器会结合前面的输入和输出:

如果前面一直很平稳,当前突然跳很高,滤波器不会完全相信这个尖峰。

它会把这个尖峰压低一些,让输出变化更平滑。

所以滤波器本质上是在做一件事:

不要被某一个瞬间采样点带偏,要结合历史趋势判断当前输出。

这对于手机 IMU 特别重要,因为手机数据经常会突然抖一下。


十三、用伪代码理解当前滤波流程

当前算法的整体处理流程可以写成伪代码:

复制代码
# 1. 输入手机 IMU 三轴加速度
ax = imu.ax
ay = imu.ay
az = imu.az

# 2. 计算三轴加速度模长
acc_mag = sqrt(ax * ax + ay * ay + az * az)

# 3. 减去重力,得到加速度波动信号
acc_norm = acc_mag - gravity

# 4. 输入四阶巴特沃斯低通滤波器
fil_Acc = butterworth_filter.update(acc_norm)

# 5. 使用滤波后的加速度进行峰谷检测
detect_peak_valley(fil_Acc)

如果四阶滤波器用两个二阶滤波器串联,可以写成:

复制代码
# 计算加速度模长并减重力
acc_norm = sqrt(ax * ax + ay * ay + az * az) - gravity

# 第一级二阶滤波
stage1 = biquad1.update(acc_norm)

# 第二级二阶滤波
fil_Acc = biquad2.update(stage1)

每个二阶滤波器内部大概是:

复制代码
y = b0 * x + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2

# 更新历史输入
x2 = x1
x1 = x

# 更新历史输出
y2 = y1
y1 = y

return y

其中:

复制代码
x  :当前输入
x1 :上一次输入
x2 :上上次输入
y  :当前输出
y1 :上一次输出
y2 :上上次输出

这就是所谓的实时滤波。

每来一个新的 IMU 采样点,滤波器就更新一次。


十四、滤波前后数据有什么区别?

假设减去重力后的加速度数据是:

复制代码
0.02, 0.15, 0.70, 0.30, 1.80, -0.20, -0.65, -0.10, 0.35

其中 1.80 可能是手机突然晃动产生的尖峰。

如果直接拿这条曲线做峰谷检测,算法很可能把 1.80 当成一个强波峰。

经过低通滤波后,曲线可能变成类似:

复制代码
0.01, 0.08, 0.25, 0.36, 0.42, 0.18, -0.10, -0.28, -0.12

可以看到,尖峰没有完全消失,但被明显压平了。

这样后面的峰谷检测就不会被瞬时毛刺轻易欺骗。


十五、滤波对峰谷检测有什么帮助?

当前 PDR 的步伐检测主要依赖波峰和波谷。

大致判断逻辑是:

复制代码
曲线从上升变下降 → 可能是波峰
曲线从下降变上升 → 可能是波谷
波峰超过正阈值 → 记录波峰
波谷低于负阈值 → 记录波谷
波峰波谷配对 → 形成候选步
候选步通过质量门控 → 变成有效步

如果没有滤波,曲线可能因为高频抖动出现大量局部峰谷。

这会导致:

  • 误检测波峰
  • 误检测波谷
  • 候选步过多
  • 静止时误计步
  • 轻微晃手机时轨迹漂移

滤波之后,曲线变得更加接近真实步态波形:

复制代码
缓慢上升 → 明显波峰 → 缓慢下降 → 明显波谷 → 再次上升

这样峰谷检测才更稳定。


十六、滤波不是最终判断

需要注意的是,滤波只是信号预处理,不是最终的步伐判断。

也就是说:

经过滤波之后,不代表每个波峰波谷都一定是真实一步。

滤波之后还要经过:

  • 峰值阈值判断
  • 谷值阈值判断
  • 峰谷时间间隔检查
  • 峰谷幅值差检查
  • 相邻步最小间隔检查
  • 连续步步长突变检查

所以当前算法不是简单地:

复制代码
有波峰 = 有一步

而是:

复制代码
滤波后的曲线出现明显峰谷
        ↓
峰谷满足阈值要求
        ↓
峰谷时间合理
        ↓
峰谷幅值差合理
        ↓
相邻步间隔合理
        ↓
步长没有异常突变
        ↓
最终确认有效步

四阶巴特沃斯低通滤波只是把第一步做好,让后面的判断更可靠。


十七、为什么滤波不能太强?

滤波不是越强越好。

如果滤波太弱,高频噪声压不住,容易误计步。

如果滤波太强,真实步态也会被压掉,容易漏计步。

滤波太强可能带来几个问题:

问题 说明
峰值变低 原本明显的步态波峰被压小
波形延迟 滤波器输出比真实动作慢一点
快速步态被削弱 用户走得快时,部分步态信息可能被压掉
起步响应慢 刚开始走时,滤波器状态需要时间跟上

所以当前算法使用四阶巴特沃斯低通,是一种折中。

它的目标是:

复制代码
尽量压制高频噪声
但不要破坏正常走路的主要波形

十八、为什么四阶滤波会带来延迟?

因为滤波器使用了历史输入和历史输出。

当前输出: yn 不仅和当前输入: xn有关,还和之前的输入输出有关:

xn−1,xn−2,yn−1,yn−2

这会让滤波结果更加平滑,但也会让信号变化稍微滞后。

在 PDR 中,这种延迟一般是可以接受的。

因为步伐检测本身不要求毫秒级瞬时反应,更重要的是不要误计步。


十九、四阶巴特沃斯滤波在当前算法中的核心价值

在当前 PDR 中,四阶巴特沃斯低通滤波的价值可以总结为四点。

第一,减少传感器噪声。

手机 IMU 数据天然存在小幅随机波动,滤波可以让曲线更稳定。

第二,压制手部小抖动。

用户拿手机时,手部轻微晃动会产生很多小波峰、小波谷,滤波可以削弱它们。

第三,降低瞬时冲击影响。

手机突然甩一下、碰一下,可能产生尖峰。低通滤波可以把这种尖峰压平。

第四,提高峰谷检测稳定性。

滤波后的曲线更接近真实走路波形,后面的峰谷检测、步伐门控和步长估计都会更可靠。


二十、它和步长估计有什么关系?

当前算法的步长估计依赖峰谷差。

也就是:

再使用 Weinberg 类模型估计步长:

如果滤波前曲线噪声很大,峰值和谷值可能不稳定。

这样会导致:

  • 峰谷差偏大
  • 步长估计偏大
  • 轨迹出现跳点

或者:

  • 峰谷差被噪声扰乱
  • 步长忽大忽小
  • 轨迹不平滑

所以滤波不仅影响"有没有检测到一步",还会间接影响"这一步估计多长"。