学习Android已经快一年了,一直在阅读专家分享的知识。 今天我也想分享一下我之前对计步器算法的一些研究。 目前在计步器领域处于领先地位的优乐动力和春雨计步器,在调试算法参数时总会比较这两款应用。 乐力电源当之无愧的行业第一。 无论是应用体验还是准确度都非常出色。 春雨计步器的亮点在于其轻巧且易于使用和操作的界面。 以前因为一些需要,需要做一个计步器,所以就开始自己研究算法。 在各种场景下(走路、拿在手上、放在口袋里、跑步),算法的准确率都能达到95.7%左右。 综合起来,我认为它比春雨略好,但无法击败乐力动力(可以达到97.7%)。 在经验和大局观为王的互联网时代,我认为技术差距会越来越小。 重要的是经验和产品定位。 ,所以我决定把算法分享给大家。 首先,希望能够对大家有所帮助。 其次,我也希望大家能够提供一些意见,以便这个算法能够得到改进。
计步器 apk 下载
apk反编译下载
2、计步算法总体思路及辅助调试工具
人们在走路时一般会陷入以下几种场景:
1. 正常走路,手里拿着手机(走路时看手机,晃动手,或者不晃动手)
2、慢慢走,手里拿着手机(边走边看,晃动手,或者不晃动手)
3.快走麻将胡了2游戏入口,手里拿着手机(要么抖手pg电子游戏官网官方网站,要么不抖手,如果走得很快,一般不会看手机)
4. 将手机放入裤兜(慢走、快走、正常行走)
5. 将手机放入外套口袋(慢走、快走、正常行走)
6、上下楼梯(本场景可以再次应用以上五个场景)
上面,无论是哪种场景(其实是对应手机不同的运动模式),G-Sensor的三轴数据都可以找到有规律的模式。
每一步都有一个特征点。 找到这个特征点就意味着识别出一个步骤。
下面推荐一个工具,叫gsensor-debug,可以观察三轴曲线。 下面是手机上下摆动的曲线。
这是一条非常规则的曲线。 只需检测峰值即可。 实际行走曲线会有很多杂乱。 算法的作用就是过滤掉这些杂乱的东西(行走波形可以自己用工具查看,可以保存为文件用Excel打开就有数据了,把数据转成波形就可以自己看到了) )
三、算法介绍(贴出核心代码) 1、变量的定义 //三轴数据的存储 float[] oriValues = new float[3]; 最终 int valueNum = 4; //用于存储峰谷差值,用于计算阈值 Value float[] tempValue = new float[valueNum]; int tempCount = 0; //上升标志 boolean isDirectionUp = false; //连续上升次数 int continueUpCount = 0; //从上一点开始连续上升的次数,用于记录波峰的上升次数 int continueUpFormerCount = 0; //上一个点的状态pg电子游戏官网官方网站,上升还是下降 boolean lastStatus = false; //波浪峰值 float PeakOfWave = 0; //波浪的谷值 float ValleyOfWave = 0; //该波峰值的时间 long timeOfThisPeak = 0; //最后一个峰值的时间 long timeOfLastPeak = 0; //当前时间 long timeOfNow = 0; //当前传感器float的值gravityNew = 0; //最后一个传感器浮点数的值gravityOld = 0; //动态阈值需要动态数据,这个值就是用来做这些动态数据的阈值的 Final float initialValue = (float) 1.3; //初始阈值 float ThreadValue = (float) 2.0; 私有StepListener mStepListeners;
2.代码,结合注释
检测步骤是检测波峰,但为了滤除无效波峰,主要采用以下三个措施
A。 指定曲线连续上升的次数
b. 峰值和谷值之间的差值需要大于阈值。
C。 阈值动态变化
另外就是一些参数的初始值,比如initialValue和ThreadValue的初始值,averageValue函数的梯度范围值。
需要结合各种场景的波形图进行统计,并进行数十次实际测试来调试参数。 这些参数的调整大约需要两周时间。 其实整体思路并不复杂。
下面贴出核心代码和一些注释:
(由于某些原因,我不会上传整个项目。稍后有时间可以上传应用程序)
/*
* 该函数只有在注册G-Sensor后才会被调用
* 对三轴数据进行平方和根处理
* 调用DetectorNewStep检测步数
* */
@覆盖
公共无效onSensorChanged(传感器事件事件){
for (int i = 0; i < 3; i++) {
oriValues[i] = event.values[i];
gravityNew = (float) Math.sqrt(oriValues[0] * oriValues[0]
+ oriValues[1] * oriValues[1] + oriValues[2] * oriValues[2]);
DetectorNewStep(gravityNew);
/*
* 检测步数并开始计算步数
* 1.传入seror中的数据
* 2. 如果检测到波峰且满足时间差和阈值条件,则判定为步骤1
* 3. 如果满足时间差条件且峰谷差值大于初始值,则该差值将包含在阈值的计算中。
* */
公共无效DetectorNewStep(浮点值){
如果(重力旧== 0){
重力旧 = 值;
} 别的 {
if (DetectorPeak(值, 重力旧)) {
最后峰值时间=当前峰值时间;
timeOfNow = System.currentTimeMillis();
if (现在时间 - 最后峰值时间 >= 250
&& (peakOfWave - ValleyOfWave >= ThreadValue)) {
此峰值时间 = 现在时间;
/*
* 更新界面的处理不涉及算法
* 一般情况下,在通知更新接口之前,会添加以下处理来处理无效动作:
* 1.连续记录10次后开始计步
* 2. 例如,如果用户在记录的9步中停顿超过3秒,则之前的记录将无效,用户下次将从头开始。
* 3. 如果用户连续记录9步后仍在锻炼,则之前的数据有效。
* */
mStepListeners.onStep();
if (现在时间 - 最后峰值时间 >= 250
&& (peakOfWave - ValleyOfWave >= 初始值)) {
此峰值时间 = 现在时间;
ThreadValue = Peak_Valley_Thread(peakOfWave - ValleyOfWave);
重力旧 = 值;
/*
* 检测波峰
* 以下四种情况判断为波峰:
* 1.当前点为下降趋势:isDirectionUp为false
* 2.前一点是上升趋势:lastStatus为true
* 3. 直至波峰,持续上升超过或等于2次。
* 4.波形峰值大于20
* 记录波谷值 * 1. 观察波形图,可以发现出现台阶的地方,波峰紧挨着波谷,有明显的特征和差异 * 2. 因此,有必要记录每个波谷值时间,以便与下一次波峰进行比较
* */public boolean DetectorPeak(float newValue, float oldValue) {
最后状态 = isDirectionUp;
if (newValue >= oldValue) {isDirectionUp = true;
继续UpCount++;
} 别的 {
继续前计数 = 继续前计数;
继续计数 = 0;
isDirectionUp = false;
if (!isDirectionUp && 最后状态
&& (continueUpFormerCount >= 2 || oldValue >= 20)) {
波峰=旧值;
返回真;
} else if (!lastStatus && isDirectionUp) {
波谷=旧值;
返回假;
} else {返回假;
/*
* 阈值的计算
* 1.通过波峰和波谷的差值计算阈值
* 2.记录4个值,存放在tempValue[]数组中
* 3.将数组传入函数averageValue时计算阈值
* */
公共浮点 Peak_Valley_Thread(浮点值) {
浮点数 tempThread = ThreadValue;
if (tempCount < valueNum) {
tempValue[tempCount] = 值;
临时计数++;
} 别的 {
tempThread =averageValue(tempValue, valueNum);
for (int i = 1; i < valueNum; i++) {
tempValue[i - 1] = tempValue[i];
tempValue[valueNum - 1] = 值;
返回临时线程;
/*
* 梯度阈值
* 1.计算数组的均值
* 2. 通过均值在一定范围内对阈值进行梯度变化
* */
公共浮点平均值(浮点值[],int n){
浮动平均值 = 0;
for (int i = 0; i < n; i++) {
ave += 值[i];
ave = ave / valueNum;
如果(平均 >= 8)
ave = (浮点数) 4.3;
否则如果(平均数 >= 7 && 平均数 < 8)
ave = (浮点数) 3.3;
否则如果(平均数 >= 4 && 平均数 < 7)
ave = (浮点数) 2.3;
否则如果(平均数 >= 3 && 平均数 < 4)
ave = (浮点数) 2.0;
别的 {
平均值 = (浮点数) 1.3;
返回大道;