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