package com.campus.gomotion.service; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import com.campus.gomotion.constant.MotionEnum; import com.campus.gomotion.constant.UIData; import com.campus.gomotion.constant.UserInfo; import com.campus.gomotion.kind.Falling; import com.campus.gomotion.kind.Moving; import com.campus.gomotion.sensorData.*; import com.campus.gomotion.util.PhysicalConversionUtil; import java.sql.Time; import java.util.*; /** * Author: zhong.zhou * Time: 16/4/24 * Email: muxin_zg@163.com */ public class MotionStatisticService { private static final String TAG = "MotionStatisticService"; public static Map<Time, Falling> fallingMap = new TreeMap<>(); public static Map<Time, Moving> walkingMap = new TreeMap<>(); public static Map<Time, Moving> runningMap = new TreeMap<>(); public static Map<Time, Float> fallingLog = new TreeMap<>(); public static Moving totalRunning = new Moving(); public static Moving totalWalking = new Moving(); /** * 存储小段时间内的数据(当前间隔:1分钟) */ private static Falling falling = new Falling(); private static Moving running = new Moving(); private static Moving walking = new Moving(); /** * handle message */ private Handler handler; /** * 跌倒到爬起来的时间计量 */ private static int interval = 0; /** * 跌倒状态位 */ private static boolean isFall = false; public MotionStatisticService(Handler handler) { this.handler = handler; } public void motionStatistic(ArrayDeque<DataPack> dataPacks) { MotionEnum motionKind = MotionEnum.UNKNOW; float averageAcceleration = averageAcceleration(dataPacks); float averageAngular = averageAngular(dataPacks); /** * 对采集的数据进行分析,得出以下规律 * 当1s内的合力加速度的平均值小于1.1时,处于静止状态,当合力加速的的均值大于1.1且小于1.3时,处于 * 行走状态,当合力加速度的均值大于1.3时,处于跑步状态. * 当1s内的合力角速度的平均值小于50时,处于静止状态,当合力角速度的均值大于50时,处于行走或跑步状态 */ /** * 排除静止情况 */ if (averageAngular > 50 || averageAcceleration > 1.1) { /** * 跌倒情况 */ if (isFalling(dataPacks)) { falling.increase(); isFall = true; motionKind = MotionEnum.FALLING; } if (isFall) { long t = System.currentTimeMillis(); Time time = new Time(t); fallingLog.put(time, (float) (interval)); isFall = false; interval = 0; } interval++; long time = 1; float distance = calculateDistance(averageAcceleration, time); float energyConsumption = calculateEnergyConsumption(UserInfo.WEIGHT, averageAcceleration, time); /** * 根据角速度大于120的频率判断行走/跑步 */ boolean isRun = isLargeAngularHighFrequency(dataPacks); /** * 正常行走 */ if (!isRun || averageAcceleration < 1.3) { Moving moving = new Moving(time, distance, 1, energyConsumption); walking.add(moving); totalWalking.add(moving); motionKind = MotionEnum.WALKING; } /** * 正常跑步情况 */ if (isRun || (averageAcceleration > 1.3 && averageAcceleration < 2)) { Moving moving = new Moving(time, distance, 2, energyConsumption); running.add(moving); totalRunning.add(moving); motionKind = MotionEnum.RUNNING; } } else { Log.v(TAG, "静止状态"); motionKind = MotionEnum.STILLING; } Message message = handler.obtainMessage(); Bundle bundle = new Bundle(); if (totalWalking != null) { /** * 保留浮点数后两位 */ float temp = (float) (totalWalking.getTime() / 60.0); float walkTime = (float) (Math.round(temp * 100)) / 100; float walkDistance = (float) (Math.round(totalWalking.getDistance() * 100)) / 100; bundle.putString(UIData.WALK_TIME, String.valueOf(walkTime)); bundle.putString(UIData.WALK_DISTANCE, String.valueOf(walkDistance)); } else { bundle.putString(UIData.WALK_TIME, "0"); bundle.putString(UIData.WALK_DISTANCE, "0"); } if (totalRunning != null) { float temp = (float) (totalRunning.getTime() / 60.0); float runTime = (float) (Math.round(temp * 100)) / 100; float runDistance = (float) (Math.round(totalRunning.getDistance() * 100)) / 100; bundle.putString(UIData.RUN_TIME, String.valueOf(runTime)); bundle.putString(UIData.RUN_DISTANCE, String.valueOf(runDistance)); } else { bundle.putString(UIData.RUN_TIME, "0"); bundle.putString(UIData.RUN_DISTANCE, "0"); } bundle.putString(UIData.FALLING_COUNT, String.valueOf(calculateFallingTotalCount())); float averageFallingTime = (float) (Math.round(calculateAverageFallingTime() * 100)) / 100; bundle.putString(UIData.FALLING_AVERAGE_TIME, String.valueOf(averageFallingTime)); bundle.putString(UIData.MOTION_KING, motionKind.getName()); message.setData(bundle); handler.sendMessage(message); } /** * 添加数据到每日的运动记录中 */ public void loadDataToCache() { long t = System.currentTimeMillis() - 60 * 1000; Time time = new Time(t); if (falling != null) { Falling temp = new Falling(falling); if(fallingMap.containsKey(time)){ Falling falling = fallingMap.get(time); falling.add(temp); }else{ fallingMap.put(time, temp); } falling.clear(); } if (running != null) { Moving temp = new Moving(running); if(runningMap.containsKey(time)){ Moving moving = runningMap.get(time); moving.add(temp); }else{ runningMap.put(time, temp); } running.clear(); } if (walking != null) { Moving temp = new Moving(walking); if(walkingMap.containsKey(time)){ Moving moving = walkingMap.get(time); moving.add(temp); }else{ walkingMap.put(time, temp); } walking.clear(); } } /** * 清空缓存 */ public void clearCache() { if (totalWalking != null) { totalWalking.clear(); } if (totalRunning != null) { totalRunning.clear(); } if (fallingMap != null) { fallingMap.clear(); } if (walkingMap != null) { walkingMap.clear(); } if (runningMap != null) { runningMap.clear(); } } /** * 计算1s内的合力加速度均值(单位:N/s) * * @param dataPacks ArrayDeque<DataPack> * @return float */ public static float averageAcceleration(ArrayDeque<DataPack> dataPacks) { float sum = 0, i = 0, temp; Accelerometer acceleration; if (dataPacks != null && dataPacks.size() > 0) { for (DataPack dataPack : dataPacks) { acceleration = dataPack.getAccelerometer(); temp = PhysicalConversionUtil.calculateGeometricMeanAcceleration(acceleration); sum += temp; i++; } return (sum / i); } else { return 0; } } /** * 计算1s内的合力角速度均值(单位:N/s) * * @param dataPacks ArrayDeque<DataPack> * @return float */ public static float averageAngular(ArrayDeque<DataPack> dataPacks) { float sum = 0, i = 0, temp; AngularVelocity angularVelocity; if (dataPacks != null && dataPacks.size() > 0) { for (DataPack dataPack : dataPacks) { angularVelocity = dataPack.getAngularVelocity(); temp = PhysicalConversionUtil.calculateGeometricMeanAngular(angularVelocity); sum += temp; i++; } return (sum / i); } else { return 0; } } /** * 计算1s内合力角速度大于100的次数 * * @param dataPacks ArrayDeque<DataPack> * @return boolean */ private boolean isLargeAngularHighFrequency(ArrayDeque<DataPack> dataPacks) { int count = 0; float temp; if (dataPacks != null && dataPacks.size() > 0) { for (DataPack dataPack : dataPacks) { temp = PhysicalConversionUtil.calculateGeometricMeanAngular(dataPack.getAngularVelocity()); if (temp > 120) { count++; } } return count > dataPacks.size() - 10; } else { return false; } } private boolean isFalling(ArrayDeque<DataPack> dataPacks) { float temp1, temp2; int count1 = 0, count2 = 0; if (dataPacks != null && dataPacks.size() > 0) { for (DataPack dataPack : dataPacks) { temp1 = PhysicalConversionUtil.calculateGeometricMeanAcceleration(dataPack.getAccelerometer()); temp2 = PhysicalConversionUtil.calculateGeometricMeanAngular(dataPack.getAngularVelocity()); if (temp1 > 4) { count1++; } if (temp2 > 400) { count2++; } } return ((count1 > 0 && count1 <= 5) || (count2 > 0 && count2 <= 5)); } else { return false; } } /** * 根据数据发送频率20ms/次计算时间(单位:s) * * @param t int * @return long */ private float calculateTime(int t) { return (float) (t * 20) / (float) 1000; } /** * 根据平均加速度求位移(单位:m) * * @param a float * @return float */ private float calculateDistance(float a, float t) { return (float) (1.0 / 2.0) * a * t * t; } /** * 根据波峰/波谷的数目计算步数(单位:步) * * @param count int * @return long */ private long calculateStep(int count) { return (long) (count / 2); } /** * 根据外力作功的物理学公式计算卡路里消耗(单位:cal) * * @param weight float * @return float */ private float calculateEnergyConsumption(float weight, float acceleration, float t) { return (float) ((float) (1.0 / 4.0) * (float) (0.014 * weight * 9.8 * acceleration * t * t) / 4.18); } /** * 计算跌倒总次数(单位:次) * * @return int */ public static int calculateFallingTotalCount() { int result = 0; if (fallingLog != null) { return fallingLog.size(); } return result; } /** * 计算平均跌倒时间(单位:s) * * @return float */ public static float calculateAverageFallingTime() { float totalTime = 0; int size = 0; if (fallingLog != null) { Collection<Float> values = fallingLog.values(); size = fallingLog.size(); for (Float value : values) { totalTime += value; } } return (float) totalTime / size; } /** * 计算运动完成量(单位:步) * * @return long */ public static long calculateCompletion() { long result = 0l; if (totalWalking != null && totalRunning != null) { result = totalWalking.getStep() + totalRunning.getStep(); } return result; } /** * 合并跑步和行走的步数(单位:步) * * @return Map<Time,Double> */ public static Map<Time, Double> calculateTotalStep() { Map<Time, Double> resultMap = new TreeMap<>(); Iterator<Time> walkIterator = walkingMap.keySet().iterator(); Iterator<Time> runIterator = runningMap.keySet().iterator(); while (walkIterator.hasNext()) { Time key = walkIterator.next(); double walkStep = (double) walkingMap.get(key).getStep(); double runStep = (double) runningMap.get(key).getStep(); resultMap.put(key, walkStep + runStep); } return resultMap; } /** * 合并跑步和行走的卡路里消耗(单位:cal) * * @return Map<Time,Double> */ public static Map<Time, Double> calculateTotalCalories() { Map<Time, Double> resultMap = new TreeMap<>(); Iterator<Time> walkIterator = walkingMap.keySet().iterator(); Iterator<Time> runIterator = runningMap.keySet().iterator(); while (walkIterator.hasNext()) { Time key = walkIterator.next(); double walkStep = (double) walkingMap.get(key).getEnergyConsumption(); double runStep = (double) runningMap.get(key).getEnergyConsumption(); resultMap.put(key, walkStep + runStep); } return resultMap; } }