View Javadoc
1   /*
2    * Copyright (C) 2020 Alberto Irurueta Carro (alberto@irurueta.com)
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.irurueta.navigation.inertial.calibration.gyroscope;
17  
18  import com.irurueta.algebra.AlgebraException;
19  import com.irurueta.algebra.Matrix;
20  import com.irurueta.algebra.WrongSizeException;
21  import com.irurueta.navigation.LockedException;
22  import com.irurueta.navigation.NotReadyException;
23  import com.irurueta.navigation.inertial.BodyKinematics;
24  import com.irurueta.navigation.inertial.INSLooselyCoupledKalmanInitializerConfig;
25  import com.irurueta.navigation.inertial.INSTightlyCoupledKalmanInitializerConfig;
26  import com.irurueta.navigation.inertial.calibration.AngularSpeedTriad;
27  import com.irurueta.navigation.inertial.calibration.CalibrationException;
28  import com.irurueta.navigation.inertial.calibration.GyroscopeBiasUncertaintySource;
29  import com.irurueta.navigation.inertial.calibration.GyroscopeCalibrationSource;
30  import com.irurueta.navigation.inertial.calibration.StandardDeviationFrameBodyKinematics;
31  import com.irurueta.navigation.inertial.estimators.ECEFKinematicsEstimator;
32  import com.irurueta.numerical.fitting.FittingException;
33  import com.irurueta.numerical.fitting.LevenbergMarquardtMultiVariateFitter;
34  import com.irurueta.numerical.fitting.LevenbergMarquardtMultiVariateFunctionEvaluator;
35  import com.irurueta.statistics.MaxIterationsExceededException;
36  import com.irurueta.units.AngularSpeed;
37  import com.irurueta.units.AngularSpeedConverter;
38  import com.irurueta.units.AngularSpeedUnit;
39  
40  import java.util.Collection;
41  
42  /**
43   * Estimates gyroscope biases, cross couplings and scaling factors
44   * along with G-dependent cross biases introduced on the gyroscope by the
45   * specific forces sensed by the accelerometer.
46   * <p>
47   * This calibrator uses an iterative approach to find a minimum least squared error
48   * solution.
49   * <p>
50   * To use this calibrator at least 7 measurements at different known frames must
51   * be provided. In other words, accelerometer and gyroscope (i.e. body kinematics)
52   * samples must be obtained at 7 different positions, orientations and velocities
53   * (although typically velocities are always zero).
54   * <p>
55   * Measured gyroscope angular rates is assumed to follow the model shown below:
56   * <pre>
57   *     Ωmeas = bg + (I + Mg) * Ωtrue + Gg * ftrue + w
58   * </pre>
59   * Where:
60   * - Ωmeas is the measured gyroscope angular rates. This is a 3x1 vector.
61   * - bg is the gyroscope bias. Ideally, on a perfect gyroscope, this should be a
62   * 3x1 zero vector.
63   * - I is the 3x3 identity matrix.
64   * - Mg is the 3x3 matrix containing cross-couplings and scaling factors. Ideally, on
65   * a perfect gyroscope, this should be a 3x3 zero matrix.
66   * - Ωtrue is ground-truth gyroscope angular rates.
67   * - Gg is the G-dependent cross biases introduced by the specific forces sensed
68   * by the accelerometer. Ideally, on a perfect gyroscope, this should be a 3x3
69   * zero matrix.
70   * - ftrue is ground-truth specific force. This is a 3x1 vector.
71   * - w is measurement noise. This is a 3x1 vector.
72   */
73  public class KnownFrameGyroscopeNonLinearLeastSquaresCalibrator implements
74          KnownFrameGyroscopeCalibrator<StandardDeviationFrameBodyKinematics,
75                  KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener>, GyroscopeNonLinearCalibrator,
76          UnknownBiasNonLinearGyroscopeCalibrator, GyroscopeCalibrationSource, GyroscopeBiasUncertaintySource,
77          UnorderedStandardDeviationFrameBodyKinematicsGyroscopeCalibrator {
78  
79      /**
80       * Indicates whether by default a common z-axis is assumed for both the accelerometer
81       * and gyroscope.
82       */
83      public static final boolean DEFAULT_USE_COMMON_Z_AXIS = false;
84  
85      /**
86       * Required minimum number of measurements.
87       */
88      public static final int MINIMUM_MEASUREMENTS = 7;
89  
90      /**
91       * Number of unknowns when common z-axis is assumed for both the accelerometer
92       * and gyroscope.
93       */
94      private static final int COMMON_Z_AXIS_UNKNOWNS = 18;
95  
96      /**
97       * Number of unknowns for the general case.
98       */
99      private static final int GENERAL_UNKNOWNS = 21;
100 
101     /**
102      * Levenberg-Marquardt fitter to find a non-linear solution.
103      */
104     private final LevenbergMarquardtMultiVariateFitter fitter = new LevenbergMarquardtMultiVariateFitter();
105 
106     /**
107      * Initial x-coordinate of gyroscope bias to be used to find a solution.
108      * This is expressed in radians per second (rad/s).
109      */
110     private double initialBiasX;
111 
112     /**
113      * Initial y-coordinate of gyroscope bias to be used to find a solution.
114      * This is expressed in radians per second (rad/s).
115      */
116     private double initialBiasY;
117 
118     /**
119      * Initial z-coordinate of gyroscope bias to be used to find a solution.
120      * This is expressed in radians per second (rad/s).
121      */
122     private double initialBiasZ;
123 
124     /**
125      * Initial x scaling factor.
126      */
127     private double initialSx;
128 
129     /**
130      * Initial y scaling factor.
131      */
132     private double initialSy;
133 
134     /**
135      * Initial z scaling factor.
136      */
137     private double initialSz;
138 
139     /**
140      * Initial x-y cross coupling error.
141      */
142     private double initialMxy;
143 
144     /**
145      * Initial x-z cross coupling error.
146      */
147     private double initialMxz;
148 
149     /**
150      * Initial y-x cross coupling error.
151      */
152     private double initialMyx;
153 
154     /**
155      * Initial y-z cross coupling error.
156      */
157     private double initialMyz;
158 
159     /**
160      * Initial z-x cross coupling error.
161      */
162     private double initialMzx;
163 
164     /**
165      * Initial z-y cross coupling error.
166      */
167     private double initialMzy;
168 
169     /**
170      * Initial G-dependent cross biases introduced on the gyroscope by the
171      * specific forces sensed by the accelerometer.
172      */
173     private Matrix initialGg;
174 
175     /**
176      * Contains a collections of body kinematics measurements taken at different
177      * frames (positions, orientations and velocities) and containing the standard
178      * deviations of accelerometer and gyroscope measurements.
179      * If a single device IMU needs to be calibrated, typically all measurements are
180      * taken at the same position, with zero velocity and multiple orientations.
181      * However, if we just want to calibrate a given IMU model (e.g. obtain
182      * an average and less precise calibration for the IMU of a given phone model),
183      * we could take measurements collected throughout the planet at multiple positions
184      * while the phone remains static (e.g. while charging), hence each measurement
185      * position will change, velocity will remain zero and orientation will be
186      * typically constant at horizontal orientation while the phone remains on a
187      * flat surface.
188      */
189     private Collection<StandardDeviationFrameBodyKinematics> measurements;
190 
191     /**
192      * This flag indicates whether z-axis is assumed to be common for accelerometer
193      * and gyroscope.
194      * When enabled, this eliminates 3 variables from Ma matrix.
195      */
196     private boolean commonAxisUsed = DEFAULT_USE_COMMON_Z_AXIS;
197 
198     /**
199      * Listener to handle events raised by this calibrator.
200      */
201     private KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener;
202 
203     /**
204      * Estimated angular rate biases for each IMU axis expressed in radians per
205      * second (rad/s).
206      */
207     private double[] estimatedBiases;
208 
209     /**
210      * Estimated gyroscope scale factors and cross coupling errors.
211      * This is the product of matrix Tg containing cross coupling errors and Kg
212      * containing scaling factors.
213      * So that:
214      * <pre>
215      *     Mg = [sx    mxy  mxz] = Tg*Kg
216      *          [myx   sy   myz]
217      *          [mzx   mzy  sz ]
218      * </pre>
219      * Where:
220      * <pre>
221      *     Kg = [sx 0   0 ]
222      *          [0  sy  0 ]
223      *          [0  0   sz]
224      * </pre>
225      * and
226      * <pre>
227      *     Tg = [1          -alphaXy    alphaXz ]
228      *          [alphaYx    1           -alphaYz]
229      *          [-alphaZx   alphaZy     1       ]
230      * </pre>
231      * Hence:
232      * <pre>
233      *     Mg = [sx    mxy  mxz] = Tg*Kg =  [sx             -sy * alphaXy   sz * alphaXz ]
234      *          [myx   sy   myz]            [sx * alphaYx   sy              -sz * alphaYz]
235      *          [mzx   mzy  sz ]            [-sx * alphaZx  sy * alphaZy    sz           ]
236      * </pre>
237      * This instance allows any 3x3 matrix however, typically alphaYx, alphaZx and alphaZy
238      * are considered to be zero if the gyroscope z-axis is assumed to be the same
239      * as the body z-axis. When this is assumed, myx = mzx = mzy = 0 and the Mg matrix
240      * becomes upper diagonal:
241      * <pre>
242      *     Mg = [sx    mxy  mxz]
243      *          [0     sy   myz]
244      *          [0     0    sz ]
245      * </pre>
246      * Values of this matrix are unit-less.
247      */
248     private Matrix estimatedMg;
249 
250     /**
251      * Estimated G-dependent cross biases introduced on the gyroscope by the
252      * specific forces sensed by the accelerometer.
253      * This instance allows any 3x3 matrix.
254      */
255     private Matrix estimatedGg;
256 
257     /**
258      * Estimated covariance matrix for estimated parameters.
259      */
260     private Matrix estimatedCovariance;
261 
262     /**
263      * Estimated chi square value.
264      */
265     private double estimatedChiSq;
266 
267     /**
268      * Estimated degrees of freedom of chi square value. Degrees of freedom is equal to the number of sampled data
269      * minus the number of estimated parameters.
270      */
271     private int estimatedChiSqDegreesOfFreedom;
272 
273     /**
274      * Estimated reduced chi square value. This is equal to estimated chi square value divided by its degrees of
275      * freedom. Ideally this value should be close to 1.0.
276      */
277     private double estimatedReducedChiSq;
278 
279     /**
280      * Estimated mean square error respect to provided measurements.
281      */
282     private double estimatedMse;
283 
284     /**
285      * Estimated probability of finding a smaller chi square value expressed as a value between 0.0 and 1.0. The smaller
286      * the found chi square value is, the better the fit of the estimated parameters to the actual parameter. Thus, the
287      * smaller the chance of finding a smaller chi square value, then the better the estimated fit is.
288      */
289     private double estimatedP;
290 
291     /**
292      * Estimated measure of quality of estimated fit as a value between 0.0 and 1.0. The larger the quality value is,
293      * the better the fit that has been estimated.
294      */
295     private double estimatedQ;
296 
297     /**
298      * Indicates whether calibrator is running.
299      */
300     private boolean running;
301 
302     /**
303      * Constructor.
304      */
305     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator() {
306         try {
307             initialGg = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
308         } catch (final WrongSizeException ignore) {
309             // never happens
310         }
311     }
312 
313     /**
314      * Constructor.
315      *
316      * @param listener listener to handle events raised by this calibrator.
317      */
318     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
319             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
320         this();
321         this.listener = listener;
322     }
323 
324     /**
325      * Constructor.
326      *
327      * @param measurements collection of body kinematics measurements with standard
328      *                     deviations taken at different frames (positions, orientations
329      *                     and velocities).
330      */
331     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
332             final Collection<StandardDeviationFrameBodyKinematics> measurements) {
333         this();
334         this.measurements = measurements;
335     }
336 
337     /**
338      * Constructor.
339      *
340      * @param measurements collection of body kinematics measurements with standard
341      *                     deviations taken at different frames (positions, orientations
342      *                     and velocities).
343      * @param listener     listener to handle events raised by this calibrator.
344      */
345     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
346             final Collection<StandardDeviationFrameBodyKinematics> measurements,
347             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
348         this(measurements);
349         this.listener = listener;
350     }
351 
352     /**
353      * Constructor.
354      *
355      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
356      *                       accelerometer and gyroscope.
357      */
358     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(final boolean commonAxisUsed) {
359         this();
360         this.commonAxisUsed = commonAxisUsed;
361     }
362 
363     /**
364      * Constructor.
365      *
366      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
367      *                       accelerometer and gyroscope.
368      * @param listener       listener to handle events raised by this calibrator.
369      */
370     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
371             final boolean commonAxisUsed, final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
372         this(commonAxisUsed);
373         this.listener = listener;
374     }
375 
376     /**
377      * Constructor.
378      *
379      * @param measurements   collection of body kinematics measurements with standard
380      *                       deviations taken at different frames (positions, orientations
381      *                       and velocities).
382      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
383      *                       accelerometer and gyroscope.
384      */
385     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
386             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed) {
387         this(measurements);
388         this.commonAxisUsed = commonAxisUsed;
389     }
390 
391     /**
392      * Constructor.
393      *
394      * @param measurements   collection of body kinematics measurements with standard
395      *                       deviations taken at different frames (positions, orientations
396      *                       and velocities).
397      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
398      *                       accelerometer and gyroscope.
399      * @param listener       listener to handle events raised by this calibrator.
400      */
401     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
402             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
403             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
404         this(measurements, commonAxisUsed);
405         this.listener = listener;
406     }
407 
408     /**
409      * Constructor.
410      *
411      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
412      *                     to find a solution. This is expressed in radians per second
413      *                     (rad/s).
414      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
415      *                     to find a solution. This is expressed in radians per second
416      *                     (rad/s).
417      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
418      *                     to find a solution. This is expressed in radians per second
419      *                     (rad/s).
420      */
421     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
422             final double initialBiasX, final double initialBiasY, final double initialBiasZ) {
423         this();
424         try {
425             setInitialBias(initialBiasX, initialBiasY, initialBiasZ);
426         } catch (final LockedException ignore) {
427             // never happens
428         }
429     }
430 
431     /**
432      * Constructor.
433      *
434      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
435      *                     to find a solution. This is expressed in radians per second
436      *                     (rad/s).
437      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
438      *                     to find a solution. This is expressed in radians per second
439      *                     (rad/s).
440      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
441      *                     to find a solution. This is expressed in radians per second
442      *                     (rad/s).
443      * @param listener     listener to handle events raised by this calibrator.
444      */
445     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
446             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
447             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
448         this(initialBiasX, initialBiasY, initialBiasZ);
449         this.listener = listener;
450     }
451 
452     /**
453      * Constructor.
454      *
455      * @param measurements collection of body kinematics measurements with standard
456      *                     deviations taken at different frames (positions, orientations
457      *                     and velocities).
458      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
459      *                     to find a solution. This is expressed in radians per second
460      *                     (rad/s).
461      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
462      *                     to find a solution. This is expressed in radians per second
463      *                     (rad/s).
464      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
465      *                     to find a solution. This is expressed in radians per second
466      *                     (rad/s).
467      */
468     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
469             final Collection<StandardDeviationFrameBodyKinematics> measurements,
470             final double initialBiasX, final double initialBiasY, final double initialBiasZ) {
471         this(initialBiasX, initialBiasY, initialBiasZ);
472         this.measurements = measurements;
473     }
474 
475     /**
476      * Constructor.
477      *
478      * @param measurements collection of body kinematics measurements with standard
479      *                     deviations taken at different frames (positions, orientations
480      *                     and velocities).
481      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
482      *                     to find a solution. This is expressed in radians per second
483      *                     (rad/s).
484      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
485      *                     to find a solution. This is expressed in radians per second
486      *                     (rad/s).
487      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
488      *                     to find a solution. This is expressed in radians per second
489      *                     (rad/s).
490      * @param listener     listener to handle events raised by this calibrator.
491      */
492     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
493             final Collection<StandardDeviationFrameBodyKinematics> measurements,
494             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
495             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
496         this(measurements, initialBiasX, initialBiasY, initialBiasZ);
497         this.listener = listener;
498     }
499 
500     /**
501      * Constructor.
502      *
503      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
504      *                       accelerometer and gyroscope.
505      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
506      *                       to find a solution. This is expressed in radians per second
507      *                       (rad/s).
508      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
509      *                       to find a solution. This is expressed in radians per second
510      *                       (rad/s).
511      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
512      *                       to find a solution. This is expressed in radians per second
513      *                       (rad/s).
514      */
515     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
516             final boolean commonAxisUsed, final double initialBiasX, final double initialBiasY,
517             final double initialBiasZ) {
518         this(initialBiasX, initialBiasY, initialBiasZ);
519         this.commonAxisUsed = commonAxisUsed;
520     }
521 
522     /**
523      * Constructor.
524      *
525      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
526      *                       accelerometer and gyroscope.
527      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
528      *                       to find a solution. This is expressed in radians per second
529      *                       (rad/s).
530      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
531      *                       to find a solution. This is expressed in radians per second
532      *                       (rad/s).
533      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
534      *                       to find a solution. This is expressed in radians per second
535      *                       (rad/s).
536      * @param listener       listener to handle events raised by this calibrator.
537      */
538     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
539             final boolean commonAxisUsed,
540             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
541             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
542         this(commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ);
543         this.listener = listener;
544     }
545 
546     /**
547      * Constructor.
548      *
549      * @param measurements   collection of body kinematics measurements with standard
550      *                       deviations taken at different frames (positions, orientations
551      *                       and velocities).
552      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
553      *                       accelerometer and gyroscope.
554      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
555      *                       to find a solution. This is expressed in radians per second
556      *                       (rad/s).
557      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
558      *                       to find a solution. This is expressed in radians per second
559      *                       (rad/s).
560      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
561      *                       to find a solution. This is expressed in radians per second
562      *                       (rad/s).
563      */
564     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
565             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
566             final double initialBiasX, final double initialBiasY, final double initialBiasZ) {
567         this(commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ);
568         this.measurements = measurements;
569     }
570 
571     /**
572      * Constructor.
573      *
574      * @param measurements   collection of body kinematics measurements with standard
575      *                       deviations taken at different frames (positions, orientations
576      *                       and velocities).
577      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
578      *                       accelerometer and gyroscope.
579      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
580      *                       to find a solution. This is expressed in radians per second
581      *                       (rad/s).
582      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
583      *                       to find a solution. This is expressed in radians per second
584      *                       (rad/s).
585      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
586      *                       to find a solution. This is expressed in radians per second
587      *                       (rad/s).
588      * @param listener       listener to handle events raised by this calibrator.
589      */
590     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
591             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
592             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
593             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
594         this(measurements, commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ);
595         this.listener = listener;
596     }
597 
598     /**
599      * Constructor.
600      *
601      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
602      *                     to find a solution.
603      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
604      *                     to find a solution.
605      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
606      *                     to find a solution.
607      */
608     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
609             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ) {
610         this();
611         try {
612             setInitialBias(initialBiasX, initialBiasY, initialBiasZ);
613         } catch (final LockedException ignore) {
614             // never happens
615         }
616     }
617 
618     /**
619      * Constructor.
620      *
621      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
622      *                     to find a solution.
623      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
624      *                     to find a solution.
625      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
626      *                     to find a solution.
627      * @param listener     listener to handle events raised by this calibrator.
628      */
629     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
630             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
631             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
632         this(initialBiasX, initialBiasY, initialBiasZ);
633         this.listener = listener;
634     }
635 
636     /**
637      * Constructor.
638      *
639      * @param measurements collection of body kinematics measurements with standard
640      *                     deviations taken at different frames (positions, orientations
641      *                     and velocities).
642      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
643      *                     to find a solution.
644      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
645      *                     to find a solution.
646      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
647      *                     to find a solution.
648      */
649     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
650             final Collection<StandardDeviationFrameBodyKinematics> measurements,
651             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ) {
652         this(initialBiasX, initialBiasY, initialBiasZ);
653         this.measurements = measurements;
654     }
655 
656     /**
657      * Constructor.
658      *
659      * @param measurements collection of body kinematics measurements with standard
660      *                     deviations taken at different frames (positions, orientations
661      *                     and velocities).
662      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
663      *                     to find a solution.
664      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
665      *                     to find a solution.
666      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
667      *                     to find a solution.
668      * @param listener     listener to handle events raised by this calibrator.
669      */
670     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
671             final Collection<StandardDeviationFrameBodyKinematics> measurements,
672             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
673             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
674         this(measurements, initialBiasX, initialBiasY, initialBiasZ);
675         this.listener = listener;
676     }
677 
678     /**
679      * Constructor.
680      *
681      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
682      *                       accelerometer and gyroscope.
683      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
684      *                       to find a solution.
685      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
686      *                       to find a solution.
687      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
688      *                       to find a solution.
689      */
690     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
691             final boolean commonAxisUsed, final AngularSpeed initialBiasX, final AngularSpeed initialBiasY,
692             final AngularSpeed initialBiasZ) {
693         this(initialBiasX, initialBiasY, initialBiasZ);
694         this.commonAxisUsed = commonAxisUsed;
695     }
696 
697     /**
698      * Constructor.
699      *
700      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
701      *                       accelerometer and gyroscope.
702      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
703      *                       to find a solution.
704      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
705      *                       to find a solution.
706      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
707      *                       to find a solution.
708      * @param listener       listener to handle events raised by this calibrator.
709      */
710     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
711             final boolean commonAxisUsed,
712             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
713             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
714         this(commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ);
715         this.listener = listener;
716     }
717 
718     /**
719      * Constructor.
720      *
721      * @param measurements   collection of body kinematics measurements with standard
722      *                       deviations taken at different frames (positions, orientations
723      *                       and velocities).
724      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
725      *                       accelerometer and gyroscope.
726      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
727      *                       to find a solution.
728      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
729      *                       to find a solution.
730      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
731      *                       to find a solution.
732      */
733     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
734             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
735             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ) {
736         this(commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ);
737         this.measurements = measurements;
738     }
739 
740     /**
741      * Constructor.
742      *
743      * @param measurements   collection of body kinematics measurements with standard
744      *                       deviations taken at different frames (positions, orientations
745      *                       and velocities).
746      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
747      *                       accelerometer and gyroscope.
748      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
749      *                       to find a solution.
750      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
751      *                       to find a solution.
752      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
753      *                       to find a solution.
754      * @param listener       listener to handle events raised by this calibrator.
755      */
756     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
757             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
758             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
759             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
760         this(measurements, commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ);
761         this.listener = listener;
762     }
763 
764     /**
765      * Constructor.
766      *
767      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
768      *                     to find a solution. This is expressed in radians per
769      *                     second (rad/s).
770      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
771      *                     to find a solution. This is expressed in radians per
772      *                     second (rad/s).
773      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
774      *                     to find a solution. This is expressed in radians per
775      *                     second (rad/s).
776      * @param initialSx    initial x scaling factor.
777      * @param initialSy    initial y scaling factor.
778      * @param initialSz    initial z scaling factor.
779      */
780     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
781             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
782             final double initialSx, final double initialSy, final double initialSz) {
783         this(initialBiasX, initialBiasY, initialBiasZ);
784         try {
785             setInitialScalingFactors(initialSx, initialSy, initialSz);
786         } catch (final LockedException ignore) {
787             // never happens
788         }
789     }
790 
791     /**
792      * Constructor.
793      *
794      * @param measurements collection of body kinematics measurements with standard
795      *                     deviations taken at different frames (positions, orientations
796      *                     and velocities).
797      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
798      *                     to find a solution. This is expressed in radians per
799      *                     second (rad/s).
800      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
801      *                     to find a solution. This is expressed in radians per
802      *                     second (rad/s).
803      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
804      *                     to find a solution. This is expressed in radians per
805      *                     second (rad/s).
806      * @param initialSx    initial x scaling factor.
807      * @param initialSy    initial y scaling factor.
808      * @param initialSz    initial z scaling factor.
809      */
810     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
811             final Collection<StandardDeviationFrameBodyKinematics> measurements,
812             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
813             final double initialSx, final double initialSy, final double initialSz) {
814         this(initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz);
815         this.measurements = measurements;
816     }
817 
818     /**
819      * Constructor.
820      *
821      * @param measurements collection of body kinematics measurements with standard
822      *                     deviations taken at different frames (positions, orientations
823      *                     and velocities).
824      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
825      *                     to find a solution. This is expressed in radians per
826      *                     second (rad/s).
827      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
828      *                     to find a solution. This is expressed in radians per
829      *                     second (rad/s).
830      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
831      *                     to find a solution. This is expressed in radians per
832      *                     second (rad/s).
833      * @param initialSx    initial x scaling factor.
834      * @param initialSy    initial y scaling factor.
835      * @param initialSz    initial z scaling factor.
836      * @param listener     listener to handle events raised by this calibrator.
837      */
838     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
839             final Collection<StandardDeviationFrameBodyKinematics> measurements,
840             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
841             final double initialSx, final double initialSy, final double initialSz,
842             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
843         this(measurements, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz);
844         this.listener = listener;
845     }
846 
847     /**
848      * Constructor.
849      *
850      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
851      *                       accelerometer and gyroscope.
852      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
853      *                       to find a solution. This is expressed in radians per
854      *                       second (rad/s).
855      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
856      *                       to find a solution. This is expressed in radians per
857      *                       second (rad/s).
858      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
859      *                       to find a solution. This is expressed in radians per
860      *                       second (rad/s).
861      * @param initialSx      initial x scaling factor.
862      * @param initialSy      initial y scaling factor.
863      * @param initialSz      initial z scaling factor.
864      */
865     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
866             final boolean commonAxisUsed,
867             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
868             final double initialSx, final double initialSy, final double initialSz) {
869         this(initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz);
870         this.commonAxisUsed = commonAxisUsed;
871     }
872 
873     /**
874      * Constructor.
875      *
876      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
877      *                       accelerometer and gyroscope.
878      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
879      *                       to find a solution. This is expressed in radians per
880      *                       second (rad/s).
881      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
882      *                       to find a solution. This is expressed in radians per
883      *                       second (rad/s).
884      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
885      *                       to find a solution. This is expressed in radians per
886      *                       second (rad/s).
887      * @param initialSx      initial x scaling factor.
888      * @param initialSy      initial y scaling factor.
889      * @param initialSz      initial z scaling factor.
890      * @param listener       listener to handle events raised by this calibrator.
891      */
892     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
893             final boolean commonAxisUsed,
894             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
895             final double initialSx, final double initialSy, final double initialSz,
896             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
897         this(commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz);
898         this.listener = listener;
899     }
900 
901     /**
902      * Constructor.
903      *
904      * @param measurements   collection of body kinematics measurements with standard
905      *                       deviations taken at different frames (positions, orientations
906      *                       and velocities).
907      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
908      *                       accelerometer and gyroscope.
909      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
910      *                       to find a solution. This is expressed in radians per
911      *                       second (rad/s).
912      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
913      *                       to find a solution. This is expressed in radians per
914      *                       second (rad/s).
915      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
916      *                       to find a solution. This is expressed in radians per
917      *                       second (rad/s).
918      * @param initialSx      initial x scaling factor.
919      * @param initialSy      initial y scaling factor.
920      * @param initialSz      initial z scaling factor.
921      */
922     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
923             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
924             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
925             final double initialSx, final double initialSy, final double initialSz) {
926         this(commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz);
927         this.measurements = measurements;
928     }
929 
930     /**
931      * Constructor.
932      *
933      * @param measurements   collection of body kinematics measurements with standard
934      *                       deviations taken at different frames (positions, orientations
935      *                       and velocities).
936      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
937      *                       accelerometer and gyroscope.
938      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
939      *                       to find a solution. This is expressed in radians per
940      *                       second (rad/s).
941      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
942      *                       to find a solution. This is expressed in radians per
943      *                       second (rad/s).
944      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
945      *                       to find a solution. This is expressed in radians per
946      *                       second (rad/s).
947      * @param initialSx      initial x scaling factor.
948      * @param initialSy      initial y scaling factor.
949      * @param initialSz      initial z scaling factor.
950      * @param listener       listener to handle events raised by this calibrator.
951      */
952     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
953             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
954             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
955             final double initialSx, final double initialSy, final double initialSz,
956             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
957         this(measurements, commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz);
958         this.listener = listener;
959     }
960 
961     /**
962      * Constructor.
963      *
964      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
965      *                     to find a solution.
966      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
967      *                     to find a solution.
968      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
969      *                     to find a solution.
970      * @param initialSx    initial x scaling factor.
971      * @param initialSy    initial y scaling factor.
972      * @param initialSz    initial z scaling factor.
973      */
974     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
975             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
976             final double initialSx, final double initialSy, final double initialSz) {
977         this(initialBiasX, initialBiasY, initialBiasZ);
978         try {
979             setInitialScalingFactors(initialSx, initialSy, initialSz);
980         } catch (final LockedException ignore) {
981             // never happens
982         }
983     }
984 
985     /**
986      * Constructor.
987      *
988      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
989      *                     to find a solution.
990      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
991      *                     to find a solution.
992      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
993      *                     to find a solution.
994      * @param initialSx    initial x scaling factor.
995      * @param initialSy    initial y scaling factor.
996      * @param initialSz    initial z scaling factor.
997      * @param listener     listener to handle events raised by this calibrator.
998      */
999     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1000             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
1001             final double initialSx, final double initialSy, final double initialSz,
1002             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1003         this(initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz);
1004         this.listener = listener;
1005     }
1006 
1007     /**
1008      * Constructor.
1009      *
1010      * @param measurements collection of body kinematics measurements with standard
1011      *                     deviations taken at different frames (positions, orientations
1012      *                     and velocities).
1013      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
1014      *                     to find a solution.
1015      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
1016      *                     to find a solution.
1017      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
1018      *                     to find a solution.
1019      * @param initialSx    initial x scaling factor.
1020      * @param initialSy    initial y scaling factor.
1021      * @param initialSz    initial z scaling factor.
1022      */
1023     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1024             final Collection<StandardDeviationFrameBodyKinematics> measurements,
1025             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
1026             final double initialSx, final double initialSy, final double initialSz) {
1027         this(initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz);
1028         this.measurements = measurements;
1029     }
1030 
1031     /**
1032      * Constructor.
1033      *
1034      * @param measurements collection of body kinematics measurements with standard
1035      *                     deviations taken at different frames (positions, orientations
1036      *                     and velocities).
1037      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
1038      *                     to find a solution.
1039      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
1040      *                     to find a solution.
1041      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
1042      *                     to find a solution.
1043      * @param initialSx    initial x scaling factor.
1044      * @param initialSy    initial y scaling factor.
1045      * @param initialSz    initial z scaling factor.
1046      * @param listener     listener to handle events raised by this calibrator.
1047      */
1048     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1049             final Collection<StandardDeviationFrameBodyKinematics> measurements,
1050             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
1051             final double initialSx, final double initialSy, final double initialSz,
1052             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1053         this(measurements, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz);
1054         this.listener = listener;
1055     }
1056 
1057     /**
1058      * Constructor.
1059      *
1060      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1061      *                       accelerometer and gyroscope.
1062      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
1063      *                       to find a solution.
1064      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
1065      *                       to find a solution.
1066      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
1067      *                       to find a solution.
1068      * @param initialSx      initial x scaling factor.
1069      * @param initialSy      initial y scaling factor.
1070      * @param initialSz      initial z scaling factor.
1071      */
1072     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1073             final boolean commonAxisUsed,
1074             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
1075             final double initialSx, final double initialSy, final double initialSz) {
1076         this(initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz);
1077         this.commonAxisUsed = commonAxisUsed;
1078     }
1079 
1080     /**
1081      * Constructor.
1082      *
1083      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1084      *                       accelerometer and gyroscope.
1085      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
1086      *                       to find a solution.
1087      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
1088      *                       to find a solution.
1089      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
1090      *                       to find a solution.
1091      * @param initialSx      initial x scaling factor.
1092      * @param initialSy      initial y scaling factor.
1093      * @param initialSz      initial z scaling factor.
1094      * @param listener       listener to handle events raised by this calibrator.
1095      */
1096     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1097             final boolean commonAxisUsed,
1098             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
1099             final double initialSx, final double initialSy, final double initialSz,
1100             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1101         this(commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz);
1102         this.listener = listener;
1103     }
1104 
1105     /**
1106      * Constructor.
1107      *
1108      * @param measurements   collection of body kinematics measurements with standard
1109      *                       deviations taken at different frames (positions, orientations
1110      *                       and velocities).
1111      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1112      *                       accelerometer and gyroscope.
1113      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
1114      *                       to find a solution.
1115      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
1116      *                       to find a solution.
1117      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
1118      *                       to find a solution.
1119      * @param initialSx      initial x scaling factor.
1120      * @param initialSy      initial y scaling factor.
1121      * @param initialSz      initial z scaling factor.
1122      */
1123     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1124             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
1125             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
1126             final double initialSx, final double initialSy, final double initialSz) {
1127         this(commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz);
1128         this.measurements = measurements;
1129     }
1130 
1131     /**
1132      * Constructor.
1133      *
1134      * @param measurements   collection of body kinematics measurements with standard
1135      *                       deviations taken at different frames (positions, orientations
1136      *                       and velocities).
1137      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1138      *                       accelerometer and gyroscope.
1139      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
1140      *                       to find a solution.
1141      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
1142      *                       to find a solution.
1143      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
1144      *                       to find a solution.
1145      * @param initialSx      initial x scaling factor.
1146      * @param initialSy      initial y scaling factor.
1147      * @param initialSz      initial z scaling factor.
1148      * @param listener       listeners to handle events raised by this calibrator.
1149      */
1150     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1151             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
1152             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
1153             final double initialSx, final double initialSy, final double initialSz,
1154             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1155         this(measurements, commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz);
1156         this.listener = listener;
1157     }
1158 
1159     /**
1160      * Constructor.
1161      *
1162      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
1163      *                     to find a solution. This is expressed in radians per
1164      *                     second (rad/s).
1165      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
1166      *                     to find a solution. This is expressed in radians per
1167      *                     second (rad/s).
1168      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
1169      *                     to find a solution. This is expressed in radians per
1170      *                     second (rad/s).
1171      * @param initialSx    initial x scaling factor.
1172      * @param initialSy    initial y scaling factor.
1173      * @param initialSz    initial z scaling factor.
1174      * @param initialMxy   initial x-y cross coupling error.
1175      * @param initialMxz   initial x-z cross coupling error.
1176      * @param initialMyx   initial y-x cross coupling error.
1177      * @param initialMyz   initial y-z cross coupling error.
1178      * @param initialMzx   initial z-x cross coupling error.
1179      * @param initialMzy   initial z-y cross coupling error.
1180      */
1181     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1182             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
1183             final double initialSx, final double initialSy, final double initialSz,
1184             final double initialMxy, final double initialMxz, final double initialMyx,
1185             final double initialMyz, final double initialMzx, final double initialMzy) {
1186         this(initialBiasX, initialBiasY, initialBiasZ);
1187         try {
1188             setInitialScalingFactorsAndCrossCouplingErrors(initialSx, initialSy, initialSz,
1189                     initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1190         } catch (final LockedException ignore) {
1191             // never happens
1192         }
1193     }
1194 
1195     /**
1196      * Constructor.
1197      *
1198      * @param measurements collection of body kinematics measurements with standard
1199      *                     deviations taken at different frames (positions, orientations
1200      *                     and velocities).
1201      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
1202      *                     to find a solution. This is expressed in radians per
1203      *                     second (rad/s).
1204      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
1205      *                     to find a solution. This is expressed in radians per
1206      *                     second (rad/s).
1207      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
1208      *                     to find a solution. This is expressed in radians per
1209      *                     second (rad/s).
1210      * @param initialSx    initial x scaling factor.
1211      * @param initialSy    initial y scaling factor.
1212      * @param initialSz    initial z scaling factor.
1213      * @param initialMxy   initial x-y cross coupling error.
1214      * @param initialMxz   initial x-z cross coupling error.
1215      * @param initialMyx   initial y-x cross coupling error.
1216      * @param initialMyz   initial y-z cross coupling error.
1217      * @param initialMzx   initial z-x cross coupling error.
1218      * @param initialMzy   initial z-y cross coupling error.
1219      */
1220     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1221             final Collection<StandardDeviationFrameBodyKinematics> measurements,
1222             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
1223             final double initialSx, final double initialSy, final double initialSz,
1224             final double initialMxy, final double initialMxz, final double initialMyx,
1225             final double initialMyz, final double initialMzx, final double initialMzy) {
1226         this(initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz,
1227                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1228         this.measurements = measurements;
1229     }
1230 
1231     /**
1232      * Constructor.
1233      *
1234      * @param measurements collection of body kinematics measurements with standard
1235      *                     deviations taken at different frames (positions, orientations
1236      *                     and velocities).
1237      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
1238      *                     to find a solution. This is expressed in radians per
1239      *                     second (rad/s).
1240      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
1241      *                     to find a solution. This is expressed in radians per
1242      *                     second (rad/s).
1243      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
1244      *                     to find a solution. This is expressed in radians per
1245      *                     second (rad/s).
1246      * @param initialSx    initial x scaling factor.
1247      * @param initialSy    initial y scaling factor.
1248      * @param initialSz    initial z scaling factor.
1249      * @param initialMxy   initial x-y cross coupling error.
1250      * @param initialMxz   initial x-z cross coupling error.
1251      * @param initialMyx   initial y-x cross coupling error.
1252      * @param initialMyz   initial y-z cross coupling error.
1253      * @param initialMzx   initial z-x cross coupling error.
1254      * @param initialMzy   initial z-y cross coupling error.
1255      * @param listener     listener to handle events raised by this calibrator.
1256      */
1257     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1258             final Collection<StandardDeviationFrameBodyKinematics> measurements,
1259             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
1260             final double initialSx, final double initialSy, final double initialSz,
1261             final double initialMxy, final double initialMxz, final double initialMyx,
1262             final double initialMyz, final double initialMzx, final double initialMzy,
1263             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1264         this(measurements, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz,
1265                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1266         this.listener = listener;
1267     }
1268 
1269     /**
1270      * Constructor.
1271      *
1272      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1273      *                       accelerometer and gyroscope.
1274      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
1275      *                       to find a solution. This is expressed in radians per
1276      *                       second (rad/s).
1277      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
1278      *                       to find a solution. This is expressed in radians per
1279      *                       second (rad/s).
1280      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
1281      *                       to find a solution. This is expressed in radians per
1282      *                       second (rad/s).
1283      * @param initialSx      initial x scaling factor.
1284      * @param initialSy      initial y scaling factor.
1285      * @param initialSz      initial z scaling factor.
1286      * @param initialMxy     initial x-y cross coupling error.
1287      * @param initialMxz     initial x-z cross coupling error.
1288      * @param initialMyx     initial y-x cross coupling error.
1289      * @param initialMyz     initial y-z cross coupling error.
1290      * @param initialMzx     initial z-x cross coupling error.
1291      * @param initialMzy     initial z-y cross coupling error.
1292      */
1293     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1294             final boolean commonAxisUsed,
1295             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
1296             final double initialSx, final double initialSy, final double initialSz,
1297             final double initialMxy, final double initialMxz, final double initialMyx,
1298             final double initialMyz, final double initialMzx, final double initialMzy) {
1299         this(initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz,
1300                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1301         this.commonAxisUsed = commonAxisUsed;
1302     }
1303 
1304     /**
1305      * Constructor.
1306      *
1307      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1308      *                       accelerometer and gyroscope.
1309      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
1310      *                       to find a solution. This is expressed in radians per
1311      *                       second (rad/s).
1312      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
1313      *                       to find a solution. This is expressed in radians per
1314      *                       second (rad/s).
1315      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
1316      *                       to find a solution. This is expressed in radians per
1317      *                       second (rad/s).
1318      * @param initialSx      initial x scaling factor.
1319      * @param initialSy      initial y scaling factor.
1320      * @param initialSz      initial z scaling factor.
1321      * @param initialMxy     initial x-y cross coupling error.
1322      * @param initialMxz     initial x-z cross coupling error.
1323      * @param initialMyx     initial y-x cross coupling error.
1324      * @param initialMyz     initial y-z cross coupling error.
1325      * @param initialMzx     initial z-x cross coupling error.
1326      * @param initialMzy     initial z-y cross coupling error.
1327      * @param listener       listener to handle events raised by this calibrator.
1328      */
1329     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1330             final boolean commonAxisUsed,
1331             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
1332             final double initialSx, final double initialSy, final double initialSz,
1333             final double initialMxy, final double initialMxz, final double initialMyx,
1334             final double initialMyz, final double initialMzx, final double initialMzy,
1335             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1336         this(commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz,
1337                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1338         this.listener = listener;
1339     }
1340 
1341     /**
1342      * Constructor.
1343      *
1344      * @param measurements   collection of body kinematics measurements with standard
1345      *                       deviations taken at different frames (positions, orientations
1346      *                       and velocities).
1347      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1348      *                       accelerometer and gyroscope.
1349      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
1350      *                       to find a solution. This is expressed in radians per
1351      *                       second (rad/s).
1352      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
1353      *                       to find a solution. This is expressed in radians per
1354      *                       second (rad/s).
1355      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
1356      *                       to find a solution. This is expressed in radians per
1357      *                       second (rad/s).
1358      * @param initialSx      initial x scaling factor.
1359      * @param initialSy      initial y scaling factor.
1360      * @param initialSz      initial z scaling factor.
1361      * @param initialMxy     initial x-y cross coupling error.
1362      * @param initialMxz     initial x-z cross coupling error.
1363      * @param initialMyx     initial y-x cross coupling error.
1364      * @param initialMyz     initial y-z cross coupling error.
1365      * @param initialMzx     initial z-x cross coupling error.
1366      * @param initialMzy     initial z-y cross coupling error.
1367      */
1368     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1369             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
1370             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
1371             final double initialSx, final double initialSy, final double initialSz,
1372             final double initialMxy, final double initialMxz, final double initialMyx,
1373             final double initialMyz, final double initialMzx, final double initialMzy) {
1374         this(commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz,
1375                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1376         this.measurements = measurements;
1377     }
1378 
1379     /**
1380      * Constructor.
1381      *
1382      * @param measurements   collection of body kinematics measurements with standard
1383      *                       deviations taken at different frames (positions, orientations
1384      *                       and velocities).
1385      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1386      *                       accelerometer and gyroscope.
1387      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
1388      *                       to find a solution. This is expressed in radians per
1389      *                       second (rad/s).
1390      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
1391      *                       to find a solution. This is expressed in radians per
1392      *                       second (rad/s).
1393      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
1394      *                       to find a solution. This is expressed in radians per
1395      *                       second (rad/s).
1396      * @param initialSx      initial x scaling factor.
1397      * @param initialSy      initial y scaling factor.
1398      * @param initialSz      initial z scaling factor.
1399      * @param initialMxy     initial x-y cross coupling error.
1400      * @param initialMxz     initial x-z cross coupling error.
1401      * @param initialMyx     initial y-x cross coupling error.
1402      * @param initialMyz     initial y-z cross coupling error.
1403      * @param initialMzx     initial z-x cross coupling error.
1404      * @param initialMzy     initial z-y cross coupling error.
1405      * @param listener       listener to handle events raised by this calibrator.
1406      */
1407     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1408             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
1409             final double initialBiasX, final double initialBiasY, final double initialBiasZ,
1410             final double initialSx, final double initialSy, final double initialSz,
1411             final double initialMxy, final double initialMxz, final double initialMyx,
1412             final double initialMyz, final double initialMzx, final double initialMzy,
1413             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1414         this(measurements, commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz,
1415                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1416         this.listener = listener;
1417     }
1418 
1419     /**
1420      * Constructor.
1421      *
1422      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
1423      *                     to find a solution.
1424      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
1425      *                     to find a solution.
1426      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
1427      *                     to find a solution.
1428      * @param initialSx    initial x scaling factor.
1429      * @param initialSy    initial y scaling factor.
1430      * @param initialSz    initial z scaling factor.
1431      * @param initialMxy   initial x-y cross coupling error.
1432      * @param initialMxz   initial x-z cross coupling error.
1433      * @param initialMyx   initial y-x cross coupling error.
1434      * @param initialMyz   initial y-z cross coupling error.
1435      * @param initialMzx   initial z-x cross coupling error.
1436      * @param initialMzy   initial z-y cross coupling error.
1437      */
1438     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1439             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
1440             final double initialSx, final double initialSy, final double initialSz,
1441             final double initialMxy, final double initialMxz, final double initialMyx,
1442             final double initialMyz, final double initialMzx, final double initialMzy) {
1443         this(initialBiasX, initialBiasY, initialBiasZ);
1444         try {
1445             setInitialScalingFactorsAndCrossCouplingErrors(initialSx, initialSy, initialSz,
1446                     initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1447         } catch (final LockedException ignore) {
1448             // never happens
1449         }
1450     }
1451 
1452     /**
1453      * Constructor.
1454      *
1455      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
1456      *                     to find a solution.
1457      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
1458      *                     to find a solution.
1459      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
1460      *                     to find a solution.
1461      * @param initialSx    initial x scaling factor.
1462      * @param initialSy    initial y scaling factor.
1463      * @param initialSz    initial z scaling factor.
1464      * @param initialMxy   initial x-y cross coupling error.
1465      * @param initialMxz   initial x-z cross coupling error.
1466      * @param initialMyx   initial y-x cross coupling error.
1467      * @param initialMyz   initial y-z cross coupling error.
1468      * @param initialMzx   initial z-x cross coupling error.
1469      * @param initialMzy   initial z-y cross coupling error.
1470      * @param listener     listener to handle events raised by this calibrator.
1471      */
1472     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1473             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
1474             final double initialSx, final double initialSy, final double initialSz,
1475             final double initialMxy, final double initialMxz, final double initialMyx,
1476             final double initialMyz, final double initialMzx, final double initialMzy,
1477             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1478         this(initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz,
1479                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1480         this.listener = listener;
1481     }
1482 
1483     /**
1484      * Constructor.
1485      *
1486      * @param measurements collection of body kinematics measurements with standard
1487      *                     deviations taken at different frames (positions, orientations
1488      *                     and velocities).
1489      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
1490      *                     to find a solution.
1491      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
1492      *                     to find a solution.
1493      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
1494      *                     to find a solution.
1495      * @param initialSx    initial x scaling factor.
1496      * @param initialSy    initial y scaling factor.
1497      * @param initialSz    initial z scaling factor.
1498      * @param initialMxy   initial x-y cross coupling error.
1499      * @param initialMxz   initial x-z cross coupling error.
1500      * @param initialMyx   initial y-x cross coupling error.
1501      * @param initialMyz   initial y-z cross coupling error.
1502      * @param initialMzx   initial z-x cross coupling error.
1503      * @param initialMzy   initial z-y cross coupling error.
1504      */
1505     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1506             final Collection<StandardDeviationFrameBodyKinematics> measurements,
1507             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
1508             final double initialSx, final double initialSy, final double initialSz,
1509             final double initialMxy, final double initialMxz, final double initialMyx,
1510             final double initialMyz, final double initialMzx, final double initialMzy) {
1511         this(initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz,
1512                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1513         this.measurements = measurements;
1514     }
1515 
1516 
1517     /**
1518      * Constructor.
1519      *
1520      * @param measurements collection of body kinematics measurements with standard
1521      *                     deviations taken at different frames (positions, orientations
1522      *                     and velocities).
1523      * @param initialBiasX initial x-coordinate of gyroscope bias to be used
1524      *                     to find a solution.
1525      * @param initialBiasY initial y-coordinate of gyroscope bias to be used
1526      *                     to find a solution.
1527      * @param initialBiasZ initial z-coordinate of gyroscope bias to be used
1528      *                     to find a solution.
1529      * @param initialSx    initial x scaling factor.
1530      * @param initialSy    initial y scaling factor.
1531      * @param initialSz    initial z scaling factor.
1532      * @param initialMxy   initial x-y cross coupling error.
1533      * @param initialMxz   initial x-z cross coupling error.
1534      * @param initialMyx   initial y-x cross coupling error.
1535      * @param initialMyz   initial y-z cross coupling error.
1536      * @param initialMzx   initial z-x cross coupling error.
1537      * @param initialMzy   initial z-y cross coupling error.
1538      * @param listener     listener to handle events raised by this calibrator.
1539      */
1540     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1541             final Collection<StandardDeviationFrameBodyKinematics> measurements,
1542             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
1543             final double initialSx, final double initialSy, final double initialSz,
1544             final double initialMxy, final double initialMxz, final double initialMyx,
1545             final double initialMyz, final double initialMzx, final double initialMzy,
1546             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1547         this(measurements, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz,
1548                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1549         this.listener = listener;
1550     }
1551 
1552     /**
1553      * Constructor.
1554      *
1555      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1556      *                       accelerometer and gyroscope.
1557      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
1558      *                       to find a solution.
1559      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
1560      *                       to find a solution.
1561      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
1562      *                       to find a solution.
1563      * @param initialSx      initial x scaling factor.
1564      * @param initialSy      initial y scaling factor.
1565      * @param initialSz      initial z scaling factor.
1566      * @param initialMxy     initial x-y cross coupling error.
1567      * @param initialMxz     initial x-z cross coupling error.
1568      * @param initialMyx     initial y-x cross coupling error.
1569      * @param initialMyz     initial y-z cross coupling error.
1570      * @param initialMzx     initial z-x cross coupling error.
1571      * @param initialMzy     initial z-y cross coupling error.
1572      */
1573     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1574             final boolean commonAxisUsed,
1575             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
1576             final double initialSx, final double initialSy, final double initialSz,
1577             final double initialMxy, final double initialMxz, final double initialMyx,
1578             final double initialMyz, final double initialMzx, final double initialMzy) {
1579         this(initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz,
1580                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1581         this.commonAxisUsed = commonAxisUsed;
1582     }
1583 
1584     /**
1585      * Constructor.
1586      *
1587      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1588      *                       accelerometer and gyroscope.
1589      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
1590      *                       to find a solution.
1591      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
1592      *                       to find a solution.
1593      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
1594      *                       to find a solution.
1595      * @param initialSx      initial x scaling factor.
1596      * @param initialSy      initial y scaling factor.
1597      * @param initialSz      initial z scaling factor.
1598      * @param initialMxy     initial x-y cross coupling error.
1599      * @param initialMxz     initial x-z cross coupling error.
1600      * @param initialMyx     initial y-x cross coupling error.
1601      * @param initialMyz     initial y-z cross coupling error.
1602      * @param initialMzx     initial z-x cross coupling error.
1603      * @param initialMzy     initial z-y cross coupling error.
1604      * @param listener       listener to handle events raised by this calibrator.
1605      */
1606     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1607             final boolean commonAxisUsed,
1608             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
1609             final double initialSx, final double initialSy, final double initialSz,
1610             final double initialMxy, final double initialMxz, final double initialMyx,
1611             final double initialMyz, final double initialMzx, final double initialMzy,
1612             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1613         this(commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz,
1614                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1615         this.listener = listener;
1616     }
1617 
1618     /**
1619      * Constructor.
1620      *
1621      * @param measurements   collection of body kinematics measurements with standard
1622      *                       deviations taken at different frames (positions, orientations
1623      *                       and velocities).
1624      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1625      *                       accelerometer and gyroscope.
1626      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
1627      *                       to find a solution.
1628      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
1629      *                       to find a solution.
1630      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
1631      *                       to find a solution.
1632      * @param initialSx      initial x scaling factor.
1633      * @param initialSy      initial y scaling factor.
1634      * @param initialSz      initial z scaling factor.
1635      * @param initialMxy     initial x-y cross coupling error.
1636      * @param initialMxz     initial x-z cross coupling error.
1637      * @param initialMyx     initial y-x cross coupling error.
1638      * @param initialMyz     initial y-z cross coupling error.
1639      * @param initialMzx     initial z-x cross coupling error.
1640      * @param initialMzy     initial z-y cross coupling error.
1641      */
1642     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1643             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
1644             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
1645             final double initialSx, final double initialSy, final double initialSz,
1646             final double initialMxy, final double initialMxz, final double initialMyx,
1647             final double initialMyz, final double initialMzx, final double initialMzy) {
1648         this(commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz,
1649                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1650         this.measurements = measurements;
1651     }
1652 
1653     /**
1654      * Constructor.
1655      *
1656      * @param measurements   collection of body kinematics measurements with standard
1657      *                       deviations taken at different frames (positions, orientations
1658      *                       and velocities).
1659      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1660      *                       accelerometer and gyroscope.
1661      * @param initialBiasX   initial x-coordinate of gyroscope bias to be used
1662      *                       to find a solution.
1663      * @param initialBiasY   initial y-coordinate of gyroscope bias to be used
1664      *                       to find a solution.
1665      * @param initialBiasZ   initial z-coordinate of gyroscope bias to be used
1666      *                       to find a solution.
1667      * @param initialSx      initial x scaling factor.
1668      * @param initialSy      initial y scaling factor.
1669      * @param initialSz      initial z scaling factor.
1670      * @param initialMxy     initial x-y cross coupling error.
1671      * @param initialMxz     initial x-z cross coupling error.
1672      * @param initialMyx     initial y-x cross coupling error.
1673      * @param initialMyz     initial y-z cross coupling error.
1674      * @param initialMzx     initial z-x cross coupling error.
1675      * @param initialMzy     initial z-y cross coupling error.
1676      * @param listener       listener to handle events raised by this calibrator.
1677      */
1678     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1679             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
1680             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ,
1681             final double initialSx, final double initialSy, final double initialSz,
1682             final double initialMxy, final double initialMxz, final double initialMyx,
1683             final double initialMyz, final double initialMzx, final double initialMzy,
1684             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1685         this(measurements, commonAxisUsed, initialBiasX, initialBiasY, initialBiasZ, initialSx, initialSy, initialSz,
1686                 initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
1687         this.listener = listener;
1688     }
1689 
1690     /**
1691      * Constructor.
1692      *
1693      * @param initialBias initial gyroscope bias to be used to find a solution.
1694      *                    This must have length 3 and is expressed in radians per
1695      *                    second (rad/s).
1696      * @throws IllegalArgumentException if provided bias array does not have length 3.
1697      */
1698     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(final double[] initialBias) {
1699         this();
1700         try {
1701             setInitialBias(initialBias);
1702         } catch (final LockedException ignore) {
1703             // never happens
1704         }
1705     }
1706 
1707     /**
1708      * Constructor.
1709      *
1710      * @param initialBias initial gyroscope bias to be used to find a solution.
1711      *                    This must have length 3 and is expressed in radians per
1712      *                    second (rad/s).
1713      * @param listener    listener to handle events raised by this calibrator.
1714      * @throws IllegalArgumentException if provided bias array does not have length 3.
1715      */
1716     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1717             final double[] initialBias, final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1718         this(initialBias);
1719         this.listener = listener;
1720     }
1721 
1722     /**
1723      * Constructor.
1724      *
1725      * @param measurements collection of body kinematics measurements with standard
1726      *                     deviations taken at different frames (positions, orientations
1727      *                     and velocities).
1728      * @param initialBias  initial gyroscope bias to be used to find a solution.
1729      *                     This must have length 3 and is expressed in radians per
1730      *                     second (rad/s).
1731      * @throws IllegalArgumentException if provided bias array does not have length 3.
1732      */
1733     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1734             final Collection<StandardDeviationFrameBodyKinematics> measurements, final double[] initialBias) {
1735         this(initialBias);
1736         this.measurements = measurements;
1737     }
1738 
1739     /**
1740      * Constructor.
1741      *
1742      * @param measurements collection of body kinematics measurements with standard
1743      *                     deviations taken at different frames (positions, orientations
1744      *                     and velocities).
1745      * @param initialBias  initial gyroscope bias to be used to find a solution.
1746      *                     This must have length 3 and is expressed in radians per
1747      *                     second (rad/s).
1748      * @param listener     listener to handle events raised by this calibrator.
1749      * @throws IllegalArgumentException if provided bias array does not have length 3.
1750      */
1751     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1752             final Collection<StandardDeviationFrameBodyKinematics> measurements, final double[] initialBias,
1753             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1754         this(measurements, initialBias);
1755         this.listener = listener;
1756     }
1757 
1758     /**
1759      * Constructor.
1760      *
1761      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1762      *                       accelerometer and gyroscope.
1763      * @param initialBias    initial gyroscope bias to be used to find a solution.
1764      *                       This must have length 3 and is expressed in radians per
1765      *                       second (rad/s).
1766      * @throws IllegalArgumentException if provided bias array does not have length 3.
1767      */
1768     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1769             final boolean commonAxisUsed, final double[] initialBias) {
1770         this(initialBias);
1771         this.commonAxisUsed = commonAxisUsed;
1772     }
1773 
1774     /**
1775      * Constructor.
1776      *
1777      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1778      *                       accelerometer and gyroscope.
1779      * @param initialBias    initial gyroscope bias to be used to find a solution.
1780      *                       This must have length 3 and is expressed in radians per
1781      *                       second (rad/s).
1782      * @param listener       listener to handle events raised by this calibrator.
1783      * @throws IllegalArgumentException if provided bias array does not have length 3.
1784      */
1785     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1786             final boolean commonAxisUsed, final double[] initialBias,
1787             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1788         this(commonAxisUsed, initialBias);
1789         this.listener = listener;
1790     }
1791 
1792     /**
1793      * Constructor.
1794      *
1795      * @param measurements   collection of body kinematics measurements with standard
1796      *                       deviations taken at different frames (positions, orientations
1797      *                       and velocities).
1798      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1799      *                       accelerometer and gyroscope.
1800      * @param initialBias    initial gyroscope bias to be used to find a solution.
1801      *                       This must have length 3 and is expressed in radians per
1802      *                       second (rad/s).
1803      * @throws IllegalArgumentException if provided bias array does not have length 3.
1804      */
1805     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1806             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
1807             final double[] initialBias) {
1808         this(commonAxisUsed, initialBias);
1809         this.measurements = measurements;
1810     }
1811 
1812     /**
1813      * Constructor.
1814      *
1815      * @param measurements   collection of body kinematics measurements with standard
1816      *                       deviations taken at different frames (positions, orientations
1817      *                       and velocities).
1818      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1819      *                       accelerometer and gyroscope.
1820      * @param initialBias    initial gyroscope bias to be used to find a solution.
1821      *                       This must have length 3 and is expressed in radians per
1822      *                       second (rad/s).
1823      * @param listener       listener to handle events raised by this calibrator.
1824      * @throws IllegalArgumentException if provided bias array does not have length 3.
1825      */
1826     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1827             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
1828             final double[] initialBias, final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1829         this(measurements, commonAxisUsed, initialBias);
1830         this.listener = listener;
1831     }
1832 
1833     /**
1834      * Constructor.
1835      *
1836      * @param initialBias initial bias to find a solution.
1837      * @throws IllegalArgumentException if provided bias matrix is not 3x1.
1838      */
1839     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(final Matrix initialBias) {
1840         this();
1841         try {
1842             setInitialBias(initialBias);
1843         } catch (final LockedException ignore) {
1844             // never happens
1845         }
1846     }
1847 
1848     /**
1849      * Constructor.
1850      *
1851      * @param initialBias initial bias to find a solution.
1852      * @param listener    listener to handle events raised by this calibrator.
1853      * @throws IllegalArgumentException if provided bias matrix is not 3x1.
1854      */
1855     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1856             final Matrix initialBias, final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1857         this(initialBias);
1858         this.listener = listener;
1859     }
1860 
1861     /**
1862      * Constructor.
1863      *
1864      * @param measurements collection of body kinematics measurements with standard
1865      *                     deviations taken at different frames (positions, orientations
1866      *                     and velocities).
1867      * @param initialBias  initial bias to find a solution.
1868      * @throws IllegalArgumentException if provided bias matrix is not 3x1.
1869      */
1870     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1871             final Collection<StandardDeviationFrameBodyKinematics> measurements, final Matrix initialBias) {
1872         this(initialBias);
1873         this.measurements = measurements;
1874     }
1875 
1876     /**
1877      * Constructor.
1878      *
1879      * @param measurements collection of body kinematics measurements with standard
1880      *                     deviations taken at different frames (positions, orientations
1881      *                     and velocities).
1882      * @param initialBias  initial bias to find a solution.
1883      * @param listener     listener to handle events raised by this calibrator.
1884      * @throws IllegalArgumentException if provided bias matrix is not 3x1.
1885      */
1886     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1887             final Collection<StandardDeviationFrameBodyKinematics> measurements, final Matrix initialBias,
1888             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1889         this(measurements, initialBias);
1890         this.listener = listener;
1891     }
1892 
1893     /**
1894      * Constructor.
1895      *
1896      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1897      *                       accelerometer and gyroscope.
1898      * @param initialBias    initial bias to find a solution.
1899      * @throws IllegalArgumentException if provided bias matrix is not 3x1.
1900      */
1901     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(final boolean commonAxisUsed, final Matrix initialBias) {
1902         this(initialBias);
1903         this.commonAxisUsed = commonAxisUsed;
1904     }
1905 
1906     /**
1907      * Constructor.
1908      *
1909      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1910      *                       accelerometer and gyroscope.
1911      * @param initialBias    initial bias to find a solution.
1912      * @param listener       listener to handle events raised by this calibrator.
1913      * @throws IllegalArgumentException if provided bias matrix is not 3x1.
1914      */
1915     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1916             final boolean commonAxisUsed, final Matrix initialBias,
1917             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1918         this(commonAxisUsed, initialBias);
1919         this.listener = listener;
1920     }
1921 
1922     /**
1923      * Constructor.
1924      *
1925      * @param measurements   collection of body kinematics measurements with standard
1926      *                       deviations taken at different frames (positions, orientations
1927      *                       and velocities).
1928      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1929      *                       accelerometer and gyroscope.
1930      * @param initialBias    initial bias to find a solution.
1931      * @throws IllegalArgumentException if provided bias matrix is not 3x1.
1932      */
1933     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1934             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
1935             final Matrix initialBias) {
1936         this(commonAxisUsed, initialBias);
1937         this.measurements = measurements;
1938     }
1939 
1940     /**
1941      * Constructor.
1942      *
1943      * @param measurements   collection of body kinematics measurements with standard
1944      *                       deviations taken at different frames (positions, orientations
1945      *                       and velocities).
1946      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
1947      *                       accelerometer and gyroscope.
1948      * @param initialBias    initial bias to find a solution.
1949      * @param listener       listener to handle events raised by this calibrator.
1950      * @throws IllegalArgumentException if provided bias matrix is not 3x1.
1951      */
1952     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1953             final Collection<StandardDeviationFrameBodyKinematics> measurements, final boolean commonAxisUsed,
1954             final Matrix initialBias, final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1955         this(measurements, commonAxisUsed, initialBias);
1956         this.listener = listener;
1957     }
1958 
1959     /**
1960      * Constructor.
1961      *
1962      * @param initialBias initial bias to find a solution.
1963      * @param initialMg   initial scale factors and cross coupling errors matrix.
1964      * @throws IllegalArgumentException if either provided bias matrix is not 3x1 or
1965      *                                  scaling and coupling error matrix is not 3x3.
1966      */
1967     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(final Matrix initialBias, final Matrix initialMg) {
1968         this(initialBias);
1969         try {
1970             setInitialMg(initialMg);
1971         } catch (final LockedException ignore) {
1972             // never happens
1973         }
1974     }
1975 
1976     /**
1977      * Constructor.
1978      *
1979      * @param initialBias initial bias to find a solution.
1980      * @param initialMg   initial scale factors and cross coupling errors matrix.
1981      * @param listener    listener to handle events raised by this calibrator.
1982      * @throws IllegalArgumentException if either provided bias matrix is not 3x1 or
1983      *                                  scaling and coupling error matrix is not 3x3.
1984      */
1985     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
1986             final Matrix initialBias, final Matrix initialMg,
1987             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
1988         this(initialBias, initialMg);
1989         this.listener = listener;
1990     }
1991 
1992     /**
1993      * Constructor.
1994      *
1995      * @param measurements collection of body kinematics measurements with standard
1996      *                     deviations taken at different frames (positions, orientations
1997      *                     and velocities).
1998      * @param initialBias  initial bias to find a solution.
1999      * @param initialMg    initial scale factors and cross coupling errors matrix.
2000      * @throws IllegalArgumentException if either provided bias matrix is not 3x1 or
2001      *                                  scaling and coupling error matrix is not 3x3.
2002      */
2003     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
2004             final Collection<StandardDeviationFrameBodyKinematics> measurements,
2005             final Matrix initialBias, final Matrix initialMg) {
2006         this(initialBias, initialMg);
2007         this.measurements = measurements;
2008     }
2009 
2010     /**
2011      * Constructor.
2012      *
2013      * @param measurements collection of body kinematics measurements with standard
2014      *                     deviations taken at different frames (positions, orientations
2015      *                     and velocities).
2016      * @param initialBias  initial bias to find a solution.
2017      * @param initialMg    initial scale factors and cross coupling errors matrix.
2018      * @param listener     listener to handle events raised by this calibrator.
2019      * @throws IllegalArgumentException if either provided bias matrix is not 3x1 or
2020      *                                  scaling and coupling error matrix is not 3x3.
2021      */
2022     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
2023             final Collection<StandardDeviationFrameBodyKinematics> measurements, final Matrix initialBias,
2024             final Matrix initialMg, final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
2025         this(measurements, initialBias, initialMg);
2026         this.listener = listener;
2027     }
2028 
2029     /**
2030      * Constructor.
2031      *
2032      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
2033      *                       accelerometer and gyroscope.
2034      * @param initialBias    initial bias to find a solution.
2035      * @param initialMg      initial scale factors and cross coupling errors matrix.
2036      * @throws IllegalArgumentException if either provided bias matrix is not 3x1 or
2037      *                                  scaling and coupling error matrix is not 3x3.
2038      */
2039     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
2040             final boolean commonAxisUsed, final Matrix initialBias, final Matrix initialMg) {
2041         this(initialBias, initialMg);
2042         this.commonAxisUsed = commonAxisUsed;
2043     }
2044 
2045     /**
2046      * Constructor.
2047      *
2048      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
2049      *                       accelerometer and gyroscope.
2050      * @param initialBias    initial bias to find a solution.
2051      * @param initialMg      initial scale factors and cross coupling errors matrix.
2052      * @param listener       listener to handle events raised by this calibrator.
2053      * @throws IllegalArgumentException if either provided bias matrix is not 3x1 or
2054      *                                  scaling and coupling error matrix is not 3x3.
2055      */
2056     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
2057             final boolean commonAxisUsed, final Matrix initialBias, final Matrix initialMg,
2058             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
2059         this(commonAxisUsed, initialBias, initialMg);
2060         this.listener = listener;
2061     }
2062 
2063     /**
2064      * Constructor.
2065      *
2066      * @param measurements   collection of body kinematics measurements with standard
2067      *                       deviations taken at different frames (positions, orientations
2068      *                       and velocities).
2069      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
2070      *                       accelerometer and gyroscope.
2071      * @param initialBias    initial bias to find a solution.
2072      * @param initialMg      initial scale factors and cross coupling errors matrix.
2073      * @throws IllegalArgumentException if either provided bias matrix is not 3x1 or
2074      *                                  scaling and coupling error matrix is not 3x3.
2075      */
2076     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
2077             final Collection<StandardDeviationFrameBodyKinematics> measurements,
2078             final boolean commonAxisUsed, final Matrix initialBias, final Matrix initialMg) {
2079         this(commonAxisUsed, initialBias, initialMg);
2080         this.measurements = measurements;
2081     }
2082 
2083     /**
2084      * Constructor.
2085      *
2086      * @param measurements   collection of body kinematics measurements with standard
2087      *                       deviations taken at different frames (positions, orientations
2088      *                       and velocities).
2089      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
2090      *                       accelerometer and gyroscope.
2091      * @param initialBias    initial bias to find a solution.
2092      * @param initialMg      initial scale factors and cross coupling errors matrix.
2093      * @param listener       listener to handle events raised by this calibrator.
2094      * @throws IllegalArgumentException if either provided bias matrix is not 3x1 or
2095      *                                  scaling and coupling error matrix is not 3x3.
2096      */
2097     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
2098             final Collection<StandardDeviationFrameBodyKinematics> measurements,
2099             final boolean commonAxisUsed, final Matrix initialBias, final Matrix initialMg,
2100             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
2101         this(measurements, commonAxisUsed, initialBias, initialMg);
2102         this.listener = listener;
2103     }
2104 
2105     /**
2106      * Constructor.
2107      *
2108      * @param initialBias initial bias to find a solution.
2109      * @param initialMg   initial scale factors and cross coupling errors matrix.
2110      * @param initialGg   initial G-dependent cross biases.
2111      * @throws IllegalArgumentException if either provided bias matrix is not 3x1,
2112      *                                  scaling and coupling error matrix is not 3x3
2113      *                                  or g-dependant cross biases is not 3x3.
2114      */
2115     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
2116             final Matrix initialBias, final Matrix initialMg, final Matrix initialGg) {
2117         this(initialBias, initialMg);
2118         try {
2119             setInitialGg(initialGg);
2120         } catch (final LockedException ignore) {
2121             // never happens
2122         }
2123     }
2124 
2125     /**
2126      * Constructor.
2127      *
2128      * @param initialBias initial bias to find a solution.
2129      * @param initialMg   initial scale factors and cross coupling errors matrix.
2130      * @param initialGg   initial G-dependent cross biases.
2131      * @param listener    listener to handle events raised by this calibrator.
2132      * @throws IllegalArgumentException if either provided bias matrix is not 3x1,
2133      *                                  scaling and coupling error matrix is not 3x3
2134      *                                  or g-dependant cross biases is not 3x3.
2135      */
2136     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
2137             final Matrix initialBias, final Matrix initialMg, final Matrix initialGg,
2138             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
2139         this(initialBias, initialMg, initialGg);
2140         this.listener = listener;
2141     }
2142 
2143     /**
2144      * Constructor.
2145      *
2146      * @param measurements collection of body kinematics measurements with standard
2147      *                     deviations taken at different frames (positions, orientations
2148      *                     and velocities).
2149      * @param initialBias  initial bias to find a solution.
2150      * @param initialMg    initial scale factors and cross coupling errors matrix.
2151      * @param initialGg    initial G-dependent cross biases.
2152      * @throws IllegalArgumentException if either provided bias matrix is not 3x1,
2153      *                                  scaling and coupling error matrix is not 3x3
2154      *                                  or g-dependant cross biases is not 3x3.
2155      */
2156     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
2157             final Collection<StandardDeviationFrameBodyKinematics> measurements,
2158             final Matrix initialBias, final Matrix initialMg, final Matrix initialGg) {
2159         this(initialBias, initialMg, initialGg);
2160         this.measurements = measurements;
2161     }
2162 
2163     /**
2164      * Constructor.
2165      *
2166      * @param measurements collection of body kinematics measurements with standard
2167      *                     deviations taken at different frames (positions, orientations
2168      *                     and velocities).
2169      * @param initialBias  initial bias to find a solution.
2170      * @param initialMg    initial scale factors and cross coupling errors matrix.
2171      * @param initialGg    initial G-dependent cross biases.
2172      * @param listener     listener to handle events raised by this calibrator.
2173      * @throws IllegalArgumentException if either provided bias matrix is not 3x1,
2174      *                                  scaling and coupling error matrix is not 3x3
2175      *                                  or g-dependant cross biases is not 3x3.
2176      */
2177     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
2178             final Collection<StandardDeviationFrameBodyKinematics> measurements,
2179             final Matrix initialBias, final Matrix initialMg, final Matrix initialGg,
2180             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
2181         this(measurements, initialBias, initialMg, initialGg);
2182         this.listener = listener;
2183     }
2184 
2185     /**
2186      * Constructor.
2187      *
2188      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
2189      *                       accelerometer and gyroscope.
2190      * @param initialBias    initial bias to find a solution.
2191      * @param initialMg      initial scale factors and cross coupling errors matrix.
2192      * @param initialGg      initial G-dependent cross biases.
2193      * @throws IllegalArgumentException if either provided bias matrix is not 3x1,
2194      *                                  scaling and coupling error matrix is not 3x3
2195      *                                  or g-dependant cross biases is not 3x3.
2196      */
2197     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
2198             final boolean commonAxisUsed, final Matrix initialBias, final Matrix initialMg, final Matrix initialGg) {
2199         this(initialBias, initialMg, initialGg);
2200         this.commonAxisUsed = commonAxisUsed;
2201     }
2202 
2203     /**
2204      * Constructor.
2205      *
2206      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
2207      *                       accelerometer and gyroscope.
2208      * @param initialBias    initial bias to find a solution.
2209      * @param initialMg      initial scale factors and cross coupling errors matrix.
2210      * @param initialGg      initial G-dependent cross biases.
2211      * @param listener       listener to handle events raised by this calibrator.
2212      * @throws IllegalArgumentException if either provided bias matrix is not 3x1,
2213      *                                  scaling and coupling error matrix is not 3x3
2214      *                                  or g-dependant cross biases is not 3x3.
2215      */
2216     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
2217             final boolean commonAxisUsed, final Matrix initialBias, final Matrix initialMg, final Matrix initialGg,
2218             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
2219         this(commonAxisUsed, initialBias, initialMg, initialGg);
2220         this.listener = listener;
2221     }
2222 
2223     /**
2224      * Constructor.
2225      *
2226      * @param measurements   collection of body kinematics measurements with standard
2227      *                       deviations taken at different frames (positions, orientations
2228      *                       and velocities).
2229      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
2230      *                       accelerometer and gyroscope.
2231      * @param initialBias    initial bias to find a solution.
2232      * @param initialMg      initial scale factors and cross coupling errors matrix.
2233      * @param initialGg      initial G-dependent cross biases.
2234      * @throws IllegalArgumentException if either provided bias matrix is not 3x1,
2235      *                                  scaling and coupling error matrix is not 3x3
2236      *                                  or g-dependant cross biases is not 3x3.
2237      */
2238     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
2239             final Collection<StandardDeviationFrameBodyKinematics> measurements,
2240             final boolean commonAxisUsed, final Matrix initialBias, final Matrix initialMg, final Matrix initialGg) {
2241         this(commonAxisUsed, initialBias, initialMg, initialGg);
2242         this.measurements = measurements;
2243     }
2244 
2245     /**
2246      * Constructor.
2247      *
2248      * @param measurements   collection of body kinematics measurements with standard
2249      *                       deviations taken at different frames (positions, orientations
2250      *                       and velocities).
2251      * @param commonAxisUsed indicates whether z-axis is assumed to be common for
2252      *                       accelerometer and gyroscope.
2253      * @param initialBias    initial bias to find a solution.
2254      * @param initialMg      initial scale factors and cross coupling errors matrix.
2255      * @param initialGg      initial G-dependent cross biases.
2256      * @param listener       listener to handle events raised by this calibrator.
2257      * @throws IllegalArgumentException if either provided bias matrix is not 3x1,
2258      *                                  scaling and coupling error matrix is not 3x3
2259      *                                  or g-dependant cross biases is not 3x3.
2260      */
2261     public KnownFrameGyroscopeNonLinearLeastSquaresCalibrator(
2262             final Collection<StandardDeviationFrameBodyKinematics> measurements,
2263             final boolean commonAxisUsed, final Matrix initialBias, final Matrix initialMg, final Matrix initialGg,
2264             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) {
2265         this(measurements, commonAxisUsed, initialBias, initialMg, initialGg);
2266         this.listener = listener;
2267     }
2268 
2269     /**
2270      * Gets initial x-coordinate of gyroscope bias to be used to find a solution.
2271      * This is expressed in radians per second (rad/s).
2272      *
2273      * @return initial x-coordinate of gyroscope bias.
2274      */
2275     @Override
2276     public double getInitialBiasX() {
2277         return initialBiasX;
2278     }
2279 
2280     /**
2281      * Sets initial x-coordinate of gyroscope bias to be used to find a solution.
2282      * This is expressed in radians per second (rad/s).
2283      *
2284      * @param initialBiasX initial x-coordinate of gyroscope bias.
2285      * @throws LockedException if calibrator is currently running.
2286      */
2287     @Override
2288     public void setInitialBiasX(final double initialBiasX) throws LockedException {
2289         if (running) {
2290             throw new LockedException();
2291         }
2292         this.initialBiasX = initialBiasX;
2293     }
2294 
2295     /**
2296      * Gets initial y-coordinate of gyroscope bias to be used to find a solution.
2297      * This is expressed in radians per second (rad/s).
2298      *
2299      * @return initial y-coordinate of gyroscope bias.
2300      */
2301     @Override
2302     public double getInitialBiasY() {
2303         return initialBiasY;
2304     }
2305 
2306     /**
2307      * Sets initial y-coordinate of gyroscope bias to be used to find a solution.
2308      * This is expressed in radians per second (rad/s).
2309      *
2310      * @param initialBiasY initial y-coordinate of gyroscope bias.
2311      * @throws LockedException if calibrator is currently running.
2312      */
2313     @Override
2314     public void setInitialBiasY(final double initialBiasY) throws LockedException {
2315         if (running) {
2316             throw new LockedException();
2317         }
2318         this.initialBiasY = initialBiasY;
2319     }
2320 
2321     /**
2322      * Gets initial z-coordinate of gyroscope bias to be used to find a solution.
2323      * This is expressed in radians per second (rad/s).
2324      *
2325      * @return initial z-coordinate of gyroscope bias.
2326      */
2327     @Override
2328     public double getInitialBiasZ() {
2329         return initialBiasZ;
2330     }
2331 
2332     /**
2333      * Sets initial z-coordinate of gyroscope bias to be used to find a solution.
2334      * This is expressed in radians per second (rad/s).
2335      *
2336      * @param initialBiasZ initial z-coordinate of gyroscope bias.
2337      * @throws LockedException if calibrator is currently running.
2338      */
2339     @Override
2340     public void setInitialBiasZ(final double initialBiasZ) throws LockedException {
2341         if (running) {
2342             throw new LockedException();
2343         }
2344         this.initialBiasZ = initialBiasZ;
2345     }
2346 
2347     /**
2348      * Gets initial x-coordinate of gyroscope bias to be used to find a solution.
2349      *
2350      * @return initial x-coordinate of gyroscope bias.
2351      */
2352     @Override
2353     public AngularSpeed getInitialBiasAngularSpeedX() {
2354         return new AngularSpeed(initialBiasX, AngularSpeedUnit.RADIANS_PER_SECOND);
2355     }
2356 
2357     /**
2358      * Gets initial x-coordinate of gyroscope bias to be used to find a solution.
2359      *
2360      * @param result instance where result data will be stored.
2361      */
2362     @Override
2363     public void getInitialBiasAngularSpeedX(final AngularSpeed result) {
2364         result.setValue(initialBiasX);
2365         result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
2366     }
2367 
2368     /**
2369      * Sets initial x-coordinate of gyroscope bias to be used to find a solution.
2370      *
2371      * @param initialBiasX initial x-coordinate of gyroscope bias.
2372      * @throws LockedException if calibrator is currently running.
2373      */
2374     @Override
2375     public void setInitialBiasX(final AngularSpeed initialBiasX) throws LockedException {
2376         if (running) {
2377             throw new LockedException();
2378         }
2379         this.initialBiasX = convertAngularSpeed(initialBiasX);
2380     }
2381 
2382     /**
2383      * Gets initial y-coordinate of gyroscope bias to be used to find a solution.
2384      *
2385      * @return initial y-coordinate of gyroscope bias.
2386      */
2387     @Override
2388     public AngularSpeed getInitialBiasAngularSpeedY() {
2389         return new AngularSpeed(initialBiasY, AngularSpeedUnit.RADIANS_PER_SECOND);
2390     }
2391 
2392     /**
2393      * Gets initial y-coordinate of gyroscope bias to be used to find a solution.
2394      *
2395      * @param result instance where result data will be stored.
2396      */
2397     @Override
2398     public void getInitialBiasAngularSpeedY(final AngularSpeed result) {
2399         result.setValue(initialBiasY);
2400         result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
2401     }
2402 
2403     /**
2404      * Sets initial y-coordinate of gyroscope bias to be used to find a solution.
2405      *
2406      * @param initialBiasY initial y-coordinate of gyroscope bias.
2407      * @throws LockedException if calibrator is currently running.
2408      */
2409     @Override
2410     public void setInitialBiasY(final AngularSpeed initialBiasY) throws LockedException {
2411         if (running) {
2412             throw new LockedException();
2413         }
2414         this.initialBiasY = convertAngularSpeed(initialBiasY);
2415     }
2416 
2417     /**
2418      * Gets initial z-coordinate of gyroscope bias to be used to find a solution.
2419      *
2420      * @return initial z-coordinate of gyroscope bias.
2421      */
2422     @Override
2423     public AngularSpeed getInitialBiasAngularSpeedZ() {
2424         return new AngularSpeed(initialBiasZ, AngularSpeedUnit.RADIANS_PER_SECOND);
2425     }
2426 
2427     /**
2428      * Gets initial z-coordinate of gyroscope bias to be used to find a solution.
2429      *
2430      * @param result instance where result data will be stored.
2431      */
2432     @Override
2433     public void getInitialBiasAngularSpeedZ(final AngularSpeed result) {
2434         result.setValue(initialBiasZ);
2435         result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
2436     }
2437 
2438     /**
2439      * Sets initial z-coordinate of gyroscope bias to be used to find a solution.
2440      *
2441      * @param initialBiasZ initial z-coordinate of gyroscope bias.
2442      * @throws LockedException if calibrator is currently running.
2443      */
2444     @Override
2445     public void setInitialBiasZ(final AngularSpeed initialBiasZ) throws LockedException {
2446         if (running) {
2447             throw new LockedException();
2448         }
2449         this.initialBiasZ = convertAngularSpeed(initialBiasZ);
2450     }
2451 
2452     /**
2453      * Sets initial bias coordinates of gyroscope used to find a solution
2454      * expressed in radians per second (rad/s).
2455      *
2456      * @param initialBiasX initial x-coordinate of gyroscope bias.
2457      * @param initialBiasY initial y-coordinate of gyroscope bias.
2458      * @param initialBiasZ initial z-coordinate of gyroscope bias.
2459      * @throws LockedException if calibrator is currently running.
2460      */
2461     @Override
2462     public void setInitialBias(final double initialBiasX, final double initialBiasY, final double initialBiasZ)
2463             throws LockedException {
2464         if (running) {
2465             throw new LockedException();
2466         }
2467         this.initialBiasX = initialBiasX;
2468         this.initialBiasY = initialBiasY;
2469         this.initialBiasZ = initialBiasZ;
2470     }
2471 
2472     /**
2473      * Sets initial bias coordinates of gyroscope used to find a solution.
2474      *
2475      * @param initialBiasX initial x-coordinate of gyroscope bias.
2476      * @param initialBiasY initial y-coordinate of gyroscope bias.
2477      * @param initialBiasZ initial z-coordinate of gyroscope bias.
2478      * @throws LockedException if calibrator is currently running.
2479      */
2480     @Override
2481     public void setInitialBias(
2482             final AngularSpeed initialBiasX, final AngularSpeed initialBiasY, final AngularSpeed initialBiasZ)
2483             throws LockedException {
2484 
2485         if (running) {
2486             throw new LockedException();
2487         }
2488         this.initialBiasX = convertAngularSpeed(initialBiasX);
2489         this.initialBiasY = convertAngularSpeed(initialBiasY);
2490         this.initialBiasZ = convertAngularSpeed(initialBiasZ);
2491     }
2492 
2493     /**
2494      * Gets initial x scaling factor.
2495      *
2496      * @return initial x scaling factor.
2497      */
2498     @Override
2499     public double getInitialSx() {
2500         return initialSx;
2501     }
2502 
2503     /**
2504      * Sets initial x scaling factor.
2505      *
2506      * @param initialSx initial x scaling factor.
2507      * @throws LockedException if calibrator is currently running.
2508      */
2509     @Override
2510     public void setInitialSx(final double initialSx) throws LockedException {
2511         if (running) {
2512             throw new LockedException();
2513         }
2514         this.initialSx = initialSx;
2515     }
2516 
2517     /**
2518      * Gets initial y scaling factor.
2519      *
2520      * @return initial y scaling factor.
2521      */
2522     @Override
2523     public double getInitialSy() {
2524         return initialSy;
2525     }
2526 
2527     /**
2528      * Sets initial y scaling factor.
2529      *
2530      * @param initialSy initial y scaling factor.
2531      * @throws LockedException if calibrator is currently running.
2532      */
2533     @Override
2534     public void setInitialSy(final double initialSy) throws LockedException {
2535         if (running) {
2536             throw new LockedException();
2537         }
2538         this.initialSy = initialSy;
2539     }
2540 
2541     /**
2542      * Gets initial z scaling factor.
2543      *
2544      * @return initial z scaling factor.
2545      */
2546     @Override
2547     public double getInitialSz() {
2548         return initialSz;
2549     }
2550 
2551     /**
2552      * Sets initial z scaling factor.
2553      *
2554      * @param initialSz initial z scaling factor.
2555      * @throws LockedException if calibrator is currently running.
2556      */
2557     @Override
2558     public void setInitialSz(final double initialSz) throws LockedException {
2559         if (running) {
2560             throw new LockedException();
2561         }
2562         this.initialSz = initialSz;
2563     }
2564 
2565     /**
2566      * Gets initial x-y cross coupling error.
2567      *
2568      * @return initial x-y cross coupling error.
2569      */
2570     @Override
2571     public double getInitialMxy() {
2572         return initialMxy;
2573     }
2574 
2575     /**
2576      * Sets initial x-y cross coupling error.
2577      *
2578      * @param initialMxy initial x-y cross coupling error.
2579      * @throws LockedException if calibrator is currently running.
2580      */
2581     @Override
2582     public void setInitialMxy(final double initialMxy) throws LockedException {
2583         if (running) {
2584             throw new LockedException();
2585         }
2586         this.initialMxy = initialMxy;
2587     }
2588 
2589     /**
2590      * Gets initial x-z cross coupling error.
2591      *
2592      * @return initial x-z cross coupling error.
2593      */
2594     @Override
2595     public double getInitialMxz() {
2596         return initialMxz;
2597     }
2598 
2599     /**
2600      * Sets initial x-z cross coupling error.
2601      *
2602      * @param initialMxz initial x-z cross coupling error.
2603      * @throws LockedException if calibrator is currently running.
2604      */
2605     @Override
2606     public void setInitialMxz(final double initialMxz) throws LockedException {
2607         if (running) {
2608             throw new LockedException();
2609         }
2610         this.initialMxz = initialMxz;
2611     }
2612 
2613     /**
2614      * Gets initial y-x cross coupling error.
2615      *
2616      * @return initial y-x cross coupling error.
2617      */
2618     @Override
2619     public double getInitialMyx() {
2620         return initialMyx;
2621     }
2622 
2623     /**
2624      * Sets initial y-x cross coupling error.
2625      *
2626      * @param initialMyx initial y-x cross coupling error.
2627      * @throws LockedException if calibrator is currently running.
2628      */
2629     @Override
2630     public void setInitialMyx(final double initialMyx) throws LockedException {
2631         if (running) {
2632             throw new LockedException();
2633         }
2634         this.initialMyx = initialMyx;
2635     }
2636 
2637     /**
2638      * Gets initial y-z cross coupling error.
2639      *
2640      * @return initial y-z cross coupling error.
2641      */
2642     @Override
2643     public double getInitialMyz() {
2644         return initialMyz;
2645     }
2646 
2647     /**
2648      * Sets initial y-z cross coupling error.
2649      *
2650      * @param initialMyz initial y-z cross coupling error.
2651      * @throws LockedException if calibrator is currently running.
2652      */
2653     @Override
2654     public void setInitialMyz(final double initialMyz) throws LockedException {
2655         if (running) {
2656             throw new LockedException();
2657         }
2658         this.initialMyz = initialMyz;
2659     }
2660 
2661     /**
2662      * Gets initial z-x cross coupling error.
2663      *
2664      * @return initial z-x cross coupling error.
2665      */
2666     @Override
2667     public double getInitialMzx() {
2668         return initialMzx;
2669     }
2670 
2671     /**
2672      * Sets initial z-x cross coupling error.
2673      *
2674      * @param initialMzx initial z-x cross coupling error.
2675      * @throws LockedException if calibrator is currently running.
2676      */
2677     @Override
2678     public void setInitialMzx(final double initialMzx) throws LockedException {
2679         if (running) {
2680             throw new LockedException();
2681         }
2682         this.initialMzx = initialMzx;
2683     }
2684 
2685     /**
2686      * Gets initial z-y cross coupling error.
2687      *
2688      * @return initial z-y cross coupling error.
2689      */
2690     @Override
2691     public double getInitialMzy() {
2692         return initialMzy;
2693     }
2694 
2695     /**
2696      * Sets initial z-y cross coupling error.
2697      *
2698      * @param initialMzy initial z-y cross coupling error.
2699      * @throws LockedException if calibrator is currently running.
2700      */
2701     @Override
2702     public void setInitialMzy(final double initialMzy) throws LockedException {
2703         if (running) {
2704             throw new LockedException();
2705         }
2706         this.initialMzy = initialMzy;
2707     }
2708 
2709     /**
2710      * Sets initial scaling factors.
2711      *
2712      * @param initialSx initial x scaling factor.
2713      * @param initialSy initial y scaling factor.
2714      * @param initialSz initial z scaling factor.
2715      * @throws LockedException if calibrator is currently running.
2716      */
2717     @Override
2718     public void setInitialScalingFactors(
2719             final double initialSx, final double initialSy, final double initialSz) throws LockedException {
2720         if (running) {
2721             throw new LockedException();
2722         }
2723         this.initialSx = initialSx;
2724         this.initialSy = initialSy;
2725         this.initialSz = initialSz;
2726     }
2727 
2728     /**
2729      * Sets initial cross coupling errors.
2730      *
2731      * @param initialMxy initial x-y cross coupling error.
2732      * @param initialMxz initial x-z cross coupling error.
2733      * @param initialMyx initial y-x cross coupling error.
2734      * @param initialMyz initial y-z cross coupling error.
2735      * @param initialMzx initial z-x cross coupling error.
2736      * @param initialMzy initial z-y cross coupling error.
2737      * @throws LockedException if calibrator is currently running.
2738      */
2739     @Override
2740     public void setInitialCrossCouplingErrors(
2741             final double initialMxy, final double initialMxz, final double initialMyx,
2742             final double initialMyz, final double initialMzx, final double initialMzy) throws LockedException {
2743         if (running) {
2744             throw new LockedException();
2745         }
2746         this.initialMxy = initialMxy;
2747         this.initialMxz = initialMxz;
2748         this.initialMyx = initialMyx;
2749         this.initialMyz = initialMyz;
2750         this.initialMzx = initialMzx;
2751         this.initialMzy = initialMzy;
2752     }
2753 
2754     /**
2755      * Sets initial scaling factors and cross coupling errors.
2756      *
2757      * @param initialSx  initial x scaling factor.
2758      * @param initialSy  initial y scaling factor.
2759      * @param initialSz  initial z scaling factor.
2760      * @param initialMxy initial x-y cross coupling error.
2761      * @param initialMxz initial x-z cross coupling error.
2762      * @param initialMyx initial y-x cross coupling error.
2763      * @param initialMyz initial y-z cross coupling error.
2764      * @param initialMzx initial z-x cross coupling error.
2765      * @param initialMzy initial z-y cross coupling error.
2766      * @throws LockedException if calibrator is currently running.
2767      */
2768     @Override
2769     public void setInitialScalingFactorsAndCrossCouplingErrors(
2770             final double initialSx, final double initialSy, final double initialSz,
2771             final double initialMxy, final double initialMxz, final double initialMyx,
2772             final double initialMyz, final double initialMzx, final double initialMzy) throws LockedException {
2773         if (running) {
2774             throw new LockedException();
2775         }
2776         setInitialScalingFactors(initialSx, initialSy, initialSz);
2777         setInitialCrossCouplingErrors(initialMxy, initialMxz, initialMyx, initialMyz, initialMzx, initialMzy);
2778     }
2779 
2780     /**
2781      * Gets initial bias to be used to find a solution as an array.
2782      * Array values are expressed in radians per second (rad/s).
2783      *
2784      * @return array containing coordinates of initial bias.
2785      */
2786     @Override
2787     public double[] getInitialBias() {
2788         final var result = new double[BodyKinematics.COMPONENTS];
2789         getInitialBias(result);
2790         return result;
2791     }
2792 
2793     /**
2794      * Gets initial bias to be used to find a solution as an array.
2795      * Array values are expressed in radians per second (rad/s).
2796      *
2797      * @param result instance where result data will be copied to.
2798      * @throws IllegalArgumentException if provided array does not have length 3.
2799      */
2800     @Override
2801     public void getInitialBias(final double[] result) {
2802         if (result.length != BodyKinematics.COMPONENTS) {
2803             throw new IllegalArgumentException();
2804         }
2805         result[0] = initialBiasX;
2806         result[1] = initialBiasY;
2807         result[2] = initialBiasZ;
2808     }
2809 
2810     /**
2811      * Sets initial bias to be used to find a solution as an array.
2812      * Array values are expressed in radians per second (rad/s).
2813      *
2814      * @param initialBias initial bias to find a solution.
2815      * @throws LockedException          if calibrator is currently running.
2816      * @throws IllegalArgumentException if provided array does not have length 3.
2817      */
2818     @Override
2819     public void setInitialBias(final double[] initialBias) throws LockedException {
2820         if (running) {
2821             throw new LockedException();
2822         }
2823 
2824         if (initialBias.length != BodyKinematics.COMPONENTS) {
2825             throw new IllegalArgumentException();
2826         }
2827         initialBiasX = initialBias[0];
2828         initialBiasY = initialBias[1];
2829         initialBiasZ = initialBias[2];
2830     }
2831 
2832     /**
2833      * Gets initial bias to be used to find a solution as a column matrix.
2834      * Values are expressed in radians per second (rad/s).
2835      *
2836      * @return initial bias to be used to find a solution as a column matrix.
2837      */
2838     @Override
2839     public Matrix getInitialBiasAsMatrix() {
2840         Matrix result;
2841         try {
2842             result = new Matrix(BodyKinematics.COMPONENTS, 1);
2843             getInitialBiasAsMatrix(result);
2844         } catch (final WrongSizeException ignore) {
2845             // never happens
2846             result = null;
2847         }
2848         return result;
2849     }
2850 
2851     /**
2852      * Gets initial bias to be used to find a solution as a column matrix.
2853      * Values are expressed in radians per second (rad/s).
2854      *
2855      * @param result instance where result data will be copied to.
2856      * @throws IllegalArgumentException if provided matrix is not 3x1.
2857      */
2858     @Override
2859     public void getInitialBiasAsMatrix(final Matrix result) {
2860         if (result.getRows() != BodyKinematics.COMPONENTS || result.getColumns() != 1) {
2861             throw new IllegalArgumentException();
2862         }
2863         result.setElementAtIndex(0, initialBiasX);
2864         result.setElementAtIndex(1, initialBiasY);
2865         result.setElementAtIndex(2, initialBiasZ);
2866     }
2867 
2868     /**
2869      * Sets initial bias to be used to find a solution as a column matrix
2870      * with values expressed in radians per second (rad/s).
2871      *
2872      * @param initialBias initial bias to find a solution.
2873      * @throws LockedException          if calibrator is currently running.
2874      * @throws IllegalArgumentException if provided matrix is not 3x1.
2875      */
2876     @Override
2877     public void setInitialBias(final Matrix initialBias) throws LockedException {
2878         if (running) {
2879             throw new LockedException();
2880         }
2881         if (initialBias.getRows() != BodyKinematics.COMPONENTS || initialBias.getColumns() != 1) {
2882             throw new IllegalArgumentException();
2883         }
2884 
2885         initialBiasX = initialBias.getElementAtIndex(0);
2886         initialBiasY = initialBias.getElementAtIndex(1);
2887         initialBiasZ = initialBias.getElementAtIndex(2);
2888     }
2889 
2890     /**
2891      * Gets initial bias coordinates of gyroscope used to find a solution.
2892      *
2893      * @return initial bias coordinates.
2894      */
2895     @Override
2896     public AngularSpeedTriad getInitialBiasAsTriad() {
2897         return new AngularSpeedTriad(AngularSpeedUnit.RADIANS_PER_SECOND, initialBiasX, initialBiasY, initialBiasZ);
2898     }
2899 
2900     /**
2901      * Gets initial bias coordinates of gyroscope used to find a solution.
2902      *
2903      * @param result instance where result will be stored.
2904      */
2905     @Override
2906     public void getInitialBiasAsTriad(final AngularSpeedTriad result) {
2907         result.setValueCoordinatesAndUnit(initialBiasX, initialBiasY, initialBiasZ,
2908                 AngularSpeedUnit.RADIANS_PER_SECOND);
2909     }
2910 
2911     /**
2912      * Sets initial bias coordinates of gyroscope used to find a solution.
2913      *
2914      * @param initialBias initial bias coordinates to be set.
2915      * @throws LockedException if calibrator is currently running.
2916      */
2917     @Override
2918     public void setInitialBias(final AngularSpeedTriad initialBias) throws LockedException {
2919         if (running) {
2920             throw new LockedException();
2921         }
2922 
2923         initialBiasX = convertAngularSpeed(initialBias.getValueX(), initialBias.getUnit());
2924         initialBiasY = convertAngularSpeed(initialBias.getValueY(), initialBias.getUnit());
2925         initialBiasZ = convertAngularSpeed(initialBias.getValueZ(), initialBias.getUnit());
2926     }
2927 
2928     /**
2929      * Gets initial scale factors and cross coupling errors matrix.
2930      *
2931      * @return initial scale factors and cross coupling errors matrix.
2932      */
2933     @Override
2934     public Matrix getInitialMg() {
2935         Matrix result;
2936         try {
2937             result = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
2938             getInitialMg(result);
2939         } catch (final WrongSizeException ignore) {
2940             // never happens
2941             result = null;
2942         }
2943         return result;
2944     }
2945 
2946     /**
2947      * Gets initial scale factors and cross coupling errors matrix.
2948      *
2949      * @param result instance where data will be stored.
2950      * @throws IllegalArgumentException if provided matrix is not 3x3.
2951      */
2952     @Override
2953     public void getInitialMg(final Matrix result) {
2954         if (result.getRows() != BodyKinematics.COMPONENTS || result.getColumns() != BodyKinematics.COMPONENTS) {
2955             throw new IllegalArgumentException();
2956         }
2957         result.setElementAtIndex(0, initialSx);
2958         result.setElementAtIndex(1, initialMyx);
2959         result.setElementAtIndex(2, initialMzx);
2960 
2961         result.setElementAtIndex(3, initialMxy);
2962         result.setElementAtIndex(4, initialSy);
2963         result.setElementAtIndex(5, initialMzy);
2964 
2965         result.setElementAtIndex(6, initialMxz);
2966         result.setElementAtIndex(7, initialMyz);
2967         result.setElementAtIndex(8, initialSz);
2968     }
2969 
2970     /**
2971      * Sets initial scale factors and cross coupling errors matrix.
2972      *
2973      * @param initialMg initial scale factors and cross coupling errors matrix.
2974      * @throws IllegalArgumentException if provided matrix is not 3x3.
2975      * @throws LockedException          if calibrator is currently running.
2976      */
2977     @Override
2978     public void setInitialMg(final Matrix initialMg) throws LockedException {
2979         if (running) {
2980             throw new LockedException();
2981         }
2982         if (initialMg.getRows() != BodyKinematics.COMPONENTS || initialMg.getColumns() != BodyKinematics.COMPONENTS) {
2983             throw new IllegalArgumentException();
2984         }
2985 
2986         initialSx = initialMg.getElementAtIndex(0);
2987         initialMyx = initialMg.getElementAtIndex(1);
2988         initialMzx = initialMg.getElementAtIndex(2);
2989 
2990         initialMxy = initialMg.getElementAtIndex(3);
2991         initialSy = initialMg.getElementAtIndex(4);
2992         initialMzy = initialMg.getElementAtIndex(5);
2993 
2994         initialMxz = initialMg.getElementAtIndex(6);
2995         initialMyz = initialMg.getElementAtIndex(7);
2996         initialSz = initialMg.getElementAtIndex(8);
2997     }
2998 
2999     /**
3000      * Gets initial G-dependent cross biases introduced on the gyroscope by the
3001      * specific forces sensed by the accelerometer.
3002      *
3003      * @return a 3x3 matrix containing initial g-dependent cross biases.
3004      */
3005     @Override
3006     public Matrix getInitialGg() {
3007         return new Matrix(initialGg);
3008     }
3009 
3010     /**
3011      * Gets initial G-dependent cross biases introduced on the gyroscope by the
3012      * specific forces sensed by the accelerometer.
3013      *
3014      * @param result instance where data will be stored.
3015      * @throws IllegalArgumentException if provided matrix is not 3x3.
3016      */
3017     @Override
3018     public void getInitialGg(final Matrix result) {
3019         if (result.getRows() != BodyKinematics.COMPONENTS || result.getColumns() != BodyKinematics.COMPONENTS) {
3020             throw new IllegalArgumentException();
3021         }
3022 
3023         result.copyFrom(initialGg);
3024     }
3025 
3026     /**
3027      * Sets initial G-dependent cross biases introduced on the gyroscope by the
3028      * specific forces sensed by the accelerometer.
3029      *
3030      * @param initialGg g-dependent cross biases.
3031      * @throws LockedException          if calibrator is currently running.
3032      * @throws IllegalArgumentException if provided matrix is not 3x3.
3033      */
3034     @Override
3035     public void setInitialGg(final Matrix initialGg) throws LockedException {
3036         if (running) {
3037             throw new LockedException();
3038         }
3039 
3040         if (initialGg.getRows() != BodyKinematics.COMPONENTS || initialGg.getColumns() != BodyKinematics.COMPONENTS) {
3041             throw new IllegalArgumentException();
3042         }
3043 
3044         initialGg.copyTo(this.initialGg);
3045     }
3046 
3047     /**
3048      * Gets a collection of body kinematics measurements taken at different
3049      * frames (positions, orientations and velocities) and containing the standard
3050      * deviations of accelerometer and gyroscope measurements.
3051      * If a single device IMU needs to be calibrated, typically all measurements are
3052      * taken at the same position, with zero velocity and multiple orientations.
3053      * However, if we just want to calibrate a given IMU model (e.g. obtain
3054      * an average and less precise calibration for the IMU of a given phone model),
3055      * we could take measurements collected throughout the planet at multiple positions
3056      * while the phone remains static (e.g. while charging), hence each measurement
3057      * position will change, velocity will remain zero and orientation will be
3058      * typically constant at horizontal orientation while the phone remains on a
3059      * flat surface.
3060      *
3061      * @return a collection of body kinematics measurements taken at different
3062      * frames (positions, orientations and velocities).
3063      */
3064     @Override
3065     public Collection<StandardDeviationFrameBodyKinematics> getMeasurements() {
3066         return measurements;
3067     }
3068 
3069     /**
3070      * Sets a collection of body kinematics measurements taken at different
3071      * frames (positions, orientations and velocities) and containing the standard
3072      * deviations of accelerometer and gyroscope measurements.
3073      * If a single device IMU needs to be calibrated, typically all measurements are
3074      * taken at the same position, with zero velocity and multiple orientations.
3075      * However, if we just want to calibrate a given IMU model (e.g. obtain
3076      * an average and less precise calibration for the IMU of a given phone model),
3077      * we could take measurements collected throughout the planet at multiple positions
3078      * while the phone remains static (e.g. while charging), hence each measurement
3079      * position will change, velocity will remain zero and orientation will be
3080      * typically constant at horizontal orientation while the phone remains on a
3081      * flat surface.
3082      *
3083      * @param measurements collection of body kinematics measurements taken at different
3084      *                     frames (positions, orientations and velocities).
3085      * @throws LockedException if calibrator is currently running.
3086      */
3087     @Override
3088     public void setMeasurements(
3089             final Collection<? extends StandardDeviationFrameBodyKinematics> measurements) throws LockedException {
3090         if (running) {
3091             throw new LockedException();
3092         }
3093         //noinspection unchecked
3094         this.measurements = (Collection<StandardDeviationFrameBodyKinematics>) measurements;
3095     }
3096 
3097     /**
3098      * Indicates the type of measurement or sequence used by this calibrator.
3099      *
3100      * @return type of measurement or sequence used by this calibrator.
3101      */
3102     @Override
3103     public GyroscopeCalibratorMeasurementOrSequenceType getMeasurementOrSequenceType() {
3104         return GyroscopeCalibratorMeasurementOrSequenceType.STANDARD_DEVIATION_FRAME_BODY_KINEMATICS_MEASUREMENT;
3105     }
3106 
3107     /**
3108      * Indicates whether this calibrator requires ordered measurements or sequences
3109      * in a list or not.
3110      *
3111      * @return true if measurements or sequences must be ordered, false otherwise.
3112      */
3113     @Override
3114     public boolean isOrderedMeasurementsOrSequencesRequired() {
3115         return false;
3116     }
3117 
3118     /**
3119      * Indicates whether this calibrator requires quality scores for each
3120      * measurement/sequence or not.
3121      *
3122      * @return true if quality scores are required, false otherwise.
3123      */
3124     @Override
3125     public boolean isQualityScoresRequired() {
3126         return false;
3127     }
3128 
3129     /**
3130      * Indicates whether z-axis is assumed to be common for accelerometer and
3131      * gyroscope.
3132      * When enabled, this eliminates 3 variables from Ma matrix.
3133      *
3134      * @return true if z-axis is assumed to be common for accelerometer and gyroscope,
3135      * false otherwise.
3136      */
3137     @Override
3138     public boolean isCommonAxisUsed() {
3139         return commonAxisUsed;
3140     }
3141 
3142     /**
3143      * Specifies whether z-axis is assumed to be common for accelerometer and
3144      * gyroscope.
3145      * When enabled, this eliminates 3 variables from Ma matrix.
3146      *
3147      * @param commonAxisUsed true if z-axis is assumed to be common for accelerometer
3148      *                       and gyroscope, false otherwise.
3149      * @throws LockedException if calibrator is currently running.
3150      */
3151     @Override
3152     public void setCommonAxisUsed(final boolean commonAxisUsed) throws LockedException {
3153         if (running) {
3154             throw new LockedException();
3155         }
3156 
3157         this.commonAxisUsed = commonAxisUsed;
3158     }
3159 
3160     /**
3161      * Gets listener to handle events raised by this estimator.
3162      *
3163      * @return listener to handle events raised by this estimator.
3164      */
3165     @Override
3166     public KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener getListener() {
3167         return listener;
3168     }
3169 
3170     /**
3171      * Sets listener to handle events raised by this estimator.
3172      *
3173      * @param listener listener to handle events raised by this estimator.
3174      * @throws LockedException if calibrator is currently running.
3175      */
3176     @Override
3177     public void setListener(
3178             final KnownFrameGyroscopeNonLinearLeastSquaresCalibratorListener listener) throws LockedException {
3179         if (running) {
3180             throw new LockedException();
3181         }
3182 
3183         this.listener = listener;
3184     }
3185 
3186     /**
3187      * Gets minimum number of required measurements.
3188      *
3189      * @return minimum number of required measurements.
3190      */
3191     @Override
3192     public int getMinimumRequiredMeasurementsOrSequences() {
3193         return MINIMUM_MEASUREMENTS;
3194     }
3195 
3196     /**
3197      * Indicates whether calibrator is ready to start.
3198      *
3199      * @return true if calibrator is ready, false otherwise.
3200      */
3201     @Override
3202     public boolean isReady() {
3203         return measurements != null && measurements.size() >= MINIMUM_MEASUREMENTS;
3204     }
3205 
3206     /**
3207      * Indicates whether calibrator is currently running or not.
3208      *
3209      * @return true if calibrator is running, false otherwise.
3210      */
3211     @Override
3212     public boolean isRunning() {
3213         return running;
3214     }
3215 
3216     /**
3217      * Estimates gyroscope calibration parameters containing bias, scale factors,
3218      * cross-coupling errors and G-dependent coupling.
3219      *
3220      * @throws LockedException      if calibrator is currently running.
3221      * @throws NotReadyException    if calibrator is not ready.
3222      * @throws CalibrationException if estimation fails for numerical reasons.
3223      */
3224     @Override
3225     public void calibrate() throws LockedException, NotReadyException, CalibrationException {
3226         if (running) {
3227             throw new LockedException();
3228         }
3229 
3230         if (!isReady()) {
3231             throw new NotReadyException();
3232         }
3233 
3234         try {
3235             running = true;
3236 
3237             if (listener != null) {
3238                 listener.onCalibrateStart(this);
3239             }
3240 
3241             if (commonAxisUsed) {
3242                 calibrateCommonAxis();
3243             } else {
3244                 calibrateGeneral();
3245             }
3246 
3247             if (listener != null) {
3248                 listener.onCalibrateEnd(this);
3249             }
3250 
3251         } catch (final AlgebraException | FittingException | com.irurueta.numerical.NotReadyException e) {
3252             throw new CalibrationException(e);
3253         } finally {
3254             running = false;
3255         }
3256     }
3257 
3258     /**
3259      * Gets array containing x,y,z components of estimated gyroscope biases
3260      * expressed in radians per second (rad/s).
3261      *
3262      * @return array containing x,y,z components of estimated gyroscope biases.
3263      */
3264     @Override
3265     public double[] getEstimatedBiases() {
3266         return estimatedBiases;
3267     }
3268 
3269     /**
3270      * Gets array containing x,y,z components of estimated gyroscope biases
3271      * expressed in radians per second (rad/s).
3272      *
3273      * @param result instance where estimated gyroscope biases will be stored.
3274      * @return true if result instance was updated, false otherwise (when estimation
3275      * is not yet available).
3276      */
3277     @Override
3278     public boolean getEstimatedBiases(final double[] result) {
3279         if (estimatedBiases != null) {
3280             System.arraycopy(estimatedBiases, 0, result, 0, estimatedBiases.length);
3281             return true;
3282         } else {
3283             return false;
3284         }
3285     }
3286 
3287     /**
3288      * Gets column matrix containing x,y,z components of estimated gyroscope biases
3289      * expressed in radians per second (rad/s).
3290      *
3291      * @return column matrix containing x,y,z components of estimated gyroscope
3292      * biases.
3293      */
3294     @Override
3295     public Matrix getEstimatedBiasesAsMatrix() {
3296         return estimatedBiases != null ? Matrix.newFromArray(estimatedBiases) : null;
3297     }
3298 
3299     /**
3300      * Gets column matrix containing x,y,z components of estimated gyroscope biases
3301      * expressed in radians per second (rad/s).
3302      *
3303      * @param result instance where result data will be stored.
3304      * @return true if result was updated, false otherwise.
3305      * @throws WrongSizeException if provided result instance has invalid size.
3306      */
3307     @Override
3308     public boolean getEstimatedBiasesAsMatrix(final Matrix result) throws WrongSizeException {
3309         if (estimatedBiases != null) {
3310             result.fromArray(estimatedBiases);
3311             return true;
3312         } else {
3313             return false;
3314         }
3315     }
3316 
3317     /**
3318      * Gets x coordinate of estimated gyroscope bias expressed in radians per
3319      * second (rad/s).
3320      *
3321      * @return x coordinate of estimated gyroscope bias or null if not available.
3322      */
3323     @Override
3324     public Double getEstimatedBiasX() {
3325         return estimatedBiases != null ? estimatedBiases[0] : null;
3326     }
3327 
3328     /**
3329      * Gets y coordinate of estimated gyroscope bias expressed in radians per
3330      * second (rad/s).
3331      *
3332      * @return y coordinate of estimated gyroscope bias or null if not available.
3333      */
3334     @Override
3335     public Double getEstimatedBiasY() {
3336         return estimatedBiases != null ? estimatedBiases[1] : null;
3337     }
3338 
3339     /**
3340      * Gets z coordinate of estimated gyroscope bias expressed in radians per
3341      * second (rad/s).
3342      *
3343      * @return z coordinate of estimated gyroscope bias or null if not available.
3344      */
3345     @Override
3346     public Double getEstimatedBiasZ() {
3347         return estimatedBiases != null ? estimatedBiases[2] : null;
3348     }
3349 
3350     /**
3351      * Gets x coordinate of estimated gyroscope bias.
3352      *
3353      * @return x coordinate of estimated gyroscope bias or null if not available.
3354      */
3355     @Override
3356     public AngularSpeed getEstimatedBiasAngularSpeedX() {
3357         return estimatedBiases != null
3358                 ? new AngularSpeed(estimatedBiases[0], AngularSpeedUnit.RADIANS_PER_SECOND) : null;
3359     }
3360 
3361     /**
3362      * Gets x coordinate of estimated gyroscope bias.
3363      *
3364      * @param result instance where result will be stored.
3365      * @return true if result was updated, false if estimation is not available.
3366      */
3367     @Override
3368     public boolean getEstimatedBiasAngularSpeedX(final AngularSpeed result) {
3369         if (estimatedBiases != null) {
3370             result.setValue(estimatedBiases[0]);
3371             result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
3372             return true;
3373         } else {
3374             return false;
3375         }
3376     }
3377 
3378     /**
3379      * Gets y coordinate of estimated gyroscope bias.
3380      *
3381      * @return y coordinate of estimated gyroscope bias or null if not available.
3382      */
3383     @Override
3384     public AngularSpeed getEstimatedBiasAngularSpeedY() {
3385         return estimatedBiases != null
3386                 ? new AngularSpeed(estimatedBiases[1], AngularSpeedUnit.RADIANS_PER_SECOND) : null;
3387     }
3388 
3389     /**
3390      * Gets y coordinate of estimated gyroscope bias.
3391      *
3392      * @param result instance where result will be stored.
3393      * @return true if result was updated, false if estimation is not available.
3394      */
3395     @Override
3396     public boolean getEstimatedBiasAngularSpeedY(final AngularSpeed result) {
3397         if (estimatedBiases != null) {
3398             result.setValue(estimatedBiases[1]);
3399             result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
3400             return true;
3401         } else {
3402             return false;
3403         }
3404     }
3405 
3406     /**
3407      * Gets z coordinate of estimated gyroscope bias.
3408      *
3409      * @return z coordinate of estimated gyroscope bias or null if not available.
3410      */
3411     @Override
3412     public AngularSpeed getEstimatedBiasAngularSpeedZ() {
3413         return estimatedBiases != null
3414                 ? new AngularSpeed(estimatedBiases[2], AngularSpeedUnit.RADIANS_PER_SECOND) : null;
3415     }
3416 
3417     /**
3418      * Gets z coordinate of estimated gyroscope bias.
3419      *
3420      * @param result instance where result will be stored.
3421      * @return true if result was updated, false if estimation is not available.
3422      */
3423     @Override
3424     public boolean getEstimatedBiasAngularSpeedZ(final AngularSpeed result) {
3425         if (estimatedBiases != null) {
3426             result.setValue(estimatedBiases[2]);
3427             result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
3428             return true;
3429         } else {
3430             return false;
3431         }
3432     }
3433 
3434     /**
3435      * Gets estimated gyroscope bias.
3436      *
3437      * @return estimated gyroscope bias or null if not available.
3438      */
3439     @Override
3440     public AngularSpeedTriad getEstimatedBiasAsTriad() {
3441         return estimatedBiases != null
3442                 ? new AngularSpeedTriad(AngularSpeedUnit.RADIANS_PER_SECOND,
3443                 estimatedBiases[0], estimatedBiases[1], estimatedBiases[2])
3444                 : null;
3445     }
3446 
3447     /**
3448      * Gets estimated gyroscope bias.
3449      *
3450      * @param result instance where result will be stored.
3451      * @return true if estimated gyroscope bias is available and result was
3452      * modified, false otherwise.
3453      */
3454     @Override
3455     public boolean getEstimatedBiasAsTriad(final AngularSpeedTriad result) {
3456         if (estimatedBiases != null) {
3457             result.setValueCoordinatesAndUnit(
3458                     estimatedBiases[0], estimatedBiases[1], estimatedBiases[2],
3459                     AngularSpeedUnit.RADIANS_PER_SECOND);
3460             return true;
3461         } else {
3462             return false;
3463         }
3464     }
3465 
3466     /**
3467      * Gets estimated gyroscope scale factors and cross coupling errors.
3468      * This is the product of matrix Tg containing cross coupling errors and Kg
3469      * containing scaling factors.
3470      * So that:
3471      * <pre>
3472      *     Mg = [sx    mxy  mxz] = Tg*Kg
3473      *          [myx   sy   myz]
3474      *          [mzx   mzy  sz ]
3475      * </pre>
3476      * Where:
3477      * <pre>
3478      *     Kg = [sx 0   0 ]
3479      *          [0  sy  0 ]
3480      *          [0  0   sz]
3481      * </pre>
3482      * and
3483      * <pre>
3484      *     Tg = [1          -alphaXy    alphaXz ]
3485      *          [alphaYx    1           -alphaYz]
3486      *          [-alphaZx   alphaZy     1       ]
3487      * </pre>
3488      * Hence:
3489      * <pre>
3490      *     Mg = [sx    mxy  mxz] = Tg*Kg =  [sx             -sy * alphaXy   sz * alphaXz ]
3491      *          [myx   sy   myz]            [sx * alphaYx   sy              -sz * alphaYz]
3492      *          [mzx   mzy  sz ]            [-sx * alphaZx  sy * alphaZy    sz           ]
3493      * </pre>
3494      * This instance allows any 3x3 matrix however, typically alphaYx, alphaZx and alphaZy
3495      * are considered to be zero if the gyroscope z-axis is assumed to be the same
3496      * as the body z-axis. When this is assumed, myx = mzx = mzy = 0 and the Mg matrix
3497      * becomes upper diagonal:
3498      * <pre>
3499      *     Mg = [sx    mxy  mxz]
3500      *          [0     sy   myz]
3501      *          [0     0    sz ]
3502      * </pre>
3503      * Values of this matrix are unit-less.
3504      *
3505      * @return estimated gyroscope scale factors and cross coupling errors, or null
3506      * if not available.
3507      */
3508     @Override
3509     public Matrix getEstimatedMg() {
3510         return estimatedMg;
3511     }
3512 
3513     /**
3514      * Gets estimated x-axis scale factor.
3515      *
3516      * @return estimated x-axis scale factor or null if not available.
3517      */
3518     @Override
3519     public Double getEstimatedSx() {
3520         return estimatedMg != null ? estimatedMg.getElementAt(0, 0) : null;
3521     }
3522 
3523     /**
3524      * Gets estimated y-axis scale factor.
3525      *
3526      * @return estimated y-axis scale factor or null if not available.
3527      */
3528     @Override
3529     public Double getEstimatedSy() {
3530         return estimatedMg != null
3531                 ? estimatedMg.getElementAt(1, 1) : null;
3532     }
3533 
3534     /**
3535      * Gets estimated z-axis scale factor.
3536      *
3537      * @return estimated z-axis scale factor or null if not available.
3538      */
3539     @Override
3540     public Double getEstimatedSz() {
3541         return estimatedMg != null ? estimatedMg.getElementAt(2, 2) : null;
3542     }
3543 
3544     /**
3545      * Gets estimated x-y cross-coupling error.
3546      *
3547      * @return estimated x-y cross-coupling error or null if not available.
3548      */
3549     @Override
3550     public Double getEstimatedMxy() {
3551         return estimatedMg != null ? estimatedMg.getElementAt(0, 1) : null;
3552     }
3553 
3554     /**
3555      * Gets estimated x-z cross-coupling error.
3556      *
3557      * @return estimated x-z cross-coupling error or null if not available.
3558      */
3559     @Override
3560     public Double getEstimatedMxz() {
3561         return estimatedMg != null ? estimatedMg.getElementAt(0, 2) : null;
3562     }
3563 
3564     /**
3565      * Gets estimated y-x cross-coupling error.
3566      *
3567      * @return estimated y-x cross-coupling error or null if not available.
3568      */
3569     @Override
3570     public Double getEstimatedMyx() {
3571         return estimatedMg != null ? estimatedMg.getElementAt(1, 0) : null;
3572     }
3573 
3574     /**
3575      * Gets estimated y-z cross-coupling error.
3576      *
3577      * @return estimated y-z cross-coupling error or null if not available.
3578      */
3579     @Override
3580     public Double getEstimatedMyz() {
3581         return estimatedMg != null ? estimatedMg.getElementAt(1, 2) : null;
3582     }
3583 
3584     /**
3585      * Gets estimated z-x cross-coupling error.
3586      *
3587      * @return estimated z-x cross-coupling error or null if not available.
3588      */
3589     @Override
3590     public Double getEstimatedMzx() {
3591         return estimatedMg != null ? estimatedMg.getElementAt(2, 0) : null;
3592     }
3593 
3594     /**
3595      * Gets estimated z-y cross-coupling error.
3596      *
3597      * @return estimated z-y cross-coupling error or null if not available.
3598      */
3599     @Override
3600     public Double getEstimatedMzy() {
3601         return estimatedMg != null ? estimatedMg.getElementAt(2, 1) : null;
3602     }
3603 
3604     /**
3605      * Gets estimated G-dependent cross biases introduced on the gyroscope by the
3606      * specific forces sensed by the accelerometer.
3607      * This instance allows any 3x3 matrix.
3608      *
3609      * @return estimated G-dependent cross biases.
3610      */
3611     @Override
3612     public Matrix getEstimatedGg() {
3613         return estimatedGg;
3614     }
3615 
3616     /**
3617      * Gets estimated covariance matrix for estimated parameters.
3618      * Diagonal elements of the matrix contains variance for the following
3619      * parameters (following indicated order): bgx, bgy, bgz, sx, sy, sz,
3620      * mxy, mxz, myx, myz, mzx, mzy, gg11, gg21, gg31, gg12, gg22, gg32,
3621      * gg13, gg23, gg33.
3622      *
3623      * @return estimated covariance matrix for estimated parameters.
3624      */
3625     @Override
3626     public Matrix getEstimatedCovariance() {
3627         return estimatedCovariance;
3628     }
3629 
3630     /**
3631      * Gets estimated chi square value.
3632      *
3633      * @return estimated chi square value.
3634      */
3635     @Override
3636     public double getEstimatedChiSq() {
3637         return estimatedChiSq;
3638     }
3639 
3640     /**
3641      * Gets estimated chi square degrees of freedom. Degrees of freedom is equal to the number of sampled data minus the
3642      * number of estimated parameters.
3643      *
3644      * @return estimated degrees of freedom of chi square value
3645      */
3646     @Override
3647     public int getEstimatedChiSqDegreesOfFreedom() {
3648         return estimatedChiSqDegreesOfFreedom;
3649     }
3650 
3651     /**
3652      * Gets estimated reduced chi square value. This is equal to estimated chi square value divided by its degrees of
3653      * freedom. Ideally this value should be close to 1.0, indicating that fit is optimal.
3654      * A value larger than 1.0 indicates that fit is not good or noise has been underestimated, and a value smaller than
3655      * 1.0 indicates that there is overfitting or noise has been overestimated.
3656      *
3657      * @return estimated reduced chi square value
3658      */
3659     @Override
3660     public double getEstimatedReducedChiSq() {
3661         return estimatedReducedChiSq;
3662     }
3663 
3664     /**
3665      * Gets estimated mean square error respect to provided measurements.
3666      *
3667      * @return estimated mean square error respect to provided measurements.
3668      */
3669     @Override
3670     public double getEstimatedMse() {
3671         return estimatedMse;
3672     }
3673 
3674     /**
3675      * Gets estimated probability of finding a smaller chi square value expressed as a value between 0.0 and 1.0. The
3676      * smaller the found chi square value is, the better the fit of the estimated parameters to the actual parameter.
3677      * Thus, the smaller the chance of finding a smaller chi square value, then the better the estimated fit is.
3678      *
3679      * @return estimated probability of finding a smaller chi square value.
3680      */
3681     @Override
3682     public double getEstimatedP() {
3683         return estimatedP;
3684     }
3685 
3686     /**
3687      * Gets estimated measure of quality of estimated fit as a value between 0.0 and 1.0. The larger the quality value
3688      * is, the better the fit that has been estimated.
3689      *
3690      * @return estimated measure of quality of estimated fit.
3691      */
3692     @Override
3693     public double getEstimatedQ() {
3694         return estimatedQ;
3695     }
3696 
3697     /**
3698      * Gets variance of estimated x coordinate of gyroscope bias expressed in (rad^2/s^2).
3699      *
3700      * @return variance of estimated x coordinate of gyroscope bias or null if not available.
3701      */
3702     public Double getEstimatedBiasXVariance() {
3703         return estimatedCovariance != null ? estimatedCovariance.getElementAt(0, 0) : null;
3704     }
3705 
3706     /**
3707      * Gets standard deviation of estimated x coordinate of gyroscope bias expressed in
3708      * radians per second (rad/s).
3709      *
3710      * @return standard deviation of estimated x coordinate of gyroscope bias or null if not
3711      * available.
3712      */
3713     public Double getEstimatedBiasXStandardDeviation() {
3714         final var variance = getEstimatedBiasXVariance();
3715         return variance != null ? Math.sqrt(variance) : null;
3716     }
3717 
3718     /**
3719      * Gets standard deviation of estimated x coordinate of gyroscope bias.
3720      *
3721      * @return standard deviation of estimated x coordinate of gyroscope bias or null if not
3722      * available.
3723      */
3724     public AngularSpeed getEstimatedBiasXStandardDeviationAsAngularSpeed() {
3725         return estimatedCovariance != null
3726                 ? new AngularSpeed(getEstimatedBiasXStandardDeviation(), AngularSpeedUnit.RADIANS_PER_SECOND)
3727                 : null;
3728     }
3729 
3730     /**
3731      * Gets standard deviation of estimated x coordinate of gyroscope bias.
3732      *
3733      * @param result instance where result will be stored.
3734      * @return true if standard deviation of estimated x coordinate of gyroscope bias is available,
3735      * false otherwise.
3736      */
3737     public boolean getEstimatedBiasXStandardDeviationAsAngularSpeed(final AngularSpeed result) {
3738         if (estimatedCovariance != null) {
3739             result.setValue(getEstimatedBiasXStandardDeviation());
3740             result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
3741             return true;
3742         } else {
3743             return false;
3744         }
3745     }
3746 
3747     /**
3748      * Gets variance of estimated y coordinate of gyroscope bias expressed in (rad^2/s^2).
3749      *
3750      * @return variance of estimated y coordinate of gyroscope bias or null if not available.
3751      */
3752     public Double getEstimatedBiasYVariance() {
3753         return estimatedCovariance != null ? estimatedCovariance.getElementAt(1, 1) : null;
3754     }
3755 
3756     /**
3757      * Gets standard deviation of estimated y coordinate of gyroscope bias expressed in
3758      * radians per second (rad/s).
3759      *
3760      * @return standard deviation of estimated y coordinate of gyroscope bias or null if not
3761      * available.
3762      */
3763     public Double getEstimatedBiasYStandardDeviation() {
3764         final var variance = getEstimatedBiasYVariance();
3765         return variance != null ? Math.sqrt(variance) : null;
3766     }
3767 
3768     /**
3769      * Gets standard deviation of estimated y coordinate of gyroscope bias.
3770      *
3771      * @return standard deviation of estimated y coordinate of gyroscope bias or null if not
3772      * available.
3773      */
3774     public AngularSpeed getEstimatedBiasYStandardDeviationAsAngularSpeed() {
3775         return estimatedCovariance != null
3776                 ? new AngularSpeed(getEstimatedBiasYStandardDeviation(), AngularSpeedUnit.RADIANS_PER_SECOND)
3777                 : null;
3778     }
3779 
3780     /**
3781      * Gets standard deviation of estimated y coordinate of gyroscope bias.
3782      *
3783      * @param result instance where result will be stored.
3784      * @return true if standard deviation of estimated y coordinate of gyroscope bias is available,
3785      * false otherwise.
3786      */
3787     public boolean getEstimatedBiasYStandardDeviationAsAngularSpeed(final AngularSpeed result) {
3788         if (estimatedCovariance != null) {
3789             result.setValue(getEstimatedBiasYStandardDeviation());
3790             result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
3791             return true;
3792         } else {
3793             return false;
3794         }
3795     }
3796 
3797     /**
3798      * Gets variance of estimated z coordinate of gyroscope bias expressed in (rad^2/s^2).
3799      *
3800      * @return variance of estimated z coordinate of gyroscope bias or null if not available.
3801      */
3802     public Double getEstimatedBiasZVariance() {
3803         return estimatedCovariance != null ? estimatedCovariance.getElementAt(2, 2) : null;
3804     }
3805 
3806     /**
3807      * Gets standard deviation of estimated z coordinate of gyroscope bias expressed in
3808      * radians per second (rad/s).
3809      *
3810      * @return standard deviation of estimated z coordinate of gyroscope bias or null if not
3811      * available.
3812      */
3813     public Double getEstimatedBiasZStandardDeviation() {
3814         final var variance = getEstimatedBiasZVariance();
3815         return variance != null ? Math.sqrt(variance) : null;
3816     }
3817 
3818     /**
3819      * Gets standard deviation of estimated z coordinate of gyroscope bias.
3820      *
3821      * @return standard deviation of estimated z coordinate of gyroscope bias or null if not
3822      * available.
3823      */
3824     public AngularSpeed getEstimatedBiasZStandardDeviationAsAngularSpeed() {
3825         return estimatedCovariance != null
3826                 ? new AngularSpeed(getEstimatedBiasZStandardDeviation(), AngularSpeedUnit.RADIANS_PER_SECOND)
3827                 : null;
3828     }
3829 
3830     /**
3831      * Gets standard deviation of estimated z coordinate of gyroscope bias.
3832      *
3833      * @param result instance where result will be stored.
3834      * @return true if standard deviation of estimated z coordinate of gyroscope bias is available,
3835      * false otherwise.
3836      */
3837     public boolean getEstimatedBiasZStandardDeviationAsAngularSpeed(final AngularSpeed result) {
3838         if (estimatedCovariance != null) {
3839             result.setValue(getEstimatedBiasZStandardDeviation());
3840             result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
3841             return true;
3842         } else {
3843             return false;
3844         }
3845     }
3846 
3847     /**
3848      * Gets standard deviation of estimated gyroscope bias coordinates.
3849      *
3850      * @return standard deviation of estimated gyroscope bias coordinates.
3851      */
3852     public AngularSpeedTriad getEstimatedBiasStandardDeviation() {
3853         return estimatedCovariance != null
3854                 ? new AngularSpeedTriad(AngularSpeedUnit.RADIANS_PER_SECOND,
3855                 getEstimatedBiasXStandardDeviation(),
3856                 getEstimatedBiasYStandardDeviation(),
3857                 getEstimatedBiasZStandardDeviation())
3858                 : null;
3859     }
3860 
3861     /**
3862      * Gets standard deviation of estimated gyroscope bias coordinates.
3863      *
3864      * @param result instance where result will be stored.
3865      * @return true if standard deviation of gyroscope bias was available, false
3866      * otherwise.
3867      */
3868     public boolean getEstimatedBiasStandardDeviation(final AngularSpeedTriad result) {
3869         if (estimatedCovariance != null) {
3870             result.setValueCoordinatesAndUnit(
3871                     getEstimatedBiasXStandardDeviation(),
3872                     getEstimatedBiasYStandardDeviation(),
3873                     getEstimatedBiasZStandardDeviation(),
3874                     AngularSpeedUnit.RADIANS_PER_SECOND);
3875             return true;
3876         } else {
3877             return false;
3878         }
3879     }
3880 
3881     /**
3882      * Gets average of estimated standard deviation of gyroscope bias coordinates expressed
3883      * in radians per second (rad/s).
3884      *
3885      * @return average of estimated standard deviation of gyroscope bias coordinates or null
3886      * if not available.
3887      */
3888     public Double getEstimatedBiasStandardDeviationAverage() {
3889         return estimatedCovariance != null
3890                 ? (getEstimatedBiasXStandardDeviation() + getEstimatedBiasYStandardDeviation()
3891                 + getEstimatedBiasZStandardDeviation()) / 3.0
3892                 : null;
3893     }
3894 
3895     /**
3896      * Gets average of estimated standard deviation of gyroscope bias coordinates.
3897      *
3898      * @return average of estimated standard deviation of gyroscope bias coordinates or null.
3899      */
3900     public AngularSpeed getEstimatedBiasStandardDeviationAverageAsAngularSpeed() {
3901         return estimatedCovariance != null
3902                 ? new AngularSpeed(getEstimatedBiasStandardDeviationAverage(), AngularSpeedUnit.RADIANS_PER_SECOND)
3903                 : null;
3904     }
3905 
3906     /**
3907      * Gets average of estimated standard deviation of gyroscope bias coordinates.
3908      *
3909      * @param result instance where result will be stored.
3910      * @return true if average of estimated standard deviation of gyroscope bias is available,
3911      * false otherwise.
3912      */
3913     public boolean getEstimatedBiasStandardDeviationAverageAsAngularSpeed(final AngularSpeed result) {
3914         if (estimatedCovariance != null) {
3915             result.setValue(getEstimatedBiasStandardDeviationAverage());
3916             result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
3917             return true;
3918         } else {
3919             return false;
3920         }
3921     }
3922 
3923     /**
3924      * Gets norm of estimated standard deviation of gyroscope bias expressed in
3925      * radians per second (rad/s).
3926      * This can be used as the initial gyroscope bias uncertainty for
3927      * {@link INSLooselyCoupledKalmanInitializerConfig} or {@link INSTightlyCoupledKalmanInitializerConfig}.
3928      *
3929      * @return norm of estimated standard deviation of gyroscope bias or null
3930      * if not available.
3931      */
3932     @Override
3933     public Double getEstimatedBiasStandardDeviationNorm() {
3934         return estimatedCovariance != null
3935                 ? Math.sqrt(getEstimatedBiasXVariance() + getEstimatedBiasYVariance() + getEstimatedBiasZVariance())
3936                 : null;
3937     }
3938 
3939     /**
3940      * Gets norm of estimated standard deviation of gyroscope bias.
3941      * This can be used as the initial gyroscope bias uncertainty for
3942      * {@link INSLooselyCoupledKalmanInitializerConfig} or {@link INSTightlyCoupledKalmanInitializerConfig}.
3943      *
3944      * @return norm of estimated standard deviation of gyroscope bias or null
3945      * if not available.
3946      */
3947     public AngularSpeed getEstimatedBiasStandardDeviationNormAsAngularSpeed() {
3948         return estimatedCovariance != null
3949                 ? new AngularSpeed(getEstimatedBiasStandardDeviationNorm(), AngularSpeedUnit.RADIANS_PER_SECOND)
3950                 : null;
3951     }
3952 
3953     /**
3954      * Gets norm of estimated standard deviation of gyroscope bias coordinates.
3955      * This can be used as the initial gyroscope bias uncertainty for
3956      * {@link INSLooselyCoupledKalmanInitializerConfig} or {@link INSTightlyCoupledKalmanInitializerConfig}.
3957      *
3958      * @param result instance where result will be stored.
3959      * @return true if norm of estimated standard deviation of gyroscope bias is
3960      * available, false otherwise.
3961      */
3962     public boolean getEstimatedBiasStandardDeviationNormAsAngularSpeed(final AngularSpeed result) {
3963         if (estimatedCovariance != null) {
3964             result.setValue(getEstimatedBiasStandardDeviationNorm());
3965             result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
3966             return true;
3967         } else {
3968             return false;
3969         }
3970     }
3971 
3972     /**
3973      * Internal method to perform calibration when common z-axis is assumed for both
3974      * the accelerometer and gyroscope.
3975      *
3976      * @throws AlgebraException                         if there are numerical errors.
3977      * @throws FittingException                         if no convergence to solution is found.
3978      * @throws com.irurueta.numerical.NotReadyException if fitter is not ready.
3979      */
3980     private void calibrateCommonAxis() throws AlgebraException, FittingException,
3981             com.irurueta.numerical.NotReadyException {
3982 
3983         // The gyroscope model is:
3984         // Ωmeas = bg + (I + Mg) * Ωtrue + Gg * ftrue + w
3985 
3986         // Ideally a least squares solution tries to minimize noise component, so:
3987         // Ωmeas = bg + (I + Mg) * Ωtrue + Gg * ftrue
3988 
3989         // where myx = mzx = mzy = 0
3990 
3991         // Hence:
3992         // [Ωmeasx] = [bx] + ( [1   0   0] + [sx    mxy    mxz]) [Ωtruex] + [g11   g12   g13][ftruex]
3993         // [Ωmeasy]   [by]     [0   1   0]   [0     sy     myz]  [Ωtruey]   [g21   g22   g23][ftruey]
3994         // [Ωmeasz]   [bz]     [0   0   1]   [0     0      sz ]  [Ωtruez]   [g31   g32   g33][ftruez]
3995 
3996         // [Ωmeasx] = [bx] + ( [1+sx  mxy    mxz ]) [Ωtruex] + [g11   g12   g13][ftruex]
3997         // [Ωmeasy]   [by]     [0     1+sy   myz ]  [Ωtruey]   [g21   g22   g23][ftruey]
3998         // [Ωmeasz]   [bz]     [0     0      1+sz]  [Ωtruez]   [g31   g32   g33][ftruez]
3999 
4000         // Ωmeasx = bx + (1+sx) * Ωtruex + mxy * Ωtruey + mxz * Ωtruez + g11 * ftruex + g12 * ftruey + g13 * ftruez
4001         // Ωmeasy = by + (1+sy) * Ωtruey + myz * Ωtruez + g21 * ftruex * g22 * ftruey + g23 * ftruez
4002         // Ωmeasz = bz + (1+sz) * Ωtruez + g31 * ftruex + g32 * ftruey + g33 * ftruez
4003 
4004         // Where the unknowns are: bx, by, bz, sx, sy, sz, mxy mxz, myz, g11, g12, g13, g21, g22, g23, g31, g32, g33
4005         // Reordering:
4006         // Ωmeasx = bx + Ωtruex + sx * Ωtruex + mxy * Ωtruey + mxz * Ωtruez + g11 * ftruex + g12 * ftruey + g13 * ftruez
4007         // Ωmeasy = by + Ωtruey + sy * Ωtruey + myz * Ωtruez + g21 * ftruex * g22 * ftruey + g23 * ftruez
4008         // Ωmeasz = bz + Ωtruez + sz * Ωtruez + g31 * ftruex + g32 * ftruey + g33 * ftruez
4009 
4010         // Ωmeasx - Ωtruex = bx + sx * Ωtruex + mxy * Ωtruey + mxz * Ωtruez + g11 * ftruex + g12 * ftruey + g13 * ftruez
4011         // Ωmeasy - Ωtruey = by + sy * Ωtruey + myz * Ωtruez + g21 * ftruex * g22 * ftruey + g23 * ftruez
4012         // Ωmeasz - Ωtruez = bz + sz * Ωtruez + g31 * ftruex + g32 * ftruey + g33 * ftruez
4013 
4014         // [1   0   0   Ωtruex  0       0       Ωtruey  Ωtruez  0       ftruex  ftruey  ftruez  0       0       0       0       0       0     ][bx ] =  [Ωmeasx - Ωtruex]
4015         // [0   1   0   0       Ωtruey  0       0       0       Ωtruez  0       0       0       ftruex  ftruey  ftruez  0       0       0     ][by ]    [Ωmeasy - Ωtruey]
4016         // [0   0   1   0       0       Ωtruez  0       0       0       0       0       0       0       0       0       ftruex  ftruey  ftruez][bz ]    [Ωmeasz - Ωtruez]
4017         //                                                                                                                                              [sx ]
4018         //                                                                                                                                              [sy ]
4019         //                                                                                                                                              [sz ]
4020         //                                                                                                                                              [mxy]
4021         //                                                                                                                                              [mxz]
4022         //                                                                                                                                              [myz]
4023         //                                                                                                                                              [g11]
4024         //                                                                                                                                              [g12]
4025         //                                                                                                                                              [g13]
4026         //                                                                                                                                              [g21]
4027         //                                                                                                                                              [g22]
4028         //                                                                                                                                              [g23]
4029         //                                                                                                                                              [g31]
4030         //                                                                                                                                              [g32]
4031         //                                                                                                                                              [g33]
4032 
4033         fitter.setFunctionEvaluator(new LevenbergMarquardtMultiVariateFunctionEvaluator() {
4034             @Override
4035             public int getNumberOfDimensions() {
4036                 // Input points are true angular rate + specific force coordinates
4037                 return 2 * BodyKinematics.COMPONENTS;
4038             }
4039 
4040             @Override
4041             public int getNumberOfVariables() {
4042                 // The multivariate function returns the components of measured angular rate
4043                 return BodyKinematics.COMPONENTS;
4044             }
4045 
4046             @Override
4047             public double[] createInitialParametersArray() {
4048                 final var initial = new double[COMMON_Z_AXIS_UNKNOWNS];
4049 
4050                 initial[0] = initialBiasX;
4051                 initial[1] = initialBiasY;
4052                 initial[2] = initialBiasZ;
4053 
4054                 initial[3] = initialSx;
4055                 initial[4] = initialSy;
4056                 initial[5] = initialSz;
4057 
4058                 initial[6] = initialMxy;
4059                 initial[7] = initialMxz;
4060                 initial[8] = initialMyz;
4061 
4062                 final var buffer = initialGg.getBuffer();
4063                 final var num = buffer.length;
4064                 System.arraycopy(buffer, 0, initial, 9, num);
4065 
4066                 return initial;
4067             }
4068 
4069             @Override
4070             public void evaluate(final int i, final double[] point, final double[] result, final double[] params,
4071                                  final Matrix jacobian) {
4072                 // We know that:
4073                 // Ωmeasx = bx + Ωtruex + sx * Ωtruex + mxy * Ωtruey + mxz * Ωtruez + g11 * ftruex + g12 * ftruey + g13 * ftruez
4074                 // Ωmeasy = by + Ωtruey + sy * Ωtruey + myz * Ωtruez + g21 * ftruex * g22 * ftruey + g23 * ftruez
4075                 // Ωmeasz = bz + Ωtruez + sz * Ωtruez + g31 * ftruex + g32 * ftruey + g33 * ftruez
4076 
4077                 // Hence, the derivatives respect the parameters bx, by, bz,
4078                 // sx, sy, sz, mxy mxz, myz, g11, g12, g13, g21, g22, g23,
4079                 // g31, g32, and g33 is:
4080 
4081                 // d(Ωmeasx)/d(bx) = 1.0
4082                 // d(Ωmeasx)/d(by) = 0.0
4083                 // d(Ωmeasx)/d(bz) = 0.0
4084                 // d(Ωmeasx)/d(sx) = Ωtruex
4085                 // d(Ωmeasx)/d(sy) = 0.0
4086                 // d(Ωmeasx)/d(sz) = 0.0
4087                 // d(Ωmeasx)/d(mxy) = Ωtruey
4088                 // d(Ωmeasx)/d(mxz) = Ωtruez
4089                 // d(Ωmeasx)/d(myz) = 0.0
4090                 // d(Ωmeasx)/d(g11) = ftruex
4091                 // d(Ωmeasx)/d(g12) = ftruey
4092                 // d(Ωmeasx)/d(g13) = ftruez
4093                 // d(Ωmeasx)/d(g21) = 0.0
4094                 // d(Ωmeasx)/d(g22) = 0.0
4095                 // d(Ωmeasx)/d(g23) = 0.0
4096                 // d(Ωmeasx)/d(g31) = 0.0
4097                 // d(Ωmeasx)/d(g32) = 0.0
4098                 // d(Ωmeasx)/d(g33) = 0.0
4099 
4100                 // d(Ωmeasy)/d(bx) = 0.0
4101                 // d(Ωmeasy)/d(by) = 1.0
4102                 // d(Ωmeasy)/d(bz) = 0.0
4103                 // d(Ωmeasy)/d(sx) = 0.0
4104                 // d(Ωmeasy)/d(sy) = Ωtruey
4105                 // d(Ωmeasy)/d(sz) = 0.0
4106                 // d(Ωmeasy)/d(mxy) = 0.0
4107                 // d(Ωmeasy)/d(mxz) = 0.0
4108                 // d(Ωmeasy)/d(myz) = Ωtruez
4109                 // d(Ωmeasx)/d(g11) = 0.0
4110                 // d(Ωmeasx)/d(g12) = 0.0
4111                 // d(Ωmeasx)/d(g13) = 0.0
4112                 // d(Ωmeasx)/d(g21) = ftruex
4113                 // d(Ωmeasx)/d(g22) = ftruey
4114                 // d(Ωmeasx)/d(g23) = ftruez
4115                 // d(Ωmeasx)/d(g31) = 0.0
4116                 // d(Ωmeasx)/d(g32) = 0.0
4117                 // d(Ωmeasx)/d(g33) = 0.0
4118 
4119                 // d(Ωmeasz)/d(bx) = 0.0
4120                 // d(Ωmeasz)/d(by) = 0.0
4121                 // d(Ωmeasz)/d(bz) = 1.0
4122                 // d(Ωmeasz)/d(sx) = 0.0
4123                 // d(Ωmeasz)/d(sy) = 0.0
4124                 // d(Ωmeasz)/d(sz) = Ωtruez
4125                 // d(Ωmeasz)/d(mxy) = 0.0
4126                 // d(Ωmeasz)/d(mxz) = 0.0
4127                 // d(Ωmeasz)/d(myz) = 0.0
4128                 // d(Ωmeasx)/d(g11) = 0.0
4129                 // d(Ωmeasx)/d(g12) = 0.0
4130                 // d(Ωmeasx)/d(g13) = 0.0
4131                 // d(Ωmeasx)/d(g21) = 0.0
4132                 // d(Ωmeasx)/d(g22) = 0.0
4133                 // d(Ωmeasx)/d(g23) = 0.0
4134                 // d(Ωmeasx)/d(g31) = ftruex
4135                 // d(Ωmeasx)/d(g32) = ftruey
4136                 // d(Ωmeasx)/d(g33) = ftruez
4137 
4138                 final var bx = params[0];
4139                 final var by = params[1];
4140                 final var bz = params[2];
4141 
4142                 final var sx = params[3];
4143                 final var sy = params[4];
4144                 final var sz = params[5];
4145 
4146                 final var mxy = params[6];
4147                 final var mxz = params[7];
4148                 final var myz = params[8];
4149 
4150                 final var g11 = params[9];
4151                 final var g21 = params[10];
4152                 final var g31 = params[11];
4153                 final var g12 = params[12];
4154                 final var g22 = params[13];
4155                 final var g32 = params[14];
4156                 final var g13 = params[15];
4157                 final var g23 = params[16];
4158                 final var g33 = params[17];
4159 
4160                 final var omegatruex = point[0];
4161                 final var omegatruey = point[1];
4162                 final var omegatruez = point[2];
4163 
4164                 final var ftruex = point[3];
4165                 final var ftruey = point[4];
4166                 final var ftruez = point[5];
4167 
4168                 result[0] = bx + omegatruex + sx * omegatruex + mxy * omegatruey + mxz * omegatruez
4169                         + g11 * ftruex + g12 * ftruey + g13 * ftruez;
4170                 result[1] = by + omegatruey + sy * omegatruey + myz * omegatruez
4171                         + g21 * ftruex * g22 * ftruey + g23 * ftruez;
4172                 result[2] = bz + omegatruez + sz * omegatruez
4173                         + g31 * ftruex + g32 * ftruey + g33 * ftruez;
4174 
4175                 jacobian.setElementAt(0, 0, 1.0);
4176                 jacobian.setElementAt(0, 1, 0.0);
4177                 jacobian.setElementAt(0, 2, 0.0);
4178                 jacobian.setElementAt(0, 3, omegatruex);
4179                 jacobian.setElementAt(0, 4, 0.0);
4180                 jacobian.setElementAt(0, 5, 0.0);
4181                 jacobian.setElementAt(0, 6, omegatruey);
4182                 jacobian.setElementAt(0, 7, omegatruez);
4183                 jacobian.setElementAt(0, 8, 0.0);
4184                 jacobian.setElementAt(0, 9, ftruex);
4185                 jacobian.setElementAt(0, 10, ftruey);
4186                 jacobian.setElementAt(0, 11, ftruez);
4187                 jacobian.setElementAt(0, 12, 0.0);
4188                 jacobian.setElementAt(0, 13, 0.0);
4189                 jacobian.setElementAt(0, 14, 0.0);
4190                 jacobian.setElementAt(0, 15, 0.0);
4191                 jacobian.setElementAt(0, 16, 0.0);
4192                 jacobian.setElementAt(0, 17, 0.0);
4193 
4194                 jacobian.setElementAt(1, 0, 0.0);
4195                 jacobian.setElementAt(1, 1, 1.0);
4196                 jacobian.setElementAt(1, 2, 0.0);
4197                 jacobian.setElementAt(1, 3, 0.0);
4198                 jacobian.setElementAt(1, 4, omegatruey);
4199                 jacobian.setElementAt(1, 5, 0.0);
4200                 jacobian.setElementAt(1, 6, 0.0);
4201                 jacobian.setElementAt(1, 7, 0.0);
4202                 jacobian.setElementAt(1, 8, omegatruez);
4203                 jacobian.setElementAt(1, 9, 0.0);
4204                 jacobian.setElementAt(1, 10, 0.0);
4205                 jacobian.setElementAt(1, 11, 0.0);
4206                 jacobian.setElementAt(1, 12, ftruex);
4207                 jacobian.setElementAt(1, 13, ftruey);
4208                 jacobian.setElementAt(1, 14, ftruez);
4209                 jacobian.setElementAt(1, 15, 0.0);
4210                 jacobian.setElementAt(1, 16, 0.0);
4211                 jacobian.setElementAt(1, 17, 0.0);
4212 
4213                 jacobian.setElementAt(2, 0, 0.0);
4214                 jacobian.setElementAt(2, 1, 0.0);
4215                 jacobian.setElementAt(2, 2, 1.0);
4216                 jacobian.setElementAt(2, 3, 0.0);
4217                 jacobian.setElementAt(2, 4, 0.0);
4218                 jacobian.setElementAt(2, 5, omegatruez);
4219                 jacobian.setElementAt(2, 6, 0.0);
4220                 jacobian.setElementAt(2, 7, 0.0);
4221                 jacobian.setElementAt(2, 8, 0.0);
4222                 jacobian.setElementAt(2, 9, 0.0);
4223                 jacobian.setElementAt(2, 10, 0.0);
4224                 jacobian.setElementAt(2, 11, 0.0);
4225                 jacobian.setElementAt(2, 12, 0.0);
4226                 jacobian.setElementAt(2, 13, 0.0);
4227                 jacobian.setElementAt(2, 14, 0.0);
4228                 jacobian.setElementAt(2, 15, ftruex);
4229                 jacobian.setElementAt(2, 16, ftruey);
4230                 jacobian.setElementAt(2, 17, ftruez);
4231             }
4232         });
4233 
4234         setInputData();
4235 
4236         fitter.fit();
4237 
4238         final var result = fitter.getA();
4239 
4240         final var bx = result[0];
4241         final var by = result[1];
4242         final var bz = result[2];
4243 
4244         final var sx = result[3];
4245         final var sy = result[4];
4246         final var sz = result[5];
4247 
4248         final var mxy = result[6];
4249         final var mxz = result[7];
4250         final var myz = result[8];
4251 
4252         final var g11 = result[9];
4253         final var g21 = result[10];
4254         final var g31 = result[11];
4255         final var g12 = result[12];
4256         final var g22 = result[13];
4257         final var g32 = result[14];
4258         final var g13 = result[15];
4259         final var g23 = result[16];
4260         final var g33 = result[17];
4261 
4262         if (estimatedBiases == null) {
4263             estimatedBiases = new double[BodyKinematics.COMPONENTS];
4264         }
4265 
4266         estimatedBiases[0] = bx;
4267         estimatedBiases[1] = by;
4268         estimatedBiases[2] = bz;
4269 
4270         if (estimatedMg == null) {
4271             estimatedMg = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
4272         } else {
4273             estimatedMg.initialize(0.0);
4274         }
4275 
4276         estimatedMg.setElementAt(0, 0, sx);
4277 
4278         estimatedMg.setElementAt(0, 1, mxy);
4279         estimatedMg.setElementAt(1, 1, sy);
4280 
4281         estimatedMg.setElementAt(0, 2, mxz);
4282         estimatedMg.setElementAt(1, 2, myz);
4283         estimatedMg.setElementAt(2, 2, sz);
4284 
4285         if (estimatedGg == null) {
4286             estimatedGg = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
4287         } else {
4288             estimatedGg.initialize(0.0);
4289         }
4290 
4291         estimatedGg.setElementAtIndex(0, g11);
4292         estimatedGg.setElementAtIndex(1, g21);
4293         estimatedGg.setElementAtIndex(2, g31);
4294         estimatedGg.setElementAtIndex(3, g12);
4295         estimatedGg.setElementAtIndex(4, g22);
4296         estimatedGg.setElementAtIndex(5, g32);
4297         estimatedGg.setElementAtIndex(6, g13);
4298         estimatedGg.setElementAtIndex(7, g23);
4299         estimatedGg.setElementAtIndex(8, g33);
4300 
4301         estimatedCovariance = fitter.getCovar();
4302 
4303         // propagate covariance matrix so that all parameters are taken into
4304         // account in the order: bx, by, bz, sx, sy, sz, mxy, mxz, myx,
4305         // myz, mzx, mzy,g11, g21, g31, g12, g22, g32, g13, g23, g33
4306 
4307         // We define a lineal function mapping original parameters for the common
4308         // axis case to the general case
4309         // [bx'] =   [1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0][bx]
4310         // [by']     [0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0][by]
4311         // [bz']     [0  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0][bz]
4312         // [sx']     [0  0  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0][sx]
4313         // [sy']     [0  0  0  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0][sy]
4314         // [sz']     [0  0  0  0  0  1  0  0  0  0  0  0  0  0  0  0  0  0][sz]
4315         // [mxy']    [0  0  0  0  0  0  1  0  0  0  0  0  0  0  0  0  0  0][mxy]
4316         // [mxz']    [0  0  0  0  0  0  0  1  0  0  0  0  0  0  0  0  0  0][mxz]
4317         // [myx']    [0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0][myz]
4318         // [myz']    [0  0  0  0  0  0  0  0  1  0  0  0  0  0  0  0  0  0][g11]
4319         // [mzx']    [0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0][g21]
4320         // [mzy']    [0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0][g31]
4321         // [g11']    [0  0  0  0  0  0  0  0  0  1  0  0  0  0  0  0  0  0][g12]
4322         // [g21']    [0  0  0  0  0  0  0  0  0  0  1  0  0  0  0  0  0  0][g22]
4323         // [g31']    [0  0  0  0  0  0  0  0  0  0  0  1  0  0  0  0  0  0][g32]
4324         // [g12']    [0  0  0  0  0  0  0  0  0  0  0  0  1  0  0  0  0  0][g13]
4325         // [g22']    [0  0  0  0  0  0  0  0  0  0  0  0  0  1  0  0  0  0][g23]
4326         // [g32']    [0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  0  0  0][g33]
4327         // [g13']    [0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  0  0]
4328         // [g23']    [0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  0]
4329         // [g33']    [0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1]
4330 
4331         // As defined in com.irurueta.statistics.MultivariateNormalDist,
4332         // if we consider the jacobian of the lineal application the matrix shown
4333         // above, then covariance can be propagated as follows
4334         final var jacobian = new Matrix(GENERAL_UNKNOWNS, COMMON_Z_AXIS_UNKNOWNS);
4335         for (int i = 0; i < 8; i++) {
4336             jacobian.setElementAt(i, i, 1.0);
4337         }
4338         jacobian.setElementAt(9, 8, 1.0);
4339 
4340         for (int j = 9, i = 12; j < 18; j++, i++) {
4341             jacobian.setElementAt(i, j, 1.0);
4342         }
4343 
4344         // propagated covariance is J * Cov * J'
4345         final var jacobianTrans = jacobian.transposeAndReturnNew();
4346         jacobian.multiply(estimatedCovariance);
4347         jacobian.multiply(jacobianTrans);
4348         estimatedCovariance = jacobian;
4349         estimatedChiSq = fitter.getChisq();
4350         estimatedChiSqDegreesOfFreedom = fitter.getChisqDegreesOfFreedom();
4351         estimatedReducedChiSq = fitter.getReducedChisq();
4352         estimatedMse = fitter.getMse();
4353         try {
4354             estimatedP = fitter.getP();
4355             estimatedQ = fitter.getQ();
4356         } catch (final MaxIterationsExceededException ignore) {
4357             // if numerical instabilities arise, we assume worst case (no fit at all)
4358             // probability of finding a smaller chi square value is 1.0
4359             // quality of fit is 0.0
4360             estimatedP = 1.0;
4361             estimatedQ = 0.0;
4362         }
4363     }
4364 
4365     /**
4366      * Internal method to perform general calibration.
4367      *
4368      * @throws AlgebraException                         if there are numerical errors.
4369      * @throws FittingException                         if no convergence to solution is found.
4370      * @throws com.irurueta.numerical.NotReadyException if fitter is not ready.
4371      */
4372     private void calibrateGeneral() throws AlgebraException, FittingException,
4373             com.irurueta.numerical.NotReadyException {
4374 
4375         // The gyroscope model is:
4376         // Ωmeas = bg + (I + Mg) * Ωtrue + Gg * ftrue + w
4377 
4378         // Ideally a least squares solution tries to minimize noise component, so:
4379         // Ωmeas = bg + (I + Mg) * Ωtrue + Gg * ftrue
4380 
4381         // Hence:
4382         // [Ωmeasx] = [bx] + ( [1   0   0] + [sx    mxy    mxz]) [Ωtruex] + [g11   g12   g13][ftruex]
4383         // [Ωmeasy]   [by]     [0   1   0]   [myx   sy     myz]  [Ωtruey]   [g21   g22   g23][ftruey]
4384         // [Ωmeasz]   [bz]     [0   0   1]   [mzx   mzy    sz ]  [Ωtruez]   [g31   g32   g33][ftruez]
4385 
4386         // [Ωmeasx] = [bx] + ( [1+sx  mxy    mxz ]) [Ωtruex] + [g11   g12   g13][ftruex]
4387         // [Ωmeasy]   [by]     [myx   1+sy   myz ]  [Ωtruey]   [g21   g22   g23][ftruey]
4388         // [Ωmeasz]   [bz]     [mzx   mzy    1+sz]  [Ωtruez]   [g31   g32   g33][ftruez]
4389 
4390         // Ωmeasx = bx + (1+sx) * Ωtruex + mxy * Ωtruey + mxz * Ωtruez + g11 * ftruex + g12 * ftruey + g13 * ftruez
4391         // Ωmeasy = by + myx * Ωtruex + (1+sy) * Ωtruey + myz * Ωtruez + g21 * ftruex * g22 * ftruey + g23 * ftruez
4392         // Ωmeasz = bz + mzx * Ωtruex + mzy * Ωtruey + (1+sz) * Ωtruez + g31 * ftruex + g32 * ftruey + g33 * ftruez
4393 
4394         // Where the unknowns are: bx, by, bz, sx, sy, sz, mxy mxz, myx, myz, mzx, mzy, g11, g12, g13, g21, g22, g23,
4395         // g31, g32, g33
4396         // Reordering:
4397         // Ωmeasx = bx + Ωtruex + sx * Ωtruex + mxy * Ωtruey + mxz * Ωtruez + g11 * ftruex + g12 * ftruey + g13 * ftruez
4398         // Ωmeasy = by + myx * Ωtruex + Ωtruey + sy * Ωtruey + myz * Ωtruez + g21 * ftruex * g22 * ftruey + g23 * ftruez
4399         // Ωmeasz = bz + mzx * Ωtruex + mzy * Ωtruey + Ωtruez + sz * Ωtruez + g31 * ftruex + g32 * ftruey + g33 * ftruez
4400 
4401         // Ωmeasx - Ωtruex = bx + sx * Ωtruex + mxy * Ωtruey + mxz * Ωtruez + g11 * ftruex + g12 * ftruey + g13 * ftruez
4402         // Ωmeasy - Ωtruey = by + myx * Ωtruex + sy * Ωtruey + myz * Ωtruez + g21 * ftruex * g22 * ftruey + g23 * ftruez
4403         // Ωmeasz - Ωtruez = bz + mzx * Ωtruex + mzy * Ωtruey + sz * Ωtruez + g31 * ftruex + g32 * ftruey + g33 * ftruez
4404 
4405         // [1   0   0   Ωtruex  0       0       Ωtruey  Ωtruez  0       0       0       0       ftruex  ftruey  ftruez  0       0       0       0       0       0     ][bx ] =  [Ωmeasx - Ωtruex]
4406         // [0   1   0   0       Ωtruey  0       0       0       Ωtruex  Ωtruez  0       0       0       0       0       ftruex  ftruey  ftruez  0       0       0     ][by ]    [Ωmeasy - Ωtruey]
4407         // [0   0   1   0       0       Ωtruez  0       0       0       0       Ωtruex  Ωtruey  0       0       0       0       0       0       ftruex  ftruey  ftruez][bz ]    [Ωmeasz - Ωtruez]
4408         //                                                                                                                                                             [sx ]
4409         //                                                                                                                                                             [sy ]
4410         //                                                                                                                                                             [sz ]
4411         //                                                                                                                                                             [mxy]
4412         //                                                                                                                                                             [mxz]
4413         //                                                                                                                                                             [myx]
4414         //                                                                                                                                                             [myz]
4415         //                                                                                                                                                             [mzx]
4416         //                                                                                                                                                             [mzy]
4417         //                                                                                                                                                             [g11]
4418         //                                                                                                                                                             [g12]
4419         //                                                                                                                                                             [g13]
4420         //                                                                                                                                                             [g21]
4421         //                                                                                                                                                             [g22]
4422         //                                                                                                                                                             [g23]
4423         //                                                                                                                                                             [g31]
4424         //                                                                                                                                                             [g32]
4425         //                                                                                                                                                             [g33]
4426 
4427         fitter.setFunctionEvaluator(new LevenbergMarquardtMultiVariateFunctionEvaluator() {
4428             @Override
4429             public int getNumberOfDimensions() {
4430                 // Input points are true angular rate + specific force coordinates
4431                 return 2 * BodyKinematics.COMPONENTS;
4432             }
4433 
4434             @Override
4435             public int getNumberOfVariables() {
4436                 // The multivariate function returns the components of measured angular rate
4437                 return BodyKinematics.COMPONENTS;
4438             }
4439 
4440             @Override
4441             public double[] createInitialParametersArray() {
4442                 final var initial = new double[GENERAL_UNKNOWNS];
4443 
4444                 initial[0] = initialBiasX;
4445                 initial[1] = initialBiasY;
4446                 initial[2] = initialBiasZ;
4447 
4448                 initial[3] = initialSx;
4449                 initial[4] = initialSy;
4450                 initial[5] = initialSz;
4451 
4452                 initial[6] = initialMxy;
4453                 initial[7] = initialMxz;
4454                 initial[8] = initialMyx;
4455                 initial[9] = initialMyz;
4456                 initial[10] = initialMzx;
4457                 initial[11] = initialMzy;
4458 
4459                 final var buffer = initialGg.getBuffer();
4460                 final var num = buffer.length;
4461                 System.arraycopy(buffer, 0, initial, 12, num);
4462 
4463                 return initial;
4464             }
4465 
4466             @Override
4467             public void evaluate(final int i, final double[] point, final double[] result, final double[] params,
4468                                  final Matrix jacobian) {
4469                 // We know that:
4470                 // Ωmeasx = bx + Ωtruex + sx * Ωtruex + mxy * Ωtruey + mxz * Ωtruez + g11 * ftruex + g12 * ftruey + g13 * ftruez
4471                 // Ωmeasy = by + myx * Ωtruex + Ωtruey + sy * Ωtruey + myz * Ωtruez + g21 * ftruex * g22 * ftruey + g23 * ftruez
4472                 // Ωmeasz = bz + mzx * Ωtruex + mzy * Ωtruey + Ωtruez + sz * Ωtruez + g31 * ftruex + g32 * ftruey + g33 * ftruez
4473 
4474                 // Hence, the derivatives respect the parameters bx, by, bz, sx, sy,
4475                 // sz, mxy, mxz, myx, myz, mzx, mzy, g11, g12, g13, g21, g22, g23,
4476                 // g31, g32 and g33 is:
4477 
4478                 // d(Ωmeasx)/d(bx) = 1.0
4479                 // d(Ωmeasx)/d(by) = 0.0
4480                 // d(Ωmeasx)/d(bz) = 0.0
4481                 // d(Ωmeasx)/d(sx) = Ωtruex
4482                 // d(Ωmeasx)/d(sy) = 0.0
4483                 // d(Ωmeasx)/d(sz) = 0.0
4484                 // d(Ωmeasx)/d(mxy) = Ωtruey
4485                 // d(Ωmeasx)/d(mxz) = Ωtruez
4486                 // d(Ωmeasx)/d(myx) = 0.0
4487                 // d(Ωmeasx)/d(myz) = 0.0
4488                 // d(Ωmeasx)/d(mzx) = 0.0
4489                 // d(Ωmeasx)/d(mzy) = 0.0
4490                 // d(Ωmeasx)/d(g11) = ftruex
4491                 // d(Ωmeasx)/d(g12) = ftruey
4492                 // d(Ωmeasx)/d(g13) = ftruez
4493                 // d(Ωmeasx)/d(g21) = 0.0
4494                 // d(Ωmeasx)/d(g22) = 0.0
4495                 // d(Ωmeasx)/d(g23) = 0.0
4496                 // d(Ωmeasx)/d(g31) = 0.0
4497                 // d(Ωmeasx)/d(g32) = 0.0
4498                 // d(Ωmeasx)/d(g33) = 0.0
4499 
4500                 // d(Ωmeasy)/d(bx) = 0.0
4501                 // d(Ωmeasy)/d(by) = 1.0
4502                 // d(Ωmeasy)/d(bz) = 0.0
4503                 // d(Ωmeasy)/d(sx) = 0.0
4504                 // d(Ωmeasy)/d(sy) = Ωtruey
4505                 // d(Ωmeasy)/d(sz) = 0.0
4506                 // d(Ωmeasy)/d(mxy) = 0.0
4507                 // d(Ωmeasy)/d(mxz) = 0.0
4508                 // d(Ωmeasy)/d(myx) = Ωtruex
4509                 // d(Ωmeasy)/d(myz) = Ωtruez
4510                 // d(Ωmeasy)/d(mzx) = 0.0
4511                 // d(Ωmeasy)/d(mzy) = 0.0
4512                 // d(Ωmeasx)/d(g11) = 0.0
4513                 // d(Ωmeasx)/d(g12) = 0.0
4514                 // d(Ωmeasx)/d(g13) = 0.0
4515                 // d(Ωmeasx)/d(g21) = ftruex
4516                 // d(Ωmeasx)/d(g22) = ftruey
4517                 // d(Ωmeasx)/d(g23) = ftruez
4518                 // d(Ωmeasx)/d(g31) = 0.0
4519                 // d(Ωmeasx)/d(g32) = 0.0
4520                 // d(Ωmeasx)/d(g33) = 0.0
4521 
4522                 // d(Ωmeasz)/d(bx) = 0.0
4523                 // d(Ωmeasz)/d(by) = 0.0
4524                 // d(Ωmeasz)/d(bz) = 1.0
4525                 // d(Ωmeasz)/d(sx) = 0.0
4526                 // d(Ωmeasz)/d(sy) = 0.0
4527                 // d(Ωmeasz)/d(sz) = Ωtruez
4528                 // d(Ωmeasz)/d(mxy) = 0.0
4529                 // d(Ωmeasz)/d(mxz) = 0.0
4530                 // d(Ωmeasz)/d(myx) = 0.0
4531                 // d(Ωmeasz)/d(myz) = 0.0
4532                 // d(Ωmeasz)/d(mzx) = Ωtruex
4533                 // d(Ωmeasz)/d(mzy) = Ωtruey
4534                 // d(Ωmeasx)/d(g11) = 0.0
4535                 // d(Ωmeasx)/d(g12) = 0.0
4536                 // d(Ωmeasx)/d(g13) = 0.0
4537                 // d(Ωmeasx)/d(g21) = 0.0
4538                 // d(Ωmeasx)/d(g22) = 0.0
4539                 // d(Ωmeasx)/d(g23) = 0.0
4540                 // d(Ωmeasx)/d(g31) = ftruex
4541                 // d(Ωmeasx)/d(g32) = ftruey
4542                 // d(Ωmeasx)/d(g33) = ftruez
4543 
4544                 final var bx = params[0];
4545                 final var by = params[1];
4546                 final var bz = params[2];
4547 
4548                 final var sx = params[3];
4549                 final var sy = params[4];
4550                 final var sz = params[5];
4551 
4552                 final var mxy = params[6];
4553                 final var mxz = params[7];
4554                 final var myx = params[8];
4555                 final var myz = params[9];
4556                 final var mzx = params[10];
4557                 final var mzy = params[11];
4558 
4559                 final var g11 = params[12];
4560                 final var g21 = params[13];
4561                 final var g31 = params[14];
4562                 final var g12 = params[15];
4563                 final var g22 = params[16];
4564                 final var g32 = params[17];
4565                 final var g13 = params[18];
4566                 final var g23 = params[19];
4567                 final var g33 = params[20];
4568 
4569                 final var omegatruex = point[0];
4570                 final var omegatruey = point[1];
4571                 final var omegatruez = point[2];
4572 
4573                 final var ftruex = point[3];
4574                 final var ftruey = point[4];
4575                 final var ftruez = point[5];
4576 
4577                 result[0] = bx + omegatruex + sx * omegatruex + mxy * omegatruey + mxz * omegatruez
4578                         + g11 * ftruex + g12 * ftruey + g13 * ftruez;
4579                 result[1] = by + myx * omegatruex + omegatruey + sy * omegatruey + myz * omegatruez
4580                         + g21 * ftruex * g22 * ftruey + g23 * ftruez;
4581                 result[2] = bz + mzx * omegatruex + mzy * omegatruey + omegatruez + sz * omegatruez
4582                         + g31 * ftruex + g32 * ftruey + g33 * ftruez;
4583 
4584                 jacobian.setElementAt(0, 0, 1.0);
4585                 jacobian.setElementAt(0, 1, 0.0);
4586                 jacobian.setElementAt(0, 2, 0.0);
4587                 jacobian.setElementAt(0, 3, omegatruex);
4588                 jacobian.setElementAt(0, 4, 0.0);
4589                 jacobian.setElementAt(0, 5, 0.0);
4590                 jacobian.setElementAt(0, 6, omegatruey);
4591                 jacobian.setElementAt(0, 7, omegatruez);
4592                 jacobian.setElementAt(0, 8, 0.0);
4593                 jacobian.setElementAt(0, 9, 0.0);
4594                 jacobian.setElementAt(0, 10, 0.0);
4595                 jacobian.setElementAt(0, 11, 0.0);
4596                 jacobian.setElementAt(0, 12, ftruex);
4597                 jacobian.setElementAt(0, 13, ftruey);
4598                 jacobian.setElementAt(0, 14, ftruez);
4599                 jacobian.setElementAt(0, 15, 0.0);
4600                 jacobian.setElementAt(0, 16, 0.0);
4601                 jacobian.setElementAt(0, 17, 0.0);
4602                 jacobian.setElementAt(0, 18, 0.0);
4603                 jacobian.setElementAt(0, 19, 0.0);
4604                 jacobian.setElementAt(0, 20, 0.0);
4605 
4606                 jacobian.setElementAt(1, 0, 0.0);
4607                 jacobian.setElementAt(1, 1, 1.0);
4608                 jacobian.setElementAt(1, 2, 0.0);
4609                 jacobian.setElementAt(1, 3, 0.0);
4610                 jacobian.setElementAt(1, 4, omegatruey);
4611                 jacobian.setElementAt(1, 5, 0.0);
4612                 jacobian.setElementAt(1, 6, 0.0);
4613                 jacobian.setElementAt(1, 7, 0.0);
4614                 jacobian.setElementAt(1, 8, omegatruex);
4615                 jacobian.setElementAt(1, 9, omegatruez);
4616                 jacobian.setElementAt(1, 10, 0.0);
4617                 jacobian.setElementAt(1, 11, 0.0);
4618                 jacobian.setElementAt(1, 12, 0.0);
4619                 jacobian.setElementAt(1, 13, 0.0);
4620                 jacobian.setElementAt(1, 14, 0.0);
4621                 jacobian.setElementAt(1, 15, ftruex);
4622                 jacobian.setElementAt(1, 16, ftruey);
4623                 jacobian.setElementAt(1, 17, ftruez);
4624                 jacobian.setElementAt(1, 18, 0.0);
4625                 jacobian.setElementAt(1, 19, 0.0);
4626                 jacobian.setElementAt(1, 20, 0.0);
4627 
4628                 jacobian.setElementAt(2, 0, 0.0);
4629                 jacobian.setElementAt(2, 1, 0.0);
4630                 jacobian.setElementAt(2, 2, 1.0);
4631                 jacobian.setElementAt(2, 3, 0.0);
4632                 jacobian.setElementAt(2, 4, 0.0);
4633                 jacobian.setElementAt(2, 5, omegatruez);
4634                 jacobian.setElementAt(2, 6, 0.0);
4635                 jacobian.setElementAt(2, 7, 0.0);
4636                 jacobian.setElementAt(2, 8, 0.0);
4637                 jacobian.setElementAt(2, 9, 0.0);
4638                 jacobian.setElementAt(2, 10, omegatruex);
4639                 jacobian.setElementAt(2, 11, omegatruey);
4640                 jacobian.setElementAt(2, 12, 0.0);
4641                 jacobian.setElementAt(2, 13, 0.0);
4642                 jacobian.setElementAt(2, 14, 0.0);
4643                 jacobian.setElementAt(2, 15, 0.0);
4644                 jacobian.setElementAt(2, 16, 0.0);
4645                 jacobian.setElementAt(2, 17, 0.0);
4646                 jacobian.setElementAt(2, 18, ftruex);
4647                 jacobian.setElementAt(2, 19, ftruey);
4648                 jacobian.setElementAt(2, 20, ftruez);
4649             }
4650         });
4651 
4652         setInputData();
4653 
4654         fitter.fit();
4655 
4656         final var result = fitter.getA();
4657 
4658         final var bx = result[0];
4659         final var by = result[1];
4660         final var bz = result[2];
4661 
4662         final var sx = result[3];
4663         final var sy = result[4];
4664         final var sz = result[5];
4665 
4666         final var mxy = result[6];
4667         final var mxz = result[7];
4668         final var myx = result[8];
4669         final var myz = result[9];
4670         final var mzx = result[10];
4671         final var mzy = result[11];
4672 
4673         final var g11 = result[12];
4674         final var g21 = result[13];
4675         final var g31 = result[14];
4676         final var g12 = result[15];
4677         final var g22 = result[16];
4678         final var g32 = result[17];
4679         final var g13 = result[18];
4680         final var g23 = result[19];
4681         final var g33 = result[20];
4682 
4683         if (estimatedBiases == null) {
4684             estimatedBiases = new double[BodyKinematics.COMPONENTS];
4685         }
4686 
4687         estimatedBiases[0] = bx;
4688         estimatedBiases[1] = by;
4689         estimatedBiases[2] = bz;
4690 
4691         if (estimatedMg == null) {
4692             estimatedMg = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
4693         } else {
4694             estimatedMg.initialize(0.0);
4695         }
4696 
4697         estimatedMg.setElementAt(0, 0, sx);
4698         estimatedMg.setElementAt(1, 0, myx);
4699         estimatedMg.setElementAt(2, 0, mzx);
4700 
4701         estimatedMg.setElementAt(0, 1, mxy);
4702         estimatedMg.setElementAt(1, 1, sy);
4703         estimatedMg.setElementAt(2, 1, mzy);
4704 
4705         estimatedMg.setElementAt(0, 2, mxz);
4706         estimatedMg.setElementAt(1, 2, myz);
4707         estimatedMg.setElementAt(2, 2, sz);
4708 
4709         if (estimatedGg == null) {
4710             estimatedGg = new Matrix(BodyKinematics.COMPONENTS, BodyKinematics.COMPONENTS);
4711         } else {
4712             estimatedGg.initialize(0.0);
4713         }
4714 
4715         estimatedGg.setElementAtIndex(0, g11);
4716         estimatedGg.setElementAtIndex(1, g21);
4717         estimatedGg.setElementAtIndex(2, g31);
4718         estimatedGg.setElementAtIndex(3, g12);
4719         estimatedGg.setElementAtIndex(4, g22);
4720         estimatedGg.setElementAtIndex(5, g32);
4721         estimatedGg.setElementAtIndex(6, g13);
4722         estimatedGg.setElementAtIndex(7, g23);
4723         estimatedGg.setElementAtIndex(8, g33);
4724 
4725         estimatedCovariance = fitter.getCovar();
4726         estimatedChiSq = fitter.getChisq();
4727         estimatedChiSqDegreesOfFreedom = fitter.getChisqDegreesOfFreedom();
4728         estimatedReducedChiSq = fitter.getReducedChisq();
4729         estimatedMse = fitter.getMse();
4730         try {
4731             estimatedP = fitter.getP();
4732             estimatedQ = fitter.getQ();
4733         } catch (final MaxIterationsExceededException ignore) {
4734             // if numerical instabilities arise, we assume worst case (no fit at all)
4735             // probability of finding a smaller chi square value is 1.0
4736             // quality of fit is 0.0
4737             estimatedP = 1.0;
4738             estimatedQ = 0.0;
4739         }
4740     }
4741 
4742     /**
4743      * Sets input data into Levenberg-Marquardt fitter.
4744      *
4745      * @throws WrongSizeException never happens.
4746      */
4747     private void setInputData() throws WrongSizeException {
4748         // set input data using:
4749         // Ωmeasx = bx + Ωtruex + sx * Ωtruex + mxy * Ωtruey + mxz * Ωtruez + g11 * ftruex + g12 * ftruey + g13 * ftruez
4750         // Ωmeasy = by + myx * Ωtruex + Ωtruey + sy * Ωtruey + myz * Ωtruez + g21 * ftruex * g22 * ftruey + g23 * ftruez
4751         // Ωmeasz = bz + mzx * Ωtruex + mzy * Ωtruey + Ωtruez + sz * Ωtruez + g31 * ftruex + g32 * ftruey + g33 * ftruez
4752 
4753         // fmeasx = bx + ftruex + sx * ftruex + mxy * ftruey + mxz * ftruez
4754         // fmeasy = by + myx * ftruex + ftruey + sy * ftruey + myz * ftruez
4755         // fmeasz = bz + mzx * ftruex + mzy * ftruey + ftruez + sz * ftruez
4756 
4757         final var expectedKinematics = new BodyKinematics();
4758 
4759         final var numMeasurements = measurements.size();
4760         final var x = new Matrix(numMeasurements, 2 * BodyKinematics.COMPONENTS);
4761         final var y = new Matrix(numMeasurements, BodyKinematics.COMPONENTS);
4762         final var standardDeviations = new double[numMeasurements];
4763         var i = 0;
4764         for (final var measurement : measurements) {
4765             final var measuredKinematics = measurement.getKinematics();
4766             final var ecefFrame = measurement.getFrame();
4767             final var previousEcefFrame = measurement.getPreviousFrame();
4768             final var timeInterval = measurement.getTimeInterval();
4769 
4770             ECEFKinematicsEstimator.estimateKinematics(timeInterval, ecefFrame, previousEcefFrame, expectedKinematics);
4771 
4772             final var omegaMeasX = measuredKinematics.getAngularRateX();
4773             final var omegaMeasY = measuredKinematics.getAngularRateY();
4774             final var omegaMeasZ = measuredKinematics.getAngularRateZ();
4775 
4776             final var omegaTrueX = expectedKinematics.getAngularRateX();
4777             final var omegaTrueY = expectedKinematics.getAngularRateY();
4778             final var omegaTrueZ = expectedKinematics.getAngularRateZ();
4779 
4780             final var fTrueX = expectedKinematics.getFx();
4781             final var fTrueY = expectedKinematics.getFy();
4782             final var fTrueZ = expectedKinematics.getFz();
4783 
4784             x.setElementAt(i, 0, omegaTrueX);
4785             x.setElementAt(i, 1, omegaTrueY);
4786             x.setElementAt(i, 2, omegaTrueZ);
4787 
4788             x.setElementAt(i, 3, fTrueX);
4789             x.setElementAt(i, 4, fTrueY);
4790             x.setElementAt(i, 5, fTrueZ);
4791 
4792             y.setElementAt(i, 0, omegaMeasX);
4793             y.setElementAt(i, 1, omegaMeasY);
4794             y.setElementAt(i, 2, omegaMeasZ);
4795 
4796             standardDeviations[i] = measurement.getAngularRateStandardDeviation();
4797             i++;
4798         }
4799 
4800         fitter.setInputData(x, y, standardDeviations);
4801     }
4802 
4803     /**
4804      * Converts angular speed value and unit to radians per second.
4805      *
4806      * @param value angular speed value.
4807      * @param unit  unit of angular speed value.
4808      * @return converted value.
4809      */
4810     private static double convertAngularSpeed(final double value, final AngularSpeedUnit unit) {
4811         return AngularSpeedConverter.convert(value, unit, AngularSpeedUnit.RADIANS_PER_SECOND);
4812     }
4813 
4814     /**
4815      * Converts angular speed instance to radians per second.
4816      *
4817      * @param angularSpeed angular speed instance to be converted.
4818      * @return converted value.
4819      */
4820     private static double convertAngularSpeed(final AngularSpeed angularSpeed) {
4821         return convertAngularSpeed(angularSpeed.getValue().doubleValue(), angularSpeed.getUnit());
4822     }
4823 }