Android精準計步器
阿新 • • 發佈:2018-11-09
demo連結:https://download.csdn.net/download/meixi_android/10690974
工具類:
public class StepDetector implements SensorEventListener { //存放三軸資料 float[] oriValues = new float[3]; final int ValueNum = 4; //用於存放計算閾值的波峰波谷差值 float[] tempValue = new float[ValueNum]; int tempCount = 0; //是否上升的標誌位 boolean isDirectionUp = false; //持續上升次數 int continueUpCount = 0; //上一點的持續上升的次數,為了記錄波峰的上升次數 int continueUpFormerCount = 0; //上一點的狀態,上升還是下降 boolean lastStatus = false; //波峰值 float peakOfWave = 0; //波谷值 float valleyOfWave = 0; //此次波峰的時間 long timeOfThisPeak = 0; //上次波峰的時間 long timeOfLastPeak = 0; //當前的時間 long timeOfNow = 0; //當前感測器的值 float gravityNew = 0; //上次感測器的值 float gravityOld = 0; //動態閾值需要動態的資料,這個值用於這些動態資料的閾值 final float InitialValue = (float) 1.3; //初始閾值 float ThreadValue = (float) 2.0; //波峰波谷時間差 int TimeInterval = 250; private StepCountListener mStepListeners; @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); } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // } public void initListener(StepCountListener listener) { this.mStepListeners = listener; } /* * 檢測步子,並開始計步 * 1.傳入sersor中的資料 * 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 >= TimeInterval && (peakOfWave - valleyOfWave >= ThreadValue)) { timeOfThisPeak = timeOfNow; /* * 更新介面的處理,不涉及到演算法 * 一般在通知更新介面之前,增加下面處理,為了處理無效運動: * 1.連續記錄10才開始計步 * 2.例如記錄的9步使用者停住超過3秒,則前面的記錄失效,下次從頭開始 * 3.連續記錄了9步使用者還在運動,之前的資料才有效 * */ mStepListeners.countStep(); } if (timeOfNow - timeOfLastPeak >= TimeInterval && (peakOfWave - valleyOfWave >= InitialValue)) { timeOfThisPeak = timeOfNow; ThreadValue = peakValleyThread(peakOfWave - valleyOfWave); } } } gravityOld = values; } /* * 檢測波峰 * 以下四個條件判斷為波峰: * 1.目前點為下降的趨勢:isDirectionUp為false * 2.之前的點為上升的趨勢:lastStatus為true * 3.到波峰為止,持續上升大於等於2次 * 4.波峰值大於20 * 記錄波谷值 * 1.觀察波形圖,可以發現在出現步子的地方,波谷的下一個就是波峰,有比較明顯的特徵以及差值 * 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[]陣列中 * 3.在將陣列傳入函式averageValue中計算閾值 * */ public float peakValleyThread(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.計算陣列的均值 * 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; } }