@wemap/providers 9.1.1 → 9.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +1 -0
- package/package.json +8 -8
- package/src/providers/steps/StepDetectionMinMaxPeaks3.js +201 -0
- package/src/providers/steps/StepDetector.js +32 -1
- package/src/providers/steps/StepDetectorLadetto.js +108 -0
- package/src/providers/steps/StepDetectorMinMaxPeaks.js +108 -0
- package/src/providers/steps/StepDetectorMinMaxPeaks2.js +108 -0
- package/src/providers/steps/StepDetectorMinMaxPeaks3.js +108 -0
- package/dist/wemap-providers.es.js +0 -5284
- package/dist/wemap-providers.es.js.map +0 -1
package/index.js
CHANGED
|
@@ -36,6 +36,7 @@ export { default as Inclination } from './src/providers/inclination/Inclination.
|
|
|
36
36
|
export { default as StepDetector } from './src/providers/steps/StepDetector.js';
|
|
37
37
|
export { default as StraightLineDetector } from './src/providers/steps/StraightLineDetector.js';
|
|
38
38
|
export { default as StepDetectionMinMaxPeaks2 } from './src/providers/steps/StepDetectionMinMaxPeaks2.js';
|
|
39
|
+
export { default as StepDetectionMinMaxPeaks3 } from './src/providers/steps/StepDetectionMinMaxPeaks3.js';
|
|
39
40
|
|
|
40
41
|
export { default as Pdr } from './src/providers/position/relative/Pdr.js';
|
|
41
42
|
export { default as GeoRelativePositionFromArCore } from './src/providers/position/relative/GeoRelativePositionFromArCore.js';
|
package/package.json
CHANGED
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
"Guillaume Pannetier <guillaume.pannetier@getwemap.com>"
|
|
9
9
|
],
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@wemap/camera": "^9.0
|
|
12
|
-
"@wemap/geo": "^9.
|
|
11
|
+
"@wemap/camera": "^9.2.0",
|
|
12
|
+
"@wemap/geo": "^9.2.0",
|
|
13
13
|
"@wemap/geomagnetism": "^0.1.1",
|
|
14
|
-
"@wemap/logger": "^9.
|
|
15
|
-
"@wemap/map": "^9.
|
|
14
|
+
"@wemap/logger": "^9.2.0",
|
|
15
|
+
"@wemap/map": "^9.2.0",
|
|
16
16
|
"@wemap/maths": "^9.0.0",
|
|
17
|
-
"@wemap/osm": "^9.
|
|
18
|
-
"@wemap/routers": "^9.
|
|
17
|
+
"@wemap/osm": "^9.2.0",
|
|
18
|
+
"@wemap/routers": "^9.2.0",
|
|
19
19
|
"@wemap/utils": "^9.0.0"
|
|
20
20
|
},
|
|
21
21
|
"description": "A package using different geoloc systems",
|
|
@@ -42,6 +42,6 @@
|
|
|
42
42
|
"url": "git+https://github.com/wemap/wemap-modules-js.git"
|
|
43
43
|
},
|
|
44
44
|
"type": "module",
|
|
45
|
-
"version": "9.
|
|
46
|
-
"gitHead": "
|
|
45
|
+
"version": "9.2.0",
|
|
46
|
+
"gitHead": "9eee407fadd76fc5cbfbeeb13be0d74391ca5d9e"
|
|
47
47
|
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/* eslint-disable max-statements */
|
|
2
|
+
class StepDetectionMinMaxPeaks3 {
|
|
3
|
+
|
|
4
|
+
// in seconds
|
|
5
|
+
static WINDOW_TIME = 0.6;
|
|
6
|
+
|
|
7
|
+
// in seconds
|
|
8
|
+
static MIN_TIME_BETWEEN_STEPS = 0.6;
|
|
9
|
+
|
|
10
|
+
// in Hz
|
|
11
|
+
static MAX_FRENQUENCY = 4;
|
|
12
|
+
static MIN_FRENQUENCY = 1;
|
|
13
|
+
|
|
14
|
+
// in m.s-2
|
|
15
|
+
static VERTICAL_ACC_POSITIVE_PEAK_THRESHOLD = 0.2;
|
|
16
|
+
static VERTICAL_ACC_NEGATIVE_PEAK_THRESHOLD = -0.1;
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
constructor() {
|
|
20
|
+
this.slidingWindow = [];
|
|
21
|
+
|
|
22
|
+
this.lastStepTimestamp = -StepDetectionMinMaxPeaks3.MIN_TIME_BETWEEN_STEPS;
|
|
23
|
+
this.previousVerticalAcc = 0;
|
|
24
|
+
this.previousHorizontalAcc = 0;
|
|
25
|
+
this.influence = 0.05;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
compute(timestamp, linearAcc) {
|
|
30
|
+
|
|
31
|
+
const verticalAcc = this.influence * linearAcc[2] + (1 - this.influence) * this.previousVerticalAcc;
|
|
32
|
+
this.previousVerticalAcc = verticalAcc;
|
|
33
|
+
|
|
34
|
+
// let horizontalAcc = Math.sqrt(linearAcc[0] ** 2 + linearAcc[1] ** 2);
|
|
35
|
+
// horizontalAcc = this.influence * horizontalAcc + (1 - this.influence) * this.previousHorizontalAcc;
|
|
36
|
+
// this.previousHorizontalAcc = horizontalAcc;
|
|
37
|
+
|
|
38
|
+
// const angularRateNorm = Math.sqrt(angularRate[0] ** 2 + angularRate[1] ** 2 + angularRate[2] ** 2);
|
|
39
|
+
// horizontalAcc = this.influence * horizontalAcc + (1 - this.influence) * this.previousHorizontalAcc;
|
|
40
|
+
// this.previousangularRateNorm = angularRateNorm;
|
|
41
|
+
|
|
42
|
+
// Update sliding window
|
|
43
|
+
this.slidingWindow = this.slidingWindow.filter(item =>
|
|
44
|
+
item.timestamp >= timestamp - StepDetectionMinMaxPeaks3.WINDOW_TIME
|
|
45
|
+
);
|
|
46
|
+
this.slidingWindow.push({ timestamp, verticalAcc });
|
|
47
|
+
// , horizontalAcc });
|
|
48
|
+
|
|
49
|
+
// this.horizontalAccStd = this.stddev(this.slidingWindow.map(el => el.horizontalAcc));
|
|
50
|
+
// this.verticalAccStd = this.stddev(this.slidingWindow.map(el => el.verticalAcc));
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
const isTooEarlyForANewStep = this.lastStepTimestamp
|
|
54
|
+
&& this.lastStepTimestamp + StepDetectionMinMaxPeaks3.MIN_TIME_BETWEEN_STEPS > timestamp;
|
|
55
|
+
if (isTooEarlyForANewStep) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Looking for max peak
|
|
60
|
+
let maxValue = Number.MIN_VALUE;
|
|
61
|
+
let maxValueIdx = -1;
|
|
62
|
+
let foundMaxPeakHigherThanThreshold = false;
|
|
63
|
+
this.slidingWindow.forEach(function(item, idx) {
|
|
64
|
+
if (item.verticalAcc > maxValue
|
|
65
|
+
&& item.verticalAcc >= StepDetectionMinMaxPeaks3.VERTICAL_ACC_POSITIVE_PEAK_THRESHOLD) {
|
|
66
|
+
maxValue = item.verticalAcc;
|
|
67
|
+
maxValueIdx = idx;
|
|
68
|
+
foundMaxPeakHigherThanThreshold = true;
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
if (!foundMaxPeakHigherThanThreshold) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Looking for a value lower than a threshold before the max peak
|
|
76
|
+
let hasLowNegativeValueBeforeMaxPeak = false;
|
|
77
|
+
let minValueBeforeMaxPeak = Number.MAX_VALUE;
|
|
78
|
+
for (let i = 0; i < maxValueIdx; i++) {
|
|
79
|
+
const curValue = this.slidingWindow[i].verticalAcc;
|
|
80
|
+
minValueBeforeMaxPeak = Math.min(minValueBeforeMaxPeak, curValue);
|
|
81
|
+
if (curValue < StepDetectionMinMaxPeaks3.VERTICAL_ACC_NEGATIVE_PEAK_THRESHOLD) {
|
|
82
|
+
hasLowNegativeValueBeforeMaxPeak = true;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (!hasLowNegativeValueBeforeMaxPeak) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// looking for another minimum after max peak
|
|
91
|
+
const diffMinMax = maxValue - minValueBeforeMaxPeak;
|
|
92
|
+
const targetValue = maxValue - 0.5 * diffMinMax;
|
|
93
|
+
let targetValueFoundAfterMaxPeak = false;
|
|
94
|
+
for (let i = maxValueIdx + 1; i < this.slidingWindow.length; i++) {
|
|
95
|
+
if (this.slidingWindow[i].verticalAcc <= targetValue) {
|
|
96
|
+
targetValueFoundAfterMaxPeak = true;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (!targetValueFoundAfterMaxPeak) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// // looking for another local minimum / maximum after 100ms
|
|
105
|
+
// let localMinimumFound = false;
|
|
106
|
+
// let localMaximumFound = false;
|
|
107
|
+
// let localMaxiumValue = Number.MIN_SAFE_INTEGER;
|
|
108
|
+
// let localMinimumVal = null;
|
|
109
|
+
// const maxPeakTimestamp = this.slidingWindow[maxValueIdx].timestamp;
|
|
110
|
+
// for (let i = maxValueIdx + 1; i < this.slidingWindow.length; i++) {
|
|
111
|
+
// const curVal = this.slidingWindow[i];
|
|
112
|
+
// const prevVal = this.slidingWindow[i - 1];
|
|
113
|
+
|
|
114
|
+
// if (curVal.timestamp > maxPeakTimestamp + 0.4) {
|
|
115
|
+
// break;
|
|
116
|
+
// }
|
|
117
|
+
|
|
118
|
+
// if (!localMinimumFound) {
|
|
119
|
+
// // if (curVal.timestamp < maxPeakTimestamp + 0.05) {
|
|
120
|
+
// // // too early
|
|
121
|
+
// // continue;
|
|
122
|
+
// // }
|
|
123
|
+
|
|
124
|
+
// if (curVal.verticalAcc > prevVal.verticalAcc) {
|
|
125
|
+
// localMinimumFound = true;
|
|
126
|
+
// localMinimumVal = prevVal;
|
|
127
|
+
// }
|
|
128
|
+
// continue;
|
|
129
|
+
// }
|
|
130
|
+
|
|
131
|
+
// if (!localMaximumFound) {
|
|
132
|
+
|
|
133
|
+
// // if (curVal.timestamp < localMinimumVal.timestamp + 0.05) {
|
|
134
|
+
// // // too early
|
|
135
|
+
// // continue;
|
|
136
|
+
// // }
|
|
137
|
+
|
|
138
|
+
// if (curVal.verticalAcc < prevVal.verticalAcc) {
|
|
139
|
+
// localMaximumFound = true;
|
|
140
|
+
// localMaxiumValue = prevVal.verticalAcc;
|
|
141
|
+
// break;
|
|
142
|
+
// }
|
|
143
|
+
// }
|
|
144
|
+
// }
|
|
145
|
+
// const localMinMaxFoundAfterPeak = localMinimumFound && localMaximumFound;
|
|
146
|
+
// // && localMaxiumValue / maxValue < 0.8;
|
|
147
|
+
// // if (!localMinMaxFoundAfterPeak) {
|
|
148
|
+
// // return false;
|
|
149
|
+
// // }
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
// const highRotationDetected = angularRateNorm > 0.75;
|
|
153
|
+
// // if (highRotationDetected) {
|
|
154
|
+
// // return false;
|
|
155
|
+
// // }
|
|
156
|
+
|
|
157
|
+
const timeInterval = this.lastStepTimestamp ? timestamp - this.lastStepTimestamp : 1;
|
|
158
|
+
this.frequency = Math.min(Math.max((1 / timeInterval), StepDetectionMinMaxPeaks3.MIN_FRENQUENCY), StepDetectionMinMaxPeaks3.MAX_FRENQUENCY);
|
|
159
|
+
|
|
160
|
+
this.lastStepTimestamp = timestamp;
|
|
161
|
+
return true;
|
|
162
|
+
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
get lastStepSize() {
|
|
166
|
+
|
|
167
|
+
if (!this.frequency) {
|
|
168
|
+
return 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const kParamA = 0.45;
|
|
172
|
+
const kParamB = 0.2;
|
|
173
|
+
return kParamA + kParamB * this.frequency;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
get speed() {
|
|
177
|
+
return this.lastStepSize && this.frequency ? this.lastStepSize * this.frequency : 0;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
mean(data) {
|
|
181
|
+
let sum = 0.0, mean = 0.0;
|
|
182
|
+
|
|
183
|
+
for (let i = 0; i < data.length; ++i) {
|
|
184
|
+
sum += data[i];
|
|
185
|
+
}
|
|
186
|
+
mean = sum / data.length;
|
|
187
|
+
return mean;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
stddev(data) {
|
|
191
|
+
const theMean = this.mean(data);
|
|
192
|
+
let standardDeviation = 0;
|
|
193
|
+
for (let i = 0; i < data.length; ++i) {
|
|
194
|
+
standardDeviation += (data[i] - theMean) ** 2;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return Math.sqrt(standardDeviation / data.length);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export default StepDetectionMinMaxPeaks3;
|
|
@@ -6,7 +6,10 @@ import RelativeAttitudeFromInertial from '../attitude/relative/RelativeAttitudeF
|
|
|
6
6
|
import Accelerometer from '../imu/Accelerometer.js';
|
|
7
7
|
import Gyroscope from '../imu/Gyroscope.js';
|
|
8
8
|
import Provider from '../Provider.js';
|
|
9
|
+
import StepDetectionLadetto from './StepDetectionLadetto.js';
|
|
10
|
+
import StepDetectionMinMaxPeaks from './StepDetectionMinMaxPeaks.js';
|
|
9
11
|
import StepDetectionMinMaxPeaks2 from './StepDetectionMinMaxPeaks2.js';
|
|
12
|
+
import StepDetectionMinMaxPeaks3 from './StepDetectionMinMaxPeaks3.js';
|
|
10
13
|
|
|
11
14
|
|
|
12
15
|
class StepDetector extends Provider {
|
|
@@ -14,11 +17,19 @@ class StepDetector extends Provider {
|
|
|
14
17
|
/** @type {number} */
|
|
15
18
|
static DEFAULT_STEP_SIZE_MULTIPLIER = 1;
|
|
16
19
|
|
|
20
|
+
// ladetto, minMaxPeaks, minMaxPeaks2, minMaxPeaks3
|
|
21
|
+
static DEFAULT_ALGORITHM = 'minMaxPeaks3';
|
|
22
|
+
|
|
17
23
|
_stepSizeMultiplier = StepDetector.DEFAULT_STEP_SIZE_MULTIPLIER;
|
|
18
24
|
|
|
25
|
+
/** @type {string} */
|
|
26
|
+
_algorithm = StepDetector.DEFAULT_ALGORITHM;
|
|
27
|
+
|
|
28
|
+
_accValues = [];
|
|
29
|
+
|
|
19
30
|
constructor() {
|
|
20
31
|
super();
|
|
21
|
-
this.
|
|
32
|
+
this.algorithm = this._algorithm;
|
|
22
33
|
}
|
|
23
34
|
|
|
24
35
|
/**
|
|
@@ -115,6 +126,26 @@ class StepDetector extends Provider {
|
|
|
115
126
|
get stepSizeMultiplier() {
|
|
116
127
|
return this._stepSizeMultiplier;
|
|
117
128
|
}
|
|
129
|
+
|
|
130
|
+
set algorithm(algorithm) {
|
|
131
|
+
switch (algorithm) {
|
|
132
|
+
case 'ladetto':
|
|
133
|
+
this.stepDetector = new StepDetectionLadetto();
|
|
134
|
+
break;
|
|
135
|
+
case 'minMaxPeaks':
|
|
136
|
+
this.stepDetector = new StepDetectionMinMaxPeaks();
|
|
137
|
+
break;
|
|
138
|
+
case 'minMaxPeaks2':
|
|
139
|
+
this.stepDetector = new StepDetectionMinMaxPeaks2();
|
|
140
|
+
break;
|
|
141
|
+
case 'minMaxPeaks3':
|
|
142
|
+
default:
|
|
143
|
+
algorithm = 'minMaxPeaks3';
|
|
144
|
+
this.stepDetector = new StepDetectionMinMaxPeaks3();
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
this._algorithm = algorithm;
|
|
148
|
+
}
|
|
118
149
|
}
|
|
119
150
|
|
|
120
151
|
export default new StepDetector();
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Constants as GeoConstants } from '@wemap/geo';
|
|
2
|
+
import { Quaternion } from '@wemap/maths';
|
|
3
|
+
|
|
4
|
+
import EventType from '../../events/EventType.js';
|
|
5
|
+
import RelativeAttitudeFromInertial from '../attitude/relative/RelativeAttitudeFromInertial.js';
|
|
6
|
+
import Accelerometer from '../imu/Accelerometer.js';
|
|
7
|
+
import Gyroscope from '../imu/Gyroscope.js';
|
|
8
|
+
import Provider from '../Provider.js';
|
|
9
|
+
import StepDetectionLadetto from './StepDetectionLadetto.js';
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class StepDetectorLadetto extends Provider {
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
this.stepDetector = new StepDetectionLadetto();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @override
|
|
21
|
+
*/
|
|
22
|
+
static get pname() {
|
|
23
|
+
return 'StepDetectorLadetto';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @override
|
|
28
|
+
*/
|
|
29
|
+
get _availability() {
|
|
30
|
+
return Promise.all([
|
|
31
|
+
Accelerometer.availability,
|
|
32
|
+
Gyroscope.availability,
|
|
33
|
+
RelativeAttitudeFromInertial.availability
|
|
34
|
+
]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @override
|
|
39
|
+
*/
|
|
40
|
+
start() {
|
|
41
|
+
|
|
42
|
+
this.numOfSteps = 0;
|
|
43
|
+
|
|
44
|
+
this.accelerometerProviderId = Accelerometer.addEventListener(
|
|
45
|
+
events => this.onAccelerometerEvent(events[0]),
|
|
46
|
+
error => this.notifyError(error)
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
this.gyroscopeProviderId = Gyroscope.addEventListener(
|
|
50
|
+
events => (this.angularRateEvent = events[0]),
|
|
51
|
+
error => this.notifyError(error)
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
this.attitudeProviderId = RelativeAttitudeFromInertial.addEventListener(
|
|
55
|
+
events => (this.attitudeEvent = events[0]),
|
|
56
|
+
error => this.notifyError(error)
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @override
|
|
62
|
+
*/
|
|
63
|
+
stop() {
|
|
64
|
+
Accelerometer.removeEventListener(this.accelerometerProviderId);
|
|
65
|
+
Gyroscope.removeEventListener(this.gyroscopeProviderId);
|
|
66
|
+
RelativeAttitudeFromInertial.removeEventListener(this.attitudeProviderId);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
onAccelerometerEvent(accelerationEvent) {
|
|
70
|
+
|
|
71
|
+
if (!this.attitudeEvent || !this.angularRateEvent) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const {
|
|
76
|
+
values: acceleration, timestamp
|
|
77
|
+
} = accelerationEvent.data;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Step Detection and Step Size Detection
|
|
81
|
+
*/
|
|
82
|
+
const linearAcc = this.constructor.computeLinearAcceleration(
|
|
83
|
+
this.attitudeEvent.data.quaternion, acceleration);
|
|
84
|
+
const stepDetected = this.stepDetector.compute(timestamp, linearAcc, this.angularRateEvent.data.values);
|
|
85
|
+
|
|
86
|
+
if (stepDetected) {
|
|
87
|
+
const size = this.stepDetector.lastStepSize;
|
|
88
|
+
this.numOfSteps++;
|
|
89
|
+
this.notify(this.createEvent(
|
|
90
|
+
EventType.Step, {
|
|
91
|
+
size,
|
|
92
|
+
number: this.numOfSteps
|
|
93
|
+
},
|
|
94
|
+
[accelerationEvent, this.angularRateEvent, this.attitudeEvent]
|
|
95
|
+
));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Linear acceleration in ENU
|
|
100
|
+
static computeLinearAcceleration(quaternion, acc) {
|
|
101
|
+
const linearAcc = Quaternion.rotateMatlab(Quaternion.inverse(quaternion), acc);
|
|
102
|
+
linearAcc[2] -= GeoConstants.EARTH_GRAVITY;
|
|
103
|
+
return linearAcc;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export default new StepDetectorLadetto();
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Constants as GeoConstants } from '@wemap/geo';
|
|
2
|
+
import { Quaternion } from '@wemap/maths';
|
|
3
|
+
|
|
4
|
+
import EventType from '../../events/EventType.js';
|
|
5
|
+
import RelativeAttitudeFromInertial from '../attitude/relative/RelativeAttitudeFromInertial.js';
|
|
6
|
+
import Accelerometer from '../imu/Accelerometer.js';
|
|
7
|
+
import Gyroscope from '../imu/Gyroscope.js';
|
|
8
|
+
import Provider from '../Provider.js';
|
|
9
|
+
import StepDetectionMinMaxPeaks from './StepDetectionMinMaxPeaks.js';
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class StepDetectorMinMaxPeaks extends Provider {
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
this.stepDetector = new StepDetectionMinMaxPeaks();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @override
|
|
21
|
+
*/
|
|
22
|
+
static get pname() {
|
|
23
|
+
return 'StepDetectorMinMaxPeaks';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @override
|
|
28
|
+
*/
|
|
29
|
+
get _availability() {
|
|
30
|
+
return Promise.all([
|
|
31
|
+
Accelerometer.availability,
|
|
32
|
+
Gyroscope.availability,
|
|
33
|
+
RelativeAttitudeFromInertial.availability
|
|
34
|
+
]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @override
|
|
39
|
+
*/
|
|
40
|
+
start() {
|
|
41
|
+
|
|
42
|
+
this.numOfSteps = 0;
|
|
43
|
+
|
|
44
|
+
this.accelerometerProviderId = Accelerometer.addEventListener(
|
|
45
|
+
events => this.onAccelerometerEvent(events[0]),
|
|
46
|
+
error => this.notifyError(error)
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
this.gyroscopeProviderId = Gyroscope.addEventListener(
|
|
50
|
+
events => (this.angularRateEvent = events[0]),
|
|
51
|
+
error => this.notifyError(error)
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
this.attitudeProviderId = RelativeAttitudeFromInertial.addEventListener(
|
|
55
|
+
events => (this.attitudeEvent = events[0]),
|
|
56
|
+
error => this.notifyError(error)
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @override
|
|
62
|
+
*/
|
|
63
|
+
stop() {
|
|
64
|
+
Accelerometer.removeEventListener(this.accelerometerProviderId);
|
|
65
|
+
Gyroscope.removeEventListener(this.gyroscopeProviderId);
|
|
66
|
+
RelativeAttitudeFromInertial.removeEventListener(this.attitudeProviderId);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
onAccelerometerEvent(accelerationEvent) {
|
|
70
|
+
|
|
71
|
+
if (!this.attitudeEvent || !this.angularRateEvent) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const {
|
|
76
|
+
values: acceleration, timestamp
|
|
77
|
+
} = accelerationEvent.data;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Step Detection and Step Size Detection
|
|
81
|
+
*/
|
|
82
|
+
const linearAcc = this.constructor.computeLinearAcceleration(
|
|
83
|
+
this.attitudeEvent.data.quaternion, acceleration);
|
|
84
|
+
const stepDetected = this.stepDetector.compute(timestamp, linearAcc, this.angularRateEvent.data.values);
|
|
85
|
+
|
|
86
|
+
if (stepDetected) {
|
|
87
|
+
const size = this.stepDetector.lastStepSize;
|
|
88
|
+
this.numOfSteps++;
|
|
89
|
+
this.notify(this.createEvent(
|
|
90
|
+
EventType.Step, {
|
|
91
|
+
size,
|
|
92
|
+
number: this.numOfSteps
|
|
93
|
+
},
|
|
94
|
+
[accelerationEvent, this.angularRateEvent, this.attitudeEvent]
|
|
95
|
+
));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Linear acceleration in ENU
|
|
100
|
+
static computeLinearAcceleration(quaternion, acc) {
|
|
101
|
+
const linearAcc = Quaternion.rotateMatlab(Quaternion.inverse(quaternion), acc);
|
|
102
|
+
linearAcc[2] -= GeoConstants.EARTH_GRAVITY;
|
|
103
|
+
return linearAcc;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export default new StepDetectorMinMaxPeaks();
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Constants as GeoConstants } from '@wemap/geo';
|
|
2
|
+
import { Quaternion } from '@wemap/maths';
|
|
3
|
+
|
|
4
|
+
import EventType from '../../events/EventType.js';
|
|
5
|
+
import RelativeAttitudeFromInertial from '../attitude/relative/RelativeAttitudeFromInertial.js';
|
|
6
|
+
import Accelerometer from '../imu/Accelerometer.js';
|
|
7
|
+
import Gyroscope from '../imu/Gyroscope.js';
|
|
8
|
+
import Provider from '../Provider.js';
|
|
9
|
+
import StepDetectionMinMaxPeaks2 from './StepDetectionMinMaxPeaks2.js';
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class StepDetectorMinMaxPeaks2 extends Provider {
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
this.stepDetector = new StepDetectionMinMaxPeaks2();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @override
|
|
21
|
+
*/
|
|
22
|
+
static get pname() {
|
|
23
|
+
return 'StepDetectorMinMaxPeaks2';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @override
|
|
28
|
+
*/
|
|
29
|
+
get _availability() {
|
|
30
|
+
return Promise.all([
|
|
31
|
+
Accelerometer.availability,
|
|
32
|
+
Gyroscope.availability,
|
|
33
|
+
RelativeAttitudeFromInertial.availability
|
|
34
|
+
]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @override
|
|
39
|
+
*/
|
|
40
|
+
start() {
|
|
41
|
+
|
|
42
|
+
this.numOfSteps = 0;
|
|
43
|
+
|
|
44
|
+
this.accelerometerProviderId = Accelerometer.addEventListener(
|
|
45
|
+
events => this.onAccelerometerEvent(events[0]),
|
|
46
|
+
error => this.notifyError(error)
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
this.gyroscopeProviderId = Gyroscope.addEventListener(
|
|
50
|
+
events => (this.angularRateEvent = events[0]),
|
|
51
|
+
error => this.notifyError(error)
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
this.attitudeProviderId = RelativeAttitudeFromInertial.addEventListener(
|
|
55
|
+
events => (this.attitudeEvent = events[0]),
|
|
56
|
+
error => this.notifyError(error)
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @override
|
|
62
|
+
*/
|
|
63
|
+
stop() {
|
|
64
|
+
Accelerometer.removeEventListener(this.accelerometerProviderId);
|
|
65
|
+
Gyroscope.removeEventListener(this.gyroscopeProviderId);
|
|
66
|
+
RelativeAttitudeFromInertial.removeEventListener(this.attitudeProviderId);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
onAccelerometerEvent(accelerationEvent) {
|
|
70
|
+
|
|
71
|
+
if (!this.attitudeEvent || !this.angularRateEvent) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const {
|
|
76
|
+
values: acceleration, timestamp
|
|
77
|
+
} = accelerationEvent.data;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Step Detection and Step Size Detection
|
|
81
|
+
*/
|
|
82
|
+
const linearAcc = this.constructor.computeLinearAcceleration(
|
|
83
|
+
this.attitudeEvent.data.quaternion, acceleration);
|
|
84
|
+
const stepDetected = this.stepDetector.compute(timestamp, linearAcc, this.angularRateEvent.data.values);
|
|
85
|
+
|
|
86
|
+
if (stepDetected) {
|
|
87
|
+
const size = this.stepDetector.lastStepSize;
|
|
88
|
+
this.numOfSteps++;
|
|
89
|
+
this.notify(this.createEvent(
|
|
90
|
+
EventType.Step, {
|
|
91
|
+
size,
|
|
92
|
+
number: this.numOfSteps
|
|
93
|
+
},
|
|
94
|
+
[accelerationEvent, this.angularRateEvent, this.attitudeEvent]
|
|
95
|
+
));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Linear acceleration in ENU
|
|
100
|
+
static computeLinearAcceleration(quaternion, acc) {
|
|
101
|
+
const linearAcc = Quaternion.rotateMatlab(Quaternion.inverse(quaternion), acc);
|
|
102
|
+
linearAcc[2] -= GeoConstants.EARTH_GRAVITY;
|
|
103
|
+
return linearAcc;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export default new StepDetectorMinMaxPeaks2();
|