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 org.hipparchus.geometry.euclidean.threed.Vector3D;
20  import org.hipparchus.util.FastMath;
21  import org.junit.jupiter.api.Assertions;
22  import org.junit.jupiter.api.BeforeEach;
23  import org.junit.jupiter.api.Test;
24  import org.orekit.Utils;
25  import org.orekit.bodies.GeodeticPoint;
26  import org.orekit.bodies.OneAxisEllipsoid;
27  import org.orekit.estimation.measurements.EstimatedMeasurement;
28  import org.orekit.estimation.measurements.GroundStation;
29  import org.orekit.estimation.measurements.ObservableSatellite;
30  import org.orekit.estimation.measurements.gnss.AmbiguityCache;
31  import org.orekit.estimation.measurements.gnss.Phase;
32  import org.orekit.frames.FramesFactory;
33  import org.orekit.frames.TopocentricFrame;
34  import org.orekit.gnss.PredefinedGnssSignal;
35  import org.orekit.orbits.CartesianOrbit;
36  import org.orekit.propagation.SpacecraftState;
37  import org.orekit.propagation.analytical.tle.TLE;
38  import org.orekit.propagation.analytical.tle.TLEPropagator;
39  import org.orekit.utils.Constants;
40  import org.orekit.utils.IERSConventions;
41  import org.orekit.utils.ParameterDriver;
42  import org.orekit.utils.TimeStampedPVCoordinates;
43  
44  import java.util.Arrays;
45  
46  /**
47   * Check against prediction in
48   * "Springer Handbook oƒ Global Navigation Satellite Systems, Teunissen, Montenbruck"
49   * An approximate value is given in terms of delay for Galileo satellites.
50   * As these satellites are close to GPS satellites, we consider the delays to be
51   * of the same order, namely around 62ps.
52   * The values produced by the modifiers are translated in terms of delay and checked against
53   * the approximate value.
54   */
55  
56  public class RelativisticJ2ClockPhaseModifierTest {
57  
58  
59      @Test
60      public void testRelativisticClockCorrection() {
61  
62          // Station
63          final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
64                                                              Constants.WGS84_EARTH_FLATTENING,
65                                                              FramesFactory.getITRF(IERSConventions.IERS_2010, true));
66          final GeodeticPoint point    = new GeodeticPoint(FastMath.toRadians(42.0), FastMath.toRadians(1.0), 100.0);
67          final TopocentricFrame topo  = new TopocentricFrame(earth, point, "");
68          final GroundStation station  = new GroundStation(topo);
69  
70          // Satellite (GPS orbit from TLE)
71          final TLE tle = new TLE("1 28474U 04045A   20252.59334296 -.00000043  00000-0  00000-0 0  9998",
72                                  "2 28474  55.0265  49.5108 0200271 267.9106 149.0797  2.00552216116165");
73          final TimeStampedPVCoordinates satPV = TLEPropagator.selectExtrapolator(tle).getPVCoordinates(tle.getDate(), FramesFactory.getEME2000());
74          final SpacecraftState state = new SpacecraftState(new CartesianOrbit(satPV, FramesFactory.getEME2000(), Constants.WGS84_EARTH_MU));
75  
76          // Set reference date to station drivers
77          for (ParameterDriver driver : Arrays.asList(station.getClockOffsetDriver(),
78                                                      station.getEastOffsetDriver(),
79                                                      station.getNorthOffsetDriver(),
80                                                      station.getZenithOffsetDriver(),
81                                                      station.getPrimeMeridianOffsetDriver(),
82                                                      station.getPrimeMeridianDriftDriver(),
83                                                      station.getPolarOffsetXDriver(),
84                                                      station.getPolarDriftXDriver(),
85                                                      station.getPolarOffsetYDriver(),
86                                                      station.getPolarDriftYDriver())) {
87              if (driver.getReferenceDate() == null) {
88                  driver.setReferenceDate(state.getDate());
89              }
90          }
91  
92          // Station PV
93          final Vector3D zero = Vector3D.ZERO;
94          final TimeStampedPVCoordinates stationPV = station.getOffsetToInertial(state.getFrame(), state.getDate(), false).transformPVCoordinates(new TimeStampedPVCoordinates(state.getDate(), zero, zero, zero));
95  
96          // phase measurement
97          final Phase phase = new Phase(station, state.getDate(), 26584264.45, PredefinedGnssSignal.G01.getWavelength(),
98                                  1.0, 1.0, new ObservableSatellite(0),
99                                        new AmbiguityCache());
100         final EstimatedMeasurement<Phase> estimated = new EstimatedMeasurement<>(phase, 0, 0,
101                         new SpacecraftState[] {state},
102                         new TimeStampedPVCoordinates[] {state.getPVCoordinates(), stationPV});
103         estimated.setEstimatedValue(phase.getObservedValue()[0]);
104         Assertions.assertEquals(0.0, estimated.getObservedValue()[0] - estimated.getEstimatedValue()[0], 1.0e-3);
105 
106         // Measurement modifier
107         final RelativisticJ2ClockPhaseModifier modifier = new RelativisticJ2ClockPhaseModifier(Constants.WGS84_EARTH_MU,
108                 Constants.WGS84_EARTH_C20, Constants.WGS84_EARTH_EQUATORIAL_RADIUS );
109         modifier.modify(estimated);
110         Assertions.assertEquals(0, modifier.getParametersDrivers().size());
111 
112         // Verify : According to Teunissen and Montenbruck, the delay is supposed to be around 60ps for Galileo.
113         //          The computed value is equal to 64.745 ps, therefore lying in the supposed range.
114         Assertions.assertEquals(-0.10202, estimated.getObservedValue()[0] - estimated.getEstimatedValue()[0], 1.0e-2);
115         Assertions.assertEquals(1,
116                                 estimated.getAppliedEffects().entrySet().stream().
117                                 filter(e -> e.getKey().getEffectName().equals("J₂ clock relativity")).count());
118 
119     }
120 
121     @BeforeEach
122     public void setUp() {
123         Utils.setDataRoot("regular-data");
124     }
125 
126 }