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.Test;
24  import org.orekit.Utils;
25  import org.orekit.data.DataContext;
26  import org.orekit.frames.Frame;
27  import org.orekit.frames.Frames;
28  import org.orekit.frames.FramesFactory;
29  import org.orekit.gnss.SatelliteSystem;
30  import org.orekit.propagation.SpacecraftState;
31  import org.orekit.propagation.analytical.gnss.data.GNSSOrbitalElements;
32  import org.orekit.propagation.analytical.gnss.data.NavICAlmanac;
33  import org.orekit.time.AbsoluteDate;
34  import org.orekit.time.GNSSDate;
35  import org.orekit.time.TimeInterpolator;
36  import org.orekit.time.TimeScalesFactory;
37  import org.orekit.utils.CartesianDerivativesFilter;
38  import org.orekit.utils.Constants;
39  import org.orekit.utils.PVCoordinates;
40  import org.orekit.utils.TimeStampedPVCoordinates;
41  import org.orekit.utils.TimeStampedPVCoordinatesHermiteInterpolator;
42  
43  import java.util.ArrayList;
44  import java.util.List;
45  
46  public class NavICPropagatorTest {
47  
48      private static NavICAlmanac almanac;
49      private static Frames frames;
50  
51      @BeforeAll
52      public static void setUpBeforeClass() {
53          Utils.setDataRoot("gnss");
54  
55          // Almanac for satellite 1 for April 1st 2014 (Source: Rinex 3.04 format - Table A19)
56          almanac = new NavICAlmanac(DataContext.getDefault().getTimeScales(), SatelliteSystem.NAVIC);
57          almanac.setPRN(1);
58          almanac.setWeek(1786);
59          almanac.setTime(172800.0);
60          almanac.setSqrtA(6.493487739563E03);
61          almanac.setE(2.257102518342E-03);
62          almanac.setI0(4.758105460020e-01);
63          almanac.setOmega0(-8.912102146884E-01);
64          almanac.setOmegaDot(-4.414469594664e-09);
65          almanac.setPa(-2.999907424014);
66          almanac.setM0(-1.396094758025);
67          almanac.setAf0(-9.473115205765e-04);
68          almanac.setAf1(1.250555214938e-12);
69  
70          frames = DataContext.getDefault().getFrames();
71      }
72  
73      @Test
74      public void testNavICCycle() {
75          // Builds the NavIC propagator from the almanac
76          final GNSSPropagator propagator = almanac.getPropagator(frames);
77          // Propagate at the NavIC date and one NavIC cycle later
78          final AbsoluteDate date0 = almanac.getDate();
79          final Vector3D p0 = propagator.propagateInEcef(date0).getPosition();
80          final double bdtCycleDuration = almanac.getCycleDuration();
81          final AbsoluteDate date1 = date0.shiftedBy(bdtCycleDuration);
82          final Vector3D p1 = propagator.propagateInEcef(date1).getPosition();
83  
84          // Checks
85          Assertions.assertEquals(0., p0.distance(p1), 0.);
86      }
87  
88      @Test
89      public void testFrames() {
90          // Builds the NavIC propagator from the almanac
91          final GNSSPropagator propagator = almanac.getPropagator(frames);
92          Assertions.assertEquals("EME2000", propagator.getFrame().getName());
93          Assertions.assertEquals(3.986005e+14, almanac.getMu(), 1.0e6);
94          // Defines some date
95          final AbsoluteDate date = new AbsoluteDate(2016, 3, 3, 12, 0, 0., TimeScalesFactory.getUTC());
96          // Get PVCoordinates at the date in the ECEF
97          final PVCoordinates pv0 = propagator.propagateInEcef(date);
98          // Get PVCoordinates at the date in the ECEF
99          final PVCoordinates pv1 = propagator.getPVCoordinates(date, propagator.getECEF());
100 
101         // Checks
102         Assertions.assertEquals(0., pv0.getPosition().distance(pv1.getPosition()), 3.3e-8);
103         Assertions.assertEquals(0., pv0.getVelocity().distance(pv1.getVelocity()), 3.9e-12);
104     }
105 
106     @Test
107     public void testResetInitialState() {
108         final GNSSPropagator propagator = almanac.getPropagator();
109         final SpacecraftState old = propagator.getInitialState();
110         propagator.resetInitialState(new SpacecraftState(old.getOrbit(), old.getAttitude(), old.getMass() + 1000));
111         Assertions.assertEquals(old.getMass() + 1000, propagator.getInitialState().getMass(), 1.0e-9);
112     }
113 
114     @Test
115     public void testResetIntermediateState() {
116         GNSSPropagator propagator = new GNSSPropagatorBuilder(almanac).build();
117         final SpacecraftState old = propagator.getInitialState();
118         propagator.resetIntermediateState(new SpacecraftState(old.getOrbit(), old.getAttitude(), old.getMass() + 1000),
119                                           true);
120         Assertions.assertEquals(old.getMass() + 1000, propagator.getInitialState().getMass(), 1.0e-9);
121     }
122 
123     @Test
124     public void testDerivativesConsistency() {
125 
126         final Frame eme2000 = FramesFactory.getEME2000();
127         double errorP = 0;
128         double errorV = 0;
129         double errorA = 0;
130         final GNSSPropagator propagator = almanac.getPropagator(frames);
131         GNSSOrbitalElements<?> elements = propagator.getOrbitalElements();
132         AbsoluteDate t0 = new GNSSDate(elements.getWeek(), elements.getTime(), SatelliteSystem.NAVIC).getDate();
133         for (double dt = 0; dt < Constants.JULIAN_DAY; dt += 600) {
134             final AbsoluteDate central = t0.shiftedBy(dt);
135             final PVCoordinates pv = propagator.getPVCoordinates(central, eme2000);
136             final double h = 10.0;
137             List<TimeStampedPVCoordinates> sample = new ArrayList<>();
138             for (int i = -3; i <= 3; ++i) {
139                 sample.add(propagator.getPVCoordinates(central.shiftedBy(i * h), eme2000));
140             }
141 
142             // create interpolator
143             final TimeInterpolator<TimeStampedPVCoordinates> interpolator =
144                     new TimeStampedPVCoordinatesHermiteInterpolator(sample.size(), CartesianDerivativesFilter.USE_P);
145 
146             final PVCoordinates interpolated = interpolator.interpolate(central, sample);
147             errorP = FastMath.max(errorP, Vector3D.distance(pv.getPosition(), interpolated.getPosition()));
148             errorV = FastMath.max(errorV, Vector3D.distance(pv.getVelocity(), interpolated.getVelocity()));
149             errorA = FastMath.max(errorA, Vector3D.distance(pv.getAcceleration(), interpolated.getAcceleration()));
150         }
151 
152         Assertions.assertEquals(0.0, errorP, 3.8e-9);
153         Assertions.assertEquals(0.0, errorV, 2.6e-7);
154         Assertions.assertEquals(0.0, errorA, 6.5e-8);
155 
156     }
157 
158     @Test
159     public void testIssue544() {
160         // Builds the NavICPropagator from the almanac
161         final GNSSPropagator propagator = almanac.getPropagator(frames);
162         // In order to test the issue, we voluntary set a Double.NaN value in the date.
163         final AbsoluteDate date0 = new AbsoluteDate(2010, 5, 7, 7, 50, Double.NaN, TimeScalesFactory.getUTC());
164         final PVCoordinates pv0 = propagator.propagateInEcef(date0);
165         // Verify that an infinite loop did not occur
166         Assertions.assertEquals(Vector3D.NaN, pv0.getPosition());
167         Assertions.assertEquals(Vector3D.NaN, pv0.getVelocity());
168     }
169 
170     @Test
171     public void testConversion() {
172         GnssTestUtils.checkFieldConversion(almanac);
173     }
174 
175 }