1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.estimation.measurements.gnss;
18
19 import org.hipparchus.geometry.euclidean.threed.Vector3D;
20 import org.hipparchus.stat.descriptive.moment.Mean;
21 import org.hipparchus.stat.descriptive.rank.Max;
22 import org.hipparchus.stat.descriptive.rank.Median;
23 import org.hipparchus.stat.descriptive.rank.Min;
24 import org.hipparchus.util.FastMath;
25 import org.junit.jupiter.api.Assertions;
26 import org.junit.jupiter.api.Test;
27 import org.orekit.estimation.Context;
28 import org.orekit.estimation.EstimationTestUtils;
29 import org.orekit.estimation.measurements.EstimatedMeasurementBase;
30 import org.orekit.estimation.measurements.ObservedMeasurement;
31 import org.orekit.orbits.CartesianOrbit;
32 import org.orekit.orbits.Orbit;
33 import org.orekit.orbits.OrbitType;
34 import org.orekit.orbits.PositionAngleType;
35 import org.orekit.propagation.BoundedPropagator;
36 import org.orekit.propagation.EphemerisGenerator;
37 import org.orekit.propagation.Propagator;
38 import org.orekit.propagation.SpacecraftState;
39 import org.orekit.propagation.conversion.NumericalPropagatorBuilder;
40 import org.orekit.time.AbsoluteDate;
41 import org.orekit.utils.Constants;
42 import org.orekit.utils.Differentiation;
43 import org.orekit.utils.ParameterDriver;
44 import org.orekit.utils.ParameterFunction;
45 import org.orekit.utils.TimeSpanMap.Span;
46 import org.orekit.utils.TimeStampedPVCoordinates;
47
48 import java.util.ArrayList;
49 import java.util.Comparator;
50 import java.util.List;
51 import java.util.Locale;
52
53 public class OneWayGNSSRangeRateTest {
54
55
56
57
58
59 @Test
60 public void testValues() {
61 boolean printResults = false;
62 if (printResults) {
63 System.out.println("\nTest One-way GNSS range rate Values\n");
64 }
65
66 this.genericTestValues(printResults);
67 }
68
69
70
71
72
73 @Test
74 public void testStateDerivatives() {
75
76 boolean printResults = false;
77 if (printResults) {
78 System.out.println("\nTest One-way GNSS range rate State Derivatives - Finite Differences Comparison\n");
79 }
80
81
82
83
84
85
86
87
88 double refErrorsPMedian = 5.6e-10;
89 double refErrorsPMean = 3.4e-09;
90 double refErrorsPMax = 6.8e-07;
91 double refErrorsVMedian = 6.6e-11;
92 double refErrorsVMean = 1.8e-10;
93 double refErrorsVMax = 7.1e-09;
94 this.genericTestStateDerivatives(printResults, 0,
95 refErrorsPMedian, refErrorsPMean, refErrorsPMax,
96 refErrorsVMedian, refErrorsVMean, refErrorsVMax);
97 }
98
99
100
101
102
103 @Test
104 public void testParameterDerivatives() {
105
106
107 boolean printResults = false;
108
109 if (printResults) {
110 System.out.println("\nTest One-way GNSS range rate Derivatives - Finite Differences Comparison\n");
111 }
112
113 double refErrorsMedian = 6.7e-8;
114 double refErrorsMean = 2.1e-7;
115 double refErrorsMax = 2.8e-6;
116 this.genericTestParameterDerivatives(printResults,
117 refErrorsMedian, refErrorsMean, refErrorsMax);
118
119 }
120
121
122
123
124
125 void genericTestValues(final boolean printResults) {
126
127 Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides");
128
129 final NumericalPropagatorBuilder propagatorBuilder =
130 context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true,
131 1.0e-6, 60.0, 0.001);
132
133
134 final TimeStampedPVCoordinates original = context.initialOrbit.getPVCoordinates();
135 final Orbit closeOrbit = new CartesianOrbit(new TimeStampedPVCoordinates(context.initialOrbit.getDate(),
136 original.getPosition().add(new Vector3D(1000, 2000, 3000)),
137 original.getVelocity().add(new Vector3D(-0.03, 0.01, 0.02))),
138 context.initialOrbit.getFrame(),
139 context.initialOrbit.getMu());
140 final Propagator closePropagator = EstimationTestUtils.createPropagator(closeOrbit,
141 propagatorBuilder);
142 final EphemerisGenerator generator = closePropagator.getEphemerisGenerator();
143 closePropagator.propagate(context.initialOrbit.getDate().shiftedBy(3.5 * closeOrbit.getKeplerianPeriod()));
144 final BoundedPropagator ephemeris = generator.getGeneratedEphemeris();
145 final Propagator propagator = EstimationTestUtils.createPropagator(context.initialOrbit,
146 propagatorBuilder);
147
148 final double localClockOffset = 0.14e-06;
149 final double localClockRate = -0.12e-10;
150 final double localClockAcceleration = 1.4e-13;
151 final double remoteClockOffset = 469.0e-06;
152 final double remoteClockRate = 33.0e-10;
153 final double remoteClockAcceleration = 0.5e-13;
154 final List<ObservedMeasurement<?>> measurements =
155 EstimationTestUtils.createMeasurements(propagator,
156 new OneWayGNSSRangeRateCreator(ephemeris,
157 localClockOffset, localClockRate, localClockAcceleration,
158 remoteClockOffset, remoteClockRate, remoteClockAcceleration),
159 1.0, 3.0, 300.0);
160
161
162
163 final List<Double> absoluteErrors = new ArrayList<>();
164 final List<Double> relativeErrors = new ArrayList<>();
165
166
167 propagator.setStepHandler(interpolator -> {
168
169 for (final ObservedMeasurement<?> measurement : measurements) {
170
171
172 if ((measurement.getDate().durationFrom(interpolator.getPreviousState().getDate()) > 0.) &&
173 (measurement.getDate().durationFrom(interpolator.getCurrentState().getDate()) <= 0.)
174 ) {
175
176
177
178
179
180 final double meanDelay = measurement.getObservedValue()[0] / Constants.SPEED_OF_LIGHT;
181 final AbsoluteDate date = measurement.getDate().shiftedBy(-0.75 * meanDelay);
182 final SpacecraftState state = interpolator.getInterpolatedState(date);
183
184
185 final double rangeObserved = measurement.getObservedValue()[0];
186 final EstimatedMeasurementBase<?> estimated = measurement.estimateWithoutDerivatives(new SpacecraftState[] {
187 state,
188 ephemeris.propagate(state.getDate())
189 });
190
191 final double rangeEstimated = estimated.getEstimatedValue()[0];
192 final double absoluteError = rangeEstimated-rangeObserved;
193 absoluteErrors.add(absoluteError);
194 relativeErrors.add(FastMath.abs(absoluteError)/FastMath.abs(rangeObserved));
195
196
197 if (printResults) {
198 final AbsoluteDate measurementDate = measurement.getDate();
199
200 System.out.format(Locale.US, "%-23s %-23s %19.6f %19.6f %13.6e %13.6e%n",
201 measurementDate, date,
202 rangeObserved, rangeEstimated,
203 FastMath.abs(rangeEstimated-rangeObserved),
204 FastMath.abs((rangeEstimated-rangeObserved)/rangeObserved));
205 }
206
207 }
208 }
209 });
210
211
212 if (printResults) {
213 System.out.format(Locale.US, "%-23s %-23s %19s %19s %19s %19s%n",
214 "Measurement Date", "State Date",
215 "range rate observed [m/s]", "range rate estimated [m/s]",
216 "Δrange rate[m/s]", "rel ΔRange rate");
217 }
218
219
220 propagator.propagate(context.initialOrbit.getDate());
221
222
223 measurements.sort(Comparator.naturalOrder());
224
225
226 propagator.propagate(measurements.get(measurements.size()-1).getDate());
227
228
229 final double[] absErrors = absoluteErrors.stream().mapToDouble(Double::doubleValue).toArray();
230 final double[] relErrors = relativeErrors.stream().mapToDouble(Double::doubleValue).toArray();
231
232
233 final double absErrorsMedian = new Median().evaluate(absErrors);
234 final double absErrorsMin = new Min().evaluate(absErrors);
235 final double absErrorsMax = new Max().evaluate(absErrors);
236 final double relErrorsMedian = new Median().evaluate(relErrors);
237 final double relErrorsMax = new Max().evaluate(relErrors);
238
239
240 if (printResults) {
241 System.out.println();
242 System.out.println("Absolute errors median: " + absErrorsMedian);
243 System.out.println("Absolute errors min : " + absErrorsMin);
244 System.out.println("Absolute errors max : " + absErrorsMax);
245 System.out.println("Relative errors median: " + relErrorsMedian);
246 System.out.println("Relative errors max : " + relErrorsMax);
247 }
248
249 Assertions.assertEquals(0.0, absErrorsMedian, 3.9e-9);
250 Assertions.assertEquals(0.0, absErrorsMin, 1.2e-11);
251 Assertions.assertEquals(0.0, absErrorsMax, 1.6e-8);
252 Assertions.assertEquals(0.0, relErrorsMedian, 1.1e-9);
253 Assertions.assertEquals(0.0, relErrorsMax, 1.1e-7);
254
255
256 Assertions.assertEquals(OneWayGNSSRangeRate.MEASUREMENT_TYPE, measurements.get(0).getMeasurementType());
257 }
258
259 void genericTestStateDerivatives(final boolean printResults, final int index,
260 final double refErrorsPMedian, final double refErrorsPMean, final double refErrorsPMax,
261 final double refErrorsVMedian, final double refErrorsVMean, final double refErrorsVMax) {
262
263 Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides");
264
265 final NumericalPropagatorBuilder propagatorBuilder =
266 context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true,
267 1.0e-6, 60.0, 0.001);
268
269
270 final TimeStampedPVCoordinates original = context.initialOrbit.getPVCoordinates();
271 final Orbit closeOrbit = new CartesianOrbit(new TimeStampedPVCoordinates(context.initialOrbit.getDate(),
272 original.getPosition().add(new Vector3D(1000, 2000, 3000)),
273 original.getVelocity().add(new Vector3D(-0.03, 0.01, 0.02))),
274 context.initialOrbit.getFrame(),
275 context.initialOrbit.getMu());
276 final Propagator closePropagator = EstimationTestUtils.createPropagator(closeOrbit,
277 propagatorBuilder);
278 final EphemerisGenerator generator = closePropagator.getEphemerisGenerator();
279 closePropagator.propagate(context.initialOrbit.getDate().shiftedBy(3.5 * closeOrbit.getKeplerianPeriod()));
280 final BoundedPropagator ephemeris = generator.getGeneratedEphemeris();
281 final Propagator propagator = EstimationTestUtils.createPropagator(context.initialOrbit,
282 propagatorBuilder);
283
284 final double localClockOffset = 0.14e-06;
285 final double localClockRate = -0.12e-10;
286 final double localClockAcceleration = 1.4e-13;
287 final double remoteClockOffset = 469.0e-06;
288 final double remoteClockRate = 33.0e-10;
289 final double remoteClockAcceleration = 0.5e-13;
290 final List<ObservedMeasurement<?>> measurements =
291 EstimationTestUtils.createMeasurements(propagator,
292 new OneWayGNSSRangeRateCreator(ephemeris,
293 localClockOffset, localClockRate, localClockAcceleration,
294 remoteClockOffset, remoteClockRate, remoteClockAcceleration),
295 1.0, 3.0, 300.0);
296
297
298
299 final List<Double> errorsP = new ArrayList<>();
300 final List<Double> errorsV = new ArrayList<>();
301
302
303 propagator.setStepHandler(interpolator -> {
304
305 for (final ObservedMeasurement<?> measurement : measurements) {
306
307
308 if ((measurement.getDate().durationFrom(interpolator.getPreviousState().getDate()) > 0.) &&
309 (measurement.getDate().durationFrom(interpolator.getCurrentState().getDate()) <= 0.)
310 ) {
311
312
313
314
315
316
317 final double meanDelay = measurement.getObservedValue()[0] / Constants.SPEED_OF_LIGHT;
318 final AbsoluteDate date = measurement.getDate().shiftedBy(-0.9 * meanDelay);
319 final SpacecraftState[] states = {
320 interpolator.getInterpolatedState(date),
321 ephemeris.propagate(date)
322 };
323 final double[][] jacobian = measurement.estimate(0, 0, states).getStateDerivatives(index);
324
325
326 final double[][] jacobianRef;
327
328
329 jacobianRef = Differentiation.differentiate(state -> {
330 final SpacecraftState[] s = states.clone();
331 s[index] = state;
332 return measurement.estimateWithoutDerivatives(s).getEstimatedValue();
333 }, measurement.getDimension(), propagator.getAttitudeProvider(),
334 OrbitType.CARTESIAN, PositionAngleType.TRUE, 8.0, 5).value(states[index]);
335
336 Assertions.assertEquals(jacobianRef.length, jacobian.length);
337 Assertions.assertEquals(jacobianRef[0].length, jacobian[0].length);
338
339
340 double [][] dJacobian = new double[jacobian.length][jacobian[0].length];
341 double [][] dJacobianRelative = new double[jacobian.length][jacobian[0].length];
342 for (int i = 0; i < jacobian.length; ++i) {
343 for (int j = 0; j < jacobian[i].length; ++j) {
344 dJacobian[i][j] = jacobian[i][j] - jacobianRef[i][j];
345 dJacobianRelative[i][j] = FastMath.abs(dJacobian[i][j]/jacobianRef[i][j]);
346
347 if (j < 3) { errorsP.add(dJacobianRelative[i][j]);
348 } else { errorsV.add(dJacobianRelative[i][j]); }
349 }
350 }
351
352 if (printResults) {
353 System.out.format(Locale.US, "%-23s %-23s " +
354 "%10.3e %10.3e %10.3e " +
355 "%10.3e %10.3e %10.3e " +
356 "%10.3e %10.3e %10.3e " +
357 "%10.3e %10.3e %10.3e%n",
358 measurement.getDate(), date,
359 dJacobian[0][0], dJacobian[0][1], dJacobian[0][2],
360 dJacobian[0][3], dJacobian[0][4], dJacobian[0][5],
361 dJacobianRelative[0][0], dJacobianRelative[0][1], dJacobianRelative[0][2],
362 dJacobianRelative[0][3], dJacobianRelative[0][4], dJacobianRelative[0][5]);
363 }
364 }
365 }
366 });
367
368
369 if (printResults) {
370 System.out.format(Locale.US, "%-23s %-23s " +
371 "%10s %10s %10s " +
372 "%10s %10s %10s " +
373 "%10s %10s %10s " +
374 "%10s %10s %10s%n",
375 "Measurement Date", "State Date",
376 "ΔdPx", "ΔdPy", "ΔdPz", "ΔdVx", "ΔdVy", "ΔdVz",
377 "rel ΔdPx", "rel ΔdPy", "rel ΔdPz",
378 "rel ΔdVx", "rel ΔdVy", "rel ΔdVz");
379 }
380
381
382 propagator.propagate(context.initialOrbit.getDate());
383
384
385 measurements.sort(Comparator.naturalOrder());
386
387
388 propagator.propagate(measurements.get(measurements.size()-1).getDate());
389
390
391 final double[] relErrorsP = errorsP.stream().mapToDouble(Double::doubleValue).toArray();
392 final double[] relErrorsV = errorsV.stream().mapToDouble(Double::doubleValue).toArray();
393
394 final double errorsPMedian = new Median().evaluate(relErrorsP);
395 final double errorsPMean = new Mean().evaluate(relErrorsP);
396 final double errorsPMax = new Max().evaluate(relErrorsP);
397 final double errorsVMedian = new Median().evaluate(relErrorsV);
398 final double errorsVMean = new Mean().evaluate(relErrorsV);
399 final double errorsVMax = new Max().evaluate(relErrorsV);
400
401
402 if (printResults) {
403 System.out.println();
404 System.out.format(Locale.US, "Relative errors dR/dP -> Median: %6.3e / Mean: %6.3e / Max: %6.3e%n",
405 errorsPMedian, errorsPMean, errorsPMax);
406 System.out.format(Locale.US, "Relative errors dR/dV -> Median: %6.3e / Mean: %6.3e / Max: %6.3e%n",
407 errorsVMedian, errorsVMean, errorsVMax);
408 }
409
410 Assertions.assertEquals(0.0, errorsPMedian, refErrorsPMedian);
411 Assertions.assertEquals(0.0, errorsPMean, refErrorsPMean);
412 Assertions.assertEquals(0.0, errorsPMax, refErrorsPMax);
413 Assertions.assertEquals(0.0, errorsVMedian, refErrorsVMedian);
414 Assertions.assertEquals(0.0, errorsVMean, refErrorsVMean);
415 Assertions.assertEquals(0.0, errorsVMax, refErrorsVMax);
416 }
417
418 void genericTestParameterDerivatives(final boolean printResults,
419 final double refErrorsMedian, final double refErrorsMean, final double refErrorsMax) {
420
421 Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides");
422
423 final NumericalPropagatorBuilder propagatorBuilder =
424 context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true,
425 1.0e-6, 60.0, 0.001);
426
427
428 final TimeStampedPVCoordinates original = context.initialOrbit.getPVCoordinates();
429 final Orbit closeOrbit = new CartesianOrbit(new TimeStampedPVCoordinates(context.initialOrbit.getDate(),
430 original.getPosition().add(new Vector3D(1000, 2000, 3000)),
431 original.getVelocity().add(new Vector3D(-0.03, 0.01, 0.02))),
432 context.initialOrbit.getFrame(),
433 context.initialOrbit.getMu());
434 final Propagator closePropagator = EstimationTestUtils.createPropagator(closeOrbit, propagatorBuilder);
435 final EphemerisGenerator generator = closePropagator.getEphemerisGenerator();
436 closePropagator.propagate(context.initialOrbit.getDate().shiftedBy(3.5 * closeOrbit.getKeplerianPeriod()));
437 final BoundedPropagator ephemeris = generator.getGeneratedEphemeris();
438
439
440 final double localClockOffset = 0.14e-06;
441 final double localClockRate = -0.12e-10;
442 final double localClockAcceleration = 1.4e-13;
443 final double remoteClockOffset = 469.0e-06;
444 final double remoteClockRate = 33.0e-10;
445 final double remoteClockAcceleration = 0.5e-13;
446 final OneWayGNSSRangeRateCreator creator = new OneWayGNSSRangeRateCreator(ephemeris,
447 localClockOffset, localClockRate, localClockAcceleration,
448 remoteClockOffset, remoteClockRate, remoteClockAcceleration);
449 creator.getLocalSatellite().getClockOffsetDriver().setSelected(true);
450
451 final Propagator propagator = EstimationTestUtils.createPropagator(context.initialOrbit,
452 propagatorBuilder);
453 final List<ObservedMeasurement<?>> measurements =
454 EstimationTestUtils.createMeasurements(propagator, creator, 1.0, 3.0, 300.0);
455
456
457 final List<Double> relErrorList = new ArrayList<>();
458
459
460 propagator.setStepHandler(interpolator -> {
461
462 for (final ObservedMeasurement<?> measurement : measurements) {
463
464
465 if ((measurement.getDate().durationFrom(interpolator.getPreviousState().getDate()) > 0.) &&
466 (measurement.getDate().durationFrom(interpolator.getCurrentState().getDate()) <= 0.)) {
467
468
469
470
471
472
473
474
475 final double meanDelay = measurement.getObservedValue()[0] / Constants.SPEED_OF_LIGHT;
476 final AbsoluteDate date = measurement.getDate().shiftedBy(-0.75 * meanDelay);
477 final SpacecraftState[] states = {
478 interpolator.getInterpolatedState(date),
479 ephemeris.propagate(date)
480 };
481 final ParameterDriver[] drivers = new ParameterDriver[] {
482 measurement.getSatellites().get(0).getClockOffsetDriver(),
483 };
484
485 for (int i = 0; i < drivers.length; ++i) {
486 for (Span<String> span = drivers[i].getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
487
488 final double[] gradient = measurement.estimate(0, 0, states).getParameterDerivatives(drivers[i], span.getStart());
489 Assertions.assertEquals(1, measurement.getDimension());
490 Assertions.assertEquals(1, gradient.length);
491
492
493 final ParameterFunction dMkdP =
494 Differentiation.differentiate(new ParameterFunction() {
495
496 @Override
497 public double value(final ParameterDriver parameterDriver, final AbsoluteDate date) {
498 return measurement.
499 estimateWithoutDerivatives(states).
500 getEstimatedValue()[0];
501 }
502 }, 5, 10.0 * drivers[i].getScale());
503 final double ref = dMkdP.value(drivers[i], date);
504
505 if (printResults) {
506 System.out.format(Locale.US, "%10.3e %10.3e ", gradient[0]-ref, FastMath.abs((gradient[0]-ref)/ref));
507 }
508
509 final double relError = FastMath.abs((ref-gradient[0])/ref);
510 relErrorList.add(relError);
511 }
512 }
513 if (printResults) {
514 System.out.format(Locale.US, "%n");
515 }
516
517 }
518 }
519 });
520
521
522 propagator.propagate(context.initialOrbit.getDate());
523
524
525 measurements.sort(Comparator.naturalOrder());
526
527
528 if (printResults) {
529 System.out.format(Locale.US, "%-15s %-23s %-23s " +
530 "%10s %10s %10s %10s %10s %10s %10s %10s %10s %10s%n",
531 "Station", "Measurement Date", "State Date",
532 "Δt", "rel Δt",
533 "ΔdQx", "rel ΔdQx",
534 "ΔdQy", "rel ΔdQy",
535 "ΔdQz", "rel ΔdQz",
536 "Δtsat", "rel Δtsat");
537 }
538
539
540 propagator.propagate(measurements.get(measurements.size()-1).getDate());
541
542
543 final double[] relErrors = relErrorList.stream().mapToDouble(Double::doubleValue).toArray();
544
545
546 final double relErrorsMedian = new Median().evaluate(relErrors);
547 final double relErrorsMean = new Mean().evaluate(relErrors);
548 final double relErrorsMax = new Max().evaluate(relErrors);
549
550
551 if (printResults) {
552 System.out.println();
553 System.out.format(Locale.US, "Relative errors dR/dQ -> Median: %6.3e / Mean: %6.3e / Max: %6.3e%n",
554 relErrorsMedian, relErrorsMean, relErrorsMax);
555 }
556
557 Assertions.assertEquals(0.0, relErrorsMedian, refErrorsMedian);
558 Assertions.assertEquals(0.0, relErrorsMean, refErrorsMean);
559 Assertions.assertEquals(0.0, relErrorsMax, refErrorsMax);
560
561 }
562
563 }