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