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 }