View Javadoc
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.generators;
17  
18  import com.irurueta.navigation.LockedException;
19  import com.irurueta.navigation.inertial.calibration.AccelerometerNoiseRootPsdSource;
20  import com.irurueta.navigation.inertial.calibration.AngularSpeedTriad;
21  import com.irurueta.navigation.inertial.calibration.BodyKinematicsSequence;
22  import com.irurueta.navigation.inertial.calibration.GyroscopeNoiseRootPsdSource;
23  import com.irurueta.navigation.inertial.calibration.StandardDeviationBodyKinematics;
24  import com.irurueta.navigation.inertial.calibration.StandardDeviationTimedBodyKinematics;
25  import com.irurueta.navigation.inertial.calibration.TimedBodyKinematics;
26  import com.irurueta.navigation.inertial.calibration.intervals.TriadStaticIntervalDetector;
27  import com.irurueta.units.Acceleration;
28  import com.irurueta.units.AngularSpeed;
29  import com.irurueta.units.Time;
30  import com.irurueta.units.TimeConverter;
31  import com.irurueta.units.TimeUnit;
32  
33  /**
34   * Generates measurements for the calibration of accelerometers and gyroscopes by alternating
35   * static and dynamic intervals where device is kept static or moved.
36   * Generated measurements must be used with accelerometer calibrators based
37   * on the knowledge of gravity norm (or Earth position) when the device orientation
38   * is unknown, and with easy gyroscope calibrators.
39   * Notice that accuracy of the gyroscope calibration is very sensitive to the
40   * accuracy of detected dynamic intervals respect the average specific forces
41   * during static intervals.
42   * In order to increase the accuracy, calibration should be repeated trying different
43   * threshold factors {@link #getThresholdFactor()}.
44   *
45   * @see AccelerometerMeasurementsGenerator
46   * @see GyroscopeMeasurementsGenerator
47   */
48  public class AccelerometerAndGyroscopeMeasurementsGenerator
49          implements AccelerometerNoiseRootPsdSource, GyroscopeNoiseRootPsdSource {
50  
51      /**
52       * Listener to handle generated events.
53       */
54      private AccelerometerAndGyroscopeMeasurementsGeneratorListener listener;
55  
56      /**
57       * Listener for internal accelerometer measurements generator.
58       */
59      private final AccelerometerMeasurementsGeneratorListener accelerometerListener =
60              new AccelerometerMeasurementsGeneratorListener() {
61                  @Override
62                  public void onInitializationStarted(final AccelerometerMeasurementsGenerator generator) {
63                      // no action required
64                  }
65  
66                  @Override
67                  public void onInitializationCompleted(
68                          final AccelerometerMeasurementsGenerator generator, final double baseNoiseLevel) {
69                      // no action required
70                  }
71  
72                  @Override
73                  public void onError(
74                          final AccelerometerMeasurementsGenerator generator,
75                          final TriadStaticIntervalDetector.ErrorReason reason) {
76                      if (listener != null) {
77                          listener.onError(AccelerometerAndGyroscopeMeasurementsGenerator.this, reason);
78                      }
79                  }
80  
81                  @Override
82                  public void onStaticIntervalDetected(final AccelerometerMeasurementsGenerator generator) {
83                      // no action required
84                  }
85  
86                  @Override
87                  public void onDynamicIntervalDetected(final AccelerometerMeasurementsGenerator generator) {
88                      // no action required
89                  }
90  
91                  @Override
92                  public void onStaticIntervalSkipped(final AccelerometerMeasurementsGenerator generator) {
93                      // no action required
94                  }
95  
96                  @Override
97                  public void onDynamicIntervalSkipped(final AccelerometerMeasurementsGenerator generator) {
98                      // no action required
99                  }
100 
101                 @Override
102                 public void onGeneratedMeasurement(
103                         final AccelerometerMeasurementsGenerator generator,
104                         final StandardDeviationBodyKinematics measurement) {
105                     if (listener != null) {
106                         listener.onGeneratedAccelerometerMeasurement(
107                                 AccelerometerAndGyroscopeMeasurementsGenerator.this, measurement);
108                     }
109                 }
110 
111                 @Override
112                 public void onReset(final AccelerometerMeasurementsGenerator generator) {
113                     // no action required
114                 }
115             };
116 
117     /**
118      * Listener for internal gyroscope measurements generator.
119      */
120     private final GyroscopeMeasurementsGeneratorListener gyroscopeListener =
121             new GyroscopeMeasurementsGeneratorListener() {
122                 @Override
123                 public void onInitializationStarted(final GyroscopeMeasurementsGenerator generator) {
124                     if (listener != null) {
125                         listener.onInitializationStarted(AccelerometerAndGyroscopeMeasurementsGenerator.this);
126                     }
127                 }
128 
129                 @Override
130                 public void onInitializationCompleted(
131                         final GyroscopeMeasurementsGenerator generator, final double baseNoiseLevel) {
132                     if (listener != null) {
133                         listener.onInitializationCompleted(
134                                 AccelerometerAndGyroscopeMeasurementsGenerator.this, baseNoiseLevel);
135                     }
136                 }
137 
138                 @Override
139                 public void onError(
140                         final GyroscopeMeasurementsGenerator generator,
141                         final TriadStaticIntervalDetector.ErrorReason reason) {
142                     // no action required
143                 }
144 
145                 @Override
146                 public void onStaticIntervalDetected(final GyroscopeMeasurementsGenerator generator) {
147                     if (listener != null) {
148                         listener.onStaticIntervalDetected(
149                                 AccelerometerAndGyroscopeMeasurementsGenerator.this);
150                     }
151                 }
152 
153                 @Override
154                 public void onDynamicIntervalDetected(final GyroscopeMeasurementsGenerator generator) {
155                     if (listener != null) {
156                         listener.onDynamicIntervalDetected(
157                                 AccelerometerAndGyroscopeMeasurementsGenerator.this);
158                     }
159                 }
160 
161                 @Override
162                 public void onStaticIntervalSkipped(final GyroscopeMeasurementsGenerator generator) {
163                     if (listener != null) {
164                         listener.onStaticIntervalSkipped(
165                                 AccelerometerAndGyroscopeMeasurementsGenerator.this);
166                     }
167                 }
168 
169                 @Override
170                 public void onDynamicIntervalSkipped(final GyroscopeMeasurementsGenerator generator) {
171                     if (listener != null) {
172                         listener.onDynamicIntervalSkipped(
173                                 AccelerometerAndGyroscopeMeasurementsGenerator.this);
174                     }
175                 }
176 
177                 @Override
178                 public void onGeneratedMeasurement(
179                         final GyroscopeMeasurementsGenerator generator,
180                         final BodyKinematicsSequence<StandardDeviationTimedBodyKinematics> measurement) {
181                     if (listener != null) {
182                         listener.onGeneratedGyroscopeMeasurement(
183                                 AccelerometerAndGyroscopeMeasurementsGenerator.this, measurement);
184                     }
185                 }
186 
187                 @Override
188                 public void onReset(final GyroscopeMeasurementsGenerator generator) {
189                     // no action required
190                 }
191             };
192 
193     /**
194      * Internal accelerometer measurements generator.
195      */
196     private final AccelerometerMeasurementsGenerator accelerometerMeasurementsGenerator =
197             new AccelerometerMeasurementsGenerator(accelerometerListener);
198 
199     /**
200      * Internal gyroscope measurements generator.
201      */
202     private final GyroscopeMeasurementsGenerator gyroscopeMeasurementsGenerator =
203             new GyroscopeMeasurementsGenerator(gyroscopeListener);
204 
205     /**
206      * Indicates whether generator is running or not.
207      */
208     private boolean running;
209 
210     /**
211      * Constructor.
212      */
213     public AccelerometerAndGyroscopeMeasurementsGenerator() {
214     }
215 
216     /**
217      * Constructor.
218      *
219      * @param listener listener to handle events raised by this generator.
220      */
221     public AccelerometerAndGyroscopeMeasurementsGenerator(
222             final AccelerometerAndGyroscopeMeasurementsGeneratorListener listener) {
223         this();
224         this.listener = listener;
225     }
226 
227     /**
228      * Gets time interval between input samples expressed in seconds (s).
229      *
230      * @return time interval between input samples.
231      */
232     public double getTimeInterval() {
233         return accelerometerMeasurementsGenerator.getTimeInterval();
234     }
235 
236     /**
237      * Sets time interval between input samples expressed in seconds (s).
238      *
239      * @param timeInterval time interval between input samples.
240      * @throws IllegalArgumentException if provided value is negative.
241      * @throws LockedException          if generator is currently running.
242      */
243     public void setTimeInterval(final double timeInterval) throws LockedException {
244         if (running) {
245             throw new LockedException();
246         }
247 
248         if (timeInterval < 0.0) {
249             throw new IllegalArgumentException();
250         }
251 
252         accelerometerMeasurementsGenerator.setTimeInterval(timeInterval);
253         gyroscopeMeasurementsGenerator.setTimeInterval(timeInterval);
254     }
255 
256     /**
257      * Gets time interval between input samples.
258      *
259      * @return time interval between input samples.
260      */
261     public Time getTimeIntervalAsTime() {
262         return new Time(getTimeInterval(), TimeUnit.SECOND);
263     }
264 
265     /**
266      * Gets time interval between input samples.
267      *
268      * @param result instance where time interval will be stored.
269      */
270     public void getTimeIntervalAsTime(final Time result) {
271         result.setValue(getTimeInterval());
272         result.setUnit(TimeUnit.SECOND);
273     }
274 
275     /**
276      * Sets time interval between input samples.
277      *
278      * @param timeInterval time interval between input samples.
279      * @throws IllegalArgumentException if provided value is negative.
280      * @throws LockedException          if estimator is currently running.
281      */
282     public void setTimeInterval(final Time timeInterval) throws LockedException {
283         setTimeInterval(TimeConverter.convert(timeInterval.getValue().doubleValue(), timeInterval.getUnit(),
284                 TimeUnit.SECOND));
285     }
286 
287     /**
288      * Gets minimum number of samples required in a static interval to be taken into account.
289      * Smaller static intervals will be discarded.
290      *
291      * @return minimum number of samples required in a static interval to be taken into account.
292      */
293     public int getMinStaticSamples() {
294         return accelerometerMeasurementsGenerator.getMinStaticSamples();
295     }
296 
297     /**
298      * Sets minimum number of samples required in a static interval to be taken into account.
299      * Smaller static intervals will be discarded.
300      *
301      * @param minStaticSamples minimum number of samples required in a static interval to be
302      *                         taken into account.
303      * @throws LockedException          if generator is busy.
304      * @throws IllegalArgumentException if provided value is less than 2.
305      */
306     public void setMinStaticSamples(final int minStaticSamples) throws LockedException {
307         if (running) {
308             throw new LockedException();
309         }
310 
311         accelerometerMeasurementsGenerator.setMinStaticSamples(minStaticSamples);
312         gyroscopeMeasurementsGenerator.setMinStaticSamples(minStaticSamples);
313     }
314 
315     /**
316      * Gets maximum number of samples allowed in dynamic intervals.
317      *
318      * @return maximum number of samples allowed in dynamic intervals.
319      */
320     public int getMaxDynamicSamples() {
321         return accelerometerMeasurementsGenerator.getMaxDynamicSamples();
322     }
323 
324     /**
325      * Sets maximum number of samples allowed in dynamic intervals.
326      *
327      * @param maxDynamicSamples maximum number of samples allowed in dynamic intervals.
328      * @throws LockedException          if generator is busy.
329      * @throws IllegalArgumentException if provided value is less than 2.
330      */
331     public void setMaxDynamicSamples(final int maxDynamicSamples) throws LockedException {
332         if (running) {
333             throw new LockedException();
334         }
335 
336         accelerometerMeasurementsGenerator.setMaxDynamicSamples(maxDynamicSamples);
337         gyroscopeMeasurementsGenerator.setMaxDynamicSamples(maxDynamicSamples);
338     }
339 
340     /**
341      * Gets listener to handle generated events.
342      *
343      * @return listener to handle generated events.
344      */
345     public AccelerometerAndGyroscopeMeasurementsGeneratorListener getListener() {
346         return listener;
347     }
348 
349     /**
350      * Sets listener to handle generated events.
351      *
352      * @param listener listener to handle generated events.
353      * @throws LockedException if generator is busy.
354      */
355     public void setListener(final AccelerometerAndGyroscopeMeasurementsGeneratorListener listener)
356             throws LockedException {
357         if (running) {
358             throw new LockedException();
359         }
360 
361         this.listener = listener;
362     }
363 
364     /**
365      * Gets length of number of samples to keep within the window being processed
366      * to determine instantaneous accelerometer noise level.
367      *
368      * @return length of number of samples to keep within the window.
369      */
370     public int getWindowSize() {
371         return accelerometerMeasurementsGenerator.getWindowSize();
372     }
373 
374     /**
375      * Sets length of number of samples to keep within the window being processed
376      * to determine instantaneous accelerometer noise level.
377      * Window size must always be larger than allowed minimum value, which is 2 and
378      * must have an odd value.
379      *
380      * @param windowSize length of number of samples to keep within the window.
381      * @throws LockedException          if detector is busy processing a previous sample.
382      * @throws IllegalArgumentException if provided value is not valid.
383      */
384     public void setWindowSize(final int windowSize) throws LockedException {
385         if (running) {
386             throw new LockedException();
387         }
388 
389         accelerometerMeasurementsGenerator.setWindowSize(windowSize);
390         gyroscopeMeasurementsGenerator.setWindowSize(windowSize);
391     }
392 
393     /**
394      * Gets number of samples to be processed initially while keeping the sensor static in order
395      * to find the base noise level when device is static.
396      *
397      * @return number of samples to be processed initially.
398      */
399     public int getInitialStaticSamples() {
400         return accelerometerMeasurementsGenerator.getInitialStaticSamples();
401     }
402 
403     /**
404      * Sets number of samples to be processed initially while keeping the sensor static in order
405      * to find the base noise level when device is static.
406      *
407      * @param initialStaticSamples number of samples to be processed initially.
408      * @throws LockedException          if detector is busy.
409      * @throws IllegalArgumentException if provided value is less than
410      *                                  {@link TriadStaticIntervalDetector#MINIMUM_INITIAL_STATIC_SAMPLES}
411      */
412     public void setInitialStaticSamples(final int initialStaticSamples) throws LockedException {
413         if (running) {
414             throw new LockedException();
415         }
416 
417         accelerometerMeasurementsGenerator.setInitialStaticSamples(initialStaticSamples);
418         gyroscopeMeasurementsGenerator.setInitialStaticSamples(initialStaticSamples);
419     }
420 
421     /**
422      * Gets factor to be applied to detected base noise level in order to
423      * determine threshold for static/dynamic period changes. This factor is
424      * unit-less.
425      *
426      * @return factor to be applied to detected base noise level.
427      */
428     public double getThresholdFactor() {
429         return accelerometerMeasurementsGenerator.getThresholdFactor();
430     }
431 
432     /**
433      * Sets factor to be applied to detected base noise level in order to
434      * determine threshold for static/dynamic period changes. This factor is
435      * unit-less.
436      *
437      * @param thresholdFactor factor to be applied to detected base noise level.
438      * @throws LockedException          if detector is busy.
439      * @throws IllegalArgumentException if provided value is zero or negative.
440      */
441     public void setThresholdFactor(final double thresholdFactor) throws LockedException {
442         if (running) {
443             throw new LockedException();
444         }
445 
446         accelerometerMeasurementsGenerator.setThresholdFactor(thresholdFactor);
447         gyroscopeMeasurementsGenerator.setThresholdFactor(thresholdFactor);
448     }
449 
450     /**
451      * Gets factor to determine that a sudden movement has occurred during
452      * initialization if instantaneous noise level exceeds accumulated noise
453      * level by this factor amount.
454      * This factor is unit-less.
455      *
456      * @return factor to determine that a sudden movement has occurred.
457      */
458     public double getInstantaneousNoiseLevelFactor() {
459         return accelerometerMeasurementsGenerator.getInstantaneousNoiseLevelFactor();
460     }
461 
462     /**
463      * Sets factor to determine that a sudden movement has occurred during
464      * initialization if instantaneous noise level exceeds accumulated noise
465      * level by this factor amount.
466      * This factor is unit-less.
467      *
468      * @param instantaneousNoiseLevelFactor factor to determine that a sudden
469      *                                      movement has occurred during
470      *                                      initialization.
471      * @throws LockedException          if detector is busy.
472      * @throws IllegalArgumentException if provided value is zero or negative.
473      */
474     public void setInstantaneousNoiseLevelFactor(final double instantaneousNoiseLevelFactor) throws LockedException {
475         if (running) {
476             throw new LockedException();
477         }
478 
479         accelerometerMeasurementsGenerator.setInstantaneousNoiseLevelFactor(instantaneousNoiseLevelFactor);
480         gyroscopeMeasurementsGenerator.setInstantaneousNoiseLevelFactor(instantaneousNoiseLevelFactor);
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      * This threshold is expressed in meters per squared second (m/s^2).
489      *
490      * @return overall absolute threshold to determine whether there has
491      * been excessive motion.
492      */
493     public double getBaseNoiseLevelAbsoluteThreshold() {
494         return accelerometerMeasurementsGenerator.getBaseNoiseLevelAbsoluteThreshold();
495     }
496 
497     /**
498      * Sets overall absolute threshold to determine whether there has been
499      * excessive motion during the whole initialization phase.
500      * Failure will be detected if estimated base noise level exceeds this
501      * threshold when initialization completes.
502      * This threshold is expressed in meters per squared second (m/s^2).
503      *
504      * @param baseNoiseLevelAbsoluteThreshold overall absolute threshold to
505      *                                        determine whether there has been
506      *                                        excessive motion.
507      * @throws LockedException          if detector is busy.
508      * @throws IllegalArgumentException if provided value is zero or negative.
509      */
510     public void setBaseNoiseLevelAbsoluteThreshold(final double baseNoiseLevelAbsoluteThreshold)
511             throws LockedException {
512         if (running) {
513             throw new LockedException();
514         }
515 
516         accelerometerMeasurementsGenerator.setBaseNoiseLevelAbsoluteThreshold(baseNoiseLevelAbsoluteThreshold);
517         gyroscopeMeasurementsGenerator.setBaseNoiseLevelAbsoluteThreshold(baseNoiseLevelAbsoluteThreshold);
518     }
519 
520     /**
521      * Gets overall absolute threshold to determine whether there has been
522      * excessive motion during the whole initialization phase.
523      * Failure will be detected if estimated base noise level exceeds this
524      * threshold when initialization completes.
525      *
526      * @return overall absolute threshold to determine whether there has been
527      * excessive motion.
528      */
529     public Acceleration getBaseNoiseLevelAbsoluteThresholdAsMeasurement() {
530         return accelerometerMeasurementsGenerator.getBaseNoiseLevelAbsoluteThresholdAsMeasurement();
531     }
532 
533     /**
534      * Gets overall absolute threshold to determine whether there has been
535      * excessive motion during the whole initialization phase.
536      * Failure will be detected if estimated base noise level exceeds this
537      * threshold when initialization completes.
538      *
539      * @param result instance where result will be stored.
540      */
541     public void getBaseNoiseLevelAbsoluteThresholdAsMeasurement(final Acceleration result) {
542         accelerometerMeasurementsGenerator.getBaseNoiseLevelAbsoluteThresholdAsMeasurement(result);
543     }
544 
545     /**
546      * Sets overall absolute threshold to determine whether there has been
547      * excessive motion during the whole initialization phase.
548      * Failure will be detected if estimated base noise level exceeds this
549      * threshold when initialization completes.
550      *
551      * @param baseNoiseLevelAbsoluteThreshold overall absolute threshold to
552      *                                        determine whether there has been
553      *                                        excessive motion.
554      * @throws LockedException          if detector is busy.
555      * @throws IllegalArgumentException if provided value is zero or negative.
556      */
557     public void setBaseNoiseLevelAbsoluteThreshold(
558             final Acceleration baseNoiseLevelAbsoluteThreshold) throws LockedException {
559         if (running) {
560             throw new LockedException();
561         }
562 
563         accelerometerMeasurementsGenerator.setBaseNoiseLevelAbsoluteThreshold(baseNoiseLevelAbsoluteThreshold);
564         gyroscopeMeasurementsGenerator.setBaseNoiseLevelAbsoluteThreshold(baseNoiseLevelAbsoluteThreshold);
565     }
566 
567     /**
568      * Gets internal status of this generator.
569      *
570      * @return internal status of this generator.
571      */
572     public TriadStaticIntervalDetector.Status getStatus() {
573         return accelerometerMeasurementsGenerator.getStatus();
574     }
575 
576     /**
577      * Gets accelerometer base noise level that has been detected during
578      * initialization expressed in meters per squared second (m/s^2).
579      * This is equal to the standard deviation of the accelerometer measurements
580      * during initialization phase.
581      *
582      * @return accelerometer base noise level.
583      */
584     public double getAccelerometerBaseNoiseLevel() {
585         return accelerometerMeasurementsGenerator.getAccelerometerBaseNoiseLevel();
586     }
587 
588     /**
589      * Gets accelerometer base noise level that has been detected during
590      * initialization.
591      * This is equal to the standard deviation of the accelerometer measurements
592      * during initialization phase.
593      *
594      * @return measurement base noise level.
595      */
596     public Acceleration getAccelerometerBaseNoiseLevelAsMeasurement() {
597         return accelerometerMeasurementsGenerator.getAccelerometerBaseNoiseLevelAsMeasurement();
598     }
599 
600     /**
601      * Gets accelerometer base noise level that has been detected during
602      * initialization.
603      *
604      * @param result instance where result will be stored.
605      */
606     public void getAccelerometerBaseNoiseLevelAsMeasurement(final Acceleration result) {
607         accelerometerMeasurementsGenerator.getAccelerometerBaseNoiseLevelAsMeasurement(result);
608     }
609 
610     /**
611      * Gets accelerometer base noise level PSD (Power Spectral Density)
612      * expressed in (m^2 * s^-3).
613      *
614      * @return accelerometer base noise level PSD.
615      */
616     public double getAccelerometerBaseNoiseLevelPsd() {
617         return accelerometerMeasurementsGenerator.getAccelerometerBaseNoiseLevelPsd();
618     }
619 
620     /**
621      * Gets accelerometer base noise level root PSD (Power Spectral Density)
622      * expressed in (m * s^-1.5).
623      *
624      * @return accelerometer base noise level root PSD.
625      */
626     @Override
627     public double getAccelerometerBaseNoiseLevelRootPsd() {
628         return accelerometerMeasurementsGenerator.getAccelerometerBaseNoiseLevelRootPsd();
629     }
630 
631     /**
632      * Gets threshold to determine static/dynamic period changes expressed in
633      * meters per squared second (m/s^2).
634      *
635      * @return threshold to determine static/dynamic period changes.
636      */
637     public double getThreshold() {
638         return accelerometerMeasurementsGenerator.getThreshold();
639     }
640 
641     /**
642      * Gets threshold to determine static/dynamic period changes.
643      *
644      * @return threshold to determine static/dynamic period changes.
645      */
646     public Acceleration getThresholdAsMeasurement() {
647         return accelerometerMeasurementsGenerator.getThresholdAsMeasurement();
648     }
649 
650     /**
651      * Gets threshold to determine static/dynamic period changes.
652      *
653      * @param result instance where result will be stored.
654      */
655     public void getThresholdAsMeasurement(final Acceleration result) {
656         accelerometerMeasurementsGenerator.getThresholdAsMeasurement(result);
657     }
658 
659     /**
660      * Gets number of samples that have been processed in a static period so far.
661      *
662      * @return number of samples that have been processed in a static period so far.
663      */
664     public int getProcessedStaticSamples() {
665         return accelerometerMeasurementsGenerator.getProcessedStaticSamples();
666     }
667 
668     /**
669      * Gets number of samples that have been processed in a dynamic period so far.
670      *
671      * @return number of samples that have been processed in a dynamic period so far.
672      */
673     public int getProcessedDynamicSamples() {
674         return accelerometerMeasurementsGenerator.getProcessedDynamicSamples();
675     }
676 
677     /**
678      * Indicates whether last static interval must be skipped.
679      *
680      * @return true if last static interval must be skipped.
681      */
682     public boolean isStaticIntervalSkipped() {
683         return accelerometerMeasurementsGenerator.isStaticIntervalSkipped();
684     }
685 
686     /**
687      * Indicates whether last dynamic interval must be skipped.
688      *
689      * @return true if last dynamic interval must be skipped.
690      */
691     public boolean isDynamicIntervalSkipped() {
692         return accelerometerMeasurementsGenerator.isDynamicIntervalSkipped();
693     }
694 
695     /**
696      * Indicates whether generator is running or not.
697      *
698      * @return true if generator is running, false otherwise.
699      */
700     public boolean isRunning() {
701         return running;
702     }
703 
704     /**
705      * Processes a sample of data.
706      *
707      * @param sample sample of data to be processed.
708      * @return true if provided samples has been processed, false if provided triad has been skipped because
709      * generator previously failed. If generator previously failed, it will need to be reset before
710      * processing additional samples.
711      * @throws LockedException if generator is busy processing a previous sample.
712      */
713     public boolean process(final TimedBodyKinematics sample) throws LockedException {
714         if (running) {
715             throw new LockedException();
716         }
717 
718         try {
719             running = true;
720             return accelerometerMeasurementsGenerator.process(sample.getKinematics())
721                     && gyroscopeMeasurementsGenerator.process(sample);
722         } finally {
723             running = false;
724         }
725     }
726 
727     /**
728      * Resets this generator.
729      *
730      * @throws LockedException if generator is busy.
731      */
732     public void reset() throws LockedException {
733         if (running) {
734             throw new LockedException();
735         }
736 
737         accelerometerMeasurementsGenerator.reset();
738         gyroscopeMeasurementsGenerator.reset();
739 
740         if (listener != null) {
741             listener.onReset(this);
742         }
743     }
744 
745     /**
746      * Gets estimated average angular rate during initialization phase.
747      *
748      * @return estimated average angular rate during initialization phase.
749      */
750     public AngularSpeedTriad getInitialAvgAngularSpeedTriad() {
751         return gyroscopeMeasurementsGenerator.getInitialAvgAngularSpeedTriad();
752     }
753 
754     /**
755      * Gets estimated average angular rate during initialization phase.
756      *
757      * @param result instance where result will be stored.
758      */
759     public void getInitialAvgAngularSpeedTriad(final AngularSpeedTriad result) {
760         gyroscopeMeasurementsGenerator.getInitialAvgAngularSpeedTriad(result);
761     }
762 
763     /**
764      * Gets estimated standard deviation of angular rate during initialization phase.
765      *
766      * @return estimated standard deviation of angular rate during initialization phase.
767      */
768     public AngularSpeedTriad getInitialAngularSpeedTriadStandardDeviation() {
769         return gyroscopeMeasurementsGenerator.getInitialAngularSpeedTriadStandardDeviation();
770     }
771 
772     /**
773      * Gets estimated standard deviation of angular rate during initialization phase.
774      *
775      * @param result instance where result will be stored.
776      */
777     public void getInitialAngularSpeedTriadStandardDeviation(final AngularSpeedTriad result) {
778         gyroscopeMeasurementsGenerator.getInitialAngularSpeedTriadStandardDeviation(result);
779     }
780 
781     /**
782      * Gets gyroscope base noise level that has been detected during
783      * initialization expressed in radians per second (rad/s).
784      * This is equal to the standard deviation of the gyroscope measurements
785      * during initialization phase.
786      *
787      * @return gyroscope base noise level.
788      */
789     public double getGyroscopeBaseNoiseLevel() {
790         return gyroscopeMeasurementsGenerator.getGyroscopeBaseNoiseLevel();
791     }
792 
793     /**
794      * Gets gyroscope base noise level that has been detected during
795      * initialization.
796      * This is equal to the standard deviation of the gyroscope measurements
797      * during initialization phase.
798      *
799      * @return gyroscope base noise level.
800      */
801     public AngularSpeed getGyroscopeBaseNoiseLevelAsMeasurement() {
802         return gyroscopeMeasurementsGenerator.getGyroscopeBaseNoiseLevelAsMeasurement();
803     }
804 
805     /**
806      * Gets gyroscope base noise level that has been detected during
807      * initialization.
808      * This is equal to the standard deviation of the gyroscope measurements
809      * during initialization phase.
810      *
811      * @param result instance where result will be stored.
812      */
813     public void getGyroscopeBaseNoiseLevelAsMeasurement(final AngularSpeed result) {
814         gyroscopeMeasurementsGenerator.getGyroscopeBaseNoiseLevelAsMeasurement(result);
815     }
816 
817     /**
818      * Gets gyroscope base noise level PSD (Power Spectral Density)
819      * expressed in (rad^2/s).
820      *
821      * @return gyroscope base noise level PSD.
822      */
823     public double getGyroscopeBaseNoiseLevelPsd() {
824         return gyroscopeMeasurementsGenerator.getGyroscopeBaseNoiseLevelPsd();
825     }
826 
827     /**
828      * Gets gyroscope base noise level root PSD (Power Spectral Density)
829      * expressed in (rad * s^-0.5)
830      *
831      * @return gyroscope base noise level root PSD.
832      */
833     @Override
834     public double getGyroscopeBaseNoiseLevelRootPsd() {
835         return gyroscopeMeasurementsGenerator.getGyroscopeBaseNoiseLevelRootPsd();
836     }
837 }