1 /*
2 * Copyright (C) 2018 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.radiosource;
17
18 import com.irurueta.algebra.AlgebraException;
19 import com.irurueta.algebra.Matrix;
20 import com.irurueta.geometry.Point;
21 import com.irurueta.navigation.LockedException;
22 import com.irurueta.navigation.NotReadyException;
23 import com.irurueta.navigation.indoor.RadioSource;
24 import com.irurueta.navigation.indoor.RadioSourceLocated;
25 import com.irurueta.navigation.indoor.RangingAndRssiReadingLocated;
26 import com.irurueta.navigation.indoor.RangingReadingLocated;
27 import com.irurueta.navigation.indoor.ReadingLocated;
28 import com.irurueta.navigation.indoor.RssiReadingLocated;
29 import com.irurueta.navigation.indoor.Utils;
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 * This is an abstract class to robustly estimate position, transmitted power and path-loss
39 * exponent of a radio source (e.g. Wi-Fi access point or bluetooth beacon), by discarding
40 * outliers and assuming that the ranging data is available to obtain position with
41 * greater accuracy and that the radio source emits isotropically following the
42 * expression below:
43 * Pr = Pt*Gt*Gr*lambda^2 / (4*pi*d)^2,
44 * where Pr is the received power (expressed in mW),
45 * Gt is the Gain of the transmission antenna
46 * Gr is the Gain of the receiver antenna
47 * d is the distance between emitter and receiver
48 * and lambda is the wavelength and is equal to: lambda = c / f,
49 * where c is the speed of light
50 * and f is the carrier frequency of the radio signal.
51 * <p>
52 * Implementations of this class sequentially estimate position and then remaining
53 * parameters. First ranging data is used to robustly estimate position and then
54 * remaining parameters are robustly estimated using former estimated position as
55 * an initial guess.
56 * <p>
57 * Because usually information about the antenna of the radio source cannot be
58 * retrieved (because many measurements are made on unknown devices where
59 * physical access is not possible), this implementation will estimate the
60 * equivalent transmitted power as: Pte = Pt * Gt * Gr.
61 * If Readings contain RSSI standard deviations, those values will be used,
62 * otherwise it will be assumed an RSSI standard deviation of 1 dB.
63 * <p>
64 * This implementation is like SequentialRobustRangingAndRssiRadioSourceEstimator but
65 * allows mixing different kinds of located radio source readings (ranging, RSSI
66 * and ranging+RSSI).
67 *
68 * @param <S> a {@link RadioSource} type.
69 * @param <P> a {@link Point} type.
70 */
71 public abstract class SequentialRobustMixedRadioSourceEstimator<S extends RadioSource, P extends Point<P>> {
72
73 /**
74 * Default robust estimator method for robust position estimation using ranging
75 * data when no robust method is provided.
76 */
77 public static final RobustEstimatorMethod DEFAULT_PANGING_ROBUST_METHOD = RobustEstimatorMethod.PROMEDS;
78
79 /**
80 * Default robust estimator method for path-loss exponent and transmitted power
81 * estimation using RSSI data when no robust method is provided.
82 */
83 public static final RobustEstimatorMethod DEFAULT_RSSI_ROBUST_METHOD = RobustEstimatorMethod.PROMEDS;
84
85 /**
86 * Indicates that result is refined by default using all found inliers.
87 */
88 public static final boolean DEFAULT_REFINE_RESULT = true;
89
90 /**
91 * Indicates that covariance is kept by default after refining result.
92 */
93 public static final boolean DEFAULT_KEEP_COVARIANCE = true;
94
95 /**
96 * Default amount of progress variation before notifying a change in estimation progress.
97 * By default, this is set to 5%.
98 */
99 public static final float DEFAULT_PROGRESS_DELTA = 0.05f;
100
101 /**
102 * Minimum allowed value for progress delta.
103 */
104 public static final float MIN_PROGRESS_DELTA = 0.0f;
105
106 /**
107 * Maximum allowed value for progress delta.
108 */
109 public static final float MAX_PROGRESS_DELTA = 1.0f;
110
111 /**
112 * Constant defining default confidence of the estimated result, which is
113 * 99%. This means that with a probability of 99% estimation will be
114 * accurate because chosen sub-samples will be inliers.
115 */
116 public static final double DEFAULT_CONFIDENCE = 0.99;
117
118 /**
119 * Default maximum allowed number of iterations.
120 */
121 public static final int DEFAULT_MAX_ITERATIONS = 5000;
122
123 /**
124 * Minimum allowed confidence value.
125 */
126 public static final double MIN_CONFIDENCE = 0.0;
127
128 /**
129 * Maximum allowed confidence value.
130 */
131 public static final double MAX_CONFIDENCE = 1.0;
132
133 /**
134 * Minimum allowed number of iterations.
135 */
136 public static final int MIN_ITERATIONS = 1;
137
138 /**
139 * Indicates that by default position covariances of readings must be taken into account to increase
140 * the amount of standard deviation of each ranging measure by the amount of position standard deviation
141 * assuming that both measures are statistically independent.
142 */
143 public static final boolean DEFAULT_USE_READING_POSITION_COVARIANCES = true;
144
145 /**
146 * Internal robust estimator for position estimation.
147 */
148 protected RobustRangingRadioSourceEstimator<S, P> rangingEstimator;
149
150 /**
151 * Internal robust estimator for path-loss exponent and transmitted power
152 * estimation.
153 */
154 protected RobustRssiRadioSourceEstimator<S, P> rssiEstimator;
155
156 /**
157 * Robust method used for robust position estimation using ranging data.
158 */
159 protected RobustEstimatorMethod rangingRobustMethod = DEFAULT_PANGING_ROBUST_METHOD;
160
161 /**
162 * Robust method used for path-loss exponent and transmitted power estimation
163 * using RSSI data.
164 */
165 protected RobustEstimatorMethod rssiRobustMethod = DEFAULT_RSSI_ROBUST_METHOD;
166
167 /**
168 * Size of subsets to be checked during ranging robust estimation.
169 */
170 protected int rangingPreliminarySubsetSize;
171
172 /**
173 * Size of subsets to be checked during RSSI robust estimation.
174 */
175 protected int rssiPreliminarySubsetSize;
176
177 /**
178 * Threshold to determine when samples are inliers or not used during robust
179 * position estimation.
180 * If not defined, default threshold will be used.
181 */
182 protected Double rangingThreshold;
183
184 /**
185 * Threshold to determine when samples are inliers or not used during robust
186 * path-loss exponent and transmitted power estimation.
187 */
188 protected Double rssiThreshold;
189
190 /**
191 * Indicates whether position is estimated using RSSI data.
192 * If enough ranging readings are available, this is false and position is estimated using ranging readings,
193 * otherwise this is true and position is estimated using RSSI data in a less reliable way.
194 */
195 protected boolean rssiPositionEnabled;
196
197 /**
198 * Signal readings belonging to the same radio source to be estimated.
199 */
200 private List<? extends ReadingLocated<P>> readings;
201
202 /**
203 * Quality scores corresponding to each provided sample.
204 * The larger the score value the better the quality of the sample.
205 */
206 private double[] qualityScores;
207
208 /**
209 * Listener to be notified of events such as when estimation starts, ends or its
210 * progress significantly changes.
211 */
212 private SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener;
213
214 /**
215 * Estimated position.
216 */
217 private P estimatedPosition;
218
219 /**
220 * Indicates if this instance is locked because estimation is being executed.
221 */
222 private boolean locked;
223
224 /**
225 * Amount of progress variation before notifying a progress change during estimation.
226 */
227 private float progressDelta = DEFAULT_PROGRESS_DELTA;
228
229 /**
230 * Amount of confidence expressed as a value between 0.0 and 1.0 (which is equivalent
231 * to 100%) for robust position estimation. The amount of confidence indicates the
232 * probability that the estimated result is correct. Usually this value will be
233 * close to 1.0, but not exactly 1.0.
234 */
235 private double rangingConfidence = DEFAULT_CONFIDENCE;
236
237 /**
238 * Amount of confidence expressed as a value between 0.0 and 1.0 (which is equivalent
239 * to 100%) for robust path-loss exponent and transmitted power estimation. The amount
240 * of confidence indicates the probability that the estimated result is correct.
241 * Usually this value will be close to 1.0, but not exactly 1.0.
242 */
243 private double rssiConfidence = DEFAULT_CONFIDENCE;
244
245 /**
246 * Maximum allowed number of iterations for robust position estimation. When the
247 * maximum number of iterations is exceeded, an approximate result might be
248 * available for retrieval.
249 */
250 private int rangingMaxIterations = DEFAULT_MAX_ITERATIONS;
251
252 /**
253 * Maximum allowed number of iterations for robust path-loss exponent and transmitted
254 * power estimation. When the maximum number of iterations is exceeded, an
255 * approximate result might be available for retrieval.
256 */
257 private int rssiMaxIterations = DEFAULT_MAX_ITERATIONS;
258
259 /**
260 * Indicates whether result must be refined using found inliers.
261 * If true, inliers will be computed and kept in any implementation regardless of the
262 * settings.
263 */
264 private boolean refineResult = DEFAULT_REFINE_RESULT;
265
266 /**
267 * Indicates whether covariance must be kept after refining result.
268 * This setting is only taken into account if result is refined.
269 */
270 private boolean keepCovariance = DEFAULT_KEEP_COVARIANCE;
271
272 /**
273 * Covariance of estimated position, power and/or path-loss exponent.
274 * This is only available when result has been refined and covariance is kept.
275 */
276 private Matrix covariance;
277
278 /**
279 * Covariance of estimated position.
280 * Size of this matrix will depend on the number of dimensions
281 * of estimated position (either 2 or 3).
282 * This value will only be available when position estimation is enabled.
283 */
284 private Matrix estimatedPositionCovariance;
285
286 /**
287 * Initially transmitted power to start the estimation of radio source
288 * transmitted power.
289 * If not defined, average value of received power readings will be used.
290 */
291 private Double initialTransmittedPowerdBm;
292
293 /**
294 * Initial position to start the estimation of radio source position.
295 * If not defined, centroid of provided located readings will be used.
296 */
297 private P initialPosition;
298
299 /**
300 * Initial exponent typically used on free space for path loss propagation in
301 * terms of distance.
302 * On different environments path loss exponent might have different values:
303 * - Free space: 2.0
304 * - Urban Area: 2.7 to 3.5
305 * - Suburban Area: 3 to 5
306 * - Indoor (line-of-sight): 1.6 to 1.8
307 * <p>
308 * If path loss exponent estimation is enabled, estimation will start at this
309 * value and will converge to the most appropriate value.
310 * If path loss exponent estimation is disabled, this value will be assumed
311 * to be exact and the estimated path loss exponent will be equal to this
312 * value.
313 */
314 private double initialPathLossExponent = MixedRadioSourceEstimator.DEFAULT_PATH_LOSS_EXPONENT;
315
316 /**
317 * Indicates whether transmitted power estimation is enabled or not.
318 */
319 private boolean transmittedPowerEstimationEnabled =
320 MixedRadioSourceEstimator.DEFAULT_TRANSMITTED_POWER_ESTIMATION_ENABLED;
321
322 /**
323 * Indicates whether path loss estimation is enabled or not.
324 */
325 private boolean pathLossEstimationEnabled = MixedRadioSourceEstimator.DEFAULT_PATHLOSS_ESTIMATION_ENABLED;
326
327 /**
328 * Estimated transmitted power expressed in dBm's or null if not available.
329 */
330 private Double estimatedTransmittedPowerdBm;
331
332 /**
333 * Estimated exponent typically used on free space for path loss propagation in
334 * terms of distance.
335 * On different environments path loss exponent might have different values:
336 * - Free space: 2.0
337 * - Urban Area: 2.7 to 3.5
338 * - Suburban Area: 3 to 5
339 * - Indoor (line-of-sight): 1.6 to 1.8
340 * If path loss exponent estimation is not enabled, this value will always be equal to
341 * {@link RssiRadioSourceEstimator#DEFAULT_PATH_LOSS_EXPONENT}
342 */
343 private double estimatedPathLossExponent = MixedRadioSourceEstimator.DEFAULT_PATH_LOSS_EXPONENT;
344
345 /**
346 * Variance of estimated transmitted power.
347 * This value will only be available when transmitted power
348 * estimation is enabled.
349 */
350 private Double estimatedTransmittedPowerVariance;
351
352 /**
353 * Variance of estimated path loss exponent.
354 * This value will only be available when path-loss
355 * exponent estimation is enabled.
356 */
357 private Double estimatedPathLossExponentVariance;
358
359 /**
360 * Data related to inliers found after estimation.
361 */
362 private InliersData inliersData;
363
364 /**
365 * Indicates whether position covariances of readings must be taken into account to increase
366 * the amount of standard deviation of each ranging measure by the amount of position standard deviation
367 * assuming that both measures are statistically independent.
368 */
369 private boolean useReadingPositionCovariances = DEFAULT_USE_READING_POSITION_COVARIANCES;
370
371 /**
372 * Indicates whether an homogeneous ranging linear solver is used to estimate preliminary positions.
373 */
374 private boolean useHomogeneousRangingLinearSolver =
375 RangingRadioSourceEstimator.DEFAULT_USE_HOMOGENEOUS_LINEAR_SOLVER;
376
377 /**
378 * Number of ranging readings available among all readings.
379 */
380 private int numRangingReadings;
381
382 /**
383 * Number of RSSI readings available among all readings.
384 */
385 private int numRssiReadings;
386
387 /**
388 * Constructor.
389 */
390 protected SequentialRobustMixedRadioSourceEstimator() {
391 }
392
393 /**
394 * Constructor.
395 * Sets signal readings belonging to the same radio source.
396 *
397 * @param readings signal readings belonging to the same radio source.
398 * @throws IllegalArgumentException if readings are not valid.
399 */
400 protected SequentialRobustMixedRadioSourceEstimator(final List<? extends ReadingLocated<P>> readings) {
401 internalSetReadings(readings);
402 }
403
404 /**
405 * Constructor.
406 *
407 * @param listener listener in charge of attending events raised by this instance.
408 */
409 protected SequentialRobustMixedRadioSourceEstimator(
410 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
411 this.listener = listener;
412 }
413
414 /**
415 * Constructor.
416 * Sets signal readings belonging to the same radio source.
417 *
418 * @param readings signal readings belonging to the same radio source.
419 * @param listener listener in charge of attending events raised by this instance.
420 * @throws IllegalArgumentException if readings are not valid.
421 */
422 protected SequentialRobustMixedRadioSourceEstimator(
423 final List<? extends ReadingLocated<P>> readings,
424 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
425 this(readings);
426 this.listener = listener;
427 }
428
429 /**
430 * Constructor.
431 * Sets signal readings belonging to the same radio source.
432 *
433 * @param readings signal readings belonging to the same radio source.
434 * @param initialPosition initial position to start the estimation of radio
435 * source position.
436 * @throws IllegalArgumentException if readings are not valid.
437 */
438 protected SequentialRobustMixedRadioSourceEstimator(
439 final List<? extends ReadingLocated<P>> readings, final P initialPosition) {
440 this(readings);
441 this.initialPosition = initialPosition;
442 }
443
444 /**
445 * Constructor.
446 *
447 * @param initialPosition initial position to start the estimation of radio
448 * source position.
449 */
450 protected SequentialRobustMixedRadioSourceEstimator(final P initialPosition) {
451 this.initialPosition = initialPosition;
452 }
453
454 /**
455 * Constructor.
456 *
457 * @param initialPosition initial position to start the estimation of radio
458 * source position.
459 * @param listener listener in charge of attending events raised by this instance.
460 */
461 protected SequentialRobustMixedRadioSourceEstimator(
462 final P initialPosition, final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
463 this(listener);
464 this.initialPosition = initialPosition;
465 }
466
467 /**
468 * Constructor.
469 * Sets signal readings belonging to the same radio source.
470 *
471 * @param readings signal readings belonging to the same radio source.
472 * @param initialPosition initial position to start the estimation of radio
473 * source position.
474 * @param listener listener in charge of attending events raised by this instance.
475 * @throws IllegalArgumentException if readings are not valid.
476 */
477 protected SequentialRobustMixedRadioSourceEstimator(
478 final List<? extends ReadingLocated<P>> readings, final P initialPosition,
479 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
480 this(readings, listener);
481 this.initialPosition = initialPosition;
482 }
483
484 /**
485 * Constructor.
486 *
487 * @param initialTransmittedPowerdBm initial transmitted power to start the
488 * estimation of radio source transmitted power
489 * (expressed in dBm's).
490 */
491 protected SequentialRobustMixedRadioSourceEstimator(final Double initialTransmittedPowerdBm) {
492 this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
493 }
494
495 /**
496 * Constructor.
497 * Sets signal readings belonging to the same radio source.
498 *
499 * @param readings signal readings belonging to the same radio source.
500 * @param initialTransmittedPowerdBm initial transmitted power to start the
501 * estimation of radio source transmitted power
502 * (expressed in dBm's).
503 * @throws IllegalArgumentException if readings are not valid.
504 */
505 protected SequentialRobustMixedRadioSourceEstimator(
506 final List<? extends ReadingLocated<P>> readings, final Double initialTransmittedPowerdBm) {
507 this(readings);
508 this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
509 }
510
511 /**
512 * Constructor.
513 *
514 * @param initialTransmittedPowerdBm initial transmitted power to start the
515 * estimation of radio source transmitted power
516 * (expressed in dBm's).
517 * @param listener listener in charge of attending events raised by this instance.
518 */
519 protected SequentialRobustMixedRadioSourceEstimator(
520 final Double initialTransmittedPowerdBm,
521 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
522 this(listener);
523 this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
524 }
525
526 /**
527 * Constructor.
528 * Sets signal readings belonging to the same radio source.
529 *
530 * @param readings signal readings belonging to the same radio source.
531 * @param initialTransmittedPowerdBm initial transmitted power to start the
532 * estimation of radio source transmitted power
533 * (expressed in dBm's).
534 * @param listener listener in charge of attending events raised by this instance.
535 * @throws IllegalArgumentException if readings are not valid.
536 */
537 protected SequentialRobustMixedRadioSourceEstimator(
538 final List<? extends ReadingLocated<P>> readings, final Double initialTransmittedPowerdBm,
539 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
540 this(readings, listener);
541 this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
542 }
543
544 /**
545 * Constructor.
546 * Sets signal readings belonging to the same radio source.
547 *
548 * @param readings signal readings belonging to the same radio source.
549 * @param initialPosition initial position to start the estimation of radio
550 * source position.
551 * @param initialTransmittedPowerdBm initial transmitted power to start the
552 * estimation of radio source transmitted power
553 * (expressed in dBm's).
554 * @throws IllegalArgumentException if readings are not valid.
555 */
556 protected SequentialRobustMixedRadioSourceEstimator(
557 final List<? extends ReadingLocated<P>> readings, final P initialPosition,
558 final Double initialTransmittedPowerdBm) {
559 this(readings);
560 this.initialPosition = initialPosition;
561 this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
562 }
563
564 /**
565 * Constructor.
566 *
567 * @param initialPosition initial position to start the estimation of radio
568 * source position.
569 * @param initialTransmittedPowerdBm initial transmitted power to start the
570 * estimation of radio source transmitted power
571 * (expressed in dBm's).
572 */
573 protected SequentialRobustMixedRadioSourceEstimator(
574 final P initialPosition, final Double initialTransmittedPowerdBm) {
575 this.initialPosition = initialPosition;
576 this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
577 }
578
579 /**
580 * Constructor.
581 *
582 * @param initialPosition initial position to start the estimation of radio
583 * source position.
584 * @param initialTransmittedPowerdBm initial transmitted power to start the
585 * estimation of radio source transmitted power
586 * (expressed in dBm's).
587 * @param listener listener in charge of attending events raised by this instance.
588 */
589 protected SequentialRobustMixedRadioSourceEstimator(
590 final P initialPosition, final Double initialTransmittedPowerdBm,
591 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
592 this(listener);
593 this.initialPosition = initialPosition;
594 this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
595 }
596
597 /**
598 * Constructor.
599 * Sets signal readings belonging to the same radio source.
600 *
601 * @param readings signal readings belonging to the same radio source.
602 * @param initialPosition initial position to start the estimation of radio
603 * source position.
604 * @param initialTransmittedPowerdBm initial transmitted power to start the
605 * estimation of radio source transmitted power
606 * (expressed in dBm's).
607 * @param listener listener in charge of attending events raised by this instance.
608 * @throws IllegalArgumentException if readings are not valid.
609 */
610 protected SequentialRobustMixedRadioSourceEstimator(
611 final List<? extends ReadingLocated<P>> readings, final P initialPosition,
612 final Double initialTransmittedPowerdBm,
613 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
614 this(readings, listener);
615 this.initialPosition = initialPosition;
616 this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
617 }
618
619 /**
620 * Constructor.
621 * Sets signal readings belonging to the same radio source.
622 *
623 * @param readings signal readings belonging to the same radio source.
624 * @param initialPosition initial position to start the estimation of radio
625 * source position.
626 * @param initialTransmittedPowerdBm initial transmitted power to start the
627 * estimation of radio source transmitted power
628 * (expressed in dBm's).
629 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
630 * @throws IllegalArgumentException if readings are not valid.
631 */
632 protected SequentialRobustMixedRadioSourceEstimator(
633 final List<? extends ReadingLocated<P>> readings, final P initialPosition,
634 final Double initialTransmittedPowerdBm, final double initialPathLossExponent) {
635 this(readings, initialPosition, initialTransmittedPowerdBm);
636 this.initialPathLossExponent = initialPathLossExponent;
637 }
638
639 /**
640 * Constructor.
641 *
642 * @param initialPosition initial position to start the estimation of radio
643 * source position.
644 * @param initialTransmittedPowerdBm initial transmitted power to start the
645 * estimation of radio source transmitted power
646 * (expressed in dBm's).
647 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
648 */
649 protected SequentialRobustMixedRadioSourceEstimator(
650 final P initialPosition, final Double initialTransmittedPowerdBm, final double initialPathLossExponent) {
651 this(initialPosition, initialTransmittedPowerdBm);
652 this.initialPathLossExponent = initialPathLossExponent;
653 }
654
655 /**
656 * Constructor.
657 *
658 * @param initialPosition initial position to start the estimation of radio
659 * source position.
660 * @param initialTransmittedPowerdBm initial transmitted power to start the
661 * estimation of radio source transmitted power
662 * (expressed in dBm's).
663 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
664 * @param listener listener in charge of attending events raised by this instance.
665 */
666 protected SequentialRobustMixedRadioSourceEstimator(
667 final P initialPosition, final Double initialTransmittedPowerdBm, final double initialPathLossExponent,
668 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
669 this(initialPosition, initialTransmittedPowerdBm, listener);
670 this.initialPathLossExponent = initialPathLossExponent;
671 }
672
673 /**
674 * Constructors.
675 * Sets signal readings belonging to the same radio source.
676 *
677 * @param readings signal readings belonging to the same radio source.
678 * @param initialPosition initial position to start the estimation of radio
679 * source position.
680 * @param initialTransmittedPowerdBm initial transmitted power to start the
681 * estimation of radio source transmitted power
682 * (expressed in dBm's).
683 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
684 * @param listener listener in charge of attending events raised by this instance.
685 * @throws IllegalArgumentException if readings are not valid.
686 */
687 protected SequentialRobustMixedRadioSourceEstimator(
688 final List<? extends ReadingLocated<P>> readings, final P initialPosition,
689 final Double initialTransmittedPowerdBm, final double initialPathLossExponent,
690 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
691 this(readings, initialPosition, initialTransmittedPowerdBm, listener);
692 this.initialPathLossExponent = initialPathLossExponent;
693 }
694
695 /**
696 * Constructor.
697 *
698 * @param qualityScores quality scores corresponding to each provided sample.
699 * The larger the score value the better the quality of
700 * the sample.
701 * @throws IllegalArgumentException if quality scores is null, or length of
702 * quality scores is less than required minimum.
703 */
704 protected SequentialRobustMixedRadioSourceEstimator(final double[] qualityScores) {
705 this();
706 internalSetQualityScores(qualityScores);
707 }
708
709 /**
710 * Constructor.
711 * Sets signal readings belonging to the same radio source.
712 *
713 * @param qualityScores quality scores corresponding to each provided sample.
714 * The larger the score value the better the quality of
715 * the sample.
716 * @param readings signal readings belonging to the same radio source.
717 * @throws IllegalArgumentException if readings are not valid, quality scores is
718 * null, or length of quality scores is less than required minimum.
719 */
720 protected SequentialRobustMixedRadioSourceEstimator(
721 final double[] qualityScores, final List<? extends ReadingLocated<P>> readings) {
722 this(readings);
723 internalSetQualityScores(qualityScores);
724 }
725
726 /**
727 * Constructor.
728 *
729 * @param qualityScores quality scores corresponding to each provided sample.
730 * The larger the score value the better the quality of
731 * the sample.
732 * @param listener listener in charge of attending events raised by this instance.
733 * @throws IllegalArgumentException if quality scores is null, or length
734 * of quality scores is less than required minimum.
735 */
736 protected SequentialRobustMixedRadioSourceEstimator(
737 final double[] qualityScores, final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
738 this(listener);
739 internalSetQualityScores(qualityScores);
740 }
741
742 /**
743 * Constructor.
744 * Sets signal readings belonging to the same radio source.
745 *
746 * @param qualityScores quality scores corresponding to each provided sample.
747 * The larger the score value the better the quality of
748 * the sample.
749 * @param readings signal readings belonging to the same radio source.
750 * @param listener listener in charge of attending events raised by this instance.
751 * @throws IllegalArgumentException if readings are not valid, quality scores is
752 * null, or length of quality scores is less than required minimum.
753 */
754 protected SequentialRobustMixedRadioSourceEstimator(
755 final double[] qualityScores, final List<? extends ReadingLocated<P>> readings,
756 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
757 this(readings, listener);
758 internalSetQualityScores(qualityScores);
759 }
760
761 /**
762 * Constructor.
763 * Sets signal readings belonging to the same radio source.
764 *
765 * @param qualityScores quality scores corresponding to each provided sample.
766 * The larger the score value the better the quality of
767 * the sample.
768 * @param readings signal readings belonging to the same radio source.
769 * @param initialPosition initial position to start the estimation of radio
770 * source position.
771 * @throws IllegalArgumentException if readings are not valid, quality scores is
772 * null, or length of quality scores is less than required minimum.
773 */
774 protected SequentialRobustMixedRadioSourceEstimator(
775 final double[] qualityScores, final List<? extends ReadingLocated<P>> readings, final P initialPosition) {
776 this(readings, initialPosition);
777 internalSetQualityScores(qualityScores);
778 }
779
780 /**
781 * Constructor.
782 *
783 * @param qualityScores quality scores corresponding to each provided sample.
784 * The larger the score value the better the quality of
785 * the sample.
786 * @param initialPosition initial position to start the estimation of radio
787 * source position.
788 * @throws IllegalArgumentException if quality scores is null, or length
789 * of quality scores is less than required minimum.
790 */
791 protected SequentialRobustMixedRadioSourceEstimator(final double[] qualityScores, final P initialPosition) {
792 this(initialPosition);
793 internalSetQualityScores(qualityScores);
794 }
795
796 /**
797 * Constructor.
798 *
799 * @param qualityScores quality scores corresponding to each provided sample.
800 * The larger the score value the better the quality of
801 * the sample.
802 * @param initialPosition initial position to start the estimation of radio
803 * source position.
804 * @param listener listener in charge of attending events raised by this instance.
805 * @throws IllegalArgumentException if quality scores is null, or length
806 * of quality scores is less than required minimum.
807 */
808 protected SequentialRobustMixedRadioSourceEstimator(
809 final double[] qualityScores, final P initialPosition,
810 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
811 this(initialPosition, listener);
812 internalSetQualityScores(qualityScores);
813 }
814
815 /**
816 * Constructor.
817 * Sets signal readings belonging to the same radio source.
818 *
819 * @param qualityScores quality scores corresponding to each provided sample.
820 * The larger the score value the better the quality of
821 * the sample.
822 * @param readings signal readings belonging to the same radio source.
823 * @param initialPosition initial position to start the estimation of radio
824 * source position.
825 * @param listener listener in charge of attending events raised by this instance.
826 * @throws IllegalArgumentException if readings are not valid, quality scores
827 * is null, or length of quality scores is less than required minimum.
828 */
829 protected SequentialRobustMixedRadioSourceEstimator(
830 final double[] qualityScores, final List<? extends ReadingLocated<P>> readings,
831 final P initialPosition, final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
832 this(readings, initialPosition, listener);
833 internalSetQualityScores(qualityScores);
834 }
835
836 /**
837 * Constructor.
838 *
839 * @param qualityScores quality scores corresponding to each provided sample.
840 * The larger the score value the better the quality of
841 * the sample.
842 * @param initialTransmittedPowerdBm initial transmitted power to start the
843 * estimation of radio source transmitted power
844 * (expressed in dBm's).
845 * @throws IllegalArgumentException if quality scores is null, or length
846 * of quality scores is less than required minimum.
847 */
848 protected SequentialRobustMixedRadioSourceEstimator(
849 final double[] qualityScores, final Double initialTransmittedPowerdBm) {
850 this(initialTransmittedPowerdBm);
851 internalSetQualityScores(qualityScores);
852 }
853
854 /**
855 * Constructor.
856 * Sets signal readings belonging to the same radio source.
857 *
858 * @param qualityScores quality scores corresponding to each provided sample.
859 * The larger the score value the better the quality of
860 * the sample.
861 * @param readings signal readings belonging to the same radio source.
862 * @param initialTransmittedPowerdBm initial transmitted power to start the
863 * estimation of radio source transmitted power
864 * (expressed in dBm's).
865 * @throws IllegalArgumentException if readings are not valid, quality scores
866 * is null, or length of quality scores is less than required minimum.
867 */
868 protected SequentialRobustMixedRadioSourceEstimator(
869 final double[] qualityScores, final List<? extends ReadingLocated<P>> readings,
870 final Double initialTransmittedPowerdBm) {
871 this(readings, initialTransmittedPowerdBm);
872 internalSetQualityScores(qualityScores);
873 }
874
875 /**
876 * Constructor.
877 *
878 * @param qualityScores quality scores corresponding to each provided sample.
879 * The larger the score value the better the quality of
880 * the sample.
881 * @param initialTransmittedPowerdBm initial transmitted power to start the
882 * estimation of radio source transmitted power
883 * (expressed in dBm's).
884 * @param listener listener in charge of attending events raised by this instance.
885 * @throws IllegalArgumentException if quality scores is null, or length
886 * of quality scores is less than required minimum.
887 */
888 protected SequentialRobustMixedRadioSourceEstimator(
889 final double[] qualityScores, final Double initialTransmittedPowerdBm,
890 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
891 this(initialTransmittedPowerdBm, listener);
892 internalSetQualityScores(qualityScores);
893 }
894
895 /**
896 * Constructor.
897 * Sets signal readings belonging to the same radio source.
898 *
899 * @param qualityScores quality scores corresponding to each provided
900 * sample. The larger the score value the better
901 * the quality of the sample.
902 * @param readings signal readings belonging to the same radio source.
903 * @param initialTransmittedPowerdBm initial transmitted power to start the
904 * estimation of radio source transmitted power
905 * (expressed in dBm's).
906 * @param listener listener in charge of attending events raised by this instance.
907 * @throws IllegalArgumentException if readings are not valid, quality scores
908 * is null, or length of quality scores is less than required minimum.
909 */
910 protected SequentialRobustMixedRadioSourceEstimator(
911 final double[] qualityScores, final List<? extends ReadingLocated<P>> readings,
912 final Double initialTransmittedPowerdBm,
913 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
914 this(readings, initialTransmittedPowerdBm, listener);
915 internalSetQualityScores(qualityScores);
916 }
917
918 /**
919 * Constructor.
920 * Sets signal readings belonging to the same radio source.
921 *
922 * @param qualityScores quality scores corresponding to each provided
923 * sample. The larger the score value the better
924 * the quality of the sample.
925 * @param readings signal readings belonging to the same radio source.
926 * @param initialPosition initial position to start the estimation of radio
927 * source position.
928 * @param initialTransmittedPowerdBm initial transmitted power to start the
929 * estimation of radio source transmitted power
930 * (expressed in dBm's).
931 * @throws IllegalArgumentException if readings are not valid, quality scores
932 * is null, or length of quality scores is less than required minimum.
933 */
934 protected SequentialRobustMixedRadioSourceEstimator(
935 final double[] qualityScores, final List<? extends ReadingLocated<P>> readings,
936 final P initialPosition, final Double initialTransmittedPowerdBm) {
937 this(readings, initialPosition, initialTransmittedPowerdBm);
938 internalSetQualityScores(qualityScores);
939 }
940
941 /**
942 * Constructor.
943 *
944 * @param qualityScores quality scores corresponding to each provided
945 * sample. The larger the score value the better
946 * the quality of the sample.
947 * @param initialPosition initial position to start the estimation of radio
948 * source position.
949 * @param initialTransmittedPowerdBm initial transmitted power to start the
950 * estimation of radio source transmitted power
951 * (expressed in dBm's).
952 * @throws IllegalArgumentException if quality scores is null, or length
953 * of quality scores is less than required minimum.
954 */
955 protected SequentialRobustMixedRadioSourceEstimator(
956 final double[] qualityScores, final P initialPosition, final Double initialTransmittedPowerdBm) {
957 this(initialPosition, initialTransmittedPowerdBm);
958 internalSetQualityScores(qualityScores);
959 }
960
961 /**
962 * Constructor.
963 *
964 * @param qualityScores quality scores corresponding to each provided
965 * sample. The larger the score value the better
966 * the quality of the sample.
967 * @param initialPosition initial position to start the estimation of radio
968 * source position.
969 * @param initialTransmittedPowerdBm initial transmitted power to start the
970 * estimation of radio source transmitted power
971 * (expressed in dBm's).
972 * @param listener in charge of attending events raised by this instance.
973 * @throws IllegalArgumentException if quality scores is null, or length
974 * of quality scores is less than required minimum.
975 */
976 protected SequentialRobustMixedRadioSourceEstimator(
977 final double[] qualityScores, final P initialPosition, final Double initialTransmittedPowerdBm,
978 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
979 this(initialPosition, initialTransmittedPowerdBm, listener);
980 internalSetQualityScores(qualityScores);
981 }
982
983 /**
984 * Constructor.
985 * Sets signal readings belonging to the same radio source.
986 *
987 * @param qualityScores quality scores corresponding to each provided
988 * sample. The larger the score value the better
989 * the quality of the sample.
990 * @param readings signal readings belonging to the same radio source.
991 * @param initialPosition initial position to start the estimation of radio
992 * source position.
993 * @param initialTransmittedPowerdBm initial transmitted power to start the
994 * estimation of radio source transmitted power
995 * (expressed in dBm's).
996 * @param listener listener in charge of attending events raised by this instance.
997 * @throws IllegalArgumentException if readings are not valid, quality scores
998 * is null, or length of quality scores is less than required minimum.
999 */
1000 protected SequentialRobustMixedRadioSourceEstimator(
1001 final double[] qualityScores, final List<? extends ReadingLocated<P>> readings, final P initialPosition,
1002 final Double initialTransmittedPowerdBm,
1003 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
1004 this(readings, initialPosition, initialTransmittedPowerdBm, listener);
1005 internalSetQualityScores(qualityScores);
1006 }
1007
1008 /**
1009 * Constructor.
1010 * Sets signal readings belonging to the same radio source.
1011 *
1012 * @param qualityScores quality scores corresponding to each provided
1013 * sample. The larger the score value the better
1014 * the quality of the sample.
1015 * @param readings signal readings belonging to the same radio source.
1016 * @param initialPosition initial position to start the estimation of radio
1017 * source position.
1018 * @param initialTransmittedPowerdBm initial transmitted power to start the
1019 * estimation of radio source transmitted power
1020 * (expressed in dBm's).
1021 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
1022 * @throws IllegalArgumentException if readings are not valid, quality scores
1023 * is null, or length of quality scores is less than required minimum.
1024 */
1025 protected SequentialRobustMixedRadioSourceEstimator(
1026 final double[] qualityScores, final List<? extends ReadingLocated<P>> readings, final P initialPosition,
1027 final Double initialTransmittedPowerdBm, final double initialPathLossExponent) {
1028 this(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
1029 internalSetQualityScores(qualityScores);
1030 }
1031
1032 /**
1033 * Constructor.
1034 *
1035 * @param qualityScores quality scores corresponding to each provided
1036 * sample. The larger the score value the better
1037 * the quality of the sample.
1038 * @param initialPosition initial position to start the estimation of radio
1039 * source position.
1040 * @param initialTransmittedPowerdBm initial transmitted power to start the
1041 * estimation of radio source transmitted power
1042 * (expressed in dBm's).
1043 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
1044 * @throws IllegalArgumentException if quality scores is null, or length
1045 * of quality scores is less than required minimum.
1046 */
1047 protected SequentialRobustMixedRadioSourceEstimator(
1048 final double[] qualityScores, final P initialPosition, final Double initialTransmittedPowerdBm,
1049 final double initialPathLossExponent) {
1050 this(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
1051 internalSetQualityScores(qualityScores);
1052 }
1053
1054 /**
1055 * Constructor.
1056 *
1057 * @param qualityScores quality scores corresponding to each provided
1058 * sample. The larger the score value the better
1059 * the quality of the sample.
1060 * @param initialPosition initial position to start the estimation of radio
1061 * source position.
1062 * @param initialTransmittedPowerdBm initial transmitted power to start the
1063 * estimation of radio source transmitted power
1064 * (expressed in dBm's).
1065 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
1066 * @param listener listener in charge of attending events raised by this instance.
1067 * @throws IllegalArgumentException if quality scores is null, or length
1068 * of quality scores is less than required minimum.
1069 */
1070 protected SequentialRobustMixedRadioSourceEstimator(
1071 final double[] qualityScores, final P initialPosition, final Double initialTransmittedPowerdBm,
1072 final double initialPathLossExponent,
1073 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
1074 this(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
1075 internalSetQualityScores(qualityScores);
1076 }
1077
1078 /**
1079 * Constructors.
1080 * Sets signal readings belonging to the same radio source.
1081 *
1082 * @param qualityScores quality scores corresponding to each provided
1083 * sample. The larger the score value the better
1084 * the quality of the sample.
1085 * @param readings signal readings belonging to the same radio source.
1086 * @param initialPosition initial position to start the estimation of radio
1087 * source position.
1088 * @param initialTransmittedPowerdBm initial transmitted power to start the
1089 * estimation of radio source transmitted power
1090 * (expressed in dBm's).
1091 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
1092 * @param listener listener in charge of attending events raised by this instance.
1093 * @throws IllegalArgumentException if readings are not valid, quality scores
1094 * is null, or length of quality scores is less than required minimum.
1095 */
1096 protected SequentialRobustMixedRadioSourceEstimator(
1097 final double[] qualityScores, final List<? extends ReadingLocated<P>> readings, final P initialPosition,
1098 final Double initialTransmittedPowerdBm, final double initialPathLossExponent,
1099 final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener) {
1100 this(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
1101 internalSetQualityScores(qualityScores);
1102 }
1103
1104 /**
1105 * Indicates whether estimator is locked during estimation.
1106 *
1107 * @return true if estimator is locked, false otherwise.
1108 */
1109 public boolean isLocked() {
1110 return locked;
1111 }
1112
1113 /**
1114 * Returns amount of progress variation before notifying a progress change during
1115 * estimation.
1116 *
1117 * @return amount of progress variation before notifying a progress change during
1118 * estimation.
1119 */
1120 public float getProgressDelta() {
1121 return progressDelta;
1122 }
1123
1124 /**
1125 * Sets amount of progress variation before notifying a progress change during
1126 * estimation.
1127 *
1128 * @param progressDelta amount of progress variation before notifying a progress
1129 * change during estimation.
1130 * @throws IllegalArgumentException if progress delta is less than zero or greater than 1.
1131 * @throws LockedException if this estimator is locked.
1132 */
1133 public void setProgressDelta(final float progressDelta) throws LockedException {
1134 if (isLocked()) {
1135 throw new LockedException();
1136 }
1137 if (progressDelta < MIN_PROGRESS_DELTA || progressDelta > MAX_PROGRESS_DELTA) {
1138 throw new IllegalArgumentException();
1139 }
1140 this.progressDelta = progressDelta;
1141 }
1142
1143 /**
1144 * Gets robust method used for robust position estimation using ranging data.
1145 *
1146 * @return robust method used for robust position estimation.
1147 */
1148 public RobustEstimatorMethod getRangingRobustMethod() {
1149 return rangingRobustMethod;
1150 }
1151
1152 /**
1153 * Sets robust method used for robust position estimation using ranging data.
1154 *
1155 * @param rangingRobustMethod robust method used for robust position estimation.
1156 * @throws LockedException if estimator is locked.
1157 */
1158 public void setRangingRobustMethod(final RobustEstimatorMethod rangingRobustMethod) throws LockedException {
1159 if (isLocked()) {
1160 throw new LockedException();
1161 }
1162 this.rangingRobustMethod = rangingRobustMethod;
1163 }
1164
1165 /**
1166 * Gets robust method used for path-loss exponent and transmitted power estimation
1167 * using RSSI data.
1168 *
1169 * @return robust method used for path-loss exponent and transmitted power
1170 * estimation.
1171 */
1172 public RobustEstimatorMethod getRssiRobustMethod() {
1173 return rssiRobustMethod;
1174 }
1175
1176 /**
1177 * Sets robust method used for path-loss exponent and transmitted power estimation
1178 * using RSSI data.
1179 *
1180 * @param rssiRobustMethod robust method used for path-loss exponent and transmitted
1181 * power estimation.
1182 * @throws LockedException if estimator is locked.
1183 */
1184 public void setRssiRobustMethod(final RobustEstimatorMethod rssiRobustMethod) throws LockedException {
1185 if (isLocked()) {
1186 throw new LockedException();
1187 }
1188 this.rssiRobustMethod = rssiRobustMethod;
1189 }
1190
1191 /**
1192 * Gets size of subsets to be checked during ranging robust estimation.
1193 *
1194 * @return size of subsets to be checked during ranging robust estimation.
1195 */
1196 public int getRangingPreliminarySubsetSize() {
1197 return rangingPreliminarySubsetSize;
1198 }
1199
1200 /**
1201 * Sets size of subsets to be checked during ranging robust estimation.
1202 *
1203 * @param rangingPreliminarySubsetSize size of subsets to be checked during
1204 * ranging robust estimation.
1205 * @throws LockedException if estimator is locked.
1206 * @throws IllegalArgumentException if provided value is less than {@link #getMinReadings()}.
1207 */
1208 public void setRangingPreliminarySubsetSize(final int rangingPreliminarySubsetSize) throws LockedException {
1209 if (isLocked()) {
1210 throw new LockedException();
1211 }
1212 if (rangingPreliminarySubsetSize < getMinReadings()) {
1213 throw new IllegalArgumentException();
1214 }
1215
1216 this.rangingPreliminarySubsetSize = rangingPreliminarySubsetSize;
1217 }
1218
1219 /**
1220 * Gets size of subsets to be checked during RSSI robust estimation.
1221 *
1222 * @return size of subsets to be checked during RSSI robust estimation.
1223 */
1224 public int getRssiPreliminarySubsetSize() {
1225 return rssiPreliminarySubsetSize;
1226 }
1227
1228 /**
1229 * Sets size of subsets to be checked during RSSI robust estimation.
1230 *
1231 * @param rssiPreliminarySubsetSize size of subsets to be checked during
1232 * RSSI robust estimation.
1233 * @throws LockedException if estimator is locked.
1234 * @throws IllegalArgumentException if provided value is less than {@link #getMinReadings()}.
1235 */
1236 public void setRssiPreliminarySubsetSize(final int rssiPreliminarySubsetSize) throws LockedException {
1237 if (isLocked()) {
1238 throw new LockedException();
1239 }
1240 if (rssiPreliminarySubsetSize < getMinReadings()) {
1241 throw new IllegalArgumentException();
1242 }
1243
1244 this.rssiPreliminarySubsetSize = rssiPreliminarySubsetSize;
1245 }
1246
1247 /**
1248 * Gets threshold to determine when samples are inliers or not, used during robust
1249 * position estimation.
1250 * If not defined, default threshold will be used.
1251 *
1252 * @return threshold for ranging estimation or null.
1253 */
1254 public Double getRangingThreshold() {
1255 return rangingThreshold;
1256 }
1257
1258 /**
1259 * Sets threshold to determine when samples are inliers or not, used during robust
1260 * position estimation.
1261 * If not defined, default threshold will be used.
1262 *
1263 * @param rangingThreshold threshold for ranging estimation or null.
1264 * @throws LockedException if estimator is locked.
1265 */
1266 public void setRangingThreshold(final Double rangingThreshold) throws LockedException {
1267 if (isLocked()) {
1268 throw new LockedException();
1269 }
1270 this.rangingThreshold = rangingThreshold;
1271 }
1272
1273 /**
1274 * Gets threshold to determine when samples are inliers or not, used during robust
1275 * path-loss exponent and transmitted power estimation.
1276 * If not defined, default threshold will be used.
1277 *
1278 * @return threshold for RSSI estimation or null.
1279 */
1280 public Double getRssiThreshold() {
1281 return rssiThreshold;
1282 }
1283
1284 /**
1285 * Sets threshold to determine when samples are inliers or not, used during robust
1286 * path-loss exponent and transmitted power estimation.
1287 * If not defined, default threshold will be used.
1288 *
1289 * @param rssiThreshold threshold for RSSI estimation or null.
1290 * @throws LockedException if estimator is locked.
1291 */
1292 public void setRssiThreshold(final Double rssiThreshold) throws LockedException {
1293 if (isLocked()) {
1294 throw new LockedException();
1295 }
1296 this.rssiThreshold = rssiThreshold;
1297 }
1298
1299 /**
1300 * Returns amount of confidence expressed as a value between 0.0 and 1.0
1301 * (which is equivalent to 100%) for robust position estimation. The amount of
1302 * confidence indicates the probability that the estimated result is correct.
1303 * Usually this value will be close to 1.0, but not exactly 1.0.
1304 *
1305 * @return amount of confidence for robust position estimation as a value
1306 * between 0.0 and 1.0.
1307 */
1308 public double getRangingConfidence() {
1309 return rangingConfidence;
1310 }
1311
1312 /**
1313 * Sets amount of confidence expressed as a value between 0.0 and 1.0 (which is
1314 * equivalent to 100%) for robust position estimation. The amount of confidence
1315 * indicates the probability that the estimated result is correct. Usually this
1316 * value will be close to 1.0, but not exactly 1.0.
1317 *
1318 * @param rangingConfidence confidence to be set for robust position estimation
1319 * as a value between 0.0 and 1.0.
1320 * @throws IllegalArgumentException if provided value is not between 0.0 and 1.0.
1321 * @throws LockedException if estimator is locked.
1322 */
1323 public void setRangingConfidence(final double rangingConfidence) throws LockedException {
1324 if (isLocked()) {
1325 throw new LockedException();
1326 }
1327 if (rangingConfidence < MIN_CONFIDENCE || rangingConfidence > MAX_CONFIDENCE) {
1328 throw new IllegalArgumentException();
1329 }
1330 this.rangingConfidence = rangingConfidence;
1331 }
1332
1333 /**
1334 * Returns amount of confidence expressed as a value between 0.0 and 1.0
1335 * (which is equivalent to 100%) for path-loss exponent and transmitted power
1336 * estimation. The amount of confidence indicates the probability that the
1337 * estimated result is correct.
1338 * Usually this value will be close to 1.0, but not exactly 1.0.
1339 *
1340 * @return amount of confidence for robust path-loss exponent and transmitted power
1341 * estimation as a value between 0.0 and 1.0.
1342 */
1343 public double getRssiConfidence() {
1344 return rssiConfidence;
1345 }
1346
1347 /**
1348 * Sets amount of confidence expressed as a value between 0.0 and 1.0
1349 * (which is equivalent to 100%) for path-loss exponent and transmitted power
1350 * estimation. The amount of confidence indicates the probability that the
1351 * estimated result is correct. Usually this value will be close to 10.0, but
1352 * not exactly 1.0.
1353 *
1354 * @param rssiConfidence confidence to be set for robust path-loss exponent and
1355 * transmitted power estimation as a value between 0.0 and
1356 * 1.0.
1357 * @throws IllegalArgumentException if provided value is not between 0.0 and 1.0.
1358 * @throws LockedException if estimator is locked.
1359 */
1360 public void setRssiConfidence(final double rssiConfidence) throws LockedException {
1361 if (isLocked()) {
1362 throw new LockedException();
1363 }
1364 if (rssiConfidence < MIN_CONFIDENCE || rssiConfidence > MAX_CONFIDENCE) {
1365 throw new IllegalArgumentException();
1366 }
1367 this.rssiConfidence = rssiConfidence;
1368 }
1369
1370 /**
1371 * Returns maximum allowed number of iterations for robust position estimation. If
1372 * maximum allowed number of iterations is achieved without converging to a result
1373 * when calling estimate(), a RobustEstimatorException will be raised.
1374 *
1375 * @return maximum allowed number of iterations for position estimation.
1376 */
1377 public int getRangingMaxIterations() {
1378 return rangingMaxIterations;
1379 }
1380
1381 /**
1382 * Sets maximum allowed number of iterations for robust position estimation. When
1383 * the maximum number of iterations is exceeded, an approximate result might be
1384 * available for retrieval.
1385 *
1386 * @param rangingMaxIterations maximum allowed number of iterations to be set
1387 * for position estimation.
1388 * @throws IllegalArgumentException if provided value is less than 1.
1389 * @throws LockedException if this estimator is locked.
1390 */
1391 public void setRangingMaxIterations(final int rangingMaxIterations) throws LockedException {
1392 if (isLocked()) {
1393 throw new LockedException();
1394 }
1395 if (rangingMaxIterations < MIN_ITERATIONS) {
1396 throw new IllegalArgumentException();
1397 }
1398 this.rangingMaxIterations = rangingMaxIterations;
1399 }
1400
1401 /**
1402 * Returns maximum allowed number of iterations for robust path-loss exponent and
1403 * transmitted power estimation. If maximum allowed number of iterations is achieved
1404 * without converging to a result when calling estimate(), a RobustEstimatorException
1405 * will be raised.
1406 *
1407 * @return maximum allowed number of iterations for path-loss exponent and transmitted
1408 * power estimation.
1409 */
1410 public int getRssiMaxIterations() {
1411 return rssiMaxIterations;
1412 }
1413
1414 /**
1415 * Sets maximum allowed number of iterations for robust path-loss exponent and
1416 * transmitted power estimation. When the maximum number of iterations is exceeded,
1417 * an approximate result might be available for retrieval.
1418 *
1419 * @param rssiMaxIterations maximum allowed number of iterations to be set for
1420 * path-loss exponent and transmitted power estimation.
1421 * @throws IllegalArgumentException if provided value is less than 1.
1422 * @throws LockedException if this estimator is locked.
1423 */
1424 public void setRssiMaxIterations(final int rssiMaxIterations) throws LockedException {
1425 if (isLocked()) {
1426 throw new LockedException();
1427 }
1428 if (rssiMaxIterations < MIN_ITERATIONS) {
1429 throw new IllegalArgumentException();
1430 }
1431 this.rssiMaxIterations = rssiMaxIterations;
1432 }
1433
1434 /**
1435 * Indicates whether result must be refined using a non-linear solver over found inliers.
1436 *
1437 * @return true to refine result, false to simply use result found by robust estimator
1438 * without further refining.
1439 */
1440 public boolean isResultRefined() {
1441 return refineResult;
1442 }
1443
1444 /**
1445 * Specifies whether result must be refined using a non-linear solver over found inliers.
1446 *
1447 * @param refineResult true to refine result, false to simply use result found by robust
1448 * estimator without further refining.
1449 * @throws LockedException if estimator is locked.
1450 */
1451 public void setResultRefined(final boolean refineResult) throws LockedException {
1452 if (isLocked()) {
1453 throw new LockedException();
1454 }
1455 this.refineResult = refineResult;
1456 }
1457
1458 /**
1459 * Indicates whether covariance must be kept after refining result.
1460 * This setting is only taken into account if result is refined.
1461 *
1462 * @return true if covariance must be kept after refining result, false otherwise.
1463 */
1464 public boolean isCovarianceKept() {
1465 return keepCovariance;
1466 }
1467
1468 /**
1469 * Specifies whether covariance must be kept after refining result.
1470 * This setting is only taken into account if result is refined.
1471 *
1472 * @param keepCovariance true if covariance must be kept after refining result,
1473 * false otherwise.
1474 * @throws LockedException if estimator is locked.
1475 */
1476 public void setCovarianceKept(final boolean keepCovariance) throws LockedException {
1477 if (isLocked()) {
1478 throw new LockedException();
1479 }
1480 this.keepCovariance = keepCovariance;
1481 }
1482
1483 /**
1484 * Gets signal readings belonging to the same radio source.
1485 *
1486 * @return signal readings belonging to the same radio source.
1487 */
1488 public List<ReadingLocated<P>> getReadings() {
1489 //noinspection unchecked
1490 return (List<ReadingLocated<P>>) readings;
1491 }
1492
1493 /**
1494 * Sets signal readings belonging to the same radio source.
1495 *
1496 * @param readings signal readings belonging to the same
1497 * radio source.
1498 * @throws LockedException if estimator is locked.
1499 * @throws IllegalArgumentException if readings are not valid.
1500 */
1501 public void setReadings(final List<? extends ReadingLocated<P>> readings) throws LockedException {
1502 if (isLocked()) {
1503 throw new LockedException();
1504 }
1505
1506 internalSetReadings(readings);
1507 }
1508
1509 /**
1510 * Gets listener in charge of attending events raised by this instance.
1511 *
1512 * @return listener in charge of attending events raised by this instance.
1513 */
1514 public SequentialRobustMixedRadioSourceEstimatorListener<S, P> getListener() {
1515 return listener;
1516 }
1517
1518 /**
1519 * Sets listener in charge of attending events raised by this instance.
1520 *
1521 * @param listener listener in charge of attending events raised by this
1522 * instance.
1523 * @throws LockedException if estimator is locked.
1524 */
1525 public void setListener(final SequentialRobustMixedRadioSourceEstimatorListener<S, P> listener)
1526 throws LockedException {
1527 if (isLocked()) {
1528 throw new LockedException();
1529 }
1530
1531 this.listener = listener;
1532 }
1533
1534 /**
1535 * Returns quality scores corresponding to each pair of
1536 * positions and distances (i.e. sample).
1537 * The larger the score value the better the quality of the sample.
1538 * This implementation always returns null.
1539 * Subclasses using quality scores must implement proper behavior.
1540 *
1541 * @return quality scores corresponding to each sample.
1542 */
1543 public double[] getQualityScores() {
1544 return qualityScores;
1545 }
1546
1547 /**
1548 * Sets quality scores corresponding to each pair of positions and
1549 * distances (i.e. sample).
1550 * The larger the score value the better the quality of the sample.
1551 * This implementation makes no action.
1552 * Subclasses using quality scores must implement proper behaviour.
1553 *
1554 * @param qualityScores quality scores corresponding to each pair of
1555 * matched points.
1556 * @throws IllegalArgumentException if provided quality scores length
1557 * is smaller than minimum required samples.
1558 * @throws LockedException if robust solver is locked because an
1559 * estimation is already in progress.
1560 */
1561 public void setQualityScores(final double[] qualityScores) throws LockedException {
1562 if (isLocked()) {
1563 throw new LockedException();
1564 }
1565 internalSetQualityScores(qualityScores);
1566 }
1567
1568 /**
1569 * Gets initial transmitted power to start the estimation of radio source
1570 * transmitted power (expressed in dBm's).
1571 * If not defined, average value of received power readings will be used.
1572 *
1573 * @return initial transmitted power to start the estimation of radio source
1574 * transmitted power.
1575 */
1576 public Double getInitialTransmittedPowerdBm() {
1577 return initialTransmittedPowerdBm;
1578 }
1579
1580 /**
1581 * Sets initial transmitted power to start the estimation of radio source
1582 * transmitted power (expressed in dBm's).
1583 * If not defined, average value of received power readings will be used.
1584 *
1585 * @param initialTransmittedPowerdBm initial transmitted power to start the
1586 * estimation of radio source transmitted
1587 * power.
1588 * @throws LockedException if estimator is locked.
1589 */
1590 public void setInitialTransmittedPowerdBm(final Double initialTransmittedPowerdBm) throws LockedException {
1591 if (isLocked()) {
1592 throw new LockedException();
1593 }
1594 this.initialTransmittedPowerdBm = initialTransmittedPowerdBm;
1595 }
1596
1597 /**
1598 * Gets initial transmitted power to start the estimation of radio source
1599 * transmitted power (expressed in mW).
1600 * If not defined, average value of received power readings will be used.
1601 *
1602 * @return initial transmitted power to start the estimation of radio source
1603 * transmitted power.
1604 */
1605 public Double getInitialTransmittedPower() {
1606 return initialTransmittedPowerdBm != null ? Utils.dBmToPower(initialTransmittedPowerdBm) : null;
1607 }
1608
1609 /**
1610 * Sets initial transmitted power to start the estimation of radio source
1611 * transmitted power (expressed in mW).
1612 * If not defined, average value of received power readings will be used.
1613 *
1614 * @param initialTransmittedPower initial transmitted power to start the
1615 * estimation of radio source transmitted power.
1616 * @throws LockedException if estimator is locked.
1617 * @throws IllegalArgumentException if provided value is negative.
1618 */
1619 public void setInitialTransmittedPower(final Double initialTransmittedPower) throws LockedException {
1620 if (isLocked()) {
1621 throw new LockedException();
1622 }
1623 if (initialTransmittedPower != null) {
1624 if (initialTransmittedPower < 0.0) {
1625 throw new IllegalArgumentException();
1626 }
1627 initialTransmittedPowerdBm = Utils.powerTodBm(initialTransmittedPower);
1628 } else {
1629 initialTransmittedPowerdBm = null;
1630 }
1631 }
1632
1633 /**
1634 * Gets initial position to start the estimation of radio source position.
1635 * If not defined, centroid of provided fingerprints will be used.
1636 *
1637 * @return initial position to start the estimation of radio source position.
1638 */
1639 public P getInitialPosition() {
1640 return initialPosition;
1641 }
1642
1643 /**
1644 * Sets initial position to start the estimation of radio source position.
1645 * If not defined, centroid of provided fingerprints will be used.
1646 *
1647 * @param initialPosition initial position to start the estimation of radio
1648 * source position.
1649 * @throws LockedException if estimator is locked.
1650 */
1651 public void setInitialPosition(final P initialPosition) throws LockedException {
1652 if (isLocked()) {
1653 throw new LockedException();
1654 }
1655 this.initialPosition = initialPosition;
1656 }
1657
1658 /**
1659 * Gets initial exponent typically used on free space for path loss propagation
1660 * in terms of distance.
1661 * On different environments path loss exponent might have different value:
1662 * - Free space: 2.0
1663 * - Urban Area: 2.7 to 3.5
1664 * - Suburban Area: 3 to 5
1665 * - Indoor (line-of-sight): 1.6 to 1.8
1666 * <p>
1667 * If path loss exponent estimation is enabled, estimation will start at this
1668 * value and will converge to the most appropriate value.
1669 * If path loss exponent estimation is disabled, this value will be assumed
1670 * to be exact and the estimated path loss exponent will be equal to this
1671 * value.
1672 *
1673 * @return initial path loss exponent.
1674 */
1675 public double getInitialPathLossExponent() {
1676 return initialPathLossExponent;
1677 }
1678
1679 /**
1680 * Sets initial exponent typically used on free space for path loss propagation
1681 * in terms of distance.
1682 * On different environments path loss exponent might have different value:
1683 * - Free space: 2.0
1684 * - Urban Area: 2.7 to 3.5
1685 * - Suburban Area: 3 to 5
1686 * - Indoor (line-of-sight): 1.6 to 1.8
1687 * <p>
1688 * If path loss exponent estimation is enabled, estimation will start at this
1689 * value and will converge to the most appropriate value.
1690 * If path loss exponent estimation is disabled, this value will be assumed
1691 * to be exact and the estimated path loss exponent will be equal to this
1692 * value.
1693 *
1694 * @param initialPathLossExponent initial path loss exponent.
1695 * @throws LockedException if estimator is locked.
1696 */
1697 public void setInitialPathLossExponent(final double initialPathLossExponent) throws LockedException {
1698 if (isLocked()) {
1699 throw new LockedException();
1700 }
1701 this.initialPathLossExponent = initialPathLossExponent;
1702 }
1703
1704 /**
1705 * Indicates whether transmitted power estimation is enabled or not.
1706 *
1707 * @return true if transmitted power estimation is enabled, false otherwise.
1708 */
1709 public boolean isTransmittedPowerEstimationEnabled() {
1710 return transmittedPowerEstimationEnabled;
1711 }
1712
1713 /**
1714 * Specifies whether transmitted power estimation is enabled or not.
1715 *
1716 * @param transmittedPowerEstimationEnabled true if transmitted power estimation is enabled,
1717 * false otherwise.
1718 * @throws LockedException if estimator is locked.
1719 */
1720 public void setTransmittedPowerEstimationEnabled(final boolean transmittedPowerEstimationEnabled)
1721 throws LockedException {
1722 if (isLocked()) {
1723 throw new LockedException();
1724 }
1725 this.transmittedPowerEstimationEnabled = transmittedPowerEstimationEnabled;
1726 }
1727
1728 /**
1729 * Indicates whether path loss estimation is enabled or not.
1730 *
1731 * @return true if path loss estimation is enabled, false otherwise.
1732 */
1733 public boolean isPathLossEstimationEnabled() {
1734 return pathLossEstimationEnabled;
1735 }
1736
1737 /**
1738 * Specifies whether path loss estimation is enabled or not.
1739 *
1740 * @param pathLossEstimationEnabled true if path loss estimation is enabled,
1741 * false otherwise.
1742 * @throws LockedException if estimator is locked.
1743 */
1744 public void setPathLossEstimationEnabled(final boolean pathLossEstimationEnabled) throws LockedException {
1745 if (isLocked()) {
1746 throw new LockedException();
1747 }
1748 this.pathLossEstimationEnabled = pathLossEstimationEnabled;
1749 }
1750
1751 /**
1752 * Indicates whether position covariances of readings must be taken into account to increase
1753 * the amount of standard deviation of each ranging measure by the amount of position standard
1754 * deviation assuming that both measures are statistically independent.
1755 *
1756 * @return true to take into account reading position covariances, false otherwise.
1757 */
1758 public boolean getUseReadingPositionCovariance() {
1759 return useReadingPositionCovariances;
1760 }
1761
1762 /**
1763 * Specifies whether position covariances of readings must be taken into account to increase
1764 * the amount of standard deviation of each ranging measure by the amount of position standard
1765 * deviation assuming that both measures are statistically independent.
1766 *
1767 * @param useReadingPositionCovariances true to take into account reading position covariances, false
1768 * otherwise.
1769 * @throws LockedException if estimator is locked.
1770 */
1771 public void setUseReadingPositionCovariances(final boolean useReadingPositionCovariances) throws LockedException {
1772 if (isLocked()) {
1773 throw new LockedException();
1774 }
1775 this.useReadingPositionCovariances = useReadingPositionCovariances;
1776 }
1777
1778 /**
1779 * Indicates whether an homogeneous ranging linear solver is used to estimate preliminary
1780 * positions.
1781 *
1782 * @return true if homogeneous ranging linear solver is used, false if an inhomogeneous ranging linear
1783 * one is used instead.
1784 */
1785 public boolean isHomogeneousRangingLinearSolverUsed() {
1786 return useHomogeneousRangingLinearSolver;
1787 }
1788
1789 /**
1790 * Specifies whether an homogeneous ranging linear solver is used to estimate preliminary
1791 * positions.
1792 *
1793 * @param useHomogeneousRangingLinearSolver true if homogeneous ranging linear solver is used, false
1794 * if an inhomogeneous ranging linear one is used instead.
1795 * @throws LockedException if estimator is locked.
1796 */
1797 public void setHomogeneousRangingLinearSolverUsed(final boolean useHomogeneousRangingLinearSolver)
1798 throws LockedException {
1799 if (isLocked()) {
1800 throw new LockedException();
1801 }
1802
1803 this.useHomogeneousRangingLinearSolver = useHomogeneousRangingLinearSolver;
1804 }
1805
1806
1807 /**
1808 * Gets covariance for estimated position and power.
1809 * Matrix contains information in the following order:
1810 * Top-left sub-matrix contains covariance of position,
1811 * then follows transmitted power variance, and finally
1812 * the last element contains path-loss exponent variance.
1813 * This is only available when result has been refined and covariance is kept.
1814 *
1815 * @return covariance for estimated position and power.
1816 */
1817 public Matrix getCovariance() {
1818 return covariance;
1819 }
1820
1821 /**
1822 * Gets estimated position covariance.
1823 * Size of this matrix will depend on the number of dimensions
1824 * of estimated position (either 2 or 3).
1825 * This is only available when result has been refined and covariance is kept.
1826 *
1827 * @return estimated position covariance.
1828 */
1829 public Matrix getEstimatedPositionCovariance() {
1830 return estimatedPositionCovariance;
1831 }
1832
1833 /**
1834 * Gets estimated position.
1835 *
1836 * @return estimated position.
1837 */
1838 public P getEstimatedPosition() {
1839 return estimatedPosition;
1840 }
1841
1842 /**
1843 * Indicates whether readings are valid or not.
1844 * Readings are considered valid when there are enough readings.
1845 *
1846 * @param readings readings to be validated.
1847 * @return true if readings are valid, false otherwise.
1848 */
1849 public boolean areValidReadings(final List<? extends ReadingLocated<P>> readings) {
1850 if (readings == null) {
1851 return false;
1852 }
1853
1854 checkReadings(readings);
1855
1856 // if enough ranging data is available, we check validity both for ranging and RSSI readings
1857 return ((!rssiPositionEnabled && numRangingReadings >= getMinRangingReadings()
1858 && numRssiReadings >= getMinRssiReadings())
1859 // if not enough ranging data is available, we check validity only for RSSI readings
1860 || (rssiPositionEnabled && numRssiReadings >= getMinRssiReadings())
1861 // if only position is enabled, then only check for ranging readings
1862 || (!transmittedPowerEstimationEnabled && !pathLossEstimationEnabled
1863 && numRangingReadings >= getMinRangingReadings()))
1864 // in both upper cases enough general readings must be available
1865 && readings.size() >= getMinReadings();
1866 }
1867
1868 /**
1869 * Indicates whether this instance is ready to start the estimation.
1870 *
1871 * @return true if this instance is ready, false otherwise.
1872 * @throws LockedException if estimator is locked
1873 */
1874 public boolean isReady() throws LockedException {
1875 checkReadings(readings);
1876
1877 buildRangingEstimatorIfNeeded();
1878 setupRangingEstimator();
1879
1880 if (transmittedPowerEstimationEnabled || pathLossEstimationEnabled) {
1881 buildRssiEstimatorIfNeeded();
1882 setupRssiEstimator();
1883 }
1884
1885 if (rssiPositionEnabled) {
1886 return rssiEstimator.isReady();
1887 } else {
1888 return rangingEstimator.isReady() && ((!transmittedPowerEstimationEnabled && !pathLossEstimationEnabled)
1889 || rssiEstimator.isReady());
1890 }
1891 }
1892
1893 /**
1894 * Gets minimum required number of ranging or ranging+rssi readings
1895 * required to start estimation.
1896 *
1897 * @return minimum required number of ranging or ranging+rssi readings.
1898 */
1899 public int getMinRangingReadings() {
1900 return getNumberOfDimensions() + 1;
1901 }
1902
1903 /**
1904 * Gets minimum required number of rssi or ranging+rssi readings
1905 * required to start estimation.
1906 *
1907 * @return minimum required number of rssi or ranging+rssi readings.
1908 */
1909 public int getMinRssiReadings() {
1910 return getMinReadings();
1911 }
1912
1913 /**
1914 * Gets minimum required number of readings to estimate
1915 * power, position and path-loss exponent.
1916 * This value depends on the number of parameters to
1917 * be estimated, but for position only, this is 3
1918 * readings for 2D, and 4 readings for 3D.
1919 *
1920 * @return minimum required number of readings.
1921 */
1922 public abstract int getMinReadings();
1923
1924 /**
1925 * Gets number of dimensions of position points.
1926 *
1927 * @return number of dimensions of position points.
1928 */
1929 public abstract int getNumberOfDimensions();
1930
1931 /**
1932 * Gets estimated transmitted power variance.
1933 * This is only available when result has been refined and covariance is kept.
1934 *
1935 * @return estimated transmitted power variance.
1936 */
1937 public Double getEstimatedTransmittedPowerVariance() {
1938 return estimatedTransmittedPowerVariance;
1939 }
1940
1941 /**
1942 * Gets estimated path loss exponent variance.
1943 * This is only available when result has been refined and covariance is kept.
1944 *
1945 * @return estimated path loss exponent variance.
1946 */
1947 public Double getEstimatedPathLossExponentVariance() {
1948 return estimatedPathLossExponentVariance;
1949 }
1950
1951 /**
1952 * Gets estimated transmitted power expressed in milli watts (mW) or null if
1953 * not available.
1954 *
1955 * @return estimated transmitted power expressed in milli watts or null.
1956 */
1957 public Double getEstimatedTransmittedPower() {
1958 return estimatedTransmittedPowerdBm != null ? Utils.dBmToPower(estimatedTransmittedPowerdBm) : null;
1959 }
1960
1961 /**
1962 * Gets estimated transmitted power expressed in dBm's or null if not available.
1963 *
1964 * @return estimated transmitted power expressed in dBm's or null.
1965 */
1966 public Double getEstimatedTransmittedPowerdBm() {
1967 return estimatedTransmittedPowerdBm;
1968 }
1969
1970 /**
1971 * Gets estimated exponent typically used on free space for path loss propagation in
1972 * terms of distance.
1973 * On different environments path loss exponent might have different values:
1974 * - Free space: 2.0
1975 * - Urban Area: 2.7 to 3.5
1976 * - Suburban Area: 3 to 5
1977 * - Indoor (line-of-sight): 1.6 to 1.8
1978 * If path loss exponent estimation is not enabled, this value will always be equal to
1979 * {@link RssiRadioSourceEstimator#DEFAULT_PATH_LOSS_EXPONENT}
1980 *
1981 * @return estimated path loss exponent.
1982 */
1983 public double getEstimatedPathLossExponent() {
1984 return estimatedPathLossExponent;
1985 }
1986
1987 /**
1988 * Robustly estimates position, transmitted power and path-loss exponent for a
1989 * radio source.
1990 *
1991 * @throws LockedException if instance is busy during estimation.
1992 * @throws NotReadyException if estimator is not ready.
1993 * @throws RobustEstimatorException if estimation fails for any reason
1994 * (i.e. numerical instability, no solution available, etc).
1995 */
1996 public void estimate() throws LockedException, NotReadyException, RobustEstimatorException {
1997 if (isLocked()) {
1998 throw new LockedException();
1999 }
2000 try {
2001 locked = true;
2002
2003 // when checking for readiness, inner estimators are created and setup
2004 if (!isReady()) {
2005 throw new NotReadyException();
2006 }
2007
2008 if (listener != null) {
2009 listener.onEstimateStart(this);
2010 }
2011
2012 // estimate position
2013 if (!rssiPositionEnabled) {
2014 rangingEstimator.setPreliminarySubsetSize(rangingPreliminarySubsetSize);
2015
2016 rangingEstimator.estimate();
2017
2018 estimatedPosition = rangingEstimator.getEstimatedPosition();
2019 estimatedPositionCovariance = rangingEstimator.getEstimatedPositionCovariance();
2020 inliersData = rangingEstimator.getInliersData();
2021 } else {
2022 estimatedPosition = null;
2023 }
2024
2025 // estimate transmitted power and/or path-loss if enabled
2026 if (transmittedPowerEstimationEnabled || pathLossEstimationEnabled || rssiPositionEnabled) {
2027 rssiEstimator.setPositionEstimationEnabled(rssiPositionEnabled);
2028 rssiEstimator.setInitialPosition(estimatedPosition);
2029 rssiEstimator.setPreliminarySubsetSize(rssiPreliminarySubsetSize);
2030
2031 rssiEstimator.estimate();
2032
2033 if (rssiPositionEnabled) {
2034 estimatedPosition = rssiEstimator.getEstimatedPosition();
2035 estimatedPositionCovariance = rssiEstimator.getEstimatedPositionCovariance();
2036 }
2037
2038 inliersData = rssiEstimator.getInliersData();
2039
2040 if (transmittedPowerEstimationEnabled) {
2041 // transmitted power estimation enabled
2042 estimatedTransmittedPowerdBm = rssiEstimator.getEstimatedTransmittedPowerdBm();
2043 estimatedTransmittedPowerVariance = rssiEstimator.getEstimatedTransmittedPowerVariance();
2044 } else {
2045 // transmitted power estimation disabled
2046 estimatedTransmittedPowerdBm = initialTransmittedPowerdBm;
2047 estimatedTransmittedPowerVariance = null;
2048 }
2049
2050 if (pathLossEstimationEnabled) {
2051 // path-loss exponent estimation enabled
2052 estimatedPathLossExponent = rssiEstimator.getEstimatedPathLossExponent();
2053 estimatedPathLossExponentVariance = rssiEstimator.getEstimatedPathLossExponentVariance();
2054 } else {
2055 // path-loss exponent estimation disabled
2056 estimatedPathLossExponent = initialPathLossExponent;
2057 estimatedPathLossExponentVariance = null;
2058 }
2059
2060 // build covariance matrix
2061 if (rssiPositionEnabled) {
2062 // if only RSSI estimation is done, we use directly the available estimated covariance
2063 covariance = rssiEstimator.getCovariance();
2064 } else {
2065 // if both ranging and RSSI data is used, we build covariance matrix by setting
2066 // position covariance estimated by ranging estimator into top-left corner, and then
2067 // adding covariance terms related to path loss exponent and transmitted power
2068 final var rssiCov = rssiEstimator.getCovariance();
2069 if (estimatedPositionCovariance != null && rssiCov != null) {
2070 final var dims = getNumberOfDimensions();
2071 var n = dims;
2072 if (transmittedPowerEstimationEnabled) {
2073 n++;
2074 }
2075 if (pathLossEstimationEnabled) {
2076 n++;
2077 }
2078
2079 final var dimsMinus1 = dims - 1;
2080 final var nMinus1 = n - 1;
2081 covariance = new Matrix(n, n);
2082 covariance.setSubmatrix(0, 0, dimsMinus1, dimsMinus1,
2083 estimatedPositionCovariance);
2084 covariance.setSubmatrix(dims, dims, nMinus1, nMinus1, rssiCov);
2085 } else {
2086 covariance = null;
2087 }
2088 }
2089 } else {
2090 covariance = estimatedPositionCovariance;
2091 estimatedTransmittedPowerdBm = initialTransmittedPowerdBm;
2092 estimatedTransmittedPowerVariance = null;
2093
2094 estimatedPathLossExponent = initialPathLossExponent;
2095 estimatedPathLossExponentVariance = null;
2096 }
2097
2098 if (listener != null) {
2099 listener.onEstimateEnd(this);
2100 }
2101 } catch (final AlgebraException e) {
2102 throw new RobustEstimatorException(e);
2103 } finally {
2104 locked = false;
2105 }
2106 }
2107
2108 /**
2109 * Gets data related to inliers found after estimation.
2110 *
2111 * @return data related to inliers found after estimation.
2112 */
2113 public InliersData getInliersData() {
2114 return inliersData;
2115 }
2116
2117 /**
2118 * Indicates whether position is estimated using RSSI data.
2119 * If enough ranging readings are available, this is false and position is estimated using ranging readings,
2120 * otherwise this is true and position is estimated using RSSI data in a less reliable way.
2121 *
2122 * @return true if position is estimated using RSSI data, false if position is estimated using ranging data.
2123 */
2124 public boolean isRssiPositionEnabled() {
2125 return rssiPositionEnabled;
2126 }
2127
2128 /**
2129 * Gets estimated located radio source.
2130 *
2131 * @param <S2> type of located radio source.
2132 * @return estimated located radio source.
2133 */
2134 public abstract <S2 extends RadioSourceLocated<P>> S2 getEstimatedRadioSource();
2135
2136 /**
2137 * Builds ranging estimator.
2138 */
2139 protected abstract void buildRangingEstimatorIfNeeded();
2140
2141 /**
2142 * Build RSSI estimator.
2143 *
2144 * @throws LockedException if estimator is locked.
2145 */
2146 protected abstract void buildRssiEstimatorIfNeeded() throws LockedException;
2147
2148 /**
2149 * Setups ranging estimator.
2150 *
2151 * @throws LockedException if estimator is locked.
2152 */
2153 protected void setupRangingEstimator() throws LockedException {
2154 if (readings != null && !rssiPositionEnabled) {
2155 // build ranging readings
2156 final var rangingReadings = new ArrayList<RangingReadingLocated<S, P>>();
2157 for (final var reading : readings) {
2158 if (reading instanceof RangingReadingLocated) {
2159 rangingReadings.add((RangingReadingLocated<S, P>) reading);
2160 } else if (reading instanceof RangingAndRssiReadingLocated) {
2161 rangingReadings.add(createRangingReading((RangingAndRssiReadingLocated<S, P>) reading));
2162 }
2163 }
2164 rangingEstimator.setReadings(rangingReadings);
2165
2166 if (qualityScores != null && !rangingReadings.isEmpty()) {
2167 // build quality scores
2168 final var numReadings = readings.size();
2169 final var newNumRangingReadings = rangingReadings.size();
2170 final var rangingQualityScores = new double[newNumRangingReadings];
2171 var pos = 0;
2172 for (var i = 0; i < numReadings; i++) {
2173 final var reading = readings.get(i);
2174 if (reading instanceof RangingReadingLocated || reading instanceof RangingAndRssiReadingLocated) {
2175 rangingQualityScores[pos] = qualityScores[i];
2176 pos++;
2177 }
2178 }
2179
2180 rangingEstimator.setQualityScores(rangingQualityScores);
2181 }
2182
2183 // enable RSSI position estimation only if not enough ranging readings are
2184 // available
2185 rssiPositionEnabled = rangingReadings.size() < rangingEstimator.getMinReadings();
2186 }
2187
2188 rangingEstimator.setProgressDelta(2.0f * progressDelta);
2189 rangingEstimator.setConfidence(rangingConfidence);
2190 rangingEstimator.setMaxIterations(rangingMaxIterations);
2191 rangingEstimator.setResultRefined(refineResult);
2192 rangingEstimator.setCovarianceKept(keepCovariance);
2193 rangingEstimator.setUseReadingPositionCovariances(useReadingPositionCovariances);
2194 rangingEstimator.setHomogeneousLinearSolverUsed(useHomogeneousRangingLinearSolver);
2195
2196 rangingEstimator.setInitialPosition(initialPosition);
2197
2198 rangingEstimator.setListener(new RobustRangingRadioSourceEstimatorListener<>() {
2199 @Override
2200 public void onEstimateStart(final RobustRangingRadioSourceEstimator<S, P> estimator) {
2201 // not used
2202 }
2203
2204 @Override
2205 public void onEstimateEnd(final RobustRangingRadioSourceEstimator<S, P> estimator) {
2206 // not used
2207 }
2208
2209 @Override
2210 public void onEstimateNextIteration(
2211 final RobustRangingRadioSourceEstimator<S, P> estimator, final int iteration) {
2212 // not used
2213 }
2214
2215 @Override
2216 public void onEstimateProgressChange(
2217 final RobustRangingRadioSourceEstimator<S, P> estimator, final float progress) {
2218 if (listener != null) {
2219 listener.onEstimateProgressChange(
2220 SequentialRobustMixedRadioSourceEstimator.this, 0.5f * progress);
2221 }
2222 }
2223 });
2224 }
2225
2226 /**
2227 * Setups RSSI estimator.
2228 *
2229 * @throws LockedException if estimator is locked.
2230 */
2231 protected void setupRssiEstimator() throws LockedException {
2232 if (readings != null) {
2233 rssiEstimator.setPositionEstimationEnabled(rssiPositionEnabled);
2234
2235 // build RSSI readings
2236 final var rssiReadings = new ArrayList<RssiReadingLocated<S, P>>();
2237 for (final var reading : readings) {
2238 if (reading instanceof RssiReadingLocated) {
2239 rssiReadings.add((RssiReadingLocated<S, P>) reading);
2240 } else if (reading instanceof RangingAndRssiReadingLocated) {
2241 rssiReadings.add(createRssiReading((RangingAndRssiReadingLocated<S, P>) reading));
2242 }
2243 }
2244 rssiEstimator.setReadings(rssiReadings);
2245
2246 if (qualityScores != null && !rssiReadings.isEmpty()) {
2247 // build quality scores
2248 final var numReadings = readings.size();
2249 final var newNumRssiReadings = rssiReadings.size();
2250 final var rssiQualityScores = new double[newNumRssiReadings];
2251 var pos = 0;
2252 for (var i = 0; i < numReadings; i++) {
2253 final var reading = readings.get(i);
2254 if (reading instanceof RssiReadingLocated || reading instanceof RangingAndRssiReadingLocated) {
2255 rssiQualityScores[pos] = qualityScores[i];
2256 pos++;
2257 }
2258 }
2259
2260 rssiEstimator.setQualityScores(rssiQualityScores);
2261 }
2262 }
2263
2264 rssiEstimator.setProgressDelta(2.0f * progressDelta);
2265 rssiEstimator.setConfidence(rssiConfidence);
2266 rssiEstimator.setMaxIterations(rssiMaxIterations);
2267 rssiEstimator.setResultRefined(refineResult);
2268 rssiEstimator.setCovarianceKept(keepCovariance);
2269
2270 // initial position is not set because position estimated from ranging measures
2271 // will be later used
2272 rssiEstimator.setInitialTransmittedPowerdBm(initialTransmittedPowerdBm);
2273 rssiEstimator.setInitialPathLossExponent(initialPathLossExponent);
2274
2275 rssiEstimator.setTransmittedPowerEstimationEnabled(transmittedPowerEstimationEnabled);
2276 rssiEstimator.setPathLossEstimationEnabled(pathLossEstimationEnabled);
2277
2278 rssiEstimator.setListener(new RobustRssiRadioSourceEstimatorListener<>() {
2279 @Override
2280 public void onEstimateStart(final RobustRssiRadioSourceEstimator<S, P> estimator) {
2281 // not used
2282 }
2283
2284 @Override
2285 public void onEstimateEnd(final RobustRssiRadioSourceEstimator<S, P> estimator) {
2286 // not used
2287 }
2288
2289 @Override
2290 public void onEstimateNextIteration(
2291 final RobustRssiRadioSourceEstimator<S, P> estimator, final int iteration) {
2292 // not used
2293 }
2294
2295 @Override
2296 public void onEstimateProgressChange(
2297 final RobustRssiRadioSourceEstimator<S, P> estimator, final float progress) {
2298 if (listener != null) {
2299 listener.onEstimateProgressChange(
2300 SequentialRobustMixedRadioSourceEstimator.this, 0.5f + 0.5f * progress);
2301 }
2302 }
2303 });
2304 }
2305
2306 /**
2307 * Internally sets signal readings belonging to the same radio source.
2308 *
2309 * @param readings signal readings belonging to the same radio source.
2310 * @throws IllegalArgumentException if readings are null, not enough readings
2311 * are available, or readings do not belong to the same access point.
2312 */
2313 private void internalSetReadings(final List<? extends ReadingLocated<P>> readings) {
2314 if (!areValidReadings(readings)) {
2315 throw new IllegalArgumentException();
2316 }
2317
2318 this.readings = readings;
2319 }
2320
2321 /**
2322 * Sets quality scores corresponding to each provided sample.
2323 * This method is used internally and does not check whether instance is
2324 * locked or not.
2325 *
2326 * @param qualityScores quality scores to be set.
2327 * @throws IllegalArgumentException if provided quality scores length
2328 * is smaller than required minimum.
2329 */
2330 private void internalSetQualityScores(final double[] qualityScores) {
2331 if (qualityScores == null || qualityScores.length < getMinReadings()) {
2332 throw new IllegalArgumentException();
2333 }
2334
2335 this.qualityScores = qualityScores;
2336 }
2337
2338 /**
2339 * Creates a ranging reading from a ranging and RSSI reading.
2340 *
2341 * @param reading input reading to convert from.
2342 * @return a ranging reading containing only the ranging data of input reading.
2343 */
2344 private RangingReadingLocated<S, P> createRangingReading(final RangingAndRssiReadingLocated<S, P> reading) {
2345 return new RangingReadingLocated<>(reading.getSource(), reading.getDistance(), reading.getPosition(),
2346 reading.getDistanceStandardDeviation(), reading.getPositionCovariance());
2347 }
2348
2349 /**
2350 * Creates an RSSI reading from a ranging and RSSI reading.
2351 *
2352 * @param reading input reading to convert from.
2353 * @return an RSSI reading containing only the RSSI data of input reading.
2354 */
2355 private RssiReadingLocated<S, P> createRssiReading(final RangingAndRssiReadingLocated<S, P> reading) {
2356 return new RssiReadingLocated<>(reading.getSource(), reading.getRssi(), reading.getPosition(),
2357 reading.getRssiStandardDeviation(), reading.getPositionCovariance());
2358 }
2359
2360 /**
2361 * Checks number of available ranging readings and number of available RSSI readings. Also determines
2362 * whether position must be estimated using ranging data or RSSI data.
2363 *
2364 * @param readings readings to be checked.
2365 */
2366 private void checkReadings(final List<? extends ReadingLocated<P>> readings) {
2367 numRangingReadings = numRssiReadings = 0;
2368
2369 if (readings == null) {
2370 return;
2371 }
2372
2373 for (final var reading : readings) {
2374 if (reading instanceof RangingReadingLocated) {
2375 numRangingReadings++;
2376
2377 } else if (reading instanceof RssiReadingLocated) {
2378 numRssiReadings++;
2379
2380 } else if (reading instanceof RangingAndRssiReadingLocated) {
2381 numRangingReadings++;
2382 numRssiReadings++;
2383 }
2384 }
2385
2386 rssiPositionEnabled = numRangingReadings < getMinRangingReadings();
2387 }
2388 }