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