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.geometry.Point2D;
19 import com.irurueta.navigation.LockedException;
20 import com.irurueta.navigation.NotReadyException;
21 import com.irurueta.navigation.indoor.RadioSource;
22 import com.irurueta.navigation.indoor.RssiReadingLocated;
23 import com.irurueta.numerical.robust.PROSACRobustEstimator;
24 import com.irurueta.numerical.robust.PROSACRobustEstimatorListener;
25 import com.irurueta.numerical.robust.RobustEstimator;
26 import com.irurueta.numerical.robust.RobustEstimatorException;
27 import com.irurueta.numerical.robust.RobustEstimatorMethod;
28
29 import java.util.List;
30
31 /**
32 * Robustly estimate 2D position, transmitted power and path-loss exponent of a radio source
33 * (e.g. Wi-Fi access point or bluetooth beacon), by discarding outliers using PROSAC
34 * algorithm and assuming that the radio source emits isotropically following the
35 * expression below:
36 * Pr = Pt*Gt*Gr*lambda^2 / (4*pi*d)^2,
37 * where Pr is the received power (expressed in mW),
38 * Gt is the Gain of the transmission antenna
39 * Gr is the Gain of the receiver antenna
40 * d is the distance between emitter and receiver
41 * and lambda is the wavelength and is equal to: lambda = c / f,
42 * where c is the speed of light
43 * and f is the carrier frequency of the radio signal.
44 * Because usually information about the antenna of the radio source cannot be
45 * retrieved (because many measurements are made on unknown devices where
46 * physical access is not possible), this implementation will estimate the
47 * equivalent transmitted power as: Pte = Pt * Gt * Gr.
48 * If RssiReadings contain RSSI standard deviations, those values will be used,
49 * otherwise it will be assumed an RSSI standard deviation of 1 dB.
50 * Implementations of this class should be able to detect and discard outliers in
51 * order to find the best solution.
52 * <p>
53 * IMPORTANT: When using this class estimation can be done using a
54 * combination of radio source position, transmitted power and path loss
55 * exponent. However enabling all three estimations usually achieves
56 * inaccurate results. When using this class, estimation must be of at least
57 * one parameter (position, transmitted power or path loss exponent) when
58 * initial values are provided for the other two, and at most it should consist
59 * of two parameters (either position and transmitted power, position and
60 * path loss exponent or transmitted power and path loss exponent), providing an
61 * initial value for the remaining parameter.
62 *
63 * @param <S> a {@link RadioSource} type.
64 */
65 @SuppressWarnings("Duplicates")
66 public class PROSACRobustRssiRadioSourceEstimator2D<S extends RadioSource> extends RobustRssiRadioSourceEstimator2D<S> {
67
68 /**
69 * Constant defining default threshold to determine whether samples are inliers or not.
70 */
71 public static final double DEFAULT_THRESHOLD = 0.1;
72
73 /**
74 * Minimum value that can be set as threshold.
75 * Threshold must be strictly greater than 0.0.
76 */
77 public static final double MIN_THRESHOLD = 0.0;
78
79 /**
80 * Indicates that by default inliers will only be computed but not kept.
81 */
82 public static final boolean DEFAULT_COMPUTE_AND_KEEP_INLIERS = false;
83
84 /**
85 * Indicates that by default residuals will only be computed but not kept.
86 */
87 public static final boolean DEFAULT_COMPUTE_AND_KEEP_RESIDUALS = false;
88
89 /**
90 * Threshold to determine whether samples are inliers or not when testing possible solutions.
91 * The threshold refers to the amount of error on distance between estimated position and
92 * distances provided for each sample.
93 */
94 private double threshold = DEFAULT_THRESHOLD;
95
96 /**
97 * Indicates whether inliers must be computed and kept.
98 */
99 private boolean computeAndKeepInliers = DEFAULT_COMPUTE_AND_KEEP_INLIERS;
100
101 /**
102 * Indicates whether residuals must be computed and kept.
103 */
104 private boolean computeAndKeepResiduals = DEFAULT_COMPUTE_AND_KEEP_RESIDUALS;
105
106 /**
107 * Quality scores corresponding to each provided sample.
108 * The larger the score value the better the quality of the sample.
109 */
110 private double[] qualityScores;
111
112 /**
113 * Constructor.
114 */
115 public PROSACRobustRssiRadioSourceEstimator2D() {
116 super();
117 }
118
119 /**
120 * Constructor.
121 * Sets signal readings belonging to the same radio source.
122 *
123 * @param readings signal readings belonging to the same radio source.
124 * @throws IllegalArgumentException if readings are not valid.
125 */
126 public PROSACRobustRssiRadioSourceEstimator2D(final List<? extends RssiReadingLocated<S, Point2D>> readings) {
127 super(readings);
128 }
129
130 /**
131 * Constructor.
132 *
133 * @param listener listener in charge of attending events raised by this instance.
134 */
135 public PROSACRobustRssiRadioSourceEstimator2D(final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
136 this.listener = listener;
137 }
138
139 /**
140 * Constructor.
141 * Sets signal readings belonging to the same radio source.
142 *
143 * @param readings signal readings belonging to the same radio source.
144 * @param listener listener in charge of attending events raised by this instance.
145 * @throws IllegalArgumentException if readings are not valid.
146 */
147 public PROSACRobustRssiRadioSourceEstimator2D(
148 final List<? extends RssiReadingLocated<S, Point2D>> readings,
149 final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
150 super(readings, listener);
151 }
152
153 /**
154 * Constructor.
155 * Sets signal readings belonging to the same radio source.
156 *
157 * @param readings signal readings belonging to the same radio source.
158 * @param initialPosition initial position to start the estimation of radio
159 * source position.
160 * @throws IllegalArgumentException if readings are not valid.
161 */
162 public PROSACRobustRssiRadioSourceEstimator2D(
163 final List<? extends RssiReadingLocated<S, Point2D>> readings, final Point2D initialPosition) {
164 super(readings, initialPosition);
165 }
166
167 /**
168 * Constructor.
169 *
170 * @param initialPosition initial position to start the estimation of radio
171 * source position.
172 */
173 public PROSACRobustRssiRadioSourceEstimator2D(final Point2D initialPosition) {
174 super(initialPosition);
175 }
176
177 /**
178 * Constructor.
179 *
180 * @param initialPosition initial position to start the estimation of radio
181 * source position.
182 * @param listener listener in charge of attending events raised by this instance.
183 */
184 public PROSACRobustRssiRadioSourceEstimator2D(
185 final Point2D initialPosition, final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
186 super(initialPosition, listener);
187 }
188
189 /**
190 * Constructor.
191 * Sets signal readings belonging to the same radio source.
192 *
193 * @param readings signal readings belonging to the same radio source.
194 * @param initialPosition initial position to start the estimation of radio
195 * source position.
196 * @param listener listener in charge of attending events raised by this instance.
197 * @throws IllegalArgumentException if readings are not valid.
198 */
199 public PROSACRobustRssiRadioSourceEstimator2D(
200 final List<? extends RssiReadingLocated<S, Point2D>> readings, final Point2D initialPosition,
201 final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
202 super(readings, initialPosition, listener);
203 }
204
205 /**
206 * Constructor.
207 *
208 * @param initialTransmittedPowerdBm initial transmitted power to start the
209 * estimation of radio source transmitted power
210 * (expressed in dBm's)
211 */
212 public PROSACRobustRssiRadioSourceEstimator2D(final Double initialTransmittedPowerdBm) {
213 super(initialTransmittedPowerdBm);
214 }
215
216 /**
217 * Constructor.
218 * Sets signal readings belonging to the same radio source.
219 *
220 * @param readings signal readings belonging to the same radio source.
221 * @param initialTransmittedPowerdBm initial transmitted power to start the
222 * estimation of radio source transmitted power
223 * (expressed in dBm's)
224 * @throws IllegalArgumentException if readings are not valid.
225 */
226 public PROSACRobustRssiRadioSourceEstimator2D(
227 final List<? extends RssiReadingLocated<S, Point2D>> readings, final Double initialTransmittedPowerdBm) {
228 super(readings, initialTransmittedPowerdBm);
229 }
230
231 /**
232 * Constructor.
233 *
234 * @param initialTransmittedPowerdBm initial transmitted power to start the
235 * estimation of radio source transmitted power
236 * (expressed in dBm's)
237 * @param listener listener in charge of attending events raised by this instance.
238 */
239 public PROSACRobustRssiRadioSourceEstimator2D(
240 final Double initialTransmittedPowerdBm,
241 final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
242 super(initialTransmittedPowerdBm, listener);
243 }
244
245 /**
246 * Constructor.
247 * Sets signal readings belonging to the same radio source.
248 *
249 * @param readings signal readings belonging to the same radio source.
250 * @param initialTransmittedPowerdBm initial transmitted power to start the
251 * estimation of radio source transmitted power
252 * (expressed in dBm's)
253 * @param listener listener in charge of attending events raised by this instance.
254 * @throws IllegalArgumentException if readings are not valid.
255 */
256 public PROSACRobustRssiRadioSourceEstimator2D(
257 final List<? extends RssiReadingLocated<S, Point2D>> readings, final Double initialTransmittedPowerdBm,
258 final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
259 super(readings, initialTransmittedPowerdBm, listener);
260 }
261
262 /**
263 * Constructor.
264 * Sets signal readings belonging to the same radio source.
265 *
266 * @param readings signal readings belonging to the same radio source.
267 * @param initialPosition initial position to start the estimation of radio
268 * source position.
269 * @param initialTransmittedPowerdBm initial transmitted power to start the
270 * estimation of radio source transmitted power
271 * (expressed in dBm's).
272 * @throws IllegalArgumentException if readings are not valid.
273 */
274 public PROSACRobustRssiRadioSourceEstimator2D(
275 final List<? extends RssiReadingLocated<S, Point2D>> readings, final Point2D initialPosition,
276 final Double initialTransmittedPowerdBm) {
277 super(readings, initialPosition, initialTransmittedPowerdBm);
278 }
279
280 /**
281 * Constructor.
282 *
283 * @param initialPosition initial position to start the estimation of radio
284 * source position.
285 * @param initialTransmittedPowerdBm initial transmitted power to start the
286 * estimation of radio source transmitted power
287 * (expressed in dBm's).
288 */
289 public PROSACRobustRssiRadioSourceEstimator2D(
290 final Point2D initialPosition, final Double initialTransmittedPowerdBm) {
291 super(initialPosition, initialTransmittedPowerdBm);
292 }
293
294 /**
295 * Constructor.
296 *
297 * @param initialPosition initial position to start the estimation of radio
298 * source position.
299 * @param initialTransmittedPowerdBm initial transmitted power to start the
300 * estimation of radio source transmitted power
301 * (expressed in dBm's).
302 * @param listener in charge of attending events raised by this instance.
303 */
304 public PROSACRobustRssiRadioSourceEstimator2D(
305 final Point2D initialPosition, final Double initialTransmittedPowerdBm,
306 final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
307 super(initialPosition, initialTransmittedPowerdBm, listener);
308 }
309
310 /**
311 * Constructor.
312 * Sets signal readings belonging to the same radio source.
313 *
314 * @param readings signal readings belonging to the same radio source.
315 * @param initialPosition initial position to start the estimation of radio
316 * source position.
317 * @param initialTransmittedPowerdBm initial transmitted power to start the
318 * estimation of radio source transmitted power
319 * (expressed in dBm's).
320 * @param listener listener in charge of attending events raised by this instance.
321 * @throws IllegalArgumentException if readings are not valid.
322 */
323 public PROSACRobustRssiRadioSourceEstimator2D(
324 final List<? extends RssiReadingLocated<S, Point2D>> readings, final Point2D initialPosition,
325 final Double initialTransmittedPowerdBm,
326 final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
327 super(readings, initialPosition, initialTransmittedPowerdBm, listener);
328 }
329
330 /**
331 * Constructor.
332 * Sets signal readings belonging to the same radio source.
333 *
334 * @param readings signal readings belonging to the same radio source.
335 * @param initialPosition initial position to start the estimation of radio
336 * source position.
337 * @param initialTransmittedPowerdBm initial transmitted power to start the
338 * estimation of radio source transmitted power
339 * (expressed in dBm's).
340 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
341 * @throws IllegalArgumentException if readings are not valid.
342 */
343 public PROSACRobustRssiRadioSourceEstimator2D(
344 final List<? extends RssiReadingLocated<S, Point2D>> readings, final Point2D initialPosition,
345 final Double initialTransmittedPowerdBm, final double initialPathLossExponent) {
346 super(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
347 }
348
349 /**
350 * Constructor.
351 *
352 * @param initialPosition initial position to start the estimation of radio
353 * source position.
354 * @param initialTransmittedPowerdBm initial transmitted power to start the
355 * estimation of radio source transmitted power
356 * (expressed in dBm's).
357 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
358 */
359 public PROSACRobustRssiRadioSourceEstimator2D(
360 final Point2D initialPosition, final Double initialTransmittedPowerdBm,
361 final double initialPathLossExponent) {
362 super(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
363 }
364
365 /**
366 * Constructor.
367 *
368 * @param initialPosition initial position to start the estimation of radio
369 * source position.
370 * @param initialTransmittedPowerdBm initial transmitted power to start the
371 * estimation of radio source transmitted power
372 * (expressed in dBm's).
373 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
374 * @param listener listener in charge of attending events raised by this instance.
375 */
376 public PROSACRobustRssiRadioSourceEstimator2D(
377 final Point2D initialPosition, final Double initialTransmittedPowerdBm,
378 final double initialPathLossExponent, final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
379 super(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
380 }
381
382 /**
383 * Constructor.
384 * Sets signal readings belonging to the same radio source.
385 *
386 * @param readings signal readings belonging to the same radio source.
387 * @param initialPosition initial position to start the estimation of radio
388 * source position.
389 * @param initialTransmittedPowerdBm initial transmitted power to start the
390 * estimation of radio source transmitted power
391 * (expressed in dBm's).
392 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
393 * @param listener listener in charge of attending events raised by this instance.
394 * @throws IllegalArgumentException if readings are not valid.
395 */
396 public PROSACRobustRssiRadioSourceEstimator2D(
397 final List<? extends RssiReadingLocated<S, Point2D>> readings, final Point2D initialPosition,
398 final Double initialTransmittedPowerdBm, final double initialPathLossExponent,
399 final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
400 super(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
401 }
402
403 /**
404 * Constructor.
405 *
406 * @param qualityScores quality scores corresponding to each provided
407 * sample. The larger the score value the better
408 * the quality of the sample.
409 * @throws IllegalArgumentException if quality scores is null, or length
410 * of quality scores is less than required minimum.
411 */
412 public PROSACRobustRssiRadioSourceEstimator2D(final double[] qualityScores) {
413 super();
414 internalSetQualityScores(qualityScores);
415 }
416
417 /**
418 * Constructor.
419 * Sets signal readings belonging to the same radio source.
420 *
421 * @param qualityScores quality scores corresponding to each provided
422 * sample. The larger the score value the better
423 * the quality of the sample.
424 * @param readings signal readings belonging to the same radio source.
425 * @throws IllegalArgumentException if readings are not valid, quality scores
426 * is null, or length of quality scores is less than required minimum.
427 */
428 public PROSACRobustRssiRadioSourceEstimator2D(
429 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point2D>> readings) {
430 super(readings);
431 internalSetQualityScores(qualityScores);
432 }
433
434 /**
435 * Constructor.
436 *
437 * @param qualityScores quality scores corresponding to each provided
438 * sample. The larger the score value the better
439 * the quality of the sample.
440 * @param listener listener in charge of attending events raised by this instance.
441 * @throws IllegalArgumentException if quality scores is null, or length
442 * of quality scores is less than required minimum.
443 */
444 public PROSACRobustRssiRadioSourceEstimator2D(
445 final double[] qualityScores, final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
446 super(listener);
447 internalSetQualityScores(qualityScores);
448 }
449
450 /**
451 * Constructor.
452 * Sets signal readings belonging to the same radio source.
453 *
454 * @param qualityScores quality scores corresponding to each provided
455 * sample. The larger the score value the better
456 * the quality of the sample.
457 * @param readings signal readings belonging to the same radio source.
458 * @param listener listener in charge of attending events raised by this instance.
459 * @throws IllegalArgumentException if readings are not valid, quality scores
460 * is null, or length of quality scores is less than required minimum.
461 */
462 public PROSACRobustRssiRadioSourceEstimator2D(
463 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point2D>> readings,
464 final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
465 super(readings, listener);
466 internalSetQualityScores(qualityScores);
467 }
468
469 /**
470 * Constructor.
471 * Sets signal readings belonging to the same radio source.
472 *
473 * @param qualityScores quality scores corresponding to each provided
474 * sample. The larger the score value the better
475 * the quality of the sample.
476 * @param readings signal readings belonging to the same radio source.
477 * @param initialPosition initial position to start the estimation of radio
478 * source position.
479 * @throws IllegalArgumentException if readings are not valid, quality scores
480 * is null, or length of quality scores is less than required minimum.
481 */
482 public PROSACRobustRssiRadioSourceEstimator2D(
483 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point2D>> readings,
484 final Point2D initialPosition) {
485 super(readings, initialPosition);
486 internalSetQualityScores(qualityScores);
487 }
488
489 /**
490 * Constructor.
491 *
492 * @param qualityScores quality scores corresponding to each provided
493 * sample. The larger the score value the better
494 * the quality of the sample.
495 * @param initialPosition initial position to start the estimation of radio
496 * source position.
497 */
498 public PROSACRobustRssiRadioSourceEstimator2D(final double[] qualityScores, final Point2D initialPosition) {
499 super(initialPosition);
500 internalSetQualityScores(qualityScores);
501 }
502
503 /**
504 * Constructor.
505 *
506 * @param qualityScores quality scores corresponding to each provided
507 * sample. The larger the score value the better
508 * the quality of the sample.
509 * @param initialPosition initial position to start the estimation of radio
510 * source position.
511 * @param listener listener in charge of attending events raised by this instance.
512 * @throws IllegalArgumentException if quality scores is null, or length
513 * of quality scores is less than required minimum.
514 */
515 public PROSACRobustRssiRadioSourceEstimator2D(
516 final double[] qualityScores, final Point2D initialPosition,
517 final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
518 super(initialPosition, listener);
519 internalSetQualityScores(qualityScores);
520 }
521
522 /**
523 * Constructor.
524 * Sets signal readings belonging to the same radio source.
525 *
526 * @param qualityScores quality scores corresponding to each provided
527 * sample. The larger the score value the better
528 * the quality of the sample.
529 * @param readings signal readings belonging to the same radio source.
530 * @param initialPosition initial position to start the estimation of radio
531 * source position.
532 * @param listener listener in charge of attending events raised by this instance.
533 * @throws IllegalArgumentException if readings are not valid, quality scores
534 * is null, or length of quality scores is less than required minimum.
535 */
536 public PROSACRobustRssiRadioSourceEstimator2D(
537 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point2D>> readings,
538 final Point2D initialPosition, final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
539 super(readings, initialPosition, listener);
540 internalSetQualityScores(qualityScores);
541 }
542
543 /**
544 * Constructor.
545 *
546 * @param qualityScores quality scores corresponding to each provided
547 * sample. The larger the score value the better
548 * the quality of the sample.
549 * @param initialTransmittedPowerdBm initial transmitted power to start the
550 * estimation of radio source transmitted power
551 * (expressed in dBm's)
552 * @throws IllegalArgumentException if quality scores is null, or length
553 * of quality scores is less than required minimum.
554 */
555 public PROSACRobustRssiRadioSourceEstimator2D(
556 final double[] qualityScores, final Double initialTransmittedPowerdBm) {
557 super(initialTransmittedPowerdBm);
558 internalSetQualityScores(qualityScores);
559 }
560
561 /**
562 * Constructor.
563 * Sets signal readings belonging to the same radio source.
564 *
565 * @param qualityScores quality scores corresponding to each provided
566 * sample. The larger the score value the better
567 * the quality of the sample.
568 * @param readings signal readings belonging to the same radio source.
569 * @param initialTransmittedPowerdBm initial transmitted power to start the
570 * estimation of radio source transmitted power
571 * (expressed in dBm's)
572 * @throws IllegalArgumentException if readings are not valid, quality scores
573 * is null, or length of quality scores is less than required minimum.
574 */
575 public PROSACRobustRssiRadioSourceEstimator2D(
576 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point2D>> readings,
577 final Double initialTransmittedPowerdBm) {
578 super(readings, initialTransmittedPowerdBm);
579 internalSetQualityScores(qualityScores);
580 }
581
582 /**
583 * Constructor.
584 *
585 * @param qualityScores quality scores corresponding to each provided
586 * sample. The larger the score value the better
587 * the quality of the sample.
588 * @param initialTransmittedPowerdBm initial transmitted power to start the
589 * estimation of radio source transmitted power
590 * (expressed in dBm's)
591 * @param listener listener in charge of attending events raised by this instance.
592 * @throws IllegalArgumentException if quality scores is null, or length
593 * of quality scores is less than required minimum.
594 */
595 public PROSACRobustRssiRadioSourceEstimator2D(
596 final double[] qualityScores, final Double initialTransmittedPowerdBm,
597 final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
598 super(initialTransmittedPowerdBm, listener);
599 internalSetQualityScores(qualityScores);
600 }
601
602 /**
603 * Constructor.
604 * Sets signal readings belonging to the same radio source.
605 *
606 * @param qualityScores quality scores corresponding to each provided
607 * sample. The larger the score value the better
608 * the quality of the sample.
609 * @param readings signal readings belonging to the same radio source.
610 * @param initialTransmittedPowerdBm initial transmitted power to start the
611 * estimation of radio source transmitted power
612 * (expressed in dBm's)
613 * @param listener listener in charge of attending events raised by this instance.
614 * @throws IllegalArgumentException if readings are not valid, quality scores
615 * is null, or length of quality scores is less than required minimum.
616 */
617 public PROSACRobustRssiRadioSourceEstimator2D(
618 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point2D>> readings,
619 final Double initialTransmittedPowerdBm,
620 final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
621 super(readings, initialTransmittedPowerdBm, listener);
622 internalSetQualityScores(qualityScores);
623 }
624
625 /**
626 * Constructor.
627 * Sets signal readings belonging to the same radio source.
628 *
629 * @param qualityScores quality scores corresponding to each provided
630 * sample. The larger the score value the better
631 * the quality of the sample.
632 * @param readings signal readings belonging to the same radio source.
633 * @param initialPosition initial position to start the estimation of radio
634 * source position.
635 * @param initialTransmittedPowerdBm initial transmitted power to start the
636 * estimation of radio source transmitted power
637 * (expressed in dBm's).
638 * @throws IllegalArgumentException if readings are not valid, quality scores
639 * is null, or length of quality scores is less than required minimum.
640 */
641 public PROSACRobustRssiRadioSourceEstimator2D(
642 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point2D>> readings,
643 final Point2D initialPosition, final Double initialTransmittedPowerdBm) {
644 super(readings, initialPosition, initialTransmittedPowerdBm);
645 internalSetQualityScores(qualityScores);
646 }
647
648 /**
649 * Constructor.
650 *
651 * @param qualityScores quality scores corresponding to each provided
652 * sample. The larger the score value the better
653 * the quality of the sample.
654 * @param initialPosition initial position to start the estimation of radio
655 * source position.
656 * @param initialTransmittedPowerdBm initial transmitted power to start the
657 * estimation of radio source transmitted power
658 * (expressed in dBm's).
659 * @throws IllegalArgumentException if quality scores is null, or length
660 * of quality scores is less than required minimum.
661 */
662 public PROSACRobustRssiRadioSourceEstimator2D(
663 final double[] qualityScores, final Point2D initialPosition, final Double initialTransmittedPowerdBm) {
664 super(initialPosition, initialTransmittedPowerdBm);
665 internalSetQualityScores(qualityScores);
666 }
667
668 /**
669 * Constructor.
670 *
671 * @param qualityScores quality scores corresponding to each provided
672 * sample. The larger the score value the better
673 * the quality of the sample.
674 * @param initialPosition initial position to start the estimation of radio
675 * source position.
676 * @param initialTransmittedPowerdBm initial transmitted power to start the
677 * estimation of radio source transmitted power
678 * (expressed in dBm's).
679 * @param listener in charge of attending events raised by this instance.
680 * @throws IllegalArgumentException if quality scores is null, or length
681 * of quality scores is less than required minimum.
682 */
683 public PROSACRobustRssiRadioSourceEstimator2D(
684 final double[] qualityScores, final Point2D initialPosition, final Double initialTransmittedPowerdBm,
685 final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
686 super(initialPosition, initialTransmittedPowerdBm, listener);
687 internalSetQualityScores(qualityScores);
688 }
689
690 /**
691 * Constructor.
692 * Sets signal readings belonging to the same radio source.
693 *
694 * @param qualityScores quality scores corresponding to each provided
695 * sample. The larger the score value the better
696 * the quality of the sample.
697 * @param readings signal readings belonging to the same radio source.
698 * @param initialPosition initial position to start the estimation of radio
699 * source position.
700 * @param initialTransmittedPowerdBm initial transmitted power to start the
701 * estimation of radio source transmitted power
702 * (expressed in dBm's).
703 * @param listener listener in charge of attending events raised by this instance.
704 * @throws IllegalArgumentException if readings are not valid, quality scores
705 * is null, or length of quality scores is less than required minimum.
706 */
707 public PROSACRobustRssiRadioSourceEstimator2D(
708 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point2D>> readings,
709 final Point2D initialPosition, final Double initialTransmittedPowerdBm,
710 final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
711 super(readings, initialPosition, initialTransmittedPowerdBm, listener);
712 internalSetQualityScores(qualityScores);
713 }
714
715 /**
716 * Constructor.
717 * Sets signal readings belonging to the same radio source.
718 *
719 * @param qualityScores quality scores corresponding to each provided
720 * sample. The larger the score value the better
721 * the quality of the sample.
722 * @param readings signal readings belonging to the same radio source.
723 * @param initialPosition initial position to start the estimation of radio
724 * source position.
725 * @param initialTransmittedPowerdBm initial transmitted power to start the
726 * estimation of radio source transmitted power
727 * (expressed in dBm's).
728 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
729 * @throws IllegalArgumentException if readings are not valid, quality scores
730 * is null, or length of quality scores is less than required minimum.
731 */
732 public PROSACRobustRssiRadioSourceEstimator2D(
733 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point2D>> readings,
734 final Point2D initialPosition, final Double initialTransmittedPowerdBm,
735 final double initialPathLossExponent) {
736 super(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
737 internalSetQualityScores(qualityScores);
738 }
739
740 /**
741 * Constructor.
742 *
743 * @param qualityScores quality scores corresponding to each provided
744 * sample. The larger the score value the better
745 * the quality of the sample.
746 * @param initialPosition initial position to start the estimation of radio
747 * source position.
748 * @param initialTransmittedPowerdBm initial transmitted power to start the
749 * estimation of radio source transmitted power
750 * (expressed in dBm's).
751 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
752 */
753 public PROSACRobustRssiRadioSourceEstimator2D(
754 final double[] qualityScores, final Point2D initialPosition, final Double initialTransmittedPowerdBm,
755 final double initialPathLossExponent) {
756 super(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
757 internalSetQualityScores(qualityScores);
758 }
759
760 /**
761 * Constructor.
762 *
763 * @param qualityScores quality scores corresponding to each provided
764 * sample. The larger the score value the better
765 * the quality of the sample.
766 * @param initialPosition initial position to start the estimation of radio
767 * source position.
768 * @param initialTransmittedPowerdBm initial transmitted power to start the
769 * estimation of radio source transmitted power
770 * (expressed in dBm's).
771 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
772 * @param listener listener in charge of attending events raised by this instance.
773 */
774 public PROSACRobustRssiRadioSourceEstimator2D(
775 final double[] qualityScores, final Point2D initialPosition, final Double initialTransmittedPowerdBm,
776 final double initialPathLossExponent, final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
777 super(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
778 internalSetQualityScores(qualityScores);
779 }
780
781 /**
782 * Constructor.
783 * Sets signal readings belonging to the same radio source.
784 *
785 * @param qualityScores quality scores corresponding to each provided
786 * sample. The larger the score value the better
787 * the quality of the sample.
788 * @param readings signal readings belonging to the same radio source.
789 * @param initialPosition initial position to start the estimation of radio
790 * source position.
791 * @param initialTransmittedPowerdBm initial transmitted power to start the
792 * estimation of radio source transmitted power
793 * (expressed in dBm's).
794 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
795 * @param listener listener in charge of attending events raised by this instance.
796 * @throws IllegalArgumentException if readings are not valid, quality scores
797 * is null, or length of quality scores is less than required minimum.
798 */
799 public PROSACRobustRssiRadioSourceEstimator2D(
800 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point2D>> readings,
801 final Point2D initialPosition, final Double initialTransmittedPowerdBm,
802 final double initialPathLossExponent, final RobustRssiRadioSourceEstimatorListener<S, Point2D> listener) {
803 super(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
804 internalSetQualityScores(qualityScores);
805 }
806
807 /**
808 * Gets threshold to determine whether samples are inliers or not when testing possible solutions.
809 * The threshold refers to the amount of error on distance between estimated position and distances
810 * provided for each sample.
811 *
812 * @return threshold to determine whether samples are inliers or not.
813 */
814 public double getThreshold() {
815 return threshold;
816 }
817
818 /**
819 * Sets threshold to determine whether samples are inliers or not when testing possible solutions.
820 * The threshold refers to the amount of error on distance between estimated position and distances
821 * provided for each sample.
822 *
823 * @param threshold threshold to determine whether samples are inliers or not.
824 * @throws IllegalArgumentException if provided value is equal or less than zero.
825 * @throws LockedException if this solver is locked.
826 */
827 public void setThreshold(final double threshold) throws LockedException {
828 if (isLocked()) {
829 throw new LockedException();
830 }
831 if (threshold <= MIN_THRESHOLD) {
832 throw new IllegalArgumentException();
833 }
834 this.threshold = threshold;
835 }
836
837 /**
838 * Returns quality scores corresponding to each pair of
839 * positions and distances (i.e. sample).
840 * The larger the score value the better the quality of the sample.
841 * This implementation always returns null.
842 * Subclasses using quality scores must implement proper behavior.
843 *
844 * @return quality scores corresponding to each sample.
845 */
846 @Override
847 public double[] getQualityScores() {
848 return qualityScores;
849 }
850
851 /**
852 * Sets quality scores corresponding to each pair of positions and
853 * distances (i.e. sample).
854 * The larger the score value the better the quality of the sample.
855 * This implementation makes no action.
856 * Subclasses using quality scores must implement proper behaviour.
857 *
858 * @param qualityScores quality scores corresponding to each pair of
859 * matched points.
860 * @throws IllegalArgumentException if provided quality scores length
861 * is smaller than minimum required samples.
862 * @throws LockedException if robust solver is locked because an
863 * estimation is already in progress.
864 */
865 @Override
866 public void setQualityScores(final double[] qualityScores) throws LockedException {
867 if (isLocked()) {
868 throw new LockedException();
869 }
870 internalSetQualityScores(qualityScores);
871 }
872
873 /**
874 * Indicates whether solver is ready to find a solution.
875 *
876 * @return true if solver is ready, false otherwise.
877 */
878 @Override
879 public boolean isReady() {
880 return super.isReady() && qualityScores != null && qualityScores.length == readings.size();
881 }
882
883 /**
884 * Indicates whether inliers must be computed and kept.
885 *
886 * @return true if inliers must be computed and kept, false if inliers
887 * only need to be computed but not kept.
888 */
889 public boolean isComputeAndKeepInliersEnabled() {
890 return computeAndKeepInliers;
891 }
892
893 /**
894 * Specifies whether inliers must be computed and kept.
895 *
896 * @param computeAndKeepInliers true if inliers must be computed and kept,
897 * false if inliers only need to be computed but not kept.
898 * @throws LockedException if this solver is locked.
899 */
900 public void setComputeAndKeepInliersEnabled(boolean computeAndKeepInliers) throws LockedException {
901 if (isLocked()) {
902 throw new LockedException();
903 }
904 this.computeAndKeepInliers = computeAndKeepInliers;
905 }
906
907 /**
908 * Indicates whether residuals must be computed and kept.
909 *
910 * @return true if residuals must be computed and kept, false if residuals
911 * only need to be computed but not kept.
912 */
913 public boolean isComputeAndKeepResidualsEnabled() {
914 return computeAndKeepResiduals;
915 }
916
917 /**
918 * Specifies whether residuals must be computed and kept.
919 *
920 * @param computeAndKeepResiduals true if residuals must be computed and kept,
921 * false if residuals only need to be computed but not kept.
922 * @throws LockedException if this solver is locked.
923 */
924 public void setComputeAndKeepResidualsEnabled(final boolean computeAndKeepResiduals) throws LockedException {
925 if (isLocked()) {
926 throw new LockedException();
927 }
928 this.computeAndKeepResiduals = computeAndKeepResiduals;
929 }
930
931 /**
932 * Robustly estimates position, transmitted power and path-loss exponent for a
933 * radio source.
934 *
935 * @throws LockedException if instance is busy during estimation.
936 * @throws NotReadyException if estimator is not ready.
937 * @throws RobustEstimatorException if estimation fails for any reason
938 * (i.e. numerical instability, no solution available, etc).
939 */
940 @Override
941 public void estimate() throws LockedException, NotReadyException, RobustEstimatorException {
942 if (isLocked()) {
943 throw new LockedException();
944 }
945 if (!isReady()) {
946 throw new NotReadyException();
947 }
948
949 final var innerEstimator = new PROSACRobustEstimator<>(new PROSACRobustEstimatorListener<Solution<Point2D>>() {
950
951 @Override
952 public double[] getQualityScores() {
953 return qualityScores;
954 }
955
956 @Override
957 public double getThreshold() {
958 return threshold;
959 }
960
961 @Override
962 public int getTotalSamples() {
963 return readings.size();
964 }
965
966 @Override
967 public int getSubsetSize() {
968 return Math.max(preliminarySubsetSize, getMinReadings());
969 }
970
971 @Override
972 public void estimatePreliminarSolutions(
973 final int[] samplesIndices, final List<Solution<Point2D>> solutions) {
974 solvePreliminarySolutions(samplesIndices, solutions);
975 }
976
977 @Override
978 public double computeResidual(final Solution<Point2D> currentEstimation, final int i) {
979 return residual(currentEstimation, i);
980 }
981
982 @Override
983 public boolean isReady() {
984 return PROSACRobustRssiRadioSourceEstimator2D.this.isReady();
985 }
986
987 @Override
988 public void onEstimateStart(final RobustEstimator<Solution<Point2D>> estimator) {
989 // no action needed
990 }
991
992 @Override
993 public void onEstimateEnd(final RobustEstimator<Solution<Point2D>> estimator) {
994 // no action needed
995 }
996
997 @Override
998 public void onEstimateNextIteration(
999 final RobustEstimator<Solution<Point2D>> estimator, final int iteration) {
1000 if (listener != null) {
1001 listener.onEstimateNextIteration(
1002 PROSACRobustRssiRadioSourceEstimator2D.this, iteration);
1003 }
1004 }
1005
1006 @Override
1007 public void onEstimateProgressChange(
1008 final RobustEstimator<Solution<Point2D>> estimator, final float progress) {
1009 if (listener != null) {
1010 listener.onEstimateProgressChange(
1011 PROSACRobustRssiRadioSourceEstimator2D.this, progress);
1012 }
1013 }
1014 });
1015
1016 try {
1017 locked = true;
1018
1019 if (listener != null) {
1020 listener.onEstimateStart(this);
1021 }
1022
1023 inliersData = null;
1024 innerEstimator.setComputeAndKeepInliersEnabled(computeAndKeepInliers || refineResult);
1025 innerEstimator.setComputeAndKeepResidualsEnabled(computeAndKeepResiduals || refineResult);
1026 innerEstimator.setConfidence(confidence);
1027 innerEstimator.setMaxIterations(maxIterations);
1028 innerEstimator.setProgressDelta(progressDelta);
1029 final var result = innerEstimator.estimate();
1030 inliersData = innerEstimator.getInliersData();
1031 attemptRefine(result);
1032
1033 if (listener != null) {
1034 listener.onEstimateEnd(this);
1035 }
1036
1037 } catch (final com.irurueta.numerical.LockedException e) {
1038 throw new LockedException(e);
1039 } catch (final com.irurueta.numerical.NotReadyException e) {
1040 throw new NotReadyException(e);
1041 } finally {
1042 locked = false;
1043 }
1044 }
1045
1046 /**
1047 * Returns method being used for robust estimation.
1048 *
1049 * @return method being used for robust estimation.
1050 */
1051 @Override
1052 public RobustEstimatorMethod getMethod() {
1053 return RobustEstimatorMethod.PROSAC;
1054 }
1055
1056 /**
1057 * Sets quality scores corresponding to each provided sample.
1058 * This method is used internally and does not check whether instance is
1059 * locked or not.
1060 *
1061 * @param qualityScores quality scores to be set.
1062 * @throws IllegalArgumentException if provided quality scores length
1063 * is smaller than required minimum.
1064 */
1065 private void internalSetQualityScores(final double[] qualityScores) {
1066 if (qualityScores == null || qualityScores.length < getMinReadings()) {
1067 throw new IllegalArgumentException();
1068 }
1069
1070 this.qualityScores = qualityScores;
1071 }
1072 }