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