在10km跑总结里提到:这次10km跑成绩的提高最重要因素是步频的提高。
在网上看了一些资料,提到提高步频的好处,并指出长跑理想的步频应该在每分钟180步左右,就开始尝试练习提高步频。但是跑起来并不知道怎样的频率才是合适的,还需要有工具测量才行。想到可以用手机的加速度传感器来测量,跑步时把手机绑在手臂上或者拿手上,测量手的摆动周期应该就可以计算出步频。
有了想法后,就考虑怎样实现。先要知道跑步时加速度传感器得到的数据会是怎样的,在market上找到软件Accelero-meter Log,能显出加速度传感器三轴数据的曲线。拿着手机跑了几步看看曲线,发现完全不是想象中那么简单:从曲线可以看出每跑一步的加速度变化,但并不是一步一个脉冲那么理想,而是大脉冲中包含着小脉冲,波形很不规则;更要命的是不同轴测量到的数据频率会不一样,软件应该按那个轴的数据计算?后来才想到不同轴测量数据频率不同的原因是手摆动的频率与身体重心上下移动的频率不一致,只是一半,再加上手的活动太自如了,跑动过程中会有不同的动作,都会引起加速度变化。
上网找到一个开源的Android计步器的代码,看看它怎么做,发现它只是将三个轴的数值加在一起,然后判断变化量。根据前面看得的数据波形,我感觉这样的算法太不靠谱了,再看看这个软件的用户评价,果然不佳。
这时想到Nike的配合iPhone使用的计步器,是藏在鞋里面的。它应该是感应脚的每次着地,而且计步器是固定在鞋里的,有特定的安装方向,因此它可以只检测垂直地面的加速度。想到这里就豁然开朗了,原来测量摆臂的想法是错误的,应该测量脚着地的冲击,也就是垂直方向的加速度。但那个轴才是垂直地面的呢?我不能规定用户使用这个软件时手机摆放的方向啊,他可以绑在臂上,拿在手里,放裤袋中。。。因此首先要解决的问题是如何判断手机的姿态,找出垂直于地面的轴。
人在运动的时候加速度不断变化,但加速度矢量一段时间的累计应该为零,而重力加速度是恒定的,并且垂直于地面,检测出重力加速度的方向就ok了。具体实现的方法也比较简单:对传感器三个轴的数据分别做截止频率为0.25Hz的低通滤波后,数值最大的那个轴应该就是最接近于垂直地面的。
还有个问题是手机加速度传感器的采样频率能到多高?是否能满足要求?长跑理想的着地次数是每分钟180次,相当于3Hz,一般人都只会比这个慢。实测我的Nexus One使用最短采样间隔时大约30~50ms能获取到一组数据,也就是采样频率大于20Hz,对于检测3Hz的信号完全足够。
对于复杂波形的处理方法,同样是简单的一阶低通滤波,截止频率取了3.5Hz,相当于每分钟210次着地。高频干扰通过滤波削弱后,相邻波峰的时间间隔就是两次着地的时间间隔了。具体实现时,波峰判断会比较麻烦,采样检查是否超过阈值来代替。本来想按振幅比例来设定阈值的,但算振幅也比较麻烦,之前检测重力加速度时已经得到重力加速度在测量轴上的分量,直接拿它的1/2做阈值就好了。这样做还带来了一个没有预料到的副作用:走路时脚步比较轻,超不过阈值,因此软件还能知道当前是否处于跑步状态。
步频数据算出来以后其他的就好办了。跑步时不方便看屏幕,通过语音合成播放出来。设定目标步频,语音提示应该加快还是减慢。还打算过增加个目标步频的节拍音,当实际步频与目标不一致时播放出来,不过软件用了这段时间,感觉有语音播报步频基本上已经足够了,暂时不做以后再说吧。
这个软件项目的网站: http://code.google.com/p/running-cadence/
软件发布在Android Market:https://market.android.com/details?id=leoliang.runningcadence