Commit a337ae61 authored by Bryan Cazabonne's avatar Bryan Cazabonne
Browse files

Merge branch 'master' into develop

parents 46754791 9f731446
......@@ -21,9 +21,6 @@
</properties>
<body>
<release version="11.2" date="TBD" description="TBD">
<action dev="luc" type="add" issue="902">
Take additional derivatives into account in {Field}SpacecraftState.shiftedBy.
</action>
<action dev="bryan" type="add" issue="900">
Added init method in {Field}AdditionalStateProvider.
</action>
......@@ -37,6 +34,33 @@
Added static method to create a BodyFacade from a CenterName.
</action>
</release>
<release version="11.1.1" date="2022-03-17"
description="Version 11.1.1 is a patch release of Orekit.
It fixes issues related to the parsing of SP3 and Rinex files. It also takes
additional derivatives into account in {Field}SpacecraftState.shiftedBy method.
Finally it includes some improvements in the class documentation">
<action dev="lars" type="add" issue="896">
Added Git configuration instructions in contributing guide.
</action>
<action dev="lars" type="fix" issue="897">
Corrected wrong path in release guide.
</action>
<action dev="bryan" type="fix" issue="894">
Fixed dead link in contributing guidelines.
</action>
<action dev="bryan" type="fix" issue="698">
Added missing BDS-3 signal for Rinex 3.04.
</action>
<action dev="bryan" type="fixed" issue="892">
Removed check of not supported keys in RinexLoader.
</action>
<action dev="lirw1984" type="update" issue="895">
Enhanced parsing of SP3 files.
</action>
<action dev="luc" type="add" issue="902">
Take additional derivatives into account in {Field}SpacecraftState.shiftedBy.
</action>
</release>
<release version="11.1" date="2022-02-14"
description="Version 11.1 is a minor release of Orekit.
It includes both new features and bug fixes. New features introduced
......
......@@ -19,6 +19,8 @@ package org.orekit.files.sp3;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.Scanner;
......@@ -28,10 +30,12 @@ import java.util.stream.Stream;
import org.hipparchus.exception.LocalizedCoreFormats;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.util.FastMath;
import org.orekit.annotation.DefaultDataContext;
import org.orekit.data.DataContext;
import org.orekit.data.DataSource;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitIllegalArgumentException;
import org.orekit.errors.OrekitMessages;
import org.orekit.files.general.EphemerisFileParser;
import org.orekit.files.sp3.SP3.SP3Coordinate;
......@@ -39,7 +43,9 @@ import org.orekit.files.sp3.SP3.SP3FileType;
import org.orekit.frames.Frame;
import org.orekit.gnss.TimeSystem;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.DateComponents;
import org.orekit.time.DateTimeComponents;
import org.orekit.time.TimeComponents;
import org.orekit.time.TimeScale;
import org.orekit.time.TimeScales;
import org.orekit.utils.CartesianDerivativesFilter;
......@@ -524,7 +530,7 @@ public class SP3Parser implements EphemerisFileParser<SP3> {
},
/** Parser for comments. */
HEADER_COMMENTS("^/\\*.*") {
HEADER_COMMENTS("^[%]?/\\*.*|") {
/** {@inheritDoc} */
@Override
......@@ -551,14 +557,95 @@ public class SP3Parser implements EphemerisFileParser<SP3> {
final int day = Integer.parseInt(line.substring(11, 13).trim());
final int hour = Integer.parseInt(line.substring(14, 16).trim());
final int minute = Integer.parseInt(line.substring(17, 19).trim());
final double second = Double.parseDouble(line.substring(20, 31).trim());
pi.latestEpoch = new AbsoluteDate(year, month, day,
hour, minute, second,
pi.timeScale);
final double second = Double.parseDouble(line.substring(20).trim());
// some SP3 files have weird epochs as in the following two examples, where
// the middle dates are wrong
//
// * 2016 7 6 16 58 0.00000000
// PL51 11872.234459 3316.551981 101.400098 999999.999999
// VL51 8054.606014 -27076.640110 -53372.762255 999999.999999
// * 2016 7 6 16 60 0.00000000
// PL51 11948.228978 2986.113872 -538.901114 999999.999999
// VL51 4605.419303 -27972.588048 -53316.820671 999999.999999
// * 2016 7 6 17 2 0.00000000
// PL51 11982.652569 2645.786926 -1177.549463 999999.999999
// VL51 1128.248622 -28724.293303 -53097.358387 999999.999999
//
// * 2016 7 6 23 58 0.00000000
// PL51 3215.382310 -7958.586164 8812.395707
// VL51 -18058.659942 -45834.335707 -34496.540437
// * 2016 7 7 24 0 0.00000000
// PL51 2989.229334 -8494.421415 8385.068555
// VL51 -19617.027447 -43444.824985 -36706.159070
// * 2016 7 7 0 2 0.00000000
// PL51 2744.983592 -9000.639164 7931.904779
// VL51 -21072.925764 -40899.633288 -38801.567078
//
// In the first case, the date should really be 2016 7 6 17 0 0.00000000,
// i.e as the minutes field overflows, the hours field should be incremented
// In the second case, the date should really be 2016 7 7 0 0 0.00000000,
// i.e. as the hours field overflows, the day field should be kept as is
// we cannot be sure how carry was managed when these bogus files were written
// so we try different options, incrementing or not previous field, and selecting
// the closest one to expected date
DateComponents dc = new DateComponents(year, month, day);
final List<AbsoluteDate> candidates = new ArrayList<>();
int h = hour;
int m = minute;
double s = second;
if (s >= 60.0) {
s -= 60;
addCandidate(candidates, dc, h, m, s, pi.timeScale);
m++;
}
if (m > 59) {
m = 0;
addCandidate(candidates, dc, h, m, s, pi.timeScale);
h++;
}
if (h > 23) {
h = 0;
addCandidate(candidates, dc, h, m, s, pi.timeScale);
dc = new DateComponents(dc, 1);
}
addCandidate(candidates, dc, h, m, s, pi.timeScale);
final AbsoluteDate expected = pi.latestEpoch == null ?
pi.file.getEpoch() :
pi.latestEpoch.shiftedBy(pi.file.getEpochInterval());
pi.latestEpoch = null;
for (final AbsoluteDate candidate : candidates) {
if (FastMath.abs(candidate.durationFrom(expected)) < 0.01 * pi.file.getEpochInterval()) {
pi.latestEpoch = candidate;
}
}
if (pi.latestEpoch == null) {
// no date recognized, just parse again the initial fields
// in order to generate again an exception
pi.latestEpoch = new AbsoluteDate(year, month, day, hour, minute, second, pi.timeScale);
}
pi.nbEpochs++;
}
/** Add an epoch candidate to a list.
* @param candidates list of candidates
* @param dc date components
* @param hour hour number from 0 to 23
* @param minute minute number from 0 to 59
* @param second second number from 0.0 to 60.0 (excluded)
* @param timeScale time scale
* @since 11.1.1
*/
private void addCandidate(final List<AbsoluteDate> candidates, final DateComponents dc,
final int hour, final int minute, final double second,
final TimeScale timeScale) {
try {
candidates.add(new AbsoluteDate(dc, new TimeComponents(hour, minute, second), timeScale));
} catch (OrekitIllegalArgumentException oiae) {
// ignored
}
}
/** {@inheritDoc} */
@Override
public Stream<LineParser> allowedNext() {
......@@ -586,7 +673,7 @@ public class SP3Parser implements EphemerisFileParser<SP3> {
pi.latestPosition = new Vector3D(x * 1000, y * 1000, z * 1000);
// clock (microsec)
pi.latestClock = line.length() <= 46 ?
pi.latestClock = line.trim().length() <= 46 ?
DEFAULT_CLOCK_VALUE :
Double.parseDouble(line.substring(46, 60).trim()) * 1e-6;
......@@ -670,7 +757,7 @@ public class SP3Parser implements EphemerisFileParser<SP3> {
final Vector3D velocity = new Vector3D(xv / 10d, yv / 10d, zv / 10d);
// clock rate in file is 1e-4 us / s
final double clockRateChange = line.length() <= 46 ?
final double clockRateChange = line.trim().length() <= 46 ?
DEFAULT_CLOCK_VALUE :
Double.parseDouble(line.substring(46, 60).trim()) * 1e-4;
......
......@@ -63,7 +63,7 @@ import org.orekit.utils.ParameterDriver;
* The radiative model of the satellite, and its ability to diffuse, reflect or absorb radiation is handled
* by a {@link RadiationSensitive radiation sensitive model}.
* </p> <p>
* <b>Caution:</b> The spacecraft state must be defined in an Earth centered frame.
* <b>Caution:</b> This model is only suitable for Earth. Using it with another central body is prone to error..
* </p>
*
* @author Thomas Paulet
......
......@@ -270,7 +270,6 @@ public class RinexObservationLoader {
int nbSatObs = -1;
int nbLinesSat = -1;
double rcvrClkOffset = 0;
boolean inRunBy = false;
boolean inMarkerName = false;
boolean inObserver = false;
boolean inRecType = false;
......@@ -280,8 +279,6 @@ public class RinexObservationLoader {
boolean inTypesObs = false;
boolean inFirstObs = false;
boolean inPhaseShift = false;
boolean inGlonassSlot = false;
boolean inGlonassCOD = false;
RinexObservationHeader rinexHeader = null;
int scaleFactor = 1;
int nbObsScaleFactor = 0;
......@@ -327,7 +324,7 @@ public class RinexObservationLoader {
// nothing to do
break;
case PGM_RUN_BY_DATE :
inRunBy = true;
// nothing to do
break;
case MARKER_NAME :
markerName = parseString(0, 60);
......@@ -482,7 +479,7 @@ public class RinexObservationLoader {
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 ||
if (!inRinexVersion || !inMarkerName ||
!inObserver || !inRecType || !inAntType ||
formatVersion < 2.20 && !inAproxPos ||
formatVersion < 2.20 && !inAntDelta ||
......@@ -678,7 +675,7 @@ public class RinexObservationLoader {
// nothing to do
break;
case PGM_RUN_BY_DATE :
inRunBy = true;
// nothing to do
break;
case MARKER_NAME :
markerName = parseString(0, 60);
......@@ -936,20 +933,17 @@ public class RinexObservationLoader {
break;
}
case GLONASS_SLOT_FRQ_NB :
//Not defined yet
inGlonassSlot = true;
// Not defined yet
break;
case GLONASS_COD_PHS_BIS :
//Not defined yet
inGlonassCOD = true;
// Not defined yet
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 ||
if (!inRinexVersion || !inMarkerName ||
!inObserver || !inRecType || !inAntType ||
!inAntDelta || !inTypesObs || !inFirstObs ||
formatVersion >= 3.01 && !inPhaseShift ||
formatVersion >= 3.03 && (!inGlonassSlot || !inGlonassCOD)) {
formatVersion >= 3.01 && !inPhaseShift) {
throw new OrekitException(OrekitMessages.INCOMPLETE_HEADER, name);
}
......
......@@ -39,7 +39,7 @@ import org.orekit.time.TimeScale;
*/
public class MagneticFieldDetector extends AbstractDetector<MagneticFieldDetector> {
/** Fixed threshold value of Magnetic field to be crossed. */
/** Fixed threshold value of Magnetic field to be crossed, in nano Teslas. */
private final double limit;
/** Fixed altitude of computed magnetic field value. */
......@@ -68,7 +68,7 @@ public class MagneticFieldDetector extends AbstractDetector<MagneticFieldDetecto
*
* <p>This method uses the {@link DataContext#getDefault() default data context}.
*
* @param limit the threshold value of magnetic field at see level
* @param limit the threshold value of magnetic field at see level, in nano Teslas
* @param type the magnetic field model
* @param body the body
* @exception OrekitIllegalArgumentException if orbit type is {@link OrbitType#CARTESIAN}
......@@ -87,7 +87,7 @@ public class MagneticFieldDetector extends AbstractDetector<MagneticFieldDetecto
*
* <p>This method uses the {@link DataContext#getDefault() default data context}.
*
* @param limit the threshold value of magnetic field at see level
* @param limit the threshold value of magnetic field at see level, in nano Teslas
* @param type the magnetic field model
* @param body the body
* @param seaLevel true if the magnetic field intensity is computed at the sea level, false if it is computed at satellite altitude
......@@ -106,7 +106,7 @@ public class MagneticFieldDetector extends AbstractDetector<MagneticFieldDetecto
*
* @param maxCheck maximal checking interval (s)
* @param threshold convergence threshold (s)
* @param limit the threshold value of magnetic field at see level
* @param limit the threshold value of magnetic field at see level, in nano Teslas
* @param type the magnetic field model
* @param body the body
* @param seaLevel true if the magnetic field intensity is computed at the sea level, false if it is computed at satellite altitude
......@@ -126,7 +126,7 @@ public class MagneticFieldDetector extends AbstractDetector<MagneticFieldDetecto
*
* @param maxCheck maximal checking interval (s)
* @param threshold convergence threshold (s)
* @param limit the threshold value of magnetic field at see level
* @param limit the threshold value of magnetic field at see level, in nano Teslas
* @param type the magnetic field model
* @param body the body
* @param seaLevel true if the magnetic field intensity is computed at the sea
......@@ -157,7 +157,7 @@ public class MagneticFieldDetector extends AbstractDetector<MagneticFieldDetecto
* @param threshold convergence threshold (s)
* @param maxIter maximum number of iterations in the event time search
* @param handler event handler to call at event occurrences
* @param limit the threshold value of magnetic field at see level
* @param limit the threshold value of magnetic field at see level, in nano Teslas
* @param type the magnetic field model
* @param body the body
* @param seaLevel true if the magnetic field intensity is computed at the sea level, false if it is computed at satellite altitude
......
......@@ -209,7 +209,7 @@ Pressing the *Add...* button at the top right of the install wizard will
display a small popup asking for the name and location of a new software site.
* Name = Checkstyle
* Location = http://eclipse-cs.sf.net/update/
* Location = https://checkstyle.org/eclipse-cs-update-site
Press *Add* to close the popup.
......
......@@ -45,7 +45,7 @@ with groupID org.orekit and artifactId orekit so maven
internal mechanism will download automatically all artifacts and dependencies
as required.
#set ( $versions = {"11.1": "2022-02-14", "11.0.2": "2021-11-24", "11.0.1": "2021-10-22", "11.0": "2021-09-20", "10.3.1": "2021-06-16", "10.3": "2020-12-21", "10.2": "2020-07-14", "10.1": "2020-02-19", "10.0": "2019-06-24", "9.3.1": "2019-03-16", "9.3": "2019-01-25", "9.2": "2018-05-26","9.1": "2017-11-26","9.0.1": "2017-11-03","9.0": "2017-07-26","8.0.1": "2017-11-03","8.0": "2016-06-30","7.2.1": "2017-11-03","7.2": "2016-04-05","7.1": "2016-02-07","7.0": "2015-01-11","6.1": "2013-12-13","6.0": "2013-04-23","5.0.3": "2011-07-13","5.0.2": "2011-07-11","5.0.1": "2011-04-18"} )
#set ( $versions = {"11.1.1": "2022-03-17", "11.1": "2022-02-14", "11.0.2": "2021-11-24", "11.0.1": "2021-10-22", "11.0": "2021-09-20", "10.3.1": "2021-06-16", "10.3": "2020-12-21", "10.2": "2020-07-14", "10.1": "2020-02-19", "10.0": "2019-06-24", "9.3.1": "2019-03-16", "9.3": "2019-01-25", "9.2": "2018-05-26","9.1": "2017-11-26","9.0.1": "2017-11-03","9.0": "2017-07-26","8.0.1": "2017-11-03","8.0": "2016-06-30","7.2.1": "2017-11-03","7.2": "2016-04-05","7.1": "2016-02-07","7.0": "2015-01-11","6.1": "2013-12-13","6.0": "2013-04-23","5.0.3": "2011-07-13","5.0.2": "2011-07-11","5.0.1": "2011-04-18"} )
#foreach( $version in $versions.entrySet() )
| package | link |
......
......@@ -144,6 +144,7 @@ Math to Hipparchus
Orekit 11.0.1 | Hipparchus 2.0
Orekit 11.0.2 | Hipparchus 2.0
Orekit 11.1 | Hipparchus 2.0
Orekit 11.1.1 | Hipparchus 2.0
### Maven failed to compile Orekit and complained about a missing artifact.
......
......@@ -567,6 +567,170 @@ public class SP3ParserTest {
}
@Test
public void testIssue895HeaderComment() {
// Test issue 895
final String ex = "/sp3/issue895-header-comment.sp3";
final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
final SP3 file = new SP3Parser().parse(source);
// Verify
Assert.assertEquals(TimeSystem.UTC, file.getTimeSystem());
Assert.assertEquals(SP3.SP3FileType.LEO, file.getType());
}
@Test
public void testIssue895ClockRecord() {
// Test issue 895
final String ex = "/sp3/issue895-clock-record.sp3";
final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
final SP3 file = new SP3Parser().parse(source);
// Verify
Assert.assertEquals(TimeSystem.UTC, file.getTimeSystem());
Assert.assertEquals(SP3.SP3FileType.LEO, file.getType());
Assert.assertEquals(1, file.getSatelliteCount());
final List<SP3Coordinate> coords = file.getSatellites().get("L51").getCoordinates();
Assert.assertEquals(1, coords.size());
final SP3Coordinate coord = coords.get(0);
// 2021 12 26 0 0 0.00000000
Assert.assertEquals(new AbsoluteDate(2021, 12, 26, 0, 0, 0,
TimeScalesFactory.getUTC()), coord.getDate());
// PL51 5029.867893 1304.362160 -11075.527276 999999.999999
// VL51 -17720.521773 -55720.482742 -14441.695083 999999.999999
checkPVEntry(new PVCoordinates(new Vector3D(5029867.893, 1304362.160, -11075527.276),
new Vector3D(-1772.0521773, -5572.0482742, -1444.1695083)),
coord);
}
@Test
public void testIssue895RolloverMinutes() {
// Test issue 895
final String ex = "/sp3/issue895-minutes-increment.sp3";
final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
final SP3 file = new SP3Parser().parse(source);
// Verify
Assert.assertEquals(TimeSystem.UTC, file.getTimeSystem());
Assert.assertEquals(SP3.SP3FileType.LEO, file.getType());
Assert.assertEquals(1, file.getSatelliteCount());
final List<SP3Coordinate> coords = file.getSatellites().get("L51").getCoordinates();
Assert.assertEquals(91, coords.size());
final SP3Coordinate coord30 = coords.get(30);
// 2016 7 6 16 60 0.00000000
Assert.assertEquals(new AbsoluteDate(2016, 7, 6, 17, 0, 0,
TimeScalesFactory.getUTC()), coord30.getDate());
// PL51 11948.228978 2986.113872 -538.901114 999999.999999
// VL51 4605.419303 -27972.588048 -53316.820671 999999.999999
checkPVEntry(new PVCoordinates(new Vector3D(11948228.978, 2986113.872, -538901.114),
new Vector3D(460.5419303, -2797.2588048, -5331.6820671)),
coord30);
final SP3Coordinate coord31 = coords.get(31);
// 2016 7 6 17 2 0.00000000
Assert.assertEquals(new AbsoluteDate(2016, 7, 6, 17, 2, 0,
TimeScalesFactory.getUTC()), coord31.getDate());
// PL51 11982.652569 2645.786926 -1177.549463 999999.999999
// VL51 1128.248622 -28724.293303 -53097.358387 999999.999999
checkPVEntry(new PVCoordinates(new Vector3D(11982652.569, 2645786.926, -1177549.463),
new Vector3D(112.8248622, -2872.4293303, -5309.7358387)),
coord31);
final SP3Coordinate coord60 = coords.get(60);
// 2016 7 6 17 60 0.00000000
Assert.assertEquals(new AbsoluteDate(2016, 7, 6, 18, 0, 0,
TimeScalesFactory.getUTC()), coord60.getDate());
// PL51 -1693.056569 -4123.276630 -11431.599723 999999.999999
// VL51 -59412.268951 4066.817074 7604.890337 999999.999999
checkPVEntry(new PVCoordinates(new Vector3D(-1693056.569, -4123276.630, -11431599.723),
new Vector3D(-5941.2268951, 406.6817074, 760.4890337)),
coord60);
}
@Test
public void testIssue895RolloverHours() {
// Test issue 895
final String ex = "/sp3/issue895-hours-increment.sp3";
final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
final SP3 file = new SP3Parser().parse(source);
// Verify
Assert.assertEquals(TimeSystem.UTC, file.getTimeSystem());
Assert.assertEquals(SP3.SP3FileType.LEO, file.getType());
Assert.assertEquals(1, file.getSatelliteCount());
final List<SP3Coordinate> coords = file.getSatellites().get("L51").getCoordinates();
Assert.assertEquals(61, coords.size());
final SP3Coordinate coord30 = coords.get(30);
// 2016 7 7 24 0 0.00000000
Assert.assertEquals(new AbsoluteDate(2016, 7, 7, 0, 0, 0,
TimeScalesFactory.getUTC()), coord30.getDate());
//PL51 2989.229334 -8494.421415 8385.068555
//VL51 -19617.027447 -43444.824985 -36706.159070
checkPVEntry(new PVCoordinates(new Vector3D(2989229.334, -8494421.415, 8385068.555),
new Vector3D(-1961.7027447, -4344.4824985, -3670.6159070)),
coord30);
final SP3Coordinate coord31 = coords.get(31);
// 2016 7 7 0 2 0.00000000
Assert.assertEquals(new AbsoluteDate(2016, 7, 7, 0, 2, 0,
TimeScalesFactory.getUTC()), coord31.getDate());
// PL51 2744.983592 -9000.639164 7931.904779
// VL51 -21072.925764 -40899.633288 -38801.567078
checkPVEntry(new PVCoordinates(new Vector3D(2744983.592, -9000639.164, 7931904.779),
new Vector3D(-2107.2925764, -4089.9633288, -3880.1567078)),
coord31);
}
@Test
public void testIssue895SecondDigits() {
// Test issue 895
final String ex = "/sp3/issue895-second-digits.sp3";
final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
final SP3 file = new SP3Parser().parse(source);
// Verify
Assert.assertEquals(TimeSystem.UTC, file.getTimeSystem());
Assert.assertEquals(SP3.SP3FileType.LEO, file.getType());
Assert.assertEquals(1, file.getSatelliteCount());
final List<SP3Coordinate> coords = file.getSatellites().get("L51").getCoordinates();
Assert.assertEquals(1, coords.size());
final SP3Coordinate coord = coords.get(0);
// 2016 7 3 0 0 0.1234
Assert.assertEquals(new AbsoluteDate(2016, 7, 3, 0, 0, 0.1234,
TimeScalesFactory.getUTC()), coord.getDate());
}
@Before
public void setUp() {
Utils.setDataRoot("regular-data");
......
......@@ -601,6 +601,47 @@ public class HatanakaCompressFilterTest {
}
@Test
public void testIssue892() throws IOException, NoSuchAlgorithmException {
//Tests Rinex 3 with Hatanaka compression
final String name = "rinex/DJIG00DJI_R_20191820000_01D_30S_MO.crx.gz";
final DataSource raw = new DataSource(name.substring(name.indexOf('/') + 1),
() -> Utils.class.getClassLoader().getResourceAsStream(name));
Digester digester = new Digester(new HatanakaCompressFilter().filter(new GzipFilter().filter(raw)),
"3813aa1ac94733dd56c289998a34e7ec0cac8d5d03692038a966124994b52343");
RinexObservationLoader loader = new RinexObservationLoader(digester.getDigestedSource());
AbsoluteDate t0 = new AbsoluteDate(2019, 7, 1, TimeScalesFactory.getGPS());
List<ObservationDataSet> ods = loader.getObservationDataSets();
Assert.assertEquals(133040, ods.size());
Assert.assertEquals("DJIG", ods.get(0).getHeader().getMarkerName());
Assert.assertEquals(SatelliteSystem.BEIDOU, ods.get(0).getSatelliteSystem());
Assert.assertEquals(2, ods.get(0).getPrnNumber());
Assert.assertEquals(0.0, ods.get(0).getDate().durationFrom(t0), 1.0e-15);
Assert.assertEquals(12, ods.get(0).getObservationData().size());
Assert.assertEquals(37732983.563, ods.get(0).getObservationData().get(0).getValue(), 1.0e-3);
Assert.assertEquals(37732971.582, ods.get(0).getObservationData().get(1).getValue(), 1.0e-3);
Assert.assertEquals(37732976.137, ods.get(0).getObservationData().get(2).getValue(), 1.0e-3);
Assert.assertEquals(-2.043, ods.get(0).getObservationData().get(3).getValue(), 1.0e-3);
Assert.assertEquals("DJIG", ods.get(96).getHeader().getMarkerName());
Assert.assertEquals(SatelliteSystem.BEIDOU, ods.get(96).getSatelliteSystem());
Assert.assertEquals(12, ods.get(96).getPrnNumber());
Assert.assertEquals(60.0, ods.get(96).getDate().durationFrom(t0), 1.0e-15);
Assert.assertEquals(12, ods.get(96).getObservationData().size());
Assert.assertEquals(25161908.281, ods.get(96).getObservationData().get(0).getValue(), 1.0e-3);
Assert.assertEquals(25161895.332, ods.get(96).getObservationData().get(1).getValue(), 1.0e-3);
Assert.assertEquals(25161903.730, ods.get(96).getObservationData().get(2).getValue(), 1.0e-3);
Assert.assertEquals(1488.887, ods.get(96).getObservationData().get(3).getValue(), 1.0e-3);
Assert.assertEquals(1207.371, ods.get(96).getObservationData().get(4).getValue(), 1.0e-3);
// the reference digest was computed externally using CRX2RNX and sha256sum on a Linux computer
digester.checkDigest();
}
private static class Digester {