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