第4章:零速检测算法
零速检测,说白了就是判断行人脚是不是「粘」在地上了。我刚开始做惯导时,觉得这步很简单——脚不动就是零速呗。后来发现,事情远没那么简单。
你想想看,人在走路时,脚掌落地那一瞬间,速度真的为零吗?其实不是。严格来说,脚底和地面接触时,会有微小的滑动和形变。我们说的「零速」,是一个近似状态。检测这个状态,就是零速检测算法的核心任务。
我个人习惯把零速检测算法分成五类。咱们一个一个来看。
4.1 加速度幅值检测法
这个方法最直观。当脚静止时,加速度计只感受重力。理想情况下,加速度幅值就是1g(约9.8 m/s²)。
判断逻辑很简单:
|acc_norm - g| < threshold_acc
其中 acc_norm 是加速度三轴幅值,g 是当地重力加速度,threshold_acc 是阈值。
我在项目中遇到过一个问题:阈值设得太小,正常走路时频繁漏检;设得太大,又把摆动阶段误判为零速。嗯,这里要注意,加速度幅值法对剧烈运动很敏感,但慢走时效果一般。
4.2 角速度幅值检测法
这个方法我更喜欢。为什么?因为脚落地时,角速度变化比加速度更明显。你想想看,脚在空中摆动时,角速度很大;一落地,角速度瞬间掉到接近零。
判断逻辑:
|gyro_norm| < threshold_gyro
角速度幅值法有个好处——对重力变化不敏感。你在斜坡上走,加速度幅值会变,但角速度幅值不会。我曾经在楼梯测试中吃过亏,加速度法频繁误判,换成角速度法就稳了。
4.3 加速度方差检测法
这个方法看的是加速度的「波动程度」。脚静止时,加速度值很稳定,方差小;脚运动时,加速度剧烈变化,方差大。
计算方式:
var_acc = variance(acc_x, acc_y, acc_z) // 滑动窗口内计算方差
if var_acc < threshold_var:
判定为零速
滑动窗口长度很关键。我建议取 5~10 个采样点(对应 0.05~0.1 秒)。窗口太短,方差不稳定;窗口太长,会延迟检测。
说实话,方差法单独用效果一般。我习惯把它和幅值法组合起来用。
4.4 组合检测法
这才是工程上最常用的方案。把加速度幅值、角速度幅值、加速度方差三个条件组合起来,同时满足才判定为零速。
逻辑如下:
if (|acc_norm - g| < th_acc) AND
(|gyro_norm| < th_gyro) AND
(var_acc < th_var):
判定为零速
else:
判定为运动
为什么用组合?因为单一方法都有盲区。加速度幅值法在斜坡上会误判,角速度法在慢速转身时可能漏检,方差法对高频噪声敏感。三个条件一组合,鲁棒性就上来了。
我在做室内定位项目时,用的就是组合检测法。实测下来,零速检测准确率从单方法的85%提升到了97%以上。
4.5 自适应阈值设计
固定阈值有个硬伤——不同人走路习惯不同,不同地面材质也不同。你想想看,在水泥地上走和草地上走,传感器噪声能一样吗?
自适应阈值就是让算法自己「学习」阈值。我常用的方法有两种:
- 基于统计的自适应: 实时计算加速度和角速度的均值和标准差,阈值 = 均值 + k * 标准差。k 一般取 2~3。
- 基于运动强度的自适应: 用滑动窗口内的能量值来动态调整阈值。运动强度大时,阈值放宽;运动强度小时,阈值收紧。
代码实现思路:
// 滑动窗口内计算统计量
mean_acc = mean(window_acc)
std_acc = std(window_acc)
th_acc = mean_acc + 2.5 * std_acc
// 同样方法计算角速度阈值
mean_gyro = mean(window_gyro)
std_gyro = std(window_gyro)
th_gyro = mean_gyro + 2.5 * std_gyro
我曾经在自适应阈值上栽过跟头。有一次测试,用户突然从走路变成跑步,自适应阈值没跟上,导致连续漏检了好几步。后来我加了「阈值变化速率限制」,问题就解决了。
知识体系总览
下面这张图,是我梳理的零速检测算法知识结构。你可以看到,五种方法各有侧重,组合检测是工程落地的首选。
好了,零速检测算法就讲到这里。每种方法都有它的脾气,你得根据实际场景去调参。下一章,咱们聊聊零速修正的具体实现——怎么用卡尔曼滤波把零速信息用起来。
公众号:蓝海资料掘金营,微信deep3321