1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.time;
18
19 import java.io.Serializable;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.concurrent.atomic.AtomicReference;
24
25 import org.hipparchus.util.FastMath;
26 import org.orekit.annotation.DefaultDataContext;
27 import org.orekit.data.DataContext;
28 import org.orekit.errors.OrekitException;
29 import org.orekit.errors.OrekitMessages;
30 import org.orekit.frames.EOPEntry;
31 import org.orekit.gnss.SatelliteSystem;
32 import org.orekit.utils.Constants;
33 import org.orekit.utils.IERSConventions;
34
35
36
37
38
39
40
41
42
43 public class GNSSDate implements Serializable, TimeStamped {
44
45
46 private static final long serialVersionUID = 201902141L;
47
48
49 private static final int WEEK_D = 7;
50
51
52 private static final double WEEK_S = WEEK_D * Constants.JULIAN_DAY;
53
54
55 private static final double S_TO_MS = 1000.0;
56
57
58
59
60 private static AtomicReference<DateComponents> rolloverReference = new AtomicReference<DateComponents>(null);
61
62
63 private final int weekNumber;
64
65
66 private final double milliInWeek;
67
68
69 private final SatelliteSystem system;
70
71
72 private final transient AbsoluteDate date;
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 @DefaultDataContext
96 public GNSSDate(final int weekNumber, final double milliInWeek,
97 final SatelliteSystem system) {
98 this(weekNumber, milliInWeek, system, DataContext.getDefault().getTimeScales());
99 }
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 public GNSSDate(final int weekNumber,
125 final double milliInWeek,
126 final SatelliteSystem system,
127 final TimeScales timeScales) {
128
129 final int day = (int) FastMath.floor(milliInWeek / (Constants.JULIAN_DAY * S_TO_MS));
130 final double secondsInDay = milliInWeek / S_TO_MS - day * Constants.JULIAN_DAY;
131
132 int w = weekNumber;
133 DateComponents dc = new DateComponents(getWeekReferenceDateComponents(system), weekNumber * 7 + day);
134 final int cycleW = GNSSDateType.getRollOverWeek(system);
135 if (weekNumber < cycleW) {
136
137 DateComponents reference = rolloverReference.get();
138 if (reference == null) {
139
140 final UT1Scale ut1 = timeScales.getUT1(IERSConventions.IERS_2010, true);
141 final List<EOPEntry> eop = ut1.getEOPHistory().getEntries();
142 final int lastMJD = eop.get(eop.size() - 1).getMjd();
143 reference = new DateComponents(DateComponents.MODIFIED_JULIAN_EPOCH, lastMJD);
144 rolloverReference.compareAndSet(null, reference);
145 }
146
147
148 final int cycleD = WEEK_D * cycleW;
149 while (dc.getJ2000Day() < reference.getJ2000Day() - cycleD / 2) {
150 dc = new DateComponents(dc, cycleD);
151 w += cycleW;
152 }
153
154 }
155
156 this.weekNumber = w;
157 this.milliInWeek = milliInWeek;
158 this.system = system;
159
160 date = new AbsoluteDate(dc, new TimeComponents(secondsInDay), getTimeScale(system, timeScales));
161
162 }
163
164
165
166
167
168
169
170
171
172 @DefaultDataContext
173 public GNSSDate(final AbsoluteDate date, final SatelliteSystem system) {
174 this(date, system, DataContext.getDefault().getTimeScales());
175 }
176
177
178
179
180
181
182
183
184
185
186 public GNSSDate(final AbsoluteDate date,
187 final SatelliteSystem system,
188 final TimeScales timeScales) {
189
190 this.system = system;
191 final AbsoluteDate epoch = getWeekReferenceAbsoluteDate(system, timeScales);
192 this.weekNumber = (int) FastMath.floor(date.durationFrom(epoch) / WEEK_S);
193 final AbsoluteDate weekStart = new AbsoluteDate(epoch, WEEK_S * weekNumber);
194 this.milliInWeek = date.durationFrom(weekStart) * S_TO_MS;
195 this.date = date;
196
197 }
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216 public static void setRolloverReference(final DateComponents reference) {
217 rolloverReference.set(reference);
218 }
219
220
221
222
223
224
225
226 public static DateComponents getRolloverReference() {
227 return rolloverReference.get();
228 }
229
230
231
232
233
234
235
236
237 public int getWeekNumber() {
238 return weekNumber;
239 }
240
241
242
243
244 public double getMilliInWeek() {
245 return milliInWeek;
246 }
247
248
249 @Override
250 public AbsoluteDate getDate() {
251 return date;
252 }
253
254
255
256
257
258
259 private TimeScale getTimeScale(final SatelliteSystem satellite,
260 final TimeScales timeScales) {
261 switch (satellite) {
262 case GPS : return timeScales.getGPS();
263 case GALILEO : return timeScales.getGST();
264 case QZSS : return timeScales.getQZSS();
265 case BEIDOU : return timeScales.getBDT();
266 case IRNSS : return timeScales.getIRNSS();
267 case SBAS : return timeScales.getGPS();
268 default : throw new OrekitException(OrekitMessages.INVALID_SATELLITE_SYSTEM, satellite);
269 }
270 }
271
272
273
274
275
276
277
278 private AbsoluteDate getWeekReferenceAbsoluteDate(final SatelliteSystem satellite,
279 final TimeScales timeScales) {
280 switch (satellite) {
281 case GPS : return timeScales.getGpsEpoch();
282 case GALILEO : return timeScales.getGalileoEpoch();
283 case QZSS : return timeScales.getQzssEpoch();
284 case BEIDOU : return timeScales.getBeidouEpoch();
285 case IRNSS : return timeScales.getIrnssEpoch();
286 case SBAS : return timeScales.getGpsEpoch();
287 default : throw new OrekitException(OrekitMessages.INVALID_SATELLITE_SYSTEM, satellite);
288 }
289 }
290
291
292
293
294
295
296 private DateComponents getWeekReferenceDateComponents(final SatelliteSystem satellite) {
297 switch (satellite) {
298 case GPS : return DateComponents.GPS_EPOCH;
299 case GALILEO : return DateComponents.GALILEO_EPOCH;
300 case QZSS : return DateComponents.QZSS_EPOCH;
301 case BEIDOU : return DateComponents.BEIDOU_EPOCH;
302 case IRNSS : return DateComponents.IRNSS_EPOCH;
303 case SBAS : return DateComponents.GPS_EPOCH;
304 default : throw new OrekitException(OrekitMessages.INVALID_SATELLITE_SYSTEM, satellite);
305 }
306 }
307
308
309
310
311 @DefaultDataContext
312 private Object writeReplace() {
313 return new DataTransferObject(weekNumber, milliInWeek, system);
314 }
315
316
317 @DefaultDataContext
318 private static class DataTransferObject implements Serializable {
319
320
321 private static final long serialVersionUID = 201902141L;
322
323
324 private final int weekNumber;
325
326
327 private final double milliInWeek;
328
329
330 private final SatelliteSystem system;
331
332
333
334
335
336
337 DataTransferObject(final int weekNumber, final double milliInWeek,
338 final SatelliteSystem system) {
339 this.weekNumber = weekNumber;
340 this.milliInWeek = milliInWeek;
341 this.system = system;
342 }
343
344
345
346
347 private Object readResolve() {
348 return new GNSSDate(weekNumber, milliInWeek, system);
349 }
350
351 }
352
353
354 private enum GNSSDateType {
355
356
357 GPS(SatelliteSystem.GPS, 1024),
358
359
360 GALILEO(SatelliteSystem.GALILEO, 4096),
361
362
363 QZSS(SatelliteSystem.QZSS, 1024),
364
365
366 BEIDOU(SatelliteSystem.BEIDOU, 8192),
367
368
369 IRNSS(SatelliteSystem.IRNSS, 1024),
370
371
372 SBAS(SatelliteSystem.SBAS, 1024);
373
374
375 private static final Map<SatelliteSystem, Integer> CYCLE_MAP = new HashMap<SatelliteSystem, Integer>();
376 static {
377 for (final GNSSDateType type : values()) {
378 final int val = type.getRollOverCycle();
379 final SatelliteSystem satellite = type.getSatelliteSystem();
380 CYCLE_MAP.put(satellite, val);
381 }
382 }
383
384
385 private final int numberOfWeek;
386
387
388 private final SatelliteSystem satelliteSystem;
389
390
391
392
393
394
395
396 GNSSDateType(final SatelliteSystem system, final int rollover) {
397 this.satelliteSystem = system;
398 this.numberOfWeek = rollover;
399 }
400
401
402
403
404 private int getRollOverCycle() {
405 return numberOfWeek;
406 }
407
408
409
410
411 private SatelliteSystem getSatelliteSystem() {
412 return satelliteSystem;
413 }
414
415
416
417
418
419
420 private static int getRollOverWeek(final SatelliteSystem satellite) {
421 return CYCLE_MAP.get(satellite);
422 }
423
424 }
425 }