1 /* Copyright 2002-2012 Space Applications Services
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.files.sp3;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.LinkedHashMap;
22 import java.util.List;
23 import java.util.Locale;
24 import java.util.Map;
25 import java.util.function.Function;
26
27 import org.hipparchus.geometry.euclidean.threed.Vector3D;
28 import org.orekit.files.general.EphemerisFile;
29 import org.orekit.frames.Frame;
30 import org.orekit.gnss.TimeSystem;
31 import org.orekit.propagation.BoundedPropagator;
32 import org.orekit.time.AbsoluteDate;
33 import org.orekit.utils.CartesianDerivativesFilter;
34 import org.orekit.utils.TimeStampedPVCoordinates;
35
36 /**
37 * Represents a parsed SP3 orbit file.
38 * @author Thomas Neidhart
39 * @author Evan Ward
40 */
41 public class SP3
42 implements EphemerisFile<SP3.SP3Coordinate, SP3.SP3Ephemeris> {
43 /** String representation of the center of ephemeris coordinate system. **/
44 public static final String SP3_FRAME_CENTER_STRING = "EARTH";
45
46 /** File type indicator. */
47 public enum SP3FileType {
48 /** GPS only file. */
49 GPS,
50 /** Mixed file. */
51 MIXED,
52 /** GLONASS only file. */
53 GLONASS,
54 /** LEO only file. */
55 LEO,
56 /** Galileo only file. */
57 GALILEO,
58 /** SBAS only file. */
59 SBAS,
60 /** IRNSS only file. */
61 IRNSS,
62 /** COMPASS only file. */
63 COMPASS,
64 /** QZSS only file. */
65 QZSS,
66 /** undefined file format. */
67 UNDEFINED
68 }
69
70 /** Orbit type indicator. */
71 public enum SP3OrbitType {
72 /** fitted. */
73 FIT,
74 /** extrapolated or predicted. */
75 EXT,
76 /** broadcast. */
77 BCT,
78 /** fitted after applying a Helmert transformation. */
79 HLM,
80 /** other type, defined by SP3 file producing agency.
81 * @since 9.3
82 */
83 OTHER;
84
85 /** Parse a string to get the type.
86 * @param s string to parse
87 * @return the type corresponding to the string
88 */
89 public static SP3OrbitType parseType(final String s) {
90 final String normalizedString = s.trim().toUpperCase(Locale.US);
91 if ("EST".equals(normalizedString)) {
92 return FIT;
93 } else if ("BHN".equals(normalizedString)) {
94 // ESOC navigation team uses BHN for files produced
95 // by their main parameter estimation program Bahn
96 return FIT;
97 } else if ("PRO".equals(normalizedString)) {
98 // ESOC navigation team uses PRO for files produced
99 // by their orbit propagation program Propag
100 return EXT;
101 } else {
102 try {
103 return valueOf(normalizedString);
104 } catch (IllegalArgumentException iae) {
105 return OTHER;
106 }
107 }
108 }
109
110 }
111
112 /** File type. */
113 private SP3FileType type;
114
115 /** Time system. */
116 private TimeSystem timeSystem;
117
118 /** Epoch of the file. */
119 private AbsoluteDate epoch;
120
121 /** GPS week. */
122 private int gpsWeek;
123
124 /** Seconds of the current GPS week. */
125 private double secondsOfWeek;
126
127 /** Julian day. */
128 private int julianDay;
129
130 /** Day fraction. */
131 private double dayFraction;
132
133 /** Time-interval between epochs. */
134 private double epochInterval;
135
136 /** Number of epochs. */
137 private int numberOfEpochs;
138
139 /** Coordinate system. */
140 private String coordinateSystem;
141
142 /** Data used indicator. */
143 private String dataUsed;
144
145 /** Orbit type. */
146 private SP3OrbitType orbitType;
147
148 /** Key for orbit type.
149 * @since 9.3
150 */
151 private String orbitTypeKey;
152
153 /** Agency providing the file. */
154 private String agency;
155
156 /** Indicates if data contains velocity or not. */
157 private CartesianDerivativesFilter filter;
158
159 /** Standard gravitational parameter in m^3 / s^2. */
160 private final double mu;
161
162 /** Number of samples to use when interpolating. */
163 private final int interpolationSamples;
164
165 /** Maps {@link #coordinateSystem} to a {@link Frame}. */
166 private final Function<? super String, ? extends Frame> frameBuilder;
167
168 /** A map containing satellite information. */
169 private Map<String, SP3Ephemeris> satellites;
170
171 /**
172 * Create a new SP3 file object.
173 *
174 * @param mu is the standard gravitational parameter in m^3 / s^2.
175 * @param interpolationSamples number of samples to use in interpolation.
176 * @param frameBuilder for constructing a reference frame from the identifier
177 */
178 public SP3(final double mu,
179 final int interpolationSamples,
180 final Function<? super String, ? extends Frame> frameBuilder) {
181 this.mu = mu;
182 this.interpolationSamples = interpolationSamples;
183 this.frameBuilder = frameBuilder;
184 // must be linked has map to preserve order of satellites in the file.
185 satellites = new LinkedHashMap<>();
186 }
187
188 /**
189 * Set the derivatives filter.
190 *
191 * @param filter that indicates which derivatives of position are available.
192 */
193 public void setFilter(final CartesianDerivativesFilter filter) {
194 this.filter = filter;
195 }
196
197 /** Returns the {@link SP3FileType} associated with this SP3 file.
198 * @return the file type for this SP3 file
199 */
200 public SP3FileType getType() {
201 return type;
202 }
203
204 /** Set the file type for this SP3 file.
205 * @param fileType the file type to be set
206 */
207 public void setType(final SP3FileType fileType) {
208 this.type = fileType;
209 }
210
211 /** Returns the {@link TimeSystem} used to time-stamp position entries.
212 * @return the {@link TimeSystem} of the orbit file
213 */
214 public TimeSystem getTimeSystem() {
215 return timeSystem;
216 }
217
218 /** Set the time system used in this SP3 file.
219 * @param system the time system to be set
220 */
221 public void setTimeSystem(final TimeSystem system) {
222 this.timeSystem = system;
223 }
224
225 /** Returns the data used indicator from the SP3 file.
226 * @return the data used indicator (unparsed)
227 */
228 public String getDataUsed() {
229 return dataUsed;
230 }
231
232 /** Set the data used indicator for this SP3 file.
233 * @param data the data used indicator to be set
234 */
235 public void setDataUsed(final String data) {
236 this.dataUsed = data;
237 }
238
239 /** Returns the start epoch of the orbit file.
240 * @return the start epoch
241 */
242 public AbsoluteDate getEpoch() {
243 return epoch;
244 }
245
246 /** Set the epoch of the SP3 file.
247 * @param time the epoch to be set
248 */
249 public void setEpoch(final AbsoluteDate time) {
250 this.epoch = time;
251 }
252
253 /** Returns the GPS week as contained in the SP3 file.
254 * @return the GPS week of the SP3 file
255 */
256 public int getGpsWeek() {
257 return gpsWeek;
258 }
259
260 /** Set the GPS week of the SP3 file.
261 * @param week the GPS week to be set
262 */
263 public void setGpsWeek(final int week) {
264 this.gpsWeek = week;
265 }
266
267 /** Returns the seconds of the GPS week as contained in the SP3 file.
268 * @return the seconds of the GPS week
269 */
270 public double getSecondsOfWeek() {
271 return secondsOfWeek;
272 }
273
274 /** Set the seconds of the GPS week for this SP3 file.
275 * @param seconds the seconds to be set
276 */
277 public void setSecondsOfWeek(final double seconds) {
278 this.secondsOfWeek = seconds;
279 }
280
281 /** Returns the julian day for this SP3 file.
282 * @return the julian day
283 */
284 public int getJulianDay() {
285 return julianDay;
286 }
287
288 /** Set the julian day for this SP3 file.
289 * @param day the julian day to be set
290 */
291 public void setJulianDay(final int day) {
292 this.julianDay = day;
293 }
294
295 /** Returns the day fraction for this SP3 file.
296 * @return the day fraction
297 */
298 public double getDayFraction() {
299 return dayFraction;
300 }
301
302 /** Set the day fraction for this SP3 file.
303 * @param fraction the day fraction to be set
304 */
305 public void setDayFraction(final double fraction) {
306 this.dayFraction = fraction;
307 }
308
309 /** Returns the time interval between epochs (in seconds).
310 * @return the time interval between epochs
311 */
312 public double getEpochInterval() {
313 return epochInterval;
314 }
315
316 /** Set the epoch interval for this SP3 file.
317 * @param interval the interval between orbit entries
318 */
319 public void setEpochInterval(final double interval) {
320 this.epochInterval = interval;
321 }
322
323 /** Returns the number of epochs contained in this orbit file.
324 * @return the number of epochs
325 */
326 public int getNumberOfEpochs() {
327 return numberOfEpochs;
328 }
329
330 /** Set the number of epochs as contained in the SP3 file.
331 * @param epochCount the number of epochs to be set
332 */
333 public void setNumberOfEpochs(final int epochCount) {
334 this.numberOfEpochs = epochCount;
335 }
336
337 /** Returns the coordinate system of the entries in this orbit file.
338 * @return the coordinate system
339 */
340 public String getCoordinateSystem() {
341 return coordinateSystem;
342 }
343
344 /** Set the coordinate system used for the orbit entries.
345 * @param system the coordinate system to be set
346 */
347 public void setCoordinateSystem(final String system) {
348 this.coordinateSystem = system;
349 }
350
351 /** Returns the {@link SP3OrbitType} for this SP3 file.
352 * @return the orbit type
353 */
354 public SP3OrbitType getOrbitType() {
355 return orbitType;
356 }
357
358 /** Returns the orbit type key for this SP3 file.
359 * @return the orbit type key
360 * @since 9.3
361 */
362 public String getOrbitTypeKey() {
363 return orbitTypeKey;
364 }
365
366 /** Set the orbit type key for this SP3 file.
367 * @param oTypeKey the orbit type key to be set
368 * @since 9.3
369 */
370 public void setOrbitTypeKey(final String oTypeKey) {
371 this.orbitTypeKey = oTypeKey;
372 this.orbitType = SP3OrbitType.parseType(oTypeKey);
373 }
374
375 /** Returns the agency that prepared this SP3 file.
376 * @return the agency
377 */
378 public String getAgency() {
379 return agency;
380 }
381
382 /** Set the agency string for this SP3 file.
383 * @param agencyStr the agency string to be set
384 */
385 public void setAgency(final String agencyStr) {
386 this.agency = agencyStr;
387 }
388
389 /** Add a new satellite with a given identifier to the list of
390 * stored satellites.
391 * @param satId the satellite identifier
392 */
393 public void addSatellite(final String satId) {
394 // only add satellites which have not been added before
395 satellites.putIfAbsent(satId, new SP3Ephemeris(satId));
396 }
397
398 @Override
399 public Map<String, SP3Ephemeris> getSatellites() {
400 return Collections.unmodifiableMap(satellites);
401 }
402
403 /** Get the number of satellites contained in this orbit file.
404 * @return the number of satellites
405 */
406 public int getSatelliteCount() {
407 return satellites.size();
408 }
409
410 /**
411 * Set the formal accuracy for a satellite.
412 *
413 * @param index is the index of the satellite.
414 * @param accuracy of the satellite, in m.
415 */
416 public void setAccuracy(final int index, final double accuracy) {
417 int n = index;
418 for (final SP3Ephemeris ephemeris : satellites.values()) {
419 if (n == 0) {
420 ephemeris.setAccuracy(accuracy);
421 return;
422 }
423 n--;
424 }
425 }
426
427 /**
428 * Get the formal accuracy for a satellite.
429 *
430 * @param index is the index of the satellite.
431 * @return accuracy of the satellite, in m.
432 */
433 public double getAccuracy(final int index) {
434 int n = index;
435 for (final SP3Ephemeris ephemeris : satellites.values()) {
436 if (n == 0) {
437 return ephemeris.getAccuracy();
438 }
439 n--;
440 }
441 return Double.NaN;
442 }
443
444 /** Tests whether a satellite with the given id is contained in this orbit
445 * file.
446 * @param satId the satellite id
447 * @return {@code true} if the satellite is contained in the file,
448 * {@code false} otherwise
449 */
450 public boolean containsSatellite(final String satId) {
451 return satellites.containsKey(satId);
452 }
453
454 /**
455 * Adds a new P/V coordinate for a given satellite.
456 *
457 * @param satId the satellite identifier
458 * @param coord the P/V coordinate of the satellite
459 */
460 public void addSatelliteCoordinate(final String satId, final SP3Coordinate coord) {
461 satellites.get(satId).coordinates.add(coord);
462 }
463
464 /** An ephemeris for a single satellite in a SP3 file. */
465 public class SP3Ephemeris
466 implements EphemerisFile.SatelliteEphemeris<SP3Coordinate, SP3Ephemeris>,
467 EphemerisFile.EphemerisSegment<SP3Coordinate> {
468
469 /** Satellite ID. */
470 private final String id;
471 /** Ephemeris Data. */
472 private final List<SP3Coordinate> coordinates;
473 /** Accuracy in m. */
474 private double accuracy;
475
476 /**
477 * Create an ephemeris for a single satellite.
478 *
479 * @param id of the satellite.
480 */
481 public SP3Ephemeris(final String id) {
482 this.id = id;
483 this.coordinates = new ArrayList<>();
484 }
485
486 @Override
487 public String getId() {
488 return this.id;
489 }
490
491 @Override
492 public double getMu() {
493 return mu;
494 }
495
496 @Override
497 public Frame getFrame() {
498 return frameBuilder.apply(SP3_FRAME_CENTER_STRING);
499 }
500
501 @Override
502 public int getInterpolationSamples() {
503 return interpolationSamples;
504 }
505
506 @Override
507 public CartesianDerivativesFilter getAvailableDerivatives() {
508 return filter;
509 }
510
511 @Override
512 public List<SP3Coordinate> getCoordinates() {
513 return Collections.unmodifiableList(this.coordinates);
514 }
515
516 /** Returns a list containing only {@code this}. */
517 @Override
518 public List<SP3Ephemeris> getSegments() {
519 return Collections.singletonList(this);
520 }
521
522 @Override
523 public AbsoluteDate getStart() {
524 return coordinates.get(0).getDate();
525 }
526
527 @Override
528 public AbsoluteDate getStop() {
529 return coordinates.get(coordinates.size() - 1).getDate();
530 }
531
532 @Override
533 public BoundedPropagator getPropagator() {
534 return EphemerisSegment.super.getPropagator();
535 }
536
537 /**
538 * Set the accuracy for this satellite.
539 *
540 * @param accuracy in m.
541 */
542 public void setAccuracy(final double accuracy) {
543 this.accuracy = accuracy;
544 }
545
546 /**
547 * Get the formal accuracy for this satellite.
548 *
549 * <p>The accuracy is limited by the SP3 standard to be a power of 2 in mm.
550 * The value returned here is in meters.</p>
551 *
552 * @return magnitude of one standard deviation, in m.
553 */
554 public double getAccuracy() {
555 return accuracy;
556 }
557
558 }
559
560 /** A single record of position clock and possibly derivatives in an SP3 file. */
561 public static class SP3Coordinate extends TimeStampedPVCoordinates {
562
563 /** Serializable UID. */
564 private static final long serialVersionUID = 20161116L;
565 /** Clock correction in s. */
566 private final double clock;
567 /** Clock rate in s / s. */
568 private final double clockRate;
569
570 /**
571 * Create a coordinate with only position.
572 *
573 * @param date of validity.
574 * @param position of the satellite.
575 * @param clock correction in s.
576 */
577 public SP3Coordinate(final AbsoluteDate date,
578 final Vector3D position,
579 final double clock) {
580 this(date, position, Vector3D.ZERO, clock, 0);
581 }
582
583 /**
584 * Create a coordinate with position and velocity.
585 *
586 * @param date of validity.
587 * @param position of the satellite.
588 * @param velocity of the satellite.
589 * @param clock correction in s.
590 * @param clockRate in s / s.
591 */
592 public SP3Coordinate(final AbsoluteDate date,
593 final Vector3D position,
594 final Vector3D velocity,
595 final double clock,
596 final double clockRate) {
597 super(date, position, velocity, Vector3D.ZERO);
598 this.clock = clock;
599 this.clockRate = clockRate;
600 }
601
602 /**
603 * Returns the clock correction value.
604 *
605 * @return the clock correction in s.
606 */
607 public double getClockCorrection() {
608 return clock;
609 }
610
611 /**
612 * Returns the clock rate.
613 *
614 * @return the clock rate of change in s/s.
615 */
616 public double getClockRateChange() {
617 return clockRate;
618 }
619
620 }
621
622 }