1
1
import java .util .Arrays ;
2
2
3
3
public class StepCounter {
4
- private static final int WINDOW_LENGTH = 5 ;
5
- private static final double DEVIATION_SCALAR = 0.8 ;
4
+ private static final int WINDOW_LENGTH = 5 ; //"range" for noise smoothing
5
+ private static final double DEVIATION_SCALAR = 0.8 ; //constant that is multiplied with (mean+standard deviation) to get threshold value for naive algorithm
6
6
private static final int THRESHOLD_MULTIPLE =5 ; //multiplication factor for threshold to ensure it is above the magnitudes of invalid steps
7
+ private static final double MEAN_SCALAR = 0.54 ; //scalar applied to mean value of data to calculate minimum reasonable data value (anything smaller in mag. cannot be a step)
8
+ private static final double MEAN_SHIFT =0.72 ; //value to shift mean value of data from to calculate minimum reasonable data value (anything smaller in mag. cannot be a step)
9
+ private static final double PERCENT_ACCEPTANCE_POTENTIAL_STEP_ACTIVITY =0.8 ;
7
10
public static void main (String [] args ) {
8
- String [] columnNames ={"time" , "gyro -x" , "gyro -y" , "gyro -z" };
11
+ String [] columnNames ={"time" , "accel -x" , "accel -y" , "accel -z" };
9
12
CSVData test = new CSVData ("data/50StepWalkFemale(2).csv" , columnNames , 1 );
10
13
test .correctTime (test );
11
14
System .out .println ("Improved Algorithm:" +countSteps (test .getColumn (0 ),test .getRows (1 ,test .getNumRows ()-1 ), 10 ));
12
15
System .out .println ("Old Algorithm:" +countSteps (test .getColumn (0 ),test .getRows (1 ,test .getNumRows ()-1 )));
13
16
}
14
- //improved algorithm
17
+ /***
18
+ * NOTE: IMPROVED ALGORITHM
19
+ * Counts the number of steps with an adaptive threshold that is calculated for each sensorData value.
20
+ * If the resultant of all 3 components of acceleration (from sensorData) is above the adaptive threshold for that point
21
+ * and greater in magnitude than its two adjacent points, it is considered a step.
22
+ * @param times array of times corresponding to each resultant magnitude from the 3 components of acceleration from sensorData
23
+ * @param sensorData 2-D array of sensor data including times(ms) and the three acceleration components (x,y,z)
24
+ * @param windowLength length of window adjacent to each resultant acceleration that the thresholds are calculated from
25
+ * Ex: windowLength=3 at times=5 means thresholds will be calculated from resultant accelerations corresponding to times
26
+ * [2,8]
27
+ * @return number of steps counted from sensorData
28
+ */
15
29
private static int countSteps (double [] times , double [][] sensorData , int windowLength ) {
16
30
int stepCount = 0 ;
17
31
double [] arr = new double [times .length ];
18
32
arr = calculateMagnitudes (sensorData );
19
33
double mean = calculateMean (arr );
20
34
double minLimit = calculateMinLimit (mean ); //minimum magnitude to be a reasonable step
21
35
// arr = NoiseSmoothing.generalRunningAverage(arr, 10);
22
- double [] thresholds = calculateWindow (arr , windowLength , minLimit );
36
+ double [] thresholds = calculateAdaptiveThreshold (arr , windowLength , minLimit );
23
37
for (int i = 1 ; i < arr .length -1 ; i ++) {
24
38
if (arr [i ] > arr [i -1 ] && arr [i ] > arr [i +1 ]) {
25
39
if (arr [i ] > thresholds [i ]) {
@@ -30,7 +44,14 @@ private static int countSteps(double[] times, double[][] sensorData, int windowL
30
44
}
31
45
return stepCount ;
32
46
}
33
- //old algorithm
47
+ /**
48
+ * NOTE: OLD NAIVE ALGORITHM
49
+ * Counts the number of steps with a static threshold that is calculated by adding the mean of sensorData resultant acceleration
50
+ * vector with the standard deviation of sensorData resultant acceleration vector and multiplied by DEVIATION_SCALAR
51
+ * @param times array of times corresponding to each resultant magnitude from the 3 components of acceleration from sensorData
52
+ * @param sensorData 2-D array of sensor data including times(ms) and the three acceleration components (x,y,z)
53
+ * @return number of steps counted from sensorData
54
+ */
34
55
private static int countSteps (double [] times , double [][] sensorData ) {
35
56
int stepCount = 0 ;
36
57
double [] arr = new double [times .length ];
@@ -49,43 +70,48 @@ private static int countSteps(double[] times, double[][] sensorData) {
49
70
50
71
return stepCount ;
51
72
}
52
-
73
+ /**
74
+ * Returns minimum magnitude of acceleration resultant vector to be a reasonable step.
75
+ * MEAN_SCALAR and MEAN_SHIFT derived from trial-and-error of testing for the best minLimit for different step situations,
76
+ * and finding the best linear fit for the data
77
+ * @param mean the average from the array of acceleration resultant vectors
78
+ * @return minimum magnitude of acceleraiton resultant vecotr to be a reasonable step
79
+ */
53
80
public static double calculateMinLimit (double mean ){
54
- return 0.54 *mean +0.72 ;
81
+ return MEAN_SCALAR *mean +MEAN_SHIFT ;
55
82
}
56
- /***
83
+ /**
57
84
* Returns array of threshold values for input window size away from each arr value. If magnitude is unreasonably
58
85
* low(not a step), threshold will be set to an extreme high value to avoid counting peaks in no-step noise areas.
59
86
* @param arr array of magnitudes to calculate thresholds from
60
87
* @param windowLength length of "range" of values next to each magnitude value to calculate threshold from
61
88
* @return array of threshold values for every magnitude value calculated with int windowLength values to the left/right of
62
89
* magnitude value
63
90
*/
64
- public static double [] calculateWindow (double [] arr , int windowLength , double minLimit ) {
91
+ public static double [] calculateAdaptiveThreshold (double [] arr , int windowLength , double minLimit ) {
65
92
double [] result =new double [arr .length ];
66
93
for (int i = 0 ; i < arr .length ; i ++){
67
- if (i +windowLength < arr .length ) {
68
- if (i -windowLength >= 0 ) {
94
+ if (i +windowLength < arr .length ) { //check if in right-hand range
95
+ if (i -windowLength >= 0 ) { //check if in left-hand range
69
96
double meanForInterval = calculateMeanInInterval (arr , i -windowLength , i +windowLength );
70
97
double deviationForInterval = calculateStandardDeviationInInterval (arr , meanForInterval , i -windowLength , i +windowLength );
71
- if (magnitudeIsUnreasonblySmall (arr , WINDOW_LENGTH , i , minLimit )){
98
+ if (isMagnitudeUnreasonablySmall (arr , WINDOW_LENGTH , i , minLimit ))
72
99
result [i ]=((meanForInterval +deviationForInterval ))*THRESHOLD_MULTIPLE ;
73
- } else {
100
+ else
74
101
result [i ] = (meanForInterval +deviationForInterval );
75
- }
76
- } else {
102
+ } else { //if index is within windowLength from the left-hand end of array
77
103
double meanForInterval = calculateMeanInInterval (arr , 0 , i +windowLength );
78
104
double deviationForInterval = calculateStandardDeviationInInterval (arr , meanForInterval , 0 , i +windowLength );
79
- if (magnitudeIsUnreasonblySmall (arr , WINDOW_LENGTH , i +WINDOW_LENGTH , minLimit )){
105
+ if (isMagnitudeUnreasonablySmall (arr , WINDOW_LENGTH , i +WINDOW_LENGTH , minLimit )){
80
106
result [i ]=((meanForInterval +deviationForInterval ))*THRESHOLD_MULTIPLE ;
81
107
}else {
82
108
result [i ] = (meanForInterval +deviationForInterval );
83
109
}
84
110
}
85
- } else {
111
+ } else {//if index is within windowLength from the right-hand end of array
86
112
double meanForInterval = calculateMeanInInterval (arr , i -windowLength , arr .length );
87
113
double deviationForInterval = calculateStandardDeviationInInterval (arr , meanForInterval , i -windowLength , arr .length );
88
- if (magnitudeIsUnreasonblySmall (arr , WINDOW_LENGTH , i -WINDOW_LENGTH , minLimit )){
114
+ if (isMagnitudeUnreasonablySmall (arr , WINDOW_LENGTH , i -WINDOW_LENGTH , minLimit )){
89
115
result [i ]=((meanForInterval +deviationForInterval ))*THRESHOLD_MULTIPLE ;
90
116
}else {
91
117
result [i ] = (meanForInterval +deviationForInterval );
@@ -124,31 +150,47 @@ public static double[] calculateWindow(double[] arr, int windowLength, double mi
124
150
* @param windowLength range from the arr value
125
151
* @param index arr index value to check magnitudes from
126
152
* @param threshold threshold for reasonable magnitudes (anything under is considered too small to count as possible steps)
127
- * @return true if >80% of values are under the threshold
153
+ * @return true if >80% of values are under the threshold (aka too small to be considered any significant step activity)
154
+ * false if <80% of values are under the threshold (aka of enough significance to be considered for potential step activity)
128
155
*/
129
- private static boolean magnitudeIsUnreasonblySmall (double [] arr , int windowLength , int index , double threshold ) {
130
- int underThresholdCounter = 0 ;
131
- int totalIterations = 0 ;
156
+ private static boolean isMagnitudeUnreasonablySmall (double [] arr , int windowLength , int index , double threshold ) {
157
+ int underThresholdCounter = 0 , totalIterations =0 ;
132
158
for (int i = index -windowLength ; i < index +windowLength ; i ++) {
133
- if (arr [i ] < threshold ) {
159
+ if (arr [i ] < threshold )
134
160
underThresholdCounter ++;
135
- }
136
161
totalIterations ++;
137
162
}
138
- if ((double )underThresholdCounter /(double )totalIterations > 0.8 ) return true ;
163
+ if ((double )underThresholdCounter /(double )totalIterations > PERCENT_ACCEPTANCE_POTENTIAL_STEP_ACTIVITY )
164
+ return true ;
139
165
return false ;
140
166
}
141
-
142
- public static double [] noiseSmoothing (double [] magnitudes , int averageLength ) {
143
- double [] result = new double [magnitudes .length -averageLength ];
144
- result = NoiseSmoothing .generalRunningAverage (magnitudes , averageLength );
145
- return result ;
146
- }
147
-
167
+ // /**
168
+ // *
169
+ // * @param magnitudes
170
+ // * @param averageLength
171
+ // * @return
172
+ // */
173
+ // public static double[] noiseSmoothing(double[] magnitudes, int averageLength) {
174
+ // double[] result = new double[magnitudes.length-averageLength];
175
+ // result = NoiseSmoothing.generalRunningAverage(magnitudes, averageLength);
176
+ // return result;
177
+ // }
178
+ /**
179
+ * Returns the magnitude of the resultant vector of three input magnitudes of vectors
180
+ * @param x magnitude of x-component vector
181
+ * @param y magnitude of y-component vector
182
+ * @param z magnitude of z-component vector
183
+ * @return magnitude of the resultant vector from three input component vectors
184
+ */
148
185
public static double calculateMagnitude (double x , double y , double z ) {
149
186
return Math .sqrt (x *x + y *y + z *z );
150
187
}
151
-
188
+ /**
189
+ * Returns a 1D array with magnitudes of the resultant vectors of three vector components for multiple rows
190
+ * Calculates the magnitude of each row of three vector components for multiple rows of sensorData
191
+ * @param sensorData 2-D array of sensor data including times(ms) and the three acceleration components (x,y,z)
192
+ * @return 1D array with magnitudes of the resultant vectors of three vector components for multiple rows
193
+ */
152
194
private static double [] calculateMagnitudes (double [][] sensorData ) {
153
195
double [] result = new double [sensorData .length ];
154
196
for (int i = 0 ; i < sensorData .length ; i ++) {
@@ -159,36 +201,58 @@ private static double[] calculateMagnitudes(double[][] sensorData) {
159
201
}
160
202
return result ;
161
203
}
162
-
204
+ /**
205
+ * Returns standard deviation of a 1D array of values
206
+ * @param arr 1D array of values to calculate standard deviation from
207
+ * @param mean average of the 1D array
208
+ * @return standard deviation of arr
209
+ */
163
210
private static double calculateStandardDeviation (double [] arr , double mean ) {
164
211
double sum = 0 ;
165
212
for (int i = 0 ; i < arr .length ; i ++) {
166
213
sum += (arr [i ] - mean )*(arr [i ] - mean );
167
214
}
168
215
return Math .sqrt (sum /(arr .length -1 ));
169
216
}
170
-
217
+ /**
218
+ * Returns standard deviation of a 1D array in a select interval
219
+ * @param arr 1D array of values to calculate standard deviation from
220
+ * @param mean average of the 1D array
221
+ * @param startInterval starting index of interval
222
+ * @param endInterval ending index of interval (non-inclusive)
223
+ * @return standard deviation of arr in interval
224
+ */
171
225
private static double calculateStandardDeviationInInterval (double [] arr , double mean , int startInterval , int endInterval ) {
172
226
double sum = 0 ;
173
227
for (int i = startInterval ; i < endInterval ; i ++) {
174
228
sum += (arr [i ] - mean )*(arr [i ] - mean );
175
229
}
176
230
return Math .sqrt (sum /(double )(endInterval -startInterval ));
177
231
}
178
-
232
+ /**
233
+ * Returns average from 1D array of values
234
+ * @param arr 1D array of values
235
+ * @return average of 1D array
236
+ */
179
237
private static double calculateMean (double [] arr ) {
180
238
double sum = 0 ;
181
239
for (int i = 0 ; i < arr .length ; i ++) {
182
240
sum += arr [i ];
183
241
}
184
242
return sum /arr .length ;
185
243
}
186
-
244
+ /**
245
+ * Returns average of 1D array in a select interval
246
+ * @param arr 1D array of values
247
+ * @param startIndex starting index of interval
248
+ * @param endIndex ending index of interval (non-inclusive)
249
+ * @return average of 1D array
250
+ */
187
251
private static double calculateMeanInInterval (double [] arr , int startIndex , int endIndex ) {
188
252
double sum = 0 ;
189
253
for (int i = startIndex ; i < endIndex ; i ++) {
190
254
sum += arr [i ];
191
255
}
192
256
return sum /(double )(endIndex -startIndex );
193
257
}
194
- }
258
+ }
0 commit comments