1 /* Copyright 2002-2024 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.time;
18
19 import java.io.Serializable;
20
21 import org.hipparchus.util.FastMath;
22 import org.orekit.annotation.DefaultDataContext;
23 import org.orekit.data.DataContext;
24 import org.orekit.propagation.analytical.gnss.data.GNSSConstants;
25 import org.orekit.utils.Constants;
26
27 /**
28 * Container for date in GLONASS form.
29 * @author Bryan Cazabonne
30 * @see AbsoluteDate
31 * @see "GLONASS Interface Control Document v1.0, 2016"
32 * @since 10.0
33 */
34 public class GLONASSDate implements Serializable, TimeStamped {
35
36 /** Serializable UID. */
37 private static final long serialVersionUID = 20190131L;
38
39 /** Constant for date computation. */
40 private static final int C1 = 44195;
41
42 /** Constant for date computation. */
43 private static final int C2 = 45290;
44
45 /** The number of the current day in a four year interval N<sub>a</sub>. */
46 private final int na;
47
48 /** The number of the current four year interval N<sub>4</sub>. */
49 private final int n4;
50
51 /** Number of seconds since N<sub>a</sub>. */
52 private final double secInNa;
53
54 /** Current Julian date JD0. */
55 private double jd0;
56
57 /** Greenwich Mean Sidereal Time (rad). */
58 private double gmst;
59
60 /** Corresponding date. */
61 private final transient AbsoluteDate date;
62
63 /** Build an instance corresponding to a GLONASS date.
64 *
65 * <p>This method uses the {@link DataContext#getDefault() default data context}.
66 *
67 * @param na the number of the current day in a four year interval
68 * @param n4 the number of the current four year interval
69 * @param secInNa the number of seconds since na start
70 * @see #GLONASSDate(int, int, double, TimeScale)
71 */
72 @DefaultDataContext
73 public GLONASSDate(final int na, final int n4, final double secInNa) {
74 this(na, n4, secInNa, DataContext.getDefault().getTimeScales().getGLONASS());
75 }
76
77 /**
78 * Build an instance corresponding to a GLONASS date.
79 *
80 * @param na the number of the current day in a four year interval
81 * @param n4 the number of the current four year interval
82 * @param secInNa the number of seconds since na start
83 * @param glonass time scale.
84 * @since 10.1
85 */
86 public GLONASSDate(final int na,
87 final int n4,
88 final double secInNa,
89 final TimeScale glonass) {
90 this.na = na;
91 this.n4 = n4;
92 this.secInNa = secInNa;
93 // Compute JD0
94 final int ratio = FastMath.round((float) (na - 3) / (25 + C1 + C2));
95 this.jd0 = 1461 * (n4 - 1) + na + 2450082.5 - ratio;
96 // GMST
97 this.gmst = computeGMST();
98 this.date = computeDate(glonass);
99 }
100
101 /** Build an instance from an absolute date.
102 *
103 * <p>This method uses the {@link DataContext#getDefault() default data context}.
104 *
105 * @param date absolute date to consider
106 * @see #GLONASSDate(AbsoluteDate, TimeScale)
107 */
108 @DefaultDataContext
109 public GLONASSDate(final AbsoluteDate date) {
110 this(date, DataContext.getDefault().getTimeScales().getGLONASS());
111 }
112
113 /**
114 * Build an instance from an absolute date.
115 *
116 * @param date absolute date to consider
117 * @param glonass time scale.
118 * @since 10.1
119 */
120 public GLONASSDate(final AbsoluteDate date, final TimeScale glonass) {
121 final DateTimeComponents dateTime = date.getComponents(glonass);
122 // N4
123 final int year = dateTime.getDate().getYear();
124 this.n4 = ((int) (year - 1996) / 4) + 1;
125 // Na
126 final int start = 1996 + 4 * (n4 - 1);
127 final double duration = date.durationFrom(new AbsoluteDate(start, 1, 1, glonass));
128 this.na = (int) (duration / 86400) + 1;
129 this.secInNa = dateTime.getTime().getSecondsInLocalDay();
130 // Compute JD0
131 final int ratio = FastMath.round((float) (na - 3) / (25 + C1 + C2));
132 this.jd0 = 1461 * (n4 - 1) + na + 2450082.5 - ratio;
133 // GMST
134 this.gmst = computeGMST();
135 this.date = date;
136 }
137
138 @Override
139 public AbsoluteDate getDate() {
140 return date;
141 }
142
143 /** Get the number of seconds since N<sub>a</sub> start.
144 * @return number of seconds since N<sub>a</sub> start
145 */
146 public double getSecInDay() {
147 return secInNa;
148 }
149
150 /** Get the number of the current day in a four year interval.
151 * @return the number of the current day in a four year interval
152 */
153 public int getDayNumber() {
154 return na;
155 }
156
157 /** Get the number of the current four year interval.
158 * @return the number of the current four year interval
159 */
160 public int getIntervalNumber() {
161 return n4;
162 }
163
164 /** Get the current Julian date JD0.
165 * @return the current date JD0
166 */
167 public double getJD0() {
168 return jd0;
169 }
170
171 /** Get the Greenwich Mean Sidereal Time.
172 * @return the Greenwich Mean Sidereal Time (rad)
173 */
174 public double getGMST() {
175 return gmst;
176 }
177
178 /** Compute the Greenwich Mean Sidereal Time using the current Julian date JD0.
179 * @return the Greenwich Mean Sidereal Time (rad)
180 */
181 private double computeGMST() {
182 final double ref = 2451545.0;
183 // Earth's rotation angle in radians
184 final double era = 2. * GNSSConstants.GLONASS_PI *
185 (0.7790572732640 + 1.00273781191135448 * (jd0 - ref));
186 // Time from Epoch 2000 (1st January, 00:00 UTC) till current Epoch in Julian centuries
187 final double time = (jd0 - ref) / Constants.JULIAN_CENTURY;
188 // Time to the power n
189 final double time2 = time * time;
190 final double time3 = time2 * time;
191 final double time4 = time2 * time2;
192 final double time5 = time2 * time3;
193 // GMST computation
194 final double gTime = era + 7.03270726e-8 + time * 2.23603658710194e-2 +
195 time2 * 6.7465784654e-6 - time3 * 2.1332e-12 - time4 * 1.452308e-10 - time5 * 1.784e-13;
196 return gTime;
197 }
198
199 /** Compute the GLONASS date.
200 * @return the date
201 * @param glonass time scale.
202 */
203 private AbsoluteDate computeDate(final TimeScale glonass) {
204 // Compute the number of Julian day for the current date
205 final double jdn = jd0 + 0.5;
206 // Coefficients
207 final int a = (int) (jdn + 32044);
208 final int b = (4 * a + 3) / 146097;
209 final int c = a - (146097 * b) / 4;
210 final int d = (4 * c + 3) / 1461;
211 final int e = c - (1461 * d) / 4;
212 final int m = (5 * e + 2) / 153;
213 // Year, month and day
214 final int day = e - (153 * m + 2) / 5 + 1;
215 final int month = m + 3 - 12 * (m / 10);
216 final int year = 100 * b + d - 4800 + m / 10;
217 return new AbsoluteDate(new DateComponents(year, month, day),
218 new TimeComponents(secInNa),
219 glonass);
220 }
221
222 /** Replace the instance with a data transfer object for serialization.
223 * @return data transfer object that will be serialized
224 */
225 @DefaultDataContext
226 private Object writeReplace() {
227 return new DataTransferObject(na, n4, secInNa);
228 }
229
230 /** Internal class used only for serialization. */
231 @DefaultDataContext
232 private static class DataTransferObject implements Serializable {
233
234 /** Serializable UID. */
235 private static final long serialVersionUID = 20190131L;
236
237 /** The number of the current day in a four year interval N<sub>a</sub>. */
238 private final int na;
239
240 /** The number of the current four year interval N<sub>4</sub>. */
241 private final int n4;
242
243 /** Number of seconds since N<sub>a</sub>. */
244 private final double secInNa;
245
246 /** Simple constructor.
247 * @param na the number of the current day in a four year interval
248 * @param n4 the number of the current four year interval
249 * @param secInNa the number of seconds since na start
250 */
251 DataTransferObject(final int na, final int n4, final double secInNa) {
252 this.na = na;
253 this.n4 = n4;
254 this.secInNa = secInNa;
255 }
256
257 /** Replace the deserialized data transfer object with a {@link GPSDate}.
258 * @return replacement {@link GPSDate}
259 */
260 private Object readResolve() {
261 return new GLONASSDate(na, n4, secInNa);
262 }
263
264 }
265
266 }