1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.gnss;
18 import java.io.BufferedReader;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.InputStreamReader;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27
28 import org.hipparchus.exception.DummyLocalizable;
29 import org.hipparchus.geometry.euclidean.threed.Vector3D;
30 import org.hipparchus.geometry.euclidean.twod.Vector2D;
31 import org.hipparchus.util.FastMath;
32 import org.orekit.data.DataLoader;
33 import org.orekit.data.DataProvidersManager;
34 import org.orekit.errors.OrekitException;
35 import org.orekit.errors.OrekitMessages;
36 import org.orekit.time.AbsoluteDate;
37 import org.orekit.time.TimeScale;
38 import org.orekit.time.TimeScalesFactory;
39
40 public class RinexLoader {
41
42
43 public static final String DEFAULT_RINEX_2_SUPPORTED_NAMES = "^\\w{4}\\d{3}[0a-x](?:\\d{2})?\\.\\d{2}[oO]$";
44
45
46 public static final String DEFAULT_RINEX_3_SUPPORTED_NAMES = "^\\w{9}_\\w{1}_\\d{11}_\\d{2}\\w_\\d{2}\\w{1}_\\w{2}\\.rnx$";
47
48
49 private static final String RINEX_VERSION_TYPE = "RINEX VERSION / TYPE";
50 private static final String COMMENT = "COMMENT";
51 private static final String PGM_RUN_BY_DATE = "PGM / RUN BY / DATE";
52 private static final String MARKER_NAME = "MARKER NAME";
53 private static final String MARKER_NUMBER = "MARKER NUMBER";
54 private static final String MARKER_TYPE = "MARKER TYPE";
55 private static final String OBSERVER_AGENCY = "OBSERVER / AGENCY";
56 private static final String REC_NB_TYPE_VERS = "REC # / TYPE / VERS";
57 private static final String ANT_NB_TYPE = "ANT # / TYPE";
58 private static final String APPROX_POSITION_XYZ = "APPROX POSITION XYZ";
59 private static final String ANTENNA_DELTA_H_E_N = "ANTENNA: DELTA H/E/N";
60 private static final String ANTENNA_DELTA_X_Y_Z = "ANTENNA: DELTA X/Y/Z";
61 private static final String ANTENNA_PHASECENTER = "ANTENNA: PHASECENTER";
62 private static final String ANTENNA_B_SIGHT_XYZ = "ANTENNA: B.SIGHT XYZ";
63 private static final String ANTENNA_ZERODIR_AZI = "ANTENNA: ZERODIR AZI";
64 private static final String ANTENNA_ZERODIR_XYZ = "ANTENNA: ZERODIR XYZ";
65 private static final String NB_OF_SATELLITES = "# OF SATELLITES";
66 private static final String WAVELENGTH_FACT_L1_2 = "WAVELENGTH FACT L1/2";
67 private static final String RCV_CLOCK_OFFS_APPL = "RCV CLOCK OFFS APPL";
68 private static final String INTERVAL = "INTERVAL";
69 private static final String TIME_OF_FIRST_OBS = "TIME OF FIRST OBS";
70 private static final String TIME_OF_LAST_OBS = "TIME OF LAST OBS";
71 private static final String LEAP_SECONDS = "LEAP SECONDS";
72 private static final String PRN_NB_OF_OBS = "PRN / # OF OBS";
73 private static final String NB_TYPES_OF_OBSERV = "# / TYPES OF OBSERV";
74 private static final String END_OF_HEADER = "END OF HEADER";
75 private static final String CENTER_OF_MASS_XYZ = "CENTER OF MASS: XYZ";
76 private static final String SIGNAL_STRENGTH_UNIT = "SIGNAL STRENGTH UNIT";
77 private static final String SYS_NB_OBS_TYPES = "SYS / # / OBS TYPES";
78 private static final String SYS_DCBS_APPLIED = "SYS / DCBS APPLIED";
79 private static final String SYS_PCVS_APPLIED = "SYS / PCVS APPLIED";
80 private static final String SYS_SCALE_FACTOR = "SYS / SCALE FACTOR";
81 private static final String SYS_PHASE_SHIFT = "SYS / PHASE SHIFT";
82 private static final String GLONASS_SLOT_FRQ_NB = "GLONASS SLOT / FRQ #";
83 private static final String GLONASS_COD_PHS_BIS = "GLONASS COD/PHS/BIS";
84
85 private static final String GPS = "GPS";
86 private static final String GAL = "GAL";
87 private static final String GLO = "GLO";
88 private static final String QZS = "QZS";
89 private static final String BDT = "BDT";
90 private static final String IRN = "IRN";
91
92
93
94 private final Map<RinexHeader, List<ObservationDataSet>> observations;
95
96
97
98
99
100
101
102
103
104 public RinexLoader(final String supportedNames)
105 throws OrekitException {
106 observations = new HashMap<>();
107 DataProvidersManager.getInstance().feed(supportedNames, new Parser());
108 }
109
110
111
112
113
114
115 public RinexLoader(final InputStream input, final String name)
116 throws OrekitException {
117 try {
118 observations = new HashMap<>();
119 new Parser().loadData(input, name);
120 } catch (IOException ioe) {
121 throw new OrekitException(ioe, new DummyLocalizable(ioe.getMessage()));
122 }
123 }
124
125
126
127
128
129 private List<ObservationDataSet> addHeader(final RinexHeader header) {
130 final List<ObservationDataSet> list = new ArrayList<>();
131 observations.put(header, list);
132 return list;
133 }
134
135
136
137
138 public Map<RinexHeader, List<ObservationDataSet>> getObservations() {
139 return Collections.unmodifiableMap(observations);
140 }
141
142
143
144 public class Parser implements DataLoader {
145
146
147 private static final int LABEL_START = 60;
148
149
150 private static final String FILE_TYPE = "O";
151
152
153 @Override
154 public boolean stillAcceptsData() {
155
156 return true;
157 }
158
159
160 @Override
161 public void loadData(final InputStream input, final String name)
162 throws IOException, OrekitException {
163
164 try (BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"))) {
165
166
167 SatelliteSystem satelliteSystem = null;
168 double formatVersion = Double.NaN;
169 boolean inRinexVersion = false;
170 int lineNumber = 0;
171 SatelliteSystem obsTypesSystem = null;
172 String markerName = null;
173 String markerNumber = null;
174 String markerType = null;
175 String observerName = null;
176 String agencyName = null;
177 String receiverNumber = null;
178 String receiverType = null;
179 String receiverVersion = null;
180 String antennaNumber = null;
181 String antennaType = null;
182 Vector3D approxPos = null;
183 Vector3D antRefPoint = null;
184 String obsCode = null;
185 Vector3D antPhaseCenter = null;
186 Vector3D antBSight = null;
187 double antAzi = Double.NaN;
188 Vector3D antZeroDir = null;
189 Vector3D centerMass = null;
190 double antHeight = Double.NaN;
191 Vector2D eccentricities = Vector2D.ZERO;
192 int clkOffset = -1;
193 int nbTypes = -1;
194 int nbSat = -1;
195 double interval = Double.NaN;
196 AbsoluteDate tFirstObs = AbsoluteDate.PAST_INFINITY;
197 AbsoluteDate tLastObs = AbsoluteDate.FUTURE_INFINITY;
198 TimeScale timeScale = null;
199 String timeScaleStr = null;
200 int leapSeconds = 0;
201 AbsoluteDate tObs = AbsoluteDate.PAST_INFINITY;
202 String[] satsObsList = null;
203 String strYear = null;
204 int eventFlag = -1;
205 int nbSatObs = -1;
206 int nbLinesSat = -1;
207 double rcvrClkOffset = 0;
208 boolean inRunBy = false;
209 boolean inMarkerName = false;
210 boolean inMarkerType = false;
211 boolean inObserver = false;
212 boolean inRecType = false;
213 boolean inAntType = false;
214 boolean inAproxPos = false;
215 boolean inAntDelta = false;
216 boolean inTypesObs = false;
217 boolean inFirstObs = false;
218 boolean inPhaseShift = false;
219 boolean inGlonassSlot = false;
220 boolean inGlonassCOD = false;
221 List<ObservationDataSet> observationsList = null;
222
223
224 String line = reader.readLine();
225 lineNumber++;
226 formatVersion = parseDouble(line, 0, 9);
227 int format100 = (int) FastMath.rint(100 * formatVersion);
228
229 if ((format100 != 200) && (format100 != 210) && (format100 != 211) &&
230 (format100 != 300) && (format100 != 301) && (format100 != 302) && (format100 != 303)) {
231 throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
232 }
233
234
235 if (!(parseString(line, 20, 1)).equals(FILE_TYPE)) {
236 throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
237 }
238 satelliteSystem = SatelliteSystem.parseSatelliteSystem(parseString(line, 40, 1));
239 inRinexVersion = true;
240
241 switch (format100 / 100) {
242 case 2:
243
244 final int MAX_OBS_TYPES_PER_LINE_RNX2 = 9;
245 final int MAX_N_SAT_OBSERVATION = 12;
246 final int MAX_N_TYPES_OBSERVATION = 5;
247 final List<ObservationType> typesObs = new ArrayList<>();
248
249 for (line = reader.readLine(); line != null; line = reader.readLine()) {
250 ++lineNumber;
251
252 if (observationsList == null) {
253 switch(line.substring(LABEL_START).trim()) {
254 case RINEX_VERSION_TYPE :
255
256 formatVersion = parseDouble(line, 0, 9);
257
258 if (!(parseString(line, 20, 1)).equals(FILE_TYPE)) {
259 throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
260 }
261 satelliteSystem = SatelliteSystem.parseSatelliteSystem(parseString(line, 40, 1));
262 inRinexVersion = true;
263 break;
264 case COMMENT :
265
266 break;
267 case PGM_RUN_BY_DATE :
268 inRunBy = true;
269 break;
270 case MARKER_NAME :
271 markerName = parseString(line, 0, 60);
272 inMarkerName = true;
273 break;
274 case MARKER_NUMBER :
275 markerNumber = parseString(line, 0, 20);
276 break;
277 case OBSERVER_AGENCY :
278 observerName = parseString(line, 0, 20);
279 agencyName = parseString(line, 20, 40);
280 inObserver = true;
281 break;
282 case REC_NB_TYPE_VERS :
283 receiverNumber = parseString(line, 0, 20);
284 receiverType = parseString(line, 20, 20);
285 receiverVersion = parseString(line, 40, 20);
286 inRecType = true;
287 break;
288 case ANT_NB_TYPE :
289 antennaNumber = parseString(line, 0, 20);
290 antennaType = parseString(line, 20, 20);
291 inAntType = true;
292 break;
293 case APPROX_POSITION_XYZ :
294 approxPos = new Vector3D(parseDouble(line, 0, 14), parseDouble(line, 14, 14),
295 parseDouble(line, 28, 14));
296 inAproxPos = true;
297 break;
298 case ANTENNA_DELTA_H_E_N :
299 antHeight = parseDouble(line, 0, 14);
300 eccentricities = new Vector2D(parseDouble(line, 14, 14), parseDouble(line, 28, 14));
301 inAntDelta = true;
302 break;
303 case NB_OF_SATELLITES :
304 nbSat = parseInt(line, 0, 6);
305 break;
306 case WAVELENGTH_FACT_L1_2 :
307
308
309 break;
310 case RCV_CLOCK_OFFS_APPL :
311 clkOffset = parseInt(line, 0, 6);
312 break;
313 case INTERVAL :
314 interval = parseDouble(line, 0, 10);
315 break;
316 case TIME_OF_FIRST_OBS :
317 switch (satelliteSystem) {
318 case GPS:
319 timeScale = TimeScalesFactory.getGPS();
320 break;
321 case GALILEO:
322 timeScale = TimeScalesFactory.getGST();
323 break;
324 case GLONASS:
325 timeScale = TimeScalesFactory.getGLONASS();
326 break;
327 case MIXED:
328
329 timeScaleStr = parseString(line, 48, 3);
330
331 if (timeScaleStr.equals(GPS)) {
332 timeScale = TimeScalesFactory.getGPS();
333 } else if (timeScaleStr.equals(GAL)) {
334 timeScale = TimeScalesFactory.getGST();
335 } else if (timeScaleStr.equals(GLO)) {
336 timeScale = TimeScalesFactory.getGLONASS();
337 } else {
338 throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
339 }
340 break;
341 default :
342 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
343 lineNumber, name, line);
344 }
345
346 tFirstObs = new AbsoluteDate(parseInt(line, 0, 6),
347 parseInt(line, 6, 6),
348 parseInt(line, 12, 6),
349 parseInt(line, 18, 6),
350 parseInt(line, 24, 6),
351 parseDouble(line, 30, 13), timeScale);
352 inFirstObs = true;
353 break;
354 case TIME_OF_LAST_OBS :
355 tLastObs = new AbsoluteDate(parseInt(line, 0, 6),
356 parseInt(line, 6, 6),
357 parseInt(line, 12, 6),
358 parseInt(line, 18, 6),
359 parseInt(line, 24, 6),
360 parseDouble(line, 30, 13), timeScale);
361 break;
362 case LEAP_SECONDS :
363 leapSeconds = parseInt(line, 0, 6);
364 break;
365 case PRN_NB_OF_OBS :
366
367
368 break;
369 case NB_TYPES_OF_OBSERV :
370 nbTypes = parseInt(line, 0, 6);
371 final int nbLinesTypesObs = (nbTypes + MAX_OBS_TYPES_PER_LINE_RNX2 - 1 ) / MAX_OBS_TYPES_PER_LINE_RNX2;
372
373 for (int j = 0; j < nbLinesTypesObs; j++) {
374 if (j > 0) {
375 line = reader.readLine();
376 lineNumber++;
377 }
378 final int iMax = FastMath.min(MAX_OBS_TYPES_PER_LINE_RNX2, nbTypes - typesObs.size());
379 for (int i = 0; i < iMax; i++) {
380 try {
381 typesObs.add(ObservationType.valueOf(parseString(line, 10 + (6 * i), 2)));
382 } catch (IllegalArgumentException iae) {
383 throw new OrekitException(OrekitMessages.UNKNOWN_RINEX_FREQUENCY,
384 parseString(line, 10 + (6 * i), 2), name, lineNumber);
385 }
386 }
387 }
388 inTypesObs = true;
389 break;
390 case END_OF_HEADER :
391
392 if (!inRinexVersion || !inRunBy || !inMarkerName ||
393 !inObserver || !inRecType || !inAntType ||
394 !inAproxPos || !inAntDelta || !inTypesObs || !inFirstObs) {
395 throw new OrekitException(OrekitMessages.INCOMPLETE_HEADER, name);
396 }
397
398
399 observationsList = addHeader(new RinexHeader(formatVersion, satelliteSystem,
400 markerName, markerNumber, observerName,
401 agencyName, receiverNumber, receiverType,
402 receiverVersion, antennaNumber, antennaType,
403 approxPos, antHeight, eccentricities, interval,
404 tFirstObs, tLastObs, clkOffset, leapSeconds));
405 break;
406 default :
407 if (observationsList == null) {
408
409 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
410 lineNumber, name, line);
411 }
412 }
413 } else {
414
415
416 rcvrClkOffset = 0;
417 nbLinesSat = -1;
418 eventFlag = -1;
419 nbSatObs = -1;
420 satsObsList = null;
421 tObs = null;
422 strYear = null;
423
424 eventFlag = parseInt(line, 28, 1);
425
426 if (eventFlag != 0) {
427 if (eventFlag == 6) {
428 nbSatObs = parseInt(line, 29, 3);
429 nbLinesSat = (nbSatObs + 12 - 1) / 12;
430 final int nbLinesObs = (nbTypes + 5 - 1) / 5;
431 final int nbLinesSkip = (nbLinesSat - 1) + nbSatObs * nbLinesObs;
432 for (int i = 0; i < nbLinesSkip; i++) {
433 line = reader.readLine();
434 lineNumber++;
435 }
436 } else {
437 final int nbLinesSkip = parseInt(line, 29, 3);
438 for (int i = 0; i < nbLinesSkip; i++) {
439 line = reader.readLine();
440 lineNumber++;
441 }
442 }
443 } else {
444
445 final int y = Integer.parseInt(parseString(line, 0, 3));
446 if (79 < y && y <= 99) {
447 strYear = "19" + y;
448 } else if (0 <= y && y <= 79) {
449 strYear = "20" + parseString(line, 0, 3);
450 }
451 tObs = new AbsoluteDate(Integer.parseInt(strYear),
452 parseInt(line, 3, 3),
453 parseInt(line, 6, 3),
454 parseInt(line, 9, 3),
455 parseInt(line, 12, 3),
456 parseDouble(line, 15, 11), timeScale);
457
458 nbSatObs = parseInt(line, 29, 3);
459 satsObsList = new String[nbSatObs];
460
461 if (nbSat != -1 && nbSatObs > nbSat) {
462
463 throw new OrekitException(OrekitMessages.INCONSISTENT_NUMBER_OF_SATS,
464 lineNumber, name, nbSatObs, nbSat);
465 }
466
467 nbLinesSat = (nbSatObs + MAX_N_SAT_OBSERVATION - 1) / MAX_N_SAT_OBSERVATION;
468 for (int j = 0; j < nbLinesSat; j++) {
469 if (j > 0) {
470 line = reader.readLine();
471 lineNumber++;
472 }
473 final int iMax = FastMath.min(MAX_N_SAT_OBSERVATION, nbSatObs - j * MAX_N_SAT_OBSERVATION);
474 for (int i = 0; i < iMax; i++) {
475 satsObsList[i + MAX_N_SAT_OBSERVATION * j] = parseString(line, 32 + 3 * i, 3);
476 }
477
478
479 rcvrClkOffset = parseDouble(line, 68, 12);
480 if (Double.isNaN(rcvrClkOffset)) {
481 rcvrClkOffset = 0.0;
482 }
483
484 }
485
486
487 final int nbLinesObs = (nbTypes + MAX_N_TYPES_OBSERVATION - 1) / MAX_N_TYPES_OBSERVATION;
488 for (int k = 0; k < nbSatObs; k++) {
489
490
491
492
493
494 final List<ObservationData> observationData = new ArrayList<>(nbSatObs);
495 for (int j = 0; j < nbLinesObs; j++) {
496 line = reader.readLine();
497 lineNumber++;
498 final int iMax = FastMath.min(MAX_N_TYPES_OBSERVATION, nbTypes - observationData.size());
499 for (int i = 0; i < iMax; i++) {
500 observationData.add(new ObservationData(typesObs.get(observationData.size()),
501 parseDouble(line, 16 * i, 14),
502 parseInt(line, 14 + 16 * i, 1),
503 parseInt(line, 15 + 16 * i, 1)));
504 }
505 }
506
507
508 final SatelliteSystem satelliteSystemSat = SatelliteSystem.parseSatelliteSystem(satsObsList[k]);
509 if (!satelliteSystem.equals(SatelliteSystem.MIXED)) {
510 if (!satelliteSystemSat.equals(satelliteSystem)) {
511 throw new OrekitException(OrekitMessages.INCONSISTENT_SATELLITE_SYSTEM,
512 lineNumber, name, satelliteSystem, satelliteSystemSat);
513 }
514 }
515
516 final int prnNumber;
517 switch (satelliteSystemSat) {
518 case GPS:
519 case GLONASS:
520 case GALILEO:
521 prnNumber = Integer.parseInt(satsObsList[k].substring(1, 3).trim());
522 break;
523 case SBAS:
524 prnNumber = Integer.parseInt(satsObsList[k].substring(1, 3).trim()) + 100;
525 break;
526 default:
527
528 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
529 lineNumber, name, line);
530 }
531
532 observationsList.add(new ObservationDataSet(satelliteSystemSat, prnNumber, tObs, rcvrClkOffset,
533 observationData));
534
535 }
536 }
537 }
538 }
539 break;
540 case 3:
541
542 final int MAX_OBS_TYPES_PER_LINE_RNX3 = 13;
543 final int MAX_OBS_TYPES_SCALE_FACTOR_PER_LINE = 12;
544 final int MAX_N_SAT_PHSHIFT_PER_LINE = 10;
545
546 final Map<SatelliteSystem, List<ObservationType>> listTypeObs = new HashMap<>();
547 final List<ObservationType> typeObs = new ArrayList<>();
548 String sigStrengthUnit = null;
549 int leapSecondsFuture = 0;
550 int leapSecondsWeekNum = 0;
551 int leapSecondsDayNum = 0;
552 final List<AppliedDCBS> listAppliedDCBs = new ArrayList<>();
553 final List<AppliedPCVS> listAppliedPCVS = new ArrayList<>();
554 SatelliteSystem satSystemScaleFactor = null;
555 int scaleFactor = 1;
556 int nbObsScaleFactor = 0;
557 final List<ObservationType> typesObsScaleFactor = new ArrayList<>();
558 final List<ScaleFactorCorrection> scaleFactorCorrections = new ArrayList<>();
559 String[] satsPhaseShift = null;
560 int nbSatPhaseShift = 0;
561 SatelliteSystem satSystemPhaseShift = null;
562 double corrPhaseShift = 0.0;
563 final List<PhaseShiftCorrection> phaseShiftCorrections = new ArrayList<>();
564 ObservationType phaseShiftTypeObs = null;
565
566
567 for (line = reader.readLine(); line != null; line = reader.readLine()) {
568 ++lineNumber;
569 if (observationsList == null) {
570 switch(line.substring(LABEL_START).trim()) {
571 case RINEX_VERSION_TYPE : {
572 formatVersion = parseDouble(line, 0, 9);
573 format100 = (int) FastMath.rint(100 * formatVersion);
574 if ((format100 != 300) && (format100 != 301) && (format100 != 302) && (format100 != 303)) {
575 throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
576 }
577
578 if (!(parseString(line, 20, 1)).equals(FILE_TYPE)) {
579 throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
580 }
581 satelliteSystem = SatelliteSystem.parseSatelliteSystem(parseString(line, 40, 1));
582 inRinexVersion = true;
583 }
584 break;
585 case COMMENT :
586
587 break;
588 case PGM_RUN_BY_DATE :
589 inRunBy = true;
590 break;
591 case MARKER_NAME :
592 markerName = parseString(line, 0, 60);
593 inMarkerName = true;
594 break;
595 case MARKER_NUMBER :
596 markerNumber = parseString(line, 0, 20);
597 break;
598 case MARKER_TYPE :
599 markerType = parseString(line, 0, 20);
600 inMarkerType = true;
601
602 break;
603 case OBSERVER_AGENCY :
604 observerName = parseString(line, 0, 20);
605 agencyName = parseString(line, 20, 40);
606 inObserver = true;
607 break;
608 case REC_NB_TYPE_VERS :
609 receiverNumber = parseString(line, 0, 20);
610 receiverType = parseString(line, 20, 20);
611 receiverVersion = parseString(line, 40, 20);
612 inRecType = true;
613 break;
614 case ANT_NB_TYPE :
615 antennaNumber = parseString(line, 0, 20);
616 antennaType = parseString(line, 20, 20);
617 inAntType = true;
618 break;
619 case APPROX_POSITION_XYZ :
620 approxPos = new Vector3D(parseDouble(line, 0, 14),
621 parseDouble(line, 14, 14),
622 parseDouble(line, 28, 14));
623 inAproxPos = true;
624 break;
625 case ANTENNA_DELTA_H_E_N :
626 antHeight = parseDouble(line, 0, 14);
627 eccentricities = new Vector2D(parseDouble(line, 14, 14),
628 parseDouble(line, 28, 14));
629 inAntDelta = true;
630 break;
631 case ANTENNA_DELTA_X_Y_Z :
632 antRefPoint = new Vector3D(parseDouble(line, 0, 14),
633 parseDouble(line, 14, 14),
634 parseDouble(line, 28, 14));
635 break;
636 case ANTENNA_PHASECENTER :
637 obsCode = parseString(line, 2, 3);
638 antPhaseCenter = new Vector3D(parseDouble(line, 5, 9),
639 parseDouble(line, 14, 14),
640 parseDouble(line, 28, 14));
641 break;
642 case ANTENNA_B_SIGHT_XYZ :
643 antBSight = new Vector3D(parseDouble(line, 0, 14),
644 parseDouble(line, 14, 14),
645 parseDouble(line, 28, 14));
646 break;
647 case ANTENNA_ZERODIR_AZI :
648 antAzi = parseDouble(line, 0, 14);
649 break;
650 case ANTENNA_ZERODIR_XYZ :
651 antZeroDir = new Vector3D(parseDouble(line, 0, 14),
652 parseDouble(line, 14, 14),
653 parseDouble(line, 28, 14));
654 break;
655 case CENTER_OF_MASS_XYZ :
656 centerMass = new Vector3D(parseDouble(line, 0, 14),
657 parseDouble(line, 14, 14),
658 parseDouble(line, 28, 14));
659 break;
660 case NB_OF_SATELLITES :
661 nbSat = parseInt(line, 0, 6);
662 break;
663 case RCV_CLOCK_OFFS_APPL :
664 clkOffset = parseInt(line, 0, 6);
665 break;
666 case INTERVAL :
667 interval = parseDouble(line, 0, 10);
668 break;
669 case TIME_OF_FIRST_OBS :
670 switch(satelliteSystem) {
671 case GPS:
672 timeScale = TimeScalesFactory.getGPS();
673 break;
674 case GALILEO:
675 timeScale = TimeScalesFactory.getGST();
676 break;
677 case GLONASS:
678 timeScale = TimeScalesFactory.getGLONASS();
679 break;
680 case QZSS:
681 timeScale = TimeScalesFactory.getQZSS();
682 break;
683 case BEIDOU:
684 timeScale = TimeScalesFactory.getBDT();
685 break;
686 case IRNSS:
687 timeScale = TimeScalesFactory.getIRNSS();
688 break;
689 case MIXED:
690
691 timeScaleStr = parseString(line, 48, 3);
692
693 if (timeScaleStr.equals(GPS)) {
694 timeScale = TimeScalesFactory.getGPS();
695 } else if (timeScaleStr.equals(GAL)) {
696 timeScale = TimeScalesFactory.getGST();
697 } else if (timeScaleStr.equals(GLO)) {
698 timeScale = TimeScalesFactory.getGLONASS();
699 } else if (timeScaleStr.equals(QZS)) {
700 timeScale = TimeScalesFactory.getQZSS();
701 } else if (timeScaleStr.equals(BDT)) {
702 timeScale = TimeScalesFactory.getBDT();
703 } else if (timeScaleStr.equals(IRN)) {
704 timeScale = TimeScalesFactory.getIRNSS();
705 } else {
706 throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
707 }
708 break;
709 default :
710 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
711 lineNumber, name, line);
712 }
713
714 tFirstObs = new AbsoluteDate(parseInt(line, 0, 6),
715 parseInt(line, 6, 6),
716 parseInt(line, 12, 6),
717 parseInt(line, 18, 6),
718 parseInt(line, 24, 6),
719 parseDouble(line, 30, 13), timeScale);
720 inFirstObs = true;
721 break;
722 case TIME_OF_LAST_OBS :
723 tLastObs = new AbsoluteDate(parseInt(line, 0, 6),
724 parseInt(line, 6, 6),
725 parseInt(line, 12, 6),
726 parseInt(line, 18, 6),
727 parseInt(line, 24, 6),
728 parseDouble(line, 30, 13), timeScale);
729 break;
730 case LEAP_SECONDS :
731 leapSeconds = parseInt(line, 0, 6);
732 leapSecondsFuture = parseInt(line, 6, 6);
733 leapSecondsWeekNum = parseInt(line, 12, 6);
734 leapSecondsDayNum = parseInt(line, 18, 6);
735
736 break;
737 case PRN_NB_OF_OBS :
738
739
740 break;
741 case SYS_NB_OBS_TYPES :
742 obsTypesSystem = null;
743 typeObs.clear();
744
745 obsTypesSystem = SatelliteSystem.parseSatelliteSystem(parseString(line, 0, 1));
746 nbTypes = parseInt(line, 3, 3);
747
748 final int nbLinesTypesObs = (nbTypes + MAX_OBS_TYPES_PER_LINE_RNX3 - 1) / MAX_OBS_TYPES_PER_LINE_RNX3;
749 for (int j = 0; j < nbLinesTypesObs; j++) {
750 if (j > 0) {
751 line = reader.readLine();
752 lineNumber++;
753 }
754 final int iMax = FastMath.min(MAX_OBS_TYPES_PER_LINE_RNX3, nbTypes - typeObs.size());
755 for (int i = 0; i < iMax; i++) {
756 try {
757 typeObs.add(ObservationType.valueOf(parseString(line, 7 + (4 * i), 3)));
758 } catch (IllegalArgumentException iae) {
759 throw new OrekitException(OrekitMessages.UNKNOWN_RINEX_FREQUENCY,
760 parseString(line, 7 + (4 * i), 3), name, lineNumber);
761 }
762 }
763 }
764 listTypeObs.put(obsTypesSystem, new ArrayList<>(typeObs));
765 inTypesObs = true;
766 break;
767 case SIGNAL_STRENGTH_UNIT :
768 sigStrengthUnit = parseString(line, 0, 20);
769 break;
770 case SYS_DCBS_APPLIED :
771
772 listAppliedDCBs.add(new AppliedDCBS(SatelliteSystem.parseSatelliteSystem(parseString(line, 0, 1)),
773 parseString(line, 2, 17), parseString(line, 20, 40)));
774 break;
775 case SYS_PCVS_APPLIED :
776
777 listAppliedPCVS.add(new AppliedPCVS(SatelliteSystem.parseSatelliteSystem(parseString(line, 0, 1)),
778 parseString(line, 2, 17), parseString(line, 20, 40)));
779 break;
780 case SYS_SCALE_FACTOR :
781 satSystemScaleFactor = null;
782 scaleFactor = 1;
783 nbObsScaleFactor = 0;
784
785 satSystemScaleFactor = SatelliteSystem.parseSatelliteSystem(parseString(line, 0, 1));
786 scaleFactor = parseInt(line, 2, 4);
787 nbObsScaleFactor = parseInt(line, 8, 2);
788
789 if (nbObsScaleFactor == 0) {
790 typesObsScaleFactor.addAll(listTypeObs.get(satSystemScaleFactor));
791 } else {
792 final int nbLinesTypesObsScaleFactor = (nbObsScaleFactor + MAX_OBS_TYPES_SCALE_FACTOR_PER_LINE - 1) /
793 MAX_OBS_TYPES_SCALE_FACTOR_PER_LINE;
794 for (int j = 0; j < nbLinesTypesObsScaleFactor; j++) {
795 if ( j > 0) {
796 line = reader.readLine();
797 lineNumber++;
798 }
799 final int iMax = FastMath.min(MAX_OBS_TYPES_SCALE_FACTOR_PER_LINE, nbObsScaleFactor - typesObsScaleFactor.size());
800 for (int i = 0; i < iMax; i++) {
801 typesObsScaleFactor.add(ObservationType.valueOf(parseString(line, 11 + (4 * i), 3)));
802 }
803 }
804 }
805
806 scaleFactorCorrections.add(new ScaleFactorCorrection(satSystemScaleFactor,
807 scaleFactor, typesObsScaleFactor));
808 break;
809 case SYS_PHASE_SHIFT :
810
811 nbSatPhaseShift = 0;
812 satsPhaseShift = null;
813 corrPhaseShift = 0.0;
814 phaseShiftTypeObs = null;
815 satSystemPhaseShift = null;
816
817 satSystemPhaseShift = SatelliteSystem.parseSatelliteSystem(parseString(line, 0, 1));
818 phaseShiftTypeObs = ObservationType.valueOf(parseString(line, 2, 3));
819 nbSatPhaseShift = parseInt(line, 16, 2);
820 corrPhaseShift = parseDouble(line, 6, 8);
821
822 if (nbSatPhaseShift == 0) {
823
824 } else {
825 satsPhaseShift = new String[nbSatPhaseShift];
826 final int nbLinesSatPhaseShift = (nbSatPhaseShift + MAX_N_SAT_PHSHIFT_PER_LINE - 1) / MAX_N_SAT_PHSHIFT_PER_LINE;
827 for (int j = 0; j < nbLinesSatPhaseShift; j++) {
828 if (j > 0) {
829 line = reader.readLine();
830 lineNumber++;
831 }
832 final int iMax = FastMath.min(MAX_N_SAT_PHSHIFT_PER_LINE, nbSatPhaseShift - j * MAX_N_SAT_PHSHIFT_PER_LINE);
833 for (int i = 0; i < iMax; i++) {
834 satsPhaseShift[i + 10 * j] = parseString(line, 19 + 4 * i, 3);
835 }
836 }
837 }
838 phaseShiftCorrections.add(new PhaseShiftCorrection(satSystemPhaseShift,
839 phaseShiftTypeObs,
840 corrPhaseShift,
841 satsPhaseShift));
842 inPhaseShift = true;
843 break;
844 case GLONASS_SLOT_FRQ_NB :
845
846 inGlonassSlot = true;
847 break;
848 case GLONASS_COD_PHS_BIS :
849
850 inGlonassCOD = true;
851 break;
852 case END_OF_HEADER :
853
854 if (!inRinexVersion || !inRunBy || !inMarkerName ||
855 !inMarkerType || !inObserver || !inRecType || !inAntType ||
856 !inAproxPos || !inAntDelta || !inTypesObs || !inFirstObs ||
857 (formatVersion >= 3.01 && !inPhaseShift) ||
858 (formatVersion >= 3.03 && (!inGlonassSlot || !inGlonassCOD))) {
859 throw new OrekitException(OrekitMessages.INCOMPLETE_HEADER, name);
860 }
861
862
863 observationsList = addHeader(new RinexHeader(formatVersion, satelliteSystem,
864 markerName, markerNumber, markerType,
865 observerName, agencyName, receiverNumber,
866 receiverType, receiverVersion, antennaNumber,
867 antennaType, approxPos, antHeight, eccentricities,
868 antRefPoint, obsCode, antPhaseCenter, antBSight,
869 antAzi, antZeroDir, centerMass, sigStrengthUnit,
870 interval, tFirstObs, tLastObs, clkOffset, listAppliedDCBs,
871 listAppliedPCVS, phaseShiftCorrections, leapSeconds,
872 leapSecondsFuture, leapSecondsWeekNum, leapSecondsDayNum));
873 break;
874 default :
875 if (observationsList == null) {
876
877 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
878 lineNumber, name, line);
879 }
880 }
881 } else {
882
883
884
885 rcvrClkOffset = 0;
886 eventFlag = -1;
887 nbSatObs = -1;
888 tObs = null;
889
890
891 if (parseString(line, 0, 1).equals(">")) {
892
893 eventFlag = parseInt(line, 31, 1);
894
895 if (eventFlag != 0) {
896 final int nbLinesSkip = parseInt(line, 32, 3);
897 for (int i = 0; i < nbLinesSkip; i++) {
898 line = reader.readLine();
899 lineNumber++;
900 }
901 } else {
902
903 tObs = new AbsoluteDate(parseInt(line, 2, 4),
904 parseInt(line, 6, 3),
905 parseInt(line, 9, 3),
906 parseInt(line, 12, 3),
907 parseInt(line, 15, 3),
908 parseDouble(line, 18, 11), timeScale);
909
910 nbSatObs = parseInt(line, 32, 3);
911
912 if (nbSat != -1 && nbSatObs > nbSat) {
913
914 throw new OrekitException(OrekitMessages.INCONSISTENT_NUMBER_OF_SATS,
915 lineNumber, name, nbSatObs, nbSat);
916 }
917
918 rcvrClkOffset = parseDouble(line, 41, 15);
919 if (Double.isNaN(rcvrClkOffset)) {
920 rcvrClkOffset = 0.0;
921 }
922
923
924 for (int i = 0; i < nbSatObs; i++) {
925
926 line = reader.readLine();
927 lineNumber++;
928
929
930 final SatelliteSystem satelliteSystemSat = SatelliteSystem.parseSatelliteSystem(parseString(line, 0, 1));
931 if (!satelliteSystem.equals(SatelliteSystem.MIXED)) {
932 if (!satelliteSystemSat.equals(satelliteSystem)) {
933 throw new OrekitException(OrekitMessages.INCONSISTENT_SATELLITE_SYSTEM,
934 lineNumber, name, satelliteSystem, satelliteSystemSat);
935 }
936 }
937
938 final int prn = parseInt(line, 1, 2);
939 final int prnNumber;
940 switch (satelliteSystemSat) {
941 case GPS:
942 case GLONASS:
943 case GALILEO:
944 case BEIDOU:
945 case IRNSS:
946 prnNumber = prn;
947 break;
948 case QZSS:
949 prnNumber = prn + 192;
950 break;
951 case SBAS:
952 prnNumber = prn + 100;
953 break;
954 default:
955
956 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
957 lineNumber, name, line);
958 }
959 final List<ObservationData> observationData = new ArrayList<>(nbSatObs);
960 for (int j = 0; j < listTypeObs.get(satelliteSystemSat).size(); j++) {
961 final ObservationType rf = listTypeObs.get(satelliteSystemSat).get(j);
962 boolean scaleFactorFound = false;
963
964 int k = 0;
965 double value = parseDouble(line, 3 + j * 16, 14);
966 while (k < scaleFactorCorrections.size() && !scaleFactorFound) {
967 if (scaleFactorCorrections.get(k).getSatelliteSystem().equals(satelliteSystemSat)) {
968
969 if (scaleFactorCorrections.get(k).getTypesObsScaled().contains(rf)) {
970 value /= scaleFactorCorrections.get(k).getCorrection();
971 scaleFactorFound = true;
972 }
973 }
974 k++;
975 }
976 observationData.add(new ObservationData(rf,
977 value,
978 parseInt(line, 17 + j * 16, 1),
979 parseInt(line, 18 + j * 16, 1)));
980 }
981 observationsList.add(new ObservationDataSet(satelliteSystemSat, prnNumber, tObs, rcvrClkOffset,
982 observationData));
983
984 }
985 }
986 }
987 }
988 }
989 break;
990 default:
991
992 throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
993 }
994 }
995 }
996
997
998
999
1000
1001
1002
1003
1004 private String parseString(final String line, final int start, final int length) {
1005 if (line.length() > start) {
1006 return line.substring(start, FastMath.min(line.length(), start + length)).trim();
1007 } else {
1008 return null;
1009 }
1010 }
1011
1012
1013
1014
1015
1016
1017
1018 private int parseInt(final String line, final int start, final int length) {
1019 if (line.length() > start && !parseString(line, start, length).isEmpty()) {
1020 return Integer.parseInt(parseString(line, start, length));
1021 } else {
1022 return 0;
1023 }
1024 }
1025
1026
1027
1028
1029
1030
1031
1032 private double parseDouble(final String line, final int start, final int length) {
1033 if (line.length() > start && !parseString(line, start, length).isEmpty()) {
1034 return Double.parseDouble(parseString(line, start, length));
1035 } else {
1036 return Double.NaN;
1037 }
1038 }
1039
1040
1041
1042
1043
1044 public class PhaseShiftCorrection {
1045
1046
1047 private final SatelliteSystem satSystemPhaseShift;
1048
1049 private final ObservationType typeObsPhaseShift;
1050
1051 private final double phaseShiftCorrection;
1052
1053 private final String[] satsPhaseShift;
1054
1055
1056
1057
1058
1059
1060
1061 private PhaseShiftCorrection(final SatelliteSystem satSystemPhaseShift,
1062 final ObservationType typeObsPhaseShift,
1063 final double phaseShiftCorrection, final String[] satsPhaseShift) {
1064 this.satSystemPhaseShift = satSystemPhaseShift;
1065 this.typeObsPhaseShift = typeObsPhaseShift;
1066 this.phaseShiftCorrection = phaseShiftCorrection;
1067 this.satsPhaseShift = satsPhaseShift;
1068 }
1069
1070
1071
1072
1073 public SatelliteSystem getSatelliteSystem() {
1074 return satSystemPhaseShift;
1075 }
1076
1077
1078
1079 public ObservationType getTypeObs() {
1080 return typeObsPhaseShift;
1081 }
1082
1083
1084
1085 public double getCorrection() {
1086 return phaseShiftCorrection;
1087 }
1088
1089
1090
1091 public String[] getSatsCorrected() {
1092
1093 return satsPhaseShift;
1094 }
1095 }
1096
1097
1098
1099
1100
1101 public class ScaleFactorCorrection {
1102
1103
1104 private final SatelliteSystem satSystemScaleFactor;
1105
1106 private final List<ObservationType> typesObsScaleFactor;
1107
1108 private final double scaleFactor;
1109
1110
1111
1112
1113
1114
1115 private ScaleFactorCorrection(final SatelliteSystem satSystemScaleFactor,
1116 final double scaleFactor,
1117 final List<ObservationType> typesObsScaleFactor) {
1118 this.satSystemScaleFactor = satSystemScaleFactor;
1119 this.scaleFactor = scaleFactor;
1120 this.typesObsScaleFactor = typesObsScaleFactor;
1121 }
1122
1123
1124
1125 public SatelliteSystem getSatelliteSystem() {
1126 return satSystemScaleFactor;
1127 }
1128
1129
1130
1131 public double getCorrection() {
1132 return scaleFactor;
1133 }
1134
1135
1136
1137 public List<ObservationType> getTypesObsScaled() {
1138 return typesObsScaleFactor;
1139 }
1140 }
1141
1142
1143
1144
1145
1146 public class AppliedDCBS {
1147
1148
1149 private final SatelliteSystem satelliteSystem;
1150
1151
1152 private final String progDCBS;
1153
1154
1155 private final String sourceDCBS;
1156
1157
1158
1159
1160
1161
1162 private AppliedDCBS(final SatelliteSystem satelliteSystem,
1163 final String progDCBS, final String sourceDCBS) {
1164 this.satelliteSystem = satelliteSystem;
1165 this.progDCBS = progDCBS;
1166 this.sourceDCBS = sourceDCBS;
1167 }
1168
1169
1170
1171
1172 public SatelliteSystem getSatelliteSystem() {
1173 return satelliteSystem;
1174 }
1175
1176
1177
1178
1179 public String getProgDCBS() {
1180 return progDCBS;
1181 }
1182
1183
1184
1185
1186 public String getSourceDCBS() {
1187 return sourceDCBS;
1188 }
1189
1190 }
1191
1192
1193
1194
1195
1196 public class AppliedPCVS {
1197
1198
1199 private final SatelliteSystem satelliteSystem;
1200
1201
1202 private final String progPCVS;
1203
1204
1205 private final String sourcePCVS;
1206
1207
1208
1209
1210
1211
1212 private AppliedPCVS(final SatelliteSystem satelliteSystem,
1213 final String progPCVS, final String sourcePCVS) {
1214 this.satelliteSystem = satelliteSystem;
1215 this.progPCVS = progPCVS;
1216 this.sourcePCVS = sourcePCVS;
1217 }
1218
1219
1220
1221
1222 public SatelliteSystem getSatelliteSystem() {
1223 return satelliteSystem;
1224 }
1225
1226
1227
1228
1229 public String getProgPCVS() {
1230 return progPCVS;
1231 }
1232
1233
1234
1235
1236 public String getSourcePCVS() {
1237 return sourcePCVS;
1238 }
1239
1240 }
1241 }
1242
1243 }