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.Point2D;
19  import com.irurueta.navigation.indoor.*;
20  
21  import java.util.List;
22  
23  /**
24   * Estimates 2D position, transmitted power and path loss exponent of a
25   * radio source (e.g. Wi-Fi access point or bluetooth beacon) assuming
26   * that the ranging data is available to obtain position with greater
27   * accuracy and that the radio source emits isotropically following the
28   * expression below:
29   * Pr = Pt*Gt*Gr*lambda^2 / (4*pi*d)^2,
30   * where Pr is the received power (expressed in mW),
31   * Gt is the Gain of the transmission antenna
32   * Gr is the Gain of the receiver antenna
33   * d is the distance between emitter and receiver
34   * and lambda is the wavelength and is equal to: lambda = c / f,
35   * where c is the speed of light
36   * and f is the carrier frequency of the radio signal.
37   * Because usually information about the antenna of the radio source cannot be
38   * retrieved (because many measurements are made on unknown devices where
39   * physical access is not possible), this implementation will estimate the
40   * equivalent transmitted power as: Pte = Pt * Gt * Gr.
41   * If Readings contain RSSI standard deviations, those values will be used,
42   * otherwise it will be assumed an RSSI standard deviation of 1 dB.
43   * <p>
44   * This implementation is like RangingAndRssiRadioSourceEstimator2D but allows mixing
45   * different kinds of located radio source readings (ranging, RSSI and ranging+RSSI).
46   *
47   * @param <S> a {@link RadioSource} type.
48   */
49  @SuppressWarnings("Duplicates")
50  public class MixedRadioSourceEstimator2D<S extends RadioSource> extends MixedRadioSourceEstimator<S, Point2D> {
51  
52      /**
53       * Constructor.
54       */
55      public MixedRadioSourceEstimator2D() {
56          super();
57      }
58  
59      /**
60       * Constructor.
61       * Sets radio signal readings belonging to the same radio source.
62       *
63       * @param readings radio signal readings belonging to the same
64       *                 radio sources.
65       * @throws IllegalArgumentException if readings are not valid.
66       */
67      public MixedRadioSourceEstimator2D(final List<? extends ReadingLocated<Point2D>> readings) {
68          super(readings);
69      }
70  
71      /**
72       * Constructor.
73       *
74       * @param listener listener in charge of attending events raised by this instance.
75       */
76      public MixedRadioSourceEstimator2D(final MixedRadioSourceEstimatorListener<S, Point2D> listener) {
77          super(listener);
78      }
79  
80      /**
81       * Constructor.
82       * Sets radio signal readings belonging to the same radio source.
83       *
84       * @param readings radio signal readings belonging to the same radio source.
85       * @param listener listener in charge of attending events raised by this instance.
86       * @throws IllegalArgumentException if readings are not valid.
87       */
88      public MixedRadioSourceEstimator2D(
89              final List<? extends ReadingLocated<Point2D>> readings,
90              final MixedRadioSourceEstimatorListener<S, Point2D> listener) {
91          super(readings, listener);
92      }
93  
94      /**
95       * Constructor.
96       *
97       * @param initialPosition initial position to start the estimation of radio
98       *                        source position.
99       */
100     public MixedRadioSourceEstimator2D(final Point2D initialPosition) {
101         super(initialPosition);
102     }
103 
104     /**
105      * Constructor.
106      * Sets radio signal readings belonging to the same radio source.
107      *
108      * @param readings        radio signal readings belonging to the same radio source.
109      * @param initialPosition initial position to start the estimation of radio
110      *                        source position.
111      * @throws IllegalArgumentException if readings are not valid.
112      */
113     public MixedRadioSourceEstimator2D(
114             final List<? extends ReadingLocated<Point2D>> readings, final Point2D initialPosition) {
115         super(readings, initialPosition);
116     }
117 
118     /**
119      * Constructor.
120      *
121      * @param initialPosition initial position to start the estimation of radio
122      *                        source position.
123      * @param listener        listener in charge of attending events raised by this instance.
124      */
125     public MixedRadioSourceEstimator2D(
126             final Point2D initialPosition, final MixedRadioSourceEstimatorListener<S, Point2D> listener) {
127         super(initialPosition, listener);
128     }
129 
130     /**
131      * Constructor.
132      * Sets radio signal readings belonging to the same radio source.
133      *
134      * @param readings        radio signal readings belonging to the same radio source.
135      * @param initialPosition initial position to start the estimation of radio
136      *                        source position.
137      * @param listener        listener in charge of attending events raised by this instance.
138      * @throws IllegalArgumentException if readings are not valid.
139      */
140     public MixedRadioSourceEstimator2D(
141             final List<? extends ReadingLocated<Point2D>> readings, final Point2D initialPosition,
142             final MixedRadioSourceEstimatorListener<S, Point2D> listener) {
143         super(readings, initialPosition, listener);
144     }
145 
146     /**
147      * Constructor.
148      *
149      * @param initialTransmittedPowerDbm initial transmitted power to start the
150      *                                   estimation of radio source transmitted power
151      *                                   (expressed in dBm's).
152      */
153     public MixedRadioSourceEstimator2D(final Double initialTransmittedPowerDbm) {
154         super(initialTransmittedPowerDbm);
155     }
156 
157     /**
158      * Constructor.
159      * Sets radio signal readings belonging to the same radio source.
160      *
161      * @param readings                   radio signal readings belonging to the same radio source.
162      * @param initialTransmittedPowerdBm initial transmitted power to start the
163      *                                   estimation of radio source transmitted power
164      *                                   (expressed in dBm's).
165      * @throws IllegalArgumentException if readings are not valid.
166      */
167     public MixedRadioSourceEstimator2D(
168             final List<? extends ReadingLocated<Point2D>> readings, final Double initialTransmittedPowerdBm) {
169         super(readings, initialTransmittedPowerdBm);
170     }
171 
172     /**
173      * Constructor.
174      *
175      * @param initialTransmittedPowerdBm initial transmitted power to start the
176      *                                   estimation of radio source transmitted power
177      *                                   (expressed in dBm's).
178      * @param listener                   listener in charge of attending events raised by this instance.
179      */
180     public MixedRadioSourceEstimator2D(
181             final Double initialTransmittedPowerdBm, final MixedRadioSourceEstimatorListener<S, Point2D> listener) {
182         super(initialTransmittedPowerdBm, listener);
183     }
184 
185     /**
186      * Constructor.
187      * Sets radio signal readings belonging to the same radio source.
188      *
189      * @param readings                   radio signal readings belonging to the same radio source.
190      * @param initialTransmittedPowerdBm initial transmitted power to start the
191      *                                   estimation of radio source transmitted power
192      *                                   (expressed in dBm's).
193      * @param listener                   listener in charge of attending events raised by this instance.
194      * @throws IllegalArgumentException if readings are not valid.
195      */
196     public MixedRadioSourceEstimator2D(
197             final List<? extends ReadingLocated<Point2D>> readings, final Double initialTransmittedPowerdBm,
198             final MixedRadioSourceEstimatorListener<S, Point2D> listener) {
199         super(readings, initialTransmittedPowerdBm, listener);
200     }
201 
202     /**
203      * Constructor.
204      * Sets radio signal readings belonging to the same radio source.
205      *
206      * @param readings                   radio signal readings belonging to the same radio source.
207      * @param initialPosition            initial position to start the estimation of radio
208      *                                   source position.
209      * @param initialTransmittedPowerdBm initial transmitted power to start the
210      *                                   estimation of radio source transmitted power
211      *                                   (expressed in dBm's).
212      * @throws IllegalArgumentException if readings are not valid.
213      */
214     public MixedRadioSourceEstimator2D(
215             final List<? extends ReadingLocated<Point2D>> readings, final Point2D initialPosition,
216             final Double initialTransmittedPowerdBm) {
217         super(readings, initialPosition, initialTransmittedPowerdBm);
218     }
219 
220     /**
221      * Constructor.
222      *
223      * @param initialPosition            initial position to start the estimation of radio
224      *                                   source position.
225      * @param initialTransmittedPowerdBm initial transmitted power to start the
226      *                                   estimation of radio source transmitted power
227      *                                   (expressed in dBm's).
228      */
229     public MixedRadioSourceEstimator2D(final Point2D initialPosition, final Double initialTransmittedPowerdBm) {
230         super(initialPosition, initialTransmittedPowerdBm);
231     }
232 
233     /**
234      * Constructor.
235      *
236      * @param initialPosition            initial position to start the estimation of radio
237      *                                   source position.
238      * @param initialTransmittedPowerdBm initial transmitted power to start the
239      *                                   estimation of radio source transmitted power
240      *                                   (expressed in dBm's).
241      * @param listener                   listener in charge of attending events raised by this instance.
242      */
243     public MixedRadioSourceEstimator2D(
244             final Point2D initialPosition, final Double initialTransmittedPowerdBm,
245             final MixedRadioSourceEstimatorListener<S, Point2D> listener) {
246         super(initialPosition, initialTransmittedPowerdBm, listener);
247     }
248 
249     /**
250      * Constructor.
251      * Sets radio signal readings belonging to the same radio source.
252      *
253      * @param readings                   radio signal readings belonging to the same radio source.
254      * @param initialPosition            initial position to start the estimation of radio
255      *                                   source position.
256      * @param initialTransmittedPowerdBm initial transmitted power to start the
257      *                                   estimation of radio source transmitted power
258      *                                   (expressed in dBm's).
259      * @param listener                   listener in charge of attending events raised by this instance.
260      * @throws IllegalArgumentException if readings are not valid.
261      */
262     public MixedRadioSourceEstimator2D(
263             final List<? extends ReadingLocated<Point2D>> readings, final Point2D initialPosition,
264             final Double initialTransmittedPowerdBm, final MixedRadioSourceEstimatorListener<S, Point2D> listener) {
265         super(readings, initialPosition, initialTransmittedPowerdBm, listener);
266     }
267 
268     /**
269      * Constructor.
270      * Sets radio signal readings belonging to the same radio source.
271      *
272      * @param readings                   radio signal readings belonging to the same radio source.
273      * @param initialPosition            initial position to start the estimation of radio
274      *                                   source position.
275      * @param initialTransmittedPowerdBm initial transmitted power to start the
276      *                                   estimation of radio source transmitted power
277      *                                   (expressed in dBm's).
278      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
279      * @throws IllegalArgumentException if readings are not valid.
280      */
281     public MixedRadioSourceEstimator2D(
282             final List<? extends ReadingLocated<Point2D>> readings, final Point2D initialPosition,
283             final Double initialTransmittedPowerdBm, final double initialPathLossExponent) {
284         super(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
285     }
286 
287     /**
288      * Constructor.
289      *
290      * @param initialPosition            initial position to start the estimation of radio
291      *                                   source position.
292      * @param initialTransmittedPowerdBm initial transmitted power to start the
293      *                                   estimation of radio source transmitted power
294      *                                   (expressed in dBm's).
295      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
296      */
297     public MixedRadioSourceEstimator2D(
298             final Point2D initialPosition, final Double initialTransmittedPowerdBm,
299             final double initialPathLossExponent) {
300         super(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent);
301     }
302 
303     /**
304      * Constructor.
305      *
306      * @param initialPosition            initial position to start the estimation of radio
307      *                                   source position.
308      * @param initialTransmittedPowerdBm initial transmitted power to start the
309      *                                   estimation of radio source transmitted power
310      *                                   (expressed in dBm's).
311      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
312      * @param listener                   listener in charge of attending events raised by this instance.
313      */
314     public MixedRadioSourceEstimator2D(
315             final Point2D initialPosition, final Double initialTransmittedPowerdBm,
316             final double initialPathLossExponent, final MixedRadioSourceEstimatorListener<S, Point2D> listener) {
317         super(initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
318     }
319 
320     /**
321      * Constructor.
322      * Sets radio signal readings belonging to the same radio source.
323      *
324      * @param readings                   radio signal readings belonging to the same radio source.
325      * @param initialPosition            initial position to start the estimation of radio
326      *                                   source position.
327      * @param initialTransmittedPowerdBm initial transmitted power to start the
328      *                                   estimation of radio source transmitted power
329      *                                   (expressed in dBm's).
330      * @param initialPathLossExponent    initial path loss exponent. A typical value is 2.0.
331      * @param listener                   listener in charge of attending events raised by this instance.
332      * @throws IllegalArgumentException if readings are not valid.
333      */
334     public MixedRadioSourceEstimator2D(
335             final List<? extends ReadingLocated<Point2D>> readings, final Point2D initialPosition,
336             final Double initialTransmittedPowerdBm, final double initialPathLossExponent,
337             final MixedRadioSourceEstimatorListener<S, Point2D> listener) {
338         super(readings, initialPosition, initialTransmittedPowerdBm, initialPathLossExponent, listener);
339     }
340 
341     /**
342      * Gets number of dimensions of position points.
343      *
344      * @return number of dimensions of position points.
345      */
346     @Override
347     public int getNumberOfDimensions() {
348         return Point2D.POINT2D_INHOMOGENEOUS_COORDINATES_LENGTH;
349     }
350 
351     /**
352      * Gets estimated located radio source.
353      *
354      * @return estimated located radio source or null.
355      */
356     @SuppressWarnings("unchecked")
357     @Override
358     public RadioSourceLocated<Point2D> getEstimatedRadioSource() {
359         final var readings = getReadings();
360         if (readings == null || readings.isEmpty()) {
361             return null;
362         }
363 
364         final S source;
365         final var reading = readings.get(0);
366         if (reading instanceof RangingReadingLocated) {
367             source = ((RangingReadingLocated<S, Point2D>) reading).getSource();
368         } else if (reading instanceof RssiReadingLocated) {
369             source = ((RssiReadingLocated<S, Point2D>) reading).getSource();
370         } else if (reading instanceof RangingAndRssiReadingLocated) {
371             source = ((RangingAndRssiReadingLocated<S, Point2D>) reading).getSource();
372         } else {
373             return null;
374         }
375 
376         final var estimatedPosition = getEstimatedPosition();
377         if (estimatedPosition == null) {
378             return null;
379         }
380 
381         final var estimatedPositionCovariance = getEstimatedPositionCovariance();
382 
383         final var transmittedPowerdBm = getEstimatedTransmittedPowerdBm();
384 
385         final var transmittedPowerVariance = getEstimatedTransmittedPowerVariance();
386         final var transmittedPowerStandardDeviation = transmittedPowerVariance != null
387                 ? Math.sqrt(transmittedPowerVariance) : null;
388 
389         final var pathLossExponent = getEstimatedPathLossExponent();
390 
391         final var pathLossExponentVariance = getEstimatedPathLossExponentVariance();
392         final var pathLossExponentStandardDeviation = pathLossExponentVariance != null
393                 ? Math.sqrt(pathLossExponentVariance) : null;
394 
395         if (source instanceof WifiAccessPoint accessPoint) {
396             if (transmittedPowerdBm != null) {
397                 return new WifiAccessPointWithPowerAndLocated2D(accessPoint.getBssid(), accessPoint.getFrequency(),
398                         accessPoint.getSsid(), transmittedPowerdBm, transmittedPowerStandardDeviation, pathLossExponent,
399                         pathLossExponentStandardDeviation, estimatedPosition, estimatedPositionCovariance);
400             } else {
401                 return new WifiAccessPointLocated2D(accessPoint.getBssid(), accessPoint.getFrequency(),
402                         accessPoint.getSsid(), estimatedPosition, estimatedPositionCovariance);
403             }
404         } else if (source instanceof Beacon beacon) {
405             // transmitted power does not need to be estimated for beacons because
406             // they broadcast such information
407             return new BeaconWithPowerAndLocated2D(beacon.getIdentifiers(), beacon.getTransmittedPower(),
408                     beacon.getFrequency(), beacon.getBluetoothAddress(), beacon.getBeaconTypeCode(),
409                     beacon.getManufacturer(), beacon.getServiceUuid(), beacon.getBluetoothName(), pathLossExponent,
410                     transmittedPowerStandardDeviation, pathLossExponentStandardDeviation, estimatedPosition,
411                     estimatedPositionCovariance);
412         } else {
413             return null;
414         }
415     }
416 
417     /**
418      * Creates inner estimators if needed.
419      */
420     @Override
421     protected void createInnerEstimatorsIfNeeded() {
422         if (rangingInnerEstimator == null) {
423             rangingInnerEstimator = new RangingRadioSourceEstimator2D<>();
424         }
425 
426         if (rssiInnerEstimator == null && (transmittedPowerEstimationEnabled || pathLossEstimationEnabled)) {
427             rssiInnerEstimator = new RssiRadioSourceEstimator2D<>();
428         }
429     }
430 }