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.data;
18  
19  import org.hipparchus.ode.nonstiff.ClassicalRungeKuttaIntegrator;
20  import org.hipparchus.util.FastMath;
21  import org.orekit.annotation.DefaultDataContext;
22  import org.orekit.attitudes.AttitudeProvider;
23  import org.orekit.data.DataContext;
24  import org.orekit.frames.Frame;
25  import org.orekit.propagation.numerical.GLONASSNumericalPropagator;
26  import org.orekit.propagation.numerical.GLONASSNumericalPropagatorBuilder;
27  
28  /**
29   * Container for data contained in a Glonass FDMA navigation message.
30   * @author Bryan Cazabonne
31   * @since 11.0
32   */
33  public class GLONASSFdmaNavigationMessage extends AbstractEphemerisMessage implements GLONASSOrbitalElements {
34  
35      /** Message type.
36       * @since 14.0
37       */
38      public static final String FDMA = "FDMA";
39  
40      /** Message frame time. */
41      private double time;
42  
43      /** SV clock bias. */
44      private double tauN;
45  
46      /** SV relative frequency bias. */
47      private double gammaN;
48  
49      /** Frequency number. */
50      private int frequencyNumber;
51  
52      /** Status flags.
53       * @since 12.0
54       */
55      private int statusFlags;
56  
57      /** Health flags.
58       * @since 12.0
59       */
60      private int healthFlags;
61  
62      /** Group Delay Difference (s).
63       * @since 12.0
64       */
65      private double groupDelayDifference;
66  
67      /** User range accuracy (m).
68       * @since 12.0
69       */
70      private double ura;
71  
72      /** Constructor. */
73      public GLONASSFdmaNavigationMessage() {
74          // Nothing to do ...
75      }
76  
77      /** {@inheritDoc} */
78      @Override
79      public String getNavigationMessageType() {
80          return FDMA;
81      }
82  
83      /** {@inheritDoc} */
84      @Override
85      public String getNavigationMessageSubType() {
86          return null;
87      }
88  
89      /**
90       * Get the propagator corresponding to the navigation message.
91       * <p>The attitude provider is set by default to EME2000 aligned in the
92       *  default data context.<br>
93       * The mass is set by default to the
94       *  {@link org.orekit.propagation.Propagator#DEFAULT_MASS DEFAULT_MASS}.<br>
95       * The data context is by default to the
96       *  {@link DataContext#getDefault() default data context}.<br>
97       * The ECI frame is set by default to the
98       *  {@link org.orekit.frames.Predefined#EME2000 EME2000 frame} in the default data
99       *  context.<br>
100      * </p>
101      * @param step integration step in seconds
102      * @return the propagator corresponding to the navigation message
103      * @see #getPropagator(double, DataContext)
104      * @see #getPropagator(double, DataContext, AttitudeProvider, Frame, double)
105      * @since 12.0
106      */
107     @DefaultDataContext
108     public GLONASSNumericalPropagator getPropagator(final double step) {
109         return new GLONASSNumericalPropagatorBuilder(new ClassicalRungeKuttaIntegrator(step),
110                                                      this, isAccAvailable()).build();
111     }
112 
113     /**
114      * Get the propagator corresponding to the navigation message.
115      * <p>The attitude provider is set by default to EME2000 aligned in the
116      *  default data context.<br>
117      * The mass is set by default to the
118      *  {@link org.orekit.propagation.Propagator#DEFAULT_MASS DEFAULT_MASS}.<br>
119      * The data context is by default to the
120      *  {@link DataContext#getDefault() default data context}.<br>
121      * The ECI frame is set by default to the
122      *  {@link org.orekit.frames.Predefined#EME2000 EME2000 frame} in the default data
123      *  context.<br>
124      * </p>
125      * @param step integration step in seconds
126      * @param context data context
127      * @return the propagator corresponding to the navigation message
128      * @see #getPropagator(double)
129      * @see #getPropagator(double, DataContext, AttitudeProvider, Frame, double)
130      * @since 12.0
131      */
132     public GLONASSNumericalPropagator getPropagator(final double step, final DataContext context) {
133         return new GLONASSNumericalPropagatorBuilder(new ClassicalRungeKuttaIntegrator(step),
134                                                      this, isAccAvailable(), context).build();
135     }
136 
137     /**
138      * Get the propagator corresponding to the navigation message.
139      * @param step integration step in seconds
140      * @param context data context
141      * @param provider attitude provider
142      * @param inertial inertial frame, use to provide the propagated orbit
143      * @param mass spacecraft mass in kg
144      * @return the propagator corresponding to the navigation message
145      * @see #getPropagator(double)
146      * @see #getPropagator(double, DataContext)
147      * @since 12.0
148      */
149     public GLONASSNumericalPropagator getPropagator(final double step, final DataContext context,
150                                                     final AttitudeProvider provider, final Frame inertial,
151                                                     final double mass) {
152         return new GLONASSNumericalPropagatorBuilder(new ClassicalRungeKuttaIntegrator(step),
153                                                      this, isAccAvailable(), context).attitudeProvider(provider)
154                                                                                      .eci(inertial)
155                                                                                      .mass(mass)
156                                                                                      .build();
157     }
158 
159     /** {@inheritDoc} */
160     @Override
161     public double getTN() {
162         return tauN;
163     }
164 
165     /**
166      * Setter for the SV clock bias.
167      * @param tn the SV clock bias
168      */
169     public void setTauN(final double tn) {
170         this.tauN = tn;
171     }
172 
173     /** {@inheritDoc} */
174     @Override
175     public double getGammaN() {
176         return gammaN;
177     }
178 
179     /**
180      * Setter for the SV relative frequency bias.
181      * @param gammaN the SV relative frequency bias.
182      */
183     public void setGammaN(final double gammaN) {
184         this.gammaN = gammaN;
185     }
186 
187     /**
188      * Getter for the frequency number.
189      * @return the frequency number
190      */
191     public int getFrequencyNumber() {
192         return frequencyNumber;
193     }
194 
195     /**
196      * Setter for the frequency number.
197      * @param frequencyNumber the number to set
198      */
199     public void setFrequencyNumber(final double frequencyNumber) {
200         this.frequencyNumber = (int) frequencyNumber;
201     }
202 
203     /** {@inheritDoc} */
204     @Override
205     public double getTime() {
206         return time;
207     }
208 
209     /**
210      * Setter for the message frame time.
211      * @param time the time to set
212      */
213     public void setTime(final double time) {
214         this.time = time;
215     }
216 
217     /** Get status flags.
218      * @return status flags
219      * @since 12.0
220      */
221     public int getStatusFlags() {
222         return statusFlags;
223     }
224 
225     /** Set status flag.
226      * @param statusFlags status flag (parsed as a double)
227      * @since 12.0
228      */
229     public void setStatusFlags(final double statusFlags) {
230         this.statusFlags = (int) FastMath.rint(statusFlags);
231     }
232 
233     /** Set health flag.
234      * @param healthFlags health flag (parsed as a double)
235      * @since 12.0
236      */
237     public void setHealthFlags(final double healthFlags) {
238         this.healthFlags = Double.isNaN(healthFlags) ? 15 : (int) FastMath.rint(healthFlags);
239     }
240 
241     /** Get health flags.
242      * @return health flags
243      * @since 12.0
244      */
245     public int getHealthFlags() {
246         return healthFlags;
247     }
248 
249     /** Get group delay difference.
250      * @return group delay difference
251      * @since 12.0
252      */
253     public double getGroupDelayDifference() {
254         return groupDelayDifference;
255     }
256 
257     /** Set group delay difference.
258      * @param groupDelayDifference group delay difference
259      * @since 12.0
260      */
261     public void setGroupDelayDifference(final double groupDelayDifference) {
262         this.groupDelayDifference = Double.isNaN(groupDelayDifference) ?
263                                     0.999999999999e+09 :
264                                     groupDelayDifference;
265     }
266 
267     /**
268      * Getter for the user range accuray (meters).
269      * @return the user range accuracy
270      * @since 12.0
271      */
272     public double getURA() {
273         return ura;
274     }
275 
276     /**
277      * Setter for the user range accuracy.
278      * @param accuracy the value to set
279      * @since 12.0
280      */
281     public void setURA(final double accuracy) {
282         this.ura = accuracy;
283     }
284 
285     /**
286      * Check if the acceleration is available in the navigation message.
287      * @return true if the acceleration is available
288      */
289     private boolean isAccAvailable() {
290         return getXDotDot() != 0.0 || getYDotDot() != 0.0 || getZDotDot() != 0.0;
291     }
292 
293 }