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