1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.irurueta.navigation.inertial.calibration.intervals.thresholdfactor;
17
18 import com.irurueta.algebra.Matrix;
19 import com.irurueta.navigation.LockedException;
20 import com.irurueta.navigation.NotReadyException;
21 import com.irurueta.navigation.inertial.BodyKinematicsAndMagneticFluxDensity;
22 import com.irurueta.navigation.inertial.calibration.AccelerometerNoiseRootPsdSource;
23 import com.irurueta.navigation.inertial.calibration.CalibrationException;
24 import com.irurueta.navigation.inertial.calibration.StandardDeviationBodyMagneticFluxDensity;
25 import com.irurueta.navigation.inertial.calibration.generators.MagnetometerMeasurementsGenerator;
26 import com.irurueta.navigation.inertial.calibration.generators.MagnetometerMeasurementsGeneratorListener;
27 import com.irurueta.navigation.inertial.calibration.intervals.TriadStaticIntervalDetector;
28 import com.irurueta.navigation.inertial.calibration.magnetometer.KnownHardIronMagnetometerCalibrator;
29 import com.irurueta.navigation.inertial.calibration.magnetometer.MagnetometerCalibratorMeasurementType;
30 import com.irurueta.navigation.inertial.calibration.magnetometer.MagnetometerNonLinearCalibrator;
31 import com.irurueta.navigation.inertial.calibration.magnetometer.OrderedStandardDeviationBodyMagneticFluxDensityMagnetometerCalibrator;
32 import com.irurueta.navigation.inertial.calibration.magnetometer.QualityScoredMagnetometerCalibrator;
33 import com.irurueta.navigation.inertial.calibration.magnetometer.UnknownHardIronMagnetometerCalibrator;
34 import com.irurueta.navigation.inertial.calibration.magnetometer.UnorderedStandardDeviationBodyMagneticFluxDensityMagnetometerCalibrator;
35 import com.irurueta.units.Acceleration;
36 import com.irurueta.units.AccelerationUnit;
37 import com.irurueta.units.Time;
38
39 import java.util.ArrayList;
40 import java.util.List;
41
42
43
44
45
46
47
48
49
50
51 public abstract class MagnetometerIntervalDetectorThresholdFactorOptimizer extends
52 IntervalDetectorThresholdFactorOptimizer<BodyKinematicsAndMagneticFluxDensity,
53 MagnetometerIntervalDetectorThresholdFactorOptimizerDataSource> implements
54 AccelerometerNoiseRootPsdSource {
55
56
57
58
59 public static final double DEFAULT_MIN_THRESHOLD_FACTOR = 2.0;
60
61
62
63
64 public static final double DEFAULT_MAX_THRESHOLD_FACTOR = 10.0;
65
66
67
68
69 protected double minThresholdFactor = DEFAULT_MIN_THRESHOLD_FACTOR;
70
71
72
73
74 protected double maxThresholdFactor = DEFAULT_MAX_THRESHOLD_FACTOR;
75
76
77
78
79 private MagnetometerNonLinearCalibrator calibrator;
80
81
82
83
84 private MagnetometerMeasurementsGenerator generator;
85
86
87
88
89 private List<StandardDeviationBodyMagneticFluxDensity> measurements;
90
91
92
93
94
95 private QualityScoreMapper<StandardDeviationBodyMagneticFluxDensity> qualityScoreMapper =
96 new DefaultMagnetometerQualityScoreMapper();
97
98
99
100
101
102
103
104
105 private double baseNoiseLevel;
106
107
108
109
110
111
112 private double threshold;
113
114
115
116
117 private Matrix estimatedCovariance;
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159 private Matrix estimatedMm;
160
161
162
163
164
165 private double[] estimatedHardIron;
166
167
168
169
170 protected MagnetometerIntervalDetectorThresholdFactorOptimizer() {
171 initialize();
172 }
173
174
175
176
177
178
179 protected MagnetometerIntervalDetectorThresholdFactorOptimizer(
180 final MagnetometerIntervalDetectorThresholdFactorOptimizerDataSource dataSource) {
181 super(dataSource);
182 initialize();
183 }
184
185
186
187
188
189
190
191
192
193 protected MagnetometerIntervalDetectorThresholdFactorOptimizer(final MagnetometerNonLinearCalibrator calibrator) {
194 try {
195 setCalibrator(calibrator);
196 } catch (final LockedException ignore) {
197
198 }
199 initialize();
200 }
201
202
203
204
205
206
207
208
209
210
211 protected MagnetometerIntervalDetectorThresholdFactorOptimizer(
212 final MagnetometerIntervalDetectorThresholdFactorOptimizerDataSource dataSource,
213 final MagnetometerNonLinearCalibrator calibrator) {
214 super(dataSource);
215 try {
216 setCalibrator(calibrator);
217 } catch (final LockedException ignore) {
218
219 }
220 initialize();
221 }
222
223
224
225
226
227
228 public MagnetometerNonLinearCalibrator getCalibrator() {
229 return calibrator;
230 }
231
232
233
234
235
236
237
238
239
240 public void setCalibrator(final MagnetometerNonLinearCalibrator calibrator) throws LockedException {
241 if (running) {
242 throw new LockedException();
243 }
244
245 if (calibrator != null && calibrator.getMeasurementType()
246 != MagnetometerCalibratorMeasurementType.STANDARD_DEVIATION_BODY_MAGNETIC_FLUX_DENSITY) {
247 throw new IllegalArgumentException();
248 }
249
250 this.calibrator = calibrator;
251 }
252
253
254
255
256
257
258
259 public QualityScoreMapper<StandardDeviationBodyMagneticFluxDensity> getQualityScoreMapper() {
260 return qualityScoreMapper;
261 }
262
263
264
265
266
267
268
269
270 public void setQualityScoreMapper(
271 final QualityScoreMapper<StandardDeviationBodyMagneticFluxDensity> qualityScoreMapper)
272 throws LockedException {
273 if (running) {
274 throw new LockedException();
275 }
276
277 this.qualityScoreMapper = qualityScoreMapper;
278 }
279
280
281
282
283
284
285 public double getMinThresholdFactor() {
286 return minThresholdFactor;
287 }
288
289
290
291
292
293
294 public double getMaxThresholdFactor() {
295 return maxThresholdFactor;
296 }
297
298
299
300
301
302
303
304
305
306
307
308
309 public void setThresholdFactorRange(final double minThresholdFactor, final double maxThresholdFactor)
310 throws LockedException {
311 if (running) {
312 throw new LockedException();
313 }
314 if (minThresholdFactor < 0.0 || maxThresholdFactor < 0.0 || minThresholdFactor >= maxThresholdFactor) {
315 throw new IllegalArgumentException();
316 }
317
318 this.minThresholdFactor = minThresholdFactor;
319 this.maxThresholdFactor = maxThresholdFactor;
320 }
321
322
323
324
325
326
327 @Override
328 public boolean isReady() {
329 return super.isReady() && calibrator != null && qualityScoreMapper != null;
330 }
331
332
333
334
335
336
337
338 public double getTimeInterval() {
339 return generator.getTimeInterval();
340 }
341
342
343
344
345
346
347
348
349
350 public void setTimeInterval(final double timeInterval) throws LockedException {
351 if (running) {
352 throw new LockedException();
353 }
354
355 generator.setTimeInterval(timeInterval);
356 }
357
358
359
360
361
362
363
364 public Time getTimeIntervalAsTime() {
365 return generator.getTimeIntervalAsTime();
366 }
367
368
369
370
371
372
373
374 public void getTimeIntervalAsTime(final Time result) {
375 generator.getTimeIntervalAsTime(result);
376 }
377
378
379
380
381
382
383
384
385
386 public void setTimeInterval(final Time timeInterval) throws LockedException {
387 if (running) {
388 throw new LockedException();
389 }
390
391 generator.setTimeInterval(timeInterval);
392 }
393
394
395
396
397
398
399
400
401
402
403 public int getMinStaticSamples() {
404 return generator.getMinStaticSamples();
405 }
406
407
408
409
410
411
412
413
414
415
416
417
418 public void setMinStaticSamples(final int minStaticSamples)
419 throws LockedException {
420 if (running) {
421 throw new LockedException();
422 }
423
424 generator.setMinStaticSamples(minStaticSamples);
425 }
426
427
428
429
430
431
432
433 public int getMaxDynamicSamples() {
434 return generator.getMaxDynamicSamples();
435 }
436
437
438
439
440
441
442
443
444
445
446 public void setMaxDynamicSamples(final int maxDynamicSamples) throws LockedException {
447 if (running) {
448 throw new LockedException();
449 }
450
451 generator.setMaxDynamicSamples(maxDynamicSamples);
452 }
453
454
455
456
457
458
459
460
461 public int getWindowSize() {
462 return generator.getWindowSize();
463 }
464
465
466
467
468
469
470
471
472
473
474
475
476 public void setWindowSize(final int windowSize) throws LockedException {
477 if (running) {
478 throw new LockedException();
479 }
480
481 generator.setWindowSize(windowSize);
482 }
483
484
485
486
487
488
489
490
491 public int getInitialStaticSamples() {
492 return generator.getInitialStaticSamples();
493 }
494
495
496
497
498
499
500
501
502
503
504
505 public void setInitialStaticSamples(final int initialStaticSamples) throws LockedException {
506 if (running) {
507 throw new LockedException();
508 }
509
510 generator.setInitialStaticSamples(initialStaticSamples);
511 }
512
513
514
515
516
517
518
519
520
521 public double getInstantaneousNoiseLevelFactor() {
522 return generator.getInstantaneousNoiseLevelFactor();
523 }
524
525
526
527
528
529
530
531
532
533
534
535
536
537 public void setInstantaneousNoiseLevelFactor(final double instantaneousNoiseLevelFactor) throws LockedException {
538 if (running) {
539 throw new LockedException();
540 }
541
542 generator.setInstantaneousNoiseLevelFactor(instantaneousNoiseLevelFactor);
543 }
544
545
546
547
548
549
550
551
552
553 public double getBaseNoiseLevelAbsoluteThreshold() {
554 return generator.getBaseNoiseLevelAbsoluteThreshold();
555 }
556
557
558
559
560
561
562
563
564
565
566
567
568 public void setBaseNoiseLevelAbsoluteThreshold(final double baseNoiseLevelAbsoluteThreshold)
569 throws LockedException {
570 if (running) {
571 throw new LockedException();
572 }
573
574 generator.setBaseNoiseLevelAbsoluteThreshold(baseNoiseLevelAbsoluteThreshold);
575 }
576
577
578
579
580
581
582
583
584 public Acceleration getBaseNoiseLevelAbsoluteThresholdAsMeasurement() {
585 return generator.getBaseNoiseLevelAbsoluteThresholdAsMeasurement();
586 }
587
588
589
590
591
592
593
594 public void getBaseNoiseLevelAbsoluteThresholdAsMeasurement(final Acceleration result) {
595 generator.getBaseNoiseLevelAbsoluteThresholdAsMeasurement(result);
596 }
597
598
599
600
601
602
603
604
605
606
607
608 public void setBaseNoiseLevelAbsoluteThreshold(final Acceleration baseNoiseLevelAbsoluteThreshold)
609 throws LockedException {
610 if (running) {
611 throw new LockedException();
612 }
613
614 generator.setBaseNoiseLevelAbsoluteThreshold(baseNoiseLevelAbsoluteThreshold);
615 }
616
617
618
619
620
621
622
623
624
625
626
627 public double getAccelerometerBaseNoiseLevel() {
628 return baseNoiseLevel;
629 }
630
631
632
633
634
635
636
637
638
639
640 public Acceleration getAccelerometerBaseNoiseLevelAsMeasurement() {
641 return createMeasurement(baseNoiseLevel, getDefaultUnit());
642 }
643
644
645
646
647
648
649
650
651
652 public void getAccelerometerBaseNoiseLevelAsMeasurement(final Acceleration result) {
653 result.setValue(baseNoiseLevel);
654 result.setUnit(getDefaultUnit());
655 }
656
657
658
659
660
661
662
663
664 public double getAccelerometerBaseNoiseLevelPsd() {
665 return baseNoiseLevel * baseNoiseLevel * getTimeInterval();
666 }
667
668
669
670
671
672
673
674
675 @Override
676 public double getAccelerometerBaseNoiseLevelRootPsd() {
677 return baseNoiseLevel * Math.sqrt(getTimeInterval());
678 }
679
680
681
682
683
684
685
686
687
688 public double getThreshold() {
689 return threshold;
690 }
691
692
693
694
695
696
697
698
699 public Acceleration getThresholdAsMeasurement() {
700 return createMeasurement(threshold, getDefaultUnit());
701 }
702
703
704
705
706
707
708
709 public void getThresholdAsMeasurement(final Acceleration result) {
710 result.setValue(threshold);
711 result.setUnit(getDefaultUnit());
712 }
713
714
715
716
717
718
719
720
721 public double[] getEstimatedHardIron() {
722 return estimatedHardIron;
723 }
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768 public Matrix getEstimatedMm() {
769 return estimatedMm;
770 }
771
772
773
774
775
776
777
778
779
780
781
782
783
784 protected double evaluateForThresholdFactor(final double thresholdFactor) throws LockedException,
785 CalibrationException, NotReadyException, IntervalDetectorThresholdFactorOptimizerException {
786 if (measurements == null) {
787 measurements = new ArrayList<>();
788 } else {
789 measurements.clear();
790 }
791
792 generator.reset();
793 generator.setThresholdFactor(thresholdFactor);
794
795 var count = dataSource.count();
796 var failed = false;
797 for (var i = 0; i < count; i++) {
798 final var bodyKinematics = dataSource.getAt(i);
799 if (!generator.process(bodyKinematics)) {
800 failed = true;
801 break;
802 }
803 }
804
805 if (failed || generator.getStatus() == TriadStaticIntervalDetector.Status.FAILED) {
806
807 return Double.MAX_VALUE;
808 }
809
810
811 if (measurements.size() < calibrator.getMinimumRequiredMeasurements()) {
812 return Double.MAX_VALUE;
813 }
814
815
816 switch (calibrator.getMeasurementType()) {
817 case STANDARD_DEVIATION_BODY_MAGNETIC_FLUX_DENSITY:
818 if (calibrator.isOrderedMeasurementsRequired()) {
819 final var cal =
820 (OrderedStandardDeviationBodyMagneticFluxDensityMagnetometerCalibrator) this.calibrator;
821
822 cal.setMeasurements(measurements);
823 } else {
824 final var cal =
825 (UnorderedStandardDeviationBodyMagneticFluxDensityMagnetometerCalibrator) this.calibrator;
826
827 cal.setMeasurements(measurements);
828 }
829
830 if (calibrator.isQualityScoresRequired()) {
831 final var cal = (QualityScoredMagnetometerCalibrator) this.calibrator;
832
833 final var size = measurements.size();
834 final var qualityScores = new double[size];
835 for (var i = 0; i < size; i++) {
836 qualityScores[i] = qualityScoreMapper.map(measurements.get(i));
837 }
838 cal.setQualityScores(qualityScores);
839 }
840 break;
841 case FRAME_BODY_MAGNETIC_FLUX_DENSITY, STANDARD_DEVIATION_FRAME_BODY_MAGNETIC_FLUX_DENSITY:
842
843 default:
844 throw new IntervalDetectorThresholdFactorOptimizerException();
845 }
846
847 calibrator.calibrate();
848
849 final var mse = calibrator.getEstimatedMse();
850 if (mse < minMse) {
851 keepBestResult(mse, thresholdFactor);
852 }
853 return mse;
854 }
855
856
857
858
859
860
861 private void initialize() {
862 final var generatorListener = new MagnetometerMeasurementsGeneratorListener() {
863 @Override
864 public void onInitializationStarted(final MagnetometerMeasurementsGenerator generator) {
865
866 }
867
868 @Override
869 public void onInitializationCompleted(
870 final MagnetometerMeasurementsGenerator generator, final double baseNoiseLevel) {
871
872 }
873
874 @Override
875 public void onError(
876 final MagnetometerMeasurementsGenerator generator,
877 final TriadStaticIntervalDetector.ErrorReason reason) {
878
879 }
880
881 @Override
882 public void onStaticIntervalDetected(final MagnetometerMeasurementsGenerator generator) {
883
884 }
885
886 @Override
887 public void onDynamicIntervalDetected(final MagnetometerMeasurementsGenerator generator) {
888
889 }
890
891 @Override
892 public void onStaticIntervalSkipped(final MagnetometerMeasurementsGenerator generator) {
893
894 }
895
896 @Override
897 public void onDynamicIntervalSkipped(final MagnetometerMeasurementsGenerator generator) {
898
899 }
900
901 @Override
902 public void onGeneratedMeasurement(
903 final MagnetometerMeasurementsGenerator generator,
904 final StandardDeviationBodyMagneticFluxDensity measurement) {
905 measurements.add(measurement);
906 }
907
908 @Override
909 public void onReset(final MagnetometerMeasurementsGenerator generator) {
910
911 }
912 };
913
914 generator = new MagnetometerMeasurementsGenerator(generatorListener);
915 }
916
917
918
919
920
921
922
923 private void keepBestResult(final double mse, final double thresholdFactor) {
924 minMse = mse;
925 optimalThresholdFactor = thresholdFactor;
926
927 baseNoiseLevel = generator.getAccelerometerBaseNoiseLevel();
928 threshold = generator.getThreshold();
929
930 if (estimatedCovariance == null) {
931 estimatedCovariance = new Matrix(calibrator.getEstimatedCovariance());
932 } else {
933 estimatedCovariance.copyFrom(calibrator.getEstimatedCovariance());
934 }
935 if (estimatedMm == null) {
936 estimatedMm = new Matrix(calibrator.getEstimatedMm());
937 } else {
938 estimatedMm.copyFrom(calibrator.getEstimatedMm());
939 }
940 if (calibrator instanceof UnknownHardIronMagnetometerCalibrator unknownHardIronMagnetometerCalibrator) {
941 estimatedHardIron = unknownHardIronMagnetometerCalibrator.getEstimatedHardIron();
942 } else if (calibrator instanceof KnownHardIronMagnetometerCalibrator knownHardIronMagnetometerCalibrator) {
943 estimatedHardIron = knownHardIronMagnetometerCalibrator.getHardIron();
944 }
945 }
946
947
948
949
950
951
952
953
954 private Acceleration createMeasurement(final double value, final AccelerationUnit unit) {
955 return new Acceleration(value, unit);
956 }
957
958
959
960
961
962
963
964 private AccelerationUnit getDefaultUnit() {
965 return AccelerationUnit.METERS_PER_SQUARED_SECOND;
966 }
967 }