1   /* Copyright 2022-2025 Luc Maisonobe
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.data;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.hipparchus.util.FastMath;
22  import org.orekit.gnss.SatelliteSystem;
23  import org.orekit.time.FieldAbsoluteDate;
24  import org.orekit.time.FieldTimeStamped;
25  import org.orekit.time.GNSSDate;
26  import org.orekit.time.TimeScales;
27  
28  import java.util.function.Function;
29  
30  /** This class provides the minimal set of orbital elements needed by the {@link
31   * org.orekit.propagation.analytical.gnss.FieldGnssPropagator}.
32   * @param <T> type of the field elements
33   * @param <O> type of the orbital elements (non-field version)
34   * @since 13.0
35   * @author Luc Maisonobe
36  */
37  public abstract class FieldGnssOrbitalElements<T extends CalculusFieldElement<T>, O extends GNSSOrbitalElements<O>>
38      extends GNSSOrbitalElementsDriversProvider
39      implements FieldTimeStamped<T> {
40  
41      /** Earth's universal gravitational parameter. */
42      private final T mu;
43  
44      /** Reference epoch. */
45      private FieldAbsoluteDate<T> date;
46  
47      /** Semi-Major Axis (m). */
48      private T sma;
49  
50      /** Eccentricity. */
51      private T ecc;
52  
53      /** Inclination angle at reference time (rad). */
54      private T i0;
55  
56      /** Argument of perigee (rad). */
57      private T aop;
58  
59      /** Longitude of ascending node of orbit plane at weekly epoch (rad). */
60      private T om0;
61  
62      /** Mean anomaly at reference time (rad). */
63      private T anom;
64  
65      /** Simple constructor.
66       * @param mu              Earth's universal gravitational parameter
67       * @param angularVelocity mean angular velocity of the Earth for the GNSS model
68       * @param weeksInCycle    number of weeks in the GNSS cycle
69       * @param timeScales      known time scales
70       * @param system          satellite system to consider for interpreting week number
71       *                        (may be different from real system, for example in Rinex nav, weeks
72       *                        are always according to GPS)
73       */
74      protected FieldGnssOrbitalElements(final T mu, final double angularVelocity, final int weeksInCycle,
75                                         final TimeScales timeScales, final SatelliteSystem system) {
76  
77          super(angularVelocity, weeksInCycle, timeScales, system);
78  
79          // immutable field
80          this.mu   = mu;
81  
82          // Keplerian orbital elements
83          this.sma  = mu.newInstance(Double.NaN);
84          this.ecc  = mu.newInstance(Double.NaN);
85          this.i0   = mu.newInstance(Double.NaN);
86          this.aop  = mu.newInstance(Double.NaN);
87          this.om0  = mu.newInstance(Double.NaN);
88          this.anom = mu.newInstance(Double.NaN);
89  
90      }
91  
92      /** Constructor from non-field instance.
93       * @param field    field to which elements belong
94       * @param original regular non-field instance
95       */
96      protected FieldGnssOrbitalElements(final Field<T> field, final O original) {
97  
98          super(original.getAngularVelocity(), original.getWeeksInCycle(),
99                original.getTimeScales(), original.getSystem());
100         mu = field.getZero().newInstance(original.getMu());
101 
102         // non-Keplerian parameters
103         setPRN(original.getPRN());
104         setWeek(original.getWeek());
105         setTime(original.getTime());
106         setIDot(original.getIDot());
107         setOmegaDot(original.getOmegaDot());
108         setCuc(original.getCuc());
109         setCus(original.getCus());
110         setCrc(original.getCrc());
111         setCrs(original.getCrs());
112         setCic(original.getCic());
113         setCis(original.getCis());
114 
115         // Keplerian orbital elements
116         setGnssDate(new GNSSDate(original.getWeek(), original.getTime(), original.getSystem(), original.getTimeScales()));
117         setSma(field.getZero().newInstance(original.getSma()));
118         setE(field.getZero().newInstance(original.getE()));
119         setI0(field.getZero().newInstance(original.getI0()));
120         setPa(field.getZero().newInstance(original.getPa()));
121         setOmega0(field.getZero().newInstance(original.getOmega0()));
122         setM0(field.getZero().newInstance(original.getM0()));
123 
124         // copy selection settings
125         copySelectionSettings(original);
126 
127     }
128 
129     /** Constructor from different field instance.
130      * @param <V> type of the old field elements
131      * @param original regular non-field instance
132      * @param converter for field elements
133      */
134     protected <V extends CalculusFieldElement<V>> FieldGnssOrbitalElements(final Function<V, T> converter,
135                                                                            final FieldGnssOrbitalElements<V, O> original) {
136         super(original.getAngularVelocity(), original.getWeeksInCycle(),
137               original.getTimeScales(), original.getSystem());
138         mu = converter.apply(original.getMu());
139 
140         // non-Keplerian parameters
141         setPRN(original.getPRN());
142         setWeek(original.getWeek());
143         setTime(original.getTime());
144         setIDot(original.getIDot());
145         setOmegaDot(original.getOmegaDot());
146         setCuc(original.getCuc());
147         setCus(original.getCus());
148         setCrc(original.getCrc());
149         setCrs(original.getCrs());
150         setCic(original.getCic());
151         setCis(original.getCis());
152 
153         // Keplerian orbital elements
154         setGnssDate(new GNSSDate(original.getWeek(), original.getTime(), original.getSystem(), original.getTimeScales()));
155         setSma(converter.apply(original.getSma()));
156         setE(converter.apply(original.getE()));
157         setI0(converter.apply(original.getI0()));
158         setPa(converter.apply(original.getPa()));
159         setOmega0(converter.apply(original.getOmega0()));
160         setM0(converter.apply(original.getM0()));
161 
162         // copy selection settings
163         copySelectionSettings(original);
164 
165     }
166 
167     /** Create a non-field version of the instance.
168      * @return non-field version of the instance
169      */
170     public abstract O toNonField();
171 
172     /**
173      * Create another field version of the instance.
174      *
175      * @param <U>       type of the new field elements
176      * @param <G>       type of the orbital elements (field version)
177      * @param converter for field elements
178      * @return field version of the instance
179      */
180     public abstract <U extends CalculusFieldElement<U>, G extends FieldGnssOrbitalElements<U, O>>
181         G changeField(Function<T, U> converter);
182 
183     /** {@inheritDoc} */
184     protected void setGnssDate(final GNSSDate gnssDate) {
185         this.date = new FieldAbsoluteDate<>(mu.getField(), gnssDate.getDate());
186     }
187 
188     /** Get date.
189      * @return date
190      */
191     public FieldAbsoluteDate<T> getDate() {
192         return date;
193     }
194 
195     /** Get the Earth's universal gravitational parameter.
196      * @return the Earth's universal gravitational parameter
197      */
198     public T getMu() {
199         return mu;
200     }
201 
202     /** Get semi-major axis.
203      * @return semi-major axis (m)
204      */
205     public T getSma() {
206         return sma;
207     }
208 
209     /** Set semi-major axis.
210      * @param sma demi-major axis (m)
211      */
212     public void setSma(final T sma) {
213         this.sma = sma;
214     }
215 
216     /** Getter for the change rate in semi-major axis.
217      * <p>
218      * This value is non-zero only in civilian navigation messages
219      * </p>
220      * @return the change rate in semi-major axis
221      * @since 13.0
222      */
223     public T getADot() {
224         return mu.getField().getZero();
225     }
226 
227     /** Get the computed mean motion n₀.
228      * @return the computed mean motion n₀ (rad/s)
229      * @since 13.0
230      */
231     public T getMeanMotion0() {
232         final T invA = FastMath.abs(getSma()).reciprocal();
233         return FastMath.sqrt(getMu().multiply(invA)).multiply(invA);
234     }
235 
236     /** Getter for the delta of satellite mean motion.
237      * <p>
238      * This value is non-zero only in navigation messages
239      * </p>
240      * @return delta of satellite mean motion
241      * @since 13.0
242      */
243     public T getDeltaN0() {
244         return mu.getField().getZero();
245     }
246 
247     /** Getter for change rate in Δn₀.
248      * <p>
249      * This value is non-zero only in civilian navigation messages
250      * </p>
251      * @return change rate in Δn₀
252      * @since 13.0
253      */
254     public T getDeltaN0Dot() {
255         return mu.getField().getZero();
256     }
257 
258     /** Get eccentricity.
259      * @return eccentricity
260      */
261     public T getE() {
262         return ecc;
263     }
264 
265     /** Set eccentricity.
266      * @param e eccentricity
267      */
268     public void setE(final T e) {
269         this.ecc = e;
270     }
271 
272     /** Get the inclination angle at reference time.
273      * @return inclination angle at reference time (rad)
274      */
275     public T getI0() {
276         return i0;
277     }
278 
279     /** Set inclination angle at reference time.
280      * @param i0 inclination angle at reference time (rad)
281      */
282     public void setI0(final T i0) {
283         this.i0 = i0;
284     }
285 
286     /** Get longitude of ascending node of orbit plane at weekly epoch.
287      * @return longitude of ascending node of orbit plane at weekly epoch (rad)
288      */
289     public T getOmega0() {
290         return om0;
291     }
292 
293     /** Set longitude of ascending node of orbit plane at weekly epoch.
294      * @param omega0 longitude of ascending node of orbit plane at weekly epoch (rad)
295      */
296     public void setOmega0(final T omega0) {
297         this.om0 = omega0;
298     }
299 
300     /** Get argument of perigee.
301      * @return argument of perigee (rad)
302      */
303     public T getPa() {
304         return aop;
305     }
306 
307     /** Set argument of perigee.
308      * @param pa argument of perigee (rad)
309      */
310     public void setPa(final T pa) {
311         this.aop = pa;
312     }
313 
314     /** Get mean anomaly at reference time.
315      * @return mean anomaly at reference time (rad)
316      */
317     public T getM0() {
318         return anom;
319     }
320 
321     /** Set mean anomaly at reference time.
322      * @param m0 mean anomaly at reference time (rad)
323      */
324     public void setM0(final T m0) {
325         this.anom = m0;
326     }
327 
328 }