手機計步器原理

姓名:周君會? ? ? ? 學號:17011210526

轉載自:

https://www.zhihu.com/question/19808224

【嵌牛導讀】:計步器可以記錄我們的步數(shù)衅谷,督促我們的健康,對我們的生活帶來了極大地便利瑰妄。

【嵌牛鼻子】:運動手環(huán)也是極其常見账月,手機中自帶的也有計步器太雨。

【嵌牛提問】:但是手機中自帶的計步器是如何實現(xiàn)精準計步的呢租悄,它的相關原理是什么奕枝?

【嵌牛正文】:

Android_基于G-Sensor的計步算法

一朴沿、寫在分享之前

學習Android也有將近一年的時間了雌芽,一直在看大牛們分享的知識授艰,今天也想分享自己之前的一點研究,關于計步器算法的世落。目前在計步領域比較領先的有樂動力以及春雨計步器淮腾,在做算法的參數(shù)調試的時候也是一直拿這兩個應用做對比。樂動力當之無愧行業(yè)第一屉佳,不管是應用的體驗還是準確度都是非常棒谷朝,春雨計步器的亮點是輕量級,使用以及界面操作都很簡單武花。之前因為一些需求圆凰,需要做一個計步器,所以就開始自己研究算法了体箕,各種場景(走路拿在手上专钉,放在口袋,跑步)累铅,算法的準確度大概可以達到95.7%跃须,綜合起來覺得是比春雨略好,但是贏不了樂動力(可以達到97.7%)在體驗和大局觀為王的互聯(lián)網(wǎng)時代娃兽,我覺得技術上的差距會越來越小菇民,重要的是體驗還有對于產品的定位,所以決定將算法與大家分享,第一是希望可以幫到到家玉雾,第二也是希望大家提一些意見,讓這個算法可以得到改進轻要。

計步器apk下載

apk反編譯下載

二复旬、計步器算法的總體思路以及輔助調試的工具

人在走路時大致分為下面幾種場景:

1、正常走路冲泥,手機拿在手上(邊走邊看驹碍、甩手、不甩手)

2凡恍、慢步走志秃,手機拿在手上(邊走邊看、甩手嚼酝、不甩手)

3浮还、快步走,手機拿在手上(甩手闽巩、不甩手钧舌、走的很快一般不會看手機吧)

4、手機放在褲袋里(慢走涎跨、快走洼冻、正常走)

5、手機放在上衣口袋里(慢走隅很、快走撞牢、正常走)

6、上下樓梯(上面五中場景可以在這個場景中再次適用一遍)

以上叔营,不管出于哪一種場景(其實對應手機不同的運動規(guī)律)屋彪,g-sensor的三軸數(shù)據(jù)都是有規(guī)律可以尋找的。

每一步都有特征點绒尊,找到這個特征點撼班,就是識別出來一步。

下面推薦一個工具垒酬,叫gsensor-debug砰嘁,可以觀察三軸的曲線,下面是手機上下擺動的曲線

這是很規(guī)律曲線只要檢測波峰就行了勘究,實際的走路曲線會有很多雜波矮湘,算法的作用就是濾除這些雜波(走路的波形可以用工具自己看,可以保存為文件口糕,用excel打開有數(shù)據(jù)缅阳,將數(shù)據(jù)轉換為波形就可以自己看)

三、算法的介紹(貼出核心代碼)1、變量的定義//存放三軸數(shù)據(jù)? float[] oriValues = new float[3];? final int valueNum = 4;? //用于存放計算閾值的波峰波谷差值? float[] tempValue = new float[valueNum];? int tempCount = 0;? //是否上升的標志位? boolean isDirectionUp = false;? //持續(xù)上升次數(shù)? int continueUpCount = 0;? //上一點的持續(xù)上升的次數(shù)十办,為了記錄波峰的上升次數(shù)? int continueUpFormerCount = 0;? //上一點的狀態(tài)秀撇,上升還是下降? boolean lastStatus = false;? //波峰值? float peakOfWave = 0;? //波谷值? float valleyOfWave = 0;? //此次波峰的時間? long timeOfThisPeak = 0;? //上次波峰的時間? long timeOfLastPeak = 0;? //當前的時間? long timeOfNow = 0;? //當前傳感器的值? float gravityNew = 0;? //上次傳感器的值? float gravityOld = 0;? //動態(tài)閾值需要動態(tài)的數(shù)據(jù),這個值用于這些動態(tài)數(shù)據(jù)的閾值? final float initialValue = (float) 1.3;? //初始閾值? float ThreadValue = (float) 2.0;? private StepListener mStepListeners;

2. 代碼向族,結合注釋看

檢測步子就是檢測波峰呵燕,但是要濾除無效的波峰,主要采用了如下三種措施

a件相、規(guī)定曲線連續(xù)上升的次數(shù)

b再扭、波峰波谷的差值需要大于閾值

c、閾值是動態(tài)改變的

另一個是一些參數(shù)的初始值夜矗,比如initialValue 以及ThreadValue 的初始值泛范,以及averageValue函數(shù)的梯度化范圍值

需要結合各種場景的波形圖來統(tǒng)計,還有幾十實際的測試來調試參數(shù)紊撕,這些參數(shù)大概前后調了兩個星期罢荡,其實總體思路不復雜。

下面貼出核心代碼以及一些注釋:

(因為一些原因对扶,整個工程我就不傳了柠傍,后面有時間我可以將app傳上來)

/*

* 注冊了G-Sensor后一只會調用這個函數(shù)

* 對三軸數(shù)據(jù)進行平方和開根號的處理

* 調用DetectorNewStep檢測步子

* */

@Override

public void onSensorChanged(SensorEvent event) {

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.傳入sersor中的數(shù)據(jù)

* 2.如果檢測到了波峰辩稽,并且符合時間差以及閾值的條件惧笛,則判定為1步

* 3.符合時間差條件,波峰波谷差值大于initialValue逞泄,則將該差值納入閾值的計算中

* */

public void DetectorNewStep(float values) {

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.連續(xù)記錄10才開始計步

* 2.例如記錄的9步用戶停住超過3秒各谚,則前面的記錄失效,下次從頭開始

* 3.連續(xù)記錄了9步用戶還在運動到千,之前的數(shù)據(jù)才有效

* */

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.到波峰為止昌渤,持續(xù)上升大于等于2次

* 4.波峰值大于20

* 記錄波谷值? ? ? * 1.觀察波形圖,可以發(fā)現(xiàn)在出現(xiàn)步子的地方憔四,波谷的下一個就是波峰膀息,有比較明顯的特征以及差值? ? ? * 2.所以要記錄每次的波谷值,為了和下次的波峰做對比

* */? ? ? public boolean DetectorPeak(float newValue, float oldValue) {

lastStatus = isDirectionUp;

if (newValue >= oldValue) {? ? ? ? ? ? ? isDirectionUp = true;

continueUpCount++;

} else {

continueUpFormerCount = continueUpCount;

continueUpCount = 0;

isDirectionUp = false;

}

if (!isDirectionUp && lastStatus

&& (continueUpFormerCount >= 2 || oldValue >= 20)) {

peakOfWave = oldValue;

return true;

} else if (!lastStatus && isDirectionUp) {

valleyOfWave = oldValue;

return false;

} else {? ? ? ? ? ? ? return false;

}

}

/*

* 閾值的計算

* 1.通過波峰波谷的差值計算閾值

* 2.記錄4個值了赵,存入tempValue[]數(shù)組中

* 3.在將數(shù)組傳入函數(shù)averageValue中計算閾值

* */

public float Peak_Valley_Thread(float value) {

float tempThread = ThreadValue;

if (tempCount < valueNum) {

tempValue[tempCount] = value;

tempCount++;

} else {

tempThread = averageValue(tempValue, valueNum);

for (int i = 1; i < valueNum; i++) {

tempValue[i - 1] = tempValue[i];

}

tempValue[valueNum - 1] = value;

}

return tempThread;

}

/*

* 梯度化閾值

* 1.計算數(shù)組的均值

* 2.通過均值將閾值梯度化在一個范圍里

* */

public float averageValue(float value[], int n) {

float ave = 0;

for (int i = 0; i < n; i++) {

ave += value[i];

}

ave = ave / valueNum;

if (ave >= 8)

ave = (float) 4.3;

else if (ave >= 7 && ave < 8)

ave = (float) 3.3;

else if (ave >= 4 && ave < 7)

ave = (float) 2.3;

else if (ave >= 3 && ave < 4)

ave = (float) 2.0;

else {

ave = (float) 1.3;

}

return ave;

}

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末潜支,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子柿汛,更是在濱河造成了極大的恐慌冗酿,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異裁替,居然都是意外死亡项玛,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門弱判,熙熙樓的掌柜王于貴愁眉苦臉地迎上來襟沮,“玉大人,你說我怎么就攤上這事裕循。” “怎么了净刮?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵剥哑,是天一觀的道長。 經常有香客問我淹父,道長株婴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任暑认,我火速辦了婚禮困介,結果婚禮上,老公的妹妹穿的比我還像新娘蘸际。我一直安慰自己座哩,他們只是感情好,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布粮彤。 她就那樣靜靜地躺著根穷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪导坟。 梳的紋絲不亂的頭發(fā)上屿良,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音惫周,去河邊找鬼尘惧。 笑死,一個胖子當著我的面吹牛递递,可吹牛的內容都是我干的喷橙。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼登舞,長吁一口氣:“原來是場噩夢啊……” “哼重慢!你這毒婦竟也來了?” 一聲冷哼從身側響起逊躁,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤似踱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體核芽,經...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡囚戚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了轧简。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片驰坊。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖哮独,靈堂內的尸體忽然破棺而出拳芙,到底是詐尸還是另有隱情,我是刑警寧澤皮璧,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布舟扎,位于F島的核電站,受9級特大地震影響悴务,放射性物質發(fā)生泄漏睹限。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一讯檐、第九天 我趴在偏房一處隱蔽的房頂上張望羡疗。 院中可真熱鬧,春花似錦别洪、人聲如沸叨恨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽特碳。三九已至,卻和暖如春晕换,著一層夾襖步出監(jiān)牢的瞬間午乓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工闸准, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留益愈,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓夷家,卻偏偏與公主長得像蒸其,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子库快,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內容