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.util.FastMath;
23  import org.hipparchus.util.MathUtils;
24  import org.junit.jupiter.api.Assertions;
25  import org.junit.jupiter.api.Test;
26  import org.orekit.attitudes.LofOffset;
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.GroundStation;
31  import org.orekit.estimation.measurements.ObservedMeasurement;
32  import org.orekit.estimation.measurements.gnss.Phase;
33  import org.orekit.estimation.measurements.gnss.PhaseMeasurementCreator;
34  import org.orekit.frames.LOFType;
35  import org.orekit.gnss.PredefinedGnssSignal;
36  import org.orekit.gnss.antenna.FrequencyPattern;
37  import org.orekit.gnss.antenna.PhaseCenterVariationFunction;
38  import org.orekit.gnss.antenna.TwoDVariation;
39  import org.orekit.orbits.OrbitType;
40  import org.orekit.orbits.PositionAngleType;
41  import org.orekit.propagation.Propagator;
42  import org.orekit.propagation.SpacecraftState;
43  import org.orekit.propagation.conversion.NumericalPropagatorBuilder;
44  
45  public class PhaseCentersPhaseModifierTest {
46  
47      @Test
48      public void testPreliminary() {
49  
50          // this test does not check PhaseCentersPhaseModifier at all,
51          // it just checks PhaseMeasurementCreator behaves as necessary for the other test
52          // the *real* test is testEffect below
53          Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides");
54  
55          final NumericalPropagatorBuilder propagatorBuilder =
56                          context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true,
57                                                1.0e-6, 60.0, 0.001);
58          propagatorBuilder.setAttitudeProvider(new LofOffset(propagatorBuilder.getFrame(), LOFType.LVLH));
59  
60          // create perfect phase measurements without antenna offset
61          final Propagator p1 = EstimationTestUtils.createPropagator(context.initialOrbit,
62                                                                             propagatorBuilder);
63          final double groundClockOffset =  12.0e-6;
64          for (final GroundStation station : context.stations) {
65              station.getClockOffsetDriver().setValue(groundClockOffset);
66          }
67          final int    ambiguity         = 0;
68          final double satClockOffset    = 345.0e-6;
69          final List<ObservedMeasurement<?>> spacecraftCenteredMeasurements =
70                          EstimationTestUtils.createMeasurements(p1,
71                                                                 new PhaseMeasurementCreator(context,
72                                                                                             PredefinedGnssSignal.G01,
73                                                                                             ambiguity, satClockOffset),
74                                                                 1.0, 3.0, 300.0);
75  
76          // create perfect phase measurements with antenna offset
77          final double xOffset = -2.5;
78          final Propagator p2 = EstimationTestUtils.createPropagator(context.initialOrbit,
79                                                                     propagatorBuilder);
80          final List<ObservedMeasurement<?>> antennaCenteredMeasurements =
81                          EstimationTestUtils.createMeasurements(p2,
82                                                                 new PhaseMeasurementCreator(context,
83                                                                                             PredefinedGnssSignal.G01,
84                                                                                             ambiguity, satClockOffset,
85                                                                                             Vector3D.ZERO, null,
86                                                                                             new Vector3D(xOffset, 0, 0), null),
87                                                                 1.0, 3.0, 300.0);
88  
89          for (int i = 0; i < spacecraftCenteredMeasurements.size(); ++i) {
90              Phase sr = (Phase) spacecraftCenteredMeasurements.get(i);
91              Phase ar = (Phase) antennaCenteredMeasurements.get(i);
92              Assertions.assertTrue((ar.getObservedValue()[0] - sr.getObservedValue()[0]) * sr.getWavelength() >= +xOffset);
93              Assertions.assertTrue((ar.getObservedValue()[0] - sr.getObservedValue()[0]) * sr.getWavelength() <= -xOffset);
94          }
95      }
96  
97      @Test
98      public void testEffect() {
99  
100         Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides");
101 
102         final NumericalPropagatorBuilder propagatorBuilder =
103                         context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true,
104                                               1.0e-6, 60.0, 0.001);
105         propagatorBuilder.setAttitudeProvider(new LofOffset(propagatorBuilder.getFrame(), LOFType.LVLH));
106         final double groundClockOffset = 1.234e-3;
107         for (final GroundStation station : context.stations) {
108             station.getClockOffsetDriver().setValue(groundClockOffset);
109         }
110         final int    ambiguity         = 0;
111         final double satClockOffset    = 345.0e-6;
112 
113         // create perfect Phase measurements without antenna offset
114         final Propagator p1 = EstimationTestUtils.createPropagator(context.initialOrbit, propagatorBuilder);
115         final List<ObservedMeasurement<?>> spacecraftCenteredMeasurements =
116                         EstimationTestUtils.createMeasurements(p1,
117                                                                new PhaseMeasurementCreator(context,
118                                                                                            PredefinedGnssSignal.G01,
119                                                                                            ambiguity, satClockOffset,
120                                                                                            Vector3D.ZERO, null,
121                                                                                            Vector3D.ZERO, null),
122                                                                1.0, 3.0, 300.0);
123 
124         // create perfect Phase measurements with antenna offset
125         final Vector3D stationMeanPosition   = new Vector3D(0.25, 0.25, -0.5);
126         final PhaseCenterVariationFunction stationPCV = new TwoDVariation(0, FastMath.PI, MathUtils.SEMI_PI,
127                                                                           new double[][] {
128                                                                               { 0.0,  0.25, -0.25, 0.5 },
129                                                                               { 0.0, -0.25,  0.25, 0.5 }
130                                                                           });
131         final Vector3D satelliteMeanPosition = new Vector3D(-2.5,  0,  0);
132         final PhaseCenterVariationFunction satellitePCV = new TwoDVariation(0, FastMath.PI, MathUtils.SEMI_PI,
133                                                                             new double[][] {
134                                                                                 { 0.0,  0.5, -0.5, 1.0 },
135                                                                                 { 0.0, -0.5,  0.5, 1.0 }
136                                                                             });
137         final Propagator p2 = EstimationTestUtils.createPropagator(context.initialOrbit,
138                                                                    propagatorBuilder);
139         final List<ObservedMeasurement<?>> antennaCenteredMeasurements =
140                         EstimationTestUtils.createMeasurements(p2,
141                                                                new PhaseMeasurementCreator(context,
142                                                                                            PredefinedGnssSignal.G01,
143                                                                                            ambiguity, satClockOffset,
144                                                                                            stationMeanPosition,   stationPCV,
145                                                                                            satelliteMeanPosition, satellitePCV),
146                                                                1.0, 3.0, 300.0);
147 
148         final Propagator p3 = EstimationTestUtils.createPropagator(context.initialOrbit,
149                                                                    propagatorBuilder);
150 
151         PhaseCentersPhaseModifier modifier = new PhaseCentersPhaseModifier(new FrequencyPattern(stationMeanPosition,
152                                                                                                 stationPCV),
153                                                                            new FrequencyPattern(satelliteMeanPosition,
154                                                                                                 satellitePCV));
155         for (int i = 0; i < spacecraftCenteredMeasurements.size(); ++i) {
156             Phase sr = (Phase) spacecraftCenteredMeasurements.get(i);
157             sr.addModifier(modifier);
158             EstimatedMeasurementBase<Phase> estimated = sr.estimateWithoutDerivatives(new SpacecraftState[] { p3.propagate(sr.getDate()) });
159             Phase ar = (Phase) antennaCenteredMeasurements.get(i);
160             Assertions.assertEquals(0.0, sr.getDate().durationFrom(ar.getDate()), 1.0e-8);
161             Assertions.assertEquals(ar.getObservedValue()[0], estimated.getEstimatedValue()[0], 1.1e-5);
162             Assertions.assertEquals(1,
163                                     estimated.getAppliedEffects().entrySet().stream().
164                                     filter(e -> e.getKey().getEffectName().equals("mean phase center")).count());
165         }
166 
167     }
168 
169 }
170 
171