-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathMovingAverageStepDetector.java
executable file
·197 lines (163 loc) · 5.85 KB
/
MovingAverageStepDetector.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
package cz.muni.fi.sandbox.service.stepdetector;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.util.Log;
import cz.muni.fi.sandbox.dsp.filters.CumulativeSignalPowerTD;
import cz.muni.fi.sandbox.dsp.filters.MovingAverageTD;
import cz.muni.fi.sandbox.dsp.filters.SignalPowerTD;
/**
* MovingAverageStepDetector class, step detection filter based on two moving averages
* with minimum and maximum signal power thresholds
*
*/
public class MovingAverageStepDetector extends StepDetector {
@SuppressWarnings("unused")
private static final String TAG = "MovingAverageStepDetector";
private float[] maValues;
private MovingAverageTD[] ma;
private SignalPowerTD sp;
private CumulativeSignalPowerTD asp;
private boolean mMASwapState;
private boolean stepDetected;
private boolean signalPowerOutOfRange;
private long mLastStepTimestamp;
private double strideDuration;
public double stepLength;
private static final long SECOND_IN_NANOSECONDS = (long) Math.pow(10, 9);
public static final double MA1_WINDOW = 0.2;
public static final double MA2_WINDOW = 5 * MA1_WINDOW;
@SuppressWarnings("unused")
private static final long POWER_WINDOW = SECOND_IN_NANOSECONDS / 10;
public static final float LOW_POWER_CUTOFF_VALUE = 500.0f; //2000.0f // 200 for vertical 45 degrees with wall
public static final float HIGH_POWER_CUTOFF_VALUE = 500000.0f; // 90000.0f // 100000000
private static final double MAX_STRIDE_DURATION = 2.0; // in seconds
private static final double MIN_STRIDE_DURATION = 0.1;
private double mWindowMa1;
private double mWindowMa2;
private long mWindowPower;
private float mLowPowerCutoff, mHighPowerCutoff;
public MovingAverageStepDetector() {
this(MA1_WINDOW, MA2_WINDOW, LOW_POWER_CUTOFF_VALUE, HIGH_POWER_CUTOFF_VALUE);
}
public MovingAverageStepDetector(double windowMa1, double windowMa2, double lowPowerCutoff, double highPowerCutoff) {
mWindowMa1 = windowMa1;
mWindowMa2 = windowMa2;
mLowPowerCutoff = (float)lowPowerCutoff;
mHighPowerCutoff = (float)highPowerCutoff;
maValues = new float[4];
mMASwapState = true;
ma = new MovingAverageTD[] { new MovingAverageTD(mWindowMa1),
new MovingAverageTD(mWindowMa1),
new MovingAverageTD(mWindowMa2) };
sp = new SignalPowerTD(mWindowPower);
asp = new CumulativeSignalPowerTD();
stepDetected = false;
signalPowerOutOfRange = true;
}
public class MovingAverageStepDetectorState {
public float[] values;
public boolean[] states;
public double duration;
MovingAverageStepDetectorState(float[] values, boolean[] states, double duration) {
this.values = values;
this.states = states;
}
}
public MovingAverageStepDetectorState getState() {
return new MovingAverageStepDetectorState(new float[] { maValues[0],
maValues[1], maValues[2], maValues[3] }, new boolean[] {
stepDetected, signalPowerOutOfRange }, strideDuration);
}
public float getLowPowerThreshold() {
return mLowPowerCutoff;
}
public float getHighPowerThreshold() {
return mHighPowerCutoff;
}
private double processAccelerometerValues(long timestamp, float[] values) {
float value = values[2];
// compute moving averages
maValues[0] = value;
for (int i = 1; i < 3; i++) {
ma[i].push(timestamp, value);
maValues[i] = (float) ma[i].getAverage();
value = maValues[i];
}
// detect moving average crossover
stepDetected = false;
boolean newSwapState = maValues[1] > maValues[2];
if (newSwapState != mMASwapState) {
mMASwapState = newSwapState;
if (mMASwapState) {
stepDetected = true;
}
}
// compute signal power
sp.push(timestamp, maValues[1] - maValues[2]);
asp.push(timestamp, maValues[1] - maValues[2]);
// maValues[3] = (float)sp.getPower();
maValues[3] = (float) asp.getValue();
signalPowerOutOfRange = (maValues[3] < mLowPowerCutoff) || (maValues[3] > mHighPowerCutoff);
// signalPowerOutOfRange = (maValues[3] < mLowPowerCutoff);
if (stepDetected) {
asp.reset();
}
// step event
/*
if (stepDetected && signalPowerOutOfRange) {
if (maValues[3] < mLowPowerCutoff) {
//Log.d("Invalid Step", "Power too low!");
}
if (maValues[3] > mHighPowerCutoff) {
//Log.d("Invalid Step", "Power too high!");
}
}*/
if (stepDetected && !signalPowerOutOfRange) {
strideDuration = getStrideDuration();
double strideLength;
if (strideDuration != Double.NaN && strideDuration <= MAX_STRIDE_DURATION && strideDuration >= MIN_STRIDE_DURATION) {
notifyOnStep(new StepEvent(1.0, strideDuration));
strideLength = new StrideLengthEstimator(1.76).getStrideLengthFromDuration(strideDuration);
/* Round to 4 decimal places */
strideLength = strideLength * 10000;
strideLength = Math.round(strideLength);
strideLength = strideLength / 10000;
Log.d("StrideLengthTest", Double.valueOf(strideLength).toString());
return strideLength;
}
else {
Log.d("Invalid Stride Duration", "Stride Duration NaN!");
return -10;
}
}
return -10;
}
/**
* call has side-effects, must call only when step is detected.
*
* @return stride duration if the duration is less than MAX_STRIDE_DURATION,
* NaN otherwise
*/
private double getStrideDuration() {
// compute stride duration
long currentStepTimestamp = System.nanoTime();
double strideDuration;
strideDuration = (double) (currentStepTimestamp - mLastStepTimestamp)
/ SECOND_IN_NANOSECONDS;
if (strideDuration > MAX_STRIDE_DURATION) {
strideDuration = Double.NaN;
}
mLastStepTimestamp = currentStepTimestamp;
return strideDuration;
}
@Override
public void onSensorChanged(SensorEvent event) {
// Log.d(TAG, "sensor: " + sensor + ", x: " + values[0] + ", y: " +
// values[1] + ", z: " + values[2]);
synchronized (this) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
stepLength = processAccelerometerValues(event.timestamp, event.values);
}
}
}
}