1   /* Copyright 2002-2025 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.estimation.measurements.modifiers;
18  
19  import java.util.List;
20  
21  import org.hipparchus.geometry.euclidean.threed.Vector3D;
22  import org.hipparchus.stat.descriptive.DescriptiveStatistics;
23  import org.junit.jupiter.api.Assertions;
24  import org.junit.jupiter.api.Test;
25  import org.orekit.attitudes.LofOffset;
26  import org.orekit.estimation.Context;
27  import org.orekit.estimation.EstimationTestUtils;
28  import org.orekit.estimation.measurements.EstimatedMeasurementBase;
29  import org.orekit.estimation.measurements.EstimationModifier;
30  import org.orekit.estimation.measurements.ObservedMeasurement;
31  import org.orekit.estimation.measurements.gnss.OneWayGNSSRange;
32  import org.orekit.estimation.measurements.gnss.OneWayGNSSRangeCreator;
33  import org.orekit.frames.LOFType;
34  import org.orekit.orbits.CartesianOrbit;
35  import org.orekit.orbits.Orbit;
36  import org.orekit.orbits.OrbitType;
37  import org.orekit.orbits.PositionAngleType;
38  import org.orekit.propagation.BoundedPropagator;
39  import org.orekit.propagation.EphemerisGenerator;
40  import org.orekit.propagation.Propagator;
41  import org.orekit.propagation.SpacecraftState;
42  import org.orekit.propagation.conversion.NumericalPropagatorBuilder;
43  import org.orekit.utils.TimeStampedPVCoordinates;
44  
45  public class ShapiroOneWayGNSSRangeModifierTest {
46  
47      @Test
48      public void testShapiro() {
49          doTestShapiro(0.000047764, 0.000086953, 0.000164659);
50      }
51  
52      private void doTestShapiro(final double expectedMin, final double expectedMean, final double expectedMax) {
53  
54          Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides");
55  
56          final NumericalPropagatorBuilder propagatorBuilder =
57                          context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true,
58                                                1.0e-6, 60.0, 0.001);
59          propagatorBuilder.setAttitudeProvider(new LofOffset(propagatorBuilder.getFrame(), LOFType.LVLH));
60  
61          // create perfect inter-satellites range measurements without antenna offset
62          final TimeStampedPVCoordinates original = context.initialOrbit.getPVCoordinates();
63          final Orbit closeOrbit = new CartesianOrbit(new TimeStampedPVCoordinates(context.initialOrbit.getDate(),
64                                                                                   original.getPosition().add(new Vector3D(1000, 2000, 3000)),
65                                                                                   original.getVelocity().add(new Vector3D(-0.03, 0.01, 0.02))),
66                                                      context.initialOrbit.getFrame(),
67                                                      context.initialOrbit.getMu());
68          final Propagator closePropagator = EstimationTestUtils.createPropagator(closeOrbit,
69                                                                                  propagatorBuilder);
70          final EphemerisGenerator generator = closePropagator.getEphemerisGenerator();
71          closePropagator.propagate(context.initialOrbit.getDate().shiftedBy(3.5 * closeOrbit.getKeplerianPeriod()));
72          final BoundedPropagator ephemeris = generator.getGeneratedEphemeris();
73          final Propagator p1 = EstimationTestUtils.createPropagator(context.initialOrbit,
74                                                                             propagatorBuilder);
75          final double localClockOffset  = 0.137e-6;
76          final double remoteClockOffset = 469.0e-6;
77          List<ObservedMeasurement<?>> measurements =
78                          EstimationTestUtils.createMeasurements(p1,
79                                                                 new OneWayGNSSRangeCreator(ephemeris,
80                                                                                            localClockOffset,
81                                                                                            remoteClockOffset,
82                                                                                            Vector3D.ZERO,
83                                                                                            Vector3D.ZERO),
84                                                                 1.0, 3.0, 300.0);
85  
86          final ShapiroOneWayGNSSRangeModifier modifier = new ShapiroOneWayGNSSRangeModifier(context.initialOrbit.getMu());
87          final Propagator p3 = EstimationTestUtils.createPropagator(context.initialOrbit,
88                                                                     propagatorBuilder);
89          DescriptiveStatistics stat = new DescriptiveStatistics();
90          for (int i = 0; i < measurements.size(); ++i) {
91              OneWayGNSSRange sr = (OneWayGNSSRange) measurements.get(i);
92              SpacecraftState[] states = new SpacecraftState[] {
93                  p3.propagate(sr.getDate()),
94                  ephemeris.propagate(sr.getDate())
95              };
96              EstimatedMeasurementBase<OneWayGNSSRange> evalNoMod = sr.estimateWithoutDerivatives(states);
97  
98              // add modifier
99              sr.addModifier(modifier);
100             boolean found = false;
101             for (final EstimationModifier<OneWayGNSSRange> existing : sr.getModifiers()) {
102                 found = found || existing == modifier;
103             }
104             Assertions.assertTrue(found);
105             EstimatedMeasurementBase<OneWayGNSSRange> eval = sr.estimateWithoutDerivatives(states);
106 
107             stat.addValue(eval.getEstimatedValue()[0] - evalNoMod.getEstimatedValue()[0]);
108             Assertions.assertEquals(1,
109                                     eval.getAppliedEffects().entrySet().stream().
110                                     filter(e -> e.getKey().getEffectName().equals("Shapiro")).count());
111 
112         }
113 
114         Assertions.assertEquals(expectedMin,  stat.getMin(),  1.0e-9);
115         Assertions.assertEquals(expectedMean, stat.getMean(), 1.0e-9);
116         Assertions.assertEquals(expectedMax,  stat.getMax(),  1.0e-9);
117 
118     }
119 
120 }