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.Point3D;
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 3D 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 access point 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 access points 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 PROSACRobustRssiRadioSourceEstimator3D<S extends RadioSource> extends RobustRssiRadioSourceEstimator3D<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 PROSACRobustRssiRadioSourceEstimator3D() {
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 PROSACRobustRssiRadioSourceEstimator3D(final List<? extends RssiReadingLocated<S, Point3D>> 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 PROSACRobustRssiRadioSourceEstimator3D(final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(
148 final List<? extends RssiReadingLocated<S, Point3D>> readings,
149 final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(
163 final List<? extends RssiReadingLocated<S, Point3D>> readings, final Point3D 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 PROSACRobustRssiRadioSourceEstimator3D(final Point3D 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 PROSACRobustRssiRadioSourceEstimator3D(
185 final Point3D initialPosition, final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(
200 final List<? extends RssiReadingLocated<S, Point3D>> readings, final Point3D initialPosition,
201 final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(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 PROSACRobustRssiRadioSourceEstimator3D(
227 final List<? extends RssiReadingLocated<S, Point3D>> 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 PROSACRobustRssiRadioSourceEstimator3D(
240 final Double initialTransmittedPowerdBm,
241 final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(
257 final List<? extends RssiReadingLocated<S, Point3D>> readings, final Double initialTransmittedPowerdBm,
258 final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(
275 final List<? extends RssiReadingLocated<S, Point3D>> readings, final Point3D 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 PROSACRobustRssiRadioSourceEstimator3D(
290 final Point3D 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 PROSACRobustRssiRadioSourceEstimator3D(
305 final Point3D initialPosition, final Double initialTransmittedPowerdBm,
306 final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(
324 final List<? extends RssiReadingLocated<S, Point3D>> readings, final Point3D initialPosition,
325 final Double initialTransmittedPowerdBm,
326 final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(
344 final List<? extends RssiReadingLocated<S, Point3D>> readings, final Point3D 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 PROSACRobustRssiRadioSourceEstimator3D(
360 final Point3D 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 PROSACRobustRssiRadioSourceEstimator3D(
377 final Point3D initialPosition, final Double initialTransmittedPowerdBm,
378 final double initialPathLossExponent, final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(
397 final List<? extends RssiReadingLocated<S, Point3D>> readings, final Point3D initialPosition,
398 final Double initialTransmittedPowerdBm, final double initialPathLossExponent,
399 final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(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 PROSACRobustRssiRadioSourceEstimator3D(
429 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point3D>> 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 PROSACRobustRssiRadioSourceEstimator3D(
445 final double[] qualityScores, final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(
463 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point3D>> readings,
464 final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(
483 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point3D>> readings,
484 final Point3D 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 PROSACRobustRssiRadioSourceEstimator3D(final double[] qualityScores, final Point3D 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 PROSACRobustRssiRadioSourceEstimator3D(
516 final double[] qualityScores, final Point3D initialPosition,
517 final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(
537 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point3D>> readings,
538 final Point3D initialPosition, final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 access point 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 PROSACRobustRssiRadioSourceEstimator3D(
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 Wi-Fi 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 PROSACRobustRssiRadioSourceEstimator3D(
576 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point3D>> 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 PROSACRobustRssiRadioSourceEstimator3D(
596 final double[] qualityScores, final Double initialTransmittedPowerdBm,
597 final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(
618 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point3D>> readings,
619 final Double initialTransmittedPowerdBm,
620 final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(
642 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point3D>> readings,
643 final Point3D 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 PROSACRobustRssiRadioSourceEstimator3D(
663 final double[] qualityScores, final Point3D 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 PROSACRobustRssiRadioSourceEstimator3D(
684 final double[] qualityScores, final Point3D initialPosition, final Double initialTransmittedPowerdBm,
685 final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 Wi-Fi 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 PROSACRobustRssiRadioSourceEstimator3D(
708 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point3D>> readings,
709 final Point3D initialPosition, final Double initialTransmittedPowerdBm,
710 final RobustRssiRadioSourceEstimatorListener<S, Point3D> 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 PROSACRobustRssiRadioSourceEstimator3D(
733 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point3D>> readings,
734 final Point3D initialPosition, Double initialTransmittedPowerdBm, final double initialPathLossExponent) {
735 super(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
736 internalSetQualityScores(qualityScores);
737 }
738
739 /**
740 * Constructor.
741 *
742 * @param qualityScores quality scores corresponding to each provided
743 * sample. The larger the score value the better
744 * the quality of the sample.
745 * @param initialPosition initial position to start the estimation of radio
746 * source position.
747 * @param initialTransmittedPowerdBm initial transmitted power to start the
748 * estimation of radio source transmitted power
749 * (expressed in dBm's).
750 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
751 */
752 public PROSACRobustRssiRadioSourceEstimator3D(
753 final double[] qualityScores, final Point3D initialPosition, final Double initialTransmittedPowerdBm,
754 final double initialPathLossExponent) {
755 super(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
756 internalSetQualityScores(qualityScores);
757 }
758
759 /**
760 * Constructor.
761 *
762 * @param qualityScores quality scores corresponding to each provided
763 * sample. The larger the score value the better
764 * the quality of the sample.
765 * @param initialPosition initial position to start the estimation of radio
766 * source position.
767 * @param initialTransmittedPowerdBm initial transmitted power to start the
768 * estimation of radio source transmitted power
769 * (expressed in dBm's).
770 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
771 * @param listener listener in charge of attending events raised by this instance.
772 */
773 public PROSACRobustRssiRadioSourceEstimator3D(
774 final double[] qualityScores, final Point3D initialPosition, final Double initialTransmittedPowerdBm,
775 final double initialPathLossExponent, final RobustRssiRadioSourceEstimatorListener<S, Point3D> listener) {
776 super(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
777 internalSetQualityScores(qualityScores);
778 }
779
780 /**
781 * Constructor.
782 * Sets Wi-Fi signal readings belonging to the same radio source.
783 *
784 * @param qualityScores quality scores corresponding to each provided
785 * sample. The larger the score value the better
786 * the quality of the sample.
787 * @param readings Wi-Fi signal readings belonging to the same radio source.
788 * @param initialPosition initial position to start the estimation of radio
789 * source position.
790 * @param initialTransmittedPowerdBm initial transmitted power to start the
791 * estimation of radio source transmitted power
792 * (expressed in dBm's).
793 * @param initialPathLossExponent initial path loss exponent. A typical value is 2.0.
794 * @param listener listener in charge of attending events raised by this instance.
795 * @throws IllegalArgumentException if readings are not valid, quality scores
796 * is null, or length of quality scores is less than required minimum.
797 */
798 public PROSACRobustRssiRadioSourceEstimator3D(
799 final double[] qualityScores, final List<? extends RssiReadingLocated<S, Point3D>> readings,
800 final Point3D initialPosition, final Double initialTransmittedPowerdBm,
801 final double initialPathLossExponent, final RobustRssiRadioSourceEstimatorListener<S, Point3D> listener) {
802 super(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
803 internalSetQualityScores(qualityScores);
804 }
805
806 /**
807 * Gets threshold to determine whether samples are inliers or not when testing possible solutions.
808 * The threshold refers to the amount of error on distance between estimated position and distances
809 * provided for each sample.
810 *
811 * @return threshold to determine whether samples are inliers or not.
812 */
813 public double getThreshold() {
814 return threshold;
815 }
816
817 /**
818 * Sets threshold to determine whether samples are inliers or not when testing possible solutions.
819 * The threshold refers to the amount of error on distance between estimated position and distances
820 * provided for each sample.
821 *
822 * @param threshold threshold to determine whether samples are inliers or not.
823 * @throws IllegalArgumentException if provided value is equal or less than zero.
824 * @throws LockedException if this solver is locked.
825 */
826 public void setThreshold(final double threshold) throws LockedException {
827 if (isLocked()) {
828 throw new LockedException();
829 }
830 if (threshold <= MIN_THRESHOLD) {
831 throw new IllegalArgumentException();
832 }
833 this.threshold = threshold;
834 }
835
836 /**
837 * Returns quality scores corresponding to each pair of
838 * positions and distances (i.e. sample).
839 * The larger the score value the better the quality of the sample.
840 * This implementation always returns null.
841 * Subclasses using quality scores must implement proper behavior.
842 *
843 * @return quality scores corresponding to each sample.
844 */
845 @Override
846 public double[] getQualityScores() {
847 return qualityScores;
848 }
849
850 /**
851 * Sets quality scores corresponding to each pair of positions and
852 * distances (i.e. sample).
853 * The larger the score value the better the quality of the sample.
854 * This implementation makes no action.
855 * Subclasses using quality scores must implement proper behaviour.
856 *
857 * @param qualityScores quality scores corresponding to each pair of
858 * matched points.
859 * @throws IllegalArgumentException if provided quality scores length
860 * is smaller than minimum required samples.
861 * @throws LockedException if robust solver is locked because an
862 * estimation is already in progress.
863 */
864 @Override
865 public void setQualityScores(final double[] qualityScores) throws LockedException {
866 if (isLocked()) {
867 throw new LockedException();
868 }
869 internalSetQualityScores(qualityScores);
870 }
871
872 /**
873 * Indicates whether solver is ready to find a solution.
874 *
875 * @return true if solver is ready, false otherwise.
876 */
877 @Override
878 public boolean isReady() {
879 return super.isReady() && qualityScores != null && qualityScores.length == readings.size();
880 }
881
882 /**
883 * Indicates whether inliers must be computed and kept.
884 *
885 * @return true if inliers must be computed and kept, false if inliers
886 * only need to be computed but not kept.
887 */
888 public boolean isComputeAndKeepInliersEnabled() {
889 return computeAndKeepInliers;
890 }
891
892 /**
893 * Specifies whether inliers must be computed and kept.
894 *
895 * @param computeAndKeepInliers true if inliers must be computed and kept,
896 * false if inliers only need to be computed but not kept.
897 * @throws LockedException if this solver is locked.
898 */
899 public void setComputeAndKeepInliersEnabled(final boolean computeAndKeepInliers) throws LockedException {
900 if (isLocked()) {
901 throw new LockedException();
902 }
903 this.computeAndKeepInliers = computeAndKeepInliers;
904 }
905
906 /**
907 * Indicates whether residuals must be computed and kept.
908 *
909 * @return true if residuals must be computed and kept, false if residuals
910 * only need to be computed but not kept.
911 */
912 public boolean isComputeAndKeepResidualsEnabled() {
913 return computeAndKeepResiduals;
914 }
915
916 /**
917 * Specifies whether residuals must be computed and kept.
918 *
919 * @param computeAndKeepResiduals true if residuals must be computed and kept,
920 * false if residuals only need to be computed but not kept.
921 * @throws LockedException if this solver is locked.
922 */
923 public void setComputeAndKeepResidualsEnabled(final boolean computeAndKeepResiduals) throws LockedException {
924 if (isLocked()) {
925 throw new LockedException();
926 }
927 this.computeAndKeepResiduals = computeAndKeepResiduals;
928 }
929
930 /**
931 * Robustly estimates position, transmitted power and path-loss exponent for a
932 * radio source.
933 *
934 * @throws LockedException if instance is busy during estimation.
935 * @throws NotReadyException if estimator is not ready.
936 * @throws RobustEstimatorException if estimation fails for any reason
937 * (i.e. numerical instability, no solution available, etc).
938 */
939 @Override
940 public void estimate() throws LockedException, NotReadyException, RobustEstimatorException {
941 if (isLocked()) {
942 throw new LockedException();
943 }
944 if (!isReady()) {
945 throw new NotReadyException();
946 }
947
948 final var innerEstimator = new PROSACRobustEstimator<>(new PROSACRobustEstimatorListener<Solution<Point3D>>() {
949
950 @Override
951 public double[] getQualityScores() {
952 return qualityScores;
953 }
954
955 @Override
956 public double getThreshold() {
957 return threshold;
958 }
959
960 @Override
961 public int getTotalSamples() {
962 return readings.size();
963 }
964
965 @Override
966 public int getSubsetSize() {
967 return Math.max(preliminarySubsetSize, getMinReadings());
968 }
969
970 @Override
971 public void estimatePreliminarSolutions(
972 final int[] samplesIndices, final List<Solution<Point3D>> solutions) {
973 solvePreliminarySolutions(samplesIndices, solutions);
974 }
975
976 @Override
977 public double computeResidual(final Solution<Point3D> currentEstimation, final int i) {
978 return residual(currentEstimation, i);
979 }
980
981 @Override
982 public boolean isReady() {
983 return PROSACRobustRssiRadioSourceEstimator3D.this.isReady();
984 }
985
986 @Override
987 public void onEstimateStart(final RobustEstimator<Solution<Point3D>> estimator) {
988 // no action needed
989 }
990
991 @Override
992 public void onEstimateEnd(final RobustEstimator<Solution<Point3D>> estimator) {
993 // no action needed
994 }
995
996 @Override
997 public void onEstimateNextIteration(
998 final RobustEstimator<Solution<Point3D>> estimator, final int iteration) {
999 if (listener != null) {
1000 listener.onEstimateNextIteration(
1001 PROSACRobustRssiRadioSourceEstimator3D.this, iteration);
1002 }
1003 }
1004
1005 @Override
1006 public void onEstimateProgressChange(
1007 final RobustEstimator<Solution<Point3D>> estimator, final float progress) {
1008 if (listener != null) {
1009 listener.onEstimateProgressChange(
1010 PROSACRobustRssiRadioSourceEstimator3D.this, progress);
1011 }
1012 }
1013 });
1014
1015 try {
1016 locked = true;
1017
1018 if (listener != null) {
1019 listener.onEstimateStart(this);
1020 }
1021
1022 inliersData = null;
1023 innerEstimator.setComputeAndKeepInliersEnabled(computeAndKeepInliers || refineResult);
1024 innerEstimator.setComputeAndKeepResidualsEnabled(computeAndKeepResiduals || refineResult);
1025 innerEstimator.setConfidence(confidence);
1026 innerEstimator.setMaxIterations(maxIterations);
1027 innerEstimator.setProgressDelta(progressDelta);
1028 final var result = innerEstimator.estimate();
1029 inliersData = innerEstimator.getInliersData();
1030 attemptRefine(result);
1031
1032 if (listener != null) {
1033 listener.onEstimateEnd(this);
1034 }
1035
1036 } catch (final com.irurueta.numerical.LockedException e) {
1037 throw new LockedException(e);
1038 } catch (final com.irurueta.numerical.NotReadyException e) {
1039 throw new NotReadyException(e);
1040 } finally {
1041 locked = false;
1042 }
1043 }
1044
1045 /**
1046 * Returns method being used for robust estimation.
1047 *
1048 * @return method being used for robust estimation.
1049 */
1050 @Override
1051 public RobustEstimatorMethod getMethod() {
1052 return RobustEstimatorMethod.PROSAC;
1053 }
1054
1055 /**
1056 * Sets quality scores corresponding to each provided sample.
1057 * This method is used internally and does not check whether instance is
1058 * locked or not.
1059 *
1060 * @param qualityScores quality scores to be set.
1061 * @throws IllegalArgumentException if provided quality scores length
1062 * is smaller than required minimum.
1063 */
1064 private void internalSetQualityScores(final double[] qualityScores) {
1065 if (qualityScores == null || qualityScores.length < getMinReadings()) {
1066 throw new IllegalArgumentException();
1067 }
1068
1069 this.qualityScores = qualityScores;
1070 }
1071 }