1 /*
2 * Copyright (C) 2020 Alberto Irurueta Carro (alberto@irurueta.com)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package com.irurueta.navigation.inertial.calibration.intervals;
17
18 import com.irurueta.navigation.LockedException;
19 import com.irurueta.navigation.inertial.calibration.Triad;
20 import com.irurueta.navigation.inertial.calibration.noise.AccumulatedTriadNoiseEstimator;
21 import com.irurueta.navigation.inertial.calibration.noise.WindowedTriadNoiseEstimator;
22 import com.irurueta.units.Measurement;
23 import com.irurueta.units.Time;
24 import com.irurueta.units.TimeConverter;
25 import com.irurueta.units.TimeUnit;
26
27 /**
28 * Abstract base class for detectors in charge of determining when a static period of
29 * measurements starts and finishes.
30 * Static periods are periods of time where the device is considered to
31 * remain static (no movement applied to it).
32 *
33 * @param <U> type of unit.
34 * @param <M> a type of measurement.
35 * @param <T> a triad type.
36 * @param <D> a detector type.
37 * @param <L> a listener type.
38 */
39 public abstract class TriadStaticIntervalDetector<U extends Enum<?>, M extends Measurement<U>,
40 T extends Triad<U, M, T>, D extends TriadStaticIntervalDetector<U, M, T, D, L>,
41 L extends TriadStaticIntervalDetectorListener<U, M, T, D>> {
42
43 /**
44 * Number of samples to keep within the window by default.
45 * For a sensor generating 100 samples/second, this is equivalent to 1 second.
46 * For a sensor generating 50 samples/second, this is equivalent to 2 seconds.
47 */
48 public static final int DEFAULT_WINDOW_SIZE = WindowedTriadNoiseEstimator.DEFAULT_WINDOW_SIZE;
49
50 /**
51 * Number of samples to process during the initial static period to determine the sensor
52 * (accelerometer, gyroscope or magnetometer) noise level.
53 * For a sensor generating 100 samples/second, this is equivalent to 50 seconds.
54 * For a sensor generating 50 samples/second, this is equivalent to 100 seconds.
55 */
56 public static final int DEFAULT_INITIAL_STATIC_SAMPLES = 5000;
57
58 /**
59 * Minimum allowed number of samples to be processed during the initial static period.
60 */
61 public static final int MINIMUM_INITIAL_STATIC_SAMPLES = 2;
62
63 /**
64 * Default factor to be applied to detected base noise level in order to determine
65 * threshold for static/dynamic period changes. This factor is unit-less.
66 */
67 public static final double DEFAULT_THRESHOLD_FACTOR = 2.0;
68
69 /**
70 * Default factor to determine that a sudden movement has occurred during initialization
71 * if instantaneous noise level exceeds accumulated noise level by this factor amount.
72 * This factor is unit-less.
73 */
74 public static final double DEFAULT_INSTANTANEOUS_NOISE_LEVEL_FACTOR = 2.0;
75
76 /**
77 * Default overall absolute threshold to determine whether there has been excessive motion
78 * during the whole initialization phase.
79 * This threshold is expressed in meters per squared second (m/s^2) for acceleration, radians
80 * per second (rad/s) for angular speed or Teslas (T) for magnetic flux density, and by
81 * default it is set to the maximum allowed value, thus effectively disabling this error
82 * condition check during initialization.
83 */
84 public static final double DEFAULT_BASE_NOISE_LEVEL_ABSOLUTE_THRESHOLD = Double.MAX_VALUE;
85
86 /**
87 * Number of samples to keep in window to find instantaneous noise level averaged within
88 * the window of samples.
89 * Window size should contain about 1 or 2 seconds of data to be averaged to obtain
90 * a more reliable instantaneous noise level.
91 */
92 private int windowSize = DEFAULT_WINDOW_SIZE;
93
94 /**
95 * Number of samples to be processed initially while keeping the sensor static in order
96 * to find the base noise level when device is static.
97 */
98 private int initialStaticSamples = DEFAULT_INITIAL_STATIC_SAMPLES;
99
100 /**
101 * Factor to be applied to detected base noise level in order to determine
102 * threshold for static/dynamic period changes. This factor is unit-less.
103 */
104 private double thresholdFactor = DEFAULT_THRESHOLD_FACTOR;
105
106 /**
107 * Factor to determine that a sudden movement has occurred during initialization if
108 * instantaneous noise level exceeds accumulated noise level by this factor amount.
109 * This factor is unit-less.
110 */
111 private double instantaneousNoiseLevelFactor = DEFAULT_INSTANTANEOUS_NOISE_LEVEL_FACTOR;
112
113 /**
114 * Overall absolute threshold to determine whether there has been excessive motion
115 * during the whole initialization phase.
116 * Failure will be detected if estimated base noise level exceeds this threshold when
117 * initialization completes.
118 * This threshold is expressed in meters per squared second (m/s^2) for acceleration,
119 * radians per second (rad/s) for angular speed or Teslas (T) for magnetic flux density.
120 */
121 private double baseNoiseLevelAbsoluteThreshold = DEFAULT_BASE_NOISE_LEVEL_ABSOLUTE_THRESHOLD;
122
123 /**
124 * Listener to handle events generated by this detector.
125 */
126 private L listener;
127
128 /**
129 * Current status of this detector.
130 */
131 private Status status = Status.IDLE;
132
133 /**
134 * Measurement base noise level that has been detected during initialization expressed in
135 * meters per squared second (m/s^2) for acceleration, radians per second (rad/s) for
136 * angular speed or Teslas (T) for magnetic flux density.
137 */
138 private double baseNoiseLevel;
139
140 /**
141 * Threshold to determine static/dynamic period changes expressed in meters per squared
142 * second (m/s^2) for acceleration, radians per second (rad/s) for angular speed or
143 * Teslas (T) for magnetic flux density.
144 */
145 private double threshold;
146
147 /**
148 * Indicates whether this detector is busy processing last provided sample.
149 */
150 private boolean running;
151
152 /**
153 * Number of samples that have been processed so far.
154 */
155 private int processedSamples;
156
157 /**
158 * Average x-coordinate of measurements accumulated during last static
159 * period expressed in meters per squared second (m/s^2) for acceleration,
160 * radians per second (rad/s) for angular speed or Teslas (T) for
161 * magnetic flux density.
162 * This value is updated when switching from a static period to a dynamic
163 * one or after completing initialization.
164 */
165 private double accumulatedAvgX;
166
167 /**
168 * Average y-coordinate of measurements accumulated during last static
169 * period expressed in meters per squared second (m/s^2) for acceleration,
170 * radians per second (rad/s) for angular speed or Teslas (T) for
171 * magnetic flux density.
172 * This value is updated when switching from a static period to a dynamic
173 * one or after completing initialization.
174 */
175 private double accumulatedAvgY;
176
177 /**
178 * Average z-coordinate of measurements accumulated during last static
179 * period expressed in meters per squared second (m/s^2) for acceleration,
180 * radians per second (rad/s) for angular speed or Teslas (T) for
181 * magnetic flux density.
182 * This value is updated when switching from a static period to a dynamic
183 * one or after completing initialization.
184 */
185 private double accumulatedAvgZ;
186
187 /**
188 * Standard deviation of x-coordinate of measurements accumulated during
189 * last static period expressed in meters per squared second (m/s^2) for
190 * acceleration, radians per second (rad/s) for angular speed or Teslas
191 * (T) for magnetic flux density.
192 * This value is updated when switching from a static period to a dynamic
193 * one or after completing initialization.
194 */
195 private double accumulatedStdX;
196
197 /**
198 * Standard deviation of y-coordinate of measurements accumulated during
199 * last static period expressed in meters per squared second (m/s^2) for
200 * acceleration, radians per second (rad/s) for angular speed or Teslas
201 * (T) for magnetic flux density.
202 * This value is updated when switching from a static period to a dynamic
203 * one or after completing initialization.
204 */
205 private double accumulatedStdY;
206
207 /**
208 * Standard deviation of z-coordinate of measurements accumulated during
209 * last static period expressed in meters per squared second (m/s^2) for
210 * acceleration, radians per second (rad/s) for angular speed or Teslas
211 * (T) for magnetic flux density.
212 * This value is updated when switching from a static period to a dynamic
213 * one or after completing initialization.
214 */
215 private double accumulatedStdZ;
216
217 /**
218 * Windowed average x-coordinate of measurements for each processed triad
219 * expressed in meters per squared second (m/s^2) for acceleration,
220 * radians per second (rad/s) for angular speed or Teslas (T) for
221 * magnetic flux density.
222 * This value is updated for each processed sample containing an average
223 * value for the samples within the window.
224 */
225 private double instantaneousAvgX;
226
227 /**
228 * Windowed average y-coordinate of measurements for each processed triad
229 * expressed in meters per squared second (m/s^2) for acceleration,
230 * radians per second (rad/s) for angular speed or Teslas (T) for
231 * magnetic flux density.
232 * This value is updated for each processed sample containing an average
233 * value for the samples within the window.
234 */
235 private double instantaneousAvgY;
236
237 /**
238 * Windowed average z-coordinate of measurements for each processed triad
239 * expressed in meters per squared second (m/s^2) for acceleration,
240 * radians per second (rad/s) for angular speed or Teslas (T) for
241 * magnetic flux density.
242 * This value is updated for each processed sample containing an average
243 * value for the samples within the window.
244 */
245 private double instantaneousAvgZ;
246
247 /**
248 * Windowed standard deviation of x-coordinate of measurements for each
249 * processed triad expressed in meters per squared second (m/s^2) for
250 * acceleration, radians per second (rad/s) for angular speed or Teslas (T)
251 * for magnetic flux density.
252 * This value is updated for each processed sample containing measured standard
253 * deviation for the samples within the window.
254 */
255 private double instantaneousStdX;
256
257 /**
258 * Windowed standard deviation of y-coordinate of measurements for each
259 * processed triad expressed in meters per squared second (m/s^2) for
260 * acceleration, radians per second (rad/s) for angular speed or Teslas (T)
261 * for magnetic flux density.
262 * This value is updated for each processed sample containing measured standard
263 * deviation for the samples within the window.
264 */
265 private double instantaneousStdY;
266
267 /**
268 * Windowed standard deviation of z-coordinate of measurements for each
269 * processed triad expressed in meters per squared second (m/s^2) for
270 * acceleration, radians per second (rad/s) for angular speed or Teslas (T)
271 * for magnetic flux density.
272 * This value is updated for each processed sample containing measured standard
273 * deviation for the samples within the window.
274 */
275 private double instantaneousStdZ;
276
277 /**
278 * Estimator to find instantaneous measurement noise level averaged for a certain window of samples.
279 */
280 private final WindowedTriadNoiseEstimator<U, M, T, ?, ?> windowedNoiseEstimator;
281
282 /**
283 * Estimator to find accumulated accelerometer noise level.
284 */
285 private final AccumulatedTriadNoiseEstimator<U, M, T, ?, ?> accumulatedNoiseEstimator;
286
287 /**
288 * Constructor.
289 *
290 * @param windowedNoiseEstimator windowed noise estimator to estimate noise within a window of measures.
291 * @param accumulatedNoiseEstimator accumulated noise estimator to estimate accumulated noise and average.
292 */
293 protected TriadStaticIntervalDetector(
294 final WindowedTriadNoiseEstimator<U, M, T, ?, ?> windowedNoiseEstimator,
295 final AccumulatedTriadNoiseEstimator<U, M, T, ?, ?> accumulatedNoiseEstimator) {
296 this.windowedNoiseEstimator = windowedNoiseEstimator;
297 this.accumulatedNoiseEstimator = accumulatedNoiseEstimator;
298 }
299
300 /**
301 * Constructor.
302 *
303 * @param windowedNoiseEstimator windowed noise estimator to estimate noise within a window of measures.
304 * @param accumulatedNoiseEstimator accumulated noise estimator to estimate accumulated noise and average.
305 * @param listener listener to handle events generated by this detector.
306 */
307 protected TriadStaticIntervalDetector(
308 final WindowedTriadNoiseEstimator<U, M, T, ?, ?> windowedNoiseEstimator,
309 final AccumulatedTriadNoiseEstimator<U, M, T, ?, ?> accumulatedNoiseEstimator, final L listener) {
310 this(windowedNoiseEstimator, accumulatedNoiseEstimator);
311 this.listener = listener;
312 }
313
314 /**
315 * Gets length of number of samples to keep within the window being processed
316 * to determine instantaneous accelerometer noise level.
317 *
318 * @return length of number of samples to keep within the window.
319 */
320 public int getWindowSize() {
321 return windowSize;
322 }
323
324 /**
325 * Sets length of number of samples to keep within the window being processed
326 * to determine instantaneous accelerometer noise level.
327 * Window size must always be larger than allowed minimum value, which is 2 and
328 * must have and odd value.
329 *
330 * @param windowSize length of number of samples to keep within the window.
331 * @throws LockedException if detector is busy processing a previous sample.
332 * @throws IllegalArgumentException if provided value is not valid.
333 */
334 public void setWindowSize(final int windowSize) throws LockedException {
335 if (running) {
336 throw new LockedException();
337 }
338
339 windowedNoiseEstimator.setWindowSize(windowSize);
340 this.windowSize = windowSize;
341 }
342
343 /**
344 * Gets number of samples to be processed initially while keeping the sensor static in order
345 * to find the base noise level when device is static.
346 *
347 * @return number of samples to be processed initially.
348 */
349 public int getInitialStaticSamples() {
350 return initialStaticSamples;
351 }
352
353 /**
354 * Sets number of samples to be processed initially while keeping the sensor static in order
355 * to find the base noise level when device is static.
356 *
357 * @param initialStaticSamples number of samples to be processed initially.
358 * @throws LockedException if detector is busy.
359 * @throws IllegalArgumentException if provided value is less than {@link #MINIMUM_INITIAL_STATIC_SAMPLES}
360 */
361 public void setInitialStaticSamples(final int initialStaticSamples) throws LockedException {
362 if (running) {
363 throw new LockedException();
364 }
365
366 if (initialStaticSamples < MINIMUM_INITIAL_STATIC_SAMPLES) {
367 throw new IllegalArgumentException();
368 }
369
370 this.initialStaticSamples = initialStaticSamples;
371 }
372
373 /**
374 * Gets factor to be applied to detected base noise level in order to
375 * determine threshold for static/dynamic period changes. This factor is
376 * unit-less.
377 *
378 * @return factor to be applied to detected base noise level.
379 */
380 public double getThresholdFactor() {
381 return thresholdFactor;
382 }
383
384 /**
385 * Sets factor to be applied to detected base noise level in order to
386 * determine threshold for static/dynamic period changes. This factor is
387 * unit-less.
388 *
389 * @param thresholdFactor factor to be applied to detected base noise level.
390 * @throws LockedException if detector is busy.
391 * @throws IllegalArgumentException if provided value is zero or negative.
392 */
393 public void setThresholdFactor(final double thresholdFactor) throws LockedException {
394 if (running) {
395 throw new LockedException();
396 }
397 if (thresholdFactor <= 0.0) {
398 throw new IllegalArgumentException();
399 }
400
401 this.thresholdFactor = thresholdFactor;
402 }
403
404 /**
405 * Gets factor to determine that a sudden movement has occurred during
406 * initialization if instantaneous noise level exceeds accumulated noise
407 * level by this factor amount.
408 * This factor is unit-less.
409 *
410 * @return factor to determine that a sudden movement has occurred.
411 */
412 public double getInstantaneousNoiseLevelFactor() {
413 return instantaneousNoiseLevelFactor;
414 }
415
416 /**
417 * Sets factor to determine that a sudden movement has occurred during
418 * initialization if instantaneous noise level exceeds accumulated noise
419 * level by this factor amount.
420 * This factor is unit-less.
421 *
422 * @param instantaneousNoiseLevelFactor factor to determine that a sudden
423 * movement has occurred during
424 * initialization.
425 * @throws LockedException if detector is busy.
426 * @throws IllegalArgumentException if provided value is zero or negative.
427 */
428 public void setInstantaneousNoiseLevelFactor(
429 final double instantaneousNoiseLevelFactor) throws LockedException {
430 if (running) {
431 throw new LockedException();
432 }
433 if (instantaneousNoiseLevelFactor <= 0.0) {
434 throw new IllegalArgumentException();
435 }
436
437 this.instantaneousNoiseLevelFactor = instantaneousNoiseLevelFactor;
438 }
439
440 /**
441 * Gets overall absolute threshold to determine whether there has been
442 * excessive motion during the whole initialization phase.
443 * Failure will be detected if estimated base noise level exceeds this
444 * threshold when initialization completes.
445 * This threshold is expressed in meters per squared second (m/s^2) for
446 * acceleration, radians per second (rad/s) for angular speed or Teslas
447 * (T) for magnetic flux density.
448 *
449 * @return overall absolute threshold to determine whether there has
450 * been excessive motion.
451 */
452 public double getBaseNoiseLevelAbsoluteThreshold() {
453 return baseNoiseLevelAbsoluteThreshold;
454 }
455
456 /**
457 * Sets overall absolute threshold to determine whether there has been
458 * excessive motion during the whole initialization phase.
459 * Failure will be detected if estimated base noise level exceeds this
460 * threshold when initialization completes.
461 * This threshold is expressed in meters per squared second (m/s^2) for
462 * acceleration, radians per second (rad/s) for angular speed or Teslas
463 * (T) for magnetic flux density.
464 *
465 * @param baseNoiseLevelAbsoluteThreshold overall absolute threshold to
466 * determine whether there has been
467 * excessive motion.
468 * @throws LockedException if detector is busy.
469 * @throws IllegalArgumentException if provided value is zero or negative.
470 */
471 public void setBaseNoiseLevelAbsoluteThreshold(
472 final double baseNoiseLevelAbsoluteThreshold) throws LockedException {
473 if (running) {
474 throw new LockedException();
475 }
476 if (baseNoiseLevelAbsoluteThreshold <= 0.0) {
477 throw new IllegalArgumentException();
478 }
479
480 this.baseNoiseLevelAbsoluteThreshold = baseNoiseLevelAbsoluteThreshold;
481 }
482
483 /**
484 * Gets overall absolute threshold to determine whether there has been
485 * excessive motion during the whole initialization phase.
486 * Failure will be detected if estimated base noise level exceeds this
487 * threshold when initialization completes.
488 *
489 * @return overall absolute threshold to determine whether there has been
490 * excessive motion.
491 */
492 public M getBaseNoiseLevelAbsoluteThresholdAsMeasurement() {
493 return createMeasurement(baseNoiseLevelAbsoluteThreshold, getDefaultUnit());
494 }
495
496 /**
497 * Gets overall absolute threshold to determine whether there has been
498 * excessive motion during the whole initialization phase.
499 * Failure will be detected if estimated base noise level exceeds this
500 * threshold when initialization completes.
501 *
502 * @param result instance where result will be stored.
503 */
504 public void getBaseNoiseLevelAbsoluteThresholdAsMeasurement(final M result) {
505 result.setValue(baseNoiseLevelAbsoluteThreshold);
506 result.setUnit(getDefaultUnit());
507 }
508
509 /**
510 * Sets overall absolute threshold to determine whether there has been
511 * excessive motion during the whole initialization phase.
512 * Failure will be detected if estimated base noise level exceeds this
513 * threshold when initialization completes.
514 *
515 * @param baseNoiseLevelAbsoluteThreshold overall absolute threshold to
516 * determine whether there has been
517 * excessive motion.
518 * @throws LockedException if detector is busy.
519 * @throws IllegalArgumentException if provided value is zero or negative.
520 */
521 public void setBaseNoiseLevelAbsoluteThreshold(
522 final M baseNoiseLevelAbsoluteThreshold) throws LockedException {
523 if (running) {
524 throw new LockedException();
525 }
526
527 setBaseNoiseLevelAbsoluteThreshold(convertMeasurement(baseNoiseLevelAbsoluteThreshold));
528 }
529
530 /**
531 * Gets listener to handle events generated by this detector.
532 *
533 * @return listener to handle events.
534 */
535 public L getListener() {
536 return listener;
537 }
538
539 /**
540 * Sets listener to handle events generated by this detector.
541 *
542 * @param listener listener to handle events.
543 * @throws LockedException if detector is busy.
544 */
545 public void setListener(final L listener) throws LockedException {
546 if (running) {
547 throw new LockedException();
548 }
549
550 this.listener = listener;
551 }
552
553 /**
554 * Gets time interval between triad samples expressed in seconds (s).
555 *
556 * @return time interval between triad samples.
557 */
558 public double getTimeInterval() {
559 return windowedNoiseEstimator.getTimeInterval();
560 }
561
562 /**
563 * Sets time interval between triad samples expressed in
564 * seconds (s).
565 *
566 * @param timeInterval time interval between triad samples.
567 * @throws IllegalArgumentException if provided value is negative.
568 * @throws LockedException if estimator is currently running.
569 */
570 public void setTimeInterval(final double timeInterval) throws LockedException {
571 if (running) {
572 throw new LockedException();
573 }
574
575 if (timeInterval < 0.0) {
576 throw new IllegalArgumentException();
577 }
578
579 windowedNoiseEstimator.setTimeInterval(timeInterval);
580 accumulatedNoiseEstimator.setTimeInterval(timeInterval);
581 }
582
583 /**
584 * Gets time interval between triad samples.
585 *
586 * @return time interval between triad samples.
587 */
588 public Time getTimeIntervalAsTime() {
589 return new Time(getTimeInterval(), TimeUnit.SECOND);
590 }
591
592 /**
593 * Gets time interval between triad samples.
594 *
595 * @param result instance where time interval will be stored.
596 */
597 public void getTimeIntervalAsTime(final Time result) {
598 result.setValue(getTimeInterval());
599 result.setUnit(TimeUnit.SECOND);
600 }
601
602 /**
603 * Sets time interval between triad samples.
604 *
605 * @param timeInterval time interval between triad samples.
606 * @throws IllegalArgumentException if provided value is negative.
607 * @throws LockedException if estimator is currently running.
608 */
609 public void setTimeInterval(final Time timeInterval) throws LockedException {
610 setTimeInterval(TimeConverter.convert(timeInterval.getValue().doubleValue(), timeInterval.getUnit(),
611 TimeUnit.SECOND));
612 }
613
614 /**
615 * Gets current status of this detector.
616 *
617 * @return current status of this detector.
618 */
619 public Status getStatus() {
620 return status;
621 }
622
623 /**
624 * Gets measurement base noise level that has been detected during
625 * initialization expressed in meters per squared second (m/s^2) for
626 * acceleration, radians per second (rad/s) for angular speed or
627 * Teslas (T) for magnetic flux density.
628 *
629 * @return base noise level.
630 */
631 public double getBaseNoiseLevel() {
632 return baseNoiseLevel;
633 }
634
635 /**
636 * Gets measurement base noise level that has been detected during
637 * initialization.
638 *
639 * @return measurement base noise level.
640 */
641 public M getBaseNoiseLevelAsMeasurement() {
642 return createMeasurement(baseNoiseLevel, getDefaultUnit());
643 }
644
645 /**
646 * Gets measurement base noise level that has been detected during
647 * initialization.
648 *
649 * @param result instance where result will be stored.
650 */
651 public void getBaseNoiseLevelAsMeasurement(final M result) {
652 result.setValue(baseNoiseLevel);
653 result.setUnit(getDefaultUnit());
654 }
655
656 /**
657 * Gets measurement base noise level PSD (Power Spectral Density) expressed in
658 * (m^2 * s^-3) for accelerometer, (rad^2/s) for gyroscope or (T^2 * s) for
659 * magnetometer.
660 *
661 * @return measurement base noise level PSD.
662 */
663 public double getBaseNoiseLevelPsd() {
664 return baseNoiseLevel * baseNoiseLevel * getTimeInterval();
665 }
666
667 /**
668 * Gets measurement base noise level root PSD (Power SpectralDensity) expressed
669 * in (m * s^-1.5) for accelerometer, (rad * s^-0.5) for gyroscope or (T * s^0.5)
670 * for magnetometer.
671 *
672 * @return measurement base noise level root PSD.
673 */
674 public double getBaseNoiseLevelRootPsd() {
675 return baseNoiseLevel * Math.sqrt(getTimeInterval());
676 }
677
678 /**
679 * Gets threshold to determine static/dynamic period changes expressed in
680 * meters per squared second (m/s^2) for acceleration, radians per second
681 * (rad/s) for angular speed or Teslas (T) for magnetic flux density.
682 *
683 * @return threshold to determine static/dynamic period changes.
684 */
685 public double getThreshold() {
686 return threshold;
687 }
688
689 /**
690 * Gets threshold to determine static/dynamic period changes.
691 *
692 * @return threshold to determine static/dynamic period changes.
693 */
694 public M getThresholdAsMeasurement() {
695 return createMeasurement(threshold, getDefaultUnit());
696 }
697
698 /**
699 * Gets threshold to determine static/dynamic period changes.
700 *
701 * @param result instance where result will be stored.
702 */
703 public void getThresholdAsMeasurement(final M result) {
704 result.setValue(threshold);
705 result.setUnit(getDefaultUnit());
706 }
707
708 /**
709 * Indicates whether this detector is busy processing last provided sample.
710 *
711 * @return true if this detector is busy, false otherwise.
712 */
713 public boolean isRunning() {
714 return running;
715 }
716
717 /**
718 * Gets number of samples that have been processed so far.
719 *
720 * @return number of samples that have been processed so far.
721 */
722 public int getProcessedSamples() {
723 return processedSamples;
724 }
725
726 /**
727 * Gets average x-coordinate of measurements accumulated during last static
728 * period expressed in meters per squared second (m/s^2) for acceleration,
729 * radians per second (rad/s) for angular speed or Teslas (T) for
730 * magnetic flux density.
731 * This value is updated when switching from a static period to a dynamic
732 * one or after completing initialization.
733 *
734 * @return accumulated average x-coordinate of measurement during last static
735 * period.
736 */
737 public double getAccumulatedAvgX() {
738 return accumulatedAvgX;
739 }
740
741 /**
742 * Gets average x-coordinate of measurements accumulated during last static
743 * period.
744 * This value is updated when switching from a static period to a dynamic
745 * one or after completing initialization.
746 *
747 * @return accumulated average x-coordinate of measurement during last static
748 * period.
749 */
750 public M getAccumulatedAvgXAsMeasurement() {
751 return createMeasurement(accumulatedAvgX, getDefaultUnit());
752 }
753
754 /**
755 * Gets average x-coordinate of measurements accumulated during last static
756 * period.
757 * This value is updated when switching from a static period to a dynamic
758 * one or after completing initialization.
759 *
760 * @param result instance where result will be stored.
761 */
762 public void getAccumulatedAvgXAsMeasurement(final M result) {
763 result.setValue(accumulatedAvgX);
764 result.setUnit(getDefaultUnit());
765 }
766
767 /**
768 * Gets average y-coordinate of measurements accumulated during last static
769 * period expressed in meters per squared second (m/s^2) for acceleration,
770 * radians per second (rad/s) for angular speed or Teslas (T) for
771 * magnetic flux density.
772 * This value is updated when switching from a static period to a dynamic
773 * one or after completing initialization.
774 *
775 * @return accumulated average y-coordinate of measurement during last static
776 * period.
777 */
778 public double getAccumulatedAvgY() {
779 return accumulatedAvgY;
780 }
781
782 /**
783 * Gets average y-coordinate of measurements accumulated during last static
784 * period.
785 * This value is updated when switching from a static period to a dynamic
786 * one or after completing initialization.
787 *
788 * @return accumulated average y-coordinate of measurement during last static
789 * period.
790 */
791 public M getAccumulatedAvgYAsMeasurement() {
792 return createMeasurement(accumulatedAvgY, getDefaultUnit());
793 }
794
795 /**
796 * Gets average y-coordinate of measurements accumulated during last static
797 * period.
798 * This value is updated when switching from a static period to a dynamic
799 * one or after completing initialization.
800 *
801 * @param result instance where result will be stored.
802 */
803 public void getAccumulatedAvgYAsMeasurement(final M result) {
804 result.setValue(accumulatedAvgY);
805 result.setUnit(getDefaultUnit());
806 }
807
808 /**
809 * Gets average z-coordinate of measurements accumulated during last static
810 * period expressed in meters per squared second (m/s^2) for acceleration,
811 * radians per second (rad/s) for angular speed or Teslas (T) for
812 * magnetic flux density.
813 * This value is updated when switching from a static period to a dynamic
814 * one or after completing initialization.
815 *
816 * @return accumulated average y-coordinate of measurement during last static
817 * period.
818 */
819 public double getAccumulatedAvgZ() {
820 return accumulatedAvgZ;
821 }
822
823 /**
824 * Gets average z-coordinate of measurements accumulated during last static
825 * period.
826 * This value is updated when switching from a static period to a dynamic
827 * one or after completing initialization.
828 *
829 * @return accumulated average z-coordinate of measurement during last static
830 * period.
831 */
832 public M getAccumulatedAvgZAsMeasurement() {
833 return createMeasurement(accumulatedAvgZ, getDefaultUnit());
834 }
835
836 /**
837 * Gets average z-coordinate of measurements accumulated during last static
838 * period.
839 * This value is updated when switching from a static period to a dynamic
840 * one or after completing initialization.
841 *
842 * @param result instance where result will be stored.
843 */
844 public void getAccumulatedAvgZAsMeasurement(final M result) {
845 result.setValue(accumulatedAvgZ);
846 result.setUnit(getDefaultUnit());
847 }
848
849 /**
850 * Gets average measurements triad accumulated during last static period.
851 * This value is updated when switching from a static period to a dynamic
852 * one or after completing initialization.
853 *
854 * @return accumulated average measurements triad during last static period.
855 */
856 public T getAccumulatedAvgTriad() {
857 return createTriad(accumulatedAvgX, accumulatedAvgY, accumulatedAvgZ, getDefaultUnit());
858 }
859
860 /**
861 * Gets average measurements triad accumulated during last static period.
862 * This value is updated when switching from a static period to a dynamic
863 * one or after completing initialization.
864 *
865 * @param result instance where result will be stored.
866 */
867 public void getAccumulatedAvgTriad(final T result) {
868 result.setValueCoordinatesAndUnit(accumulatedAvgX, accumulatedAvgY, accumulatedAvgZ, getDefaultUnit());
869 }
870
871 /**
872 * Gets standard deviation of x-coordinate of measurements accumulated during
873 * last static period expressed in meters per squared second (m/s^2) for
874 * acceleration, radians per second (rad/s) for angular speed or Teslas
875 * (T) for magnetic flux density.
876 * This value is updated when switching from a static period to a dynamic
877 * one or after completing initialization.
878 *
879 * @return standard deviation of x-coordinate of measurements accumulated
880 * during last static period.
881 */
882 public double getAccumulatedStdX() {
883 return accumulatedStdX;
884 }
885
886 /**
887 * Gets standard deviation of x-coordinate of measurements accumulated during
888 * last static period.
889 * This value is updated when switching from a static period to a dynamic
890 * one or after completing initialization.
891 *
892 * @return standard deviation of x-coordinate of measurements accumulated
893 * during last static period.
894 */
895 public M getAccumulatedStdXAsMeasurement() {
896 return createMeasurement(accumulatedStdX, getDefaultUnit());
897 }
898
899 /**
900 * Gets standard deviation of x-coordinate of measurements accumulated during
901 * last static period.
902 * This value is updated when switching from a static period to a dynamic
903 * one or after completing initialization.
904 *
905 * @param result instance where result will be stored.
906 */
907 public void getAccumulatedStdXAsMeasurement(final M result) {
908 result.setValue(accumulatedStdX);
909 result.setUnit(getDefaultUnit());
910 }
911
912 /**
913 * Gets standard deviation of y-coordinate of measurements accumulated during
914 * last static period expressed in meters per squared second (m/s^2) for
915 * acceleration, radians per second (rad/s) for angular speed or Teslas
916 * (T) for magnetic flux density.
917 * This value is updated when switching from a static period to a dynamic
918 * one or after completing initialization.
919 *
920 * @return standard deviation of y-coordinate of measurements accumulated
921 * during last static period.
922 */
923 public double getAccumulatedStdY() {
924 return accumulatedStdY;
925 }
926
927 /**
928 * Gets standard deviation of y-coordinate of measurements accumulated during
929 * last static period.
930 * This value is updated when switching from a static period to a dynamic
931 * one or after completing initialization.
932 *
933 * @return standard deviation of y-coordinate of measurements accumulated
934 * during last static period.
935 */
936 public M getAccumulatedStdYAsMeasurement() {
937 return createMeasurement(accumulatedStdY, getDefaultUnit());
938 }
939
940 /**
941 * Gets standard deviation of y-coordinate of measurements accumulated during
942 * last static period.
943 * This value is updated when switching from a static period to a dynamic
944 * one or after completing initialization.
945 *
946 * @param result instance where result will be stored.
947 */
948 public void getAccumulatedStdYAsMeasurement(final M result) {
949 result.setValue(accumulatedStdY);
950 result.setUnit(getDefaultUnit());
951 }
952
953 /**
954 * Gets standard deviation of z-coordinate of measurements accumulated during
955 * last static period expressed in meters per squared second (m/s^2) for
956 * acceleration, radians per second (rad/s) for angular speed or Teslas
957 * (T) for magnetic flux density.
958 * This value is updated when switching from a static period to a dynamic
959 * one or after completing initialization.
960 *
961 * @return standard deviation of z-coordinate of measurements accumulated
962 * during last static period.
963 */
964 public double getAccumulatedStdZ() {
965 return accumulatedStdZ;
966 }
967
968 /**
969 * Gets standard deviation of z-coordinate of measurements accumulated during
970 * last static period.
971 * This value is updated when switching from a static period to a dynamic
972 * one or after completing initialization.
973 *
974 * @return standard deviation of z-coordinate of measurements accumulated
975 * during last static period.
976 */
977 public M getAccumulatedStdZAsMeasurement() {
978 return createMeasurement(accumulatedStdZ, getDefaultUnit());
979 }
980
981 /**
982 * Gets standard deviation of z-coordinate of measurements accumulated during
983 * last static period.
984 * This value is updated when switching from a static period to a dynamic
985 * one or after completing initialization.
986 *
987 * @param result instance where result will be stored.
988 */
989 public void getAccumulatedStdZAsMeasurement(final M result) {
990 result.setValue(accumulatedStdZ);
991 result.setUnit(getDefaultUnit());
992 }
993
994 /**
995 * Gets standard deviation of measurements accumulated during last static
996 * period.
997 * This value is updated when switching from a static period to a dynamic
998 * one or after completing initialization.
999 *
1000 * @return standard deviation of measurements accumulated during last static
1001 * period.
1002 */
1003 public T getAccumulatedStdTriad() {
1004 return createTriad(accumulatedStdX, accumulatedStdY, accumulatedStdZ, getDefaultUnit());
1005 }
1006
1007 /**
1008 * Gets standard deviation of measurements accumulated during last static
1009 * period.
1010 * This value is updated when switching from a static period to a dynamic
1011 * one or after completing initialization.
1012 *
1013 * @param result instance where result will be stored.
1014 */
1015 public void getAccumulatedStdTriad(final T result) {
1016 result.setValueCoordinatesAndUnit(accumulatedStdX, accumulatedStdY, accumulatedStdZ, getDefaultUnit());
1017 }
1018
1019 /**
1020 * Gets windowed average x-coordinate of measurements for each processed triad
1021 * expressed in meters per squared second (m/s^2) for acceleration,
1022 * radians per second (rad/s) for angular speed or Teslas (T) for
1023 * magnetic flux density.
1024 * This value is updated for each processed sample containing an average
1025 * value for the samples within the window.
1026 *
1027 * @return windowed average x-coordinate of measurements for each processed
1028 * triad.
1029 */
1030 public double getInstantaneousAvgX() {
1031 return instantaneousAvgX;
1032 }
1033
1034 /**
1035 * Gets windowed average x-coordinate of measurements for each processed triad.
1036 * This value is updated for each processed sample containing an average
1037 * value for the samples within the window.
1038 *
1039 * @return windowed average x-coordinate of measurements for each processed
1040 * triad.
1041 */
1042 public M getInstantaneousAvgXAsMeasurement() {
1043 return createMeasurement(instantaneousAvgX, getDefaultUnit());
1044 }
1045
1046 /**
1047 * Gets windowed average x-coordinate of measurements for each processed triad.
1048 * This value is updated for each processed sample containing an average
1049 * value for the samples within the window.
1050 *
1051 * @param result instance where result will be stored.
1052 */
1053 public void getInstantaneousAvgXAsMeasurement(final M result) {
1054 result.setValue(instantaneousAvgX);
1055 result.setUnit(getDefaultUnit());
1056 }
1057
1058 /**
1059 * Gets windowed average y-coordinate of measurements for each processed triad
1060 * expressed in meters per squared second (m/s^2) for acceleration,
1061 * radians per second (rad/s) for angular speed or Teslas (T) for
1062 * magnetic flux density.
1063 * This value is updated for each processed sample containing an average
1064 * value for the samples within the window.
1065 *
1066 * @return windowed average y-coordinate of measurements for each processed
1067 * triad.
1068 */
1069 public double getInstantaneousAvgY() {
1070 return instantaneousAvgY;
1071 }
1072
1073 /**
1074 * Gets windowed average y-coordinate of measurements for each processed triad.
1075 * This value is updated for each processed sample containing an average
1076 * value for the samples within the window.
1077 *
1078 * @return windowed average y-coordinate of measurements for each processed
1079 * triad.
1080 */
1081 public M getInstantaneousAvgYAsMeasurement() {
1082 return createMeasurement(instantaneousAvgY, getDefaultUnit());
1083 }
1084
1085 /**
1086 * Gets windowed average y-coordinate of measurements for each processed triad.
1087 * This value is updated for each processed sample containing an average
1088 * value for the samples within the window.
1089 *
1090 * @param result instance where result will be stored.
1091 */
1092 public void getInstantaneousAvgYAsMeasurement(final M result) {
1093 result.setValue(instantaneousAvgY);
1094 result.setUnit(getDefaultUnit());
1095 }
1096
1097 /**
1098 * Gets windowed average z-coordinate of measurements for each processed triad
1099 * expressed in meters per squared second (m/s^2) for acceleration,
1100 * radians per second (rad/s) for angular speed or Teslas (T) for
1101 * magnetic flux density.
1102 * This value is updated for each processed sample containing an average
1103 * value for the samples within the window.
1104 *
1105 * @return windowed average z-coordinate of measurements for each processed
1106 * triad.
1107 */
1108 public double getInstantaneousAvgZ() {
1109 return instantaneousAvgZ;
1110 }
1111
1112 /**
1113 * Gets windowed average z-coordinate of measurements for each processed triad.
1114 * This value is updated for each processed sample containing an average
1115 * value for the samples within the window.
1116 *
1117 * @return windowed average z-coordinate of measurements for each processed
1118 * triad.
1119 */
1120 public M getInstantaneousAvgZAsMeasurement() {
1121 return createMeasurement(instantaneousAvgZ, getDefaultUnit());
1122 }
1123
1124 /**
1125 * Gets windowed average z-coordinate of measurements for each processed triad.
1126 * This value is updated for each processed sample containing an average
1127 * value for the samples within the window.
1128 *
1129 * @param result instance where result will be stored.
1130 */
1131 public void getInstantaneousAvgZAsMeasurement(final M result) {
1132 result.setValue(instantaneousAvgZ);
1133 result.setUnit(getDefaultUnit());
1134 }
1135
1136 /**
1137 * Gets windowed average of measurements for each processed triad.
1138 * This value is updated for each processed sample containing an average
1139 * value for the samples within the window.
1140 *
1141 * @return windowed average of measurements for each processed triad.
1142 */
1143 public T getInstantaneousAvgTriad() {
1144 return createTriad(instantaneousAvgX, instantaneousAvgY, instantaneousAvgZ, getDefaultUnit());
1145 }
1146
1147 /**
1148 * Gets windowed average of measurements for each processed triad.
1149 * This value is updated for each processed sample containing an average
1150 * value for the samples within the window.
1151 *
1152 * @param result instance where result will be stored.
1153 */
1154 public void getInstantaneousAvgTriad(final T result) {
1155 result.setValueCoordinatesAndUnit(instantaneousAvgX, instantaneousAvgY, instantaneousAvgZ, getDefaultUnit());
1156 }
1157
1158 /**
1159 * Gets windowed standard deviation of x-coordinate of measurements for each
1160 * processed triad expressed in meters per squared second (m/s^2) for
1161 * acceleration, radians per second (rad/s) for angular speed or Teslas
1162 * (T) for magnetic flux density.
1163 * This value is updated for each processed sample containing measured standard
1164 * deviation for the samples within the window.
1165 *
1166 * @return windowed standard deviation of x-coordinate of measurements for
1167 * each processed triad.
1168 */
1169 public double getInstantaneousStdX() {
1170 return instantaneousStdX;
1171 }
1172
1173 /**
1174 * Gets windowed standard deviation of x-coordinate of measurements for each
1175 * processed triad.
1176 * This value is updated for each processed sample containing measured standard
1177 * deviation for the samples within the window.
1178 *
1179 * @return windowed standard deviation of x-coordinate of measurements for
1180 * each processed triad.
1181 */
1182 public M getInstantaneousStdXAsMeasurement() {
1183 return createMeasurement(instantaneousStdX, getDefaultUnit());
1184 }
1185
1186 /**
1187 * Gets windowed standard deviation of x-coordinate of measurements for each
1188 * processed triad.
1189 * This value is updated for each processed sample containing measured standard
1190 * deviation for the samples within the window.
1191 *
1192 * @param result instance where result will be stored.
1193 */
1194 public void getInstantaneousStdXAsMeasurement(final M result) {
1195 result.setValue(instantaneousStdX);
1196 result.setUnit(getDefaultUnit());
1197 }
1198
1199 /**
1200 * Gets windowed standard deviation of y-coordinate of measurements for each
1201 * processed triad expressed in meters per squared second (m/s^2) for
1202 * acceleration, radians per second (rad/s) for angular speed or Teslas
1203 * (T) for magnetic flux density.
1204 * This value is updated for each processed sample containing measured standard
1205 * deviation for the samples within the window.
1206 *
1207 * @return windowed standard deviation of y-coordinate of measurements for
1208 * each processed triad.
1209 */
1210 public double getInstantaneousStdY() {
1211 return instantaneousStdY;
1212 }
1213
1214 /**
1215 * Gets windowed standard deviation of y-coordinate of measurements for each
1216 * processed triad.
1217 * This value is updated for each processed sample containing measured standard
1218 * deviation of the samples within the window.
1219 *
1220 * @return windowed standard deviation of y-coordinate of measurements for
1221 * each processed triad.
1222 */
1223 public M getInstantaneousStdYAsMeasurement() {
1224 return createMeasurement(instantaneousStdY, getDefaultUnit());
1225 }
1226
1227 /**
1228 * Gets windowed standard deviation of y-coordinate of measurements for each
1229 * processed triad.
1230 * This value is updated for each processed sample containing measured standard
1231 * deviation of the samples within the window.
1232 *
1233 * @param result instance where result will be stored.
1234 */
1235 public void getInstantaneousStdYAsMeasurement(final M result) {
1236 result.setValue(instantaneousStdY);
1237 result.setUnit(getDefaultUnit());
1238 }
1239
1240 /**
1241 * Gets windowed standard deviation of z-coordinate of measurements for each
1242 * processed triad expressed in meters per squared second (m/s^2) for
1243 * acceleration, radians per second (rad/s) for angular speed or Teslas (T)
1244 * for magnetic flux density.
1245 * This value is updated for each processed sample containing measured standard
1246 * deviation for the samples within the window.
1247 *
1248 * @return windowed standard deviation of z-coordinate of measurements for
1249 * each processed triad.
1250 */
1251 public double getInstantaneousStdZ() {
1252 return instantaneousStdZ;
1253 }
1254
1255 /**
1256 * Gets windowed standard deviation of z-coordinate of measurements for each
1257 * processed triad.
1258 * This value is updated for each processed sample containing measured standard
1259 * deviation for the samples within the window.
1260 *
1261 * @return windowed standard deviation of z-coordinate of measurements for
1262 * each processed triad.
1263 */
1264 public M getInstantaneousStdZAsMeasurement() {
1265 return createMeasurement(instantaneousStdZ, getDefaultUnit());
1266 }
1267
1268 /**
1269 * Gets windowed standard deviation of z-coordinate of measurements for each
1270 * processed triad.
1271 * This value is updated for each processed sample containing measured standard
1272 * deviation for the samples within the window.
1273 *
1274 * @param result instance where result will be stored.
1275 */
1276 public void getInstantaneousStdZAsMeasurement(final M result) {
1277 result.setValue(instantaneousStdZ);
1278 result.setUnit(getDefaultUnit());
1279 }
1280
1281 /**
1282 * Gets windowed standard deviation of measurements for each processed triad.
1283 * This value is updated for each processed sample containing measured standard
1284 * deviation for the samples within the window.
1285 *
1286 * @return windowed standard deviation of measurements for each processed
1287 * triad.
1288 */
1289 public T getInstantaneousStdTriad() {
1290 return createTriad(instantaneousStdX, instantaneousStdY, instantaneousStdZ, getDefaultUnit());
1291 }
1292
1293 /**
1294 * Gets windowed standard deviation of measurements for each processed triad.
1295 * This value is updated for each processed sample containing measured standard
1296 * deviation for the samples within the window.
1297 *
1298 * @param result instance where result will be stored.
1299 */
1300 public void getInstantaneousStdTriad(final T result) {
1301 result.setValueCoordinatesAndUnit(instantaneousStdX, instantaneousStdY, instantaneousStdZ, getDefaultUnit());
1302 }
1303
1304 /**
1305 * Processes a new measurement triad sample.
1306 *
1307 * @param triad a new measurement triad to be processed.
1308 * @return true if provided triad has been processed, false if provided triad has been skipped because detector
1309 * previously failed. If detector previously failed, it will need to be reset before processing additional
1310 * samples.
1311 * @throws LockedException if detector is busy processing a previous sample.
1312 */
1313 public boolean process(final T triad) throws LockedException {
1314 return process(convertMeasurement(triad.getValueX(), triad.getUnit()),
1315 convertMeasurement(triad.getValueY(), triad.getUnit()),
1316 convertMeasurement(triad.getValueZ(), triad.getUnit()));
1317 }
1318
1319 /**
1320 * Processes a new measurement triad sample.
1321 *
1322 * @param valueX x-coordinate of sensed measurement.
1323 * @param valueY y-coordinate of sensed measurement.
1324 * @param valueZ z-coordinate of sensed measurement.
1325 * @return true if provided triad has been processed, false if provided triad has been skipped because detector
1326 * previously failed. If detector previously failed, it will need to be reset before processing additional
1327 * samples.
1328 * @throws LockedException if detector is busy processing a previous sample.
1329 */
1330 public boolean process(final M valueX, final M valueY, final M valueZ) throws LockedException {
1331 return process(convertMeasurement(valueX), convertMeasurement(valueY), convertMeasurement(valueZ));
1332 }
1333
1334 /**
1335 * Processes a new measurement triad sample.
1336 * Provided measurement coordinates are expressed in meters per squared second (m/s^2) for acceleration,
1337 * radians per second (rad/s) for angular speed or Teslas (T) for magnetic flux density.
1338 *
1339 * @param valueX x-coordinate of sensed measurement.
1340 * @param valueY y-coordinate of sensed measurement.
1341 * @param valueZ z-coordinate of sensed measurement.
1342 * @return true if provided triad has been processed, false if provided triad has been skipped because detector
1343 * previously failed. If detector previously failed, it will need to be reset before processing additional
1344 * samples.
1345 * @throws LockedException if detector is busy processing a previous sample.
1346 */
1347 public boolean process(final double valueX, final double valueY, final double valueZ) throws LockedException {
1348 if (running) {
1349 throw new LockedException();
1350 }
1351
1352 if (status == Status.FAILED) {
1353 return false;
1354 }
1355
1356 running = true;
1357
1358 if (status == Status.IDLE) {
1359 // start initialization
1360 status = Status.INITIALIZING;
1361
1362 if (listener != null) {
1363 //noinspection unchecked
1364 listener.onInitializationStarted((D) this);
1365 }
1366 }
1367
1368 processedSamples++;
1369
1370 windowedNoiseEstimator.addTriadAndProcess(valueX, valueY, valueZ);
1371
1372 instantaneousAvgX = windowedNoiseEstimator.getAvgX();
1373 instantaneousAvgY = windowedNoiseEstimator.getAvgY();
1374 instantaneousAvgZ = windowedNoiseEstimator.getAvgZ();
1375
1376 instantaneousStdX = windowedNoiseEstimator.getStandardDeviationX();
1377 instantaneousStdY = windowedNoiseEstimator.getStandardDeviationY();
1378 instantaneousStdZ = windowedNoiseEstimator.getStandardDeviationZ();
1379
1380 final var windowedStdNorm = windowedNoiseEstimator.getStandardDeviationNorm();
1381
1382 final var filledWindow = windowedNoiseEstimator.isWindowFilled();
1383
1384 if (status == Status.INITIALIZING) {
1385 // process sample during initialization
1386 accumulatedNoiseEstimator.addTriad(valueX, valueY, valueZ);
1387 final var accumulatedStdNorm = accumulatedNoiseEstimator.getStandardDeviationNorm();
1388
1389 if (processedSamples < initialStaticSamples) {
1390 if (filledWindow && (windowedStdNorm / accumulatedStdNorm > instantaneousNoiseLevelFactor)) {
1391 // sudden motion detected
1392 status = Status.FAILED;
1393
1394 // notify error
1395 if (listener != null) {
1396 //noinspection unchecked
1397 listener.onError((D) this, accumulatedStdNorm, windowedStdNorm,
1398 ErrorReason.SUDDEN_EXCESSIVE_MOVEMENT_DETECTED);
1399 }
1400 }
1401
1402 } else if (filledWindow) {
1403 // initialization completed
1404 // set base noise level and threshold
1405 baseNoiseLevel = accumulatedStdNorm;
1406 threshold = baseNoiseLevel * thresholdFactor;
1407
1408 // keep average/std measurements triad in case we want to obtain
1409 // its value since initial period must be static
1410 accumulatedAvgX = accumulatedNoiseEstimator.getAvgX();
1411 accumulatedAvgY = accumulatedNoiseEstimator.getAvgY();
1412 accumulatedAvgZ = accumulatedNoiseEstimator.getAvgZ();
1413
1414 accumulatedStdX = accumulatedNoiseEstimator.getStandardDeviationX();
1415 accumulatedStdY = accumulatedNoiseEstimator.getStandardDeviationY();
1416 accumulatedStdZ = accumulatedNoiseEstimator.getStandardDeviationZ();
1417
1418 // reset accumulated estimator so that we can estimate
1419 // average specific force in static periods
1420 accumulatedNoiseEstimator.reset();
1421
1422 if (baseNoiseLevel > baseNoiseLevelAbsoluteThreshold) {
1423 // base noise level exceeds allowed value
1424 status = Status.FAILED;
1425
1426 // notify error
1427 if (listener != null) {
1428 //noinspection unchecked
1429 listener.onError((D) this, accumulatedStdNorm, windowedStdNorm,
1430 ErrorReason.OVERALL_EXCESSIVE_MOVEMENT_DETECTED);
1431 }
1432
1433 } else {
1434 // initialization has been successfully completed
1435 status = Status.INITIALIZATION_COMPLETED;
1436
1437 if (listener != null) {
1438 //noinspection unchecked
1439 listener.onInitializationCompleted((D) this, baseNoiseLevel);
1440 }
1441 }
1442
1443 }
1444
1445 running = false;
1446 return true;
1447 } else {
1448 // detect static or dynamic period
1449 final var previousStatus = status;
1450
1451 if (windowedStdNorm < threshold) {
1452 status = Status.STATIC_INTERVAL;
1453 } else {
1454 status = Status.DYNAMIC_INTERVAL;
1455 }
1456
1457 if (status == Status.STATIC_INTERVAL) {
1458 // while we are in static interval, keep adding samples to estimate
1459 // accumulated average measurement triad
1460 accumulatedNoiseEstimator.addTriad(valueX, valueY, valueZ);
1461 }
1462
1463 if (previousStatus != status) {
1464 // static/dynamic period change detected
1465 if (status == Status.STATIC_INTERVAL && listener != null) {
1466 //noinspection unchecked
1467 listener.onStaticIntervalDetected((D) this,
1468 instantaneousAvgX, instantaneousAvgY, instantaneousAvgZ,
1469 instantaneousStdX, instantaneousStdY, instantaneousStdZ);
1470 } else if (status == Status.DYNAMIC_INTERVAL) {
1471 // when switching from static to dynamic interval,
1472 // pick accumulated average and standard deviation measurement triads
1473 accumulatedAvgX = accumulatedNoiseEstimator.getAvgX();
1474 accumulatedAvgY = accumulatedNoiseEstimator.getAvgY();
1475 accumulatedAvgZ = accumulatedNoiseEstimator.getAvgZ();
1476
1477 accumulatedStdX = accumulatedNoiseEstimator.getStandardDeviationX();
1478 accumulatedStdY = accumulatedNoiseEstimator.getStandardDeviationY();
1479 accumulatedStdZ = accumulatedNoiseEstimator.getStandardDeviationZ();
1480
1481 // reset accumulated estimator when switching to dynamic period
1482 accumulatedNoiseEstimator.reset();
1483
1484 if (listener != null) {
1485 //noinspection unchecked
1486 listener.onDynamicIntervalDetected((D) this,
1487 instantaneousAvgX, instantaneousAvgY, instantaneousAvgZ,
1488 instantaneousStdX, instantaneousStdY, instantaneousStdZ,
1489 accumulatedAvgX, accumulatedAvgY, accumulatedAvgZ,
1490 accumulatedStdX, accumulatedStdY, accumulatedStdZ);
1491 }
1492 }
1493 }
1494 }
1495
1496 running = false;
1497 return true;
1498 }
1499
1500 /**
1501 * Resets this detector so that it is initialized again when new samples are added.
1502 *
1503 * @throws LockedException if detector is busy.
1504 */
1505 public void reset() throws LockedException {
1506 if (running) {
1507 throw new LockedException();
1508 }
1509
1510 running = true;
1511
1512 status = Status.IDLE;
1513 processedSamples = 0;
1514 baseNoiseLevel = 0.0;
1515 threshold = 0.0;
1516
1517 windowedNoiseEstimator.reset();
1518 accumulatedNoiseEstimator.reset();
1519
1520 if (listener != null) {
1521 //noinspection unchecked
1522 listener.onReset((D) this);
1523 }
1524
1525 running = false;
1526 }
1527
1528 /**
1529 * Converts provided measurement instance to its default unit, which is
1530 * meters per squared second (m/s^2) for acceleration, radians per second (rad/s) for
1531 * angular speed or Teslas (T) for magnetic flux density.
1532 *
1533 * @param measurement measurement to be converted.
1534 * @return converted value.
1535 */
1536 protected double convertMeasurement(M measurement) {
1537 return convertMeasurement(measurement.getValue().doubleValue(), measurement.getUnit());
1538 }
1539
1540 /**
1541 * Converts provided measurement value expressed in provided unit to the
1542 * default measurement value, which is meters per squared second (m/s^2) for acceleration,
1543 * radians per second (rad/s) for angular speed or Teslas (t) for magnetic flux density.
1544 *
1545 * @param value value to be converted.
1546 * @param unit unit of value to be converted.
1547 * @return converted value.
1548 */
1549 protected abstract double convertMeasurement(final double value, final U unit);
1550
1551 /**
1552 * Creates a measurement instance using provided value and unit.
1553 *
1554 * @param value value of measurement.
1555 * @param unit unit of value.
1556 * @return created measurement
1557 */
1558 protected abstract M createMeasurement(final double value, final U unit);
1559
1560 /**
1561 * Gets default unit for measurements this implementation works with.
1562 *
1563 * @return default measurement unit.
1564 */
1565 protected abstract U getDefaultUnit();
1566
1567 /**
1568 * Creates a triad.
1569 *
1570 * @param valueX x-coordinate value.
1571 * @param valueY y-coordinate value.
1572 * @param valueZ z-coordinate value.
1573 * @param unit unit of values.
1574 * @return created triad.
1575 */
1576 protected abstract T createTriad(final double valueX, final double valueY, final double valueZ, final U unit);
1577
1578 /**
1579 * Possible detector status values.
1580 */
1581 public enum Status {
1582 /**
1583 * Detector is in idle status when it hasn't processed any sample yet.
1584 */
1585 IDLE,
1586
1587 /**
1588 * Detector is processing samples in the initial static process to determine base noise level.
1589 */
1590 INITIALIZING,
1591
1592 /**
1593 * Detector has successfully completed processing samples on the initial
1594 * static period.
1595 */
1596 INITIALIZATION_COMPLETED,
1597
1598 /**
1599 * A static interval has been detected, where accelerometer is considered to be subject to no substantial
1600 * movement forces.
1601 */
1602 STATIC_INTERVAL,
1603
1604 /**
1605 * A dynamic interval has been detected, where accelerometer is considered to be subject to substantial
1606 * movement forces.
1607 */
1608 DYNAMIC_INTERVAL,
1609
1610 /**
1611 * Detector has failed. This happens if accelerometer is subject to sudden movement forces while detector
1612 * is initializing during the initial static period.
1613 * When detector has failed, no new samples will be allowed to be processed until detector is reset.
1614 */
1615 FAILED
1616 }
1617
1618 /**
1619 * Reason why this detector has failed during initialization.
1620 */
1621 public enum ErrorReason {
1622 /**
1623 * If a sudden movement is detected during initialization.
1624 */
1625 SUDDEN_EXCESSIVE_MOVEMENT_DETECTED,
1626
1627 /**
1628 * If overall noise level is excessive during initialization.
1629 */
1630 OVERALL_EXCESSIVE_MOVEMENT_DETECTED
1631 }
1632 }