1 /*
2 * Copyright (C) 2019 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.indoor.position;
17
18 import com.irurueta.algebra.Matrix;
19 import com.irurueta.geometry.Point;
20 import com.irurueta.navigation.LockedException;
21 import com.irurueta.navigation.NotReadyException;
22 import com.irurueta.navigation.indoor.RadioSource;
23 import com.irurueta.navigation.indoor.RadioSourceLocated;
24 import com.irurueta.navigation.indoor.RangingAndRssiFingerprint;
25 import com.irurueta.navigation.indoor.RangingAndRssiReading;
26 import com.irurueta.navigation.indoor.RangingFingerprint;
27 import com.irurueta.navigation.indoor.RangingReading;
28 import com.irurueta.navigation.indoor.RssiFingerprint;
29 import com.irurueta.navigation.indoor.RssiReading;
30 import com.irurueta.numerical.robust.InliersData;
31 import com.irurueta.numerical.robust.RobustEstimatorException;
32 import com.irurueta.numerical.robust.RobustEstimatorMethod;
33
34 import java.util.ArrayList;
35 import java.util.List;
36
37 /**
38 * Base class for robust position estimation, using RSSI readings first to obtain
39 * an initial coarse position estimation, and then ranging readings to refine such
40 * estimation.
41 *
42 * @param <P> a {@link Point} type.
43 */
44 public abstract class SequentialRobustRangingAndRssiPositionEstimator<P extends Point<?>> {
45
46 /**
47 * Default robust estimator method for robust position estimation using ranging
48 * data when no robust method is provided.
49 */
50 public static final RobustEstimatorMethod DEFAULT_RANGING_ROBUST_METHOD = RobustEstimatorMethod.PROMEDS;
51
52 /**
53 * Default robust method for coarse robust position estimation using RSSI
54 * data when no robust method is provided.
55 */
56 public static final RobustEstimatorMethod DEFAULT_RSSI_ROBUST_METHOD = RobustEstimatorMethod.PROMEDS;
57
58 /**
59 * Indicates that by default located radio source position covariance is taken
60 * into account (if available) to determine distance standard deviation for ranging
61 * measurements.
62 */
63 public static final boolean DEFAULT_USE_RANGING_RADIO_SOURCE_POSITION_COVARIANCE = true;
64
65 /**
66 * Indicates that by default located radio source position covariance is taken
67 * into account (if available) to determine distance standard deviation for RSSI
68 * measurements.
69 */
70 public static final boolean DEFAULT_USE_RSSI_RADIO_SOURCE_POSITION_COVARIANCE = true;
71
72 /**
73 * Indicates that by default readings are distributed evenly among radio sources
74 * taking into account quality scores of both radio sources and ranging readings.
75 */
76 public static final boolean DEFAULT_EVENLY_DISTRIBUTE_RANGING_READINGS = true;
77
78 /**
79 * Indicates that by default readings are distributed evenly among radio sources
80 * taking into account quality scores of both radio sources and RSSI readings.
81 */
82 public static final boolean DEFAULT_EVENLY_DISTRIBUTE_RSSI_READINGS = true;
83
84 /**
85 * Distance standard deviation assumed for provided distances as a fallback when
86 * none can be determined.
87 */
88 public static final double FALLBACK_DISTANCE_STANDARD_DEVIATION =
89 RobustPositionEstimator.FALLBACK_DISTANCE_STANDARD_DEVIATION;
90
91 /**
92 * Default amount of progress variation before notifying a change in estimation progress.
93 * By default, this is set to 5%.
94 */
95 public static final float DEFAULT_PROGRESS_DELTA = 0.05f;
96
97 /**
98 * Minimum allowed value for progress delta.
99 */
100 public static final float MIN_PROGRESS_DELTA = 0.0f;
101
102 /**
103 * Maximum allowed value for progress delta.
104 */
105 public static final float MAX_PROGRESS_DELTA = 1.0f;
106
107 /**
108 * Constant defining default confidence of the estimated result, which is
109 * 99%. This means that with a probability of 99% estimation will be
110 * accurate because chosen sub-samples will be inliers.
111 */
112 public static final double DEFAULT_CONFIDENCE = 0.99;
113
114 /**
115 * Default maximum allowed number of iterations.
116 */
117 public static final int DEFAULT_MAX_ITERATIONS = 5000;
118
119 /**
120 * Minimum allowed confidence value.
121 */
122 public static final double MIN_CONFIDENCE = 0.0;
123
124 /**
125 * Maximum allowed confidence value.
126 */
127 public static final double MAX_CONFIDENCE = 1.0;
128
129 /**
130 * Minimum allowed number of iterations.
131 */
132 public static final int MIN_ITERATIONS = 1;
133
134 /**
135 * Indicates that result is refined by default using all found inliers.
136 */
137 public static final boolean DEFAULT_REFINE_RESULT = true;
138
139 /**
140 * Indicates that covariance is kept by default after refining result.
141 */
142 public static final boolean DEFAULT_KEEP_COVARIANCE = true;
143
144 /**
145 * Indicates that by default a linear solver is used for preliminary solution
146 * estimation using ranging measurements.
147 * The result obtained on each preliminary solution might be later refined.
148 */
149 public static final boolean DEFAULT_USE_RANGING_LINEAR_SOLVER = true;
150
151 /**
152 * Indicates that by default a linear solver is used for preliminary solution
153 * estimation using RSSI measurements.
154 * The result obtained on each preliminary solution might be later refined.
155 */
156 public static final boolean DEFAULT_USE_RSSI_LINEAR_SOLVER = true;
157
158 /**
159 * Indicates that by default an homogeneous linear solver is used either to
160 * estimate preliminary solutions or an initial solution for preliminary solutions
161 * that will be later refined on the ranging fine estimation.
162 */
163 public static final boolean DEFAULT_USE_RANGING_HOMOGENEOUS_LINEAR_SOLVER = false;
164
165 /**
166 * Indicates that by default an homogeneous linear solver is used either to
167 * estimate preliminary solutions or an initial solution for preliminary solutions
168 * that will be later refined on the RSSI coarse estimation.
169 */
170 public static final boolean DEFAULT_USE_RSSI_HOMOGENEOUS_LINEAR_SOLVER = false;
171
172 /**
173 * Indicates that by default preliminary ranging solutions are refined.
174 */
175 public static final boolean DEFAULT_REFINE_RANGING_PRELIMINARY_SOLUTIONS = true;
176
177 /**
178 * Indicates that by default preliminary RSSI solutions are refined.
179 */
180 public static final boolean DEFAULT_REFINE_RSSI_PRELIMINARY_SOLUTIONS = true;
181
182 /**
183 * Internal robust estimator for position estimation using ranging readings.
184 */
185 protected RobustRangingPositionEstimator<P> rangingEstimator;
186
187 /**
188 * Internal robust estimator for coarse position estimation using RSSI readings.
189 */
190 protected RobustRssiPositionEstimator<P> rssiEstimator;
191
192 /**
193 * Robust method used for robust position estimation using ranging data.
194 */
195 protected RobustEstimatorMethod rangingRobustMethod = DEFAULT_RANGING_ROBUST_METHOD;
196
197 /**
198 * Robust method used for coarse robust position estimation using RSSI data.
199 */
200 protected RobustEstimatorMethod rssiRobustMethod = DEFAULT_RSSI_ROBUST_METHOD;
201
202 /**
203 * Size of subsets to be checked during robust estimation.
204 */
205 protected int rangingPreliminarySubsetSize;
206
207 /**
208 * Size of subsets to be checked during RSSI robust estimation.
209 */
210 protected int rssiPreliminarySubsetSize;
211
212 /**
213 * Indicates whether located radio source position covariance is taken into account
214 * (if available) to determine distance standard deviation for ranging measurements.
215 */
216 private boolean useRangingRadioSourcePositionCovariance = DEFAULT_USE_RANGING_RADIO_SOURCE_POSITION_COVARIANCE;
217
218 /**
219 * Indicates whether located radio source position covariance is taken into account
220 * (if available) to determine distance standard deviation for RSSI measurements.
221 */
222 private boolean useRssiRadioSourcePositionCovariance = DEFAULT_USE_RSSI_RADIO_SOURCE_POSITION_COVARIANCE;
223
224 /**
225 * Indicates whether ranging readings are evenly distributed among radio sources
226 * taking into account quality scores of both radio sources and ranging readings.
227 */
228 private boolean evenlyDistributeRangingReadings = DEFAULT_EVENLY_DISTRIBUTE_RANGING_READINGS;
229
230 /**
231 * Indicates whether RSSI readings are evenly distributed among radio sources
232 * taking into account quality scores of both radio sources and RSSI readings.
233 */
234 private boolean evenlyDistributeRssiReadings = DEFAULT_EVENLY_DISTRIBUTE_RSSI_READINGS;
235
236 /**
237 * Distance standard deviation fallback value to use when none can be determined
238 * from provided RSSI measurements.
239 */
240 private double rssiFallbackDistanceStandardDeviation = FALLBACK_DISTANCE_STANDARD_DEVIATION;
241
242 /**
243 * Distance standard deviation fallback value to use when none can be determined
244 * from provided ranging measurements.
245 */
246 private double rangingFallbackDistanceStandardDeviation = FALLBACK_DISTANCE_STANDARD_DEVIATION;
247
248 /**
249 * Amount of progress variation before notifying a progress change during
250 * estimation.
251 */
252 private float progressDelta = DEFAULT_PROGRESS_DELTA;
253
254 /**
255 * Amount of confidence expressed as a value between 0.0 and 1.0 (which is
256 * equivalent to 100%) for robust position estimation on ranging data. The amount
257 * of confidence indicates the probability that the estimated result is correct.
258 * Usually this value will be close to 1.0, but not exactly 1.0.
259 */
260 private double rangingConfidence = DEFAULT_CONFIDENCE;
261
262 /**
263 * Amount of confidence expressed as a value between 0.0 and 1.0 (which is
264 * equivalent to 100%) for robust position estimation on RSSI data. The amount
265 * of confidence indicates the probability that the estimated result is correct.
266 * Usually this value will be close to 1.0, but not exactly 1.0.
267 */
268 private double rssiConfidence = DEFAULT_CONFIDENCE;
269
270 /**
271 * Maximum allowed number of iterations for robust ranging position estimation.
272 * When the maximum number of iterations is exceeded, an approximate result
273 * might be available for retrieval.
274 */
275 private int rangingMaxIterations = DEFAULT_MAX_ITERATIONS;
276
277 /**
278 * Maximum allowed number of iterations for robust RSSI position estimation.
279 * When the maximum number of iterations is exceeded, an approximate result
280 * might be available for retrieval.
281 */
282 private int rssiMaxIterations = DEFAULT_MAX_ITERATIONS;
283
284 /**
285 * Indicates whether result is refined using all found inliers.
286 */
287 private boolean refineResult = DEFAULT_REFINE_RESULT;
288
289 /**
290 * Indicates that covariance is kept after refining result.
291 */
292 private boolean keepCovariance = DEFAULT_KEEP_COVARIANCE;
293
294 /**
295 * Indicates that a linear solver is used for preliminary solution estimation
296 * using ranging measurements.
297 * The result obtained on each preliminary solution might be later refined.
298 */
299 private boolean useRangingLinearSolver = DEFAULT_USE_RANGING_LINEAR_SOLVER;
300
301 /**
302 * Indicates that a linear solver is used for preliminary solution estimation
303 * using RSSI measurements.
304 * The result obtained on each preliminary solution might be later refined.
305 */
306 private boolean useRssiLinearSolver = DEFAULT_USE_RSSI_LINEAR_SOLVER;
307
308 /**
309 * Indicates whether an homogeneous linear solver is used either to estimate
310 * preliminary solutions or an initial solution for preliminary solutions that
311 * will be later refined on the ranging fine estimation.
312 */
313 private boolean useRangingHomogeneousLinearSolver = DEFAULT_USE_RANGING_HOMOGENEOUS_LINEAR_SOLVER;
314
315 /**
316 * Indicates whether an homogeneous linear solver is used either to estimate
317 * preliminary solutions or an initial solution for preliminary solutions that
318 * will be later refined on the RSSI coarse estimation.
319 */
320 private boolean useRssiHomogeneousLinearSolver = DEFAULT_USE_RSSI_HOMOGENEOUS_LINEAR_SOLVER;
321
322 /**
323 * Indicates whether preliminary ranging solutions are refined.
324 */
325 private boolean refineRangingPreliminarySolutions = DEFAULT_REFINE_RANGING_PRELIMINARY_SOLUTIONS;
326
327 /**
328 * Indicates whether preliminary RSSI solutions are refined.
329 */
330 private boolean refineRssiPreliminarySolutions = DEFAULT_REFINE_RSSI_PRELIMINARY_SOLUTIONS;
331
332 /**
333 * Threshold to determine when samples are inliers or not used during ranging
334 * position estimation.
335 * If not defined, default threshold will be used.
336 */
337 private Double rangingThreshold;
338
339 /**
340 * Threshold to determine when samples are inliers or not used during RSSI
341 * position estimation.
342 * If not defined, default threshold will be used.
343 */
344 private Double rssiThreshold;
345
346 /**
347 * Listener in charge of handling events.
348 */
349 private SequentialRobustRangingAndRssiPositionEstimatorListener<P> listener;
350
351 /**
352 * Located radio sources used for lateration.
353 */
354 private List<? extends RadioSourceLocated<P>> sources;
355
356 /**
357 * Fingerprint containing readings at an unknown location for provided located
358 * radio sources.
359 */
360 private RangingAndRssiFingerprint<? extends RadioSource, ? extends RangingAndRssiReading<?
361 extends RadioSource>> fingerprint;
362
363 /**
364 * Quality scores corresponding to each provided located radio source.
365 * The larger the score value the better the quality of the radio source.
366 */
367 private double[] sourceQualityScores;
368
369 /**
370 * Quality scores corresponding to each reading within provided fingerprint.
371 * The larger the score value the better the quality of the reading.
372 */
373 private double[] fingerprintReadingsQualityScores;
374
375 /**
376 * An initial position to start the estimation from. This can be useful if we only
377 * intend to refine a previously known estimation.
378 */
379 private P initialPosition;
380
381 /**
382 * Indicates if this instance is locked because estimation is being executed.
383 */
384 private boolean locked;
385
386 /**
387 * Constructor.
388 */
389 protected SequentialRobustRangingAndRssiPositionEstimator() {
390 }
391
392 /**
393 * Constructor.
394 *
395 * @param sources located radio sources used for lateration.
396 * @throws IllegalArgumentException if provided sources is null or the number of
397 * provided sources is less than the required minimum.
398 */
399 protected SequentialRobustRangingAndRssiPositionEstimator(final List<? extends RadioSourceLocated<P>> sources) {
400 internalSetSources(sources);
401 }
402
403 /**
404 * Constructor.
405 *
406 * @param fingerprint fingerprint containing ranging+RSSI readings at an unknown
407 * location for provided located radio sources.
408 * @throws IllegalArgumentException if provided fingerprint is null.
409 */
410 protected SequentialRobustRangingAndRssiPositionEstimator(
411 final RangingAndRssiFingerprint<? extends RadioSource, ? extends RangingAndRssiReading<?
412 extends RadioSource>> fingerprint) {
413 internalSetFingerprint(fingerprint);
414 }
415
416 /**
417 * Constructor.
418 *
419 * @param sources located radio sources used for lateration.
420 * @param fingerprint fingerprint containing ranging+RSSI readings at an unknown
421 * location for provided located radio sources.
422 * @throws IllegalArgumentException if either provided sources or fingerprint is null
423 * or the number of provided sources is less than the required minimum.
424 */
425 protected SequentialRobustRangingAndRssiPositionEstimator(
426 final List<? extends RadioSourceLocated<P>> sources,
427 final RangingAndRssiFingerprint<? extends RadioSource, ? extends RangingAndRssiReading<?
428 extends RadioSource>> fingerprint) {
429 internalSetSources(sources);
430 internalSetFingerprint(fingerprint);
431 }
432
433 /**
434 * Constructor.
435 *
436 * @param listener listener in charge of handling events.
437 */
438 protected SequentialRobustRangingAndRssiPositionEstimator(
439 final SequentialRobustRangingAndRssiPositionEstimatorListener<P> listener) {
440 this.listener = listener;
441 }
442
443 /**
444 * Constructor.
445 *
446 * @param sources located radio sources used for lateration.
447 * @param listener listener in charge of handling events.
448 * @throws IllegalArgumentException if provided sources is null or the number of
449 * provided sources is less than the required
450 * minimum.
451 */
452 protected SequentialRobustRangingAndRssiPositionEstimator(
453 final List<? extends RadioSourceLocated<P>> sources,
454 final SequentialRobustRangingAndRssiPositionEstimatorListener<P> listener) {
455 this(sources);
456 this.listener = listener;
457 }
458
459 /**
460 * Constructor.
461 *
462 * @param fingerprint fingerprint containing ranging+RSSI readings at an unknown
463 * location for provided located radio sources.
464 * @param listener listener in charge of handling events.
465 * @throws IllegalArgumentException if provided fingerprint is null.
466 */
467 protected SequentialRobustRangingAndRssiPositionEstimator(
468 final RangingAndRssiFingerprint<? extends RadioSource, ? extends RangingAndRssiReading<?
469 extends RadioSource>> fingerprint,
470 final SequentialRobustRangingAndRssiPositionEstimatorListener<P> listener) {
471 this(fingerprint);
472 this.listener = listener;
473 }
474
475 /**
476 * Constructor.
477 *
478 * @param sources located radio sources used for lateration.
479 * @param fingerprint fingerprint containing ranging+RSSI readings at an
480 * unknown location for provided located radio sources.
481 * @param listener listener in charge of handling events.
482 * @throws IllegalArgumentException if either provided sources or fingerprint is null
483 * or the number of provided sources is less than the required minimum.
484 */
485 protected SequentialRobustRangingAndRssiPositionEstimator(
486 final List<? extends RadioSourceLocated<P>> sources,
487 final RangingAndRssiFingerprint<? extends RadioSource, ? extends RangingAndRssiReading<?
488 extends RadioSource>> fingerprint,
489 final SequentialRobustRangingAndRssiPositionEstimatorListener<P> listener) {
490 this(sources, fingerprint);
491 this.listener = listener;
492 }
493
494 /**
495 * Constructor.
496 *
497 * @param sourceQualityScores quality scores corresponding to
498 * each provided located radio source.
499 * The larger the score value the better
500 * the quality of the radio source.
501 * @param fingerprintReadingQualityScores quality scores corresponding to readings
502 * within provided fingerprint. The larger
503 * the score the better the quality of the
504 * reading.
505 */
506 protected SequentialRobustRangingAndRssiPositionEstimator(
507 final double[] sourceQualityScores, final double[] fingerprintReadingQualityScores) {
508 internalSetSourceQualityScores(sourceQualityScores);
509 internalSetFingerprintReadingsQualityScores(fingerprintReadingQualityScores);
510 }
511
512 /**
513 * Constructor.
514 *
515 * @param sourceQualityScores quality scores corresponding to
516 * each provided located radio source.
517 * The larger the score value the better
518 * the quality of the radio source.
519 * @param fingerprintReadingQualityScores quality scores corresponding to readings
520 * within provided fingerprint. The larger
521 * the score the better the quality of the
522 * reading.
523 * @param sources located radio sources used for
524 * lateration.
525 * @throws IllegalArgumentException if provided sources is null or the number of
526 * provided sources is less than the required
527 * minimum.
528 */
529 protected SequentialRobustRangingAndRssiPositionEstimator(
530 final double[] sourceQualityScores, final double[] fingerprintReadingQualityScores,
531 final List<? extends RadioSourceLocated<P>> sources) {
532 this(sources);
533 internalSetSourceQualityScores(sourceQualityScores);
534 internalSetFingerprintReadingsQualityScores(fingerprintReadingQualityScores);
535 }
536
537 /**
538 * Constructor.
539 *
540 * @param sourceQualityScores quality scores corresponding to
541 * each provided located radio source.
542 * The larger the score value the better
543 * the quality of the radio source.
544 * @param fingerprintReadingQualityScores quality scores corresponding to readings
545 * within provided fingerprint. The larger
546 * the score the better the quality of the
547 * reading.
548 * @param fingerprint fingerprint containing ranging+RSSI
549 * readings at an unknown location for
550 * provided located radio sources.
551 * @throws IllegalArgumentException if provided fingerprint is null.
552 */
553 protected SequentialRobustRangingAndRssiPositionEstimator(
554 final double[] sourceQualityScores, final double[] fingerprintReadingQualityScores,
555 final RangingAndRssiFingerprint<? extends RadioSource, ? extends RangingAndRssiReading<?
556 extends RadioSource>> fingerprint) {
557 this(fingerprint);
558 internalSetSourceQualityScores(sourceQualityScores);
559 internalSetFingerprintReadingsQualityScores(fingerprintReadingQualityScores);
560 }
561
562 /**
563 * Constructor.
564 *
565 * @param sourceQualityScores quality scores corresponding to
566 * each provided located radio source.
567 * The larger the score value the better
568 * the quality of the radio source.
569 * @param fingerprintReadingQualityScores quality scores corresponding to readings
570 * within provided fingerprint. The larger
571 * the score the better the quality of the
572 * reading.
573 * @param sources located radio sources used for
574 * lateration.
575 * @param fingerprint fingerprint containing ranging+RSSI
576 * readings at an unknown location for
577 * provided located radio sources.
578 * @throws IllegalArgumentException if either provided sources or fingerprint is null
579 * or the number of provided sources is less than the required minimum.
580 */
581 protected SequentialRobustRangingAndRssiPositionEstimator(
582 final double[] sourceQualityScores, final double[] fingerprintReadingQualityScores,
583 final List<? extends RadioSourceLocated<P>> sources,
584 final RangingAndRssiFingerprint<? extends RadioSource, ? extends RangingAndRssiReading<?
585 extends RadioSource>> fingerprint) {
586 this(sources, fingerprint);
587 internalSetSourceQualityScores(sourceQualityScores);
588 internalSetFingerprintReadingsQualityScores(fingerprintReadingQualityScores);
589 }
590
591 /**
592 * Constructor.
593 *
594 * @param sourceQualityScores quality scores corresponding to
595 * each provided located radio source.
596 * The larger the score value the better
597 * the quality of the radio source.
598 * @param fingerprintReadingQualityScores quality scores corresponding to readings
599 * within provided fingerprint. The larger
600 * the score the better the quality of the
601 * reading.
602 * @param listener listener in charge of handling events.
603 */
604 protected SequentialRobustRangingAndRssiPositionEstimator(
605 final double[] sourceQualityScores, final double[] fingerprintReadingQualityScores,
606 final SequentialRobustRangingAndRssiPositionEstimatorListener<P> listener) {
607 this(sourceQualityScores, fingerprintReadingQualityScores);
608 this.listener = listener;
609 }
610
611 /**
612 * Constructor.
613 *
614 * @param sourceQualityScores quality scores corresponding to
615 * each provided located radio source.
616 * The larger the score value the better
617 * the quality of the radio source.
618 * @param fingerprintReadingQualityScores quality scores corresponding to readings
619 * within provided fingerprint. The larger
620 * the score the better the quality of the
621 * reading.
622 * @param sources located radio sources used for
623 * lateration.
624 * @param listener listener in charge of handling events.
625 * @throws IllegalArgumentException if provided sources is null or the number of
626 * provided sources is less than the required minimum.
627 */
628 protected SequentialRobustRangingAndRssiPositionEstimator(
629 final double[] sourceQualityScores, final double[] fingerprintReadingQualityScores,
630 final List<? extends RadioSourceLocated<P>> sources,
631 final SequentialRobustRangingAndRssiPositionEstimatorListener<P> listener) {
632 this(sourceQualityScores, fingerprintReadingQualityScores, sources);
633 this.listener = listener;
634 }
635
636 /**
637 * Constructor.
638 *
639 * @param sourceQualityScores quality scores corresponding to
640 * each provided located radio source.
641 * The larger the score value the better
642 * the quality of the radio source.
643 * @param fingerprintReadingQualityScores quality scores corresponding to readings
644 * within provided fingerprint. The larger
645 * the score the better the quality of the
646 * reading.
647 * @param fingerprint fingerprint containing ranging+RSSI
648 * readings at an unknown location for
649 * provided located radio sources.
650 * @param listener listener in charge of handling events.
651 * @throws IllegalArgumentException if provided fingerprint is null.
652 */
653 protected SequentialRobustRangingAndRssiPositionEstimator(
654 final double[] sourceQualityScores, final double[] fingerprintReadingQualityScores,
655 final RangingAndRssiFingerprint<? extends RadioSource, ? extends RangingAndRssiReading<?
656 extends RadioSource>> fingerprint,
657 final SequentialRobustRangingAndRssiPositionEstimatorListener<P> listener) {
658 this(sourceQualityScores, fingerprintReadingQualityScores, fingerprint);
659 this.listener = listener;
660 }
661
662 /**
663 * Constructor.
664 *
665 * @param sourceQualityScores quality scores corresponding to
666 * each provided located radio source.
667 * The larger the score value the better
668 * the quality of the radio source.
669 * @param fingerprintReadingQualityScores quality scores corresponding to readings
670 * within provided fingerprint. The larger
671 * the score the better the quality of the
672 * reading.
673 * @param sources located radio sources used for
674 * lateration.
675 * @param fingerprint fingerprint containing ranging+RSSI
676 * readings at an unknown location for
677 * provided located radio sources.
678 * @param listener listener in charge of handling events.
679 * @throws IllegalArgumentException if either provided sources or fingerprint is null
680 * or the number of provided sources is less than the required minimum.
681 */
682 protected SequentialRobustRangingAndRssiPositionEstimator(
683 final double[] sourceQualityScores, final double[] fingerprintReadingQualityScores,
684 final List<? extends RadioSourceLocated<P>> sources,
685 final RangingAndRssiFingerprint<? extends RadioSource, ? extends RangingAndRssiReading<?
686 extends RadioSource>> fingerprint,
687 final SequentialRobustRangingAndRssiPositionEstimatorListener<P> listener) {
688 this(sourceQualityScores, fingerprintReadingQualityScores, sources, fingerprint);
689 this.listener = listener;
690 }
691
692 /**
693 * Gets robust method used for robust position estimation using ranging data.
694 *
695 * @return robust method used for robust position estimation using ranging data.
696 */
697 public RobustEstimatorMethod getRangingRobustMethod() {
698 return rangingRobustMethod;
699 }
700
701 /**
702 * Sets robust method for robust position estimation using ranging data.
703 *
704 * @param rangingRobustMethod robust method used for robust position estimation
705 * using ranging data.
706 * @throws LockedException if this instance is locked.
707 */
708 public void setRangingRobustMethod(final RobustEstimatorMethod rangingRobustMethod) throws LockedException {
709 if (isLocked()) {
710 throw new LockedException();
711 }
712
713 this.rangingRobustMethod = rangingRobustMethod;
714 }
715
716 /**
717 * Gets robust method used for coarse robust position estimation using RSSI data.
718 *
719 * @return robust method used for coarse robust position estimation using RSSI data.
720 */
721 public RobustEstimatorMethod getRssiRobustMethod() {
722 return rssiRobustMethod;
723 }
724
725 /**
726 * Sets robust method used for coarse robust position estimation using RSSI data.
727 *
728 * @param rssiRobustMethod robust method used for coarse robust position estimation
729 * using RSSI data.
730 * @throws LockedException if this instance is locked.
731 */
732 public void setRssiRobustMethod(final RobustEstimatorMethod rssiRobustMethod) throws LockedException {
733 if (isLocked()) {
734 throw new LockedException();
735 }
736
737 this.rssiRobustMethod = rssiRobustMethod;
738 }
739
740 /**
741 * Indicates whether located radio source position covariance is taken into account
742 * (if available) to determine distance standard deviation for ranging measurements.
743 *
744 * @return true to take into account radio source position covariance during
745 * ranging position estimation, false otherwise.
746 */
747 public boolean isRangingRadioSourcePositionCovarianceUsed() {
748 return useRangingRadioSourcePositionCovariance;
749 }
750
751 /**
752 * Specifies whether located radio source position covariance is taken into account
753 * (if available) to determine distance standard deviation for ranging measurements.
754 *
755 * @param useRangingRadioSourcePositionCovariance true to take into account radio
756 * source position covariance during
757 * ranging position estimation, false
758 * otherwise.
759 * @throws LockedException if this instance is locked.
760 */
761 public void setRangingRadioSourcePositionCovarianceUsed(final boolean useRangingRadioSourcePositionCovariance)
762 throws LockedException {
763 if (isLocked()) {
764 throw new LockedException();
765 }
766
767 this.useRangingRadioSourcePositionCovariance = useRangingRadioSourcePositionCovariance;
768 }
769
770 /**
771 * Indicates whether located radio source position covariance is taken into
772 * account (if available) to determine distance standard deviation for RSSI
773 * measurements.
774 *
775 * @return true to take into account radio source position covariance during
776 * RSSI position estimation, false otherwise.
777 */
778 public boolean isRssiRadioSourcePositionCovarianceUsed() {
779 return useRssiRadioSourcePositionCovariance;
780 }
781
782 /**
783 * Specifies whether located radio source position covariance is taken into
784 * account (if available) to determine distance standard deviation for RSSI
785 * measurements.
786 *
787 * @param useRssiRadioSourcePositionCovariance true to take into account radio
788 * source position covariance during
789 * RSSI position estimation, false
790 * otherwise.
791 * @throws LockedException if this instance is locked.
792 */
793 public void setRssiRadioSourcePositionCovarianceUsed(final boolean useRssiRadioSourcePositionCovariance)
794 throws LockedException {
795 if (isLocked()) {
796 throw new LockedException();
797 }
798
799 this.useRssiRadioSourcePositionCovariance = useRssiRadioSourcePositionCovariance;
800 }
801
802 /**
803 * Indicates whether ranging readings are evenly distributed among radio sources
804 * taking into account quality scores of both radio sources and ranging readings.
805 *
806 * @return true if ranging readings are evenly distributed among radio sources,
807 * false otherwise.
808 */
809 public boolean isRangingReadingsEvenlyDistributed() {
810 return evenlyDistributeRangingReadings;
811 }
812
813 /**
814 * Specifies whether ranging readings are evenly distributed among radio sources
815 * taking into account quality scores of both radio sources and ranging readings.
816 *
817 * @param evenlyDistributeRangingReadings true if ranging readings are evenly
818 * distributed among radio sources, false
819 * otherwise.
820 * @throws LockedException if this instance is locked.
821 */
822 public void setRangingReadingsEvenlyDistributed(final boolean evenlyDistributeRangingReadings)
823 throws LockedException {
824 if (isLocked()) {
825 throw new LockedException();
826 }
827
828 this.evenlyDistributeRangingReadings = evenlyDistributeRangingReadings;
829 }
830
831 /**
832 * Gets distance standard deviation fallback value to use when none can be
833 * determined from provided RSSI measurements.
834 *
835 * @return distance standard deviation fallback value to use when none can be
836 * determined from provided RSSI measurements.
837 */
838 public double getRssiFallbackDistanceStandardDeviation() {
839 return rssiFallbackDistanceStandardDeviation;
840 }
841
842 /**
843 * Sets distance standard deviation fallback value to use when none can be
844 * determined from provided RSSI measurements.
845 *
846 * @param rssiFallbackDistanceStandardDeviation distance standard deviation
847 * fallback value to use when none can
848 * be determined from provided RSSI
849 * measurements.
850 * @throws LockedException if this instance is locked.
851 */
852 public void setRssiFallbackDistanceStandardDeviation(final double rssiFallbackDistanceStandardDeviation)
853 throws LockedException {
854 if (isLocked()) {
855 throw new LockedException();
856 }
857 this.rssiFallbackDistanceStandardDeviation = rssiFallbackDistanceStandardDeviation;
858 }
859
860 /**
861 * Gets distance standard deviation fallback value to use when none can be
862 * determined from provided ranging measurements.
863 *
864 * @return distance standard deviation fallback value to use when none can be
865 * determined from provided ranging measurements.
866 */
867 public double getRangingFallbackDistanceStandardDeviation() {
868 return rangingFallbackDistanceStandardDeviation;
869 }
870
871 /**
872 * Sets distance standard deviation fallback value to use when none can be
873 * determined from provided ranging measurements.
874 *
875 * @param rangingFallbackDistanceStandardDeviation distance standard deviation
876 * fallback value to use when none can
877 * be determined from provided ranging
878 * measurements.
879 * @throws LockedException if this instance is locked.
880 */
881 public void setRangingFallbackDistanceStandardDeviation(final double rangingFallbackDistanceStandardDeviation)
882 throws LockedException {
883 if (isLocked()) {
884 throw new LockedException();
885 }
886 this.rangingFallbackDistanceStandardDeviation = rangingFallbackDistanceStandardDeviation;
887 }
888
889 /**
890 * Indicates whether RSSI readings are evenly distributed among radio sources
891 * taking into account quality scores of both radio sources and RSSI readings.
892 *
893 * @return true if RSSI readings are evenly distributed among radio sources,
894 * false otherwise.
895 */
896 public boolean isRssiReadingsEvenlyDistributed() {
897 return evenlyDistributeRssiReadings;
898 }
899
900 /**
901 * Specifies whether RSSI readings are evenly distributed among radio sources
902 * taking into account quality scores of both radio sources and RSSI readings.
903 *
904 * @param evenlyDistributeRssiReadings true if RSSI readings are evenly distributed
905 * among radio sources, false otherwise.
906 * @throws LockedException if this instance is locked.
907 */
908 public void setRssiReadingsEvenlyDistributed(final boolean evenlyDistributeRssiReadings) throws LockedException {
909 if (isLocked()) {
910 throw new LockedException();
911 }
912
913 this.evenlyDistributeRssiReadings = evenlyDistributeRssiReadings;
914 }
915
916 /**
917 * Gets amount of progress variation before notifying a progress change during
918 * estimation.
919 *
920 * @return amount of progress variation before notifying a progress change during
921 * estimation.
922 */
923 public float getProgressDelta() {
924 return progressDelta;
925 }
926
927 /**
928 * Sets amount of progress variation before notifying a progress change during
929 * estimation.
930 *
931 * @param progressDelta amount of progress variation before notifying a progress
932 * change during estimation.
933 * @throws IllegalArgumentException if progress delta is less than zero or greater than 1.
934 * @throws LockedException if this instance is locked.
935 */
936 public void setProgressDelta(final float progressDelta) throws LockedException {
937 if (isLocked()) {
938 throw new LockedException();
939 }
940 if (progressDelta < MIN_PROGRESS_DELTA || progressDelta > MAX_PROGRESS_DELTA) {
941 throw new IllegalArgumentException();
942 }
943 this.progressDelta = progressDelta;
944 }
945
946 /**
947 * Returns amount of confidence expressed as a value between 0.0 and 1.0 (which is
948 * equivalent to 100%) for robust position estimation on ranging data. The amount
949 * of confidence indicates the probability that the estimated result is correct.
950 * Usually this value will be close to 1.0, but not exactly 1.0.
951 *
952 * @return amount of confidence for robust position estimation as a value between
953 * 0.0 and 1.0.
954 */
955 public double getRangingConfidence() {
956 return rangingConfidence;
957 }
958
959 /**
960 * Sets amount of confidence expressed as a value between 0.0 and 1.0 (which is
961 * equivalent to 100%) for robust position estimation on ranging data. The amount
962 * of confidence indicates the probability that the estimated result is correct.
963 * Usually this value will be close to 1.0, but not exactly 1.0.
964 *
965 * @param rangingConfidence confidence to be set for robust position estimation
966 * as a value between 0.0 and 1.0.
967 * @throws IllegalArgumentException if provided value is not between 0.0 and 1.0.
968 * @throws LockedException if estimator is locked.
969 */
970 public void setRangingConfidence(final double rangingConfidence) throws LockedException {
971 if (isLocked()) {
972 throw new LockedException();
973 }
974 if (rangingConfidence < MIN_CONFIDENCE || rangingConfidence > MAX_CONFIDENCE) {
975 throw new IllegalArgumentException();
976 }
977 this.rangingConfidence = rangingConfidence;
978 }
979
980 /**
981 * Returns amount of confidence expressed as a value between 0.0 and 1.0 (which is
982 * equivalent to 100%) for robust position estimation on RSSI data. The amount
983 * of confidence indicates the probability that the estimated result is correct.
984 * Usually this value will be close to 1.0, but not exactly 1.0.
985 *
986 * @return amount of confidence for robust position estimation as a value between
987 * 0.0 and 1.0.
988 */
989 public double getRssiConfidence() {
990 return rssiConfidence;
991 }
992
993 /**
994 * Sets amount of confidence expressed as a value between 0.0 and 1.0 (which is
995 * equivalent to 100%) for robust position estimation on RSSI data. The amount
996 * of confidence indicates the probability that the estimated result is correct.
997 * Usually this value will be close to 1.0, but not exactly 1.0.
998 *
999 * @param rssiConfidence amount of confidence for robust position estimation as a
1000 * value between 0.0 and 1.0.
1001 * @throws IllegalArgumentException if provided value is not between 0.0 and 1.0.
1002 * @throws LockedException if estimator is locked.
1003 */
1004 public void setRssiConfidence(final double rssiConfidence) throws LockedException {
1005 if (isLocked()) {
1006 throw new LockedException();
1007 }
1008 if (rssiConfidence < MIN_CONFIDENCE || rssiConfidence > MAX_CONFIDENCE) {
1009 throw new IllegalArgumentException();
1010 }
1011 this.rssiConfidence = rssiConfidence;
1012 }
1013
1014 /**
1015 * Gets maximum allowed number of iterations for robust ranging position estimation.
1016 * When the maximum number of iterations is exceeded, an approximate result might
1017 * be available for retrieval.
1018 *
1019 * @return maximum allowed number of iterations for position estimation.
1020 */
1021 public int getRangingMaxIterations() {
1022 return rangingMaxIterations;
1023 }
1024
1025 /**
1026 * Sets maximum allowed number of iterations for robust ranging position
1027 * estimation.
1028 * When the maximum number of iterations is exceeded, an approximate result might
1029 * be available for retrieval.
1030 *
1031 * @param rangingMaxIterations maximum allowed number of iterations to be set for
1032 * position estimation.
1033 * @throws IllegalArgumentException if provided value is less than 1.
1034 * @throws LockedException if estimator is locked.
1035 */
1036 public void setRangingMaxIterations(final int rangingMaxIterations) throws LockedException {
1037 if (isLocked()) {
1038 throw new LockedException();
1039 }
1040 if (rangingMaxIterations < MIN_ITERATIONS) {
1041 throw new IllegalArgumentException();
1042 }
1043 this.rangingMaxIterations = rangingMaxIterations;
1044 }
1045
1046 /**
1047 * Gets maximum allowed number of iterations for robust RSSI position estimation.
1048 * When the maximum number of iterations is exceeded, an approximate result might
1049 * be available for retrieval.
1050 *
1051 * @return maximum allowed number of iterations for position estimation.
1052 */
1053 public int getRssiMaxIterations() {
1054 return rssiMaxIterations;
1055 }
1056
1057 /**
1058 * Sets maximum allowed number of iterations for robust RSSI position estimation.
1059 * When the maximum number of iterations is exceeded, an approximate result might
1060 * be available for retrieval.
1061 *
1062 * @param rssiMaxIterations maximum allowed number of iterations to be set for
1063 * position estimation.
1064 * @throws IllegalArgumentException if provided value is less than 1.
1065 * @throws LockedException if estimator is locked.
1066 */
1067 public void setRssiMaxIterations(final int rssiMaxIterations) throws LockedException {
1068 if (isLocked()) {
1069 throw new LockedException();
1070 }
1071 if (rssiMaxIterations < MIN_ITERATIONS) {
1072 throw new IllegalArgumentException();
1073 }
1074 this.rssiMaxIterations = rssiMaxIterations;
1075 }
1076
1077 /**
1078 * Indicates whether result is refined using all found inliers.
1079 *
1080 * @return true if result is refined, false otherwise.
1081 */
1082 public boolean isResultRefined() {
1083 return refineResult;
1084 }
1085
1086 /**
1087 * Specifies whether result is refined using all found inliers.
1088 *
1089 * @param refineResult true if result is refined, false otherwise.
1090 * @throws LockedException if this instance is locked.
1091 */
1092 public void setResultRefined(final boolean refineResult) throws LockedException {
1093 if (isLocked()) {
1094 throw new LockedException();
1095 }
1096
1097 this.refineResult = refineResult;
1098 }
1099
1100 /**
1101 * Indicates whether covariance must be kept after refining result.
1102 * This setting is only taken into account if result is refined.
1103 *
1104 * @return true if covariance must be kept after refining result, false otherwise.
1105 */
1106 public boolean isCovarianceKept() {
1107 return keepCovariance;
1108 }
1109
1110 /**
1111 * Specifies whether covariance must be kept after refining result.
1112 * This setting is only taken into account if result is refined.
1113 *
1114 * @param keepCovariance true if covariance must be kept after refining result,
1115 * false otherwise.
1116 * @throws LockedException if estimator is locked.
1117 */
1118 public void setCovarianceKept(final boolean keepCovariance) throws LockedException {
1119 if (isLocked()) {
1120 throw new LockedException();
1121 }
1122 this.keepCovariance = keepCovariance;
1123 }
1124
1125 /**
1126 * Indicates whether a linear solver is used for preliminary solution estimation
1127 * using ranging measurements.
1128 * The result obtained on each preliminary solution might be later refined.
1129 *
1130 * @return true if a linear solver is used for preliminary solution estimation on
1131 * ranging readings.
1132 */
1133 public boolean isRangingLinearSolverUsed() {
1134 return useRangingLinearSolver;
1135 }
1136
1137 /**
1138 * Specifies whether a linear solver is used for preliminary solution estimation
1139 * using ranging measurements.
1140 * The result obtained on each preliminary solution might be later refined.
1141 *
1142 * @param useRangingLinearSolver true if a linear solver is used for preliminary
1143 * solution estimation on ranging readings.
1144 * @throws LockedException if estimator is locked.
1145 */
1146 public void setRangingLinearSolverUsed(final boolean useRangingLinearSolver) throws LockedException {
1147 if (isLocked()) {
1148 throw new LockedException();
1149 }
1150 this.useRangingLinearSolver = useRangingLinearSolver;
1151 }
1152
1153 /**
1154 * Indicates whether a linear solver is used for preliminary solution estimation
1155 * using RSSI measurements.
1156 * The result obtained on each preliminary solution might be later refined.
1157 *
1158 * @return true if a linear solver is used for preliminary solution estimation on
1159 * RSSI readings.
1160 */
1161 public boolean isRssiLinearSolverUsed() {
1162 return useRssiLinearSolver;
1163 }
1164
1165 /**
1166 * Specifies whether a linear solver is used for preliminary solution estimation
1167 * using RSSI measurements.
1168 * The result obtained on each preliminary solution might be later refined.
1169 *
1170 * @param useRssiLinearSolver true if a linear solver is used for preliminary
1171 * solution estimation on RSSI readings.
1172 * @throws LockedException if estimator is locked.
1173 */
1174 public void setRssiLinearSolverUsed(final boolean useRssiLinearSolver) throws LockedException {
1175 if (isLocked()) {
1176 throw new LockedException();
1177 }
1178 this.useRssiLinearSolver = useRssiLinearSolver;
1179 }
1180
1181 /**
1182 * Indicates whether an homogeneous linear solver is used either to estimate
1183 * preliminary solutions or an initial solution for preliminary solutions that
1184 * will be later refined on the ranging fine estimation.
1185 *
1186 * @return true to use an homogeneous linear solver for preliminary solutions
1187 * during ranging fine position estimation.
1188 */
1189 public boolean isRangingHomogeneousLinearSolverUsed() {
1190 return useRangingHomogeneousLinearSolver;
1191 }
1192
1193 /**
1194 * Specifies whether an homogeneous linear solver is used either to estimate
1195 * preliminary solutions or an initial solution for preliminary solutions that
1196 * will be later refined on the ranging fine estimation.
1197 *
1198 * @param useRangingHomogeneousLinearSolver true to use an homogeneous linear
1199 * solver for preliminary solutions during
1200 * ranging fine position estimation.
1201 * @throws LockedException if estimator is locked.
1202 */
1203 public void setRangingHomogeneousLinearSolverUsed(final boolean useRangingHomogeneousLinearSolver)
1204 throws LockedException {
1205 if (isLocked()) {
1206 throw new LockedException();
1207 }
1208 this.useRangingHomogeneousLinearSolver = useRangingHomogeneousLinearSolver;
1209 }
1210
1211 /**
1212 * Indicates whether an homogeneous linear solver is used either to estimate
1213 * preliminary solutions or an initial solution for preliminary solutions that
1214 * will be later refined on the RSSI coarse estimation.
1215 *
1216 * @return true to use an homogeneous linear solver for preliminary solutions
1217 * during RSSI coarse position estimation.
1218 */
1219 public boolean isRssiHomogeneousLinearSolverUsed() {
1220 return useRssiHomogeneousLinearSolver;
1221 }
1222
1223 /**
1224 * Specifies whether an homogeneous linear solver is used either to estimate
1225 * preliminary solutions or an initial solution for preliminary solutions that
1226 * will be later refined on the RSSI coarse estimation.
1227 *
1228 * @param useRssiHomogeneousLinearSolver true to use an homogeneous linear solver
1229 * for preliminary solutions during RSSI fine
1230 * position estimation.
1231 * @throws LockedException if estimator is locked.
1232 */
1233 public void setRssiHomogeneousLinearSolverUsed(final boolean useRssiHomogeneousLinearSolver)
1234 throws LockedException {
1235 if (isLocked()) {
1236 throw new LockedException();
1237 }
1238 this.useRssiHomogeneousLinearSolver = useRssiHomogeneousLinearSolver;
1239 }
1240
1241 /**
1242 * Indicates whether preliminary ranging solutions are refined after an initial
1243 * linear solution is found.
1244 * If no initial preliminary solution is found using a linear solver, a non-linear
1245 * solver will be used regardless of this value using an average solution
1246 * as the initial value to be refined.
1247 *
1248 * @return true if preliminary ranging solutions must be refined after an initial
1249 * linear solution, false otherwise.
1250 */
1251 public boolean isRangingPreliminarySolutionRefined() {
1252 return refineRangingPreliminarySolutions;
1253 }
1254
1255 /**
1256 * Specifies whether preliminary ranging solutions are refined after an initial
1257 * linear solution is found.
1258 * If no initial preliminary solution is found using a linear solver, a non-linear
1259 * solver will be used regardless of this value using an average solution
1260 * as the initial value to be refined.
1261 *
1262 * @param refineRangingPreliminarySolutions true if preliminary ranging solutions
1263 * must be refined after an initial linear
1264 * solution, false otherwise.
1265 * @throws LockedException if estimator is locked.
1266 */
1267 public void setRangingPreliminarySolutionRefined(final boolean refineRangingPreliminarySolutions)
1268 throws LockedException {
1269 if (isLocked()) {
1270 throw new LockedException();
1271 }
1272 this.refineRangingPreliminarySolutions = refineRangingPreliminarySolutions;
1273 }
1274
1275 /**
1276 * Indicates whether preliminary RSSI solutions are refined after an initial
1277 * linear solution is found.
1278 * If no initial preliminary solution is found using a linear solver, a non-linear
1279 * solver will be used regardless of this value using an average solution
1280 * as the initial value to be refined.
1281 *
1282 * @return true if preliminary RSSI solutions must be refined after an initial
1283 * linear solution, false otherwise.
1284 */
1285 public boolean isRssiPreliminarySolutionRefined() {
1286 return refineRssiPreliminarySolutions;
1287 }
1288
1289 /**
1290 * Specifies whether preliminary RSSI solutions are refined after an initial
1291 * linear solution is found.
1292 * If no initial preliminary solution is found using a linear solver, a non-linear
1293 * solver will be used regardless of this value using an average solution
1294 * as the initial value to be refined.
1295 *
1296 * @param refineRssiPreliminarySolutions true if preliminary RSSI solutions must
1297 * be refined after an initial linear
1298 * solution, false otherwise.
1299 * @throws LockedException if estimator is locked.
1300 */
1301 public void setRssiPreliminarySolutionRefined(final boolean refineRssiPreliminarySolutions) throws LockedException {
1302 if (isLocked()) {
1303 throw new LockedException();
1304 }
1305 this.refineRssiPreliminarySolutions = refineRssiPreliminarySolutions;
1306 }
1307
1308 /**
1309 * Gets size of subsets to be checked during ranging robust estimation.
1310 *
1311 * @return size of subsets to be checked during ranging robust estimation.
1312 */
1313 public int getRangingPreliminarySubsetSize() {
1314 return rangingPreliminarySubsetSize;
1315 }
1316
1317 /**
1318 * Sets size of subsets to be checked during ranging robust estimation.
1319 *
1320 * @param rangingPreliminarySubsetSize size of subsets to be checked during
1321 * ranging robust estimation.
1322 * @throws LockedException if estimator is locked.
1323 * @throws IllegalArgumentException if provided value is less than {@link #getMinRequiredSources()}.
1324 */
1325 public void setRangingPreliminarySubsetSize(final int rangingPreliminarySubsetSize) throws LockedException {
1326 if (isLocked()) {
1327 throw new LockedException();
1328 }
1329 if (rangingPreliminarySubsetSize < getMinRequiredSources()) {
1330 throw new IllegalArgumentException();
1331 }
1332
1333 this.rangingPreliminarySubsetSize = rangingPreliminarySubsetSize;
1334 }
1335
1336 /**
1337 * Gets size of subsets to be checked during RSSI robust estimation.
1338 *
1339 * @return size of subsets to be checked during RSSI robust estimation.
1340 */
1341 public int getRssiPreliminarySubsetSize() {
1342 return rssiPreliminarySubsetSize;
1343 }
1344
1345 /**
1346 * Sets size of subsets to be checked during RSSI robust estimation.
1347 *
1348 * @param rssiPreliminarySubsetSize size of subsets to be checked during
1349 * RSSI robust estimation.
1350 * @throws LockedException if estimator is locked.
1351 * @throws IllegalArgumentException if provided value is less than {@link #getMinRequiredSources()}.
1352 */
1353 public void setRssiPreliminarySubsetSize(final int rssiPreliminarySubsetSize) throws LockedException {
1354 if (isLocked()) {
1355 throw new LockedException();
1356 }
1357 if (rssiPreliminarySubsetSize < getMinRequiredSources()) {
1358 throw new IllegalArgumentException();
1359 }
1360
1361 this.rssiPreliminarySubsetSize = rssiPreliminarySubsetSize;
1362 }
1363
1364 /**
1365 * Gets threshold to determine when samples are inliers or not, used during robust
1366 * fine ranging position estimation.
1367 * If not defined, default threshold will be used.
1368 *
1369 * @return threshold for ranging estimation or null.
1370 */
1371 public Double getRangingThreshold() {
1372 return rangingThreshold;
1373 }
1374
1375 /**
1376 * Sets threshold to determine when samples are inliers or not, used during robust
1377 * fine ranging position estimation.
1378 * If not defined, default threshold will be used.
1379 *
1380 * @param rangingThreshold threshold for ranging estimation or null.
1381 * @throws LockedException if estimator is locked.
1382 */
1383 public void setRangingThreshold(final Double rangingThreshold) throws LockedException {
1384 if (isLocked()) {
1385 throw new LockedException();
1386 }
1387 this.rangingThreshold = rangingThreshold;
1388 }
1389
1390 /**
1391 * Gets threshold to determine when samples are inliers or not, used during robust
1392 * coarse RSSI position estimation.
1393 * If not defined, default threshold will be used.
1394 *
1395 * @return threshold for RSSI estimation or null.
1396 */
1397 public Double getRssiThreshold() {
1398 return rssiThreshold;
1399 }
1400
1401 /**
1402 * Sets threshold to determine when samples are inliers or not, used during robust
1403 * coarse RSSI position estimation.
1404 * If not defined, default threshold will be used.
1405 *
1406 * @param rssiThreshold threshold for RSSI estimation or null.
1407 * @throws LockedException if estimator is locked.
1408 */
1409 public void setRssiThreshold(final Double rssiThreshold) throws LockedException {
1410 if (isLocked()) {
1411 throw new LockedException();
1412 }
1413 this.rssiThreshold = rssiThreshold;
1414 }
1415
1416 /**
1417 * Gets located radio sources used for lateration.
1418 *
1419 * @return located radio sources used for lateration.
1420 */
1421 public List<RadioSourceLocated<P>> getSources() {
1422 //noinspection unchecked
1423 return (List<RadioSourceLocated<P>>) sources;
1424 }
1425
1426 /**
1427 * Sets located radio sources used for lateration.
1428 *
1429 * @param sources located radio sources used for lateration.
1430 * @throws LockedException if estimator is locked.
1431 * @throws IllegalArgumentException if provided value is null or the number of
1432 * provided sources is less than the required
1433 * minimum.
1434 */
1435 public void setSources(final List<? extends RadioSourceLocated<P>> sources) throws LockedException {
1436 if (isLocked()) {
1437 throw new LockedException();
1438 }
1439
1440 internalSetSources(sources);
1441 }
1442
1443 /**
1444 * Gets fingerprint containing ranging+RSSI readings at an unknown location for
1445 * provided located radio sources.
1446 *
1447 * @return fingerprint containing readings at an unknown location for provided
1448 * located radio sources.
1449 */
1450 public RangingAndRssiFingerprint<RadioSource, RangingAndRssiReading<RadioSource>> getFingerprint() {
1451 //noinspection unchecked
1452 return (RangingAndRssiFingerprint<RadioSource, RangingAndRssiReading<RadioSource>>) fingerprint;
1453 }
1454
1455 /**
1456 * Sets fingerprint containing ranging+RSSI readings at an unknown location for
1457 * provided located radio sources.
1458 *
1459 * @param fingerprint fingerprint containing readings at an unknown location for
1460 * provided located radio sources.
1461 * @throws LockedException if estimator is locked.
1462 */
1463 public void setFingerprint(
1464 final RangingAndRssiFingerprint<? extends RadioSource, ? extends RangingAndRssiReading<?
1465 extends RadioSource>> fingerprint) throws LockedException {
1466 if (isLocked()) {
1467 throw new LockedException();
1468 }
1469
1470 internalSetFingerprint(fingerprint);
1471 }
1472
1473 /**
1474 * Returns quality scores corresponding to each radio source.
1475 * The larger the score value the better the quality of radio source.
1476 *
1477 * @return quality scores corresponding to each radio source.
1478 */
1479 public double[] getSourceQualityScores() {
1480 return sourceQualityScores;
1481 }
1482
1483 /**
1484 * Sets quality scores corresponding to each radio source.
1485 * The larger the score value the better the quality of the radio source.
1486 *
1487 * @param sourceQualityScores quality scores corresponding to each radio source.
1488 * @throws LockedException if this instance is locked.
1489 * @throws IllegalArgumentException if provided quality scores length is smaller
1490 * than minimum required samples.
1491 */
1492 public void setSourceQualityScores(final double[] sourceQualityScores) throws LockedException {
1493 if (isLocked()) {
1494 throw new LockedException();
1495 }
1496 internalSetSourceQualityScores(sourceQualityScores);
1497 }
1498
1499 /**
1500 * Gets quality scores corresponding to each reading within provided fingerprint.
1501 * The larger the score value the better the quality of the reading.
1502 *
1503 * @return quality scores corresponding to each reading within provided
1504 * fingerprint.
1505 */
1506 public double[] getFingerprintReadingsQualityScores() {
1507 return fingerprintReadingsQualityScores;
1508 }
1509
1510 /**
1511 * Sets quality scores corresponding to each reading within provided fingerprint.
1512 * The larger the score value the better the quality of the reading.
1513 *
1514 * @param fingerprintReadingsQualityScores quality scores corresponding to each
1515 * reading within provided fingerprint.
1516 * @throws LockedException if this instance is locked.
1517 * @throws IllegalArgumentException if provided quality scores length is smaller
1518 * than minimum required samples.
1519 */
1520 public void setFingerprintReadingsQualityScores(final double[] fingerprintReadingsQualityScores)
1521 throws LockedException {
1522 if (isLocked()) {
1523 throw new LockedException();
1524 }
1525 internalSetFingerprintReadingsQualityScores(fingerprintReadingsQualityScores);
1526 }
1527
1528 /**
1529 * Gets listener to be notified of events raised by this instance.
1530 *
1531 * @return listener to be notified of events raised by this instance.
1532 */
1533 public SequentialRobustRangingAndRssiPositionEstimatorListener<P> getListener() {
1534 return listener;
1535 }
1536
1537 /**
1538 * Sets listener to be notified of events raised by this instance.
1539 *
1540 * @param listener listener to be notified of events raised by this instance.
1541 * @throws LockedException if estimator is locked.
1542 */
1543 public void setListener(final SequentialRobustRangingAndRssiPositionEstimatorListener<P> listener)
1544 throws LockedException {
1545 if (isLocked()) {
1546 throw new LockedException();
1547 }
1548 this.listener = listener;
1549 }
1550
1551 /**
1552 * Gets initial position to use as a starting point to find a new solution.
1553 * This is optional, but if provided, when no linear solvers are used, this is
1554 * taken into account. If linear solvers are used, this is ignored.
1555 *
1556 * @return an initial position.
1557 */
1558 public P getInitialPosition() {
1559 return initialPosition;
1560 }
1561
1562 /**
1563 * Sets initial position to use as a starting point to find a new solution.
1564 * This is optional, but if provided, when no linear solvers are used, this is
1565 * taken into account. If linear solvers are used, this is ignored.
1566 *
1567 * @param initialPosition an initial position.
1568 * @throws LockedException if estimator is locked.
1569 */
1570 public void setInitialPosition(final P initialPosition) throws LockedException {
1571 if (isLocked()) {
1572 throw new LockedException();
1573 }
1574 this.initialPosition = initialPosition;
1575 }
1576
1577 /**
1578 * Returns boolean indicating if estimator is locked because estimation is
1579 * under progress.
1580 *
1581 * @return true if estimator is locked, false otherwise.
1582 */
1583 public boolean isLocked() {
1584 return locked;
1585 }
1586
1587 /**
1588 * Indicates whether this instance is ready to start the estimation.
1589 *
1590 * @return true if this instance is ready, false otherwise.
1591 */
1592 public boolean isReady() {
1593 final var numSources = sources != null ? sources.size() : 0;
1594 final var numReadings = fingerprint != null && fingerprint.getReadings() != null
1595 ? fingerprint.getReadings().size() : 0;
1596
1597 return numSources > getMinRequiredSources() && numReadings >= numSources;
1598 }
1599
1600 /**
1601 * Estimates position based on provided located radio sources and readings of such
1602 * sources at an unknown location.
1603 *
1604 * @return estimated position.
1605 * @throws LockedException if estimator is locked.
1606 * @throws NotReadyException if estimator is not ready.
1607 * @throws RobustEstimatorException if estimation fails for some other reason.
1608 */
1609 public P estimate() throws LockedException, NotReadyException, RobustEstimatorException {
1610 if (isLocked()) {
1611 throw new LockedException();
1612 }
1613
1614 // create inner estimators
1615 buildEstimators();
1616 setupEstimators();
1617
1618 if (!isReady() || !rssiEstimator.isReady() || !rangingEstimator.isReady()) {
1619 throw new NotReadyException();
1620 }
1621
1622 locked = true;
1623 if (listener != null) {
1624 listener.onEstimateStart(this);
1625 }
1626
1627 P coarsePosition;
1628 try {
1629 // estimate coarse position using RSSI data
1630 coarsePosition = rssiEstimator.estimate();
1631 } catch (final RobustEstimatorException e) {
1632 coarsePosition = null;
1633 }
1634
1635 // use coarse position as initial position for ranging estimation
1636 if (coarsePosition != null) {
1637 rangingEstimator.setInitialPosition(coarsePosition);
1638 }
1639
1640 try {
1641 final var result = rangingEstimator.estimate();
1642
1643 if (listener != null) {
1644 listener.onEstimateEnd(this);
1645 }
1646
1647 return result;
1648 } finally {
1649 locked = false;
1650 }
1651 }
1652
1653 /**
1654 * Gets data related to inliers found after estimation.
1655 *
1656 * @return data related to inliers found after estimation.
1657 */
1658 public InliersData getInliersData() {
1659 return rangingEstimator != null ? rangingEstimator.getInliersData() : null;
1660 }
1661
1662 /**
1663 * Gets known positions of radio sources used internally to solve lateration.
1664 *
1665 * @return known positions used internally.
1666 */
1667 public P[] getPositions() {
1668 return rangingEstimator != null ? rangingEstimator.getPositions() : null;
1669 }
1670
1671 /**
1672 * Gets Euclidean distances from known located radio sources to the location of
1673 * provided readings in a fingerprint.
1674 * Distance values are used internally to solve lateration.
1675 *
1676 * @return Euclidean distances used internally.
1677 */
1678 public double[] getDistances() {
1679 return rangingEstimator != null ? rangingEstimator.getDistances() : null;
1680 }
1681
1682 /**
1683 * Gets standard deviation distances from known located radio sources to the
1684 * location of provided readings in a fingerprint.
1685 * Distance standard deviations are used internally to solve lateration.
1686 *
1687 * @return standard deviations used internally.
1688 */
1689 public double[] getDistanceStandardDeviations() {
1690 return rangingEstimator != null ? rangingEstimator.getDistanceStandardDeviations() : null;
1691 }
1692
1693 /**
1694 * Gets estimated covariance of estimated position if available.
1695 * This is only available when result has been refined and covariance is kept.
1696 *
1697 * @return estimated covariance or null.
1698 */
1699 public Matrix getCovariance() {
1700 return rangingEstimator != null ? rangingEstimator.getCovariance() : null;
1701 }
1702
1703 /**
1704 * Gets estimated position.
1705 *
1706 * @return estimated position.
1707 */
1708 public P getEstimatedPosition() {
1709 return rangingEstimator != null ? rangingEstimator.getEstimatedPosition() : null;
1710 }
1711
1712 /**
1713 * Gets number of dimensions of provided points.
1714 *
1715 * @return number of dimensions of provided points.
1716 */
1717 public abstract int getNumberOfDimensions();
1718
1719 /**
1720 * Gets minimum required number of located radio sources to perform lateration.
1721 *
1722 * @return minimum required number of located radio sources to perform
1723 * lateration.
1724 */
1725 public abstract int getMinRequiredSources();
1726
1727 /**
1728 * Builds ranging and RSSI internal estimators.
1729 */
1730 protected abstract void buildEstimators();
1731
1732 /**
1733 * Setups ranging and RSSI internal estimators.
1734 *
1735 * @throws LockedException if estimator is locked.
1736 */
1737 @SuppressWarnings("DuplicatedCode")
1738 private void setupEstimators() throws LockedException {
1739 if (fingerprint != null) {
1740 // builds separated RSSI and ranging readings
1741 final var readings = fingerprint.getReadings();
1742
1743 final var rangingReadings = new ArrayList<RangingReading<RadioSource>>();
1744 final var rssiReadings = new ArrayList<RssiReading<RadioSource>>();
1745
1746 for (final var reading : readings) {
1747 rangingReadings.add(createRangingReading(reading));
1748 rssiReadings.add(createRssiReading(reading));
1749 }
1750
1751 final var rssiFingerprint = new RssiFingerprint<>(rssiReadings);
1752 final var rangingFingerprint = new RangingFingerprint<>(rangingReadings);
1753
1754 // set data and configuration on both internal estimators
1755 rssiEstimator.setSources(sources);
1756 rssiEstimator.setFingerprint(rssiFingerprint);
1757 rssiEstimator.setRadioSourcePositionCovarianceUsed(useRssiRadioSourcePositionCovariance);
1758 rssiEstimator.setEvenlyDistributeReadings(evenlyDistributeRssiReadings);
1759 rssiEstimator.setFallbackDistanceStandardDeviation(rssiFallbackDistanceStandardDeviation);
1760 rssiEstimator.setProgressDelta(2.0f * progressDelta);
1761 rssiEstimator.setConfidence(rssiConfidence);
1762 rssiEstimator.setMaxIterations(rssiMaxIterations);
1763 rssiEstimator.setResultRefined(refineResult);
1764 rssiEstimator.setCovarianceKept(keepCovariance);
1765 rssiEstimator.setInitialPosition(initialPosition);
1766 rssiEstimator.setLinearSolverUsed(useRssiLinearSolver);
1767 rssiEstimator.setHomogeneousLinearSolverUsed(useRssiHomogeneousLinearSolver);
1768 rssiEstimator.setPreliminarySolutionRefined(refineRssiPreliminarySolutions);
1769 rssiEstimator.setSourceQualityScores(sourceQualityScores);
1770 rssiEstimator.setFingerprintReadingsQualityScores(fingerprintReadingsQualityScores);
1771 rssiEstimator.setListener(new RobustRssiPositionEstimatorListener<>() {
1772 @Override
1773 public void onEstimateStart(final RobustRssiPositionEstimator<P> estimator) {
1774 // not used
1775 }
1776
1777 @Override
1778 public void onEstimateEnd(final RobustRssiPositionEstimator<P> estimator) {
1779 // not used
1780 }
1781
1782 @Override
1783 public void onEstimateNextIteration(
1784 final RobustRssiPositionEstimator<P> estimator, final int iteration) {
1785 // not used
1786 }
1787
1788 @Override
1789 public void onEstimateProgressChange(
1790 final RobustRssiPositionEstimator<P> estimator, final float progress) {
1791 if (listener != null) {
1792 listener.onEstimateProgressChange(
1793 SequentialRobustRangingAndRssiPositionEstimator.this,
1794 0.5f * progress);
1795 }
1796 }
1797 });
1798
1799 rssiEstimator.setPreliminarySubsetSize(
1800 Math.max(rssiPreliminarySubsetSize, rssiEstimator.getMinRequiredSources()));
1801
1802 rangingEstimator.setSources(sources);
1803 rangingEstimator.setFingerprint(rangingFingerprint);
1804 rangingEstimator.setRadioSourcePositionCovarianceUsed(useRangingRadioSourcePositionCovariance);
1805 rangingEstimator.setEvenlyDistributeReadings(evenlyDistributeRangingReadings);
1806 rangingEstimator.setFallbackDistanceStandardDeviation(rangingFallbackDistanceStandardDeviation);
1807 rangingEstimator.setProgressDelta(2.0f * progressDelta);
1808 rangingEstimator.setConfidence(rangingConfidence);
1809 rangingEstimator.setMaxIterations(rangingMaxIterations);
1810 rangingEstimator.setCovarianceKept(keepCovariance);
1811 rangingEstimator.setInitialPosition(initialPosition);
1812 rangingEstimator.setLinearSolverUsed(useRangingLinearSolver);
1813 rangingEstimator.setHomogeneousLinearSolverUsed(useRangingHomogeneousLinearSolver);
1814 rangingEstimator.setPreliminarySolutionRefined(refineRangingPreliminarySolutions);
1815 rangingEstimator.setSourceQualityScores(sourceQualityScores);
1816 rangingEstimator.setFingerprintReadingsQualityScores(fingerprintReadingsQualityScores);
1817 rangingEstimator.setListener(new RobustRangingPositionEstimatorListener<P>() {
1818 @Override
1819 public void onEstimateStart(final RobustRangingPositionEstimator<P> estimator) {
1820 // not used
1821 }
1822
1823 @Override
1824 public void onEstimateEnd(final RobustRangingPositionEstimator<P> estimator) {
1825 // not used
1826 }
1827
1828 @Override
1829 public void onEstimateNextIteration(
1830 final RobustRangingPositionEstimator<P> estimator, final int iteration) {
1831 // not used
1832 }
1833
1834 @Override
1835 public void onEstimateProgressChange(
1836 final RobustRangingPositionEstimator<P> estimator, final float progress) {
1837 if (listener != null) {
1838 listener.onEstimateProgressChange(
1839 SequentialRobustRangingAndRssiPositionEstimator.this,
1840 0.5f + 0.5f * progress);
1841 }
1842 }
1843 });
1844
1845 rangingEstimator.setPreliminarySubsetSize(
1846 Math.max(rangingPreliminarySubsetSize, rangingEstimator.getMinRequiredSources()));
1847 }
1848 }
1849
1850 /**
1851 * Internally sets located radio sources used for lateration.
1852 *
1853 * @param sources located radio sources used for lateration.
1854 * @throws IllegalArgumentException if provided value is null or the number of
1855 * provided sources is less than the required minimum.
1856 */
1857 private void internalSetSources(final List<? extends RadioSourceLocated<P>> sources) {
1858 if (sources == null) {
1859 throw new IllegalArgumentException();
1860 }
1861
1862 if (sources.size() < getMinRequiredSources()) {
1863 throw new IllegalArgumentException();
1864 }
1865
1866 this.sources = sources;
1867 }
1868
1869 /**
1870 * Internally sets fingerprint containing readings at an unknown location for
1871 * provided located radio sources.
1872 *
1873 * @param fingerprint fingerprint containing readings at an unknown location for
1874 * provided located radio sources.
1875 * @throws IllegalArgumentException if provided value is null.
1876 */
1877 private void internalSetFingerprint(
1878 final RangingAndRssiFingerprint<? extends RadioSource, ? extends RangingAndRssiReading<?
1879 extends RadioSource>> fingerprint) {
1880 if (fingerprint == null) {
1881 throw new IllegalArgumentException();
1882 }
1883
1884 this.fingerprint = fingerprint;
1885 }
1886
1887 /**
1888 * Sets quality scores corresponding to each provided located radio source.
1889 * This method is used internally and does not check whether instance is
1890 * locked or not.
1891 *
1892 * @param sourceQualityScores quality scores to be set.
1893 * @throws IllegalArgumentException if provided quality scores length
1894 * is smaller than 3 samples for 2D or 4 samples for 3D.
1895 */
1896 private void internalSetSourceQualityScores(final double[] sourceQualityScores) {
1897 if (sourceQualityScores == null || sourceQualityScores.length < getMinRequiredSources()) {
1898 throw new IllegalArgumentException();
1899 }
1900
1901 this.sourceQualityScores = sourceQualityScores;
1902 }
1903
1904 /**
1905 * Sets quality scores corresponding to each provided reading within provided
1906 * fingerprint.
1907 * This method is used internally and does not check whether instance is locked
1908 * or not.
1909 *
1910 * @param fingerprintReadingsQualityScores quality scores to be set.
1911 * @throws IllegalArgumentException if provided quality scores length is
1912 * smaller than 3 samples for 2D or 4 samples for 3D.
1913 */
1914 private void internalSetFingerprintReadingsQualityScores(final double[] fingerprintReadingsQualityScores) {
1915 if (fingerprintReadingsQualityScores == null
1916 || fingerprintReadingsQualityScores.length < getMinRequiredSources()) {
1917 throw new IllegalArgumentException();
1918 }
1919
1920 this.fingerprintReadingsQualityScores = fingerprintReadingsQualityScores;
1921 }
1922
1923 /**
1924 * Creates a ranging reading from a ranging and RSSI reading.
1925 *
1926 * @param reading input reading to convert from.
1927 * @return a ranging reading containing only the ranging data of input reading.
1928 */
1929 private RangingReading<RadioSource> createRangingReading(
1930 final RangingAndRssiReading<? extends RadioSource> reading) {
1931 return new RangingReading<>(reading.getSource(),
1932 reading.getDistance(),
1933 reading.getDistanceStandardDeviation(),
1934 reading.getNumAttemptedMeasurements(),
1935 reading.getNumSuccessfulMeasurements());
1936 }
1937
1938 /**
1939 * Creates an RSSI reading from a ranging and RSSI reading.
1940 *
1941 * @param reading input reading to convert from.
1942 * @return an RSSI reading containing only the RSSI data of input reading.
1943 */
1944 private RssiReading<RadioSource> createRssiReading(final RangingAndRssiReading<? extends RadioSource> reading) {
1945 return new RssiReading<>(reading.getSource(), reading.getRssi(),
1946 reading.getRssiStandardDeviation());
1947 }
1948 }