1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.irurueta.navigation.gnss;
17
18 import com.irurueta.algebra.AlgebraException;
19 import com.irurueta.algebra.Matrix;
20 import com.irurueta.algebra.Utils;
21 import com.irurueta.navigation.frames.CoordinateTransformation;
22 import com.irurueta.navigation.geodesic.Constants;
23 import com.irurueta.units.Time;
24 import com.irurueta.units.TimeConverter;
25 import com.irurueta.units.TimeUnit;
26
27 import java.util.Collection;
28
29
30
31
32
33
34
35
36
37
38 public class GNSSKalmanEpochEstimator {
39
40
41
42
43 public static final double SPEED_OF_LIGHT = Constants.SPEED_OF_LIGHT;
44
45
46
47
48 public static final double EARTH_ROTATION_RATE = Constants.EARTH_ROTATION_RATE;
49
50
51
52
53 private static final int MATRIX_SIZE = 8;
54
55
56
57
58
59 private GNSSKalmanEpochEstimator() {
60 }
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 public static GNSSKalmanState estimate(
76 final Collection<GNSSMeasurement> measurements, final Time propagationInterval,
77 final GNSSKalmanState previousState, final GNSSKalmanConfig config) throws AlgebraException {
78 return estimate(measurements, convertTime(propagationInterval), previousState, config);
79 }
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 public static void estimate(final Collection<GNSSMeasurement> measurements,
96 final Time propagationInterval,
97 final GNSSKalmanState previousState,
98 final GNSSKalmanConfig config,
99 final GNSSKalmanState result) throws AlgebraException {
100 estimate(measurements, convertTime(propagationInterval), previousState, config, result);
101 }
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 public static void estimate(final Collection<GNSSMeasurement> measurements,
122 final Time propagationInterval,
123 final GNSSEstimation previousEstimation,
124 final Matrix previousCovariance,
125 final GNSSKalmanConfig config,
126 final GNSSEstimation updatedEstimation,
127 final Matrix updatedCovariance) throws AlgebraException {
128 estimate(measurements, convertTime(propagationInterval), previousEstimation, previousCovariance, config,
129 updatedEstimation, updatedCovariance);
130 }
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145 public static GNSSKalmanState estimate(
146 final Collection<GNSSMeasurement> measurements,
147 final double propagationInterval,
148 final GNSSKalmanState previousState,
149 final GNSSKalmanConfig config) throws AlgebraException {
150 final var result = new GNSSKalmanState();
151 estimate(measurements, propagationInterval, previousState, config, result);
152 return result;
153 }
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169 public static void estimate(final Collection<GNSSMeasurement> measurements,
170 final double propagationInterval,
171 final GNSSKalmanState previousState,
172 final GNSSKalmanConfig config,
173 final GNSSKalmanState result) throws AlgebraException {
174 final var resultEstimation = new GNSSEstimation();
175 final var resultCovariance = new Matrix(GNSSEstimation.NUM_PARAMETERS, GNSSEstimation.NUM_PARAMETERS);
176
177 estimate(measurements, propagationInterval, previousState.getEstimation(), previousState.getCovariance(),
178 config, resultEstimation, resultCovariance);
179
180 result.setEstimation(resultEstimation);
181 result.setCovariance(resultCovariance);
182 }
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202 @SuppressWarnings("DuplicatedCode")
203 public static void estimate(final Collection<GNSSMeasurement> measurements,
204 final double propagationInterval,
205 final GNSSEstimation previousEstimation,
206 final Matrix previousCovariance,
207 final GNSSKalmanConfig config,
208 final GNSSEstimation updatedEstimation,
209 final Matrix updatedCovariance) throws AlgebraException {
210
211 if (previousCovariance.getRows() != GNSSEstimation.NUM_PARAMETERS
212 || previousCovariance.getColumns() != GNSSEstimation.NUM_PARAMETERS) {
213 throw new IllegalArgumentException();
214 }
215
216
217
218
219 final var phiMatrix = Matrix.identity(MATRIX_SIZE, MATRIX_SIZE);
220 phiMatrix.setElementAt(0, 3, propagationInterval);
221 phiMatrix.setElementAt(1, 4, propagationInterval);
222 phiMatrix.setElementAt(2, 5, propagationInterval);
223 phiMatrix.setElementAt(6, 7, propagationInterval);
224
225
226 final var propagationInterval2 = propagationInterval * propagationInterval;
227 final var propagationInterval3 = propagationInterval2 * propagationInterval;
228 final var accelerationPSD = config.getAccelerationPSD();
229 final var clockFrequencyPSD = config.getClockFrequencyPSD();
230 final var clockPhasePSD = config.getClockPhasePSD();
231
232 final var value1 = accelerationPSD * propagationInterval3 / 3.0;
233 final var value2 = accelerationPSD * propagationInterval2 / 2.0;
234 final var value3 = accelerationPSD * propagationInterval;
235 final var value4 = clockFrequencyPSD * propagationInterval3 / 3.0 + clockPhasePSD * propagationInterval;
236 final var value5 = clockFrequencyPSD * propagationInterval2 / 2.0;
237 final var value6 = clockFrequencyPSD * propagationInterval;
238
239 final var qMatrix = new Matrix(MATRIX_SIZE, MATRIX_SIZE);
240 qMatrix.setElementAt(0, 0, value1);
241 qMatrix.setElementAt(1, 1, value1);
242 qMatrix.setElementAt(2, 2, value1);
243
244 qMatrix.setElementAt(0, 3, value2);
245 qMatrix.setElementAt(1, 4, value2);
246 qMatrix.setElementAt(2, 5, value2);
247
248 qMatrix.setElementAt(3, 0, value2);
249 qMatrix.setElementAt(4, 1, value2);
250 qMatrix.setElementAt(5, 2, value2);
251
252 qMatrix.setElementAt(3, 3, value3);
253 qMatrix.setElementAt(4, 4, value3);
254 qMatrix.setElementAt(5, 5, value3);
255
256 qMatrix.setElementAt(6, 6, value4);
257 qMatrix.setElementAt(6, 7, value5);
258 qMatrix.setElementAt(7, 6, value5);
259 qMatrix.setElementAt(7, 7, value6);
260
261
262
263 final var xEstOld = previousEstimation.asMatrix();
264 final var xEstPropagated = phiMatrix.multiplyAndReturnNew(xEstOld);
265 final var propagatedVelocity = xEstPropagated.getSubmatrix(
266 3, 0, 5, 0);
267 final var propagatedPosition = xEstPropagated.getSubmatrix(
268 0, 0, 2, 0);
269
270
271 final var pMatrixPropagated = phiMatrix.multiplyAndReturnNew(previousCovariance);
272 phiMatrix.transpose();
273 pMatrixPropagated.multiply(phiMatrix);
274 pMatrixPropagated.add(qMatrix);
275
276
277
278
279 final var omegaIe = Utils.skewMatrix(new double[]{0.0, 0.0, EARTH_ROTATION_RATE});
280
281 final var numberOfMeasurements = measurements.size();
282 final var uAseT = new Matrix(numberOfMeasurements, 3);
283 final var predMeas = new Matrix(numberOfMeasurements, 2);
284
285 final var cei = Matrix.identity(CoordinateTransformation.ROWS, CoordinateTransformation.COLS);
286 final var satellitePosition = new Matrix(CoordinateTransformation.ROWS, 1);
287 final var satelliteVelocity = new Matrix(CoordinateTransformation.ROWS, 1);
288 final var deltaR = new Matrix(CoordinateTransformation.ROWS, 1);
289 final var tmp1 = new Matrix(CoordinateTransformation.ROWS, 1);
290 final var tmp2 = new Matrix(CoordinateTransformation.ROWS, 1);
291 final var tmp3 = new Matrix(CoordinateTransformation.ROWS, 1);
292 final var tmp4 = new Matrix(CoordinateTransformation.ROWS, 1);
293 final var tmp5 = new Matrix(CoordinateTransformation.ROWS, 1);
294 final var tmp6 = new Matrix(CoordinateTransformation.ROWS, 1);
295 final var tmp7 = new Matrix(1, CoordinateTransformation.ROWS);
296
297
298 var j = 0;
299 for (final var measurement : measurements) {
300
301 final var measX = measurement.getX();
302 final var measY = measurement.getY();
303 final var measZ = measurement.getZ();
304
305 final var deltaX = measX - xEstPropagated.getElementAtIndex(0);
306 final var deltaY = measY - xEstPropagated.getElementAtIndex(1);
307 final var deltaZ = measZ - xEstPropagated.getElementAtIndex(2);
308 final var approxRange = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ);
309
310
311 final var ceiValue = EARTH_ROTATION_RATE * approxRange / SPEED_OF_LIGHT;
312 cei.setElementAt(0, 1, ceiValue);
313 cei.setElementAt(1, 0, -ceiValue);
314
315
316 satellitePosition.setElementAtIndex(0, measX);
317 satellitePosition.setElementAtIndex(1, measY);
318 satellitePosition.setElementAtIndex(2, measZ);
319
320 cei.multiply(satellitePosition, deltaR);
321 for (var i = 0; i < CoordinateTransformation.ROWS; i++) {
322 deltaR.setElementAtIndex(i, deltaR.getElementAtIndex(i) - xEstPropagated.getElementAtIndex(i));
323 }
324 final var range = Utils.normF(deltaR);
325
326 predMeas.setElementAt(j, 0, range + xEstPropagated.getElementAtIndex(6));
327
328
329 for (var i = 0; i < CoordinateTransformation.ROWS; i++) {
330 uAseT.setElementAt(j, i, deltaR.getElementAtIndex(i) / range);
331 }
332
333
334 satelliteVelocity.setElementAtIndex(0, measurement.getVx());
335 satelliteVelocity.setElementAtIndex(1, measurement.getVy());
336 satelliteVelocity.setElementAtIndex(2, measurement.getVz());
337
338 omegaIe.multiply(satellitePosition, tmp1);
339 satelliteVelocity.add(tmp1, tmp2);
340 cei.multiply(tmp2, tmp3);
341
342 omegaIe.multiply(propagatedPosition, tmp4);
343 propagatedVelocity.add(tmp4, tmp6);
344
345 tmp3.subtract(tmp6, tmp5);
346
347 uAseT.getSubmatrix(j, 0, j, 2, tmp7);
348
349 final var rangeRate = Utils.dotProduct(tmp7, tmp5);
350
351 predMeas.setElementAt(j, 1, rangeRate + xEstPropagated.getElementAtIndex(7));
352
353 j++;
354 }
355
356
357 final var h = new Matrix(2 * numberOfMeasurements, GNSSEstimation.NUM_PARAMETERS);
358 for (int j1 = 0, j2 = numberOfMeasurements; j1 < numberOfMeasurements; j1++, j2++) {
359 for (int i1 = 0, i2 = 3; i1 < CoordinateTransformation.ROWS; i1++, i2++) {
360 final var value = -uAseT.getElementAt(j1, i1);
361
362 h.setElementAt(j1, i1, value);
363 h.setElementAt(j2, i2, value);
364 }
365 h.setElementAt(j1, 6, 1.0);
366 h.setElementAt(j2, 7, 1.0);
367 }
368
369
370
371 final var pseudoRangeSD = config.getPseudoRangeSD();
372 final var pseudoRangeSD2 = pseudoRangeSD * pseudoRangeSD;
373 final var rangeRateSD = config.getRangeRateSD();
374 final var rangeRateSD2 = rangeRateSD * rangeRateSD;
375 final var r = new Matrix(2 * numberOfMeasurements, 2 * numberOfMeasurements);
376 for (int i1 = 0, i2 = numberOfMeasurements; i1 < numberOfMeasurements; i1++, i2++) {
377 r.setElementAt(i1, i1, pseudoRangeSD2);
378 r.setElementAt(i2, i2, rangeRateSD2);
379 }
380
381
382 final var hTransposed = h.transposeAndReturnNew();
383 final var tmp8 = h.multiplyAndReturnNew(pMatrixPropagated.multiplyAndReturnNew(hTransposed));
384 tmp8.add(r);
385 final var tmp9 = Utils.inverse(tmp8);
386 final var k = pMatrixPropagated.multiplyAndReturnNew(hTransposed);
387 k.multiply(tmp9);
388
389
390 final var deltaZ = new Matrix(2 * numberOfMeasurements, 1);
391 var i1 = 0;
392 var i2 = numberOfMeasurements;
393 for (final var measurement : measurements) {
394 deltaZ.setElementAtIndex(i1, measurement.getPseudoRange() - predMeas.getElementAt(i1, 0));
395 deltaZ.setElementAtIndex(i2, measurement.getPseudoRate() - predMeas.getElementAt(i1, 1));
396 i1++;
397 i2++;
398 }
399
400
401 xEstPropagated.add(k.multiplyAndReturnNew(deltaZ));
402
403
404 updatedEstimation.fromMatrix(xEstPropagated);
405
406
407 if (updatedCovariance.getRows() != GNSSEstimation.NUM_PARAMETERS
408 || updatedCovariance.getColumns() != GNSSEstimation.NUM_PARAMETERS) {
409 updatedCovariance.resize(GNSSEstimation.NUM_PARAMETERS, GNSSEstimation.NUM_PARAMETERS);
410 }
411 Matrix.identity(updatedCovariance);
412 k.multiply(h);
413 updatedCovariance.subtract(k);
414 updatedCovariance.multiply(pMatrixPropagated);
415 }
416
417
418
419
420
421
422
423 private static double convertTime(final Time time) {
424 return TimeConverter.convert(time.getValue().doubleValue(), time.getUnit(), TimeUnit.SECOND);
425 }
426 }