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.Matrix;
19 import com.irurueta.navigation.LockedException;
20 import com.irurueta.navigation.NotReadyException;
21 import com.irurueta.navigation.frames.ECEFPosition;
22 import com.irurueta.navigation.frames.NEDPosition;
23 import com.irurueta.navigation.inertial.calibration.CalibrationException;
24 import com.irurueta.navigation.inertial.calibration.StandardDeviationBodyMagneticFluxDensity;
25 import com.irurueta.navigation.inertial.wmm.WorldMagneticModel;
26 import com.irurueta.numerical.robust.MSACRobustEstimator;
27 import com.irurueta.numerical.robust.MSACRobustEstimatorListener;
28 import com.irurueta.numerical.robust.RobustEstimator;
29 import com.irurueta.numerical.robust.RobustEstimatorException;
30 import com.irurueta.numerical.robust.RobustEstimatorMethod;
31
32 import java.io.IOException;
33 import java.util.List;
34
35 /**
36 * Robustly estimates magnetometer hard-iron biases, cross couplings and
37 * scaling factors using MSAC algorithm.
38 * <p>
39 * To use this calibrator at least 10 measurements taken at a single known
40 * position and instant must be taken at 10 different unknown orientations and
41 * zero velocity when common z-axis is assumed, otherwise at least 13
42 * measurements are required.
43 * <p>
44 * Measured magnetic flux density is assumed to follow the model shown below:
45 * <pre>
46 * mBmeas = bm + (I + Mm) * mBtrue + w
47 * </pre>
48 * Where:
49 * - mBmeas is the measured magnetic flux density. This is a 3x1 vector.
50 * - bm is magnetometer hard-iron bias. Ideally, on a perfect magnetometer,
51 * this should be a 3x1 zero vector.
52 * - I is the 3x3 identity matrix.
53 * - Mm is the 3x3 soft-iron matrix containing cross-couplings and scaling
54 * factors. Ideally, on a perfect magnetometer, this should be a 3x3 zero
55 * matrix.
56 * - mBtrue is ground-truth magnetic flux density. This is a 3x1 vector.
57 * - w is measurement noise. This is a 3x1 vector.
58 * Notice that this calibrator assumes that all measurements are taken in
59 * a short span of time, where Earth magnetic field can be assumed to be
60 * constant at provided location and instant.
61 */
62 public class MSACRobustKnownPositionAndInstantMagnetometerCalibrator extends
63 RobustKnownPositionAndInstantMagnetometerCalibrator {
64
65 /**
66 * Constant defining default threshold to determine whether samples are
67 * inliers or not.
68 */
69 public static final double DEFAULT_THRESHOLD = 1e-9;
70
71 /**
72 * Minimum value that can be set as threshold.
73 * Threshold must be strictly greater than 0.0.
74 */
75 public static final double MIN_THRESHOLD = 0.0;
76
77 /**
78 * Threshold to determine whether samples are inliers or not when
79 * testing possible estimation solutions.
80 */
81 private double threshold = DEFAULT_THRESHOLD;
82
83 /**
84 * Constructor.
85 */
86 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator() {
87 super();
88 }
89
90 /**
91 * Constructor.
92 *
93 * @param listener listener to handle events raised by this calibrator.
94 */
95 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
96 final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
97 super(listener);
98 }
99
100 /**
101 * Constructor.
102 *
103 * @param measurements list of body magnetic flux density
104 * measurements with standard deviation of
105 * magnetometer measurements taken at the same
106 * position with zero velocity and unknown different
107 * orientations.
108 */
109 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
110 final List<StandardDeviationBodyMagneticFluxDensity> measurements) {
111 super(measurements);
112 }
113
114 /**
115 * Constructor.
116 *
117 * @param commonAxisUsed indicates whether z-axis is assumed to be common
118 * for the accelerometer, gyroscope and magnetometer.
119 */
120 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(final boolean commonAxisUsed) {
121 super(commonAxisUsed);
122 }
123
124 /**
125 * Constructor.
126 *
127 * @param magneticModel Earth's magnetic model. If null, a default model
128 * will be used instead.
129 */
130 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(final WorldMagneticModel magneticModel) {
131 super(magneticModel);
132 }
133
134 /**
135 * Constructor.
136 *
137 * @param initialHardIron initial hard-iron to find a solution.
138 * @throws IllegalArgumentException if provided hard-iron array does
139 * not have length 3.
140 */
141 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(final double[] initialHardIron) {
142 super(initialHardIron);
143 }
144
145 /**
146 * Constructor.
147 *
148 * @param initialHardIron initial hard-iron to find a solution.
149 * @throws IllegalArgumentException if provided hard-iron matrix is not
150 * 3x1.
151 */
152 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(final Matrix initialHardIron) {
153 super(initialHardIron);
154 }
155
156 /**
157 * Constructor.
158 *
159 * @param initialHardIron initial hard-iron to find a solution.
160 * @param initialMm initial soft-iron matrix containing scale factors
161 * and cross coupling errors.
162 * @throws IllegalArgumentException if provided hard-iron matrix is not
163 * 3x1 or if soft-iron matrix is not
164 * 3x3.
165 */
166 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
167 final Matrix initialHardIron, final Matrix initialMm) {
168 super(initialHardIron, initialMm);
169 }
170
171 /**
172 * Constructor.
173 *
174 * @param position position where body magnetic flux density measurements
175 * have been taken.
176 */
177 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(final NEDPosition position) {
178 super(position);
179 }
180
181 /**
182 * Constructor.
183 *
184 * @param position position where body magnetic flux density measurements
185 * have been taken.
186 * @param measurements collection of body magnetic flux density
187 * measurements with standard deviation of
188 * magnetometer measurements taken at the same
189 * position with zero velocity and unknown different
190 * orientations.
191 */
192 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
193 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements) {
194 super(position, measurements);
195 }
196
197 /**
198 * Constructor.
199 *
200 * @param position position where body magnetic flux density measurements
201 * have been taken.
202 * @param measurements collection of body magnetic flux density
203 * measurements with standard deviation of
204 * magnetometer measurements taken at the same
205 * position with zero velocity and unknown different
206 * orientations.
207 * @param listener listener to handle events raised by this calibrator.
208 */
209 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
210 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
211 final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
212 super(position, measurements, listener);
213 }
214
215 /**
216 * Constructor.
217 *
218 * @param position position where body magnetic flux density measurements
219 * have been taken.
220 * @param measurements collection of body magnetic flux density
221 * measurements with standard deviation of
222 * magnetometer measurements taken at the same
223 * position with zero velocity and unknown different
224 * orientations.
225 * @param commonAxisUsed indicates whether z-axis is assumed to be common
226 * for the accelerometer, gyroscope and magnetometer.
227 */
228 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
229 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
230 final boolean commonAxisUsed) {
231 super(position, measurements, commonAxisUsed);
232 }
233
234 /**
235 * Constructor.
236 *
237 * @param position position where body magnetic flux density measurements
238 * have been taken.
239 * @param measurements collection of body magnetic flux density
240 * measurements with standard deviation of
241 * magnetometer measurements taken at the same
242 * position with zero velocity and unknown different
243 * orientations.
244 * @param commonAxisUsed indicates whether z-axis is assumed to be common
245 * for the accelerometer, gyroscope and magnetometer.
246 * @param listener listener to handle events raised by this calibrator.
247 */
248 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
249 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
250 final boolean commonAxisUsed, final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
251 super(position, measurements, commonAxisUsed, listener);
252 }
253
254 /**
255 * Constructor.
256 *
257 * @param position position where body magnetic flux density measurements
258 * have been taken.
259 * @param measurements collection of body magnetic flux density
260 * measurements with standard deviation of
261 * magnetometer measurements taken at the same
262 * position with zero velocity and unknown different
263 * orientations.
264 * @param initialHardIron initial hard-iron to find a solution.
265 * @throws IllegalArgumentException if provided hard-iron array does
266 * not have length 3.
267 */
268 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
269 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
270 final double[] initialHardIron) {
271 super(position, measurements, initialHardIron);
272 }
273
274 /**
275 * Constructor.
276 *
277 * @param position position where body magnetic flux density measurements
278 * have been taken.
279 * @param measurements collection of body magnetic flux density
280 * measurements with standard deviation of
281 * magnetometer measurements taken at the same
282 * position with zero velocity and unknown different
283 * orientations.
284 * @param initialHardIron initial hard-iron to find a solution.
285 * @param listener listener to handle events raised by this calibrator.
286 * @throws IllegalArgumentException if provided hard-iron array does
287 * not have length 3.
288 */
289 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
290 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
291 final double[] initialHardIron,
292 final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
293 super(position, measurements, initialHardIron, listener);
294 }
295
296 /**
297 * Constructor.
298 *
299 * @param position position where body magnetic flux density measurements
300 * have been taken.
301 * @param measurements collection of body magnetic flux density
302 * measurements with standard deviation of
303 * magnetometer measurements taken at the same
304 * position with zero velocity and unknown different
305 * orientations.
306 * @param commonAxisUsed indicates whether z-axis is assumed to be common
307 * for the accelerometer, gyroscope and magnetometer.
308 * @param initialHardIron initial hard-iron to find a solution.
309 * @throws IllegalArgumentException if provided hard-iron array does
310 * not have length 3.
311 */
312 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
313 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
314 final boolean commonAxisUsed, final double[] initialHardIron) {
315 super(position, measurements, commonAxisUsed, initialHardIron);
316 }
317
318 /**
319 * Constructor.
320 *
321 * @param position position where body magnetic flux density measurements
322 * have been taken.
323 * @param measurements collection of body magnetic flux density
324 * measurements with standard deviation of
325 * magnetometer measurements taken at the same
326 * position with zero velocity and unknown different
327 * orientations.
328 * @param commonAxisUsed indicates whether z-axis is assumed to be common
329 * for the accelerometer, gyroscope and magnetometer.
330 * @param initialHardIron initial hard-iron to find a solution.
331 * @param listener listener to handle events raised by this calibrator.
332 * @throws IllegalArgumentException if provided hard-iron array does
333 * not have length 3.
334 */
335 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
336 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
337 final boolean commonAxisUsed, final double[] initialHardIron,
338 final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
339 super(position, measurements, commonAxisUsed, initialHardIron, listener);
340 }
341
342 /**
343 * Constructor.
344 *
345 * @param position position where body magnetic flux density measurements
346 * have been taken.
347 * @param measurements collection of body magnetic flux density
348 * measurements with standard deviation of
349 * magnetometer measurements taken at the same
350 * position with zero velocity and unknown different
351 * orientations.
352 * @param initialHardIron initial hard-iron to find a solution.
353 * @throws IllegalArgumentException if provided hard-iron matrix is not
354 * 3x1.
355 */
356 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
357 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
358 final Matrix initialHardIron) {
359 super(position, measurements, initialHardIron);
360 }
361
362 /**
363 * Constructor.
364 *
365 * @param position position where body magnetic flux density measurements
366 * have been taken.
367 * @param measurements collection of body magnetic flux density
368 * measurements with standard deviation of
369 * magnetometer measurements taken at the same
370 * position with zero velocity and unknown different
371 * orientations.
372 * @param initialHardIron initial hard-iron to find a solution.
373 * @param listener listener to handle events raised by this calibrator.
374 * @throws IllegalArgumentException if provided hard-iron matrix is not
375 * 3x1.
376 */
377 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
378 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
379 final Matrix initialHardIron, final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
380 super(position, measurements, initialHardIron, listener);
381 }
382
383 /**
384 * Constructor.
385 *
386 * @param position position where body magnetic flux density measurements
387 * have been taken.
388 * @param measurements collection of body magnetic flux density
389 * measurements with standard deviation of
390 * magnetometer measurements taken at the same
391 * position with zero velocity and unknown different
392 * orientations.
393 * @param commonAxisUsed indicates whether z-axis is assumed to be common
394 * for the accelerometer, gyroscope and magnetometer.
395 * @param initialHardIron initial hard-iron to find a solution.
396 * @throws IllegalArgumentException if provided hard-iron matrix is not
397 * 3x1.
398 */
399 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
400 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
401 final boolean commonAxisUsed, final Matrix initialHardIron) {
402 super(position, measurements, commonAxisUsed, initialHardIron);
403 }
404
405 /**
406 * Constructor.
407 *
408 * @param position position where body magnetic flux density measurements
409 * have been taken.
410 * @param measurements collection of body magnetic flux density
411 * measurements with standard deviation of
412 * magnetometer measurements taken at the same
413 * position with zero velocity and unknown different
414 * orientations.
415 * @param commonAxisUsed indicates whether z-axis is assumed to be common
416 * for the accelerometer, gyroscope and magnetometer.
417 * @param initialHardIron initial hard-iron to find a solution.
418 * @param listener listener to handle events raised by this calibrator.
419 * @throws IllegalArgumentException if provided hard-iron matrix is not
420 * 3x1.
421 */
422 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
423 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
424 final boolean commonAxisUsed, final Matrix initialHardIron,
425 final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
426 super(position, measurements, commonAxisUsed, initialHardIron, listener);
427 }
428
429 /**
430 * Constructor.
431 *
432 * @param position position where body magnetic flux density measurements
433 * have been taken.
434 * @param measurements collection of body magnetic flux density
435 * measurements with standard deviation of
436 * magnetometer measurements taken at the same
437 * position with zero velocity and unknown different
438 * orientations.
439 * @param initialHardIron initial hard-iron to find a solution.
440 * @param initialMm initial soft-iron matrix containing scale factors
441 * and cross coupling errors.
442 * @throws IllegalArgumentException if provided hard-iron matrix is not
443 * 3x1 or if soft-iron matrix is not
444 * 3x3.
445 */
446 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
447 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
448 final Matrix initialHardIron, final Matrix initialMm) {
449 super(position, measurements, initialHardIron, initialMm);
450 }
451
452 /**
453 * Constructor.
454 *
455 * @param position position where body magnetic flux density measurements
456 * have been taken.
457 * @param measurements collection of body magnetic flux density
458 * measurements with standard deviation of
459 * magnetometer measurements taken at the same
460 * position with zero velocity and unknown different
461 * orientations.
462 * @param initialHardIron initial hard-iron to find a solution.
463 * @param initialMm initial soft-iron matrix containing scale factors
464 * and cross coupling errors.
465 * @param listener listener to handle events raised by this calibrator.
466 * @throws IllegalArgumentException if provided hard-iron matrix is not
467 * 3x1 or if soft-iron matrix is not
468 * 3x3.
469 */
470 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
471 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
472 final Matrix initialHardIron, final Matrix initialMm,
473 final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
474 super(position, measurements, initialHardIron, initialMm, listener);
475 }
476
477 /**
478 * Constructor.
479 *
480 * @param position position where body magnetic flux density measurements
481 * have been taken.
482 * @param measurements collection of body magnetic flux density
483 * measurements with standard deviation of
484 * magnetometer measurements taken at the same
485 * position with zero velocity and unknown different
486 * orientations.
487 * @param commonAxisUsed indicates whether z-axis is assumed to be common
488 * for the accelerometer, gyroscope and magnetometer.
489 * @param initialHardIron initial hard-iron to find a solution.
490 * @param initialMm initial soft-iron matrix containing scale factors
491 * and cross coupling errors.
492 * @throws IllegalArgumentException if provided hard-iron matrix is not
493 * 3x1 or if soft-iron matrix is not
494 * 3x3.
495 */
496 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
497 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
498 final boolean commonAxisUsed, final Matrix initialHardIron, final Matrix initialMm) {
499 super(position, measurements, commonAxisUsed, initialHardIron, initialMm);
500 }
501
502 /**
503 * Constructor.
504 *
505 * @param position position where body magnetic flux density measurements
506 * have been taken.
507 * @param measurements collection of body magnetic flux density
508 * measurements with standard deviation of
509 * magnetometer measurements taken at the same
510 * position with zero velocity and unknown different
511 * orientations.
512 * @param commonAxisUsed indicates whether z-axis is assumed to be common
513 * for the accelerometer, gyroscope and magnetometer.
514 * @param initialHardIron initial hard-iron to find a solution.
515 * @param initialMm initial soft-iron matrix containing scale factors
516 * and cross coupling errors.
517 * @param listener listener to handle events raised by this calibrator.
518 * @throws IllegalArgumentException if provided hard-iron matrix is not
519 * 3x1 or if soft-iron matrix is not
520 * 3x3.
521 */
522 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
523 final NEDPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
524 final boolean commonAxisUsed, final Matrix initialHardIron, final Matrix initialMm,
525 final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
526 super(position, measurements, commonAxisUsed, initialHardIron, initialMm, listener);
527 }
528
529 /**
530 * Constructor.
531 *
532 * @param position position where body magnetic flux density measurements
533 * have been taken.
534 */
535 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(final ECEFPosition position) {
536 super(position);
537 }
538
539 /**
540 * Constructor.
541 *
542 * @param position position where body magnetic flux density measurements
543 * have been taken.
544 * @param measurements collection of body magnetic flux density
545 * measurements with standard deviation of
546 * magnetometer measurements taken at the same
547 * position with zero velocity and unknown different
548 * orientations.
549 */
550 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
551 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements) {
552 super(position, measurements);
553 }
554
555 /**
556 * Constructor.
557 *
558 * @param position position where body magnetic flux density measurements
559 * have been taken.
560 * @param measurements collection of body magnetic flux density
561 * measurements with standard deviation of
562 * magnetometer measurements taken at the same
563 * position with zero velocity and unknown different
564 * orientations.
565 * @param listener listener to handle events raised by this calibrator.
566 */
567 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
568 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
569 final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
570 super(position, measurements, listener);
571 }
572
573 /**
574 * Constructor.
575 *
576 * @param position position where body magnetic flux density measurements
577 * have been taken.
578 * @param measurements collection of body magnetic flux density
579 * measurements with standard deviation of
580 * magnetometer measurements taken at the same
581 * position with zero velocity and unknown different
582 * orientations.
583 * @param commonAxisUsed indicates whether z-axis is assumed to be common
584 * for the accelerometer, gyroscope and magnetometer.
585 */
586 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
587 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
588 final boolean commonAxisUsed) {
589 super(position, measurements, commonAxisUsed);
590 }
591
592 /**
593 * Constructor.
594 *
595 * @param position position where body magnetic flux density measurements
596 * have been taken.
597 * @param measurements collection of body magnetic flux density
598 * measurements with standard deviation of
599 * magnetometer measurements taken at the same
600 * position with zero velocity and unknown different
601 * orientations.
602 * @param commonAxisUsed indicates whether z-axis is assumed to be common
603 * for the accelerometer, gyroscope and magnetometer.
604 * @param listener listener to handle events raised by this calibrator.
605 */
606 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
607 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
608 final boolean commonAxisUsed, final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
609 super(position, measurements, commonAxisUsed, listener);
610 }
611
612 /**
613 * Constructor.
614 *
615 * @param position position where body magnetic flux density measurements
616 * have been taken.
617 * @param measurements collection of body magnetic flux density
618 * measurements with standard deviation of
619 * magnetometer measurements taken at the same
620 * position with zero velocity and unknown different
621 * orientations.
622 * @param initialHardIron initial hard-iron to find a solution.
623 * @throws IllegalArgumentException if provided hard-iron array does
624 * not have length 3.
625 */
626 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
627 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
628 final double[] initialHardIron) {
629 super(position, measurements, initialHardIron);
630 }
631
632 /**
633 * Constructor.
634 *
635 * @param position position where body magnetic flux density measurements
636 * have been taken.
637 * @param measurements collection of body magnetic flux density
638 * measurements with standard deviation of
639 * magnetometer measurements taken at the same
640 * position with zero velocity and unknown different
641 * orientations.
642 * @param initialHardIron initial hard-iron to find a solution.
643 * @param listener listener to handle events raised by this calibrator.
644 * @throws IllegalArgumentException if provided hard-iron array does
645 * not have length 3.
646 */
647 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
648 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
649 final double[] initialHardIron,
650 final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
651 super(position, measurements, initialHardIron, listener);
652 }
653
654 /**
655 * Constructor.
656 *
657 * @param position position where body magnetic flux density measurements
658 * have been taken.
659 * @param measurements collection of body magnetic flux density
660 * measurements with standard deviation of
661 * magnetometer measurements taken at the same
662 * position with zero velocity and unknown different
663 * orientations.
664 * @param commonAxisUsed indicates whether z-axis is assumed to be common
665 * for the accelerometer, gyroscope and magnetometer.
666 * @param initialHardIron initial hard-iron to find a solution.
667 * @throws IllegalArgumentException if provided hard-iron array does
668 * not have length 3.
669 */
670 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
671 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
672 final boolean commonAxisUsed, final double[] initialHardIron) {
673 super(position, measurements, commonAxisUsed, initialHardIron);
674 }
675
676 /**
677 * Constructor.
678 *
679 * @param position position where body magnetic flux density measurements
680 * have been taken.
681 * @param measurements collection of body magnetic flux density
682 * measurements with standard deviation of
683 * magnetometer measurements taken at the same
684 * position with zero velocity and unknown different
685 * orientations.
686 * @param commonAxisUsed indicates whether z-axis is assumed to be common
687 * for the accelerometer, gyroscope and magnetometer.
688 * @param initialHardIron initial hard-iron to find a solution.
689 * @param listener listener to handle events raised by this calibrator.
690 * @throws IllegalArgumentException if provided hard-iron array does
691 * not have length 3.
692 */
693 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
694 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
695 final boolean commonAxisUsed, final double[] initialHardIron,
696 final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
697 super(position, measurements, commonAxisUsed, initialHardIron, listener);
698 }
699
700 /**
701 * Constructor.
702 *
703 * @param position position where body magnetic flux density measurements
704 * have been taken.
705 * @param measurements collection of body magnetic flux density
706 * measurements with standard deviation of
707 * magnetometer measurements taken at the same
708 * position with zero velocity and unknown different
709 * orientations.
710 * @param initialHardIron initial hard-iron to find a solution.
711 * @throws IllegalArgumentException if provided hard-iron matrix is not
712 * 3x1.
713 */
714 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
715 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
716 final Matrix initialHardIron) {
717 super(position, measurements, initialHardIron);
718 }
719
720 /**
721 * Constructor.
722 *
723 * @param position position where body magnetic flux density measurements
724 * have been taken.
725 * @param measurements collection of body magnetic flux density
726 * measurements with standard deviation of
727 * magnetometer measurements taken at the same
728 * position with zero velocity and unknown different
729 * orientations.
730 * @param initialHardIron initial hard-iron to find a solution.
731 * @param listener listener to handle events raised by this calibrator.
732 * @throws IllegalArgumentException if provided hard-iron matrix is not
733 * 3x1.
734 */
735 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
736 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
737 final Matrix initialHardIron, final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
738 super(position, measurements, initialHardIron, listener);
739 }
740
741 /**
742 * Constructor.
743 *
744 * @param position position where body magnetic flux density measurements
745 * have been taken.
746 * @param measurements collection of body magnetic flux density
747 * measurements with standard deviation of
748 * magnetometer measurements taken at the same
749 * position with zero velocity and unknown different
750 * orientations.
751 * @param commonAxisUsed indicates whether z-axis is assumed to be common
752 * for the accelerometer, gyroscope and magnetometer.
753 * @param initialHardIron initial hard-iron to find a solution.
754 * @throws IllegalArgumentException if provided hard-iron matrix is not
755 * 3x1.
756 */
757 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
758 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
759 final boolean commonAxisUsed, final Matrix initialHardIron) {
760 super(position, measurements, commonAxisUsed, initialHardIron);
761 }
762
763 /**
764 * Constructor.
765 *
766 * @param position position where body magnetic flux density measurements
767 * have been taken.
768 * @param measurements collection of body magnetic flux density
769 * measurements with standard deviation of
770 * magnetometer measurements taken at the same
771 * position with zero velocity and unknown different
772 * orientations.
773 * @param commonAxisUsed indicates whether z-axis is assumed to be common
774 * for the accelerometer, gyroscope and magnetometer.
775 * @param initialHardIron initial hard-iron to find a solution.
776 * @param listener listener to handle events raised by this calibrator.
777 * @throws IllegalArgumentException if provided hard-iron matrix is not
778 * 3x1.
779 */
780 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
781 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
782 final boolean commonAxisUsed, final Matrix initialHardIron,
783 final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
784 super(position, measurements, commonAxisUsed, initialHardIron, listener);
785 }
786
787 /**
788 * Constructor.
789 *
790 * @param position position where body magnetic flux density measurements
791 * have been taken.
792 * @param measurements collection of body magnetic flux density
793 * measurements with standard deviation of
794 * magnetometer measurements taken at the same
795 * position with zero velocity and unknown different
796 * orientations.
797 * @param initialHardIron initial hard-iron to find a solution.
798 * @param initialMm initial soft-iron matrix containing scale factors
799 * and cross coupling errors.
800 * @throws IllegalArgumentException if provided hard-iron matrix is not
801 * 3x1 or if soft-iron matrix is not
802 * 3x3.
803 */
804 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
805 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
806 final Matrix initialHardIron, final Matrix initialMm) {
807 super(position, measurements, initialHardIron, initialMm);
808 }
809
810 /**
811 * Constructor.
812 *
813 * @param position position where body magnetic flux density measurements
814 * have been taken.
815 * @param measurements collection of body magnetic flux density
816 * measurements with standard deviation of
817 * magnetometer measurements taken at the same
818 * position with zero velocity and unknown different
819 * orientations.
820 * @param initialHardIron initial hard-iron to find a solution.
821 * @param initialMm initial soft-iron matrix containing scale factors
822 * and cross coupling errors.
823 * @param listener listener to handle events raised by this calibrator.
824 * @throws IllegalArgumentException if provided hard-iron matrix is not
825 * 3x1 or if soft-iron matrix is not
826 * 3x3.
827 */
828 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
829 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
830 final Matrix initialHardIron, final Matrix initialMm,
831 final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
832 super(position, measurements, initialHardIron, initialMm, listener);
833 }
834
835 /**
836 * Constructor.
837 *
838 * @param position position where body magnetic flux density measurements
839 * have been taken.
840 * @param measurements collection of body magnetic flux density
841 * measurements with standard deviation of
842 * magnetometer measurements taken at the same
843 * position with zero velocity and unknown different
844 * orientations.
845 * @param commonAxisUsed indicates whether z-axis is assumed to be common
846 * for the accelerometer, gyroscope and magnetometer.
847 * @param initialHardIron initial hard-iron to find a solution.
848 * @param initialMm initial soft-iron matrix containing scale factors
849 * and cross coupling errors.
850 * @throws IllegalArgumentException if provided hard-iron matrix is not
851 * 3x1 or if soft-iron matrix is not
852 * 3x3.
853 */
854 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
855 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
856 final boolean commonAxisUsed, final Matrix initialHardIron, final Matrix initialMm) {
857 super(position, measurements, commonAxisUsed, initialHardIron, initialMm);
858 }
859
860 /**
861 * Constructor.
862 *
863 * @param position position where body magnetic flux density measurements
864 * have been taken.
865 * @param measurements collection of body magnetic flux density
866 * measurements with standard deviation of
867 * magnetometer measurements taken at the same
868 * position with zero velocity and unknown different
869 * orientations.
870 * @param commonAxisUsed indicates whether z-axis is assumed to be common
871 * for the accelerometer, gyroscope and magnetometer.
872 * @param initialHardIron initial hard-iron to find a solution.
873 * @param initialMm initial soft-iron matrix containing scale factors
874 * and cross coupling errors.
875 * @param listener listener to handle events raised by this calibrator.
876 * @throws IllegalArgumentException if provided hard-iron matrix is not
877 * 3x1 or if soft-iron matrix is not
878 * 3x3.
879 */
880 public MSACRobustKnownPositionAndInstantMagnetometerCalibrator(
881 final ECEFPosition position, final List<StandardDeviationBodyMagneticFluxDensity> measurements,
882 final boolean commonAxisUsed, final Matrix initialHardIron, final Matrix initialMm,
883 final RobustKnownPositionAndInstantMagnetometerCalibratorListener listener) {
884 super(position, measurements, commonAxisUsed, initialHardIron, initialMm, listener);
885 }
886
887 /**
888 * Returns threshold to determine whether samples are inliers or not.
889 *
890 * @return threshold to determine whether samples are inliers or not.
891 */
892 public double getThreshold() {
893 return threshold;
894 }
895
896 /**
897 * Sets threshold to determine whether samples are inliers or not.
898 *
899 * @param threshold threshold to be set.
900 * @throws IllegalArgumentException if provided value is equal or less than
901 * zero.
902 * @throws LockedException if calibrator is currently running.
903 */
904 public void setThreshold(final double threshold) throws LockedException {
905 if (running) {
906 throw new LockedException();
907 }
908 if (threshold <= MIN_THRESHOLD) {
909 throw new IllegalArgumentException();
910 }
911 this.threshold = threshold;
912 }
913
914 /**
915 * Estimates magnetometer calibration parameters containing hard-iron
916 * bias and soft-iron scale factors and cross-coupling errors.
917 *
918 * @throws LockedException if calibrator is currently running.
919 * @throws NotReadyException if calibrator is not ready.
920 * @throws CalibrationException if estimation fails for numerical reasons.
921 */
922 @SuppressWarnings("DuplicatedCode")
923 @Override
924 public void calibrate() throws LockedException, NotReadyException, CalibrationException {
925 if (running) {
926 throw new LockedException();
927 }
928 if (!isReady()) {
929 throw new NotReadyException();
930 }
931
932 final var innerEstimator = new MSACRobustEstimator<>(new MSACRobustEstimatorListener<PreliminaryResult>() {
933 @Override
934 public double getThreshold() {
935 return threshold;
936 }
937
938 @Override
939 public int getTotalSamples() {
940 return measurements.size();
941 }
942
943 @Override
944 public int getSubsetSize() {
945 return preliminarySubsetSize;
946 }
947
948 @Override
949 public void estimatePreliminarSolutions(
950 final int[] samplesIndices, final List<PreliminaryResult> solutions) {
951 computePreliminarySolutions(samplesIndices, solutions);
952 }
953
954 @Override
955 public double computeResidual(final PreliminaryResult currentEstimation, final int i) {
956 return computeError(measurements.get(i), currentEstimation);
957 }
958
959 @Override
960 public boolean isReady() {
961 return MSACRobustKnownPositionAndInstantMagnetometerCalibrator.super.isReady();
962 }
963
964 @Override
965 public void onEstimateStart(final RobustEstimator<PreliminaryResult> estimator) {
966 // no action needed
967 }
968
969 @Override
970 public void onEstimateEnd(final RobustEstimator<PreliminaryResult> estimator) {
971 // no action needed
972 }
973
974 @Override
975 public void onEstimateNextIteration(
976 final RobustEstimator<PreliminaryResult> estimator, final int iteration) {
977 if (listener != null) {
978 listener.onCalibrateNextIteration(
979 MSACRobustKnownPositionAndInstantMagnetometerCalibrator.this, iteration);
980 }
981 }
982
983 @Override
984 public void onEstimateProgressChange(
985 final RobustEstimator<PreliminaryResult> estimator, final float progress) {
986 if (listener != null) {
987 listener.onCalibrateProgressChange(
988 MSACRobustKnownPositionAndInstantMagnetometerCalibrator.this, progress);
989 }
990 }
991 });
992
993 try {
994 running = true;
995
996 if (listener != null) {
997 listener.onCalibrateStart(this);
998 }
999
1000 inliersData = null;
1001
1002 initialize();
1003
1004 innerEstimator.setConfidence(confidence);
1005 innerEstimator.setMaxIterations(maxIterations);
1006 innerEstimator.setProgressDelta(progressDelta);
1007 final var preliminaryResult = innerEstimator.estimate();
1008 inliersData = innerEstimator.getInliersData();
1009
1010 attemptRefine(preliminaryResult);
1011
1012 if (listener != null) {
1013 listener.onCalibrateEnd(this);
1014 }
1015
1016 } catch (final com.irurueta.numerical.LockedException e) {
1017 throw new LockedException(e);
1018 } catch (final com.irurueta.numerical.NotReadyException e) {
1019 throw new NotReadyException(e);
1020 } catch (final RobustEstimatorException | IOException e) {
1021 throw new CalibrationException(e);
1022 } finally {
1023 running = false;
1024 }
1025 }
1026
1027 /**
1028 * Returns method being used for robust estimation.
1029 *
1030 * @return method being used for robust estimation.
1031 */
1032 @Override
1033 public RobustEstimatorMethod getMethod() {
1034 return RobustEstimatorMethod.MSAC;
1035 }
1036
1037 /**
1038 * Indicates whether this calibrator requires quality scores for each
1039 * measurement or not.
1040 *
1041 * @return true if quality scores are required, false otherwise.
1042 */
1043 @Override
1044 public boolean isQualityScoresRequired() {
1045 return false;
1046 }
1047 }