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.util.FastMath;
20  import org.orekit.gnss.SatelliteSystem;
21  import org.orekit.time.AbsoluteDate;
22  import org.orekit.time.GNSSDate;
23  import org.orekit.time.TimeScales;
24  import org.orekit.utils.ParameterDriver;
25  import org.orekit.utils.ParameterDriversProvider;
26  import org.orekit.utils.ParameterObserver;
27  import org.orekit.utils.TimeSpanMap;
28  
29  import java.util.Arrays;
30  import java.util.List;
31  
32  /** This class manages the non-keplerian parameter drivers for
33   * {@link GNSSOrbitalElements} and {@link FieldGnssOrbitalElements}.
34   * <p>
35   * In both primitive double and field classes, only the non-Keplerian parameters
36   * are returned in the {@link #getParametersDrivers()} method, the Keplerian orbital
37   * parameters must be accessed independently. These groups ensure proper separate
38   * computation of state transition matrix and Jacobian matrix by
39   * {@link org.orekit.propagation.analytical.gnss.GNSSPropagator} and
40   * {@link org.orekit.propagation.analytical.gnss.FieldGnssPropagator}.
41   * </p>
42   * @since 13.0
43   * @author Luc Maisonobe
44   */
45  public abstract class GNSSOrbitalElementsDriversProvider
46      implements ParameterDriversProvider {
47  
48      /** Name for time parameter. */
49      public static final String TIME = "GnssTime";
50  
51      /** Name for inclination rate parameter. */
52      public static final String INCLINATION_RATE = "GnssInclinationRate";
53  
54      /** Name for longitude rate parameter. */
55      public static final String LONGITUDE_RATE = "GnssLongitudeRate";
56  
57      /** Name for cosine of latitude argument harmonic parameter. */
58      public static final String LATITUDE_COSINE = "GnssLatitudeCosine";
59  
60      /** Name for sine of latitude argument harmonic parameter. */
61      public static final String LATITUDE_SINE = "GnssLatitudeSine";
62  
63      /** Name for cosine of orbit radius harmonic parameter. */
64      public static final String RADIUS_COSINE = "GnssRadiusCosine";
65  
66      /** Name for sine of orbit radius harmonic parameter. */
67      public static final String RADIUS_SINE = "GnssRadiusSine";
68  
69      /** Name for cosine of inclination harmonic parameter. */
70      public static final String INCLINATION_COSINE = "GnssInclinationCosine";
71  
72      /** Name for sine of inclination harmonic parameter. */
73      public static final String INCLINATION_SINE = "GnssInclinationSine";
74  
75      /** Index of time in the list returned by {@link #getParametersDrivers()}. */
76      public static final int TIME_INDEX = 0;
77  
78      /** Index of inclination rate in the list returned by {@link #getParametersDrivers()}. */
79      public static final int I_DOT_INDEX = TIME_INDEX + 1;
80  
81      /** Index of longitude rate in the list returned by {@link #getParametersDrivers()}. */
82      public static final int OMEGA_DOT_INDEX = I_DOT_INDEX + 1;
83  
84      /** Index of cosine on latitude argument in the list returned by {@link #getParametersDrivers()}. */
85      public static final int CUC_INDEX = OMEGA_DOT_INDEX + 1;
86  
87      /** Index of sine on latitude argument in the list returned by {@link #getParametersDrivers()}. */
88      public static final int CUS_INDEX = CUC_INDEX + 1;
89  
90      /** Index of cosine on radius in the list returned by {@link #getParametersDrivers()}. */
91      public static final int CRC_INDEX = CUS_INDEX + 1;
92  
93      /** Index of sine on radius in the list returned by {@link #getParametersDrivers()}. */
94      public static final int CRS_INDEX = CRC_INDEX + 1;
95  
96      /** Index of cosine on inclination in the list returned by {@link #getParametersDrivers()}. */
97      public static final int CIC_INDEX = CRS_INDEX + 1;
98  
99      /** Index of sine on inclination in the list returned by {@link #getParametersDrivers()}. */
100     public static final int CIS_INDEX = CIC_INDEX + 1;
101 
102     /** Size of parameters array. */
103     public static final int SIZE = CIS_INDEX + 1;
104 
105     /** Mean angular velocity of the Earth for the GNSS model. */
106     private final double angularVelocity;
107 
108     /** Duration of the GNSS cycle in weeks. */
109     private final int weeksInCycle;
110 
111     /** Duration of the GNSS cycle in seconds. */
112     private final double cycleDuration;
113 
114     /** Satellite system to use for interpreting week number. */
115     private final SatelliteSystem system;
116 
117     /** Known time scales. */
118     private final TimeScales timeScales;
119 
120     /** PRN number of the satellite. */
121     private int prn;
122 
123     /** Reference Week of the orbit. */
124     private int week;
125 
126     /** Reference time. */
127     private final ParameterDriver timeDriver;
128 
129     /** Inclination rate (rad/s). */
130     private final ParameterDriver iDotDriver;
131 
132     /** Rate of right ascension (rad/s). */
133     private final ParameterDriver domDriver;
134 
135     /** Amplitude of the cosine harmonic correction term to the argument of latitude. */
136     private final ParameterDriver cucDriver;
137 
138     /** Amplitude of the sine harmonic correction term to the argument of latitude. */
139     private final ParameterDriver cusDriver;
140 
141     /** Amplitude of the cosine harmonic correction term to the orbit radius. */
142     private final ParameterDriver crcDriver;
143 
144     /** Amplitude of the sine harmonic correction term to the orbit radius. */
145     private final ParameterDriver crsDriver;
146 
147     /** Amplitude of the cosine harmonic correction term to the inclination. */
148     private final ParameterDriver cicDriver;
149 
150     /** Amplitude of the sine harmonic correction term to the inclination. */
151     private final ParameterDriver cisDriver;
152 
153     /** Constructor.
154      * @param angularVelocity mean angular velocity of the Earth for the GNSS model
155      * @param weeksInCycle    number of weeks in the GNSS cycle
156      * @param timeScales      known time scales
157      * @param system          satellite system to consider for interpreting week number
158      *                        (may be different from real system, for example in Rinex nav, weeks
159      *                        are always according to GPS)
160      */
161     protected GNSSOrbitalElementsDriversProvider(final double angularVelocity, final int weeksInCycle,
162                                                  final TimeScales timeScales, final SatelliteSystem system) {
163 
164         // immutable fields
165         this.angularVelocity = angularVelocity;
166         this.weeksInCycle    = weeksInCycle;
167         this.cycleDuration   = GNSSConstants.GNSS_WEEK_IN_SECONDS * weeksInCycle;
168         this.system          = system;
169         this.timeScales      = timeScales;
170 
171         this.timeDriver = createDriver(TIME);
172         this.iDotDriver = createDriver(INCLINATION_RATE);
173         this.domDriver  = createDriver(LONGITUDE_RATE);
174         this.cucDriver  = createDriver(LATITUDE_COSINE);
175         this.cusDriver  = createDriver(LATITUDE_SINE);
176         this.crcDriver  = createDriver(RADIUS_COSINE);
177         this.crsDriver  = createDriver(RADIUS_SINE);
178         this.cicDriver  = createDriver(INCLINATION_COSINE);
179         this.cisDriver  = createDriver(INCLINATION_SINE);
180 
181         // automatically update date when time driver is updated
182         timeDriver.addObserver(new ParameterObserver() {
183 
184             /** {@inheritDoc} */
185             @Override
186             public void valueChanged(final double previousValue, final ParameterDriver driver,
187                                      final AbsoluteDate date) {
188                 setGnssDate(new GNSSDate(week, driver.getValue(), system, timeScales));
189             }
190 
191             /** {@inheritDoc} */
192             @Override
193             public void valueSpanMapChanged(final TimeSpanMap<Double> previousValueSpanMap,
194                                             final ParameterDriver driver) {
195                 // nothing to do
196             }
197         });
198 
199     }
200 
201     /** Copy drivers selection settings from another instance.
202      * @param original original instance providing selection settings
203      */
204     protected void copySelectionSettings(final GNSSOrbitalElementsDriversProvider original) {
205         timeDriver.setSelected(original.timeDriver.isSelected());
206         iDotDriver.setSelected(original.iDotDriver.isSelected());
207         domDriver.setSelected(original.domDriver.isSelected());
208         cucDriver.setSelected(original.cucDriver.isSelected());
209         cusDriver.setSelected(original.cusDriver.isSelected());
210         crcDriver.setSelected(original.crcDriver.isSelected());
211         crsDriver.setSelected(original.crsDriver.isSelected());
212         cicDriver.setSelected(original.cicDriver.isSelected());
213         cisDriver.setSelected(original.cisDriver.isSelected());
214     }
215 
216     /** Set GNSS date.
217      * @param gnssDate GNSS date
218      */
219     protected abstract void setGnssDate(GNSSDate gnssDate);
220 
221     /** Create parameter driver.
222      * @param name name of the driver
223      * @return build driver
224      */
225     protected static ParameterDriver createDriver(final String name) {
226         return new ParameterDriver(name, 0, FastMath.scalb(1.0, -30),
227                                    Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
228     }
229 
230     /** Get satellite system.
231      * @return satellite system
232      */
233     public SatelliteSystem getSystem() {
234         return system;
235     }
236 
237     /** Get known time scales.
238      * @return known time scales
239      */
240     public TimeScales getTimeScales() {
241         return timeScales;
242     }
243 
244     /** {@inheritDoc}
245      * <p>
246      * Only the 9 non-Keplerian evolution parameters are listed here,
247      * i.e. {@link #getTimeDriver()} (at index {@link #TIME_INDEX}),
248      * {@link #getIDotDriver()} (at index {@link #I_DOT_INDEX}),
249      * {@link #getOmegaDotDriver()} (at index {@link #OMEGA_DOT_INDEX}),
250      * {@link #getCucDriver()} (at index {@link #CUC_INDEX}),
251      * {@link #getCusDriver()} (at index {@link #CUS_INDEX}),
252      * {@link #getCrcDriver()} (at index {@link #CRC_INDEX}),
253      * {@link #getCrsDriver()} (at index {@link #CRS_INDEX}),
254      * {@link #getCicDriver()} (at index {@link #CIC_INDEX}),
255      * and {@link #getCisDriver()} (at index {@link #CIS_INDEX})
256      * </p>
257      * <p>
258      * The Keplerian orbital parameters drivers are not included.
259      * </p>
260      */
261     @Override
262     public List<ParameterDriver> getParametersDrivers() {
263         // ensure the parameters are really at the advertised indices
264         final ParameterDriver[] array = new ParameterDriver[SIZE];
265         array[TIME_INDEX]      = getTimeDriver();
266         array[I_DOT_INDEX]     = getIDotDriver();
267         array[OMEGA_DOT_INDEX] = getOmegaDotDriver();
268         array[CUC_INDEX]       = getCucDriver();
269         array[CUS_INDEX]       = getCusDriver();
270         array[CRC_INDEX]       = getCrcDriver();
271         array[CRS_INDEX]       = getCrsDriver();
272         array[CIC_INDEX]       = getCicDriver();
273         array[CIS_INDEX]       = getCisDriver();
274         return Arrays.asList(array);
275     }
276 
277     /** Get the mean angular velocity of the Earth of the GNSS model.
278      * @return mean angular velocity of the Earth of the GNSS model
279      */
280     public double getAngularVelocity() {
281         return angularVelocity;
282     }
283 
284     /** Get for the duration of the GNSS cycle in weeks.
285      * @return the duration of the GNSS cycle in weeks
286      */
287     public int getWeeksInCycle() {
288         return weeksInCycle;
289     }
290 
291     /** Get for the duration of the GNSS cycle in seconds.
292      * @return the duration of the GNSS cycle in seconds
293      */
294     public double getCycleDuration() {
295         return cycleDuration;
296     }
297 
298     /** Get the PRN number of the satellite.
299      * @return PRN number of the satellite
300      */
301     public int getPRN() {
302         return prn;
303     }
304 
305     /** Set the PRN number of the satellite.
306      * @param number the prn number ot set
307      */
308     public void setPRN(final int number) {
309         this.prn = number;
310     }
311 
312     /** Get the reference week of the orbit.
313      * @return reference week of the orbit
314      */
315     public int getWeek() {
316         return week;
317     }
318 
319     /** Set the reference week of the orbit.
320      * @param week the week to set
321      */
322     public void setWeek(final int week) {
323         this.week = week;
324         setGnssDate(new GNSSDate(week, timeDriver.getValue(), system, timeScales));
325     }
326 
327     /** Get the driver for reference time of the GNSS orbit as a duration from week start.
328      * @return driver for the reference time of the GNSS orbit (s)
329      */
330     public ParameterDriver getTimeDriver() {
331         return timeDriver;
332     }
333 
334     /** Get reference time of the GNSS orbit as a duration from week start.
335      * @return reference time of the GNSS orbit (s)
336      */
337     public double getTime() {
338         return getTimeDriver().getValue();
339     }
340 
341     /** Set reference time of the GNSS orbit as a duration from week start.
342      * @param time reference time of the GNSS orbit (s)
343      */
344     public void setTime(final double time) {
345         getTimeDriver().setValue(time);
346     }
347 
348     /** Get the driver for the rate of inclination angle.
349      * @return driver for the rate of inclination angle (rad/s)
350      */
351     public ParameterDriver getIDotDriver() {
352         return iDotDriver;
353     }
354 
355     /** Get rate of inclination angle.
356      * @return rate of inclination angle (rad/s)
357      */
358     public double getIDot() {
359         return getIDotDriver().getValue();
360     }
361 
362     /** Set the driver for the rate of inclination angle.
363      * @param iDot rate of inclination angle (rad/s)
364      */
365     public void setIDot(final double iDot) {
366         getIDotDriver().setValue(iDot);
367     }
368 
369     /** Get the driver for the rate of right ascension.
370      * @return driver for the rate of right ascension (rad/s)
371      */
372     public ParameterDriver getOmegaDotDriver() {
373         return domDriver;
374     }
375 
376     /** Get rate of right ascension.
377      * @return rate of right ascension (rad/s)
378      */
379     public double getOmegaDot() {
380         return getOmegaDotDriver().getValue();
381     }
382 
383     /** Set rate of right ascension.
384      * @param dom rate of right ascension (rad/s)
385      */
386     public void setOmegaDot(final double dom) {
387         getOmegaDotDriver().setValue(dom);
388     }
389 
390     /** Get the driver for the amplitude of the cosine harmonic correction term to the argument of latitude.
391      * @return driver for the amplitude of the cosine harmonic correction term to the argument of latitude (rad)
392      */
393     public ParameterDriver getCucDriver() {
394         return cucDriver;
395     }
396 
397     /** Get amplitude of the cosine harmonic correction term to the argument of latitude.
398      * @return amplitude of the cosine harmonic correction term to the argument of latitude (rad)
399      */
400     public double getCuc() {
401         return getCucDriver().getValue();
402     }
403 
404     /** Set amplitude of the cosine harmonic correction term to the argument of latitude.
405      * @param cuc amplitude of the cosine harmonic correction term to the argument of latitude (rad)
406      */
407     public void setCuc(final double cuc) {
408         getCucDriver().setValue(cuc);
409     }
410 
411     /** Get the driver for the amplitude of the sine harmonic correction term to the argument of latitude.
412      * @return driver for the amplitude of the sine harmonic correction term to the argument of latitude (rad)
413      */
414     public ParameterDriver getCusDriver() {
415         return cusDriver;
416     }
417 
418     /** Get amplitude of the sine harmonic correction term to the argument of latitude.
419      * @return amplitude of the sine harmonic correction term to the argument of latitude (rad)
420      */
421     public double getCus() {
422         return getCusDriver().getValue();
423     }
424 
425     /** Set amplitude of the sine harmonic correction term to the argument of latitude.
426      * @param cus amplitude of the sine harmonic correction term to the argument of latitude (rad)
427      */
428     public void setCus(final double cus) {
429         getCusDriver().setValue(cus);
430     }
431 
432     /** Get the driver for the amplitude of the cosine harmonic correction term to the orbit radius.
433      * @return driver for the amplitude of the cosine harmonic correction term to the orbit radius (m)
434      */
435     public ParameterDriver getCrcDriver() {
436         return crcDriver;
437     }
438 
439     /** Get amplitude of the cosine harmonic correction term to the orbit radius.
440      * @return amplitude of the cosine harmonic correction term to the orbit radius (m)
441      */
442     public double getCrc() {
443         return getCrcDriver().getValue();
444     }
445 
446     /** Set amplitude of the cosine harmonic correction term to the orbit radius.
447      * @param crc amplitude of the cosine harmonic correction term to the orbit radius (m)
448      */
449     public void setCrc(final double crc) {
450         getCrcDriver().setValue(crc);
451     }
452 
453     /** Get the driver for the amplitude of the sine harmonic correction term to the orbit radius.
454      * @return driver for the amplitude of the sine harmonic correction term to the orbit radius (m)
455      */
456     public ParameterDriver getCrsDriver() {
457         return crsDriver;
458     }
459 
460     /** Get amplitude of the sine harmonic correction term to the orbit radius.
461      * @return amplitude of the sine harmonic correction term to the orbit radius (m)
462      */
463     public double getCrs() {
464         return getCrsDriver().getValue();
465     }
466 
467     /** Set amplitude of the sine harmonic correction term to the orbit radius.
468      * @param crs amplitude of the sine harmonic correction term to the orbit radius (m)
469      */
470     public void setCrs(final double crs) {
471         getCrsDriver().setValue(crs);
472     }
473 
474     /** Get the driver for the amplitude of the cosine harmonic correction term to the angle of inclination.
475      * @return driver for the amplitude of the cosine harmonic correction term to the angle of inclination (rad)
476      */
477     public ParameterDriver getCicDriver() {
478         return cicDriver;
479     }
480 
481     /** Get amplitude of the cosine harmonic correction term to the angle of inclination.
482      * @return amplitude of the cosine harmonic correction term to the angle of inclination (rad)
483      */
484     public double getCic() {
485         return getCicDriver().getValue();
486     }
487 
488     /** Set amplitude of the cosine harmonic correction term to the angle of inclination.
489      * @param cic amplitude of the cosine harmonic correction term to the angle of inclination (rad)
490      */
491     public void setCic(final double cic) {
492         getCicDriver().setValue(cic);
493     }
494 
495     /** Get the driver for the amplitude of the sine harmonic correction term to the angle of inclination.
496      * @return driver for the amplitude of the sine harmonic correction term to the angle of inclination (rad)
497      */
498     public ParameterDriver getCisDriver() {
499         return cisDriver;
500     }
501 
502     /** Get amplitude of the sine harmonic correction term to the angle of inclination.
503      * @return amplitude of the sine harmonic correction term to the angle of inclination (rad)
504      */
505     public double getCis() {
506         return getCisDriver().getValue();
507     }
508 
509     /** Set amplitude of the sine harmonic correction term to the angle of inclination.
510      * @param cis amplitude of the sine harmonic correction term to the angle of inclination (rad)
511      */
512     public void setCis(final double cis) {
513         getCisDriver().setValue(cis);
514     }
515 
516 }