1 /*
2 * Copyright (C) 2021 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.intervals.thresholdfactor;
17
18 import com.irurueta.navigation.LockedException;
19 import com.irurueta.navigation.NotReadyException;
20 import com.irurueta.navigation.inertial.calibration.BodyKinematicsSequence;
21 import com.irurueta.navigation.inertial.calibration.gyroscope.GyroscopeCalibratorMeasurementOrSequenceType;
22 import com.irurueta.navigation.inertial.calibration.gyroscope.GyroscopeNonLinearCalibrator;
23
24 /**
25 * Optimizes the threshold factor for interval detection of accelerometer and gyroscope data
26 * based on results of calibration.
27 * Only gyroscope calibrators based on unknown orientation are supported (in other terms,
28 * calibrators must be {@link GyroscopeNonLinearCalibrator} and must support
29 * {@link GyroscopeCalibratorMeasurementOrSequenceType#BODY_KINEMATICS_SEQUENCE}).
30 * This implementation makes an exhaustive search between minimum and maximum
31 * threshold factor values to find the threshold value that produces the
32 * minimum Mean Square Error (MSE) for calibration parameters.
33 */
34 public class ExhaustiveGyroscopeIntervalDetectorThresholdFactorOptimizer extends
35 GyroscopeIntervalDetectorThresholdFactorOptimizer {
36
37 /**
38 * Default step value to make exhaustive search of threshold factor values.
39 */
40 public static final double DEFAULT_STEP = 1.0;
41
42 /**
43 * Step to make exhaustive search of threshold factor values between
44 * {@link #getMaxThresholdFactor()} and {@link #getMaxThresholdFactor()}.
45 */
46 private double thresholdFactorStep = DEFAULT_STEP;
47
48 /**
49 * Constructor.
50 */
51 public ExhaustiveGyroscopeIntervalDetectorThresholdFactorOptimizer() {
52 super();
53 }
54
55 /**
56 * Constructor.
57 *
58 * @param dataSource instance in charge of retrieving data for this optimizer.
59 */
60 public ExhaustiveGyroscopeIntervalDetectorThresholdFactorOptimizer(
61 final GyroscopeIntervalDetectorThresholdFactorOptimizerDataSource dataSource) {
62 super(dataSource);
63 }
64
65 /**
66 * Constructor.
67 *
68 * @param calibrator a gyroscope calibrator to be used to optimize its
69 * Mean Square Error (MSE).
70 * @throws IllegalArgumentException if gyroscope calibrator does not use
71 * {@link BodyKinematicsSequence} sequences.
72 */
73 public ExhaustiveGyroscopeIntervalDetectorThresholdFactorOptimizer(final GyroscopeNonLinearCalibrator calibrator) {
74 super(calibrator);
75 }
76
77 /**
78 * Constructor.
79 *
80 * @param dataSource instance in charge of retrieving data for this optimizer.
81 * @param calibrator a gyroscope calibrator to be used to optimize its
82 * Mean Square Error (MSE).
83 * @throws IllegalArgumentException if gyroscope calibrator does not use
84 * {@link BodyKinematicsSequence} sequences.
85 */
86 public ExhaustiveGyroscopeIntervalDetectorThresholdFactorOptimizer(
87 final GyroscopeIntervalDetectorThresholdFactorOptimizerDataSource dataSource,
88 final GyroscopeNonLinearCalibrator calibrator) {
89 super(dataSource, calibrator);
90 }
91
92 /**
93 * Gets the step to make exhaustive search of threshold values between
94 * {@link #getMaxThresholdFactor()} and {@link #getMaxThresholdFactor()}.
95 *
96 * @return step to make exhaustive search of threshold values.
97 */
98 public double getThresholdFactorStep() {
99 return thresholdFactorStep;
100 }
101
102 /**
103 * Sets step to make exhaustive search of threshold values between
104 * {@link #getMaxThresholdFactor()} and {@link #getMaxThresholdFactor()}.
105 *
106 * @param thresholdStep step to make exhaustive search of threshold values.
107 * @throws LockedException if optimizer is already running.
108 * @throws IllegalArgumentException if provided value is zero or negative.
109 */
110 public void setThresholdFactorStep(final double thresholdStep) throws LockedException {
111 if (running) {
112 throw new LockedException();
113 }
114 if (thresholdStep <= 0.0) {
115 throw new IllegalArgumentException();
116 }
117
118 thresholdFactorStep = thresholdStep;
119 }
120
121 /**
122 * Optimizes the threshold factor for a static interval detector or measurement
123 * generator to minimize MSE (Minimum Squared Error) of estimated
124 * calibration parameters.
125 *
126 * @return optimized threshold factor.
127 * @throws NotReadyException if this optimizer is not ready to start optimization.
128 * @throws LockedException if optimizer is already running.
129 * @throws IntervalDetectorThresholdFactorOptimizerException if optimization fails for
130 * some reason.
131 */
132 @Override
133 public double optimize() throws NotReadyException, LockedException,
134 IntervalDetectorThresholdFactorOptimizerException {
135 if (running) {
136 throw new LockedException();
137 }
138
139 if (!isReady()) {
140 throw new NotReadyException();
141 }
142
143 var hasResult = false;
144 minMse = Double.MAX_VALUE;
145 try {
146 running = true;
147
148 initProgress();
149 final var progressStep = (float) (thresholdFactorStep
150 / (thresholdFactorStep + maxThresholdFactor - minThresholdFactor));
151
152 if (listener != null) {
153 listener.onOptimizeStart(this);
154 }
155
156 for (var thresholdFactor = minThresholdFactor;
157 thresholdFactor <= maxThresholdFactor;
158 thresholdFactor += thresholdFactorStep) {
159 try {
160 evaluateForThresholdFactor(thresholdFactor);
161 hasResult = true;
162 } catch (final Exception ignore) {
163 // when an error occurs, skip to the next iteration
164 }
165
166 progress += progressStep;
167 checkAndNotifyProgress();
168 }
169
170 if (!hasResult) {
171 throw new IntervalDetectorThresholdFactorOptimizerException();
172 }
173
174 if (listener != null) {
175 listener.onOptimizeEnd(this);
176 }
177
178 } finally {
179 running = false;
180 }
181
182 return optimalThresholdFactor;
183 }
184 }