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.InterSatellitesPhase;
32  import org.orekit.estimation.measurements.gnss.InterSatellitesPhaseMeasurementCreator;
33  import org.orekit.frames.LOFType;
34  import org.orekit.gnss.PredefinedGnssSignal;
35  import org.orekit.gnss.RadioWave;
36  import org.orekit.orbits.CartesianOrbit;
37  import org.orekit.orbits.Orbit;
38  import org.orekit.orbits.OrbitType;
39  import org.orekit.orbits.PositionAngleType;
40  import org.orekit.propagation.BoundedPropagator;
41  import org.orekit.propagation.EphemerisGenerator;
42  import org.orekit.propagation.Propagator;
43  import org.orekit.propagation.SpacecraftState;
44  import org.orekit.propagation.conversion.NumericalPropagatorBuilder;
45  import org.orekit.utils.TimeStampedPVCoordinates;
46  
47  public class ShapiroInterSatellitePhaseModifierTest {
48  
49      /** Radio wave of the measurements. */
50      private static final RadioWave RADIO_WAVE = PredefinedGnssSignal.G01;
51  
52      @Test
53      public void testShapiroOneWay() {
54          doTestShapiro(0.000047764, 0.000086953, 0.000164659);
55      }
56  
57      private void doTestShapiro(final double expectedMin, final double expectedMean, final double expectedMax) {
58  
59          Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides");
60  
61          final NumericalPropagatorBuilder propagatorBuilder =
62                          context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true,
63                                                1.0e-6, 60.0, 0.001);
64          propagatorBuilder.setAttitudeProvider(new LofOffset(propagatorBuilder.getFrame(), LOFType.LVLH));
65  
66          // create perfect inter-satellites phase measurements without antenna offset
67          final TimeStampedPVCoordinates original = context.initialOrbit.getPVCoordinates();
68          final Orbit closeOrbit = new CartesianOrbit(new TimeStampedPVCoordinates(context.initialOrbit.getDate(),
69                                                                                   original.getPosition().add(new Vector3D(1000, 2000, 3000)),
70                                                                                   original.getVelocity().add(new Vector3D(-0.03, 0.01, 0.02))),
71                                                      context.initialOrbit.getFrame(),
72                                                      context.initialOrbit.getMu());
73          final Propagator closePropagator = EstimationTestUtils.createPropagator(closeOrbit,
74                                                                                  propagatorBuilder);
75          final EphemerisGenerator generator = closePropagator.getEphemerisGenerator();
76          closePropagator.propagate(context.initialOrbit.getDate().shiftedBy(3.5 * closeOrbit.getKeplerianPeriod()));
77          final BoundedPropagator ephemeris = generator.getGeneratedEphemeris();
78          final Propagator p1 = EstimationTestUtils.createPropagator(context.initialOrbit,
79                                                                             propagatorBuilder);
80          final int    ambiguity         = 1234;
81          final double localClockOffset  = 0.137e-6;
82          final double remoteClockOffset = 469.0e-6;
83          List<ObservedMeasurement<?>> measurements =
84                          EstimationTestUtils.createMeasurements(p1,
85                                                                 new InterSatellitesPhaseMeasurementCreator(ephemeris,
86                                                                                                            RADIO_WAVE,
87                                                                                                            ambiguity,
88                                                                                                            localClockOffset,
89                                                                                                            remoteClockOffset,
90                                                                                                            Vector3D.ZERO,
91                                                                                                            Vector3D.ZERO),
92                                                                 1.0, 3.0, 300.0);
93  
94          final ShapiroInterSatellitePhaseModifier modifier = new ShapiroInterSatellitePhaseModifier(context.initialOrbit.getMu());
95          final Propagator p3 = EstimationTestUtils.createPropagator(context.initialOrbit,
96                                                                     propagatorBuilder);
97          DescriptiveStatistics stat = new DescriptiveStatistics();
98          for (int i = 0; i < measurements.size(); ++i) {
99              InterSatellitesPhase sr = (InterSatellitesPhase) measurements.get(i);
100             SpacecraftState[] states = new SpacecraftState[] {
101                 p3.propagate(sr.getDate()),
102                 ephemeris.propagate(sr.getDate())
103             };
104             EstimatedMeasurementBase<InterSatellitesPhase> evalNoMod = sr.estimateWithoutDerivatives(states);
105 
106             // add modifier
107             sr.addModifier(modifier);
108             boolean found = false;
109             for (final EstimationModifier<InterSatellitesPhase> existing : sr.getModifiers()) {
110                 found = found || existing == modifier;
111             }
112             Assertions.assertTrue(found);
113             EstimatedMeasurementBase<InterSatellitesPhase> eval = sr.estimateWithoutDerivatives(states);
114 
115             stat.addValue(eval.getEstimatedValue()[0] - evalNoMod.getEstimatedValue()[0]);
116             Assertions.assertEquals(1,
117                                     eval.getAppliedEffects().entrySet().stream().
118                                     filter(e -> e.getKey().getEffectName().equals("Shapiro")).count());
119         }
120 
121         // wavelength
122         final double wavelength = ((InterSatellitesPhase) measurements.get(0)).getWavelength();
123 
124         Assertions.assertEquals(expectedMin,  stat.getMin() * wavelength,  1.0e-9);
125         Assertions.assertEquals(expectedMean, stat.getMean() * wavelength, 1.0e-9);
126         Assertions.assertEquals(expectedMax,  stat.getMax() * wavelength,  1.0e-9);
127 
128     }
129 
130 }
131 
132