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.propagation.analytical.gnss;
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.BeforeAll;
23  import org.junit.jupiter.api.BeforeEach;
24  import org.junit.jupiter.api.Test;
25  import org.orekit.TestUtils;
26  import org.orekit.Utils;
27  import org.orekit.data.DataContext;
28  import org.orekit.errors.OrekitException;
29  import org.orekit.errors.OrekitMessages;
30  import org.orekit.frames.Frame;
31  import org.orekit.frames.Frames;
32  import org.orekit.frames.FramesFactory;
33  import org.orekit.gnss.SatelliteSystem;
34  import org.orekit.propagation.AdditionalDataProvider;
35  import org.orekit.propagation.analytical.gnss.data.GNSSConstants;
36  import org.orekit.propagation.analytical.gnss.data.SBASNavigationMessage;
37  import org.orekit.propagation.analytical.gnss.data.SBASOrbitalElements;
38  import org.orekit.time.AbsoluteDate;
39  import org.orekit.time.GNSSDate;
40  import org.orekit.time.TimeInterpolator;
41  import org.orekit.time.TimeScalesFactory;
42  import org.orekit.utils.CartesianDerivativesFilter;
43  import org.orekit.utils.Constants;
44  import org.orekit.utils.IERSConventions;
45  import org.orekit.utils.PVCoordinates;
46  import org.orekit.utils.TimeStampedPVCoordinates;
47  import org.orekit.utils.TimeStampedPVCoordinatesHermiteInterpolator;
48  
49  import java.util.ArrayList;
50  import java.util.List;
51  
52  
53  public class SBASPropagatorTest {
54  
55      /** Threshold for test validation. */
56      private static final double eps = 1.0e-15;
57  
58      /** SBAS orbital elements. */
59      private SBASNavigationMessage soe;
60      private Frames frames;
61  
62      @BeforeEach
63      public void setUp() {
64          // Reference data are taken from IGS file brdm0370.17p
65          soe = new SBASNavigationMessage();
66          soe.setPRN(127);
67          soe.setTime(1.23303e+05);
68          soe.setDate(new GNSSDate(1935, 123303.0, SatelliteSystem.SBAS).getDate());
69          soe.setX(2.406022248000e+07);
70          soe.setXDot(-2.712500000000e-01);
71          soe.setXDotDot(3.250000000000e-04);
72          soe.setY(3.460922568000e+07);
73          soe.setYDot(3.063125000000e-00);
74          soe.setYDotDot(-1.500000000000e-04);
75          soe.setZ(1.964040000000e+04);
76          soe.setZDot(1.012000000000e-00);
77          soe.setZDotDot(-1.250000000000e-04);
78          frames = DataContext.getDefault().getFrames();
79      }
80  
81      @BeforeAll
82      public static void setUpBeforeClass() {
83          Utils.setDataRoot("gnss");
84      }
85  
86      @Test
87      public void testPropagationAtReferenceTime() {
88          // SBAS propagator
89          final SBASPropagator propagator = new SBASPropagatorBuilder(soe, frames).
90                          attitudeProvider(Utils.defaultLaw()).
91                          mu(GNSSConstants.SBAS_MU).
92                          mass(SBASPropagator.DEFAULT_MASS).
93                          eci(FramesFactory.getEME2000()).
94                          ecef(FramesFactory.getITRF(IERSConventions.IERS_2010, true)).
95                          build();
96          // Propagation
97          final PVCoordinates pv = propagator.propagateInEcef(soe.getDate());
98          // Position/Velocity/Acceleration
99          final Vector3D position = pv.getPosition();
100         final Vector3D velocity = pv.getVelocity();
101         final Vector3D acceleration = pv.getAcceleration();
102         // Verify
103         Assertions.assertEquals(soe.getX(),       position.getX(),     eps);
104         Assertions.assertEquals(soe.getY(),       position.getY(),     eps);
105         Assertions.assertEquals(soe.getZ(),       position.getZ(),     eps);
106         Assertions.assertEquals(soe.getXDot(),    velocity.getX(),     eps);
107         Assertions.assertEquals(soe.getYDot(),    velocity.getY(),     eps);
108         Assertions.assertEquals(soe.getZDot(),    velocity.getZ(),     eps);
109         Assertions.assertEquals(soe.getXDotDot(), acceleration.getX(), eps);
110         Assertions.assertEquals(soe.getYDotDot(), acceleration.getY(), eps);
111         Assertions.assertEquals(soe.getZDotDot(), acceleration.getZ(), eps);
112     }
113 
114     @Test
115     public void testPropagation() {
116         // SBAS propagator
117         final SBASPropagator propagator = new SBASPropagatorBuilder(soe, frames).build();
118         // Propagation
119         final PVCoordinates pv = propagator.propagateInEcef(soe.getDate().shiftedBy(1.0));
120         // Position/Velocity/Acceleration
121         final Vector3D position = pv.getPosition();
122         final Vector3D velocity = pv.getVelocity();
123         final Vector3D acceleration = pv.getAcceleration();
124         // Verify
125         Assertions.assertEquals(24060222.2089125, position.getX(),     eps);
126         Assertions.assertEquals(34609228.7430500, position.getY(),     eps);
127         Assertions.assertEquals(19641.4119375,    position.getZ(),     eps);
128         Assertions.assertEquals(-0.270925,        velocity.getX(),     eps);
129         Assertions.assertEquals(3.062975,         velocity.getY(),     eps);
130         Assertions.assertEquals(1.011875,         velocity.getZ(),     eps);
131         Assertions.assertEquals(soe.getXDotDot(), acceleration.getX(), eps);
132         Assertions.assertEquals(soe.getYDotDot(), acceleration.getY(), eps);
133         Assertions.assertEquals(soe.getZDotDot(), acceleration.getZ(), eps);
134     }
135 
136     @Test
137     public void testFrames() {
138         // Builds the SBAS propagator from the ephemeris
139         final SBASPropagator propagator = new SBASPropagatorBuilder(soe, frames).build();
140         Assertions.assertEquals("EME2000", propagator.getFrame().getName());
141         Assertions.assertEquals(3.986005e+14, propagator.getMU(), 1.0e6);
142         Assertions.assertEquals(propagator.getECI().getName(), propagator.getFrame().getName());
143         // Defines some date
144         final AbsoluteDate date = new AbsoluteDate(2017, 2, 3, 12, 0, 0., TimeScalesFactory.getUTC());
145         // Get PVCoordinates at the date in the ECEF
146         final PVCoordinates pv0 = propagator.propagateInEcef(date);
147         // Get PVCoordinates at the date in the ECEF
148         final PVCoordinates pv1 = propagator.getPVCoordinates(date, propagator.getECEF());
149 
150         // Checks
151         Assertions.assertEquals(0., pv0.getPosition().distance(pv1.getPosition()), 1.6e-8);
152         Assertions.assertEquals(0., pv0.getVelocity().distance(pv1.getVelocity()), 3.8e-12);
153     }
154 
155     @Test
156     public void testDerivativesConsistency() {
157 
158         final Frame eme2000 = FramesFactory.getEME2000();
159         double errorP = 0;
160         double errorV = 0;
161         double errorA = 0;
162         final SBASPropagator propagator = new SBASPropagatorBuilder(soe, frames).build();
163         SBASOrbitalElements elements = propagator.getSBASOrbitalElements();
164         AbsoluteDate t0 = new GNSSDate(elements.getWeek(), elements.getTime(), SatelliteSystem.SBAS).getDate();
165         for (double dt = 0; dt < Constants.JULIAN_DAY; dt += 600) {
166             final AbsoluteDate central = t0.shiftedBy(dt);
167             final PVCoordinates pv = propagator.getPVCoordinates(central, eme2000);
168             final double h = 10.0;
169             List<TimeStampedPVCoordinates> sample = new ArrayList<>();
170             for (int i = -3; i <= 3; ++i) {
171                 sample.add(propagator.getPVCoordinates(central.shiftedBy(i * h), eme2000));
172             }
173 
174             // create interpolator
175             final TimeInterpolator<TimeStampedPVCoordinates> interpolator =
176                     new TimeStampedPVCoordinatesHermiteInterpolator(sample.size(), CartesianDerivativesFilter.USE_P);
177 
178             final PVCoordinates interpolated = interpolator.interpolate(central, sample);
179             errorP = FastMath.max(errorP, Vector3D.distance(pv.getPosition(), interpolated.getPosition()));
180             errorV = FastMath.max(errorV, Vector3D.distance(pv.getVelocity(), interpolated.getVelocity()));
181             errorA = FastMath.max(errorA, Vector3D.distance(pv.getAcceleration(), interpolated.getAcceleration()));
182         }
183         Assertions.assertEquals(0.0, errorP, 1.5e-11);
184         Assertions.assertEquals(0.0, errorV, 7.3e-3);
185         Assertions.assertEquals(0.0, errorA, 1.7e-3);
186 
187     }
188 
189     @Test
190     public void testNoReset() {
191         try {
192             final SBASPropagator propagator = new SBASPropagatorBuilder(soe, frames).build();
193             propagator.resetInitialState(propagator.getInitialState());
194             Assertions.fail("an exception should have been thrown");
195         } catch (OrekitException oe) {
196             Assertions.assertEquals(OrekitMessages.NON_RESETABLE_STATE, oe.getSpecifier());
197         }
198         try {
199             final SBASPropagator propagator = new SBASPropagatorBuilder(soe, frames).build();
200             propagator.resetIntermediateState(propagator.getInitialState(), true);
201             Assertions.fail("an exception should have been thrown");
202         } catch (OrekitException oe) {
203             Assertions.assertEquals(OrekitMessages.NON_RESETABLE_STATE, oe.getSpecifier());
204         }
205     }
206 
207     /** Error with specific propagators & additional state provider throwing a NullPointerException when propagating */
208     @Test
209     public void testIssue949() {
210         // GIVEN
211         // Setup propagator
212         final SBASPropagator propagator = new SBASPropagatorBuilder(soe, frames).build();
213 
214         // Setup additional data provider which use the initial state in its init method
215         final AdditionalDataProvider<double[]> additionalDataProvider = TestUtils.getAdditionalProviderWithInit();
216         propagator.addAdditionalDataProvider(additionalDataProvider);
217 
218         // WHEN & THEN
219         Assertions.assertDoesNotThrow(() -> propagator.propagate(new AbsoluteDate()), "No error should have been thrown");
220 
221     }
222 
223 }