View Javadoc
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.indoor.*;
21  
22  import java.util.List;
23  
24  /**
25   * Robustly estimate 3D position, transmitted power and path-loss exponent of a radio
26   * source (e.g. Wi-Fi access point or bluetooth beacon), by discarding
27   * outliers and assuming that the ranging data is available to obtain position with
28   * greater accuracy and that the radio source emits isotropically following the
29   * expression below:
30   * Pr = Pt*Gt*Gr*lambda^2 / (4*pi*d)^2,
31   * where Pr is the received power (expressed in mW),
32   * Gt is the Gain of the transmission antenna
33   * Gr is the Gain of the receiver antenna
34   * d is the distance between emitter and receiver
35   * and lambda is the wavelength and is equal to: lambda = c / f,
36   * where c is the speed of light
37   * and f is the carrier frequency of the radio signal.
38   * <p>
39   * Implementations of this class sequentially estimate position and then remaining
40   * parameters. First ranging data is used to robustly estimate position and then
41   * remaining parameters are robustly estimated using former estimated position as
42   * an initial guess.
43   * <p>
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 Readings contain RSSI standard deviations, those values will be used,
49   * otherwise it will be assumed an RSSI standard deviation of 1 dB.
50   * <p>
51   * This implementation is like SequentialRobustRangingAndRssiRadioSourceEstimator but
52   * allows mixing different kinds of located radio source readings (ranging, RSSI
53   * and ranging+RSSI).
54   *
55   * @param <S> a {@link RadioSource} type.
56   */
57  public class SequentialRobustMixedRadioSourceEstimator3D<S extends RadioSource> extends
58          SequentialRobustMixedRadioSourceEstimator<S, Point3D> {
59  
60      /**
61       * Constructor.
62       */
63      public SequentialRobustMixedRadioSourceEstimator3D() {
64          rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
65      }
66  
67      /**
68       * Constructor.
69       * Sets signal readings belonging to the same radio source.
70       *
71       * @param readings signal readings belonging to the same radio source.
72       * @throws IllegalArgumentException if readings are not valid.
73       */
74      public SequentialRobustMixedRadioSourceEstimator3D(final List<? extends ReadingLocated<Point3D>> readings) {
75          super(readings);
76          rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
77      }
78  
79      /**
80       * Constructor.
81       *
82       * @param listener listener in charge of attending events raised by this instance.
83       */
84      public SequentialRobustMixedRadioSourceEstimator3D(
85              final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
86          super(listener);
87          rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
88      }
89  
90      /**
91       * Constructor.
92       * Sets signal readings belonging to the same radio source.
93       *
94       * @param readings signal readings belonging to the same radio source.
95       * @param listener listener in charge of attending events raised by this instance.
96       * @throws IllegalArgumentException if readings are not valid.
97       */
98      public SequentialRobustMixedRadioSourceEstimator3D(
99              final List<? extends ReadingLocated<Point3D>> readings,
100             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
101         super(readings, listener);
102         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
103     }
104 
105     /**
106      * Constructor.
107      * Sets signal readings belonging to the same radio source.
108      *
109      * @param readings        signal readings belonging to the same radio source.
110      * @param initialPosition initial position to start the estimation of radio
111      *                        source position.
112      * @throws IllegalArgumentException if readings are not valid.
113      */
114     public SequentialRobustMixedRadioSourceEstimator3D(
115             final List<? extends ReadingLocated<Point3D>> readings, final Point3D initialPosition) {
116         super(readings, initialPosition);
117         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
118     }
119 
120     /**
121      * Constructor.
122      *
123      * @param initialPosition initial position to start the estimation of radio
124      *                        source position.
125      */
126     public SequentialRobustMixedRadioSourceEstimator3D(final Point3D initialPosition) {
127         super(initialPosition);
128         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
129     }
130 
131     /**
132      * Constructor.
133      *
134      * @param initialPosition initial position to start the estimation of radio
135      *                        source position.
136      * @param listener        listener in charge of attending events raised by this instance.
137      */
138     public SequentialRobustMixedRadioSourceEstimator3D(
139             final Point3D initialPosition,
140             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
141         super(initialPosition, listener);
142         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
143     }
144 
145     /**
146      * Constructor.
147      * Sets signal readings belonging to the same radio source.
148      *
149      * @param readings        signal readings belonging to the same radio source.
150      * @param initialPosition initial position to start the estimation of radio
151      *                        source position.
152      * @param listener        listener in charge of attending events raised by this instance.
153      * @throws IllegalArgumentException if readings are not valid.
154      */
155     public SequentialRobustMixedRadioSourceEstimator3D(
156             final List<? extends ReadingLocated<Point3D>> readings, final Point3D initialPosition,
157             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
158         super(readings, initialPosition, listener);
159         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
160     }
161 
162     /**
163      * Constructor.
164      *
165      * @param initialTransmittedPowerdBm initial transmitted power to start the
166      *                                   estimation of radio source transmitted power
167      *                                   (expressed in dBm's).
168      */
169     public SequentialRobustMixedRadioSourceEstimator3D(final Double initialTransmittedPowerdBm) {
170         super(initialTransmittedPowerdBm);
171         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
172     }
173 
174     /**
175      * Constructor.
176      * Sets signal readings belonging to the same radio source.
177      *
178      * @param readings                   signal readings belonging to the same radio source.
179      * @param initialTransmittedPowerdBm initial transmitted power to start the
180      *                                   estimation of radio source transmitted power
181      *                                   (expressed in dBm's).
182      * @throws IllegalArgumentException if readings are not valid.
183      */
184     public SequentialRobustMixedRadioSourceEstimator3D(
185             final List<? extends ReadingLocated<Point3D>> readings, final Double initialTransmittedPowerdBm) {
186         super(readings, initialTransmittedPowerdBm);
187         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
188     }
189 
190     /**
191      * Constructor.
192      *
193      * @param initialTransmittedPowerdBm initial transmitted power to start the
194      *                                   estimation of radio source transmitted power
195      *                                   (expressed in dBm's).
196      * @param listener                   listener in charge of attending events raised by this instance.
197      */
198     public SequentialRobustMixedRadioSourceEstimator3D(
199             final Double initialTransmittedPowerdBm,
200             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
201         super(initialTransmittedPowerdBm, listener);
202         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
203     }
204 
205     /**
206      * Constructor.
207      * Sets signal readings belonging to the same radio source.
208      *
209      * @param readings                   signal readings belonging to the same radio source.
210      * @param initialTransmittedPowerdBm initial transmitted power to start the
211      *                                   estimation of radio source transmitted power
212      *                                   (expressed in dBm's).
213      * @param listener                   listener in charge of attending events raised by this instance.
214      * @throws IllegalArgumentException if readings are not valid.
215      */
216     public SequentialRobustMixedRadioSourceEstimator3D(
217             final List<? extends ReadingLocated<Point3D>> readings, final Double initialTransmittedPowerdBm,
218             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
219         super(readings, initialTransmittedPowerdBm, listener);
220         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
221     }
222 
223     /**
224      * Constructor.
225      * Sets signal readings belonging to the same radio source.
226      *
227      * @param readings                   signal readings belonging to the same radio source.
228      * @param initialPosition            initial position to start the estimation of radio
229      *                                   source position.
230      * @param initialTransmittedPowerdBm initial transmitted power to start the
231      *                                   estimation of radio source transmitted power
232      *                                   (expressed in dBm's).
233      * @throws IllegalArgumentException if readings are not valid.
234      */
235     public SequentialRobustMixedRadioSourceEstimator3D(
236             final List<? extends ReadingLocated<Point3D>> readings, final Point3D initialPosition,
237             final Double initialTransmittedPowerdBm) {
238         super(readings, initialPosition, initialTransmittedPowerdBm);
239         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
240     }
241 
242     /**
243      * Constructor.
244      *
245      * @param initialPosition            initial position to start the estimation of radio
246      *                                   source position.
247      * @param initialTransmittedPowerdBm initial transmitted power to start the
248      *                                   estimation of radio source transmitted power
249      *                                   (expressed in dBm's).
250      */
251     public SequentialRobustMixedRadioSourceEstimator3D(
252             final Point3D initialPosition, final Double initialTransmittedPowerdBm) {
253         super(initialPosition, initialTransmittedPowerdBm);
254         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
255     }
256 
257     /**
258      * Constructor.
259      *
260      * @param initialPosition            initial position to start the estimation of radio
261      *                                   source position.
262      * @param initialTransmittedPowerdBm initial transmitted power to start the
263      *                                   estimation of radio source transmitted power
264      *                                   (expressed in dBm's).
265      * @param listener                   in charge of attending events raised by this instance.
266      */
267     public SequentialRobustMixedRadioSourceEstimator3D(
268             final Point3D initialPosition, final Double initialTransmittedPowerdBm,
269             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
270         super(initialPosition, initialTransmittedPowerdBm, listener);
271         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
272     }
273 
274     /**
275      * Constructor.
276      * Sets signal readings belonging to the same radio source.
277      *
278      * @param readings                   signal readings belonging to the same radio source.
279      * @param initialPosition            initial position to start the estimation of radio
280      *                                   source position.
281      * @param initialTransmittedPowerdBm initial transmitted power to start the
282      *                                   estimation of radio source transmitted power
283      *                                   (expressed in dBm's).
284      * @param listener                   listener in charge of attending events raised by this instance.
285      * @throws IllegalArgumentException if readings are not valid.
286      */
287     public SequentialRobustMixedRadioSourceEstimator3D(
288             final List<? extends ReadingLocated<Point3D>> readings, final Point3D initialPosition,
289             final Double initialTransmittedPowerdBm,
290             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
291         super(readings, initialPosition, initialTransmittedPowerdBm, listener);
292         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
293     }
294 
295     /**
296      * Constructor.
297      * Sets signal readings belonging to the same radio source.
298      *
299      * @param readings                   signal readings belonging to the same radio source.
300      * @param initialPosition            initial position to start the estimation of radio
301      *                                   source position.
302      * @param initialTransmittedPowerdBm initial transmitted power to start the
303      *                                   estimation of radio source transmitted power
304      *                                   (expressed in dBm's).
305      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
306      * @throws IllegalArgumentException if readings are not valid.
307      */
308     public SequentialRobustMixedRadioSourceEstimator3D(
309             final List<? extends ReadingLocated<Point3D>> readings, final Point3D initialPosition,
310             final Double initialTransmittedPowerdBm, final double initialPathLossExponent) {
311         super(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
312         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
313     }
314 
315     /**
316      * Constructor.
317      *
318      * @param initialPosition            initial position to start the estimation of radio
319      *                                   source position.
320      * @param initialTransmittedPowerdBm initial transmitted power to start the
321      *                                   estimation of radio source transmitted power
322      *                                   (expressed in dBm's).
323      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
324      */
325     public SequentialRobustMixedRadioSourceEstimator3D(
326             final Point3D initialPosition, final Double initialTransmittedPowerdBm,
327             final double initialPathLossExponent) {
328         super(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
329         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
330     }
331 
332     /**
333      * Constructor.
334      *
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      * @param listener                   listener in charge of attending events raised by this instance.
342      */
343     public SequentialRobustMixedRadioSourceEstimator3D(
344             final Point3D initialPosition, final Double initialTransmittedPowerdBm,
345             final double initialPathLossExponent,
346             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
347         super(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
348         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
349     }
350 
351     /**
352      * Constructors.
353      * Sets signal readings belonging to the same radio source.
354      *
355      * @param readings                   signal readings belonging to the same radio source.
356      * @param initialPosition            initial position to start the estimation of radio
357      *                                   source position.
358      * @param initialTransmittedPowerdBm initial transmitted power to start the
359      *                                   estimation of radio source transmitted power
360      *                                   (expressed in dBm's).
361      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
362      * @param listener                   listener in charge of attending events raised by this instance.
363      * @throws IllegalArgumentException if readings are not valid.
364      */
365     public SequentialRobustMixedRadioSourceEstimator3D(
366             final List<? extends ReadingLocated<Point3D>> readings, final Point3D initialPosition,
367             final Double initialTransmittedPowerdBm, final double initialPathLossExponent,
368             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
369         super(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
370         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
371     }
372 
373     /**
374      * Constructor.
375      *
376      * @param qualityScores quality scores corresponding to each provided sample.
377      *                      The larger the score value the better the quality of
378      *                      the sample.
379      * @throws IllegalArgumentException if quality scores is null, or length of
380      *                                  quality scores is less than required minimum.
381      */
382     public SequentialRobustMixedRadioSourceEstimator3D(final double[] qualityScores) {
383         super(qualityScores);
384         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
385     }
386 
387     /**
388      * Constructor.
389      * Sets signal readings belonging to the same radio source.
390      *
391      * @param qualityScores quality scores corresponding to each provided sample.
392      *                      The larger the score value the better the quality of
393      *                      the sample.
394      * @param readings      signal readings belonging to the same radio source.
395      * @throws IllegalArgumentException if readings are not valid, quality scores is
396      *                                  null, or length of quality scores is less than required minimum.
397      */
398     public SequentialRobustMixedRadioSourceEstimator3D(
399             final double[] qualityScores, final List<? extends ReadingLocated<Point3D>> readings) {
400         super(qualityScores, readings);
401         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
402     }
403 
404     /**
405      * Constructor.
406      *
407      * @param qualityScores quality scores corresponding to each provided sample.
408      *                      The larger the score value the better the quality of
409      *                      the sample.
410      * @param listener      listener in charge of attending events raised by this instance.
411      * @throws IllegalArgumentException if quality scores is null, or length
412      *                                  of quality scores is less than required minimum.
413      */
414     public SequentialRobustMixedRadioSourceEstimator3D(
415             final double[] qualityScores,
416             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
417         super(qualityScores, listener);
418         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
419     }
420 
421     /**
422      * Constructor.
423      * Sets signal readings belonging to the same radio source.
424      *
425      * @param qualityScores quality scores corresponding to each provided sample.
426      *                      The larger the score value the better the quality of
427      *                      the sample.
428      * @param readings      signal readings belonging to the same radio source.
429      * @param listener      listener in charge of attending events raised by this instance.
430      * @throws IllegalArgumentException if readings are not valid, quality scores is
431      *                                  null, or length of quality scores is less than required minimum.
432      */
433     public SequentialRobustMixedRadioSourceEstimator3D(
434             final double[] qualityScores, final List<? extends ReadingLocated<Point3D>> readings,
435             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
436         super(qualityScores, readings, listener);
437         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
438     }
439 
440     /**
441      * Constructor.
442      * Sets signal readings belonging to the same radio source.
443      *
444      * @param qualityScores   quality scores corresponding to each provided sample.
445      *                        The larger the score value the better the quality of
446      *                        the sample.
447      * @param readings        signal readings belonging to the same radio source.
448      * @param initialPosition initial position to start the estimation of radio
449      *                        source position.
450      * @throws IllegalArgumentException if readings are not valid, quality scores is
451      *                                  null, or length of quality scores is less than required minimum.
452      */
453     public SequentialRobustMixedRadioSourceEstimator3D(
454             final double[] qualityScores, final List<? extends ReadingLocated<Point3D>> readings,
455             final Point3D initialPosition) {
456         super(qualityScores, readings, initialPosition);
457         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
458     }
459 
460     /**
461      * Constructor.
462      *
463      * @param qualityScores   quality scores corresponding to each provided sample.
464      *                        The larger the score value the better the quality of
465      *                        the sample.
466      * @param initialPosition initial position to start the estimation of radio
467      *                        source position.
468      * @throws IllegalArgumentException if quality scores is null, or length
469      *                                  of quality scores is less than required minimum.
470      */
471     public SequentialRobustMixedRadioSourceEstimator3D(final double[] qualityScores, final Point3D initialPosition) {
472         super(qualityScores, initialPosition);
473         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
474     }
475 
476     /**
477      * Constructor.
478      *
479      * @param qualityScores   quality scores corresponding to each provided sample.
480      *                        The larger the score value the better the quality of
481      *                        the sample.
482      * @param initialPosition initial position to start the estimation of radio
483      *                        source position.
484      * @param listener        listener in charge of attending events raised by this instance.
485      * @throws IllegalArgumentException if quality scores is null, or length
486      *                                  of quality scores is less than required minimum.
487      */
488     public SequentialRobustMixedRadioSourceEstimator3D(
489             final double[] qualityScores, final Point3D initialPosition,
490             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
491         super(qualityScores, initialPosition, listener);
492         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
493     }
494 
495     /**
496      * Constructor.
497      * Sets signal readings belonging to the same radio source.
498      *
499      * @param qualityScores   quality scores corresponding to each provided sample.
500      *                        The larger the score value the better the quality of
501      *                        the sample.
502      * @param readings        signal readings belonging to the same radio source.
503      * @param initialPosition initial position to start the estimation of radio
504      *                        source position.
505      * @param listener        listener in charge of attending events raised by this instance.
506      * @throws IllegalArgumentException if readings are not valid, quality scores
507      *                                  is null, or length of quality scores is less than required minimum.
508      */
509     public SequentialRobustMixedRadioSourceEstimator3D(
510             final double[] qualityScores, final List<? extends ReadingLocated<Point3D>> readings,
511             final Point3D initialPosition,
512             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
513         super(qualityScores, readings, initialPosition, listener);
514         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
515     }
516 
517     /**
518      * Constructor.
519      *
520      * @param qualityScores              quality scores corresponding to each provided sample.
521      *                                   The larger the score value the better the quality of
522      *                                   the sample.
523      * @param initialTransmittedPowerdBm initial transmitted power to start the
524      *                                   estimation of radio source transmitted power
525      *                                   (expressed in dBm's).
526      * @throws IllegalArgumentException if quality scores is null, or length
527      *                                  of quality scores is less than required minimum.
528      */
529     public SequentialRobustMixedRadioSourceEstimator3D(
530             final double[] qualityScores, final Double initialTransmittedPowerdBm) {
531         super(qualityScores, initialTransmittedPowerdBm);
532         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
533     }
534 
535     /**
536      * Constructor.
537      * Sets signal readings belonging to the same radio source.
538      *
539      * @param qualityScores              quality scores corresponding to each provided sample.
540      *                                   The larger the score value the better the quality of
541      *                                   the sample.
542      * @param readings                   signal readings belonging to the same radio source.
543      * @param initialTransmittedPowerdBm initial transmitted power to start the
544      *                                   estimation of radio source transmitted power
545      *                                   (expressed in dBm's).
546      * @throws IllegalArgumentException if readings are not valid, quality scores
547      *                                  is null, or length of quality scores is less than required minimum.
548      */
549     public SequentialRobustMixedRadioSourceEstimator3D(
550             final double[] qualityScores, final List<? extends ReadingLocated<Point3D>> readings,
551             final Double initialTransmittedPowerdBm) {
552         super(qualityScores, readings, initialTransmittedPowerdBm);
553         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
554     }
555 
556     /**
557      * Constructor.
558      *
559      * @param qualityScores              quality scores corresponding to each provided sample.
560      *                                   The larger the score value the better the quality of
561      *                                   the sample.
562      * @param initialTransmittedPowerdBm initial transmitted power to start the
563      *                                   estimation of radio source transmitted power
564      *                                   (expressed in dBm's).
565      * @param listener                   listener in charge of attending events raised by this instance.
566      * @throws IllegalArgumentException if quality scores is null, or length
567      *                                  of quality scores is less than required minimum.
568      */
569     public SequentialRobustMixedRadioSourceEstimator3D(
570             final double[] qualityScores, final Double initialTransmittedPowerdBm,
571             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
572         super(qualityScores, initialTransmittedPowerdBm, listener);
573         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
574     }
575 
576     /**
577      * Constructor.
578      * Sets signal readings belonging to the same radio source.
579      *
580      * @param qualityScores              quality scores corresponding to each provided
581      *                                   sample. The larger the score value the better
582      *                                   the quality of the sample.
583      * @param readings                   signal readings belonging to the same radio source.
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      * @throws IllegalArgumentException if readings are not valid, quality scores
589      *                                  is null, or length of quality scores is less than required minimum.
590      */
591     public SequentialRobustMixedRadioSourceEstimator3D(
592             final double[] qualityScores, final List<? extends ReadingLocated<Point3D>> readings,
593             final Double initialTransmittedPowerdBm,
594             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
595         super(qualityScores, readings, initialTransmittedPowerdBm, listener);
596         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
597     }
598 
599     /**
600      * Constructor.
601      * Sets signal readings belonging to the same radio source.
602      *
603      * @param qualityScores              quality scores corresponding to each provided
604      *                                   sample. The larger the score value the better
605      *                                   the quality of the sample.
606      * @param readings                   signal readings belonging to the same radio source.
607      * @param initialPosition            initial position to start the estimation of radio
608      *                                   source position.
609      * @param initialTransmittedPowerdBm initial transmitted power to start the
610      *                                   estimation of radio source transmitted power
611      *                                   (expressed in dBm's).
612      * @throws IllegalArgumentException if readings are not valid, quality scores
613      *                                  is null, or length of quality scores is less than required minimum.
614      */
615     public SequentialRobustMixedRadioSourceEstimator3D(
616             final double[] qualityScores, final List<? extends ReadingLocated<Point3D>> readings,
617             final Point3D initialPosition, final Double initialTransmittedPowerdBm) {
618         super(qualityScores, readings, initialPosition, initialTransmittedPowerdBm);
619         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
620     }
621 
622     /**
623      * Constructor.
624      *
625      * @param qualityScores              quality scores corresponding to each provided
626      *                                   sample. The larger the score value the better
627      *                                   the quality of the sample.
628      * @param initialPosition            initial position to start the estimation of radio
629      *                                   source position.
630      * @param initialTransmittedPowerdBm initial transmitted power to start the
631      *                                   estimation of radio source transmitted power
632      *                                   (expressed in dBm's).
633      * @throws IllegalArgumentException if quality scores is null, or length
634      *                                  of quality scores is less than required minimum.
635      */
636     public SequentialRobustMixedRadioSourceEstimator3D(
637             final double[] qualityScores, final Point3D initialPosition, final Double initialTransmittedPowerdBm) {
638         super(qualityScores, initialPosition, initialTransmittedPowerdBm);
639         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
640     }
641 
642     /**
643      * Constructor.
644      *
645      * @param qualityScores              quality scores corresponding to each provided
646      *                                   sample. The larger the score value the better
647      *                                   the quality of the sample.
648      * @param initialPosition            initial position to start the estimation of radio
649      *                                   source position.
650      * @param initialTransmittedPowerdBm initial transmitted power to start the
651      *                                   estimation of radio source transmitted power
652      *                                   (expressed in dBm's).
653      * @param listener                   in charge of attending events raised by this instance.
654      * @throws IllegalArgumentException if quality scores is null, or length
655      *                                  of quality scores is less than required minimum.
656      */
657     public SequentialRobustMixedRadioSourceEstimator3D(
658             final double[] qualityScores, final Point3D initialPosition, final Double initialTransmittedPowerdBm,
659             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
660         super(qualityScores, initialPosition, initialTransmittedPowerdBm, listener);
661         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
662     }
663 
664     /**
665      * Constructor.
666      * Sets signal readings belonging to the same radio source.
667      *
668      * @param qualityScores              quality scores corresponding to each provided
669      *                                   sample. The larger the score value the better
670      *                                   the quality of the sample.
671      * @param readings                   signal readings belonging to the same radio source.
672      * @param initialPosition            initial position to start the estimation of radio
673      *                                   source position.
674      * @param initialTransmittedPowerdBm initial transmitted power to start the
675      *                                   estimation of radio source transmitted power
676      *                                   (expressed in dBm's).
677      * @param listener                   listener in charge of attending events raised by this instance.
678      * @throws IllegalArgumentException if readings are not valid, quality scores
679      *                                  is null, or length of quality scores is less than required minimum.
680      */
681     public SequentialRobustMixedRadioSourceEstimator3D(
682             final double[] qualityScores, final List<? extends ReadingLocated<Point3D>> readings,
683             final Point3D initialPosition, final Double initialTransmittedPowerdBm,
684             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
685         super(qualityScores, readings, initialPosition, initialTransmittedPowerdBm, listener);
686         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
687     }
688 
689     /**
690      * Constructor.
691      * Sets signal readings belonging to the same radio source.
692      *
693      * @param qualityScores              quality scores corresponding to each provided
694      *                                   sample. The larger the score value the better
695      *                                   the quality of the sample.
696      * @param readings                   signal readings belonging to the same radio source.
697      * @param initialPosition            initial position to start the estimation of radio
698      *                                   source position.
699      * @param initialTransmittedPowerdBm initial transmitted power to start the
700      *                                   estimation of radio source transmitted power
701      *                                   (expressed in dBm's).
702      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
703      * @throws IllegalArgumentException if readings are not valid, quality scores
704      *                                  is null, or length of quality scores is less than required minimum.
705      */
706     public SequentialRobustMixedRadioSourceEstimator3D(
707             final double[] qualityScores, final List<? extends ReadingLocated<Point3D>> readings,
708             final Point3D initialPosition, final Double initialTransmittedPowerdBm,
709             final double initialPathLossExponent) {
710         super(qualityScores, readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
711         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
712     }
713 
714     /**
715      * Constructor.
716      *
717      * @param qualityScores              quality scores corresponding to each provided
718      *                                   sample. The larger the score value the better
719      *                                   the quality of the sample.
720      * @param initialPosition            initial position to start the estimation of radio
721      *                                   source position.
722      * @param initialTransmittedPowerdBm initial transmitted power to start the
723      *                                   estimation of radio source transmitted power
724      *                                   (expressed in dBm's).
725      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
726      * @throws IllegalArgumentException if quality scores is null, or length
727      *                                  of quality scores is less than required minimum.
728      */
729     public SequentialRobustMixedRadioSourceEstimator3D(
730             final double[] qualityScores, final Point3D initialPosition, final Double initialTransmittedPowerdBm,
731             final double initialPathLossExponent) {
732         super(qualityScores, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
733         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
734     }
735 
736     /**
737      * Constructor.
738      *
739      * @param qualityScores              quality scores corresponding to each provided
740      *                                   sample. The larger the score value the better
741      *                                   the quality of the sample.
742      * @param initialPosition            initial position to start the estimation of radio
743      *                                   source position.
744      * @param initialTransmittedPowerdBm initial transmitted power to start the
745      *                                   estimation of radio source transmitted power
746      *                                   (expressed in dBm's).
747      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
748      * @param listener                   listener in charge of attending events raised by this instance.
749      * @throws IllegalArgumentException if quality scores is null, or length
750      *                                  of quality scores is less than required minimum.
751      */
752     public SequentialRobustMixedRadioSourceEstimator3D(
753             final double[] qualityScores, final Point3D initialPosition, final Double initialTransmittedPowerdBm,
754             final double initialPathLossExponent,
755             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
756         super(qualityScores, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
757         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
758     }
759 
760     /**
761      * Constructors.
762      * Sets signal readings belonging to the same radio source.
763      *
764      * @param qualityScores              quality scores corresponding to each provided
765      *                                   sample. The larger the score value the better
766      *                                   the quality of the sample.
767      * @param readings                   signal readings belonging to the same radio source.
768      * @param initialPosition            initial position to start the estimation of radio
769      *                                   source position.
770      * @param initialTransmittedPowerdBm initial transmitted power to start the
771      *                                   estimation of radio source transmitted power
772      *                                   (expressed in dBm's).
773      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
774      * @param listener                   listener in charge of attending events raised by this instance.
775      * @throws IllegalArgumentException if readings are not valid, quality scores
776      *                                  is null, or length of quality scores is less than required minimum.
777      */
778     public SequentialRobustMixedRadioSourceEstimator3D(
779             final double[] qualityScores, final List<? extends ReadingLocated<Point3D>> readings,
780             final Point3D initialPosition, final Double initialTransmittedPowerdBm,
781             final double initialPathLossExponent,
782             final SequentialRobustMixedRadioSourceEstimatorListener<S, Point3D> listener) {
783         super(qualityScores, readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
784         rangingPreliminarySubsetSize = rssiPreliminarySubsetSize = getMinReadings();
785     }
786 
787     /**
788      * Gets minimum required number of readings to estimate
789      * power, position and path-loss exponent.
790      * This value depends on the number of parameters to
791      * be estimated, but for position only, this is 3
792      * readings.
793      *
794      * @return minimum required number of readings.
795      */
796     @Override
797     public int getMinReadings() {
798         var minReadings = Point3D.POINT3D_INHOMOGENEOUS_COORDINATES_LENGTH;
799         if (isTransmittedPowerEstimationEnabled()) {
800             minReadings++;
801         }
802         if (isPathLossEstimationEnabled()) {
803             minReadings++;
804         }
805         return ++minReadings;
806     }
807 
808     /**
809      * Gets number of dimensions of position points.
810      *
811      * @return always returns 2 dimensions.
812      */
813     @Override
814     public int getNumberOfDimensions() {
815         return Point3D.POINT3D_INHOMOGENEOUS_COORDINATES_LENGTH;
816     }
817 
818     /**
819      * Gets estimated located radio source with estimated transmitted power.
820      *
821      * @return estimated located radio source with estimated transmitted power or null.
822      */
823     @Override
824     @SuppressWarnings({"unchecked", "DuplicatedCode"})
825     public RadioSourceLocated<Point3D> getEstimatedRadioSource() {
826         final var readings = getReadings();
827         if (readings == null || readings.isEmpty()) {
828             return null;
829         }
830 
831         final S source;
832         final var reading = readings.get(0);
833         if (reading instanceof RangingReadingLocated) {
834             source = ((RangingReadingLocated<S, Point3D>) reading).getSource();
835         } else if (reading instanceof RssiReadingLocated) {
836             source = ((RssiReadingLocated<S, Point3D>) reading).getSource();
837         } else if (reading instanceof RangingAndRssiReadingLocated) {
838             source = ((RangingAndRssiReadingLocated<S, Point3D>) reading).getSource();
839         } else {
840             return null;
841         }
842 
843         final var estimatedPosition = getEstimatedPosition();
844         if (estimatedPosition == null) {
845             return null;
846         }
847 
848         final var estimatedPositionCovariance = getEstimatedPositionCovariance();
849 
850         final var transmittedPowerdBm = getEstimatedTransmittedPowerdBm();
851 
852         final var transmittedPowerVariance = getEstimatedTransmittedPowerVariance();
853         final var transmittedPowerStandardDeviation = transmittedPowerVariance != null
854                 ? Math.sqrt(transmittedPowerVariance) : null;
855 
856         final var pathlossExponentVariance = getEstimatedPathLossExponentVariance();
857         final var pathlossExponentStandardDeviation = pathlossExponentVariance != null
858                 ? Math.sqrt(pathlossExponentVariance) : null;
859 
860         if (source instanceof WifiAccessPoint accessPoint) {
861             if (transmittedPowerdBm != null) {
862                 return new WifiAccessPointWithPowerAndLocated3D(accessPoint.getBssid(), source.getFrequency(),
863                         accessPoint.getSsid(), transmittedPowerdBm, transmittedPowerStandardDeviation,
864                         getEstimatedPathLossExponent(), pathlossExponentStandardDeviation, estimatedPosition,
865                         estimatedPositionCovariance);
866             } else {
867                 return new WifiAccessPointLocated3D(accessPoint.getBssid(), source.getFrequency(),
868                         accessPoint.getSsid(), estimatedPosition, estimatedPositionCovariance);
869             }
870         } else if (source instanceof Beacon beacon) {
871             return new BeaconWithPowerAndLocated3D(beacon.getIdentifiers(), beacon.getTransmittedPower(),
872                     beacon.getFrequency(), beacon.getBluetoothAddress(), beacon.getBeaconTypeCode(),
873                     beacon.getManufacturer(), beacon.getServiceUuid(), beacon.getBluetoothName(),
874                     getEstimatedPathLossExponent(), transmittedPowerStandardDeviation,
875                     pathlossExponentStandardDeviation, estimatedPosition, estimatedPositionCovariance);
876         } else {
877             return null;
878         }
879     }
880 
881     /**
882      * Builds ranging estimator.
883      */
884     @Override
885     protected void buildRangingEstimatorIfNeeded() {
886         if (rangingEstimator == null || rangingEstimator.getMethod() != rangingRobustMethod) {
887             rangingEstimator = RobustRangingRadioSourceEstimator3D.create(rangingRobustMethod);
888         }
889     }
890 
891     /**
892      * Build RSSI estimator.
893      *
894      * @throws LockedException if estimator is locked.
895      */
896     @Override
897     protected void buildRssiEstimatorIfNeeded() throws LockedException {
898         if (rssiEstimator == null || rssiEstimator.getMethod() != rssiRobustMethod) {
899             rssiEstimator = RobustRssiRadioSourceEstimator3D.create(rssiRobustMethod);
900 
901             // rssi estimator will never need position estimator, but to
902             // ensure it is ready we need to provide an initial position
903             rssiEstimator.setPositionEstimationEnabled(false);
904             rssiEstimator.setInitialPosition(Point3D.create());
905         }
906     }
907 }