1. 程式人生 > >Android精準計步器

Android精準計步器

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;
    }

}