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