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 21 /** 22 * Optimizes the threshold factor for interval detection of accelerometer data based 23 * on results of accelerometers, gyroscopes or magnetometers calibration. 24 * 25 * @param <T> type of data to be used as input for this optimizer. 26 * @param <S> type of data source for this optimizer. 27 */ 28 public abstract class IntervalDetectorThresholdFactorOptimizer<T, 29 S extends IntervalDetectorThresholdFactorOptimizerDataSource<T>> { 30 31 /** 32 * Default amount of progress variation before notifying a change in optimization progress. 33 * By default, this is set to 5%. 34 */ 35 public static final float DEFAULT_PROGRESS_DELTA = 0.05f; 36 37 /** 38 * Minimum allowed value for progress delta. 39 */ 40 public static final float MIN_PROGRESS_DELTA = 0.0f; 41 42 /** 43 * Maximum allowed value for progress delta. 44 */ 45 public static final float MAX_PROGRESS_DELTA = 1.0f; 46 47 /** 48 * Retrieves data for this optimizer. 49 */ 50 protected S dataSource; 51 52 /** 53 * Indicates whether this optimizer is running or not. 54 */ 55 protected boolean running; 56 57 /** 58 * Minimum Mean Square Error that has been found. 59 */ 60 protected double minMse; 61 62 /** 63 * Optimal threshold factor that has been found. 64 */ 65 protected double optimalThresholdFactor; 66 67 /** 68 * Listener that notifies events generated by this optimizer. 69 */ 70 protected IntervalDetectorThresholdFactorOptimizerListener<T, S> listener; 71 72 /** 73 * Amount of progress variation before notifying a progress change during optimization. 74 */ 75 protected float progressDelta = DEFAULT_PROGRESS_DELTA; 76 77 /** 78 * Current progress of optimization. 79 */ 80 protected float progress; 81 82 /** 83 * Previously notified progress of optimization. 84 */ 85 protected float previousProgress; 86 87 /** 88 * Constructor. 89 */ 90 protected IntervalDetectorThresholdFactorOptimizer() { 91 } 92 93 /** 94 * Constructor. 95 * 96 * @param dataSource instance in charge of retrieving data for this optimizer. 97 */ 98 protected IntervalDetectorThresholdFactorOptimizer(final S dataSource) { 99 this.dataSource = dataSource; 100 } 101 102 /** 103 * Gets instance in charge of retrieving data for this optimizer. 104 * 105 * @return instance in charge of retrieving data for this optimizer. 106 */ 107 public S getDataSource() { 108 return dataSource; 109 } 110 111 /** 112 * Sets an instance in charge of retrieving data for this optimizer. 113 * 114 * @param dataSource instance in charge of retrieving data for this optimizer. 115 * @throws LockedException if optimizer is already running. 116 */ 117 public void setDataSource(final S dataSource) throws LockedException { 118 if (running) { 119 throw new LockedException(); 120 } 121 122 this.dataSource = dataSource; 123 } 124 125 /** 126 * Gets a listener that notifies events generated by this optimizer. 127 * 128 * @return listener that notifies events generated by this optimizer. 129 */ 130 public IntervalDetectorThresholdFactorOptimizerListener<T, S> getListener() { 131 return listener; 132 } 133 134 /** 135 * Sets a listener that notifies events generated by this optimizer. 136 * 137 * @param listener listener that notifies events generated by this optimizer. 138 * @throws LockedException if optimizer is already running. 139 */ 140 public void setListener(final IntervalDetectorThresholdFactorOptimizerListener<T, S> listener) 141 throws LockedException { 142 if (running) { 143 throw new LockedException(); 144 } 145 146 this.listener = listener; 147 } 148 149 /** 150 * Returns the amount of progress variation before notifying a progress change during 151 * optimization. 152 * 153 * @return amount of progress variation before notifying a progress change during 154 * optimization. 155 */ 156 public float getProgressDelta() { 157 return progressDelta; 158 } 159 160 /** 161 * Sets the amount of progress variation before notifying a progress change during 162 * optimization. 163 * 164 * @param progressDelta amount of progress variation before notifying a progress 165 * change during optimization. 166 * @throws IllegalArgumentException if the progress delta is less than zero or greater than 1. 167 * @throws LockedException if optimizer is currently running. 168 */ 169 public void setProgressDelta(final float progressDelta) throws LockedException { 170 if (running) { 171 throw new LockedException(); 172 } 173 if (progressDelta < MIN_PROGRESS_DELTA || progressDelta > MAX_PROGRESS_DELTA) { 174 throw new IllegalArgumentException(); 175 } 176 this.progressDelta = progressDelta; 177 } 178 179 /** 180 * Indicates whether this optimizer is busy optimizing a threshold factor. 181 * 182 * @return true if optimizer is busy, false otherwise. 183 */ 184 public boolean isRunning() { 185 return running; 186 } 187 188 /** 189 * Indicates whether this optimizer is ready to start optimization. 190 * 191 * @return true if this optimizer is ready, false otherwise. 192 */ 193 public boolean isReady() { 194 return dataSource != null; 195 } 196 197 /** 198 * Gets minimum Mean Square Error that has been found for calibration. 199 * 200 * @return minimum Mean Square Error that has been found. 201 */ 202 public double getMinMse() { 203 return minMse; 204 } 205 206 /** 207 * Gets the optimal threshold factor that has been found. 208 * 209 * @return optimal threshold factor that has been found. 210 */ 211 public double getOptimalThresholdFactor() { 212 return optimalThresholdFactor; 213 } 214 215 /** 216 * Optimizes the threshold factor for a static interval detector or measurement 217 * generator to minimize MSE (Minimum Squared Error) of estimated 218 * calibration parameters. 219 * 220 * @return optimized threshold factor. 221 * @throws NotReadyException if this optimizer is not 222 * ready to start optimization. 223 * @throws LockedException if optimizer is already 224 * running. 225 * @throws IntervalDetectorThresholdFactorOptimizerException if optimization fails for 226 * some reason. 227 */ 228 public abstract double optimize() throws NotReadyException, LockedException, 229 IntervalDetectorThresholdFactorOptimizerException; 230 231 /** 232 * Checks current progress and notifies if progress has changed significantly. 233 */ 234 protected void checkAndNotifyProgress() { 235 if (listener != null && (progress - previousProgress > progressDelta)) { 236 previousProgress = progress; 237 listener.onOptimizeProgressChange(this, Math.min(progress, 1.0f)); 238 } 239 } 240 241 /** 242 * Initializes progress values. 243 */ 244 protected void initProgress() { 245 previousProgress = 0.0f; 246 progress = 0.0f; 247 } 248 }