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