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.noise;
17  
18  import com.irurueta.navigation.LockedException;
19  import com.irurueta.navigation.inertial.BodyKinematics;
20  import com.irurueta.navigation.inertial.calibration.AccelerationTriad;
21  import com.irurueta.navigation.inertial.calibration.AccelerometerNoiseRootPsdSource;
22  import com.irurueta.navigation.inertial.calibration.AngularSpeedTriad;
23  import com.irurueta.navigation.inertial.calibration.GyroscopeNoiseRootPsdSource;
24  import com.irurueta.navigation.inertial.calibration.TimeIntervalEstimator;
25  import com.irurueta.units.Acceleration;
26  import com.irurueta.units.AccelerationConverter;
27  import com.irurueta.units.AccelerationUnit;
28  import com.irurueta.units.AngularSpeed;
29  import com.irurueta.units.AngularSpeedConverter;
30  import com.irurueta.units.AngularSpeedUnit;
31  import com.irurueta.units.Time;
32  
33  /**
34   * Estimates accumulated acceleration and angular speed noise variances and PSD's
35   * (Power Spectral Densities) along with their average values.
36   * This estimator must be used when the body where the accelerometer and gyroscope
37   * are attached remains static on the same position with zero velocity and
38   * constant (or zero) angular speed while capturing data.
39   * To compute PSD's, this estimator assumes that measurement samples are obtained
40   * at a constant provided rate equal to {@link #getTimeInterval()} seconds.
41   * If not available, sampling rate average can be estimated using
42   * {@link TimeIntervalEstimator}.
43   * This estimator does NOT require the knowledge of current location and body
44   * orientation.
45   * Because body location and orientation is not known, estimated average values
46   * cannot be used to determine biases. Only norm of noise estimations
47   * (variance or standard deviation) can be safely used.
48   */
49  public class AccumulatedBodyKinematicsNoiseEstimator implements AccelerometerNoiseRootPsdSource,
50          GyroscopeNoiseRootPsdSource {
51  
52      /**
53       * Default time interval between accelerometer samples expressed in seconds
54       * (s).
55       */
56      public static final double DEFAULT_TIME_INTERVAL_SECONDS =
57              AccumulatedTriadNoiseEstimator.DEFAULT_TIME_INTERVAL_SECONDS;
58  
59      /**
60       * Listener to handle events raised by this estimator.
61       */
62      private AccumulatedBodyKinematicsNoiseEstimatorListener listener;
63  
64      /**
65       * Last provided body kinematics.
66       */
67      private BodyKinematics lastBodyKinematics;
68  
69      /**
70       * Accumulated acceleration estimator.
71       */
72      private final AccumulatedAccelerationTriadNoiseEstimator accelerationEstimator =
73              new AccumulatedAccelerationTriadNoiseEstimator();
74  
75      /**
76       * Accumulated angular speed estimator.
77       */
78      private final AccumulatedAngularSpeedTriadNoiseEstimator angularSpeedEstimator =
79              new AccumulatedAngularSpeedTriadNoiseEstimator();
80  
81      /**
82       * Indicates that estimator is running.
83       */
84      private boolean running;
85  
86      /**
87       * Constructor.
88       */
89      public AccumulatedBodyKinematicsNoiseEstimator() {
90      }
91  
92      /**
93       * Constructor.
94       *
95       * @param listener listener to handle events raised by this estimator.
96       */
97      public AccumulatedBodyKinematicsNoiseEstimator(final AccumulatedBodyKinematicsNoiseEstimatorListener listener) {
98          this.listener = listener;
99      }
100 
101     /**
102      * Gets time interval between body kinematics samples expressed in
103      * seconds (s).
104      *
105      * @return time interval between body kinematics samples.
106      */
107     public double getTimeInterval() {
108         return accelerationEstimator.getTimeInterval();
109     }
110 
111     /**
112      * Sets time interval between body kinematics samples expressed in
113      * seconds (s).
114      *
115      * @param timeInterval time interval between body kinematic samples.
116      * @throws IllegalArgumentException if provided value is negative.
117      * @throws LockedException          if estimator is currently running.
118      */
119     public void setTimeInterval(final double timeInterval) throws LockedException {
120         if (running) {
121             throw new LockedException();
122         }
123 
124         accelerationEstimator.setTimeInterval(timeInterval);
125         angularSpeedEstimator.setTimeInterval(timeInterval);
126     }
127 
128     /**
129      * Gets time interval between body kinematics samples.
130      *
131      * @return time interval between body kinematics samples.
132      */
133     public Time getTimeIntervalAsTime() {
134         return accelerationEstimator.getTimeIntervalAsTime();
135     }
136 
137     /**
138      * Gets time interval between body kinematics samples.
139      *
140      * @param result instance where body kinematics will be stored.
141      */
142     public void getTimeIntervalAsTime(final Time result) {
143         accelerationEstimator.getTimeIntervalAsTime(result);
144     }
145 
146     /**
147      * Sets time interval between body kinematics samples.
148      *
149      * @param timeInterval time interval between body kinematics samples.
150      * @throws LockedException if estimator is currently running.
151      */
152     public void setTimeInterval(final Time timeInterval) throws LockedException {
153         if (running) {
154             throw new LockedException();
155         }
156 
157         accelerationEstimator.setTimeInterval(timeInterval);
158         angularSpeedEstimator.setTimeInterval(timeInterval);
159     }
160 
161     /**
162      * Gets listener to handle events raised by this estimator.
163      *
164      * @return listener to handle events raised by this estimator.
165      */
166     public AccumulatedBodyKinematicsNoiseEstimatorListener getListener() {
167         return listener;
168     }
169 
170     /**
171      * Sets listener to handle events raised by this estimator.
172      *
173      * @param listener listener to handle events raised by this estimator.
174      * @throws LockedException if this estimator is running.
175      */
176     public void setListener(final AccumulatedBodyKinematicsNoiseEstimatorListener listener) throws LockedException {
177         if (running) {
178             throw new LockedException();
179         }
180 
181         this.listener = listener;
182     }
183 
184     /**
185      * Gets last provided body kinematics or null if not available.
186      *
187      * @return last provided body kinematics or null.
188      */
189     public BodyKinematics getLastBodyKinematics() {
190         return lastBodyKinematics;
191     }
192 
193     /**
194      * Gets last provided body kinematics.
195      *
196      * @param result instance where last provided body kinematics will be stored.
197      * @return true if result instance was updated, false otherwise.
198      */
199     public boolean getLastBodyKinematics(final BodyKinematics result) {
200         if (lastBodyKinematics != null) {
201             lastBodyKinematics.copyTo(result);
202             return true;
203         } else {
204             return false;
205         }
206     }
207 
208     /**
209      * Gets estimated average of x coordinate of accelerometer sensed specific force
210      * expressed in meters per squared second (m/s^2).
211      * This value will depend of body location and orientation, hence it should never
212      * be used as a calibration bias.
213      *
214      * @return average of x coordinate of sensed specific force.
215      */
216     public double getAvgSpecificForceX() {
217         return accelerationEstimator.getAvgX();
218     }
219 
220     /**
221      * Gets estimated average of x coordinate of accelerometer sensed specific force.
222      * This value will depend of body location and orientation, hence it should never
223      * be used as a calibration bias.
224      *
225      * @return average of x coordinate of sensed specific force.
226      */
227     public Acceleration getAvgSpecificForceXAsMeasurement() {
228         return accelerationEstimator.getAvgXAsMeasurement();
229     }
230 
231     /**
232      * Gets estimated average of x coordinate of accelerometer sensed specific force.
233      * This value will depend of body location and orientation, hence it should never
234      * be used as a calibration bias.
235      *
236      * @param result instance where average of x coordinate of sensed specific force
237      *               will be stored.
238      */
239     public void getAvgSpecificForceXAsMeasurement(final Acceleration result) {
240         accelerationEstimator.getAvgXAsMeasurement(result);
241     }
242 
243     /**
244      * Gets estimated average of y coordinate of accelerometer sensed specific force
245      * expressed in meters per squared second (m/s^2).
246      * This value will depend of body location and orientation, hence it should never
247      * be used as a calibration bias.
248      *
249      * @return average of y coordinate of sensed specific force.
250      */
251     public double getAvgSpecificForceY() {
252         return accelerationEstimator.getAvgY();
253     }
254 
255     /**
256      * Gets estimated average of y coordinate of accelerometer sensed specific force.
257      * This value will depend of body location and orientation, hence it should never
258      * be used as a calibration bias.
259      *
260      * @return average of y coordinate of sensed specific force.
261      */
262     public Acceleration getAvgSpecificForceYAsMeasurement() {
263         return accelerationEstimator.getAvgYAsMeasurement();
264     }
265 
266     /**
267      * Gets estimated average of y coordinate of accelerometer sensed specific force.
268      * This value will depend of body location and orientation, hence it should never
269      * be used as a calibration bias.
270      *
271      * @param result instance where average of y coordinate of sensed specific force
272      *               will be stored.
273      */
274     public void getAvgSpecificForceYAsMeasurement(final Acceleration result) {
275         accelerationEstimator.getAvgYAsMeasurement(result);
276     }
277 
278     /**
279      * Gets estimated average of z coordinate of accelerometer sensed specific force
280      * expressed in meters per squared second (m/s^2).
281      * This value will depend of body location and orientation, hence it should never
282      * be used as a calibration bias.
283      *
284      * @return average of z coordinate of sensed specific force.
285      */
286     public double getAvgSpecificForceZ() {
287         return accelerationEstimator.getAvgZ();
288     }
289 
290     /**
291      * Gets estimated average of z coordinate of accelerometer sensed specific force.
292      * This value will depend of body location and orientation, hence it should never
293      * be used as a calibration bias.
294      *
295      * @return average of z coordinate of sensed specific force.
296      */
297     public Acceleration getAvgSpecificForceZAsMeasurement() {
298         return accelerationEstimator.getAvgZAsMeasurement();
299     }
300 
301     /**
302      * Gets estimated average of z coordinate of accelerometer sensed specific force.
303      * This value will depend of body location and orientation, hence it should never
304      * be used as a calibration bias.
305      *
306      * @param result instance where average of z coordinate of sensed specific force
307      *               will be stored.
308      */
309     public void getAvgSpecificForceZAsMeasurement(final Acceleration result) {
310         accelerationEstimator.getAvgZAsMeasurement(result);
311     }
312 
313     /**
314      * Gets estimated average of accelerometer sensed specific force as a measurement
315      * triad.
316      *
317      * @return average accelerometer triad.
318      */
319     public AccelerationTriad getAvgSpecificForceAsTriad() {
320         return accelerationEstimator.getAvgTriad();
321     }
322 
323     /**
324      * Gets estimated average of accelerometer sensed specific force as a measurement
325      * triad.
326      *
327      * @param result instance where average accelerometer triad will be stored.
328      */
329     public void getAvgSpecificForceAsTriad(final AccelerationTriad result) {
330         accelerationEstimator.getAvgTriad(result);
331     }
332 
333     /**
334      * Gets norm of estimated average acceleration expressed in meters per squared
335      * second (m/s^2). This value is independent of body orientation.
336      *
337      * @return norm of estimated average acceleration.
338      */
339     public double getAvgSpecificForceNorm() {
340         return accelerationEstimator.getAvgNorm();
341     }
342 
343     /**
344      * Gets norm of estimated average acceleration within current window.
345      *
346      * @return norm of estimated average acceleration.
347      */
348     public Acceleration getAvgSpecificForceNormAsMeasurement() {
349         return accelerationEstimator.getAvgNormAsMeasurement();
350     }
351 
352     /**
353      * Gets norm of estimated average acceleration.
354      *
355      * @param result instance where norm of estimated average acceleration will be stored.
356      */
357     public void getAvgSpecificForceNormAsMeasurement(final Acceleration result) {
358         accelerationEstimator.getAvgNormAsMeasurement(result);
359     }
360 
361     /**
362      * Gets estimated average of x coordinate of gyroscope sensed angular rate
363      * expressed in radians per second (rad/s).
364      * This value will depend of body location and orientation, hence it should
365      * never be used as a calibration bias.
366      *
367      * @return average of x coordinate of sensed angular rate.
368      */
369     public double getAvgAngularRateX() {
370         return angularSpeedEstimator.getAvgX();
371     }
372 
373     /**
374      * Gets estimated average of x coordinate of gyroscope sensed angular rate.
375      * This value will depend of body location and orientation, hence it should never
376      * be used as a calibration bias.
377      *
378      * @return average of x coordinate of sensed angular rate.
379      */
380     public AngularSpeed getAvgAngularRateXAsMeasurement() {
381         return angularSpeedEstimator.getAvgXAsMeasurement();
382     }
383 
384     /**
385      * Gets estimated average of x coordinate of gyroscope sensed angular rate.
386      * This value will depend of body location and orientation, hence it should never
387      * be used as a calibration bias.
388      *
389      * @param result instance where average of x coordinate of sensed angular rate
390      *               will be stored.
391      */
392     public void getAvgAngularRateXAsMeasurement(final AngularSpeed result) {
393         angularSpeedEstimator.getAvgXAsMeasurement(result);
394     }
395 
396     /**
397      * Gets estimated average of y coordinate of gyroscope sensed angular rate
398      * expressed in radians per second (rad/s).
399      * This value will depend of body location and orientation, hence it should never
400      * be used as a calibration bias.
401      *
402      * @return average of y coordinate of sensed angular rate.
403      */
404     public double getAvgAngularRateY() {
405         return angularSpeedEstimator.getAvgY();
406     }
407 
408     /**
409      * Gets estimated average of y coordinate of gyroscope sensed angular rate.
410      * This value will depend of body location and orientation, hence it should never
411      * be used as a calibration bias.
412      *
413      * @return average of y coordinate of sensed angular rate.
414      */
415     public AngularSpeed getAvgAngularRateYAsMeasurement() {
416         return angularSpeedEstimator.getAvgYAsMeasurement();
417     }
418 
419     /**
420      * Gets estimated average of y coordinate of gyroscope sensed angular rate.
421      * This value will depend of body location and orientation, hence it should never
422      * be used as a calibration bias.
423      *
424      * @param result instance where average of y coordinate of sensed angular rate
425      *               will be stored.
426      */
427     public void getAvgAngularRateYAsMeasurement(final AngularSpeed result) {
428         angularSpeedEstimator.getAvgYAsMeasurement(result);
429     }
430 
431     /**
432      * Gets estimated average of z coordinate of gyroscope sensed angular rate
433      * expressed in radians per second (rad/s).
434      * This value will depend of body location and orientation, hence it should never
435      * be used as a calibration bias.
436      *
437      * @return average of z coordinate of sensed angular rate.
438      */
439     public double getAvgAngularRateZ() {
440         return angularSpeedEstimator.getAvgZ();
441     }
442 
443     /**
444      * Gets estimated average of z coordinate of gyroscope sensed angular rate.
445      * This value will depend of body location and orientation, hence it should never
446      * be used as a calibration bias.
447      *
448      * @return average of z coordinate of sensed angular rate.
449      */
450     public AngularSpeed getAvgAngularRateZAsMeasurement() {
451         return angularSpeedEstimator.getAvgZAsMeasurement();
452     }
453 
454     /**
455      * Gets estimated average of z coordinate of gyroscope sensed angular rate.
456      * This value will depend of body location and orientation, hence it should never
457      * be used as a calibration bias.
458      *
459      * @param result instance where average of z coordinate of sensed angular rate
460      *               will be stored.
461      */
462     public void getAvgAngularRateZAsMeasurement(final AngularSpeed result) {
463         angularSpeedEstimator.getAvgZAsMeasurement(result);
464     }
465 
466     /**
467      * Gets estimated average of gyroscope sensed angular speed as a measurement
468      * triad.
469      *
470      * @return average angular speed triad.
471      */
472     public AngularSpeedTriad getAvgAngularRateTriad() {
473         return angularSpeedEstimator.getAvgTriad();
474     }
475 
476     /**
477      * Gets estimated average of gyroscope sensed angular speed as a measurement
478      * triad.
479      *
480      * @param result instance where average angular speed triad will be stored.
481      */
482     public void getAvgAngularRateTriad(final AngularSpeedTriad result) {
483         angularSpeedEstimator.getAvgTriad(result);
484     }
485 
486     /**
487      * Gets norm of estimated average angular speed expressed in radians per
488      * second (rad/s). This value is independent of body orientation.
489      *
490      * @return norm of estimated average angular speed.
491      */
492     public double getAvgAngularRateNorm() {
493         return angularSpeedEstimator.getAvgNorm();
494     }
495 
496     /**
497      * Gets norm of estimated average angular speed.
498      * This value is independent of body orientation.
499      *
500      * @return norm of estimated average angular speed.
501      */
502     public AngularSpeed getAvgAngularRateNormAsMeasurement() {
503         return angularSpeedEstimator.getAvgNormAsMeasurement();
504     }
505 
506     /**
507      * Gets norm of estimated average angular speed.
508      * This value is independent of body orientation.
509      *
510      * @param result instance where norm of estimated average angular speed will be stored.
511      */
512     public void getAvgAngularRateNormAsMeasurement(final AngularSpeed result) {
513         angularSpeedEstimator.getAvgNormAsMeasurement(result);
514     }
515 
516     /**
517      * Gets estimated average of body kinematics.
518      *
519      * @return estimated average of body kinematics.
520      */
521     public BodyKinematics getAvgBodyKinematics() {
522         final var result = new BodyKinematics();
523         getAvgBodyKinematics(result);
524         return result;
525     }
526 
527     /**
528      * Gets estimated average of body kinematics.
529      *
530      * @param result instance where estimated average of body kinematics will be stored.
531      */
532     public void getAvgBodyKinematics(final BodyKinematics result) {
533         final var avgFx = accelerationEstimator.getAvgX();
534         final var avgFy = accelerationEstimator.getAvgY();
535         final var avgFz = accelerationEstimator.getAvgZ();
536 
537         final var avgWx = angularSpeedEstimator.getAvgX();
538         final var avgWy = angularSpeedEstimator.getAvgY();
539         final var avgWz = angularSpeedEstimator.getAvgZ();
540 
541         result.setSpecificForceCoordinates(avgFx, avgFy, avgFz);
542         result.setAngularRateCoordinates(avgWx, avgWy, avgWz);
543     }
544 
545     /**
546      * Gets estimated variance of x coordinate of accelerometer sensed specific force
547      * expressed in (m^2/s^4).
548      *
549      * @return estimated variance of x coordinate of sensed specific force.
550      */
551     public double getVarianceSpecificForceX() {
552         return accelerationEstimator.getVarianceX();
553     }
554 
555     /**
556      * Gets estimated variance of y coordinate of accelerometer sensed specific
557      * force expressed in (m^2/s^4).
558      *
559      * @return estimated variance of y coordinate of sensed specific force.
560      */
561     public double getVarianceSpecificForceY() {
562         return accelerationEstimator.getVarianceY();
563     }
564 
565     /**
566      * Gets estimated variance of z coordinate of accelerometer sensed specific
567      * force expressed in (m^2/s^4).
568      *
569      * @return estimated variance of z coordinate of sensed specific force.
570      */
571     public double getVarianceSpecificForceZ() {
572         return accelerationEstimator.getVarianceZ();
573     }
574 
575     /**
576      * Gets estimated variance of x coordinate of gyroscope sensed angular rate
577      * expressed in (rad^2/s^2).
578      *
579      * @return estimated variance of x coordinate of sensed angular rate.
580      */
581     public double getVarianceAngularRateX() {
582         return angularSpeedEstimator.getVarianceX();
583     }
584 
585     /**
586      * Gets estimated variance of y coordinate of gyroscope sensed angular rate
587      * expressed in (rad^2/s^2).
588      *
589      * @return estimated variance of y coordinate of sensed angular rate.
590      */
591     public double getVarianceAngularRateY() {
592         return angularSpeedEstimator.getVarianceY();
593     }
594 
595     /**
596      * Gets estimated variance of z coordinate of gyroscope sensed angular rate
597      * expressed in (rad^2/s^2).
598      *
599      * @return estimated variance of z coordinate of sensed angular rate.
600      */
601     public double getVarianceAngularRateZ() {
602         return angularSpeedEstimator.getVarianceZ();
603     }
604 
605     /**
606      * Gets estimated standard deviation of x coordinate of accelerometer
607      * sensed specific force expressed in meters per squared second (m/s^2).
608      *
609      * @return estimated standard deviation of x coordinate of sensed specific
610      * force.
611      */
612     public double getStandardDeviationSpecificForceX() {
613         return accelerationEstimator.getStandardDeviationX();
614     }
615 
616     /**
617      * Gets estimated standard deviation of x coordinate of accelerometer
618      * sensed specific force.
619      *
620      * @return estimated standard deviation of x coordinate of sensed specific
621      * force.
622      */
623     public Acceleration getStandardDeviationSpecificForceXAsMeasurement() {
624         return accelerationEstimator.getStandardDeviationXAsMeasurement();
625     }
626 
627     /**
628      * Gets estimated standard deviation of x coordinate of accelerometer
629      * sensed specific force.
630      *
631      * @param result instance where estimated standard deviation of x
632      *               coordinate of sensed specific force will be stored.
633      */
634     public void getStandardDeviationSpecificForceXAsMeasurement(final Acceleration result) {
635         accelerationEstimator.getStandardDeviationXAsMeasurement(result);
636     }
637 
638     /**
639      * Gets estimated standard deviation of y coordinate of accelerometer
640      * sensed specific force expressed in meters per squared second (m/s^2).
641      *
642      * @return estimated standard deviation of y coordinate of sensed specific
643      * force.
644      */
645     public double getStandardDeviationSpecificForceY() {
646         return accelerationEstimator.getStandardDeviationY();
647     }
648 
649     /**
650      * Gets estimated standard deviation of y coordinate of accelerometer
651      * sensed specific force.
652      *
653      * @return estimated standard deviation of y coordinate of sensed specific
654      * force.
655      */
656     public Acceleration getStandardDeviationSpecificForceYAsMeasurement() {
657         return accelerationEstimator.getStandardDeviationYAsMeasurement();
658     }
659 
660     /**
661      * Gets estimated standard deviation of y coordinate of accelerometer
662      * sensed specific force.
663      *
664      * @param result instance where estimated standard deviation of y
665      *               coordinate of sensed specific force will be stored.
666      */
667     public void getStandardDeviationSpecificForceYAsMeasurement(final Acceleration result) {
668         accelerationEstimator.getStandardDeviationYAsMeasurement(result);
669     }
670 
671     /**
672      * Gets estimated standard deviation of z coordinate of accelerometer
673      * sensed specific force expressed in meters per squared second (m/s^2).
674      *
675      * @return estimated standard deviation of z coordinate of sensed specific
676      * force.
677      */
678     public double getStandardDeviationSpecificForceZ() {
679         return accelerationEstimator.getStandardDeviationZ();
680     }
681 
682     /**
683      * Gets estimated standard deviation of z coordinate of accelerometer
684      * sensed specific force.
685      *
686      * @return estimated standard deviation of z coordinate of sensed specific
687      * force.
688      */
689     public Acceleration getStandardDeviationSpecificForceZAsMeasurement() {
690         return accelerationEstimator.getStandardDeviationZAsMeasurement();
691     }
692 
693     /**
694      * Gets estimated standard deviation of z coordinate of accelerometer
695      * sensed specific force.
696      *
697      * @param result instance where estimated standard deviation of z
698      *               coordinate of sensed specific force will be stored.
699      */
700     public void getStandardDeviationSpecificForceZAsMeasurement(final Acceleration result) {
701         accelerationEstimator.getStandardDeviationZAsMeasurement(result);
702     }
703 
704     /**
705      * Gets estimated standard deviation triad of accelerometer measurements.
706      *
707      * @return estimated standard deviation triad of accelerometer measurements.
708      */
709     public AccelerationTriad getStandardDeviationSpecificForceTriad() {
710         return accelerationEstimator.getStandardDeviationTriad();
711     }
712 
713     /**
714      * Gets estimated standard deviation triad of accelerometer measurements.
715      *
716      * @param result instance where estimated standard deviation triad of
717      *               accelerometer measurements will be stored.
718      */
719     public void getStandardDeviationSpecificForceTriad(final AccelerationTriad result) {
720         accelerationEstimator.getStandardDeviationTriad(result);
721     }
722 
723     /**
724      * Gets norm of estimated standard deviation of accelerometer measurements
725      * expressed in meters per squared second (m/s^2).
726      *
727      * @return norm of estimated standard deviation of accelerometer
728      * measurements.
729      */
730     public double getStandardDeviationSpecificForceNorm() {
731         return accelerationEstimator.getStandardDeviationNorm();
732     }
733 
734     /**
735      * Gets norm of estimated standard deviation of accelerometer measurements.
736      *
737      * @return norm of estimated standard deviation of measurements.
738      */
739     public Acceleration getStandardDeviationSpecificForceNormAsMeasurement() {
740         return accelerationEstimator.getStandardDeviationNormAsMeasurement();
741     }
742 
743     /**
744      * Gets norm of estimated standard deviation of accelerometer measurements.
745      *
746      * @param result instance where norm of estimated standard deviation will be
747      *               stored.
748      */
749     public void getStandardDeviationSpecificForceNormAsMeasurement(final Acceleration result) {
750         accelerationEstimator.getStandardDeviationNormAsMeasurement(result);
751     }
752 
753     /**
754      * Gets average of estimated standard deviation coordinates of accelerometer
755      * measurements expressed in meters per squared second (m/s^2).
756      *
757      * @return average of estimated standard deviation coordinates.
758      */
759     public double getAverageStandardDeviationSpecificForce() {
760         return accelerationEstimator.getAverageStandardDeviation();
761     }
762 
763     /**
764      * Gets average of estimated standard deviation coordinates of accelerometer
765      * measurements.
766      *
767      * @return average of estimated standard deviation coordinates.
768      */
769     public Acceleration getAverageStandardDeviationSpecificForceAsMeasurement() {
770         return accelerationEstimator.getAverageStandardDeviationAsMeasurement();
771     }
772 
773     /**
774      * Gets average of estimated standard deviation coordinates of accelerometer
775      * measurements.
776      *
777      * @param result instance where average of estimated standard deviation coordinates
778      *               will be stored.
779      */
780     public void getAverageStandardDeviationSpecificForceAsMeasurement(final Acceleration result) {
781         accelerationEstimator.getAverageStandardDeviationAsMeasurement(result);
782     }
783 
784     /**
785      * Gets estimated standard deviation of x coordinate of gyroscope
786      * expressed in radians per second (rad/s).
787      *
788      * @return estimated standard deviation of x coordinate of gyroscope.
789      */
790     public double getStandardDeviationAngularRateX() {
791         return angularSpeedEstimator.getStandardDeviationX();
792     }
793 
794     /**
795      * Gets estimated standard deviation of x coordinate of gyroscope.
796      *
797      * @return estimated standard deviation of x coordinate of gyroscope.
798      */
799     public AngularSpeed getStandardDeviationAngularRateXAsMeasurement() {
800         return angularSpeedEstimator.getStandardDeviationXAsMeasurement();
801     }
802 
803     /**
804      * Gets estimated standard deviation of x coordinate of gyroscope.
805      *
806      * @param result estimated standard deviation of x coordinate of gyroscope.
807      */
808     public void getStandardDeviationAngularRateXAsMeasurement(final AngularSpeed result) {
809         angularSpeedEstimator.getStandardDeviationXAsMeasurement(result);
810     }
811 
812     /**
813      * Gets estimated standard deviation of y coordinate of gyroscope
814      * expressed in radians per second (rad/s).
815      *
816      * @return estimated standard deviation of y coordinate of gyroscope.
817      */
818     public double getStandardDeviationAngularRateY() {
819         return angularSpeedEstimator.getStandardDeviationY();
820     }
821 
822     /**
823      * Gets estimated standard deviation of y coordinate of gyroscope.
824      *
825      * @return estimated standard deviation of y coordinate of gyroscope.
826      */
827     public AngularSpeed getStandardDeviationAngularRateYAsMeasurement() {
828         return angularSpeedEstimator.getStandardDeviationYAsMeasurement();
829     }
830 
831     /**
832      * Gets estimated standard deviation of y coordinate of gyroscope.
833      *
834      * @param result estimated standard deviation of y coordinate of gyroscope.
835      */
836     public void getStandardDeviationAngularRateYAsMeasurement(final AngularSpeed result) {
837         angularSpeedEstimator.getStandardDeviationYAsMeasurement(result);
838     }
839 
840     /**
841      * Gets estimated standard deviation of z coordinate of gyroscope
842      * expressed in radians per second (rad/s).
843      *
844      * @return estimated standard deviation of z coordinate of gyroscope.
845      */
846     public double getStandardDeviationAngularRateZ() {
847         return angularSpeedEstimator.getStandardDeviationZ();
848     }
849 
850     /**
851      * Gets estimated standard deviation of z coordinate of gyroscope.
852      *
853      * @return estimated standard deviation of z coordinate of gyroscope.
854      */
855     public AngularSpeed getStandardDeviationAngularRateZAsMeasurement() {
856         return angularSpeedEstimator.getStandardDeviationZAsMeasurement();
857     }
858 
859     /**
860      * Gets estimated standard deviation of z coordinate of gyroscope.
861      *
862      * @param result estimated standard deviation of z coordinate of gyroscope.
863      */
864     public void getStandardDeviationAngularRateZAsMeasurement(final AngularSpeed result) {
865         angularSpeedEstimator.getStandardDeviationZAsMeasurement(result);
866     }
867 
868     /**
869      * Gets estimated standard deviation triad of angular speed measurements.
870      *
871      * @return estimated standard deviation triad of angular speed measurements.
872      */
873     public AngularSpeedTriad getStandardDeviationAngularSpeedTriad() {
874         return angularSpeedEstimator.getStandardDeviationTriad();
875     }
876 
877     /**
878      * Gets estimated standard deviation triad of angular speed measurements.
879      *
880      * @param result instance where estimated standard deviation triad of
881      *               gyroscope measurements will be stored.
882      */
883     public void getStandardDeviationAngularSpeedTriad(final AngularSpeedTriad result) {
884         angularSpeedEstimator.getStandardDeviationTriad(result);
885     }
886 
887     /**
888      * Gets norm of estimated standard deviation of gyroscope measurements
889      * expressed in radians per second (rad/s).
890      *
891      * @return norm of estimated standard deviation of gyroscope
892      * measurements.
893      */
894     public double getStandardDeviationAngularSpeedNorm() {
895         return angularSpeedEstimator.getStandardDeviationNorm();
896     }
897 
898     /**
899      * Gets norm of estimated standard deviation of gyroscope measurements.
900      *
901      * @return norm of estimated standard deviation of measurements.
902      */
903     public AngularSpeed getStandardDeviationAngularSpeedNormAsMeasurement() {
904         return angularSpeedEstimator.getStandardDeviationNormAsMeasurement();
905     }
906 
907     /**
908      * Gets norm of estimated standard deviation of gyroscope measurements.
909      *
910      * @param result instance where norm of estimated standard deviation will be
911      *               stored.
912      */
913     public void getStandardDeviationAngularSpeedNormAsMeasurement(final AngularSpeed result) {
914         angularSpeedEstimator.getStandardDeviationNormAsMeasurement(result);
915     }
916 
917     /**
918      * Gets average of estimated standard deviation coordinates of gyroscope
919      * measurements expressed in radians per second (rad/s).
920      *
921      * @return average of estimated standard deviation coordinates.
922      */
923     public double getAverageStandardDeviationAngularSpeed() {
924         return angularSpeedEstimator.getAverageStandardDeviation();
925     }
926 
927     /**
928      * Gets average of estimated standard deviation coordinates of gyroscope
929      * measurements.
930      *
931      * @return average of estimated standard deviation coordinates.
932      */
933     public AngularSpeed getAverageStandardDeviationAngularSpeedAsMeasurement() {
934         return angularSpeedEstimator.getAverageStandardDeviationAsMeasurement();
935     }
936 
937     /**
938      * Gets average of estimated standard deviation coordinates of gyroscope
939      * measurements.
940      *
941      * @param result instance where average of estimated standard deviation coordinates
942      *               will be stored.
943      */
944     public void getAverageStandardDeviationAngularSpeedAsMeasurement(final AngularSpeed result) {
945         angularSpeedEstimator.getAverageStandardDeviationAsMeasurement(result);
946     }
947 
948     /**
949      * Gets estimated standard deviations of accelerometer and gyroscope components
950      * as a body kinematics instance.
951      *
952      * @return a body kinematics instance containing standard deviation values.
953      */
954     public BodyKinematics getStandardDeviationAsBodyKinematics() {
955         return new BodyKinematics(getStandardDeviationSpecificForceX(),
956                 getStandardDeviationSpecificForceY(),
957                 getStandardDeviationSpecificForceZ(),
958                 getStandardDeviationAngularRateX(),
959                 getStandardDeviationAngularRateY(),
960                 getStandardDeviationAngularRateZ());
961     }
962 
963     /**
964      * Gets estimated standard deviations of accelerometer and gyroscope components
965      * as a body kinematics instance.
966      *
967      * @param result instance where data will be stored.
968      */
969     public void getStandardDeviationAsBodyKinematics(final BodyKinematics result) {
970         result.setSpecificForceCoordinates(getStandardDeviationSpecificForceX(),
971                 getStandardDeviationSpecificForceY(),
972                 getStandardDeviationSpecificForceZ());
973         result.setAngularRateCoordinates(getStandardDeviationAngularRateX(),
974                 getStandardDeviationAngularRateY(),
975                 getStandardDeviationAngularRateZ());
976     }
977 
978     /**
979      * Gets accelerometer noise PSD (Power Spectral Density) on x axis expressed
980      * in (m^2 * s^-3).
981      *
982      * @return accelerometer noise PSD on x axis.
983      */
984     public double getSpecificForcePsdX() {
985         return accelerationEstimator.getPsdX();
986     }
987 
988     /**
989      * Gets accelerometer noise PSD (Power Spectral Density) on y axis expressed
990      * in (m^2 * s^-3).
991      *
992      * @return accelerometer noise PSD on y axis.
993      */
994     public double getSpecificForcePsdY() {
995         return accelerationEstimator.getPsdY();
996     }
997 
998     /**
999      * Gets accelerometer noise PSD (Power Spectral Density) on z axis expressed
1000      * in (m^2 * s^-3).
1001      *
1002      * @return accelerometer noise PSD on z axis.
1003      */
1004     public double getSpecificForcePsdZ() {
1005         return accelerationEstimator.getPsdZ();
1006     }
1007 
1008     /**
1009      * Gets gyroscope noise PSD (Power Spectral Density) on x axis expressed
1010      * in (rad^2/s).
1011      *
1012      * @return gyroscope noise PSD on x axis.
1013      */
1014     public double getAngularRatePsdX() {
1015         return angularSpeedEstimator.getPsdX();
1016     }
1017 
1018     /**
1019      * Gets gyroscope noise PSD (Power Spectral Density) on y axis expressed
1020      * in (rad^2/s).
1021      *
1022      * @return gyroscope noise PSD on y axis.
1023      */
1024     public double getAngularRatePsdY() {
1025         return angularSpeedEstimator.getPsdY();
1026     }
1027 
1028     /**
1029      * Gets gyroscope noise PSD (Power Spectral Density) on z axis expressed
1030      * in (rad^2/s).
1031      *
1032      * @return gyroscope noise PSD on z axis.
1033      */
1034     public double getAngularRatePsdZ() {
1035         return angularSpeedEstimator.getPsdZ();
1036     }
1037 
1038     /**
1039      * Gets accelerometer noise root PSD (Power Spectral Density) on x axis
1040      * expressed in (m * s^-1.5).
1041      *
1042      * @return accelerometer noise root PSD on x axis.
1043      */
1044     public double getSpecificForceRootPsdX() {
1045         return accelerationEstimator.getRootPsdX();
1046     }
1047 
1048     /**
1049      * Gets accelerometer noise root PSD (Power Spectral Density) on y axis
1050      * expressed in (m * s^-1.5).
1051      *
1052      * @return accelerometer noise root PSD on y axis.
1053      */
1054     public double getSpecificForceRootPsdY() {
1055         return accelerationEstimator.getRootPsdY();
1056     }
1057 
1058     /**
1059      * Gets accelerometer noise root PSD (Power Spectral Density) on z axis
1060      * expressed in (m * s^-1.5).
1061      *
1062      * @return accelerometer noise root PSD on z axis.
1063      */
1064     public double getSpecificForceRootPsdZ() {
1065         return accelerationEstimator.getRootPsdZ();
1066     }
1067 
1068     /**
1069      * Gets gyroscope noise root PSD (Power Spectral Density) on x axis
1070      * expressed in (rad * s^-0.5).
1071      *
1072      * @return gyroscope noise root PSD on x axis.
1073      */
1074     public double getAngularRateRootPsdX() {
1075         return angularSpeedEstimator.getRootPsdX();
1076     }
1077 
1078     /**
1079      * Gets gyroscope noise root PSD (Power Spectral Density) on y axis
1080      * expressed in (rad * s^-0.5).
1081      *
1082      * @return gyroscope noise root PSD on y axis.
1083      */
1084     public double getAngularRateRootPsdY() {
1085         return angularSpeedEstimator.getRootPsdY();
1086     }
1087 
1088     /**
1089      * Gets gyroscope noise root PSD (Power Spectral Density) on z axis
1090      * expressed in (rad * s^-0.5).
1091      *
1092      * @return gyroscope noise root PSD on z axis.
1093      */
1094     public double getAngularRateRootPsdZ() {
1095         return angularSpeedEstimator.getRootPsdZ();
1096     }
1097 
1098     /**
1099      * Gets average accelerometer noise PSD (Power Spectral Density) among
1100      * x,y,z components expressed as (m^2/s^-3).
1101      *
1102      * @return average accelerometer noise PSD.
1103      */
1104     public double getAvgSpecificForceNoisePsd() {
1105         return accelerationEstimator.getAvgNoisePsd();
1106     }
1107 
1108     /**
1109      * Gets norm of noise root PSD (Power Spectral Density) among x,y,z
1110      * components expressed as (m * s^-1.5).
1111      *
1112      * @return norm of noise root PSD.
1113      */
1114     public double getSpecificForceNoiseRootPsdNorm() {
1115         return accelerationEstimator.getNoiseRootPsdNorm();
1116     }
1117 
1118     /**
1119      * Gets average gyroscope noise PSD (Power Spectral Density) among
1120      * x,y,z components expressed in (rad^2/s).
1121      *
1122      * @return average gyroscope noise PSD.
1123      */
1124     public double getAvgAngularRateNoisePsd() {
1125         return angularSpeedEstimator.getAvgNoisePsd();
1126     }
1127 
1128     /**
1129      * Gets norm of noise root PSD (Power Spectral Density) among x,y,z
1130      * components expressed as (rad * s^-0.5).
1131      *
1132      * @return norm of noise root PSD.
1133      */
1134     public double getAngularRateNoiseRootPsdNorm() {
1135         return angularSpeedEstimator.getNoiseRootPsdNorm();
1136     }
1137 
1138     /**
1139      * Gets number of samples that have been processed so far.
1140      *
1141      * @return number of samples that have been processed so far.
1142      */
1143     public int getNumberOfProcessedSamples() {
1144         return accelerationEstimator.getNumberOfProcessedSamples();
1145     }
1146 
1147     /**
1148      * Indicates whether estimator is currently running or not.
1149      *
1150      * @return true if estimator is running, false otherwise.
1151      */
1152     public boolean isRunning() {
1153         return running;
1154     }
1155 
1156     /**
1157      * Adds body kinematics measurement samples.
1158      *
1159      * @param specificForceX x coordinate of specific force expressed in meters per squared second (m/s^2).
1160      * @param specificForceY y coordinate of specific force expressed in meters per squared second (m/s^2).
1161      * @param specificForceZ z coordinate of specific force expressed in meters per squared second (m/s^2).
1162      * @param angularRateX   x coordinate of angular rate expressed in radians per second (rad/s).
1163      * @param angularRateY   y coordinate of angular rate expressed in radians per second (rad/s).
1164      * @param angularRateZ   z coordinate of angular rate expressed in radians per second (rad/s).
1165      * @throws LockedException if estimator is currently running.
1166      */
1167     public void addBodyKinematics(
1168             final double specificForceX, final double specificForceY, final double specificForceZ,
1169             final double angularRateX, final double angularRateY, final double angularRateZ) throws LockedException {
1170 
1171         if (running) {
1172             throw new LockedException();
1173         }
1174 
1175         running = true;
1176 
1177         if (lastBodyKinematics == null && listener != null) {
1178             listener.onStart(this);
1179         }
1180 
1181         if (lastBodyKinematics == null) {
1182             lastBodyKinematics = new BodyKinematics();
1183         }
1184         lastBodyKinematics.setSpecificForceCoordinates(specificForceX, specificForceY, specificForceZ);
1185         lastBodyKinematics.setAngularRateCoordinates(angularRateX, angularRateY, angularRateZ);
1186 
1187         accelerationEstimator.addTriad(specificForceX, specificForceY, specificForceZ);
1188         angularSpeedEstimator.addTriad(angularRateX, angularRateY, angularRateZ);
1189 
1190         if (listener != null) {
1191             listener.onBodyKinematicsAdded(this);
1192         }
1193 
1194         running = false;
1195     }
1196 
1197     /**
1198      * Adds body kinematics measurement samples.
1199      *
1200      * @param specificForceX x coordinate of specific force.
1201      * @param specificForceY y coordinate of specific force.
1202      * @param specificForceZ z coordinate of specific force.
1203      * @param angularRateX   x coordinate of angular rate.
1204      * @param angularRateY   y coordinate of angular rate.
1205      * @param angularRateZ   z coordinate of angular rate.
1206      * @throws LockedException if estimator is currently running.
1207      */
1208     public void addBodyKinematics(
1209             final Acceleration specificForceX, final Acceleration specificForceY, final Acceleration specificForceZ,
1210             final AngularSpeed angularRateX, final AngularSpeed angularRateY, final AngularSpeed angularRateZ)
1211             throws LockedException {
1212         addBodyKinematics(convertAcceleration(specificForceX),
1213                 convertAcceleration(specificForceY),
1214                 convertAcceleration(specificForceZ),
1215                 convertAngularSpeed(angularRateX),
1216                 convertAngularSpeed(angularRateY),
1217                 convertAngularSpeed(angularRateZ));
1218     }
1219 
1220     /**
1221      * Adds body kinematics measurement samples.
1222      *
1223      * @param specificForce specific force triad.
1224      * @param angularSpeed  angular speed triad.
1225      * @throws LockedException if estimator is currently running.
1226      */
1227     public void addBodyKinematics(
1228             final AccelerationTriad specificForce, final AngularSpeedTriad angularSpeed) throws LockedException {
1229         addBodyKinematics(convertAcceleration(specificForce.getValueX(), specificForce.getUnit()),
1230                 convertAcceleration(specificForce.getValueY(), specificForce.getUnit()),
1231                 convertAcceleration(specificForce.getValueZ(), specificForce.getUnit()),
1232                 convertAngularSpeed(angularSpeed.getValueX(), angularSpeed.getUnit()),
1233                 convertAngularSpeed(angularSpeed.getValueY(), angularSpeed.getUnit()),
1234                 convertAngularSpeed(angularSpeed.getValueZ(), angularSpeed.getUnit()));
1235     }
1236 
1237     /**
1238      * Adds body kinematics measurement.
1239      *
1240      * @param bodyKinematics body kinematics.
1241      * @throws LockedException if estimator is currently running.
1242      */
1243     public void addBodyKinematics(final BodyKinematics bodyKinematics) throws LockedException {
1244         addBodyKinematics(bodyKinematics.getFx(), bodyKinematics.getFy(), bodyKinematics.getFz(),
1245                 bodyKinematics.getAngularRateX(), bodyKinematics.getAngularRateY(), bodyKinematics.getAngularRateZ());
1246     }
1247 
1248     /**
1249      * Resets current estimator.
1250      *
1251      * @return true if estimator was successfully reset, false if no reset was needed.
1252      * @throws LockedException if estimator is currently running.
1253      */
1254     public boolean reset() throws LockedException {
1255         if (running) {
1256             throw new LockedException();
1257         }
1258 
1259         running = true;
1260 
1261         lastBodyKinematics = null;
1262         final var result = accelerationEstimator.reset() && angularSpeedEstimator.reset();
1263 
1264         if (listener != null) {
1265             listener.onReset(this);
1266         }
1267 
1268         running = false;
1269 
1270         return result;
1271     }
1272 
1273     /**
1274      * Converts an acceleration instance to meters per squared seconds (m/s^2).
1275      *
1276      * @param value value to be converted.
1277      * @return converted value.
1278      */
1279     private double convertAcceleration(final Acceleration value) {
1280         return AccelerationConverter.convert(value.getValue().doubleValue(), value.getUnit(),
1281                 AccelerationUnit.METERS_PER_SQUARED_SECOND);
1282     }
1283 
1284     /**
1285      * Converts an acceleration value and unit to meters per squared seconds (m/s^2).
1286      *
1287      * @param value value to be converted.
1288      * @param unit  unit of value to be converted.
1289      * @return converted value.
1290      */
1291     private double convertAcceleration(final double value, final AccelerationUnit unit) {
1292         return AccelerationConverter.convert(value, unit, AccelerationUnit.METERS_PER_SQUARED_SECOND);
1293     }
1294 
1295     /**
1296      * Converts an angular speed instance to radians per second (rad/s).
1297      *
1298      * @param value value to be converted.
1299      * @return converted value.
1300      */
1301     private double convertAngularSpeed(final AngularSpeed value) {
1302         return AngularSpeedConverter.convert(value.getValue().doubleValue(), value.getUnit(),
1303                 AngularSpeedUnit.RADIANS_PER_SECOND);
1304     }
1305 
1306     /**
1307      * Converts an angular speed value and unit to radians per second (rad/s).
1308      *
1309      * @param value value to be converted.
1310      * @param unit  unit of value to be converted.
1311      * @return converted value.
1312      */
1313     private double convertAngularSpeed(final double value, final AngularSpeedUnit unit) {
1314         return AngularSpeedConverter.convert(value, unit, AngularSpeedUnit.RADIANS_PER_SECOND);
1315     }
1316 
1317     /**
1318      * Gets accelerometer base noise level root PSD (Power Spectral Density)
1319      * expressed in (m * s^-1.5).
1320      *
1321      * @return accelerometer base noise level root PSD.
1322      */
1323     @Override
1324     public double getAccelerometerBaseNoiseLevelRootPsd() {
1325         return getSpecificForceNoiseRootPsdNorm();
1326     }
1327 
1328     /**
1329      * Gets gyroscope base noise level root PSD (Power Spectral Density)
1330      * expressed in (rad * s^-0.5)
1331      *
1332      * @return gyroscope base noise level root PSD.
1333      */
1334     @Override
1335     public double getGyroscopeBaseNoiseLevelRootPsd() {
1336         return getAngularRateNoiseRootPsdNorm();
1337     }
1338 }