RinexLoader.java
- /* Copyright 2002-2018 CS Systèmes d'Information
- * Licensed to CS Systèmes d'Information (CS) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.orekit.gnss;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import org.hipparchus.exception.DummyLocalizable;
- import org.hipparchus.geometry.euclidean.threed.Vector3D;
- import org.hipparchus.geometry.euclidean.twod.Vector2D;
- import org.hipparchus.util.FastMath;
- import org.orekit.data.DataLoader;
- import org.orekit.data.DataProvidersManager;
- import org.orekit.errors.OrekitException;
- import org.orekit.errors.OrekitMessages;
- import org.orekit.time.AbsoluteDate;
- import org.orekit.time.TimeScale;
- import org.orekit.time.TimeScalesFactory;
- public class RinexLoader {
- /** Default supported files name pattern for rinex 2 observation files. */
- public static final String DEFAULT_RINEX_2_SUPPORTED_NAMES = "^\\w{4}\\d{3}[0a-x](?:\\d{2})?\\.\\d{2}[oO]$";
- /** Default supported files name pattern for rinex 3 observation files. */
- 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$";
- // CHECKSTYLE: stop JavadocVariable check
- private static final String RINEX_VERSION_TYPE = "RINEX VERSION / TYPE";
- private static final String COMMENT = "COMMENT";
- private static final String PGM_RUN_BY_DATE = "PGM / RUN BY / DATE";
- private static final String MARKER_NAME = "MARKER NAME";
- private static final String MARKER_NUMBER = "MARKER NUMBER";
- private static final String MARKER_TYPE = "MARKER TYPE";
- private static final String OBSERVER_AGENCY = "OBSERVER / AGENCY";
- private static final String REC_NB_TYPE_VERS = "REC # / TYPE / VERS";
- private static final String ANT_NB_TYPE = "ANT # / TYPE";
- private static final String APPROX_POSITION_XYZ = "APPROX POSITION XYZ";
- private static final String ANTENNA_DELTA_H_E_N = "ANTENNA: DELTA H/E/N";
- private static final String ANTENNA_DELTA_X_Y_Z = "ANTENNA: DELTA X/Y/Z";
- private static final String ANTENNA_PHASECENTER = "ANTENNA: PHASECENTER";
- private static final String ANTENNA_B_SIGHT_XYZ = "ANTENNA: B.SIGHT XYZ";
- private static final String ANTENNA_ZERODIR_AZI = "ANTENNA: ZERODIR AZI";
- private static final String ANTENNA_ZERODIR_XYZ = "ANTENNA: ZERODIR XYZ";
- private static final String NB_OF_SATELLITES = "# OF SATELLITES";
- private static final String WAVELENGTH_FACT_L1_2 = "WAVELENGTH FACT L1/2";
- private static final String RCV_CLOCK_OFFS_APPL = "RCV CLOCK OFFS APPL";
- private static final String INTERVAL = "INTERVAL";
- private static final String TIME_OF_FIRST_OBS = "TIME OF FIRST OBS";
- private static final String TIME_OF_LAST_OBS = "TIME OF LAST OBS";
- private static final String LEAP_SECONDS = "LEAP SECONDS";
- private static final String PRN_NB_OF_OBS = "PRN / # OF OBS";
- private static final String NB_TYPES_OF_OBSERV = "# / TYPES OF OBSERV";
- private static final String END_OF_HEADER = "END OF HEADER";
- private static final String CENTER_OF_MASS_XYZ = "CENTER OF MASS: XYZ";
- private static final String SIGNAL_STRENGTH_UNIT = "SIGNAL STRENGTH UNIT";
- private static final String SYS_NB_OBS_TYPES = "SYS / # / OBS TYPES";
- private static final String SYS_DCBS_APPLIED = "SYS / DCBS APPLIED";
- private static final String SYS_PCVS_APPLIED = "SYS / PCVS APPLIED";
- private static final String SYS_SCALE_FACTOR = "SYS / SCALE FACTOR";
- private static final String SYS_PHASE_SHIFT = "SYS / PHASE SHIFT";
- private static final String GLONASS_SLOT_FRQ_NB = "GLONASS SLOT / FRQ #";
- private static final String GLONASS_COD_PHS_BIS = "GLONASS COD/PHS/BIS";
- private static final String GPS = "GPS";
- private static final String GAL = "GAL";
- private static final String GLO = "GLO";
- private static final String QZS = "QZS";
- private static final String BDT = "BDT";
- private static final String IRN = "IRN";
- // CHECKSTYLE: resume JavadocVariable check
- /** Rinex Observations, grouped by file. */
- private final Map<RinexHeader, List<ObservationDataSet>> observations;
- /** Simple constructor.
- * <p>
- * This constructor is used when the rinex files are managed by the
- * global {@link DataProvidersManager DataProvidersManager}.
- * </p>
- * @param supportedNames regular expression for supported files names
- * @exception OrekitException if no rinex file can be read
- */
- public RinexLoader(final String supportedNames)
- throws OrekitException {
- observations = new HashMap<>();
- DataProvidersManager.getInstance().feed(supportedNames, new Parser());
- }
- /** Simple constructor.
- * @param input data input stream
- * @param name name of the file (or zip entry)
- * @exception OrekitException if no rinex file can be read
- */
- public RinexLoader(final InputStream input, final String name)
- throws OrekitException {
- try {
- observations = new HashMap<>();
- new Parser().loadData(input, name);
- } catch (IOException ioe) {
- throw new OrekitException(ioe, new DummyLocalizable(ioe.getMessage()));
- }
- }
- /** Add a Rinex header.
- * @param header rinex header to add
- * @return the list into which observations should be added
- */
- private List<ObservationDataSet> addHeader(final RinexHeader header) {
- final List<ObservationDataSet> list = new ArrayList<>();
- observations.put(header, list);
- return list;
- }
- /** Get parsed rinex observations.
- * @return unmodifiable view of parsed rinex observations
- */
- public Map<RinexHeader, List<ObservationDataSet>> getObservations() {
- return Collections.unmodifiableMap(observations);
- }
- /** Parser for rinex files.
- */
- public class Parser implements DataLoader {
- /** Index of label in data lines. */
- private static final int LABEL_START = 60;
- /** File type Accepted (only Observation Data). */
- private static final String FILE_TYPE = "O"; //Only Observation Data files
- /** {@inheritDoc} */
- @Override
- public boolean stillAcceptsData() {
- // we load all rinex files we can find
- return true;
- }
- /** {@inheritDoc} */
- @Override
- public void loadData(final InputStream input, final String name)
- throws IOException, OrekitException {
- try (BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"))) {
- // placeholders for parsed data
- SatelliteSystem satelliteSystem = null;
- double formatVersion = Double.NaN;
- boolean inRinexVersion = false;
- int lineNumber = 0;
- SatelliteSystem obsTypesSystem = null;
- String markerName = null;
- String markerNumber = null;
- String markerType = null;
- String observerName = null;
- String agencyName = null;
- String receiverNumber = null;
- String receiverType = null;
- String receiverVersion = null;
- String antennaNumber = null;
- String antennaType = null;
- Vector3D approxPos = null;
- Vector3D antRefPoint = null;
- String obsCode = null;
- Vector3D antPhaseCenter = null;
- Vector3D antBSight = null;
- double antAzi = Double.NaN;
- Vector3D antZeroDir = null;
- Vector3D centerMass = null;
- double antHeight = Double.NaN;
- Vector2D eccentricities = Vector2D.ZERO;
- int clkOffset = -1;
- int nbTypes = -1;
- int nbSat = -1;
- double interval = Double.NaN;
- AbsoluteDate tFirstObs = AbsoluteDate.PAST_INFINITY;
- AbsoluteDate tLastObs = AbsoluteDate.FUTURE_INFINITY;
- TimeScale timeScale = null;
- String timeScaleStr = null;
- int leapSeconds = 0;
- AbsoluteDate tObs = AbsoluteDate.PAST_INFINITY;
- String[] satsObsList = null;
- String strYear = null;
- int eventFlag = -1;
- int nbSatObs = -1;
- int nbLinesSat = -1;
- double rcvrClkOffset = 0;
- boolean inRunBy = false;
- boolean inMarkerName = false;
- boolean inMarkerType = false;
- boolean inObserver = false;
- boolean inRecType = false;
- boolean inAntType = false;
- boolean inAproxPos = false;
- boolean inAntDelta = false;
- boolean inTypesObs = false;
- boolean inFirstObs = false;
- boolean inPhaseShift = false;
- boolean inGlonassSlot = false;
- boolean inGlonassCOD = false;
- List<ObservationDataSet> observationsList = null;
- //First line must always contain Rinex Version, File Type and Satellite Systems Observed
- String line = reader.readLine();
- lineNumber++;
- formatVersion = parseDouble(line, 0, 9);
- int format100 = (int) FastMath.rint(100 * formatVersion);
- if ((format100 != 200) && (format100 != 210) && (format100 != 211) &&
- (format100 != 300) && (format100 != 301) && (format100 != 302) && (format100 != 303)) {
- throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
- }
- //File Type must be Observation_Data
- if (!(parseString(line, 20, 1)).equals(FILE_TYPE)) {
- throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
- }
- satelliteSystem = SatelliteSystem.parseSatelliteSystem(parseString(line, 40, 1));
- inRinexVersion = true;
- switch (format100 / 100) {
- case 2:
- final int MAX_OBS_TYPES_PER_LINE_RNX2 = 9;
- final int MAX_N_SAT_OBSERVATION = 12;
- final int MAX_N_TYPES_OBSERVATION = 5;
- final List<ObservationType> typesObs = new ArrayList<>();
- for (line = reader.readLine(); line != null; line = reader.readLine()) {
- ++lineNumber;
- if (observationsList == null) {
- switch(line.substring(LABEL_START).trim()) {
- case RINEX_VERSION_TYPE :
- formatVersion = parseDouble(line, 0, 9);
- //File Type must be Observation_Data
- if (!(parseString(line, 20, 1)).equals(FILE_TYPE)) {
- throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
- }
- satelliteSystem = SatelliteSystem.parseSatelliteSystem(parseString(line, 40, 1));
- inRinexVersion = true;
- break;
- case COMMENT :
- // nothing to do
- break;
- case PGM_RUN_BY_DATE :
- inRunBy = true;
- break;
- case MARKER_NAME :
- markerName = parseString(line, 0, 60);
- inMarkerName = true;
- break;
- case MARKER_NUMBER :
- markerNumber = parseString(line, 0, 20);
- break;
- case OBSERVER_AGENCY :
- observerName = parseString(line, 0, 20);
- agencyName = parseString(line, 20, 40);
- inObserver = true;
- break;
- case REC_NB_TYPE_VERS :
- receiverNumber = parseString(line, 0, 20);
- receiverType = parseString(line, 20, 20);
- receiverVersion = parseString(line, 40, 20);
- inRecType = true;
- break;
- case ANT_NB_TYPE :
- antennaNumber = parseString(line, 0, 20);
- antennaType = parseString(line, 20, 20);
- inAntType = true;
- break;
- case APPROX_POSITION_XYZ :
- approxPos = new Vector3D(parseDouble(line, 0, 14), parseDouble(line, 14, 14),
- parseDouble(line, 28, 14));
- inAproxPos = true;
- break;
- case ANTENNA_DELTA_H_E_N :
- antHeight = parseDouble(line, 0, 14);
- eccentricities = new Vector2D(parseDouble(line, 14, 14), parseDouble(line, 28, 14));
- inAntDelta = true;
- break;
- case NB_OF_SATELLITES :
- nbSat = parseInt(line, 0, 6);
- break;
- case WAVELENGTH_FACT_L1_2 :
- //Optional line in header
- //Not stored for now
- break;
- case RCV_CLOCK_OFFS_APPL :
- clkOffset = parseInt(line, 0, 6);
- break;
- case INTERVAL :
- interval = parseDouble(line, 0, 10);
- break;
- case TIME_OF_FIRST_OBS :
- switch (satelliteSystem) {
- case GPS:
- timeScale = TimeScalesFactory.getGPS();
- break;
- case GALILEO:
- timeScale = TimeScalesFactory.getGST();
- break;
- case GLONASS:
- timeScale = TimeScalesFactory.getGLONASS();
- break;
- case MIXED:
- //in Case of Mixed data, Timescale must be specified in the Time of First line
- timeScaleStr = parseString(line, 48, 3);
- if (timeScaleStr.equals(GPS)) {
- timeScale = TimeScalesFactory.getGPS();
- } else if (timeScaleStr.equals(GAL)) {
- timeScale = TimeScalesFactory.getGST();
- } else if (timeScaleStr.equals(GLO)) {
- timeScale = TimeScalesFactory.getGLONASS();
- } else {
- throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
- }
- break;
- default :
- throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
- lineNumber, name, line);
- }
- tFirstObs = new AbsoluteDate(parseInt(line, 0, 6),
- parseInt(line, 6, 6),
- parseInt(line, 12, 6),
- parseInt(line, 18, 6),
- parseInt(line, 24, 6),
- parseDouble(line, 30, 13), timeScale);
- inFirstObs = true;
- break;
- case TIME_OF_LAST_OBS :
- tLastObs = new AbsoluteDate(parseInt(line, 0, 6),
- parseInt(line, 6, 6),
- parseInt(line, 12, 6),
- parseInt(line, 18, 6),
- parseInt(line, 24, 6),
- parseDouble(line, 30, 13), timeScale);
- break;
- case LEAP_SECONDS :
- leapSeconds = parseInt(line, 0, 6);
- break;
- case PRN_NB_OF_OBS :
- //Optional line in header, indicates number of Observations par Satellite
- //Not stored for now
- break;
- case NB_TYPES_OF_OBSERV :
- nbTypes = parseInt(line, 0, 6);
- final int nbLinesTypesObs = (nbTypes + MAX_OBS_TYPES_PER_LINE_RNX2 - 1 ) / MAX_OBS_TYPES_PER_LINE_RNX2;
- for (int j = 0; j < nbLinesTypesObs; j++) {
- if (j > 0) {
- line = reader.readLine(); //Next line
- lineNumber++;
- }
- final int iMax = FastMath.min(MAX_OBS_TYPES_PER_LINE_RNX2, nbTypes - typesObs.size());
- for (int i = 0; i < iMax; i++) {
- try {
- typesObs.add(ObservationType.valueOf(parseString(line, 10 + (6 * i), 2)));
- } catch (IllegalArgumentException iae) {
- throw new OrekitException(OrekitMessages.UNKNOWN_RINEX_FREQUENCY,
- parseString(line, 10 + (6 * i), 2), name, lineNumber);
- }
- }
- }
- inTypesObs = true;
- break;
- case END_OF_HEADER :
- //We make sure that we have read all the mandatory fields inside the header of the Rinex
- if (!inRinexVersion || !inRunBy || !inMarkerName ||
- !inObserver || !inRecType || !inAntType ||
- !inAproxPos || !inAntDelta || !inTypesObs || !inFirstObs) {
- throw new OrekitException(OrekitMessages.INCOMPLETE_HEADER, name);
- }
- //Header information gathered
- observationsList = addHeader(new RinexHeader(formatVersion, satelliteSystem,
- markerName, markerNumber, observerName,
- agencyName, receiverNumber, receiverType,
- receiverVersion, antennaNumber, antennaType,
- approxPos, antHeight, eccentricities, interval,
- tFirstObs, tLastObs, clkOffset, leapSeconds));
- break;
- default :
- if (observationsList == null) {
- //There must be an error due to an unknown Label inside the Header
- throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
- lineNumber, name, line);
- }
- }
- } else {
- //Start of a new Observation
- rcvrClkOffset = 0;
- nbLinesSat = -1;
- eventFlag = -1;
- nbSatObs = -1;
- satsObsList = null;
- tObs = null;
- strYear = null;
- eventFlag = parseInt(line, 28, 1);
- //If eventFlag>1, we skip the corresponding lines to the next observation
- if (eventFlag != 0) {
- if (eventFlag == 6) {
- nbSatObs = parseInt(line, 29, 3);
- nbLinesSat = (nbSatObs + 12 - 1) / 12;
- final int nbLinesObs = (nbTypes + 5 - 1) / 5;
- final int nbLinesSkip = (nbLinesSat - 1) + nbSatObs * nbLinesObs;
- for (int i = 0; i < nbLinesSkip; i++) {
- line = reader.readLine(); //Next line
- lineNumber++;
- }
- } else {
- final int nbLinesSkip = parseInt(line, 29, 3);
- for (int i = 0; i < nbLinesSkip; i++) {
- line = reader.readLine(); //Next line
- lineNumber++;
- }
- }
- } else {
- final int y = Integer.parseInt(parseString(line, 0, 3));
- if (79 < y && y <= 99) {
- strYear = "19" + y;
- } else if (0 <= y && y <= 79) {
- strYear = "20" + parseString(line, 0, 3);
- }
- tObs = new AbsoluteDate(Integer.parseInt(strYear),
- parseInt(line, 3, 3),
- parseInt(line, 6, 3),
- parseInt(line, 9, 3),
- parseInt(line, 12, 3),
- parseDouble(line, 15, 11), timeScale);
- nbSatObs = parseInt(line, 29, 3);
- satsObsList = new String[nbSatObs];
- //If the total number of satellites was indicated in the Header
- if (nbSat != -1 && nbSatObs > nbSat) {
- //we check that the number of Sat in the observation is consistent
- throw new OrekitException(OrekitMessages.INCONSISTENT_NUMBER_OF_SATS,
- lineNumber, name, nbSatObs, nbSat);
- }
- nbLinesSat = (nbSatObs + MAX_N_SAT_OBSERVATION - 1) / MAX_N_SAT_OBSERVATION;
- for (int j = 0; j < nbLinesSat; j++) {
- if (j > 0) {
- line = reader.readLine(); //Next line
- lineNumber++;
- }
- final int iMax = FastMath.min(MAX_N_SAT_OBSERVATION, nbSatObs - j * MAX_N_SAT_OBSERVATION);
- for (int i = 0; i < iMax; i++) {
- satsObsList[i + MAX_N_SAT_OBSERVATION * j] = parseString(line, 32 + 3 * i, 3);
- }
- //Read the Receiver Clock offset, if present
- rcvrClkOffset = parseDouble(line, 68, 12);
- if (Double.isNaN(rcvrClkOffset)) {
- rcvrClkOffset = 0.0;
- }
- }
- //For each one of the Satellites in this observation
- final int nbLinesObs = (nbTypes + MAX_N_TYPES_OBSERVATION - 1) / MAX_N_TYPES_OBSERVATION;
- for (int k = 0; k < nbSatObs; k++) {
- //Once the Date and Satellites list is read:
- // - to read the Data for each satellite
- // - 5 Observations per line
- final List<ObservationData> observationData = new ArrayList<>(nbSatObs);
- for (int j = 0; j < nbLinesObs; j++) {
- line = reader.readLine(); //Next line
- lineNumber++;
- final int iMax = FastMath.min(MAX_N_TYPES_OBSERVATION, nbTypes - observationData.size());
- for (int i = 0; i < iMax; i++) {
- observationData.add(new ObservationData(typesObs.get(observationData.size()),
- parseDouble(line, 16 * i, 14),
- parseInt(line, 14 + 16 * i, 1),
- parseInt(line, 15 + 16 * i, 1)));
- }
- }
- //We check that the Satellite type is consistent with Satellite System in the top of the file
- final SatelliteSystem satelliteSystemSat = SatelliteSystem.parseSatelliteSystem(satsObsList[k]);
- if (!satelliteSystem.equals(SatelliteSystem.MIXED)) {
- if (!satelliteSystemSat.equals(satelliteSystem)) {
- throw new OrekitException(OrekitMessages.INCONSISTENT_SATELLITE_SYSTEM,
- lineNumber, name, satelliteSystem, satelliteSystemSat);
- }
- }
- final int prnNumber;
- switch (satelliteSystemSat) {
- case GPS:
- case GLONASS:
- case GALILEO:
- prnNumber = Integer.parseInt(satsObsList[k].substring(1, 3).trim());
- break;
- case SBAS:
- prnNumber = Integer.parseInt(satsObsList[k].substring(1, 3).trim()) + 100;
- break;
- default:
- // MIXED satellite system is not allowed here
- throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
- lineNumber, name, line);
- }
- observationsList.add(new ObservationDataSet(satelliteSystemSat, prnNumber, tObs, rcvrClkOffset,
- observationData));
- }
- }
- }
- }
- break;
- case 3:
- final int MAX_OBS_TYPES_PER_LINE_RNX3 = 13;
- final int MAX_OBS_TYPES_SCALE_FACTOR_PER_LINE = 12;
- final int MAX_N_SAT_PHSHIFT_PER_LINE = 10;
- final Map<SatelliteSystem, List<ObservationType>> listTypeObs = new HashMap<>();
- final List<ObservationType> typeObs = new ArrayList<>();
- String sigStrengthUnit = null;
- int leapSecondsFuture = 0;
- int leapSecondsWeekNum = 0;
- int leapSecondsDayNum = 0;
- final List<AppliedDCBS> listAppliedDCBs = new ArrayList<>();
- final List<AppliedPCVS> listAppliedPCVS = new ArrayList<>();
- SatelliteSystem satSystemScaleFactor = null;
- int scaleFactor = 1;
- int nbObsScaleFactor = 0;
- final List<ObservationType> typesObsScaleFactor = new ArrayList<>();
- final List<ScaleFactorCorrection> scaleFactorCorrections = new ArrayList<>();
- String[] satsPhaseShift = null;
- int nbSatPhaseShift = 0;
- SatelliteSystem satSystemPhaseShift = null;
- double corrPhaseShift = 0.0;
- final List<PhaseShiftCorrection> phaseShiftCorrections = new ArrayList<>();
- ObservationType phaseShiftTypeObs = null;
- for (line = reader.readLine(); line != null; line = reader.readLine()) {
- ++lineNumber;
- if (observationsList == null) {
- switch(line.substring(LABEL_START).trim()) {
- case RINEX_VERSION_TYPE : {
- formatVersion = parseDouble(line, 0, 9);
- format100 = (int) FastMath.rint(100 * formatVersion);
- if ((format100 != 300) && (format100 != 301) && (format100 != 302) && (format100 != 303)) {
- throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
- }
- //File Type must be Observation_Data
- if (!(parseString(line, 20, 1)).equals(FILE_TYPE)) {
- throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
- }
- satelliteSystem = SatelliteSystem.parseSatelliteSystem(parseString(line, 40, 1));
- inRinexVersion = true;
- }
- break;
- case COMMENT :
- // nothing to do
- break;
- case PGM_RUN_BY_DATE :
- inRunBy = true;
- break;
- case MARKER_NAME :
- markerName = parseString(line, 0, 60);
- inMarkerName = true;
- break;
- case MARKER_NUMBER :
- markerNumber = parseString(line, 0, 20);
- break;
- case MARKER_TYPE :
- markerType = parseString(line, 0, 20);
- inMarkerType = true;
- //Could be done with an Enumeration
- break;
- case OBSERVER_AGENCY :
- observerName = parseString(line, 0, 20);
- agencyName = parseString(line, 20, 40);
- inObserver = true;
- break;
- case REC_NB_TYPE_VERS :
- receiverNumber = parseString(line, 0, 20);
- receiverType = parseString(line, 20, 20);
- receiverVersion = parseString(line, 40, 20);
- inRecType = true;
- break;
- case ANT_NB_TYPE :
- antennaNumber = parseString(line, 0, 20);
- antennaType = parseString(line, 20, 20);
- inAntType = true;
- break;
- case APPROX_POSITION_XYZ :
- approxPos = new Vector3D(parseDouble(line, 0, 14),
- parseDouble(line, 14, 14),
- parseDouble(line, 28, 14));
- inAproxPos = true;
- break;
- case ANTENNA_DELTA_H_E_N :
- antHeight = parseDouble(line, 0, 14);
- eccentricities = new Vector2D(parseDouble(line, 14, 14),
- parseDouble(line, 28, 14));
- inAntDelta = true;
- break;
- case ANTENNA_DELTA_X_Y_Z :
- antRefPoint = new Vector3D(parseDouble(line, 0, 14),
- parseDouble(line, 14, 14),
- parseDouble(line, 28, 14));
- break;
- case ANTENNA_PHASECENTER :
- obsCode = parseString(line, 2, 3);
- antPhaseCenter = new Vector3D(parseDouble(line, 5, 9),
- parseDouble(line, 14, 14),
- parseDouble(line, 28, 14));
- break;
- case ANTENNA_B_SIGHT_XYZ :
- antBSight = new Vector3D(parseDouble(line, 0, 14),
- parseDouble(line, 14, 14),
- parseDouble(line, 28, 14));
- break;
- case ANTENNA_ZERODIR_AZI :
- antAzi = parseDouble(line, 0, 14);
- break;
- case ANTENNA_ZERODIR_XYZ :
- antZeroDir = new Vector3D(parseDouble(line, 0, 14),
- parseDouble(line, 14, 14),
- parseDouble(line, 28, 14));
- break;
- case CENTER_OF_MASS_XYZ :
- centerMass = new Vector3D(parseDouble(line, 0, 14),
- parseDouble(line, 14, 14),
- parseDouble(line, 28, 14));
- break;
- case NB_OF_SATELLITES :
- nbSat = parseInt(line, 0, 6);
- break;
- case RCV_CLOCK_OFFS_APPL :
- clkOffset = parseInt(line, 0, 6);
- break;
- case INTERVAL :
- interval = parseDouble(line, 0, 10);
- break;
- case TIME_OF_FIRST_OBS :
- switch(satelliteSystem) {
- case GPS:
- timeScale = TimeScalesFactory.getGPS();
- break;
- case GALILEO:
- timeScale = TimeScalesFactory.getGST();
- break;
- case GLONASS:
- timeScale = TimeScalesFactory.getGLONASS();
- break;
- case QZSS:
- timeScale = TimeScalesFactory.getQZSS();
- break;
- case BEIDOU:
- timeScale = TimeScalesFactory.getBDT();
- break;
- case IRNSS:
- timeScale = TimeScalesFactory.getIRNSS();
- break;
- case MIXED:
- //in Case of Mixed data, Timescale must be specified in the Time of First line
- timeScaleStr = parseString(line, 48, 3);
- if (timeScaleStr.equals(GPS)) {
- timeScale = TimeScalesFactory.getGPS();
- } else if (timeScaleStr.equals(GAL)) {
- timeScale = TimeScalesFactory.getGST();
- } else if (timeScaleStr.equals(GLO)) {
- timeScale = TimeScalesFactory.getGLONASS();
- } else if (timeScaleStr.equals(QZS)) {
- timeScale = TimeScalesFactory.getQZSS();
- } else if (timeScaleStr.equals(BDT)) {
- timeScale = TimeScalesFactory.getBDT();
- } else if (timeScaleStr.equals(IRN)) {
- timeScale = TimeScalesFactory.getIRNSS();
- } else {
- throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
- }
- break;
- default :
- throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
- lineNumber, name, line);
- }
- tFirstObs = new AbsoluteDate(parseInt(line, 0, 6),
- parseInt(line, 6, 6),
- parseInt(line, 12, 6),
- parseInt(line, 18, 6),
- parseInt(line, 24, 6),
- parseDouble(line, 30, 13), timeScale);
- inFirstObs = true;
- break;
- case TIME_OF_LAST_OBS :
- tLastObs = new AbsoluteDate(parseInt(line, 0, 6),
- parseInt(line, 6, 6),
- parseInt(line, 12, 6),
- parseInt(line, 18, 6),
- parseInt(line, 24, 6),
- parseDouble(line, 30, 13), timeScale);
- break;
- case LEAP_SECONDS :
- leapSeconds = parseInt(line, 0, 6);
- leapSecondsFuture = parseInt(line, 6, 6);
- leapSecondsWeekNum = parseInt(line, 12, 6);
- leapSecondsDayNum = parseInt(line, 18, 6);
- //Time System Identifier must be added, last A3 String
- break;
- case PRN_NB_OF_OBS :
- //Optional line in header, indicates number of Observations par Satellite
- //Not stored for now
- break;
- case SYS_NB_OBS_TYPES :
- obsTypesSystem = null;
- typeObs.clear();
- obsTypesSystem = SatelliteSystem.parseSatelliteSystem(parseString(line, 0, 1));
- nbTypes = parseInt(line, 3, 3);
- final int nbLinesTypesObs = (nbTypes + MAX_OBS_TYPES_PER_LINE_RNX3 - 1) / MAX_OBS_TYPES_PER_LINE_RNX3;
- for (int j = 0; j < nbLinesTypesObs; j++) {
- if (j > 0) {
- line = reader.readLine(); //Next line
- lineNumber++;
- }
- final int iMax = FastMath.min(MAX_OBS_TYPES_PER_LINE_RNX3, nbTypes - typeObs.size());
- for (int i = 0; i < iMax; i++) {
- try {
- typeObs.add(ObservationType.valueOf(parseString(line, 7 + (4 * i), 3)));
- } catch (IllegalArgumentException iae) {
- throw new OrekitException(OrekitMessages.UNKNOWN_RINEX_FREQUENCY,
- parseString(line, 7 + (4 * i), 3), name, lineNumber);
- }
- }
- }
- listTypeObs.put(obsTypesSystem, new ArrayList<>(typeObs));
- inTypesObs = true;
- break;
- case SIGNAL_STRENGTH_UNIT :
- sigStrengthUnit = parseString(line, 0, 20);
- break;
- case SYS_DCBS_APPLIED :
- listAppliedDCBs.add(new AppliedDCBS(SatelliteSystem.parseSatelliteSystem(parseString(line, 0, 1)),
- parseString(line, 2, 17), parseString(line, 20, 40)));
- break;
- case SYS_PCVS_APPLIED :
- listAppliedPCVS.add(new AppliedPCVS(SatelliteSystem.parseSatelliteSystem(parseString(line, 0, 1)),
- parseString(line, 2, 17), parseString(line, 20, 40)));
- break;
- case SYS_SCALE_FACTOR :
- satSystemScaleFactor = null;
- scaleFactor = 1;
- nbObsScaleFactor = 0;
- satSystemScaleFactor = SatelliteSystem.parseSatelliteSystem(parseString(line, 0, 1));
- scaleFactor = parseInt(line, 2, 4);
- nbObsScaleFactor = parseInt(line, 8, 2);
- if (nbObsScaleFactor == 0) {
- typesObsScaleFactor.addAll(listTypeObs.get(satSystemScaleFactor));
- } else {
- final int nbLinesTypesObsScaleFactor = (nbObsScaleFactor + MAX_OBS_TYPES_SCALE_FACTOR_PER_LINE - 1) /
- MAX_OBS_TYPES_SCALE_FACTOR_PER_LINE;
- for (int j = 0; j < nbLinesTypesObsScaleFactor; j++) {
- if ( j > 0) {
- line = reader.readLine(); //Next line
- lineNumber++;
- }
- final int iMax = FastMath.min(MAX_OBS_TYPES_SCALE_FACTOR_PER_LINE, nbObsScaleFactor - typesObsScaleFactor.size());
- for (int i = 0; i < iMax; i++) {
- typesObsScaleFactor.add(ObservationType.valueOf(parseString(line, 11 + (4 * i), 3)));
- }
- }
- }
- scaleFactorCorrections.add(new ScaleFactorCorrection(satSystemScaleFactor,
- scaleFactor, typesObsScaleFactor));
- break;
- case SYS_PHASE_SHIFT :
- nbSatPhaseShift = 0;
- satsPhaseShift = null;
- corrPhaseShift = 0.0;
- phaseShiftTypeObs = null;
- satSystemPhaseShift = null;
- satSystemPhaseShift = SatelliteSystem.parseSatelliteSystem(parseString(line, 0, 1));
- phaseShiftTypeObs = ObservationType.valueOf(parseString(line, 2, 3));
- nbSatPhaseShift = parseInt(line, 16, 2);
- corrPhaseShift = parseDouble(line, 6, 8);
- if (nbSatPhaseShift == 0) {
- //If nbSat with Phase Shift is not indicated: all the satellites are affected for this Obs Type
- } else {
- satsPhaseShift = new String[nbSatPhaseShift];
- final int nbLinesSatPhaseShift = (nbSatPhaseShift + MAX_N_SAT_PHSHIFT_PER_LINE - 1) / MAX_N_SAT_PHSHIFT_PER_LINE;
- for (int j = 0; j < nbLinesSatPhaseShift; j++) {
- if (j > 0) {
- line = reader.readLine(); //Next line
- lineNumber++;
- }
- final int iMax = FastMath.min(MAX_N_SAT_PHSHIFT_PER_LINE, nbSatPhaseShift - j * MAX_N_SAT_PHSHIFT_PER_LINE);
- for (int i = 0; i < iMax; i++) {
- satsPhaseShift[i + 10 * j] = parseString(line, 19 + 4 * i, 3);
- }
- }
- }
- phaseShiftCorrections.add(new PhaseShiftCorrection(satSystemPhaseShift,
- phaseShiftTypeObs,
- corrPhaseShift,
- satsPhaseShift));
- inPhaseShift = true;
- break;
- case GLONASS_SLOT_FRQ_NB :
- //Not defined yet
- inGlonassSlot = true;
- break;
- case GLONASS_COD_PHS_BIS :
- //Not defined yet
- inGlonassCOD = true;
- break;
- case END_OF_HEADER :
- //We make sure that we have read all the mandatory fields inside the header of the Rinex
- if (!inRinexVersion || !inRunBy || !inMarkerName ||
- !inMarkerType || !inObserver || !inRecType || !inAntType ||
- !inAproxPos || !inAntDelta || !inTypesObs || !inFirstObs ||
- (formatVersion >= 3.01 && !inPhaseShift) ||
- (formatVersion >= 3.03 && (!inGlonassSlot || !inGlonassCOD))) {
- throw new OrekitException(OrekitMessages.INCOMPLETE_HEADER, name);
- }
- //Header information gathered
- observationsList = addHeader(new RinexHeader(formatVersion, satelliteSystem,
- markerName, markerNumber, markerType,
- observerName, agencyName, receiverNumber,
- receiverType, receiverVersion, antennaNumber,
- antennaType, approxPos, antHeight, eccentricities,
- antRefPoint, obsCode, antPhaseCenter, antBSight,
- antAzi, antZeroDir, centerMass, sigStrengthUnit,
- interval, tFirstObs, tLastObs, clkOffset, listAppliedDCBs,
- listAppliedPCVS, phaseShiftCorrections, leapSeconds,
- leapSecondsFuture, leapSecondsWeekNum, leapSecondsDayNum));
- break;
- default :
- if (observationsList == null) {
- //There must be an error due to an unknown Label inside the Header
- throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
- lineNumber, name, line);
- }
- }
- } else {
- //If End of Header
- //Start of a new Observation
- rcvrClkOffset = 0;
- eventFlag = -1;
- nbSatObs = -1;
- tObs = null;
- //A line that starts with ">" correspond to a new observation epoch
- if (parseString(line, 0, 1).equals(">")) {
- eventFlag = parseInt(line, 31, 1);
- //If eventFlag>1, we skip the corresponding lines to the next observation
- if (eventFlag != 0) {
- final int nbLinesSkip = parseInt(line, 32, 3);
- for (int i = 0; i < nbLinesSkip; i++) {
- line = reader.readLine();
- lineNumber++;
- }
- } else {
- tObs = new AbsoluteDate(parseInt(line, 2, 4),
- parseInt(line, 6, 3),
- parseInt(line, 9, 3),
- parseInt(line, 12, 3),
- parseInt(line, 15, 3),
- parseDouble(line, 18, 11), timeScale);
- nbSatObs = parseInt(line, 32, 3);
- //If the total number of satellites was indicated in the Header
- if (nbSat != -1 && nbSatObs > nbSat) {
- //we check that the number of Sat in the observation is consistent
- throw new OrekitException(OrekitMessages.INCONSISTENT_NUMBER_OF_SATS,
- lineNumber, name, nbSatObs, nbSat);
- }
- //Read the Receiver Clock offset, if present
- rcvrClkOffset = parseDouble(line, 41, 15);
- if (Double.isNaN(rcvrClkOffset)) {
- rcvrClkOffset = 0.0;
- }
- //For each one of the Satellites in this Observation
- for (int i = 0; i < nbSatObs; i++) {
- line = reader.readLine();
- lineNumber++;
- //We check that the Satellite type is consistent with Satellite System in the top of the file
- final SatelliteSystem satelliteSystemSat = SatelliteSystem.parseSatelliteSystem(parseString(line, 0, 1));
- if (!satelliteSystem.equals(SatelliteSystem.MIXED)) {
- if (!satelliteSystemSat.equals(satelliteSystem)) {
- throw new OrekitException(OrekitMessages.INCONSISTENT_SATELLITE_SYSTEM,
- lineNumber, name, satelliteSystem, satelliteSystemSat);
- }
- }
- final int prn = parseInt(line, 1, 2);
- final int prnNumber;
- switch (satelliteSystemSat) {
- case GPS:
- case GLONASS:
- case GALILEO:
- case BEIDOU:
- case IRNSS:
- prnNumber = prn;
- break;
- case QZSS:
- prnNumber = prn + 192;
- break;
- case SBAS:
- prnNumber = prn + 100;
- break;
- default:
- // MIXED satellite system is not allowed here
- throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
- lineNumber, name, line);
- }
- final List<ObservationData> observationData = new ArrayList<>(nbSatObs);
- for (int j = 0; j < listTypeObs.get(satelliteSystemSat).size(); j++) {
- final ObservationType rf = listTypeObs.get(satelliteSystemSat).get(j);
- boolean scaleFactorFound = false;
- //We look for the lines of ScaledFactorCorrections that correspond to this SatSystem
- int k = 0;
- double value = parseDouble(line, 3 + j * 16, 14);
- while (k < scaleFactorCorrections.size() && !scaleFactorFound) {
- if (scaleFactorCorrections.get(k).getSatelliteSystem().equals(satelliteSystemSat)) {
- //We check if the next Observation Type to read needs to be scaled
- if (scaleFactorCorrections.get(k).getTypesObsScaled().contains(rf)) {
- value /= scaleFactorCorrections.get(k).getCorrection();
- scaleFactorFound = true;
- }
- }
- k++;
- }
- observationData.add(new ObservationData(rf,
- value,
- parseInt(line, 17 + j * 16, 1),
- parseInt(line, 18 + j * 16, 1)));
- }
- observationsList.add(new ObservationDataSet(satelliteSystemSat, prnNumber, tObs, rcvrClkOffset,
- observationData));
- }
- }
- }
- }
- }
- break;
- default:
- //If RINEX Version is neither 2 nor 3
- throw new OrekitException(OrekitMessages.UNSUPPORTED_FILE_FORMAT, name);
- }
- }
- }
- /** Extract a string from a line.
- * @param line to parse
- * @param start start index of the string
- * @param length length of the string
- * @return parsed string
- */
- private String parseString(final String line, final int start, final int length) {
- if (line.length() > start) {
- return line.substring(start, FastMath.min(line.length(), start + length)).trim();
- } else {
- return null;
- }
- }
- /** Extract an integer from a line.
- * @param line to parse
- * @param start start index of the integer
- * @param length length of the integer
- * @return parsed integer
- */
- private int parseInt(final String line, final int start, final int length) {
- if (line.length() > start && !parseString(line, start, length).isEmpty()) {
- return Integer.parseInt(parseString(line, start, length));
- } else {
- return 0;
- }
- }
- /** Extract a double from a line.
- * @param line to parse
- * @param start start index of the real
- * @param length length of the real
- * @return parsed real, or {@code Double.NaN} if field was empty
- */
- private double parseDouble(final String line, final int start, final int length) {
- if (line.length() > start && !parseString(line, start, length).isEmpty()) {
- return Double.parseDouble(parseString(line, start, length));
- } else {
- return Double.NaN;
- }
- }
- /** Phase Shift corrections.
- * Contains the phase shift corrections used to
- * generate phases consistent with respect to cycle shifts.
- */
- public class PhaseShiftCorrection {
- /** Satellite System. */
- private final SatelliteSystem satSystemPhaseShift;
- /** Carrier Phase Observation Code. */
- private final ObservationType typeObsPhaseShift;
- /** Phase Shift Corrections (cycles). */
- private final double phaseShiftCorrection;
- /** List of satellites involved. */
- private final String[] satsPhaseShift;
- /** Simple constructor.
- * @param satSystemPhaseShift Satellite System
- * @param typeObsPhaseShift Carrier Phase Observation Code
- * @param phaseShiftCorrection Phase Shift Corrections (cycles)
- * @param satsPhaseShift List of satellites involved
- */
- private PhaseShiftCorrection(final SatelliteSystem satSystemPhaseShift,
- final ObservationType typeObsPhaseShift,
- final double phaseShiftCorrection, final String[] satsPhaseShift) {
- this.satSystemPhaseShift = satSystemPhaseShift;
- this.typeObsPhaseShift = typeObsPhaseShift;
- this.phaseShiftCorrection = phaseShiftCorrection;
- this.satsPhaseShift = satsPhaseShift;
- }
- /** Get the Satellite System.
- * @return Satellite System.
- */
- public SatelliteSystem getSatelliteSystem() {
- return satSystemPhaseShift;
- }
- /** Get the Carrier Phase Observation Code.
- * @return Carrier Phase Observation Code.
- */
- public ObservationType getTypeObs() {
- return typeObsPhaseShift;
- }
- /** Get the Phase Shift Corrections.
- * @return Phase Shift Corrections (cycles)
- */
- public double getCorrection() {
- return phaseShiftCorrection;
- }
- /** Get the list of satellites involved.
- * @return List of satellites involved (if null, all the sats are involved)
- */
- public String[] getSatsCorrected() {
- //If empty, all the satellites of this constellation are affected for this Observation type
- return satsPhaseShift;
- }
- }
- /** Scale Factor to be applied.
- * Contains the scale factors of 10 applied to the data before
- * being stored into the RINEX file.
- */
- public class ScaleFactorCorrection {
- /** Satellite System. */
- private final SatelliteSystem satSystemScaleFactor;
- /** List of Observations types that have been scaled. */
- private final List<ObservationType> typesObsScaleFactor;
- /** Factor to divide stored observations with before use. */
- private final double scaleFactor;
- /** Simple constructor.
- * @param satSystemScaleFactor Satellite System
- * @param scaleFactor Factor to divide stored observations (1,10,100,1000)
- * @param typesObsScaleFactor List of Observations types that have been scaled
- */
- private ScaleFactorCorrection(final SatelliteSystem satSystemScaleFactor,
- final double scaleFactor,
- final List<ObservationType> typesObsScaleFactor) {
- this.satSystemScaleFactor = satSystemScaleFactor;
- this.scaleFactor = scaleFactor;
- this.typesObsScaleFactor = typesObsScaleFactor;
- }
- /** Get the Satellite System.
- * @return Satellite System
- */
- public SatelliteSystem getSatelliteSystem() {
- return satSystemScaleFactor;
- }
- /** Get the Scale Factor.
- * @return Scale Factor
- */
- public double getCorrection() {
- return scaleFactor;
- }
- /** Get the list of Observation Types scaled.
- * @return List of Observation types scaled
- */
- public List<ObservationType> getTypesObsScaled() {
- return typesObsScaleFactor;
- }
- }
- /** Corrections of Differential Code Biases (DCBs) applied.
- * Contains information on the programs used to correct the observations
- * in RINEX files for differential code biases.
- */
- public class AppliedDCBS {
- /** Satellite system. */
- private final SatelliteSystem satelliteSystem;
- /** Program name used to apply differential code bias corrections. */
- private final String progDCBS;
- /** Source of corrections (URL). */
- private final String sourceDCBS;
- /** Simple constructor.
- * @param satelliteSystem satellite system
- * @param progDCBS Program name used to apply DCBs
- * @param sourceDCBS Source of corrections (URL)
- */
- private AppliedDCBS(final SatelliteSystem satelliteSystem,
- final String progDCBS, final String sourceDCBS) {
- this.satelliteSystem = satelliteSystem;
- this.progDCBS = progDCBS;
- this.sourceDCBS = sourceDCBS;
- }
- /** Get the satellite system.
- * @return satellite system
- */
- public SatelliteSystem getSatelliteSystem() {
- return satelliteSystem;
- }
- /** Get the program name used to apply DCBs.
- * @return Program name used to apply DCBs
- */
- public String getProgDCBS() {
- return progDCBS;
- }
- /** Get the source of corrections.
- * @return Source of corrections (URL)
- */
- public String getSourceDCBS() {
- return sourceDCBS;
- }
- }
- /** Corrections of antenna phase center variations (PCVs) applied.
- * Contains information on the programs used to correct the observations
- * in RINEX files for antenna phase center variations.
- */
- public class AppliedPCVS {
- /** Satellite system. */
- private final SatelliteSystem satelliteSystem;
- /** Program name used to antenna center variation corrections. */
- private final String progPCVS;
- /** Source of corrections (URL). */
- private final String sourcePCVS;
- /** Simple constructor.
- * @param satelliteSystem satellite system
- * @param progPCVS Program name used for PCVs
- * @param sourcePCVS Source of corrections (URL)
- */
- private AppliedPCVS(final SatelliteSystem satelliteSystem,
- final String progPCVS, final String sourcePCVS) {
- this.satelliteSystem = satelliteSystem;
- this.progPCVS = progPCVS;
- this.sourcePCVS = sourcePCVS;
- }
- /** Get the satellite system.
- * @return satellite system
- */
- public SatelliteSystem getSatelliteSystem() {
- return satelliteSystem;
- }
- /** Get the program name used to apply PCVs.
- * @return Program name used to apply PCVs
- */
- public String getProgPCVS() {
- return progPCVS;
- }
- /** Get the source of corrections.
- * @return Source of corrections (URL)
- */
- public String getSourcePCVS() {
- return sourcePCVS;
- }
- }
- }
- }