View Javadoc
1   /*
2    * Copyright (C) 2021 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;
17  
18  import com.irurueta.algebra.AlgebraException;
19  import com.irurueta.algebra.Matrix;
20  import com.irurueta.geometry.InvalidRotationMatrixException;
21  import com.irurueta.geometry.Quaternion;
22  import com.irurueta.geometry.Rotation3D;
23  import com.irurueta.navigation.LockedException;
24  import com.irurueta.navigation.NotReadyException;
25  import com.irurueta.navigation.frames.CoordinateTransformation;
26  import com.irurueta.navigation.frames.ECEFFrame;
27  import com.irurueta.navigation.frames.ECEFPosition;
28  import com.irurueta.navigation.frames.ECEFVelocity;
29  import com.irurueta.navigation.frames.InvalidSourceAndDestinationFrameTypeException;
30  import com.irurueta.navigation.frames.NEDFrame;
31  import com.irurueta.navigation.frames.NEDPosition;
32  import com.irurueta.navigation.frames.NEDVelocity;
33  import com.irurueta.navigation.frames.converters.ECEFtoNEDFrameConverter;
34  import com.irurueta.navigation.frames.converters.NEDtoECEFFrameConverter;
35  import com.irurueta.navigation.inertial.BodyKinematics;
36  import com.irurueta.navigation.inertial.navigators.ECEFInertialNavigator;
37  import com.irurueta.navigation.inertial.navigators.InertialNavigatorException;
38  import com.irurueta.units.Acceleration;
39  import com.irurueta.units.AccelerationUnit;
40  import com.irurueta.units.Angle;
41  import com.irurueta.units.AngleUnit;
42  import com.irurueta.units.AngularSpeed;
43  import com.irurueta.units.AngularSpeedUnit;
44  import com.irurueta.units.Distance;
45  import com.irurueta.units.DistanceUnit;
46  import com.irurueta.units.Speed;
47  import com.irurueta.units.SpeedUnit;
48  import com.irurueta.units.Time;
49  import com.irurueta.units.TimeConverter;
50  import com.irurueta.units.TimeUnit;
51  
52  /**
53   * Estimates accumulated drift in body orientation, position and velocity per
54   * unit of time.
55   * This estimator must be executed while the body where the IMU is placed remains
56   * static.
57   */
58  public class DriftEstimator {
59  
60      /**
61       * Default time interval between kinematics samples expressed in seconds (s).
62       */
63      public static final double DEFAULT_TIME_INTERVAL_SECONDS = 0.02;
64  
65      /**
66       * Indicates whether this estimator is running.
67       */
68      protected boolean running;
69  
70      /**
71       * Number of processed body kinematics samples.
72       */
73      protected int numberOfProcessedSamples;
74  
75      /**
76       * Time interval expressed in seconds (s) between body kinematics samples.
77       */
78      protected double timeInterval = DEFAULT_TIME_INTERVAL_SECONDS;
79  
80      /**
81       * Fixes body kinematics measurements using accelerometer and gyroscope
82       * calibration data to fix measurements.
83       */
84      protected final BodyKinematicsFixer fixer = new BodyKinematicsFixer();
85  
86      /**
87       * Instance containing the last fixed body kinematics to be reused.
88       */
89      protected final BodyKinematics fixedKinematics = new BodyKinematics();
90  
91      /**
92       * Indicates whether measured kinematics must be fixed or not.
93       * When enabled, provided calibration data is used; otherwise it is
94       * ignored.
95       * By default, this is enabled.
96       */
97      protected boolean fixKinematics = true;
98  
99      /**
100      * Listener to handle events raised by this estimator.
101      */
102     protected DriftEstimatorListener listener;
103 
104     /**
105      * Initial frame containing body position, velocity and orientation expressed
106      * in ECEF coordinates before starting drift estimation.
107      */
108     protected ECEFFrame referenceFrame;
109 
110     /**
111      * Contains the current frame after one navigation step.
112      * This is reused for efficiency.
113      */
114     protected final ECEFFrame frame = new ECEFFrame();
115 
116     /**
117      * Contains orientation of a reference frame.
118      * This is reused for efficiency.
119      */
120     protected final Quaternion refQ = new Quaternion();
121 
122     /**
123      * Contains orientation inverse of the reference frame.
124      * This is reused for efficiency.
125      */
126     protected final Quaternion invRefQ = new Quaternion();
127 
128     /**
129      * Contains current frame orientation drift.
130      * This is reused for efficiency.
131      */
132     protected final Quaternion q = new Quaternion();
133 
134     /**
135      * Contains current position drift.
136      */
137     protected final ECEFPosition currentPositionDrift = new ECEFPosition();
138 
139     /**
140      * Contains current velocity drift.
141      */
142     protected final ECEFVelocity currentVelocityDrift = new ECEFVelocity();
143 
144     /**
145      * Contains current orientation expressed as a 3D rotation matrix.
146      */
147     protected Matrix currentC;
148 
149     /**
150      * Current position drift expressed in meters (m).
151      */
152     protected double currentPositionDriftMeters;
153 
154     /**
155      * Current velocity drift expressed in meters per second (m/s).
156      */
157     protected double currentVelocityDriftMetersPerSecond;
158 
159     /**
160      * Current orientation drift expressed in radians (rad).
161      */
162     protected double currentOrientationDriftRadians;
163 
164     /**
165      * Constructor.
166      */
167     public DriftEstimator() {
168     }
169 
170     /**
171      * Constructor.
172      *
173      * @param listener listener to handle events.
174      */
175     public DriftEstimator(final DriftEstimatorListener listener) {
176         this.listener = listener;
177     }
178 
179     /**
180      * Constructor.
181      *
182      * @param referenceFrame initial frame containing body position, velocity and
183      *                       orientation expressed in ECEF coordinates.
184      */
185     public DriftEstimator(final ECEFFrame referenceFrame) {
186         this.referenceFrame = referenceFrame;
187     }
188 
189     /**
190      * Constructor.
191      *
192      * @param referenceFrame initial frame containing body position, velocity and
193      *                       orientation expressed in ECEF coordinates.
194      * @param listener       listener to handle events.
195      */
196     public DriftEstimator(final ECEFFrame referenceFrame,
197                           final DriftEstimatorListener listener) {
198         this.referenceFrame = referenceFrame;
199         this.listener = listener;
200     }
201 
202     /**
203      * Constructor.
204      *
205      * @param referenceFrame initial frame containing body position, velocity and
206      *                       orientation expressed in NED coordinates.
207      */
208     public DriftEstimator(final NEDFrame referenceFrame) {
209         try {
210             setReferenceNedFrame(referenceFrame);
211         } catch (final LockedException ignore) {
212             // never happens
213         }
214     }
215 
216     /**
217      * Constructor.
218      *
219      * @param referenceFrame initial frame containing body position, velocity and
220      *                       orientation expressed in NED coordinates.
221      * @param listener       listener to handle events.
222      */
223     public DriftEstimator(final NEDFrame referenceFrame,
224                           final DriftEstimatorListener listener) {
225         this(referenceFrame);
226         this.listener = listener;
227     }
228 
229     /**
230      * Constructor.
231      *
232      * @param ba acceleration bias to be set.
233      * @param ma acceleration cross-coupling errors matrix. Must be 3x3.
234      * @param bg angular speed bias to be set.
235      * @param mg angular speed cross-coupling errors matrix. Must be 3x3.
236      * @throws AlgebraException         if provided cross-coupling matrices cannot
237      *                                  be inverted.
238      * @throws IllegalArgumentException if any provided matrices are not 3x3.
239      */
240     public DriftEstimator(final AccelerationTriad ba,
241                           final Matrix ma,
242                           final AngularSpeedTriad bg,
243                           final Matrix mg) throws AlgebraException {
244         try {
245             setAccelerationBias(ba);
246             setAccelerationCrossCouplingErrors(ma);
247             setAngularSpeedBias(bg);
248             setAngularSpeedCrossCouplingErrors(mg);
249         } catch (final LockedException ignore) {
250             // never happens
251         }
252     }
253 
254     /**
255      * Constructor.
256      *
257      * @param ba       acceleration bias to be set.
258      * @param ma       acceleration cross-coupling errors matrix. Must be 3x3.
259      * @param bg       angular speed bias to be set.
260      * @param mg       angular speed cross-coupling errors matrix. Must be 3x3.
261      * @param listener listener to handle events.
262      * @throws AlgebraException         if provided cross-coupling matrices cannot
263      *                                  be inverted.
264      * @throws IllegalArgumentException if any provided matrices are not 3x3.
265      */
266     public DriftEstimator(
267             final AccelerationTriad ba,
268             final Matrix ma,
269             final AngularSpeedTriad bg,
270             final Matrix mg,
271             final DriftEstimatorListener listener) throws AlgebraException {
272         this(ba, ma, bg, mg);
273         this.listener = listener;
274     }
275 
276     /**
277      * Constructor.
278      *
279      * @param ba acceleration bias to be set.
280      * @param ma acceleration cross-coupling errors matrix. Must be 3x3.
281      * @param bg angular speed bias to be set.
282      * @param mg angular speed cross-coupling errors matrix. Must be 3x3.
283      * @param gg angular speed g-dependent cross-biases matrix. Must be 3x3.
284      * @throws AlgebraException         if provided cross-coupling matrices cannot
285      *                                  be inverted.
286      * @throws IllegalArgumentException if any provided matrices are not 3x3.
287      */
288     public DriftEstimator(
289             final AccelerationTriad ba,
290             final Matrix ma,
291             final AngularSpeedTriad bg,
292             final Matrix mg,
293             final Matrix gg) throws AlgebraException {
294         this(ba, ma, bg, mg);
295         try {
296             setAngularSpeedGDependantCrossBias(gg);
297         } catch (final LockedException ignore) {
298             // never happens
299         }
300     }
301 
302     /**
303      * Constructor.
304      *
305      * @param ba       acceleration bias to be set.
306      * @param ma       acceleration cross-coupling errors matrix. Must be 3x3.
307      * @param bg       angular speed bias to be set.
308      * @param mg       angular speed cross-coupling errors matrix. Must be 3x3.
309      * @param gg       angular speed g-dependent cross-biases matrix. Must be 3x3.
310      * @param listener listener to handle events.
311      * @throws AlgebraException         if provided cross-coupling matrices cannot
312      *                                  be inverted.
313      * @throws IllegalArgumentException if any provided matrices are not 3x3.
314      */
315     public DriftEstimator(
316             final AccelerationTriad ba,
317             final Matrix ma,
318             final AngularSpeedTriad bg,
319             final Matrix mg,
320             final Matrix gg,
321             final DriftEstimatorListener listener) throws AlgebraException {
322         this(ba, ma, bg, mg, gg);
323         this.listener = listener;
324     }
325 
326     /**
327      * Constructor.
328      *
329      * @param ba acceleration bias to be set expressed in meters per squared second
330      *           (m/s`2). Must be 3x1.
331      * @param ma acceleration cross-coupling errors matrix. Must be 3x3.
332      * @param bg angular speed bias to be set expressed in radians per second
333      *           (rad/s). Must be 3x1.
334      * @param mg angular speed cross-coupling errors matrix. Must be 3x3.
335      * @throws AlgebraException         if provided cross-coupling matrices cannot
336      *                                  be inverted.
337      * @throws IllegalArgumentException if any provided matrices are not 3x3.
338      */
339     public DriftEstimator(
340             final Matrix ba,
341             final Matrix ma,
342             final Matrix bg,
343             final Matrix mg) throws AlgebraException {
344         try {
345             setAccelerationBias(ba);
346             setAccelerationCrossCouplingErrors(ma);
347             setAngularSpeedBias(bg);
348             setAngularSpeedCrossCouplingErrors(mg);
349         } catch (final LockedException ignore) {
350             // never happens
351         }
352     }
353 
354     /**
355      * Constructor.
356      *
357      * @param ba       acceleration bias to be set expressed in meters per squared second
358      *                 (m/s`2). Must be 3x1.
359      * @param ma       acceleration cross-coupling errors matrix. Must be 3x3.
360      * @param bg       angular speed bias to be set expressed in radians per second
361      *                 (rad/s). Must be 3x1.
362      * @param mg       angular speed cross-coupling errors matrix. Must be 3x3.
363      * @param listener listener to handle events.
364      * @throws AlgebraException         if provided cross-coupling matrices cannot
365      *                                  be inverted.
366      * @throws IllegalArgumentException if any provided matrices are not 3x3.
367      */
368     public DriftEstimator(
369             final Matrix ba,
370             final Matrix ma,
371             final Matrix bg,
372             final Matrix mg,
373             final DriftEstimatorListener listener) throws AlgebraException {
374         this(ba, ma, bg, mg);
375         this.listener = listener;
376     }
377 
378     /**
379      * Constructor.
380      *
381      * @param ba acceleration bias to be set expressed in meters per squared second
382      *           (m/s`2). Must be 3x1.
383      * @param ma acceleration cross-coupling errors matrix. Must be 3x3.
384      * @param bg angular speed bias to be set expressed in radians per second
385      *           (rad/s). Must be 3x1.
386      * @param mg angular speed cross-coupling errors matrix. Must be 3x3.
387      * @param gg angular speed g-dependent cross-biases matrix. Must be 3x3.
388      * @throws AlgebraException         if provided cross-coupling matrices cannot
389      *                                  be inverted.
390      * @throws IllegalArgumentException if any provided matrices are not 3x3.
391      */
392     public DriftEstimator(
393             final Matrix ba,
394             final Matrix ma,
395             final Matrix bg,
396             final Matrix mg,
397             final Matrix gg) throws AlgebraException {
398         this(ba, ma, bg, mg);
399         try {
400             setAngularSpeedGDependantCrossBias(gg);
401         } catch (final LockedException ignore) {
402             // never happens
403         }
404     }
405 
406     /**
407      * Constructor.
408      *
409      * @param ba       acceleration bias to be set expressed in meters per squared second
410      *                 (m/s`2). Must be 3x1.
411      * @param ma       acceleration cross-coupling errors matrix. Must be 3x3.
412      * @param bg       angular speed bias to be set expressed in radians per second
413      *                 (rad/s). Must be 3x1.
414      * @param mg       angular speed cross-coupling errors matrix. Must be 3x3.
415      * @param gg       angular speed g-dependent cross-biases matrix. Must be 3x3.
416      * @param listener listener to handle events.
417      * @throws AlgebraException         if provided cross-coupling matrices cannot
418      *                                  be inverted.
419      * @throws IllegalArgumentException if any provided matrices are not 3x3.
420      */
421     public DriftEstimator(
422             final Matrix ba,
423             final Matrix ma,
424             final Matrix bg,
425             final Matrix mg,
426             final Matrix gg,
427             final DriftEstimatorListener listener) throws AlgebraException {
428         this(ba, ma, bg, mg, gg);
429         this.listener = listener;
430     }
431 
432     /**
433      * Constructor.
434      *
435      * @param referenceFrame initial frame containing body position, velocity and
436      *                       orientation expressed in ECEF coordinates.
437      * @param ba             acceleration bias to be set.
438      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
439      * @param bg             angular speed bias to be set.
440      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
441      * @throws AlgebraException         if provided cross-coupling matrices cannot
442      *                                  be inverted.
443      * @throws IllegalArgumentException if any provided matrices are not 3x3.
444      */
445     public DriftEstimator(final ECEFFrame referenceFrame,
446                           final AccelerationTriad ba,
447                           final Matrix ma,
448                           final AngularSpeedTriad bg,
449                           final Matrix mg) throws AlgebraException {
450         this(ba, ma, bg, mg);
451         this.referenceFrame = referenceFrame;
452     }
453 
454     /**
455      * Constructor.
456      *
457      * @param referenceFrame initial frame containing body position, velocity and
458      *                       orientation expressed in ECEF coordinates.
459      * @param ba             acceleration bias to be set.
460      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
461      * @param bg             angular speed bias to be set.
462      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
463      * @param listener       listener to handle events.
464      * @throws AlgebraException         if provided cross-coupling matrices cannot
465      *                                  be inverted.
466      * @throws IllegalArgumentException if any provided matrices are not 3x3.
467      */
468     public DriftEstimator(
469             final ECEFFrame referenceFrame,
470             final AccelerationTriad ba,
471             final Matrix ma,
472             final AngularSpeedTriad bg,
473             final Matrix mg,
474             final DriftEstimatorListener listener) throws AlgebraException {
475         this(ba, ma, bg, mg, listener);
476         this.referenceFrame = referenceFrame;
477     }
478 
479     /**
480      * Constructor.
481      *
482      * @param referenceFrame initial frame containing body position, velocity and
483      *                       orientation expressed in ECEF coordinates.
484      * @param ba             acceleration bias to be set.
485      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
486      * @param bg             angular speed bias to be set.
487      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
488      * @param gg             angular speed g-dependent cross-biases matrix. Must be 3x3.
489      * @throws AlgebraException         if provided cross-coupling matrices cannot
490      *                                  be inverted.
491      * @throws IllegalArgumentException if any provided matrices are not 3x3.
492      */
493     public DriftEstimator(
494             final ECEFFrame referenceFrame,
495             final AccelerationTriad ba,
496             final Matrix ma,
497             final AngularSpeedTriad bg,
498             final Matrix mg,
499             final Matrix gg) throws AlgebraException {
500         this(ba, ma, bg, mg, gg);
501         this.referenceFrame = referenceFrame;
502     }
503 
504     /**
505      * Constructor.
506      *
507      * @param referenceFrame initial frame containing body position, velocity and
508      *                       orientation expressed in ECEF coordinates.
509      * @param ba             acceleration bias to be set.
510      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
511      * @param bg             angular speed bias to be set.
512      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
513      * @param gg             angular speed g-dependent cross-biases matrix. Must be 3x3.
514      * @param listener       listener to handle events.
515      * @throws AlgebraException         if provided cross-coupling matrices cannot
516      *                                  be inverted.
517      * @throws IllegalArgumentException if any provided matrices are not 3x3.
518      */
519     public DriftEstimator(
520             final ECEFFrame referenceFrame,
521             final AccelerationTriad ba,
522             final Matrix ma,
523             final AngularSpeedTriad bg,
524             final Matrix mg,
525             final Matrix gg,
526             final DriftEstimatorListener listener) throws AlgebraException {
527         this(ba, ma, bg, mg, gg, listener);
528         this.referenceFrame = referenceFrame;
529     }
530 
531     /**
532      * Constructor.
533      *
534      * @param referenceFrame initial frame containing body position, velocity and
535      *                       orientation expressed in ECEF coordinates.
536      * @param ba             acceleration bias to be set expressed in meters per squared second
537      *                       (m/s`2). Must be 3x1.
538      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
539      * @param bg             angular speed bias to be set expressed in radians per second
540      *                       (rad/s). Must be 3x1.
541      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
542      * @throws AlgebraException         if provided cross-coupling matrices cannot
543      *                                  be inverted.
544      * @throws IllegalArgumentException if any provided matrices are not 3x3.
545      */
546     public DriftEstimator(
547             final ECEFFrame referenceFrame,
548             final Matrix ba,
549             final Matrix ma,
550             final Matrix bg,
551             final Matrix mg) throws AlgebraException {
552         this(ba, ma, bg, mg);
553         this.referenceFrame = referenceFrame;
554     }
555 
556     /**
557      * Constructor.
558      *
559      * @param referenceFrame initial frame containing body position, velocity and
560      *                       orientation expressed in ECEF coordinates.
561      * @param ba             acceleration bias to be set expressed in meters per squared second
562      *                       (m/s`2). Must be 3x1.
563      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
564      * @param bg             angular speed bias to be set expressed in radians per second
565      *                       (rad/s). Must be 3x1.
566      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
567      * @param listener       listener to handle events.
568      * @throws AlgebraException         if provided cross-coupling matrices cannot
569      *                                  be inverted.
570      * @throws IllegalArgumentException if any provided matrices are not 3x3.
571      */
572     public DriftEstimator(
573             final ECEFFrame referenceFrame,
574             final Matrix ba,
575             final Matrix ma,
576             final Matrix bg,
577             final Matrix mg,
578             final DriftEstimatorListener listener) throws AlgebraException {
579         this(ba, ma, bg, mg, listener);
580         this.referenceFrame = referenceFrame;
581     }
582 
583     /**
584      * Constructor.
585      *
586      * @param referenceFrame initial frame containing body position, velocity and
587      *                       orientation expressed in ECEF coordinates.
588      * @param ba             acceleration bias to be set expressed in meters per squared second
589      *                       (m/s`2). Must be 3x1.
590      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
591      * @param bg             angular speed bias to be set expressed in radians per second
592      *                       (rad/s). Must be 3x1.
593      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
594      * @param gg             angular speed g-dependent cross-biases matrix. Must be 3x3.
595      * @throws AlgebraException         if provided cross-coupling matrices cannot
596      *                                  be inverted.
597      * @throws IllegalArgumentException if any provided matrices are not 3x3.
598      */
599     public DriftEstimator(
600             final ECEFFrame referenceFrame,
601             final Matrix ba,
602             final Matrix ma,
603             final Matrix bg,
604             final Matrix mg,
605             final Matrix gg) throws AlgebraException {
606         this(ba, ma, bg, mg, gg);
607         this.referenceFrame = referenceFrame;
608     }
609 
610     /**
611      * Constructor.
612      *
613      * @param referenceFrame initial frame containing body position, velocity and
614      *                       orientation expressed in ECEF coordinates.
615      * @param ba             acceleration bias to be set expressed in meters per squared second
616      *                       (m/s`2). Must be 3x1.
617      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
618      * @param bg             angular speed bias to be set expressed in radians per second
619      *                       (rad/s). Must be 3x1.
620      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
621      * @param gg             angular speed g-dependent cross-biases matrix. Must be 3x3.
622      * @param listener       listener to handle events.
623      * @throws AlgebraException         if provided cross-coupling matrices cannot
624      *                                  be inverted.
625      * @throws IllegalArgumentException if any provided matrices are not 3x3.
626      */
627     public DriftEstimator(
628             final ECEFFrame referenceFrame,
629             final Matrix ba,
630             final Matrix ma,
631             final Matrix bg,
632             final Matrix mg,
633             final Matrix gg,
634             final DriftEstimatorListener listener) throws AlgebraException {
635         this(ba, ma, bg, mg, gg, listener);
636         this.referenceFrame = referenceFrame;
637     }
638 
639     /**
640      * Constructor.
641      *
642      * @param referenceFrame initial frame containing body position, velocity and
643      *                       orientation expressed in NED coordinates.
644      * @param ba             acceleration bias to be set.
645      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
646      * @param bg             angular speed bias to be set.
647      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
648      * @throws AlgebraException         if provided cross-coupling matrices cannot
649      *                                  be inverted.
650      * @throws IllegalArgumentException if any provided matrices are not 3x3.
651      */
652     public DriftEstimator(final NEDFrame referenceFrame,
653                           final AccelerationTriad ba,
654                           final Matrix ma,
655                           final AngularSpeedTriad bg,
656                           final Matrix mg) throws AlgebraException {
657         this(NEDtoECEFFrameConverter.convertNEDtoECEFAndReturnNew(referenceFrame), ba, ma, bg, mg);
658     }
659 
660     /**
661      * Constructor.
662      *
663      * @param referenceFrame initial frame containing body position, velocity and
664      *                       orientation expressed in NED coordinates.
665      * @param ba             acceleration bias to be set.
666      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
667      * @param bg             angular speed bias to be set.
668      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
669      * @param listener       listener to handle events.
670      * @throws AlgebraException         if provided cross-coupling matrices cannot
671      *                                  be inverted.
672      * @throws IllegalArgumentException if any provided matrices are not 3x3.
673      */
674     public DriftEstimator(
675             final NEDFrame referenceFrame,
676             final AccelerationTriad ba,
677             final Matrix ma,
678             final AngularSpeedTriad bg,
679             final Matrix mg,
680             final DriftEstimatorListener listener) throws AlgebraException {
681         this(NEDtoECEFFrameConverter.convertNEDtoECEFAndReturnNew(referenceFrame), ba, ma, bg, mg, listener);
682     }
683 
684     /**
685      * Constructor.
686      *
687      * @param referenceFrame initial frame containing body position, velocity and
688      *                       orientation expressed in NED coordinates.
689      * @param ba             acceleration bias to be set.
690      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
691      * @param bg             angular speed bias to be set.
692      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
693      * @param gg             angular speed g-dependent cross-biases matrix. Must be 3x3.
694      * @throws AlgebraException         if provided cross-coupling matrices cannot
695      *                                  be inverted.
696      * @throws IllegalArgumentException if any provided matrices are not 3x3.
697      */
698     public DriftEstimator(
699             final NEDFrame referenceFrame,
700             final AccelerationTriad ba,
701             final Matrix ma,
702             final AngularSpeedTriad bg,
703             final Matrix mg,
704             final Matrix gg) throws AlgebraException {
705         this(NEDtoECEFFrameConverter.convertNEDtoECEFAndReturnNew(referenceFrame), ba, ma, bg, mg, gg);
706     }
707 
708     /**
709      * Constructor.
710      *
711      * @param referenceFrame initial frame containing body position, velocity and
712      *                       orientation expressed in NED coordinates.
713      * @param ba             acceleration bias to be set.
714      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
715      * @param bg             angular speed bias to be set.
716      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
717      * @param gg             angular speed g-dependent cross-biases matrix. Must be 3x3.
718      * @param listener       listener to handle events.
719      * @throws AlgebraException         if provided cross-coupling matrices cannot
720      *                                  be inverted.
721      * @throws IllegalArgumentException if any provided matrices are not 3x3.
722      */
723     public DriftEstimator(
724             final NEDFrame referenceFrame,
725             final AccelerationTriad ba,
726             final Matrix ma,
727             final AngularSpeedTriad bg,
728             final Matrix mg,
729             final Matrix gg,
730             final DriftEstimatorListener listener) throws AlgebraException {
731         this(NEDtoECEFFrameConverter.convertNEDtoECEFAndReturnNew(referenceFrame), ba, ma, bg, mg, gg, listener);
732     }
733 
734     /**
735      * Constructor.
736      *
737      * @param referenceFrame initial frame containing body position, velocity and
738      *                       orientation expressed in NED coordinates.
739      * @param ba             acceleration bias to be set expressed in meters per squared second
740      *                       (m/s`2). Must be 3x1.
741      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
742      * @param bg             angular speed bias to be set expressed in radians per second
743      *                       (rad/s). Must be 3x1.
744      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
745      * @throws AlgebraException         if provided cross-coupling matrices cannot
746      *                                  be inverted.
747      * @throws IllegalArgumentException if any provided matrices are not 3x3.
748      */
749     public DriftEstimator(
750             final NEDFrame referenceFrame,
751             final Matrix ba,
752             final Matrix ma,
753             final Matrix bg,
754             final Matrix mg) throws AlgebraException {
755         this(NEDtoECEFFrameConverter.convertNEDtoECEFAndReturnNew(referenceFrame), ba, ma, bg, mg);
756     }
757 
758     /**
759      * Constructor.
760      *
761      * @param referenceFrame initial frame containing body position, velocity and
762      *                       orientation expressed in NED coordinates.
763      * @param ba             acceleration bias to be set expressed in meters per squared second
764      *                       (m/s`2). Must be 3x1.
765      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
766      * @param bg             angular speed bias to be set expressed in radians per second
767      *                       (rad/s). Must be 3x1.
768      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
769      * @param listener       listener to handle events.
770      * @throws AlgebraException         if provided cross-coupling matrices cannot
771      *                                  be inverted.
772      * @throws IllegalArgumentException if any provided matrices are not 3x3.
773      */
774     public DriftEstimator(
775             final NEDFrame referenceFrame,
776             final Matrix ba,
777             final Matrix ma,
778             final Matrix bg,
779             final Matrix mg,
780             final DriftEstimatorListener listener) throws AlgebraException {
781         this(NEDtoECEFFrameConverter.convertNEDtoECEFAndReturnNew(referenceFrame), ba, ma, bg, mg, listener);
782     }
783 
784     /**
785      * Constructor.
786      *
787      * @param referenceFrame initial frame containing body position, velocity and
788      *                       orientation expressed in NED coordinates.
789      * @param ba             acceleration bias to be set expressed in meters per squared second
790      *                       (m/s`2). Must be 3x1.
791      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
792      * @param bg             angular speed bias to be set expressed in radians per second
793      *                       (rad/s). Must be 3x1.
794      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
795      * @param gg             angular speed g-dependent cross-biases matrix. Must be 3x3.
796      * @throws AlgebraException         if provided cross-coupling matrices cannot
797      *                                  be inverted.
798      * @throws IllegalArgumentException if any provided matrices are not 3x3.
799      */
800     public DriftEstimator(
801             final NEDFrame referenceFrame,
802             final Matrix ba,
803             final Matrix ma,
804             final Matrix bg,
805             final Matrix mg,
806             final Matrix gg) throws AlgebraException {
807         this(NEDtoECEFFrameConverter.convertNEDtoECEFAndReturnNew(referenceFrame), ba, ma, bg, mg, gg);
808     }
809 
810     /**
811      * Constructor.
812      *
813      * @param referenceFrame initial frame containing body position, velocity and
814      *                       orientation expressed in ECEF coordinates.
815      * @param ba             acceleration bias to be set expressed in meters per squared second
816      *                       (m/s`2). Must be 3x1.
817      * @param ma             acceleration cross-coupling errors matrix. Must be 3x3.
818      * @param bg             angular speed bias to be set expressed in radians per second
819      *                       (rad/s). Must be 3x1.
820      * @param mg             angular speed cross-coupling errors matrix. Must be 3x3.
821      * @param gg             angular speed g-dependent cross-biases matrix. Must be 3x3.
822      * @param listener       listener to handle events.
823      * @throws AlgebraException         if provided cross-coupling matrices cannot
824      *                                  be inverted.
825      * @throws IllegalArgumentException if any provided matrices are not 3x3.
826      */
827     public DriftEstimator(
828             final NEDFrame referenceFrame,
829             final Matrix ba,
830             final Matrix ma,
831             final Matrix bg,
832             final Matrix mg,
833             final Matrix gg,
834             final DriftEstimatorListener listener) throws AlgebraException {
835         this(NEDtoECEFFrameConverter.convertNEDtoECEFAndReturnNew(referenceFrame), ba, ma, bg, mg, gg, listener);
836     }
837 
838     /**
839      * Gets listener to handle events raised by this estimator.
840      *
841      * @return listener to handle events raised by this estimator.
842      */
843     public DriftEstimatorListener getListener() {
844         return listener;
845     }
846 
847     /**
848      * Sets listener to handle events raised by this estimator.
849      *
850      * @param listener listener to handle events raised by this estimator.
851      * @throws LockedException if estimator is running.
852      */
853     public void setListener(final DriftEstimatorListener listener) throws LockedException {
854         if (running) {
855             throw new LockedException();
856         }
857 
858         this.listener = listener;
859     }
860 
861     /**
862      * Gets initial frame containing body position, velocity and orientation
863      * expressed in ECEF coordinates before starting drift estimation.
864      *
865      * @return initial body frame or null.
866      */
867     public ECEFFrame getReferenceFrame() {
868         return referenceFrame;
869     }
870 
871     /**
872      * Sets initial frame containing body position, velocity and orientation
873      * expressed in ECEF coordinates before starting drift estimation.
874      *
875      * @param referenceFrame initial frame or null.
876      * @throws LockedException if estimator is already running.
877      */
878     public void setReferenceFrame(final ECEFFrame referenceFrame) throws LockedException {
879         if (running) {
880             throw new LockedException();
881         }
882         this.referenceFrame = referenceFrame;
883     }
884 
885     /**
886      * Gets initial frame containing body position, velocity and orientation
887      * expressed in NED coordinates before starting drift estimation.
888      *
889      * @return initial body frame or null.
890      */
891     public NEDFrame getReferenceNedFrame() {
892         return referenceFrame != null
893                 ? ECEFtoNEDFrameConverter.convertECEFtoNEDAndReturnNew(referenceFrame)
894                 : null;
895     }
896 
897     /**
898      * Gets initial frame containing body position, velocity and orientation
899      * expressed in NED coordinates before starting drift estimation.
900      *
901      * @param result instance where the result will be stored.
902      * @return true if the initial frame was available and the result was updated, false
903      * otherwise.
904      * @throws NullPointerException if provided result instance is null.
905      */
906     public boolean getReferenceNedFrame(final NEDFrame result) {
907         if (referenceFrame != null) {
908             ECEFtoNEDFrameConverter.convertECEFtoNED(referenceFrame, result);
909             return true;
910         } else {
911             return false;
912         }
913     }
914 
915     /**
916      * Sets an initial frame containing body position, velocity and orientation
917      * expressed in NED coordinates before starting drift estimation.
918      *
919      * @param referenceNedFrame initial body frame or null.
920      * @throws LockedException if estimator is already running.
921      */
922     public void setReferenceNedFrame(final NEDFrame referenceNedFrame) throws LockedException {
923         if (running) {
924             throw new LockedException();
925         }
926 
927         if (referenceNedFrame != null) {
928             if (referenceFrame != null) {
929                 NEDtoECEFFrameConverter.convertNEDtoECEF(referenceNedFrame, referenceFrame);
930             } else {
931                 referenceFrame = NEDtoECEFFrameConverter.convertNEDtoECEFAndReturnNew(referenceNedFrame);
932             }
933         } else {
934             referenceFrame = null;
935         }
936     }
937 
938     /**
939      * Gets initial body position, expressed in ECEF coordinates, before starting
940      * drift estimation.
941      *
942      * @return initial body position or null.
943      */
944     public ECEFPosition getReferenceEcefPosition() {
945         return referenceFrame != null ? referenceFrame.getECEFPosition() : null;
946     }
947 
948     /**
949      * Gets initial body position, expressed in ECEF coordinates, before starting
950      * drift estimation.
951      *
952      * @param result instance where the result will be stored.
953      * @return true if the initial body position was available and the result was updated,
954      * false otherwise.
955      * @throws NullPointerException if provided result instance is null.
956      */
957     public boolean getReferenceEcefPosition(final ECEFPosition result) {
958         if (referenceFrame != null) {
959             referenceFrame.getECEFPosition(result);
960             return true;
961         } else {
962             return false;
963         }
964     }
965 
966     /**
967      * Sets initial body position, expressed in ECEF coordinates, before starting
968      * drift estimation.
969      *
970      * @param referenceEcefPosition initial body position.
971      * @throws LockedException      if estimator is already running.
972      * @throws NullPointerException if provided position is null.
973      */
974     public void setReferenceEcefPosition(final ECEFPosition referenceEcefPosition) throws LockedException {
975         if (running) {
976             throw new LockedException();
977         }
978 
979         if (referenceFrame != null) {
980             referenceFrame.setPosition(referenceEcefPosition);
981         } else {
982             referenceFrame = new ECEFFrame(referenceEcefPosition);
983         }
984     }
985 
986     /**
987      * Gets initial body velocity, expressed in ECEF coordinates, before starting
988      * drift estimation.
989      *
990      * @return initial body velocity or null.
991      */
992     public ECEFVelocity getReferenceEcefVelocity() {
993         return referenceFrame != null ? referenceFrame.getECEFVelocity() : null;
994     }
995 
996     /**
997      * Gets initial body velocity, expressed in ECEF coordinates, before starting
998      * drift estimation.
999      *
1000      * @param result instance where the result will be stored.
1001      * @return true if initial body velocity was available and the result was updated,
1002      * false otherwise.
1003      * @throws NullPointerException if provided result instance is null.
1004      */
1005     public boolean getReferenceEcefVelocity(final ECEFVelocity result) {
1006         if (referenceFrame != null) {
1007             referenceFrame.getECEFVelocity(result);
1008             return true;
1009         } else {
1010             return false;
1011         }
1012     }
1013 
1014     /**
1015      * Sets initial body velocity, expressed in ECEF coordinates, before starting
1016      * drift estimation.
1017      *
1018      * @param referenceEcefVelocity initial body velocity.
1019      * @throws LockedException      if estimator is already running.
1020      * @throws NullPointerException if velocity is null.
1021      */
1022     public void setReferenceEcefVelocity(final ECEFVelocity referenceEcefVelocity) throws LockedException {
1023         if (running) {
1024             throw new LockedException();
1025         }
1026 
1027         if (referenceFrame == null) {
1028             referenceFrame = new ECEFFrame();
1029         }
1030 
1031         referenceFrame.setVelocity(referenceEcefVelocity);
1032     }
1033 
1034     /**
1035      * Gets initial body coordinate transformation, containing body orientation
1036      * expressed in ECEF coordinates, before starting estimation.
1037      *
1038      * @return initial body orientation or null.
1039      */
1040     public CoordinateTransformation getReferenceEcefCoordinateTransformation() {
1041         return referenceFrame != null ?
1042                 referenceFrame.getCoordinateTransformation() : null;
1043     }
1044 
1045     /**
1046      * Gets initial body coordinate transformation, containing body orientation
1047      * expressed in ECEF coordinates, before starting estimation.
1048      *
1049      * @param result instance where the result will be stored.
1050      * @return true if initial body orientation was available and a result was
1051      * updated, false otherwise.
1052      * @throws NullPointerException if provided result instance is null.
1053      */
1054     public boolean getReferenceEcefCoordinateTransformation(final CoordinateTransformation result) {
1055         if (referenceFrame != null) {
1056             referenceFrame.getCoordinateTransformation(result);
1057             return true;
1058         } else {
1059             return false;
1060         }
1061     }
1062 
1063     /**
1064      * Sets initial body coordinate transformation, containing body orientation
1065      * expressed in ECEF coordinates, before starting estimation.
1066      *
1067      * @param referenceEcefCoordinateTransformation initial body orientation.
1068      * @throws LockedException                               if estimator is already running.
1069      * @throws InvalidSourceAndDestinationFrameTypeException if source and
1070      *                                                       destination types are invalid. Source type must be
1071      *                                                       {@link com.irurueta.navigation.frames.FrameType#BODY_FRAME} and the destination
1072      *                                                       type must be {@link com.irurueta.navigation.frames.FrameType#EARTH_CENTERED_EARTH_FIXED_FRAME}
1073      *                                                       indicating that body orientation is expressed respect ECEF coordinates.
1074      * @throws NullPointerException                          if orientation is null.
1075      */
1076     public void setReferenceEcefCoordinateTransformation(
1077             final CoordinateTransformation referenceEcefCoordinateTransformation) throws LockedException,
1078             InvalidSourceAndDestinationFrameTypeException {
1079         if (running) {
1080             throw new LockedException();
1081         }
1082 
1083         if (referenceFrame == null) {
1084             referenceFrame = new ECEFFrame(referenceEcefCoordinateTransformation);
1085         } else {
1086             referenceFrame.setCoordinateTransformation(referenceEcefCoordinateTransformation);
1087         }
1088     }
1089 
1090     /**
1091      * Gets initial body position, expressed in NED coordinates, before starting
1092      * drift estimation.
1093      *
1094      * @return initial body position or null.
1095      */
1096     public NEDPosition getReferenceNedPosition() {
1097         final var nedFrame = getReferenceNedFrame();
1098         return nedFrame != null ? nedFrame.getPosition() : null;
1099     }
1100 
1101     /**
1102      * Gets initial body position, expressed in NED coordinates, before starting
1103      * drift estimation.
1104      *
1105      * @param result instance where the result will be stored.
1106      * @return true if the initial body position was available and the result was updated,
1107      * false otherwise.
1108      * @throws NullPointerException if provided result instance is null.
1109      */
1110     public boolean getReferenceNedPosition(final NEDPosition result) {
1111         if (referenceFrame != null) {
1112             final var nedFrame = getReferenceNedFrame();
1113             nedFrame.getPosition(result);
1114             return true;
1115         } else {
1116             return false;
1117         }
1118     }
1119 
1120     /**
1121      * Sets initial body position, expressed in NED coordinates, before starting
1122      * drift estimation.
1123      *
1124      * @param referenceNedPosition initial body position.
1125      * @throws LockedException      if estimator is already running.
1126      * @throws NullPointerException if provided position is null.
1127      */
1128     public void setReferenceNedPosition(final NEDPosition referenceNedPosition) throws LockedException {
1129         if (running) {
1130             throw new LockedException();
1131         }
1132 
1133         if (referenceFrame != null) {
1134             final var nedFrame = getReferenceNedFrame();
1135             nedFrame.setPosition(referenceNedPosition);
1136             setReferenceNedFrame(nedFrame);
1137         } else {
1138             setReferenceNedFrame(new NEDFrame(referenceNedPosition));
1139         }
1140     }
1141 
1142     /**
1143      * Gets initial body velocity, expressed in NED coordinates, before starting
1144      * drift estimation.
1145      *
1146      * @return initial body velocity or null.
1147      */
1148     public NEDVelocity getReferenceNedVelocity() {
1149         final var nedFrame = getReferenceNedFrame();
1150         return nedFrame != null ? nedFrame.getVelocity() : null;
1151     }
1152 
1153     /**
1154      * Gets initial body velocity, expressed in NED coordinates, before starting
1155      * drift estimation.
1156      *
1157      * @param result instance where the result will be stored.
1158      * @return true if initial body velocity was available and the result was updated,
1159      * false otherwise.
1160      * @throws NullPointerException if provided result instance is null.
1161      */
1162     public boolean getReferenceNedVelocity(final NEDVelocity result) {
1163         if (referenceFrame != null) {
1164             final var nedFrame = getReferenceNedFrame();
1165             nedFrame.getVelocity(result);
1166             return true;
1167         } else {
1168             return false;
1169         }
1170     }
1171 
1172     /**
1173      * Sets initial body velocity, expressed in NED coordinates, before starting
1174      * drift estimation.
1175      *
1176      * @param referenceNedVelocity initial body velocity.
1177      * @throws LockedException      if estimator is already running.
1178      * @throws NullPointerException if velocity is null.
1179      */
1180     public void setReferenceNedVelocity(final NEDVelocity referenceNedVelocity) throws LockedException {
1181         if (running) {
1182             throw new LockedException();
1183         }
1184 
1185         final NEDFrame nedFrame;
1186         if (referenceFrame != null) {
1187             nedFrame = getReferenceNedFrame();
1188         } else {
1189             nedFrame = new NEDFrame();
1190         }
1191 
1192         nedFrame.setVelocity(referenceNedVelocity);
1193         setReferenceNedFrame(nedFrame);
1194     }
1195 
1196     /**
1197      * Gets initial body coordinate transformation, containing body orientation
1198      * expressed in NED coordinates, before starting estimation.
1199      *
1200      * @return initial body orientation or null.
1201      */
1202     public CoordinateTransformation getReferenceNedCoordinateTransformation() {
1203         final var nedFrame = getReferenceNedFrame();
1204         return nedFrame != null ? nedFrame.getCoordinateTransformation() : null;
1205     }
1206 
1207     /**
1208      * Gets initial body coordinate transformation, containing body orientation
1209      * expressed in NED coordinates, before starting estimation.
1210      *
1211      * @param result instance where the result will be stored.
1212      * @return true if initial body orientation was available and the result was
1213      * updated, false otherwise.
1214      * @throws NullPointerException if provided result instance is null.
1215      */
1216     public boolean getReferenceNedCoordinateTransformation(final CoordinateTransformation result) {
1217         if (referenceFrame != null) {
1218             final var nedFrame = getReferenceNedFrame();
1219             nedFrame.getCoordinateTransformation(result);
1220             return true;
1221         } else {
1222             return false;
1223         }
1224     }
1225 
1226     /**
1227      * Sets initial body coordinate transformation, containing body orientation
1228      * expressed in NED coordinates, before starting estimation.
1229      *
1230      * @param referenceNedCoordinateTransformation initial body orientation.
1231      * @throws LockedException                               if estimator is already running.
1232      * @throws InvalidSourceAndDestinationFrameTypeException if source and
1233      *                                                       destination types are invalid. Source type must be
1234      *                                                       {@link com.irurueta.navigation.frames.FrameType#BODY_FRAME} and the destination
1235      *                                                       type must be {@link com.irurueta.navigation.frames.FrameType#LOCAL_NAVIGATION_FRAME}
1236      *                                                       indicating that body orientation is expressed respect NED coordinates.
1237      * @throws NullPointerException                          if orientation is null.
1238      */
1239     public void setReferenceNedCoordinateTransformation(
1240             final CoordinateTransformation referenceNedCoordinateTransformation) throws LockedException,
1241             InvalidSourceAndDestinationFrameTypeException {
1242         if (running) {
1243             throw new LockedException();
1244         }
1245 
1246         final NEDFrame nedFrame;
1247         if (referenceFrame == null) {
1248             nedFrame = new NEDFrame(referenceNedCoordinateTransformation);
1249             setReferenceNedFrame(nedFrame);
1250         } else {
1251             nedFrame = getReferenceNedFrame();
1252             nedFrame.setCoordinateTransformation(referenceNedCoordinateTransformation);
1253         }
1254     }
1255 
1256     /**
1257      * Gets acceleration bias values expressed in meters per squared second (m/s^2).
1258      *
1259      * @return bias values expressed in meters per squared second.
1260      */
1261     public Matrix getAccelerationBias() {
1262         return fixer.getAccelerationBias();
1263     }
1264 
1265     /**
1266      * Gets acceleration bias values expressed in meters per squared second (m/s^2).
1267      *
1268      * @param result instance where the result will be stored.
1269      */
1270     public void getAccelerationBias(final Matrix result) {
1271         fixer.getAccelerationBias(result);
1272     }
1273 
1274     /**
1275      * Sets acceleration bias values expressed in meters per squared second (m/s^2).
1276      *
1277      * @param bias bias values expressed in meters per squared second.
1278      *             Must be 3x1.
1279      * @throws LockedException          if estimator is running.
1280      * @throws IllegalArgumentException if any provided matrix is not 3x1.
1281      */
1282     public void setAccelerationBias(final Matrix bias) throws LockedException {
1283         if (running) {
1284             throw new LockedException();
1285         }
1286 
1287         fixer.setAccelerationBias(bias);
1288     }
1289 
1290     /**
1291      * Gets acceleration bias values expressed in meters per squared second (m/s^2).
1292      *
1293      * @return bias values expressed in meters per squared second.
1294      */
1295     public double[] getAccelerationBiasArray() {
1296         return fixer.getAccelerationBiasArray();
1297     }
1298 
1299     /**
1300      * Gets acceleration bias values expressed in meters per squared second (m/s^2).
1301      *
1302      * @param result instance where result data will be stored.
1303      * @throws IllegalArgumentException if provided array does not have length 3.
1304      */
1305     public void getAccelerationBiasArray(final double[] result) {
1306         fixer.getAccelerationBiasArray(result);
1307     }
1308 
1309     /**
1310      * Sets acceleration bias values expressed in meters per squared second (m/s^2).
1311      *
1312      * @param bias bias values expressed in meters per squared second (m/s^2).
1313      *             Must have length 3.
1314      * @throws IllegalArgumentException if provided array does not have length 3.
1315      * @throws LockedException          if estimator is running.
1316      */
1317     public void setAccelerationBias(final double[] bias) throws LockedException {
1318         if (running) {
1319             throw new LockedException();
1320         }
1321 
1322         fixer.setAccelerationBias(bias);
1323     }
1324 
1325     /**
1326      * Gets acceleration bias.
1327      *
1328      * @return acceleration bias.
1329      */
1330     public AccelerationTriad getAccelerationBiasAsTriad() {
1331         return fixer.getAccelerationBiasAsTriad();
1332     }
1333 
1334     /**
1335      * Gets acceleration bias.
1336      *
1337      * @param result instance where the result will be stored.
1338      */
1339     public void getAccelerationBiasAsTriad(final AccelerationTriad result) {
1340         fixer.getAccelerationBiasAsTriad(result);
1341     }
1342 
1343     /**
1344      * Sets acceleration bias.
1345      *
1346      * @param bias acceleration bias to be set.
1347      * @throws LockedException if estimator is running.
1348      */
1349     public void setAccelerationBias(final AccelerationTriad bias) throws LockedException {
1350         if (running) {
1351             throw new LockedException();
1352         }
1353 
1354         fixer.setAccelerationBias(bias);
1355     }
1356 
1357     /**
1358      * Gets acceleration x-coordinate of bias expressed in meters per squared
1359      * second (m/s^2).
1360      *
1361      * @return x-coordinate of bias expressed in meters per squared second (m/s^2).
1362      */
1363     public double getAccelerationBiasX() {
1364         return fixer.getAccelerationBiasX();
1365     }
1366 
1367     /**
1368      * Sets acceleration x-coordinate of bias expressed in meters per squared
1369      * second (m/s^2).
1370      *
1371      * @param biasX x-coordinate of bias expressed in meters per squared second
1372      *              (m/s^2).
1373      * @throws LockedException if estimator is running.
1374      */
1375     public void setAccelerationBiasX(final double biasX) throws LockedException {
1376         if (running) {
1377             throw new LockedException();
1378         }
1379 
1380         fixer.setAccelerationBiasX(biasX);
1381     }
1382 
1383     /**
1384      * Gets acceleration y-coordinate of bias expressed in meters per squared
1385      * second (m/s^2).
1386      *
1387      * @return y-coordinate of bias expressed in meters per squared second (m/s^2).
1388      */
1389     public double getAccelerationBiasY() {
1390         return fixer.getAccelerationBiasY();
1391     }
1392 
1393     /**
1394      * Sets acceleration y-coordinate of bias expressed in meters per squared
1395      * second (m/s^2).
1396      *
1397      * @param biasY y-coordinate of bias expressed in meters per squared second
1398      *              (m/s^2).
1399      * @throws LockedException if estimator is running.
1400      */
1401     public void setAccelerationBiasY(final double biasY) throws LockedException {
1402         if (running) {
1403             throw new LockedException();
1404         }
1405 
1406         fixer.setAccelerationBiasY(biasY);
1407     }
1408 
1409     /**
1410      * Gets acceleration z-coordinate of bias expressed in meters per squared
1411      * second (m/s^2).
1412      *
1413      * @return z-coordinate of bias expressed in meters per squared second (m/s^2).
1414      */
1415     public double getAccelerationBiasZ() {
1416         return fixer.getAccelerationBiasZ();
1417     }
1418 
1419     /**
1420      * Sets acceleration z-coordinate of bias expressed in meters per squared
1421      * second (m/s^2).
1422      *
1423      * @param biasZ z-coordinate of bias expressed in meters per squared second (m/s^2).
1424      * @throws LockedException if estimator is running.
1425      */
1426     public void setAccelerationBiasZ(final double biasZ) throws LockedException {
1427         if (running) {
1428             throw new LockedException();
1429         }
1430 
1431         fixer.setAccelerationBiasZ(biasZ);
1432     }
1433 
1434     /**
1435      * Sets acceleration coordinates of bias expressed in meters per squared
1436      * second (m/s^2).
1437      *
1438      * @param biasX x-coordinate of bias.
1439      * @param biasY y-coordinate of bias.
1440      * @param biasZ z-coordinate of bias.
1441      * @throws LockedException if estimator is running.
1442      */
1443     public void setAccelerationBias(final double biasX, final double biasY, final double biasZ) throws LockedException {
1444         if (running) {
1445             throw new LockedException();
1446         }
1447 
1448         fixer.setAccelerationBias(biasX, biasY, biasZ);
1449     }
1450 
1451     /**
1452      * Gets acceleration x-coordinate of bias.
1453      *
1454      * @return acceleration x-coordinate of bias.
1455      */
1456     public Acceleration getAccelerationBiasXAsAcceleration() {
1457         return fixer.getAccelerationBiasXAsAcceleration();
1458     }
1459 
1460     /**
1461      * Gets acceleration x-coordinate of bias.
1462      *
1463      * @param result instance where the result will be stored.
1464      */
1465     public void getAccelerationBiasXAsAcceleration(final Acceleration result) {
1466         fixer.getAccelerationBiasXAsAcceleration(result);
1467     }
1468 
1469     /**
1470      * Sets acceleration x-coordinate of bias.
1471      *
1472      * @param biasX acceleration x-coordinate of bias.
1473      * @throws LockedException if estimator is running.
1474      */
1475     public void setAccelerationBiasX(final Acceleration biasX) throws LockedException {
1476         if (running) {
1477             throw new LockedException();
1478         }
1479 
1480         fixer.setAccelerationBiasX(biasX);
1481     }
1482 
1483     /**
1484      * Gets acceleration y-coordinate of bias.
1485      *
1486      * @return acceleration y-coordinate of bias.
1487      */
1488     public Acceleration getAccelerationBiasYAsAcceleration() {
1489         return fixer.getAccelerationBiasYAsAcceleration();
1490     }
1491 
1492     /**
1493      * Gets acceleration y-coordinate of bias.
1494      *
1495      * @param result instance where the result will be stored.
1496      */
1497     public void getAccelerationBiasYAsAcceleration(final Acceleration result) {
1498         fixer.getAccelerationBiasYAsAcceleration(result);
1499     }
1500 
1501     /**
1502      * Sets acceleration y-coordinate of bias.
1503      *
1504      * @param biasY acceleration y-coordinate of bias.
1505      * @throws LockedException if estimator is running.
1506      */
1507     public void setAccelerationBiasY(final Acceleration biasY) throws LockedException {
1508         if (running) {
1509             throw new LockedException();
1510         }
1511 
1512         fixer.setAccelerationBiasY(biasY);
1513     }
1514 
1515     /**
1516      * Gets acceleration z-coordinate of bias.
1517      *
1518      * @return acceleration z-coordinate of bias.
1519      */
1520     public Acceleration getAccelerationBiasZAsAcceleration() {
1521         return fixer.getAccelerationBiasZAsAcceleration();
1522     }
1523 
1524     /**
1525      * Gets acceleration z-coordinate of bias.
1526      *
1527      * @param result instance where the result will be stored.
1528      */
1529     public void getAccelerationBiasZAsAcceleration(final Acceleration result) {
1530         fixer.getAccelerationBiasZAsAcceleration(result);
1531     }
1532 
1533     /**
1534      * Sets acceleration z-coordinate of bias.
1535      *
1536      * @param biasZ z-coordinate of bias.
1537      * @throws LockedException if estimator is running.
1538      */
1539     public void setAccelerationBiasZ(final Acceleration biasZ) throws LockedException {
1540         if (running) {
1541             throw new LockedException();
1542         }
1543 
1544         fixer.setAccelerationBiasZ(biasZ);
1545     }
1546 
1547     /**
1548      * Sets acceleration coordinates of bias.
1549      *
1550      * @param biasX x-coordinate of bias.
1551      * @param biasY y-coordinate of bias.
1552      * @param biasZ z-coordinate of bias.
1553      * @throws LockedException if estimator is running.
1554      */
1555     public void setAccelerationBias(
1556             final Acceleration biasX,
1557             final Acceleration biasY,
1558             final Acceleration biasZ) throws LockedException {
1559         if (running) {
1560             throw new LockedException();
1561         }
1562 
1563         fixer.setAccelerationBias(biasX, biasY, biasZ);
1564     }
1565 
1566     /**
1567      * Gets acceleration cross-coupling errors matrix.
1568      *
1569      * @return acceleration cross-coupling errors matrix.
1570      */
1571     public Matrix getAccelerationCrossCouplingErrors() {
1572         return fixer.getAccelerationCrossCouplingErrors();
1573     }
1574 
1575     /**
1576      * Gets acceleration cross-coupling errors matrix.
1577      *
1578      * @param result instance where the result will be stored.
1579      */
1580     public void getAccelerationCrossCouplingErrors(final Matrix result) {
1581         fixer.getAccelerationCrossCouplingErrors(result);
1582     }
1583 
1584     /**
1585      * Sets acceleration cross-coupling errors matrix.
1586      *
1587      * @param crossCouplingErrors acceleration cross-coupling errors matrix.
1588      *                            Must be 3x3.
1589      * @throws LockedException          if estimator is running.
1590      * @throws AlgebraException         if matrix cannot be inverted.
1591      * @throws IllegalArgumentException if matrix is not 3x3.
1592      */
1593     public void setAccelerationCrossCouplingErrors(final Matrix crossCouplingErrors) throws AlgebraException,
1594             LockedException {
1595         if (running) {
1596             throw new LockedException();
1597         }
1598 
1599         fixer.setAccelerationCrossCouplingErrors(crossCouplingErrors);
1600     }
1601 
1602     /**
1603      * Gets acceleration x scaling factor.
1604      *
1605      * @return x scaling factor.
1606      */
1607     public double getAccelerationSx() {
1608         return fixer.getAccelerationSx();
1609     }
1610 
1611     /**
1612      * Sets acceleration x scaling factor.
1613      *
1614      * @param sx x scaling factor.
1615      * @throws LockedException  if estimator is running.
1616      * @throws AlgebraException if provided value makes acceleration cross-coupling matrix non-invertible.
1617      */
1618     public void setAccelerationSx(final double sx) throws LockedException, AlgebraException {
1619         if (running) {
1620             throw new LockedException();
1621         }
1622 
1623         fixer.setAccelerationSx(sx);
1624     }
1625 
1626     /**
1627      * Gets acceleration y scaling factor.
1628      *
1629      * @return y scaling factor.
1630      */
1631     public double getAccelerationSy() {
1632         return fixer.getAccelerationSy();
1633     }
1634 
1635     /**
1636      * Sets acceleration y scaling factor.
1637      *
1638      * @param sy y scaling factor.
1639      * @throws LockedException  if estimator is running.
1640      * @throws AlgebraException if provided value makes acceleration cross-coupling matrix non-invertible.
1641      */
1642     public void setAccelerationSy(final double sy) throws LockedException, AlgebraException {
1643         if (running) {
1644             throw new LockedException();
1645         }
1646 
1647         fixer.setAccelerationSy(sy);
1648     }
1649 
1650     /**
1651      * Gets acceleration z scaling factor.
1652      *
1653      * @return z scaling factor.
1654      */
1655     public double getAccelerationSz() {
1656         return fixer.getAccelerationSz();
1657     }
1658 
1659     /**
1660      * Sets acceleration z scaling factor.
1661      *
1662      * @param sz z scaling factor.
1663      * @throws LockedException  if estimator is running.
1664      * @throws AlgebraException if provided value makes acceleration cross-coupling matrix non-invertible.
1665      */
1666     public void setAccelerationSz(final double sz) throws LockedException, AlgebraException {
1667         if (running) {
1668             throw new LockedException();
1669         }
1670 
1671         fixer.setAccelerationSz(sz);
1672     }
1673 
1674     /**
1675      * Gets acceleration x-y cross-coupling error.
1676      *
1677      * @return acceleration x-y cross-coupling error.
1678      */
1679     public double getAccelerationMxy() {
1680         return fixer.getAccelerationMxy();
1681     }
1682 
1683     /**
1684      * Sets acceleration x-y cross-coupling error.
1685      *
1686      * @param mxy acceleration x-y cross-coupling error.
1687      * @throws LockedException  if estimator is running.
1688      * @throws AlgebraException if provided value makes acceleration cross-coupling matrix non-invertible.
1689      */
1690     public void setAccelerationMxy(final double mxy) throws LockedException, AlgebraException {
1691         if (running) {
1692             throw new LockedException();
1693         }
1694 
1695         fixer.setAccelerationMxy(mxy);
1696     }
1697 
1698     /**
1699      * Gets acceleration x-z cross-coupling error.
1700      *
1701      * @return acceleration x-z cross-coupling error.
1702      */
1703     public double getAccelerationMxz() {
1704         return fixer.getAccelerationMxz();
1705     }
1706 
1707     /**
1708      * Sets acceleration x-z cross-coupling error.
1709      *
1710      * @param mxz acceleration x-z cross-coupling error.
1711      * @throws LockedException  if estimator is running.
1712      * @throws AlgebraException if provided value makes acceleration cross-coupling matrix non-invertible.
1713      */
1714     public void setAccelerationMxz(final double mxz) throws LockedException, AlgebraException {
1715         if (running) {
1716             throw new LockedException();
1717         }
1718 
1719         fixer.setAccelerationMxz(mxz);
1720     }
1721 
1722     /**
1723      * Gets acceleration y-x cross-coupling error.
1724      *
1725      * @return acceleration y-x cross-coupling error.
1726      */
1727     public double getAccelerationMyx() {
1728         return fixer.getAccelerationMyx();
1729     }
1730 
1731     /**
1732      * Sets acceleration y-x cross-coupling error.
1733      *
1734      * @param myx acceleration y-x cross-coupling error.
1735      * @throws LockedException  if estimator is running.
1736      * @throws AlgebraException if provided value makes acceleration cross-coupling matrix non-invertible.
1737      */
1738     public void setAccelerationMyx(final double myx) throws LockedException, AlgebraException {
1739         if (running) {
1740             throw new LockedException();
1741         }
1742 
1743         fixer.setAccelerationMyx(myx);
1744     }
1745 
1746     /**
1747      * Gets acceleration y-z cross-coupling error.
1748      *
1749      * @return y-z cross coupling error.
1750      */
1751     public double getAccelerationMyz() {
1752         return fixer.getAccelerationMyz();
1753     }
1754 
1755     /**
1756      * Sets acceleration y-z cross-coupling error.
1757      *
1758      * @param myz y-z cross coupling error.
1759      * @throws LockedException  if estimator is running.
1760      * @throws AlgebraException if provided value makes acceleration cross-coupling matrix non-invertible.
1761      */
1762     public void setAccelerationMyz(final double myz) throws LockedException, AlgebraException {
1763         if (running) {
1764             throw new LockedException();
1765         }
1766 
1767         fixer.setAccelerationMyz(myz);
1768     }
1769 
1770     /**
1771      * Gets acceleration z-x cross-coupling error.
1772      *
1773      * @return acceleration z-x cross-coupling error.
1774      */
1775     public double getAccelerationMzx() {
1776         return fixer.getAccelerationMzx();
1777     }
1778 
1779     /**
1780      * Sets acceleration z-x cross coupling error.
1781      *
1782      * @param mzx acceleration z-x cross coupling error.
1783      * @throws LockedException  if estimator is running.
1784      * @throws AlgebraException if provided value makes acceleration cross-coupling matrix non-invertible.
1785      */
1786     public void setAccelerationMzx(final double mzx) throws LockedException, AlgebraException {
1787         if (running) {
1788             throw new LockedException();
1789         }
1790 
1791         fixer.setAccelerationMzx(mzx);
1792     }
1793 
1794     /**
1795      * Gets acceleration z-y cross-coupling error.
1796      *
1797      * @return acceleration z-y cross-coupling error.
1798      */
1799     public double getAccelerationMzy() {
1800         return fixer.getAccelerationMzy();
1801     }
1802 
1803     /**
1804      * Sets acceleration z-y cross-coupling error.
1805      *
1806      * @param mzy acceleration z-y cross coupling error.
1807      * @throws LockedException  if estimator is running.
1808      * @throws AlgebraException if provided value makes acceleration cross-coupling matrix non-invertible.
1809      */
1810     public void setAccelerationMzy(final double mzy) throws LockedException, AlgebraException {
1811         if (running) {
1812             throw new LockedException();
1813         }
1814 
1815         fixer.setAccelerationMzy(mzy);
1816     }
1817 
1818     /**
1819      * Sets acceleration scaling factors.
1820      *
1821      * @param sx x scaling factor.
1822      * @param sy y scaling factor.
1823      * @param sz z scaling factor.
1824      * @throws LockedException  if estimator is running.
1825      * @throws AlgebraException if provided values make acceleration cross-coupling matrix non-invertible.
1826      */
1827     public void setAccelerationScalingFactors(final double sx, final double sy, final double sz)
1828             throws LockedException, AlgebraException {
1829         if (running) {
1830             throw new LockedException();
1831         }
1832 
1833         fixer.setAccelerationScalingFactors(sx, sy, sz);
1834     }
1835 
1836     /**
1837      * Sets acceleration cross-coupling errors.
1838      *
1839      * @param mxy x-y cross coupling error.
1840      * @param mxz x-z cross coupling error.
1841      * @param myx y-x cross coupling error.
1842      * @param myz y-z cross coupling error.
1843      * @param mzx z-x cross coupling error.
1844      * @param mzy z-y cross coupling error.
1845      * @throws LockedException  if estimator is running.
1846      * @throws AlgebraException if provided values make acceleration cross-coupling matrix non-invertible.
1847      */
1848     public void setAccelerationCrossCouplingErrors(
1849             final double mxy, final double mxz,
1850             final double myx, final double myz,
1851             final double mzx, final double mzy) throws LockedException, AlgebraException {
1852         if (running) {
1853             throw new LockedException();
1854         }
1855 
1856         fixer.setAccelerationCrossCouplingErrors(mxy, mxz, myx, myz, mzx, mzy);
1857     }
1858 
1859     /**
1860      * Sets acceleration scaling factors and cross-coupling errors.
1861      *
1862      * @param sx  x scaling factor.
1863      * @param sy  y scaling factor.
1864      * @param sz  z scaling factor.
1865      * @param mxy x-y cross coupling error.
1866      * @param mxz x-z cross coupling error.
1867      * @param myx y-x cross coupling error.
1868      * @param myz y-z cross coupling error.
1869      * @param mzx z-x cross coupling error.
1870      * @param mzy z-y cross coupling error.
1871      * @throws LockedException  if estimator is running.
1872      * @throws AlgebraException if provided values make acceleration cross-coupling matrix non-invertible.
1873      */
1874     public void setAccelerationScalingFactorsAndCrossCouplingErrors(
1875             final double sx, final double sy, final double sz,
1876             final double mxy, final double mxz,
1877             final double myx, final double myz,
1878             final double mzx, final double mzy) throws LockedException, AlgebraException {
1879         if (running) {
1880             throw new LockedException();
1881         }
1882 
1883         fixer.setAccelerationScalingFactorsAndCrossCouplingErrors(sx, sy, sz, mxy, mxz, myx, myz, mzx, mzy);
1884     }
1885 
1886     /**
1887      * Gets angular speed bias values expressed in radians per second (rad/s).
1888      *
1889      * @return angular speed bias values expressed in radians per second.
1890      */
1891     public Matrix getAngularSpeedBias() {
1892         return fixer.getAngularSpeedBias();
1893     }
1894 
1895     /**
1896      * Gets angular speed bias values expressed in radians per second (rad/s).
1897      *
1898      * @param result instance where the result will be stored.
1899      */
1900     public void getAngularSpeedBias(final Matrix result) {
1901         fixer.getAngularSpeedBias(result);
1902     }
1903 
1904     /**
1905      * Sets angular speed bias values expressed in radians per second (rad/s).
1906      *
1907      * @param bias bias values expressed in radians per second. Must be 3x1.
1908      * @throws IllegalArgumentException if matrix is not 3x1.
1909      * @throws LockedException          if estimator is running.
1910      */
1911     public void setAngularSpeedBias(final Matrix bias) throws LockedException {
1912         if (running) {
1913             throw new LockedException();
1914         }
1915 
1916         fixer.setAngularSpeedBias(bias);
1917     }
1918 
1919     /**
1920      * Gets angular speed bias values expressed in radians per second (rad/s).
1921      *
1922      * @return bias values expressed in radians per second.
1923      */
1924     public double[] getAngularSpeedBiasArray() {
1925         return fixer.getAngularSpeedBiasArray();
1926     }
1927 
1928     /**
1929      * Gets angular speed bias values expressed in radians per second (rad/s).
1930      *
1931      * @param result instance where result data will be stored.
1932      * @throws IllegalArgumentException if provided array does not have length 3.
1933      */
1934     public void getAngularSpeedBiasArray(final double[] result) {
1935         fixer.getAngularSpeedBiasArray(result);
1936     }
1937 
1938     /**
1939      * Sets angular speed bias values expressed in radians per second (rad/s).
1940      *
1941      * @param bias bias values expressed in radians per second (rad/s). Must
1942      *             have length 3.
1943      * @throws IllegalArgumentException if provided array does not have length 3.
1944      * @throws LockedException          if estimator is running.
1945      */
1946     public void setAngularSpeedBias(final double[] bias) throws LockedException {
1947         if (running) {
1948             throw new LockedException();
1949         }
1950 
1951         fixer.setAngularSpeedBias(bias);
1952     }
1953 
1954     /**
1955      * Gets angular speed bias.
1956      *
1957      * @return angular speed bias.
1958      */
1959     public AngularSpeedTriad getAngularSpeedBiasAsTriad() {
1960         return fixer.getAngularSpeedBiasAsTriad();
1961     }
1962 
1963     /**
1964      * Gets angular speed bias.
1965      *
1966      * @param result instance where the result will be stored.
1967      */
1968     public void getAngularSpeedBiasAsTriad(final AngularSpeedTriad result) {
1969         fixer.getAngularSpeedBiasAsTriad(result);
1970     }
1971 
1972     /**
1973      * Sets angular speed bias.
1974      *
1975      * @param bias angular speed bias to be set.
1976      * @throws LockedException if estimator is running.
1977      */
1978     public void setAngularSpeedBias(final AngularSpeedTriad bias) throws LockedException {
1979         if (running) {
1980             throw new LockedException();
1981         }
1982 
1983         fixer.setAngularSpeedBias(bias);
1984     }
1985 
1986     /**
1987      * Gets angular speed x-coordinate of bias expressed in radians per second
1988      * (rad/s).
1989      *
1990      * @return x-coordinate of bias expressed in radians per second (rad/s).
1991      */
1992     public double getAngularSpeedBiasX() {
1993         return fixer.getAngularSpeedBiasX();
1994     }
1995 
1996     /**
1997      * Sets angular speed x-coordinate of bias expressed in radians per second
1998      * (rad/s).
1999      *
2000      * @param biasX x-coordinate of bias expressed in radians per second (rad/s).
2001      * @throws LockedException if estimator is running.
2002      */
2003     public void setAngularSpeedBiasX(final double biasX) throws LockedException {
2004         if (running) {
2005             throw new LockedException();
2006         }
2007 
2008         fixer.setAngularSpeedBiasX(biasX);
2009     }
2010 
2011     /**
2012      * Gets angular speed y-coordinate of bias expressed in radians per second
2013      * (rad/s).
2014      *
2015      * @return y-coordinate of bias expressed in radians per second (rad/s).
2016      */
2017     public double getAngularSpeedBiasY() {
2018         return fixer.getAngularSpeedBiasY();
2019     }
2020 
2021     /**
2022      * Sets angular speed y-coordinate of bias expressed in radians per second
2023      * (rad/s).
2024      *
2025      * @param biasY y-coordinate of bias expressed in radians per second (rad/s).
2026      * @throws LockedException if estimator is running.
2027      */
2028     public void setAngularSpeedBiasY(final double biasY) throws LockedException {
2029         if (running) {
2030             throw new LockedException();
2031         }
2032 
2033         fixer.setAngularSpeedBiasY(biasY);
2034     }
2035 
2036     /**
2037      * Gets angular speed z-coordinate of bias expressed in radians per second
2038      * (rad/s).
2039      *
2040      * @return z-coordinate of bias expressed in radians per second (rad/s).
2041      */
2042     public double getAngularSpeedBiasZ() {
2043         return fixer.getAngularSpeedBiasZ();
2044     }
2045 
2046     /**
2047      * Sets angular speed z-coordinate of bias expressed in radians per second
2048      * (rad/s).
2049      *
2050      * @param biasZ z-coordinate of bias expressed in radians per second (rad/s).
2051      * @throws LockedException if estimator is running.
2052      */
2053     public void setAngularSpeedBiasZ(final double biasZ) throws LockedException {
2054         if (running) {
2055             throw new LockedException();
2056         }
2057 
2058         fixer.setAngularSpeedBiasZ(biasZ);
2059     }
2060 
2061     /**
2062      * Sets angular speed coordinates of bias expressed in radians per second
2063      * (rad/s).
2064      *
2065      * @param biasX x-coordinate of bias.
2066      * @param biasY y-coordinate of bias.
2067      * @param biasZ z-coordinate of bias.
2068      * @throws LockedException if estimator is running.
2069      */
2070     public void setAngularSpeedBias(final double biasX, final double biasY, final double biasZ) throws LockedException {
2071         if (running) {
2072             throw new LockedException();
2073         }
2074 
2075         fixer.setAngularSpeedBias(biasX, biasY, biasZ);
2076     }
2077 
2078     /**
2079      * Gets angular speed x-coordinate of bias.
2080      *
2081      * @return x-coordinate of bias.
2082      */
2083     public AngularSpeed getAngularSpeedBiasXAsAngularSpeed() {
2084         return fixer.getAngularSpeedBiasXAsAngularSpeed();
2085     }
2086 
2087     /**
2088      * Gets angular speed x-coordinate of bias.
2089      *
2090      * @param result instance where the result will be stored.
2091      */
2092     public void getAngularSpeedBiasXAsAngularSpeed(final AngularSpeed result) {
2093         fixer.getAngularSpeedBiasXAsAngularSpeed(result);
2094     }
2095 
2096     /**
2097      * Sets angular speed x-coordinate of bias.
2098      *
2099      * @param biasX x-coordinate of bias.
2100      * @throws LockedException if estimator is running.
2101      */
2102     public void setAngularSpeedBiasX(final AngularSpeed biasX) throws LockedException {
2103         if (running) {
2104             throw new LockedException();
2105         }
2106 
2107         fixer.setAngularSpeedBiasX(biasX);
2108     }
2109 
2110     /**
2111      * Gets angular speed y-coordinate of bias.
2112      *
2113      * @return y-coordinate of bias.
2114      */
2115     public AngularSpeed getAngularSpeedBiasYAsAngularSpeed() {
2116         return fixer.getAngularSpeedBiasYAsAngularSpeed();
2117     }
2118 
2119     /**
2120      * Gets angular speed y-coordinate of bias.
2121      *
2122      * @param result instance where the result will be stored.
2123      */
2124     public void getAngularSpeedBiasYAsAngularSpeed(final AngularSpeed result) {
2125         fixer.getAngularSpeedBiasYAsAngularSpeed(result);
2126     }
2127 
2128     /**
2129      * Sets angular speed y-coordinate of bias.
2130      *
2131      * @param biasY y-coordinate of bias.
2132      * @throws LockedException if estimator is running.
2133      */
2134     public void setAngularSpeedBiasY(final AngularSpeed biasY) throws LockedException {
2135         if (running) {
2136             throw new LockedException();
2137         }
2138 
2139         fixer.setAngularSpeedBiasY(biasY);
2140     }
2141 
2142     /**
2143      * Gets angular speed z-coordinate of bias.
2144      *
2145      * @return z-coordinate of bias.
2146      */
2147     public AngularSpeed getAngularSpeedBiasZAsAngularSpeed() {
2148         return fixer.getAngularSpeedBiasZAsAngularSpeed();
2149     }
2150 
2151     /**
2152      * Gets angular speed z-coordinate of bias.
2153      *
2154      * @param result instance where the result will be stored.
2155      */
2156     public void getAngularSpeedBiasZAsAngularSpeed(final AngularSpeed result) {
2157         fixer.getAngularSpeedBiasZAsAngularSpeed(result);
2158     }
2159 
2160     /**
2161      * Sets angular speed z-coordinate of bias.
2162      *
2163      * @param biasZ z-coordinate of bias.
2164      * @throws LockedException if estimator is running.
2165      */
2166     public void setAngularSpeedBiasZ(final AngularSpeed biasZ) throws LockedException {
2167         if (running) {
2168             throw new LockedException();
2169         }
2170 
2171         fixer.setAngularSpeedBiasZ(biasZ);
2172     }
2173 
2174     /**
2175      * Sets angular speed coordinates of bias.
2176      *
2177      * @param biasX x-coordinate of bias.
2178      * @param biasY y-coordinate of bias.
2179      * @param biasZ z-coordinate of bias.
2180      * @throws LockedException if estimator is running.
2181      */
2182     public void setAngularSpeedBias(
2183             final AngularSpeed biasX,
2184             final AngularSpeed biasY,
2185             final AngularSpeed biasZ) throws LockedException {
2186         if (running) {
2187             throw new LockedException();
2188         }
2189 
2190         fixer.setAngularSpeedBias(biasX, biasY, biasZ);
2191     }
2192 
2193     /**
2194      * Gets angular speed cross-coupling errors matrix.
2195      *
2196      * @return cross coupling errors matrix.
2197      */
2198     public Matrix getAngularSpeedCrossCouplingErrors() {
2199         return fixer.getAngularSpeedCrossCouplingErrors();
2200     }
2201 
2202     /**
2203      * Gets angular speed cross-coupling errors matrix.
2204      *
2205      * @param result instance where the result will be stored.
2206      */
2207     public void getAngularSpeedCrossCouplingErrors(final Matrix result) {
2208         fixer.getAngularSpeedCrossCouplingErrors(result);
2209     }
2210 
2211     /**
2212      * Sets angular speed cross-coupling errors matrix.
2213      *
2214      * @param crossCouplingErrors cross-coupling errors matrix. Must be 3x3.
2215      * @throws AlgebraException         if matrix cannot be inverted.
2216      * @throws IllegalArgumentException if matrix is not 3x3.
2217      * @throws LockedException          if estimator is running.
2218      */
2219     public void setAngularSpeedCrossCouplingErrors(final Matrix crossCouplingErrors) throws AlgebraException,
2220             LockedException {
2221         if (running) {
2222             throw new LockedException();
2223         }
2224 
2225         fixer.setAngularSpeedCrossCouplingErrors(crossCouplingErrors);
2226     }
2227 
2228     /**
2229      * Gets angular speed x scaling factor.
2230      *
2231      * @return x scaling factor.
2232      */
2233     public double getAngularSpeedSx() {
2234         return fixer.getAngularSpeedSx();
2235     }
2236 
2237     /**
2238      * Sets angular speed x scaling factor.
2239      *
2240      * @param sx x scaling factor.
2241      * @throws LockedException  if estimator is running.
2242      * @throws AlgebraException if provided value makes angular speed
2243      *                          cross-coupling matrix non-invertible.
2244      */
2245     public void setAngularSpeedSx(final double sx) throws LockedException, AlgebraException {
2246         if (running) {
2247             throw new LockedException();
2248         }
2249 
2250         fixer.setAngularSpeedSx(sx);
2251     }
2252 
2253     /**
2254      * Gets angular speed y scaling factor.
2255      *
2256      * @return y scaling factor.
2257      */
2258     public double getAngularSpeedSy() {
2259         return fixer.getAngularSpeedSy();
2260     }
2261 
2262     /**
2263      * Sets angular speed y-scaling factor.
2264      *
2265      * @param sy y scaling factor.
2266      * @throws LockedException  if estimator is running.
2267      * @throws AlgebraException if provided value makes angular speed
2268      *                          cross-coupling matrix non-invertible.
2269      */
2270     public void setAngularSpeedSy(final double sy) throws LockedException, AlgebraException {
2271         if (running) {
2272             throw new LockedException();
2273         }
2274 
2275         fixer.setAngularSpeedSy(sy);
2276     }
2277 
2278     /**
2279      * Gets angular speed z scaling factor.
2280      *
2281      * @return z scaling factor.
2282      */
2283     public double getAngularSpeedSz() {
2284         return fixer.getAngularSpeedSz();
2285     }
2286 
2287     /**
2288      * Sets angular speed z scaling factor.
2289      *
2290      * @param sz z scaling factor.
2291      * @throws LockedException  if estimator is running.
2292      * @throws AlgebraException if provided value makes angular speed
2293      *                          cross-coupling matrix non-invertible.
2294      */
2295     public void setAngularSpeedSz(final double sz) throws LockedException, AlgebraException {
2296         if (running) {
2297             throw new LockedException();
2298         }
2299 
2300         fixer.setAngularSpeedSz(sz);
2301     }
2302 
2303     /**
2304      * Gets angular speed x-y cross-coupling error.
2305      *
2306      * @return x-y cross coupling error.
2307      */
2308     public double getAngularSpeedMxy() {
2309         return fixer.getAngularSpeedMxy();
2310     }
2311 
2312     /**
2313      * Sets angular speed x-y cross-coupling error.
2314      *
2315      * @param mxy x-y cross coupling error.
2316      * @throws LockedException  if estimator is running.
2317      * @throws AlgebraException if provided value makes angular speed
2318      *                          cross-coupling matrix non-invertible.
2319      */
2320     public void setAngularSpeedMxy(final double mxy) throws LockedException, AlgebraException {
2321         if (running) {
2322             throw new LockedException();
2323         }
2324 
2325         fixer.setAngularSpeedMxy(mxy);
2326     }
2327 
2328     /**
2329      * Gets angular speed x-z cross-coupling error.
2330      *
2331      * @return x-z cross coupling error.
2332      */
2333     public double getAngularSpeedMxz() {
2334         return fixer.getAngularSpeedMxz();
2335     }
2336 
2337     /**
2338      * Sets angular speed x-z cross-coupling error.
2339      *
2340      * @param mxz x-z cross coupling error.
2341      * @throws LockedException  if estimator is running.
2342      * @throws AlgebraException if provided value makes angular speed
2343      *                          cross-coupling matrix non-invertible.
2344      */
2345     public void setAngularSpeedMxz(final double mxz) throws LockedException, AlgebraException {
2346         if (running) {
2347             throw new LockedException();
2348         }
2349 
2350         fixer.setAngularSpeedMxz(mxz);
2351     }
2352 
2353     /**
2354      * Gets angular speed y-x cross-coupling error.
2355      *
2356      * @return y-x cross coupling error.
2357      */
2358     public double getAngularSpeedMyx() {
2359         return fixer.getAngularSpeedMyx();
2360     }
2361 
2362     /**
2363      * Sets angular speed y-x cross-coupling error.
2364      *
2365      * @param myx y-x cross coupling error.
2366      * @throws LockedException  if estimator is running.
2367      * @throws AlgebraException if provided value makes angular speed
2368      *                          cross-coupling matrix non-invertible.
2369      */
2370     public void setAngularSpeedMyx(final double myx) throws LockedException, AlgebraException {
2371         if (running) {
2372             throw new LockedException();
2373         }
2374 
2375         fixer.setAngularSpeedMyx(myx);
2376     }
2377 
2378     /**
2379      * Gets angular speed y-z cross-coupling error.
2380      *
2381      * @return y-z cross coupling error.
2382      */
2383     public double getAngularSpeedMyz() {
2384         return fixer.getAngularSpeedMyz();
2385     }
2386 
2387     /**
2388      * Sets angular speed y-z cross-coupling error.
2389      *
2390      * @param myz y-z cross coupling error.
2391      * @throws LockedException  if estimator is running.
2392      * @throws AlgebraException if provided value makes angular speed
2393      *                          cross-coupling matrix non-invertible.
2394      */
2395     public void setAngularSpeedMyz(final double myz) throws LockedException, AlgebraException {
2396         if (running) {
2397             throw new LockedException();
2398         }
2399 
2400         fixer.setAngularSpeedMyz(myz);
2401     }
2402 
2403     /**
2404      * Gets angular speed z-x cross-coupling error.
2405      *
2406      * @return z-x cross coupling error.
2407      */
2408     public double getAngularSpeedMzx() {
2409         return fixer.getAngularSpeedMzx();
2410     }
2411 
2412     /**
2413      * Sets angular speed z-x cross-coupling error.
2414      *
2415      * @param mzx z-x cross coupling error.
2416      * @throws LockedException  if estimator is running.
2417      * @throws AlgebraException if provided value makes angular speed
2418      *                          cross-coupling matrix non-invertible.
2419      */
2420     public void setAngularSpeedMzx(final double mzx) throws LockedException, AlgebraException {
2421         if (running) {
2422             throw new LockedException();
2423         }
2424 
2425         fixer.setAngularSpeedMzx(mzx);
2426     }
2427 
2428     /**
2429      * Gets angular speed z-y cross-coupling error.
2430      *
2431      * @return z-y cross coupling error.
2432      */
2433     public double getAngularSpeedMzy() {
2434         return fixer.getAngularSpeedMzy();
2435     }
2436 
2437     /**
2438      * Sets angular speed z-y cross-coupling error.
2439      *
2440      * @param mzy z-y cross coupling error.
2441      * @throws LockedException  if estimator is running.
2442      * @throws AlgebraException if provided value makes angular speed
2443      *                          cross-coupling matrix non-invertible.
2444      */
2445     public void setAngularSpeedMzy(final double mzy) throws LockedException, AlgebraException {
2446         if (running) {
2447             throw new LockedException();
2448         }
2449 
2450         fixer.setAngularSpeedMzy(mzy);
2451     }
2452 
2453     /**
2454      * Sets angular speed scaling factors.
2455      *
2456      * @param sx x scaling factor.
2457      * @param sy y scaling factor.
2458      * @param sz z scaling factor.
2459      * @throws LockedException  if estimator is running.
2460      * @throws AlgebraException if provided values make angular speed
2461      *                          cross-coupling matrix non-invertible.
2462      */
2463     public void setAngularSpeedScalingFactors(final double sx, final double sy, final double sz) throws LockedException,
2464             AlgebraException {
2465         if (running) {
2466             throw new LockedException();
2467         }
2468 
2469         fixer.setAngularSpeedScalingFactors(sx, sy, sz);
2470     }
2471 
2472     /**
2473      * Sets angular speed cross-coupling errors.
2474      *
2475      * @param mxy x-y cross coupling error.
2476      * @param mxz x-z cross coupling error.
2477      * @param myx y-x cross coupling error.
2478      * @param myz y-z cross coupling error.
2479      * @param mzx z-x cross coupling error.
2480      * @param mzy z-y cross coupling error.
2481      * @throws LockedException  if estimator is running.
2482      * @throws AlgebraException if provided values make angular speed
2483      *                          cross-coupling matrix non-invertible.
2484      */
2485     public void setAngularSpeedCrossCouplingErrors(
2486             final double mxy, final double mxz,
2487             final double myx, final double myz,
2488             final double mzx, final double mzy) throws LockedException, AlgebraException {
2489         if (running) {
2490             throw new LockedException();
2491         }
2492 
2493         fixer.setAngularSpeedCrossCouplingErrors(mxy, mxz, myx, myz, mzx, mzy);
2494     }
2495 
2496     /**
2497      * Sets angular speed scaling factors and cross-coupling errors.
2498      *
2499      * @param sx  x scaling factor.
2500      * @param sy  y scaling factor.
2501      * @param sz  z scaling factor.
2502      * @param mxy x-y cross coupling error.
2503      * @param mxz x-z cross coupling error.
2504      * @param myx y-x cross coupling error.
2505      * @param myz y-z cross coupling error.
2506      * @param mzx z-x cross coupling error.
2507      * @param mzy z-y cross coupling error.
2508      * @throws LockedException  if estimator is running.
2509      * @throws AlgebraException if provided values make angular speed
2510      *                          cross-coupling matrix non-invertible.
2511      */
2512     public void setAngularSpeedScalingFactorsAndCrossCouplingErrors(
2513             final double sx, final double sy, final double sz,
2514             final double mxy, final double mxz,
2515             final double myx, final double myz,
2516             final double mzx, final double mzy) throws LockedException, AlgebraException {
2517         if (running) {
2518             throw new LockedException();
2519         }
2520 
2521         fixer.setAngularSpeedScalingFactorsAndCrossCouplingErrors(sx, sy, sz, mxy, mxz, myx, myz, mzx, mzy);
2522     }
2523 
2524     /**
2525      * Gets angular speed g-dependant cross biases matrix.
2526      *
2527      * @return g-dependant cross biases matrix.
2528      */
2529     public Matrix getAngularSpeedGDependantCrossBias() {
2530         return fixer.getAngularSpeedGDependantCrossBias();
2531     }
2532 
2533     /**
2534      * Gets angular speed g-dependant cross biases matrix.
2535      *
2536      * @param result instance where the result will be stored.
2537      */
2538     public void getAngularSpeedGDependantCrossBias(final Matrix result) {
2539         fixer.getAngularSpeedGDependantCrossBias(result);
2540     }
2541 
2542     /**
2543      * Sets angular speed g-dependant cross biases matrix.
2544      *
2545      * @param gDependantCrossBias g-dependant cross biases matrix.
2546      * @throws IllegalArgumentException if matrix is not 3x3.
2547      * @throws LockedException          if estimator is running.
2548      */
2549     public void setAngularSpeedGDependantCrossBias(final Matrix gDependantCrossBias) throws LockedException {
2550         if (running) {
2551             throw new LockedException();
2552         }
2553 
2554         fixer.setAngularSpeedGDependantCrossBias(gDependantCrossBias);
2555     }
2556 
2557     /**
2558      * Indicates whether measured kinematics must be fixed or not.
2559      * When enabled, provided calibration data is used; otherwise it is
2560      * ignored.
2561      * By default, this is enabled.
2562      *
2563      * @return indicates whether measured kinematics must be fixed or not.
2564      */
2565     public boolean isFixKinematicsEnabled() {
2566         return fixKinematics;
2567     }
2568 
2569     /**
2570      * Specifies whether measured kinematics must be fixed or not.
2571      * When enabled, provided calibration data is used; otherwise it is
2572      * ignored.
2573      *
2574      * @param fixKinematics true if measured kinematics must be fixed or not.
2575      * @throws LockedException if estimator is currently running.
2576      */
2577     public void setFixKinematicsEnabled(final boolean fixKinematics) throws LockedException {
2578         if (running) {
2579             throw new LockedException();
2580         }
2581         this.fixKinematics = fixKinematics;
2582     }
2583 
2584     /**
2585      * Gets the time interval between body kinematics (IMU acceleration and gyroscope)
2586      * samples expressed in seconds (s).
2587      *
2588      * @return time interval between body kinematics samples.
2589      */
2590     public double getTimeInterval() {
2591         return timeInterval;
2592     }
2593 
2594     /**
2595      * Sets a time interval between body kinematics (IMU acceleration and gyroscope)
2596      * samples expressed in seconds (s).
2597      *
2598      * @param timeInterval time interval between body kinematics samples.
2599      * @throws LockedException if estimator is currently running.
2600      */
2601     public void setTimeInterval(final double timeInterval) throws LockedException {
2602         if (running) {
2603             throw new LockedException();
2604         }
2605 
2606         if (timeInterval < 0.0) {
2607             throw new IllegalArgumentException();
2608         }
2609 
2610         this.timeInterval = timeInterval;
2611     }
2612 
2613     /**
2614      * Gets time interval between body kinematics (IMU acceleration and gyroscope)
2615      * samples.
2616      *
2617      * @return time interval between body kinematics samples.
2618      */
2619     public Time getTimeIntervalAsTime() {
2620         return new Time(timeInterval, TimeUnit.SECOND);
2621     }
2622 
2623     /**
2624      * Gets time interval between body kinematics (IMU acceleration and gyroscope)
2625      * samples.
2626      *
2627      * @param result instance where the time interval will be stored.
2628      */
2629     public void getTimeIntervalAsTime(final Time result) {
2630         result.setValue(timeInterval);
2631         result.setUnit(TimeUnit.SECOND);
2632     }
2633 
2634     /**
2635      * Sets time interval between body kinematics (IMU acceleration and gyroscope)
2636      * samples.
2637      *
2638      * @param timeInterval time interval between body kinematics samples.
2639      * @throws LockedException if estimator is currently running.
2640      */
2641     public void setTimeInterval(final Time timeInterval) throws LockedException {
2642         setTimeInterval(convertTime(timeInterval));
2643     }
2644 
2645     /**
2646      * Indicates if estimator is ready to start processing additional kinematics
2647      * measurements.
2648      *
2649      * @return true if ready, false otherwise.
2650      */
2651     public boolean isReady() {
2652         return referenceFrame != null;
2653     }
2654 
2655     /**
2656      * Indicates whether this estimator is running.
2657      *
2658      * @return true if this estimator is running, false otherwise.
2659      */
2660     public boolean isRunning() {
2661         return running;
2662     }
2663 
2664     /**
2665      * Adds a sample of measured body kinematics (accelerometer and gyroscope readings)
2666      * obtained from an IMU, fixes their values and uses fixed values to estimate
2667      * current drift and their average values.
2668      *
2669      * @param kinematics measured body kinematics.
2670      * @throws LockedException          if estimator is currently running.
2671      * @throws NotReadyException        if estimator is not ready.
2672      * @throws DriftEstimationException if estimation fails for some reason.
2673      */
2674     public void addBodyKinematics(final BodyKinematics kinematics) throws LockedException, NotReadyException,
2675             DriftEstimationException {
2676         if (running) {
2677             throw new LockedException();
2678         }
2679 
2680         if (!isReady()) {
2681             throw new NotReadyException();
2682         }
2683 
2684         try {
2685             running = true;
2686 
2687             if (numberOfProcessedSamples == 0) {
2688                 if (listener != null) {
2689                     listener.onStart(this);
2690                 }
2691 
2692                 final var c = referenceFrame.getCoordinateTransformation();
2693                 c.asRotation(refQ);
2694                 refQ.inverse(invRefQ);
2695 
2696                 frame.copyFrom(referenceFrame);
2697             }
2698 
2699             if (fixKinematics) {
2700                 fixer.fix(kinematics, fixedKinematics);
2701             } else {
2702                 fixedKinematics.copyFrom(kinematics);
2703             }
2704 
2705             // estimate navigation variation respect to previous frame
2706             ECEFInertialNavigator.navigateECEF(timeInterval, frame, fixedKinematics, frame);
2707 
2708             // estimate drift values
2709             computeCurrentPositionDrift();
2710             computeCurrentVelocityDrift();
2711             computeCurrentOrientationDrift();
2712 
2713             numberOfProcessedSamples++;
2714 
2715             if (listener != null) {
2716                 listener.onBodyKinematicsAdded(this, kinematics, fixedKinematics);
2717             }
2718 
2719         } catch (final AlgebraException | InertialNavigatorException | InvalidRotationMatrixException e) {
2720             throw new DriftEstimationException(e);
2721         } finally {
2722             running = false;
2723         }
2724     }
2725 
2726     /**
2727      * Resets this estimator to its initial state.
2728      *
2729      * @throws LockedException if estimator is currently running.
2730      */
2731     public void reset() throws LockedException {
2732         if (running) {
2733             throw new LockedException();
2734         }
2735 
2736         running = true;
2737         numberOfProcessedSamples = 0;
2738 
2739         currentPositionDriftMeters = 0.0;
2740         currentVelocityDriftMetersPerSecond = 0.0;
2741         currentOrientationDriftRadians = 0.0;
2742 
2743         if (listener != null) {
2744             listener.onReset(this);
2745         }
2746 
2747         running = false;
2748     }
2749 
2750     /**
2751      * Gets the number of samples that have been processed so far.
2752      *
2753      * @return number of samples that have been processed so far.
2754      */
2755     public int getNumberOfProcessedSamples() {
2756         return numberOfProcessedSamples;
2757     }
2758 
2759     /**
2760      * Gets elapsed time since the first processed measurement expressed in seconds.
2761      *
2762      * @return elapsed time.
2763      */
2764     public double getElapsedTimeSeconds() {
2765         return numberOfProcessedSamples * timeInterval;
2766     }
2767 
2768     /**
2769      * Gets elapsed time since the first processed measurement.
2770      *
2771      * @return elapsed time.
2772      */
2773     public Time getElapsedTime() {
2774         return numberOfProcessedSamples > 0 ? new Time(getElapsedTimeSeconds(), TimeUnit.SECOND) : null;
2775     }
2776 
2777     /**
2778      * Gets elapsed time since the first processed measurement.
2779      *
2780      * @param result instance where the result will be stored.
2781      * @return true if elapsed time is available and the result is updated,
2782      * false otherwise.
2783      */
2784     public boolean getElapsedTime(final Time result) {
2785         if (numberOfProcessedSamples > 0) {
2786             result.setValue(getElapsedTimeSeconds());
2787             result.setUnit(TimeUnit.SECOND);
2788             return true;
2789         } else {
2790             return false;
2791         }
2792     }
2793 
2794     /**
2795      * Gets current position drift for last processed body kinematics
2796      * measurement expressed in meters (m) respect ECEF coordinates.
2797      *
2798      * @return current position drift or null.
2799      */
2800     public ECEFPosition getCurrentPositionDrift() {
2801         return numberOfProcessedSamples > 0 ? new ECEFPosition(currentPositionDrift) : null;
2802     }
2803 
2804     /**
2805      * Gets current position drift for last processed body kinematics
2806      * measurement expressed in meters (m) respect ECEF coordinates.
2807      *
2808      * @param result instance where the result will be stored.
2809      * @return true if the current position drift is available and the result is updated,
2810      * false otherwise.
2811      */
2812     public boolean getCurrentPositionDrift(final ECEFPosition result) {
2813         if (numberOfProcessedSamples > 0) {
2814             result.copyFrom(currentPositionDrift);
2815             return true;
2816         } else {
2817             return false;
2818         }
2819     }
2820 
2821     /**
2822      * Gets current velocity drift for the last processed body kinematics
2823      * measurement expressed in meters per second (m/s) respect ECEF coordinates.
2824      *
2825      * @return current velocity drift or null.
2826      */
2827     public ECEFVelocity getCurrentVelocityDrift() {
2828         return numberOfProcessedSamples > 0 ? new ECEFVelocity(currentVelocityDrift) : null;
2829     }
2830 
2831     /**
2832      * Gets current velocity drift for the last processed body kinematics
2833      * measurement expressed in meters per second (m/s) respect ECEF coordinates.
2834      *
2835      * @param result instance where the result will be stored.
2836      * @return true if the current velocity drift is available and the result is updated,
2837      * false otherwise.
2838      */
2839     public boolean getCurrentVelocityDrift(final ECEFVelocity result) {
2840         if (numberOfProcessedSamples > 0) {
2841             result.copyFrom(currentVelocityDrift);
2842             return true;
2843         } else {
2844             return false;
2845         }
2846     }
2847 
2848     /**
2849      * Gets current orientation drift as a 3D rotation for the last processed body
2850      * kinematics measurement respect ECEF coordinates.
2851      *
2852      * @return current orientation drift or null.
2853      */
2854     public Rotation3D getCurrentOrientationDrift() {
2855         return numberOfProcessedSamples > 0 ? new Quaternion(q) : null;
2856     }
2857 
2858     /**
2859      * Gets current orientation drift as a 3D rotation for the last processed body
2860      * kinematics measurement respect ECEF coordinates.
2861      *
2862      * @param result instance where the result will be stored.
2863      * @return true if the current orientation drift is available and the result is
2864      * updated, false otherwise.
2865      */
2866     public boolean getCurrentOrientationDrift(final Rotation3D result) {
2867         if (numberOfProcessedSamples > 0) {
2868             result.fromRotation(q);
2869             return true;
2870         } else {
2871             return false;
2872         }
2873     }
2874 
2875     /**
2876      * Gets current amount of position drift for last processed body kinematics
2877      * measurement expressed in meters (m).
2878      *
2879      * @return the current amount of position drift or null.
2880      */
2881     public Double getCurrentPositionDriftNormMeters() {
2882         return numberOfProcessedSamples > 0 ? currentPositionDriftMeters : null;
2883     }
2884 
2885     /**
2886      * Gets current amount of position drift for last processed body kinematics
2887      * measurement.
2888      *
2889      * @return the current amount of position drift or null.
2890      */
2891     public Distance getCurrentPositionDriftNorm() {
2892         final var positionDrift = getCurrentPositionDriftNormMeters();
2893         return positionDrift != null ? new Distance(positionDrift, DistanceUnit.METER) : null;
2894     }
2895 
2896     /**
2897      * Gets current amount of position drift for last processed body kinematics
2898      * measurement.
2899      *
2900      * @param result instance where the result will be stored.
2901      * @return true if the current position drift is available and the result is updated,
2902      * false otherwise.
2903      */
2904     public boolean getCurrentPositionDriftNorm(final Distance result) {
2905         final var positionDrift = getCurrentPositionDriftNormMeters();
2906         if (positionDrift != null) {
2907             result.setValue(positionDrift);
2908             result.setUnit(DistanceUnit.METER);
2909             return true;
2910         } else {
2911             return false;
2912         }
2913     }
2914 
2915     /**
2916      * Gets current amount of velocity drift for the last processed body kinematics
2917      * measurement expressed in meters per second (m/s).
2918      *
2919      * @return current amount of velocity drift or null.
2920      */
2921     public Double getCurrentVelocityDriftNormMetersPerSecond() {
2922         return numberOfProcessedSamples > 0 ? currentVelocityDriftMetersPerSecond : null;
2923     }
2924 
2925     /**
2926      * Gets current amount of velocity drift for last processed body kinematics
2927      * measurement.
2928      *
2929      * @return current amount of velocity drift or null.
2930      */
2931     public Speed getCurrentVelocityDriftNorm() {
2932         final var velocityDrift = getCurrentVelocityDriftNormMetersPerSecond();
2933         return velocityDrift != null ? new Speed(velocityDrift, SpeedUnit.METERS_PER_SECOND) : null;
2934     }
2935 
2936     /**
2937      * Gets current amount of velocity drift for last processed body kinematics
2938      * measurement.
2939      *
2940      * @param result instance where the result will be stored.
2941      * @return true if the current velocity drift is available and the result is updated,
2942      * false otherwise.
2943      */
2944     public boolean getCurrentVelocityDriftNorm(final Speed result) {
2945         final var velocityDrift = getCurrentVelocityDriftNormMetersPerSecond();
2946         if (velocityDrift != null) {
2947             result.setValue(velocityDrift);
2948             result.setUnit(SpeedUnit.METERS_PER_SECOND);
2949             return true;
2950         } else {
2951             return false;
2952         }
2953     }
2954 
2955     /**
2956      * Gets current amount of orientation drift for last processed body kinematics
2957      * measurement expressed in radians (rad).
2958      *
2959      * @return current amount of orientation drift or null.
2960      */
2961     public Double getCurrentOrientationDriftRadians() {
2962         return numberOfProcessedSamples > 0 ? currentOrientationDriftRadians : null;
2963     }
2964 
2965     /**
2966      * Gets current amount of orientation drift for last processed body kinematics
2967      * measurement.
2968      *
2969      * @return current amount of orientation drift or null.
2970      */
2971     public Angle getCurrentOrientationDriftAngle() {
2972         final var orientationDrift = getCurrentOrientationDriftRadians();
2973         return orientationDrift != null ? new Angle(orientationDrift, AngleUnit.RADIANS) : null;
2974     }
2975 
2976     /**
2977      * Gets current amount of orientation drift for last processed body kinematics
2978      * measurement.
2979      *
2980      * @param result instance where the result will be stored.
2981      * @return true if the current orientation drift is available and the result is
2982      * updated, false otherwise.
2983      */
2984     public boolean getCurrentOrientationDriftAngle(final Angle result) {
2985         final var orientationDrift = getCurrentOrientationDriftRadians();
2986         if (orientationDrift != null) {
2987             result.setValue(orientationDrift);
2988             result.setUnit(AngleUnit.RADIANS);
2989             return true;
2990         } else {
2991             return false;
2992         }
2993     }
2994 
2995     /**
2996      * Gets the current amount of position drift per time unit expressed in meters
2997      * per second (m/s).
2998      *
2999      * @return current amount of position drift per time unit or null.
3000      */
3001     public Double getCurrentPositionDriftPerTimeUnit() {
3002         final var positionDrift = getCurrentPositionDriftNormMeters();
3003         final var elapsedTime = getElapsedTimeSeconds();
3004         return positionDrift != null ? positionDrift / elapsedTime : null;
3005     }
3006 
3007     /**
3008      * Gets the current amount of position drift per time unit.
3009      *
3010      * @return current amount of position drift per time unit or null.
3011      */
3012     public Speed getCurrentPositionDriftPerTimeUnitAsSpeed() {
3013         final var positionDriftPerTimeUnit = getCurrentPositionDriftPerTimeUnit();
3014         return positionDriftPerTimeUnit != null ? new Speed(positionDriftPerTimeUnit, SpeedUnit.METERS_PER_SECOND)
3015                 : null;
3016     }
3017 
3018     /**
3019      * Gets the current amount of position drift per time unit.
3020      *
3021      * @param result instance where the result will be stored.
3022      * @return true if the current amount of position drift per time unit is
3023      * available and the result is updated, false otherwise.
3024      */
3025     public boolean getCurrentPositionDriftPerTimeUnitAsSpeed(final Speed result) {
3026         final var positionDriftPerTimeUnit = getCurrentPositionDriftPerTimeUnit();
3027         if (positionDriftPerTimeUnit != null) {
3028             result.setValue(positionDriftPerTimeUnit);
3029             result.setUnit(SpeedUnit.METERS_PER_SECOND);
3030             return true;
3031         } else {
3032             return false;
3033         }
3034     }
3035 
3036     /**
3037      * Gets the current amount of velocity drift per time unit expressed in meters
3038      * per squared second (m/s^2).
3039      *
3040      * @return the current amount of velocity drift per time unit or null.
3041      */
3042     public Double getCurrentVelocityDriftPerTimeUnit() {
3043         final var velocityDrift = getCurrentVelocityDriftNormMetersPerSecond();
3044         final var elapsedTime = getElapsedTimeSeconds();
3045         return velocityDrift != null ? velocityDrift / elapsedTime : null;
3046     }
3047 
3048     /**
3049      * Gets the current amount of velocity drift per time unit.
3050      *
3051      * @return the current amount of velocity drift per time unit or null.
3052      */
3053     public Acceleration getCurrentVelocityDriftPerTimeUnitAsAcceleration() {
3054         final var velocityDriftPerTimeUnit = getCurrentVelocityDriftPerTimeUnit();
3055         return velocityDriftPerTimeUnit != null
3056                 ? new Acceleration(velocityDriftPerTimeUnit, AccelerationUnit.METERS_PER_SQUARED_SECOND) : null;
3057     }
3058 
3059     /**
3060      * Gets the current amount of velocity drift per time unit.
3061      *
3062      * @param result instance where the result will be stored.
3063      * @return true if the current amount of velocity drift per time unit is available
3064      * and the result is updated, false otherwise.
3065      */
3066     public boolean getCurrentVelocityDriftPerTimeUnitAsAcceleration(final Acceleration result) {
3067         final var velocityDriftPerTimeUnit = getCurrentVelocityDriftPerTimeUnit();
3068         if (velocityDriftPerTimeUnit != null) {
3069             result.setValue(velocityDriftPerTimeUnit);
3070             result.setUnit(AccelerationUnit.METERS_PER_SQUARED_SECOND);
3071             return true;
3072         } else {
3073             return false;
3074         }
3075     }
3076 
3077     /**
3078      * Gets the current amount of orientation drift per time unit expressed in radians
3079      * per second (rad/s).
3080      *
3081      * @return amount of orientation drift per time unit or null.
3082      */
3083     public Double getCurrentOrientationDriftPerTimeUnit() {
3084         final var orientationDrift = getCurrentOrientationDriftRadians();
3085         final var elapsedTime = getElapsedTimeSeconds();
3086         return orientationDrift != null ? orientationDrift / elapsedTime : null;
3087     }
3088 
3089     /**
3090      * Gets the current amount of orientation drift per time unit.
3091      *
3092      * @return amount of orientation drift per time unit or null.
3093      */
3094     public AngularSpeed getCurrentOrientationDriftPerTimeUnitAsAngularSpeed() {
3095         final var orientationDriftPerTimeUnit = getCurrentOrientationDriftPerTimeUnit();
3096         return orientationDriftPerTimeUnit != null ?
3097                 new AngularSpeed(orientationDriftPerTimeUnit, AngularSpeedUnit.RADIANS_PER_SECOND) : null;
3098     }
3099 
3100     /**
3101      * Gets the current amount of orientation drift per time unit.
3102      *
3103      * @param result instance where the result will be stored.
3104      * @return true if the current amount of orientation drift is available and the result
3105      * is updated, false otherwise.
3106      */
3107     public boolean getCurrentOrientationDriftPerTimeUnitAsAngularSpeed(final AngularSpeed result) {
3108         final var orientationDriftPerTimeUnit = getCurrentOrientationDriftPerTimeUnit();
3109         if (orientationDriftPerTimeUnit != null) {
3110             result.setValue(orientationDriftPerTimeUnit);
3111             result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
3112             return true;
3113         } else {
3114             return false;
3115         }
3116     }
3117 
3118     /**
3119      * Computes current position drift.
3120      */
3121     protected void computeCurrentPositionDrift() {
3122         final var initX = referenceFrame.getX();
3123         final var initY = referenceFrame.getY();
3124         final var initZ = referenceFrame.getZ();
3125 
3126         final var currentX = frame.getX();
3127         final var currentY = frame.getY();
3128         final var currentZ = frame.getZ();
3129 
3130         final var diffX = currentX - initX;
3131         final var diffY = currentY - initY;
3132         final var diffZ = currentZ - initZ;
3133 
3134         currentPositionDrift.setCoordinates(diffX, diffY, diffZ);
3135 
3136         currentPositionDriftMeters = currentPositionDrift.getNorm();
3137     }
3138 
3139     /**
3140      * Computes current velocity drift.
3141      */
3142     protected void computeCurrentVelocityDrift() {
3143         final var initVx = referenceFrame.getVx();
3144         final var initVy = referenceFrame.getVy();
3145         final var initVz = referenceFrame.getVz();
3146 
3147         final var currentVx = frame.getVx();
3148         final var currentVy = frame.getVy();
3149         final var currentVz = frame.getVz();
3150 
3151         final var diffVx = currentVx - initVx;
3152         final var diffVy = currentVy - initVy;
3153         final var diffVz = currentVz - initVz;
3154 
3155         currentVelocityDrift.setCoordinates(diffVx, diffVy, diffVz);
3156 
3157         currentVelocityDriftMetersPerSecond = currentVelocityDrift.getNorm();
3158     }
3159 
3160     /**
3161      * Computes current orientation drift.
3162      *
3163      * @throws AlgebraException               if there are numerical instabilities.
3164      * @throws InvalidRotationMatrixException if rotation cannot be accurately
3165      *                                        estimated.
3166      */
3167     protected void computeCurrentOrientationDrift() throws AlgebraException, InvalidRotationMatrixException {
3168         if (currentC == null) {
3169             currentC = new Matrix(Rotation3D.INHOM_COORDS, Rotation3D.INHOM_COORDS);
3170         }
3171         frame.getCoordinateTransformationMatrix(currentC);
3172 
3173         q.fromMatrix(currentC);
3174         q.combine(invRefQ);
3175 
3176         currentOrientationDriftRadians = q.getRotationAngle();
3177     }
3178 
3179     /**
3180      * Converts the provided time instance to seconds.
3181      *
3182      * @param time instance to be converted.
3183      * @return conversion in seconds.
3184      */
3185     private static double convertTime(final Time time) {
3186         return TimeConverter.convert(time.getValue().doubleValue(), time.getUnit(), TimeUnit.SECOND);
3187     }
3188 }