android 判断手机计步_Android_基于G-Sensor的计步算法
大家好,插播一下,最近花了點時間,基于g-sensor,在做一些姿勢識別的事情,比如走路,跑步,騎車,起立,坐下,文章還在整理,歡迎關注。周末爭取傳個apk給大家體驗一下。
開始:
最新發現了很多文章將算法直接拿去用,簡書上,github上,導致下面有很多疑問。
希望大家轉載或者改造的時候,可以注明一下算法的原作者為 finnfu以及原文鏈接,謝謝。
很多人問源碼地址,因為一些原因不能提供,寫了個簡單的算法demo,以及算法介紹文檔。
https://github.com/finnfu/stepcount
如果覺得對你有幫助,請給個star吧!
下面是正文:
目前在計步領域比較領先的有樂動力以及春雨計步器,在做算法的參數調試的時候也是一直拿這兩個應用做對比。樂動力當之無愧行業第一,不管是應用的體驗還是準確度都是非常棒,春雨計步器的亮點是輕量級,使用以及界面操作都很簡單。之前因為一些需求,需要做一個計步器,所以就開始自己研究算法了,各種場景(走路拿在手上,放在口袋,跑步),算法的準確度大概可以達到95.7%,綜合起來覺得是比春雨略好,但是贏不了樂動力(可以達到97.7%)在體驗和大局觀為王的互聯網時代,我覺得技術上的差距會越來越小,重要的是體驗還有對于產品的定位,所以決定將算法與大家分享,第一是希望可以幫到到家,第二也是希望大家提一些意見,讓這個算法可以得到改進。
人在走路時大致分為下面幾種場景:
1、正常走路,手機拿在手上(邊走邊看、甩手、不甩手)
2、慢步走,手機拿在手上(邊走邊看、甩手、不甩手)
3、快步走,手機拿在手上(甩手、不甩手、走的很快一般不會看手機吧)
4、手機放在褲袋里(慢走、快走、正常走)
5、手機放在上衣口袋里(慢走、快走、正常走)
6、上下樓梯(上面五中場景可以在這個場景中再次適用一遍)
以上,不管出于哪一種場景(其實對應手機不同的運動規律),g-sensor的三軸數據都是有規律可以尋找的。
每一步都有特征點,找到這個特征點,就是識別出來一步。
下面推薦一個工具,叫gsensor-debug,可以觀察三軸的曲線,下面是手機上下擺動的曲線
這是很規律曲線只要檢測波峰就行了,實際的走路曲線會有很多雜波,算法的作用就是濾除這些雜波(走路的波形可以用工具自己看,可以保存為文件,用excel打開有數據,將數據轉換為波形就可以自己看)
//存放三軸數據
float[]?oriValues?=newfloat[3];
finalintvalueNum?=4;
//用于存放計算閾值的波峰波谷差值
float[]?tempValue?=newfloat[valueNum];
inttempCount?=0;
//是否上升的標志位
booleanisDirectionUp?=false;
//持續上升次數
intcontinueUpCount?=0;
//上一點的持續上升的次數,為了記錄波峰的上升次數
intcontinueUpFormerCount?=0;
//上一點的狀態,上升還是下降
booleanlastStatus?=false;
//波峰值
floatpeakOfWave?=0;
//波谷值
floatvalleyOfWave?=0;
//此次波峰的時間
longtimeOfThisPeak?=0;
//上次波峰的時間
longtimeOfLastPeak?=0;
//當前的時間
longtimeOfNow?=0;
//當前傳感器的值
floatgravityNew?=0;
//上次傳感器的值
floatgravityOld?=0;
//動態閾值需要動態的數據,這個值用于這些動態數據的閾值
finalfloatinitialValue?=?(float)1.3;
//初始閾值
floatThreadValue?=?(float)2.0;
privateStepListener?mStepListeners;
檢測步子就是檢測波峰,但是要濾除無效的波峰,主要采用了如下三種措施
a、規定曲線連續上升的次數
b、波峰波谷的差值需要大于閾值
c、閾值是動態改變的
另一個是一些參數的初始值,比如initialValue 以及ThreadValue 的初始值,以及averageValue函數的梯度化范圍值
需要結合各種場景的波形圖來統計,還有幾十實際的測試來調試參數,這些參數大概前后調了兩個星期,其實總體思路不復雜。
下面貼出核心代碼以及一些注釋:
(因為一些原因,整個工程我就不傳了,后面有時間我可以將app傳上來)
/*
*?注冊了G-Sensor后一只會調用這個函數
*?對三軸數據進行平方和開根號的處理
*?調用DetectorNewStep檢測步子
*?*/
@Override
publicvoidonSensorChanged(SensorEvent?event)?{
for(inti?=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.傳入sersor中的數據
*?2.如果檢測到了波峰,并且符合時間差以及閾值的條件,則判定為1步
*?3.符合時間差條件,波峰波谷差值大于initialValue,則將該差值納入閾值的計算中
*?*/
publicvoidDetectorNewStep(floatvalues)?{
if(gravityOld?==0)?{
gravityOld?=?values;
}else{
if(DetectorPeak(values,?gravityOld))?{
timeOfLastPeak?=?timeOfThisPeak;
timeOfNow?=?System.currentTimeMillis();
if(timeOfNow?-?timeOfLastPeak?>=250
&&?(peakOfWave?-?valleyOfWave?>=?ThreadValue))?{
timeOfThisPeak?=?timeOfNow;
/*
*?更新界面的處理,不涉及到算法
*?一般在通知更新界面之前,增加下面處理,為了處理無效運動:
*?1.連續記錄10才開始計步
*?2.例如記錄的9步用戶停住超過3秒,則前面的記錄失效,下次從頭開始
*?3.連續記錄了9步用戶還在運動,之前的數據才有效
*?*/
mStepListeners.onStep();
}
if(timeOfNow?-?timeOfLastPeak?>=250
&&?(peakOfWave?-?valleyOfWave?>=?initialValue))?{
timeOfThisPeak?=?timeOfNow;
ThreadValue?=?Peak_Valley_Thread(peakOfWave?-?valleyOfWave);
}
}
}
gravityOld?=?values;
}
/*
*?檢測波峰
*?以下四個條件判斷為波峰:
*?1.目前點為下降的趨勢:isDirectionUp為false
*?2.之前的點為上升的趨勢:lastStatus為true
*?3.到波峰為止,持續上升大于等于2次
*?4.波峰值大于20
*?記錄波谷值
*?1.觀察波形圖,可以發現在出現步子的地方,波谷的下一個就是波峰,有比較明顯的特征以及差值
*?2.所以要記錄每次的波谷值,為了和下次的波峰做對比
*?*/
publicbooleanDetectorPeak(floatnewValue,floatoldValue)?{
lastStatus?=?isDirectionUp;
if(newValue?>=?oldValue)?{
isDirectionUp?=true;
continueUpCount++;
}else{
continueUpFormerCount?=?continueUpCount;
continueUpCount?=0;
isDirectionUp?=false;
}
if(!isDirectionUp?&&?lastStatus
&&?(continueUpFormerCount?>=2||?oldValue?>=20))?{
peakOfWave?=?oldValue;
returntrue;
}elseif(!lastStatus?&&?isDirectionUp)?{
valleyOfWave?=?oldValue;
returnfalse;
}else{
returnfalse;
}
}
/*
*?閾值的計算
*?1.通過波峰波谷的差值計算閾值
*?2.記錄4個值,存入tempValue[]數組中
*?3.在將數組傳入函數averageValue中計算閾值
*?*/
publicfloatPeak_Valley_Thread(floatvalue)?{
floattempThread?=?ThreadValue;
if(tempCount?
tempValue[tempCount]?=?value;
tempCount++;
}else{
tempThread?=?averageValue(tempValue,?valueNum);
for(inti?=1;?i?
tempValue[i?-1]?=?tempValue[i];
}
tempValue[valueNum?-1]?=?value;
}
returntempThread;
}
/*
*?梯度化閾值
*?1.計算數組的均值
*?2.通過均值將閾值梯度化在一個范圍里
*?3.參數暫時不開放(a,b,c,d,e,f,g,h,i,i,k,l)
*?*/
publicfloataverageValue(floatvalue[],intn)?{
floatave?=0;
for(inti?=0;?i?
ave?+=?value[i];
}
ave?=?ave?/?valueNum;
if(ave?>=?a)
ave?=?(float)?b;
elseif(ave?>=?c?&&?ave?
ave?=?(float)?e;
elseif(ave?>=?f?&&?ave?
ave?=?(float)?h;
elseif(ave?>=?i?&&?ave?
ave?=?(float)?k;
else{
ave?=?(float)?l;
}
returnave;
}
總結
以上是生活随笔為你收集整理的android 判断手机计步_Android_基于G-Sensor的计步算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用云计算打造政务信息化及应急指挥云平台
- 下一篇: IDEA运行下载的Servlet时报错