1   /* Copyright 2002-2025 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.files.rinex.navigation;
18  
19  import java.io.IOException;
20  import java.lang.reflect.Constructor;
21  import java.lang.reflect.Field;
22  import java.lang.reflect.InvocationTargetException;
23  import java.lang.reflect.Method;
24  import java.util.Arrays;
25  import java.util.List;
26  
27  import org.hipparchus.geometry.euclidean.threed.Vector3D;
28  import org.hipparchus.util.FastMath;
29  import org.junit.jupiter.api.Assertions;
30  import org.junit.jupiter.api.BeforeEach;
31  import org.junit.jupiter.api.Test;
32  import org.orekit.Utils;
33  import org.orekit.data.DataContext;
34  import org.orekit.data.DataSource;
35  import org.orekit.data.TruncatingFilter;
36  import org.orekit.errors.OrekitException;
37  import org.orekit.errors.OrekitIllegalArgumentException;
38  import org.orekit.errors.OrekitInternalError;
39  import org.orekit.errors.OrekitMessages;
40  import org.orekit.files.rinex.utils.RinexFileType;
41  import org.orekit.frames.Frames;
42  import org.orekit.frames.FramesFactory;
43  import org.orekit.gnss.PredefinedGnssSignal;
44  import org.orekit.gnss.SatelliteSystem;
45  import org.orekit.gnss.TimeSystem;
46  import org.orekit.propagation.Propagator;
47  import org.orekit.propagation.analytical.gnss.GNSSPropagator;
48  import org.orekit.propagation.analytical.gnss.GnssTestUtils;
49  import org.orekit.propagation.analytical.gnss.SBASPropagator;
50  import org.orekit.propagation.analytical.gnss.data.BeidouCivilianNavigationMessage;
51  import org.orekit.propagation.analytical.gnss.data.BeidouLegacyNavigationMessage;
52  import org.orekit.propagation.analytical.gnss.data.BeidouSatelliteType;
53  import org.orekit.propagation.analytical.gnss.data.GLONASSNavigationMessage;
54  import org.orekit.propagation.analytical.gnss.data.GNSSConstants;
55  import org.orekit.propagation.analytical.gnss.data.GPSCivilianNavigationMessage;
56  import org.orekit.propagation.analytical.gnss.data.GPSLegacyNavigationMessage;
57  import org.orekit.propagation.analytical.gnss.data.GalileoNavigationMessage;
58  import org.orekit.propagation.analytical.gnss.data.NavICL1NVNavigationMessage;
59  import org.orekit.propagation.analytical.gnss.data.NavICLegacyNavigationMessage;
60  import org.orekit.propagation.analytical.gnss.data.QZSSCivilianNavigationMessage;
61  import org.orekit.propagation.analytical.gnss.data.QZSSLegacyNavigationMessage;
62  import org.orekit.propagation.analytical.gnss.data.SBASNavigationMessage;
63  import org.orekit.propagation.numerical.GLONASSNumericalPropagator;
64  import org.orekit.time.AbsoluteDate;
65  import org.orekit.time.GNSSDate;
66  import org.orekit.time.TimeScalesFactory;
67  import org.orekit.utils.Constants;
68  import org.orekit.utils.IERSConventions;
69  import org.orekit.utils.PVCoordinates;
70  import org.orekit.utils.units.Unit;
71  
72  public class NavigationFileParserTest {
73  
74      @BeforeEach
75      public void setUp() {
76          Utils.setDataRoot("regular-data");
77      }
78  
79      @Test
80      public void testWorkAroundWrongFormatNumber() throws IOException {
81          // the test file tells it is in 3.05 format, but in fact
82          // its GLONASS navigation messages are in 3.04 format
83          // so there the 4th broadcast line expected in 3.05 is missing here
84          // such a file has really been found in the wild
85          final String ex = "/gnss/navigation/invalid-but-accepted.n";
86          final RinexNavigation file = new RinexNavigationParser().
87                          parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
88          Assertions.assertEquals(3.05, file.getHeader().getFormatVersion(), Double.MIN_VALUE);
89          Assertions.assertEquals(1, file.getGPSLegacyNavigationMessages().size());
90          Assertions.assertEquals(1, file.getGPSLegacyNavigationMessages().get("G32").size());
91          Assertions.assertEquals(1, file.getGlonassNavigationMessages().size());
92          Assertions.assertEquals(2, file.getGlonassNavigationMessages().get("R01").size());
93      }
94  
95      @Test
96      public void testGpsRinex301Truncated() throws IOException {
97  
98          // Parse file
99          final String ex = "/gnss/navigation/Example_GPS_Rinex301.n";
100         try {
101             new RinexNavigationParser().
102                         parse(new TruncatingFilter(5).
103                               filter(new DataSource(ex, () -> getClass().getResourceAsStream(ex))));
104             Assertions.fail("an exception should have been thrown");
105         } catch (OrekitException oe) {
106             Assertions.assertEquals(OrekitMessages.UNEXPECTED_END_OF_FILE, oe.getSpecifier());
107         }
108     }
109 
110     @Test
111     public void testGpsRinex301() throws IOException {
112 
113         // Parse file
114         final String ex = "/gnss/navigation/Example_GPS_Rinex301.n";
115         final RinexNavigation file = new RinexNavigationParser().
116                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
117 
118         // Verify Header
119         Assertions.assertEquals(3.01,                          file.getHeader().getFormatVersion(), Double.MIN_VALUE);
120         Assertions.assertEquals(RinexFileType.NAVIGATION,      file.getHeader().getFileType());
121         Assertions.assertEquals(SatelliteSystem.GPS,           file.getHeader().getSatelliteSystem());
122         Assertions.assertEquals("XXRINEXN V3",                 file.getHeader().getProgramName());
123         Assertions.assertEquals("AIUB",                        file.getHeader().getRunByName());
124         Assertions.assertEquals("1999-09-03T15:22:36.0",       file.getHeader().getCreationDateComponents().toStringWithoutUtcOffset(60, 1));
125         Assertions.assertEquals("UTC",                         file.getHeader().getCreationTimeZone());
126         Assertions.assertEquals(0.0,                           file.getHeader().getCreationDate().durationFrom(new AbsoluteDate(1999, 9, 3, 15, 22, 36.0, TimeScalesFactory.getUTC())), 0.0);
127         Assertions.assertEquals(IonosphericCorrectionType.GPS, file.getHeader().getIonosphericCorrectionType());
128         Assertions.assertEquals(0.1676e-07,                    file.getKlobucharAlpha()[0], Double.MIN_VALUE);
129         Assertions.assertEquals(0.2235e-07,                    file.getKlobucharAlpha()[1], Double.MIN_VALUE);
130         Assertions.assertEquals(0.1192e-06,                    file.getKlobucharAlpha()[2], Double.MIN_VALUE);
131         Assertions.assertEquals(0.1192e-06,                    file.getKlobucharAlpha()[3], Double.MIN_VALUE);
132         Assertions.assertEquals(0.1208e+06,                    file.getKlobucharBeta()[0],  Double.MIN_VALUE);
133         Assertions.assertEquals(0.1310e+06,                    file.getKlobucharBeta()[1],  Double.MIN_VALUE);
134         Assertions.assertEquals(-0.1310e+06,                   file.getKlobucharBeta()[2],  Double.MIN_VALUE);
135         Assertions.assertEquals(-0.1966e+06,                   file.getKlobucharBeta()[3],  Double.MIN_VALUE);
136         Assertions.assertEquals("GPUT",                        file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionType());
137         Assertions.assertEquals(0.1331791282e-06,              file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionA0(), Double.MIN_VALUE);
138         Assertions.assertEquals(0.107469589e-12,               file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionA1(), Double.MIN_VALUE);
139         GNSSDate date = new GNSSDate(file.getHeader().getTimeSystemCorrections().get(0).getReferenceDate(), SatelliteSystem.GPS);
140         Assertions.assertEquals(552960,                        date.getSecondsInWeek());
141         Assertions.assertEquals(1025,                          date.getWeekNumber());
142         Assertions.assertEquals("EXAMPLE OF VERSION 3.00 FORMAT", file.getComments().get(0).getText());
143         Assertions.assertEquals(13, file.getHeader().getNumberOfLeapSeconds());
144 
145         // Verify data
146         checkFieldConversion(file);
147         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
148         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
149         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
150         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
151         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
152         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
153         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
154         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
155         Assertions.assertEquals(2, file.getGPSLegacyNavigationMessages().size());
156         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
157 
158         final GPSLegacyNavigationMessage gps = file.getGPSLegacyNavigationMessages("G13").get(0);
159         Assertions.assertEquals(0.0, gps.getEpochToc().durationFrom(new AbsoluteDate(1999, 9, 2, 19, 0, 0, TimeScalesFactory.getGPS())), Double.MIN_VALUE);
160         Assertions.assertEquals(0.490025617182e-03,  gps.getAf0(), 1.0e-15);
161         Assertions.assertEquals(0.204636307899e-11,  gps.getAf1(), 1.0e-15);
162         Assertions.assertEquals(0.000000000000e+00,  gps.getAf2(), 1.0e-15);
163         Assertions.assertEquals(133,                 gps.getIODE());
164         Assertions.assertEquals(-0.963125000000e+02, gps.getCrs(), 1.0e-15);
165         Assertions.assertEquals(0.292961152146e+01,  gps.getM0(), 1.0e-15);
166         Assertions.assertEquals(-0.498816370964e-05, gps.getCuc(), 1.0e-15);
167         Assertions.assertEquals(0.200239347760e-02,  gps.getE(), 1.0e-15);
168         Assertions.assertEquals(0.928156077862e-05,  gps.getCus(), 1.0e-15);
169         Assertions.assertEquals(0.515328476143e+04,  FastMath.sqrt(gps.getSma()), 1.0e-15);
170         Assertions.assertEquals(0.414000000000e+06,  gps.getTime(), 1.0e-15);
171         Assertions.assertEquals(-0.279396772385e-07, gps.getCic(), 1.0e-15);
172         Assertions.assertEquals(0.243031939942e+01,  gps.getOmega0(), 1.0e-15);
173         Assertions.assertEquals(-0.558793544769e-07, gps.getCis(), 1.0e-15);
174         Assertions.assertEquals(0.110192796930e+01,  gps.getI0(), 1.0e-15);
175         Assertions.assertEquals(0.271187500000e+03,  gps.getCrc(), 1.0e-15);
176         Assertions.assertEquals(-0.232757915425e+01, gps.getPa(), 1.0e-15);
177         Assertions.assertEquals(-0.619632953057e-08, gps.getOmegaDot(), 1.0e-15);
178         Assertions.assertEquals(-0.785747015231e-11, gps.getIDot(), 1.0e-15);
179         Assertions.assertEquals(1025,                gps.getWeek());
180         Assertions.assertEquals(0.000000000000e+00,  gps.getSvAccuracy(), 1.0e-15);
181         Assertions.assertEquals(0.000000000000e+00,  gps.getSvHealth(), 1.0e-15);
182         Assertions.assertEquals(0.000000000000e+00,  gps.getTGD(), 1.0e-15);
183         Assertions.assertEquals(389,                 gps.getIODC());
184 
185         // check weeks reference in Rinex navigation are aligned with GPS weeks
186         final AbsoluteDate obsRebuiltDate = new GNSSDate(gps.getWeek(), gps.getTime(), SatelliteSystem.GPS).
187                                             getDate();
188         final double relativeTime = obsRebuiltDate.durationFrom(gps.getEpochToc());
189         Assertions.assertEquals(0.0, relativeTime / Constants.JULIAN_DAY, 7.0);
190         Assertions.assertEquals(0.0, obsRebuiltDate.durationFrom(gps.getDate()), 1.0e-15);
191         
192         // check the propagator
193         final GNSSPropagator propagator = gps.getPropagator();
194         final AbsoluteDate date0 = gps.getDate();
195         final Vector3D p0 = propagator.propagateInEcef(date0).getPosition();
196         final double gpsCycleDuration = gps.getCycleDuration();
197         final AbsoluteDate date1 = date0.shiftedBy(gpsCycleDuration);
198         final Vector3D p1 = propagator.propagateInEcef(date1).getPosition();
199         Assertions.assertEquals(0., p0.distance(p1), 0.);
200     }
201 
202     @Test
203     public void testGpsRinex400() throws IOException {
204 
205         // Parse file
206         final String ex = "/gnss/navigation/Example_GPS_Rinex400.n";
207         final RinexNavigation file = new RinexNavigationParser().
208                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
209 
210         // Verify Header
211         Assertions.assertEquals(4.00,                                 file.getHeader().getFormatVersion(), Double.MIN_VALUE);
212         Assertions.assertEquals(RinexFileType.NAVIGATION,             file.getHeader().getFileType());
213         Assertions.assertEquals(SatelliteSystem.MIXED,                file.getHeader().getSatelliteSystem());
214         Assertions.assertEquals("Manual",                             file.getHeader().getProgramName());
215         Assertions.assertEquals("Orekit",                             file.getHeader().getRunByName());
216         Assertions.assertEquals("https://doi.org/10.xxxx",            file.getHeader().getDoi());
217         Assertions.assertEquals("Apache V2",                          file.getHeader().getLicense());
218         Assertions.assertEquals("not really a station",               file.getHeader().getStationInformation());
219         Assertions.assertEquals(18,                                   file.getHeader().getNumberOfLeapSeconds());
220         Assertions.assertEquals(102,                                  file.getHeader().getMergedFiles());
221 
222         // Verify data
223         checkFieldConversion(file);
224         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
225         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
226         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
227         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
228         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
229         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
230         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
231         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
232         Assertions.assertEquals(1, file.getGPSLegacyNavigationMessages().size());
233         Assertions.assertEquals(2, file.getGPSCivilianNavigationMessages().size());
234         Assertions.assertEquals(0, file.getSystemTimeOffsets().size());
235         Assertions.assertEquals(0, file.getEarthOrientationParameters().size());
236         Assertions.assertEquals(0, file.getKlobucharMessages().size());
237         Assertions.assertEquals(0, file.getNequickGMessages().size());
238         Assertions.assertEquals(0, file.getBDGIMMessages().size());
239 
240         final GPSLegacyNavigationMessage gpsL = file.getGPSLegacyNavigationMessages("G01").get(0);
241         Assertions.assertEquals(0.0, gpsL.getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 0, 0, 0, TimeScalesFactory.getGPS())), Double.MIN_VALUE);
242         Assertions.assertEquals(0, gpsL.getSvHealth());
243         Assertions.assertEquals(4, gpsL.getFitInterval());
244 
245         final List<GPSCivilianNavigationMessage> list = file.getGPSCivilianNavigationMessages("G01");
246         Assertions.assertEquals(2, list.size());
247         Assertions.assertEquals(0.0, list.get(0).getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 1, 30, 0, TimeScalesFactory.getGPS())), Double.MIN_VALUE);
248         Assertions.assertEquals(-6, list.get(0).getUraiNed0());
249         Assertions.assertEquals( 2, list.get(0).getUraiNed1());
250         Assertions.assertEquals( 7, list.get(0).getUraiNed2());
251         Assertions.assertEquals(-1, list.get(0).getUraiEd());
252         Assertions.assertEquals(-3.492459654808e-10, list.get(0).getIscL1CA(), 1.0e-20);
253         Assertions.assertEquals(-2.823071554303e-09, list.get(0).getIscL2C(),  1.0e-20);
254         Assertions.assertEquals(6.810296326876e-09,  list.get(0).getIscL5I5(), 1.0e-20);
255         Assertions.assertEquals(6.897607818246e-09,  list.get(0).getIscL5Q5(), 1.0e-20);
256         Assertions.assertEquals(259206.0, list.get(0).getTransmissionTime(), 1.0e-10);
257         Assertions.assertEquals(2230, list.get(0).getWeek());
258         Assertions.assertEquals(0.0, list.get(1).getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 3, 30, 0, TimeScalesFactory.getGPS())), Double.MIN_VALUE);
259 
260     }
261 
262     @Test
263     public void testSBASRinex301() throws IOException {
264 
265         // Parse file
266         final String ex = "/gnss/navigation/Example_SBAS_Rinex301.n";
267         final RinexNavigation file = new RinexNavigationParser().
268                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
269 
270         // Verify Header
271         Assertions.assertEquals(3.01,                     file.getHeader().getFormatVersion(), Double.MIN_VALUE);
272         Assertions.assertEquals(RinexFileType.NAVIGATION, file.getHeader().getFileType());
273         Assertions.assertEquals(SatelliteSystem.SBAS,     file.getHeader().getSatelliteSystem());
274         Assertions.assertEquals("sbf2rin-9.3.3",          file.getHeader().getProgramName());
275         Assertions.assertEquals("",                       file.getHeader().getRunByName());
276         Assertions.assertEquals("2015-01-06T00:08:09.0",  file.getHeader().getCreationDateComponents().toStringWithoutUtcOffset(60, 1));
277         Assertions.assertEquals("LCL",                    file.getHeader().getCreationTimeZone());
278 
279         // Verify data
280         checkFieldConversion(file);
281         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
282         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
283         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
284         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
285         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
286         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
287         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
288         Assertions.assertEquals(2, file.getSBASNavigationMessages().size());
289         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
290         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
291 
292         final SBASNavigationMessage sbas = file.getSBASNavigationMessages("S27").get(0);
293         // BEWARE! in Rinex 3.01, the time scale for SBAS navigation is UTC
294         Assertions.assertEquals(0.0, sbas.getEpochToc().durationFrom(new AbsoluteDate(2015, 1, 4, 23, 58, 56.0, TimeScalesFactory.getUTC())), Double.MIN_VALUE);
295         Assertions.assertEquals(2.980232238770E-08,  sbas.getAGf0(), 1.0e-10);
296         Assertions.assertEquals(1.182343112305E-11,  sbas.getAGf1(), 1.0e-10);
297         Assertions.assertEquals(8.631300000000E+04,  sbas.getTime(), 1.0e-10);
298         Assertions.assertEquals(2420.415392000E+04,  sbas.getX(), 1.0e-10);
299         Assertions.assertEquals(-3450.000000000E-04, sbas.getXDot(), 1.0e-10);
300         Assertions.assertEquals(-3375.000000000E-07, sbas.getXDotDot(), 1.0e-10);
301         Assertions.assertEquals(3.100000000000E+01,  sbas.getHealth(), 1.0e-10);
302         Assertions.assertEquals(3453.707432000E+04,  sbas.getY(), 1.0e-10);
303         Assertions.assertEquals(-2950.625000000E-03, sbas.getYDot(), 1.0e-10);
304         Assertions.assertEquals(1750.000000000E-07,  sbas.getYDotDot(), 1.0e-10);
305         Assertions.assertEquals(4.096000000000E+03,  sbas.getURA(), 1.0e-10);
306         Assertions.assertEquals(-3269.960000000E+01, sbas.getZ(), 1.0e-10);
307         Assertions.assertEquals(-2132.000000000E-03, sbas.getZDot(), 1.0e-10);
308         Assertions.assertEquals(1875.000000000E-07,  sbas.getZDotDot(), 1.0e-10);
309         Assertions.assertEquals(192,                 sbas.getIODN(), 1.0e-10);
310 
311         // check the propagator
312         final SBASPropagator propagator = sbas.getPropagator();
313         final PVCoordinates pv = propagator.propagateInEcef(sbas.getDate());
314         final Vector3D position = pv.getPosition();
315         final Vector3D velocity = pv.getVelocity();
316         final Vector3D acceleration = pv.getAcceleration();
317         double eps = 1.0e-15;
318         Assertions.assertEquals(sbas.getX(),       position.getX(),     eps);
319         Assertions.assertEquals(sbas.getY(),       position.getY(),     eps);
320         Assertions.assertEquals(sbas.getZ(),       position.getZ(),     eps);
321         Assertions.assertEquals(sbas.getXDot(),    velocity.getX(),     eps);
322         Assertions.assertEquals(sbas.getYDot(),    velocity.getY(),     eps);
323         Assertions.assertEquals(sbas.getZDot(),    velocity.getZ(),     eps);
324         Assertions.assertEquals(sbas.getXDotDot(), acceleration.getX(), eps);
325         Assertions.assertEquals(sbas.getYDotDot(), acceleration.getY(), eps);
326         Assertions.assertEquals(sbas.getZDotDot(), acceleration.getZ(), eps);
327 
328     }
329 
330     @Test
331     public void testBeidouRinex302() throws IOException {
332 
333         final String ex = "/gnss/navigation/Example_Beidou_Rinex302.n";
334         final RinexNavigation file = new RinexNavigationParser().
335                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
336 
337         // Verify Header
338         Assertions.assertEquals(3.02,                     file.getHeader().getFormatVersion(), Double.MIN_VALUE);
339         Assertions.assertEquals(RinexFileType.NAVIGATION, file.getHeader().getFileType());
340         Assertions.assertEquals(SatelliteSystem.BEIDOU,   file.getHeader().getSatelliteSystem());
341         Assertions.assertEquals("Converto v3.5.5",        file.getHeader().getProgramName());
342         Assertions.assertEquals("IGN",                    file.getHeader().getRunByName());
343         Assertions.assertEquals("2021-02-24T01:20:52.0",  file.getHeader().getCreationDateComponents().toStringWithoutUtcOffset(60, 1));
344         Assertions.assertEquals("UTC",                    file.getHeader().getCreationTimeZone());
345         Assertions.assertEquals(4,                        file.getHeader().getNumberOfLeapSeconds());
346 
347         // Verify data
348         checkFieldConversion(file);
349         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
350         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
351         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
352         Assertions.assertEquals(2, file.getBeidouLegacyNavigationMessages().size());
353         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
354         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
355         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
356         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
357         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
358         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
359 
360         final BeidouLegacyNavigationMessage bdt = file.getBeidouLegacyNavigationMessages("C02").get(0);
361         Assertions.assertEquals(0.0, bdt.getEpochToc().durationFrom(new AbsoluteDate(2021, 2, 22, 22, 0, 0, TimeScalesFactory.getBDT())), Double.MIN_VALUE);
362         Assertions.assertEquals(4.916836041957e-04,  bdt.getAf0(), 1.0e-15);
363         Assertions.assertEquals(-3.058442388237e-11, bdt.getAf1(), 1.0e-15);
364         Assertions.assertEquals(0.000000000000e+00,  bdt.getAf2(), 1.0e-15);
365         Assertions.assertEquals(1,                   bdt.getAODE());
366         Assertions.assertEquals(2.775156250000e+02,  bdt.getCrs(), 1.0e-15);
367         Assertions.assertEquals(-2.539159755499e+00, bdt.getM0(), 1.0e-15);
368         Assertions.assertEquals(9.234994649887e-06,  bdt.getCuc(), 1.0e-15);
369         Assertions.assertEquals(9.814361110330e-04,  bdt.getE(), 1.0e-15);
370         Assertions.assertEquals(9.856652468443e-06,  bdt.getCus(), 1.0e-15);
371         Assertions.assertEquals(6.493364431381e+03,  FastMath.sqrt(bdt.getSma()), 1.0e-15);
372         Assertions.assertEquals(1.656000000000e+05,  bdt.getTime(), 1.0e-15);
373         Assertions.assertEquals(8.055940270424e-08,  bdt.getCic(), 1.0e-15);
374         Assertions.assertEquals(2.930216013841e+00,  bdt.getOmega0(), 1.0e-15);
375         Assertions.assertEquals(-1.355074346066e-07, bdt.getCis(), 1.0e-15);
376         Assertions.assertEquals(6.617987281734e-02,  bdt.getI0(), 1.0e-15);
377         Assertions.assertEquals(-2.970000000000e+02, bdt.getCrc(), 1.0e-15);
378         Assertions.assertEquals(5.859907097566e-01,  bdt.getPa(), 1.0e-15);
379         Assertions.assertEquals(4.416612541069e-09,  bdt.getOmegaDot(), 1.0e-15);
380         Assertions.assertEquals(-4.628764235181e-10, bdt.getIDot(), 1.0e-15);
381         Assertions.assertEquals(790,                 bdt.getWeek());
382         Assertions.assertEquals(2.000000000000e+00,  bdt.getSvAccuracy(), 1.0e-15);
383         Assertions.assertEquals(1.500000000000e-09,  bdt.getTGD1(), 1.0e-15);
384         Assertions.assertEquals(-1.370000000000e-08, bdt.getTGD2(), 1.0e-15);
385 
386         // check weeks reference in Rinex navigation are aligned with Beidou weeks (not GPS weeks as other systems)
387         final AbsoluteDate obsRebuiltDate = new GNSSDate(bdt.getWeek(), bdt.getTime(), SatelliteSystem.BEIDOU).getDate();
388         final double relativeTime = obsRebuiltDate.durationFrom(bdt.getEpochToc());
389         Assertions.assertEquals(0.0, relativeTime / Constants.JULIAN_DAY, 7.0);
390         Assertions.assertEquals(0.0, obsRebuiltDate.durationFrom(bdt.getDate()), 1.0e-15);
391 
392         // check the propagator
393         final GNSSPropagator propagator = bdt.getPropagator(DataContext.getDefault().getFrames());
394         final AbsoluteDate date0 = bdt.getDate();
395         final Vector3D p0 = propagator.propagateInEcef(date0).getPosition();
396         final double gpsCycleDuration = bdt.getCycleDuration();
397         final AbsoluteDate date1 = date0.shiftedBy(gpsCycleDuration);
398         final Vector3D p1 = propagator.propagateInEcef(date1).getPosition();
399         Assertions.assertEquals(0., p0.distance(p1), 0.);
400 
401     }
402 
403     @Test
404     public void testBeidouRinex400() throws IOException {
405 
406         // Parse file
407         final String ex = "/gnss/navigation/Example_Beidou_Rinex400.n";
408         final RinexNavigation file = new RinexNavigationParser().
409                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
410 
411         // Verify Header
412         Assertions.assertEquals(4.00,                                 file.getHeader().getFormatVersion(), Double.MIN_VALUE);
413         Assertions.assertEquals(RinexFileType.NAVIGATION,             file.getHeader().getFileType());
414         Assertions.assertEquals(SatelliteSystem.MIXED,                file.getHeader().getSatelliteSystem());
415         Assertions.assertEquals("BCEmerge",                           file.getHeader().getProgramName());
416         Assertions.assertEquals("congo",                              file.getHeader().getRunByName());
417         Assertions.assertEquals("https://doi.org/10.57677/BRD400DLR", file.getHeader().getDoi());
418         Assertions.assertNull(file.getHeader().getLicense());
419         Assertions.assertNull(file.getHeader().getStationInformation());
420         Assertions.assertEquals(18,                                   file.getHeader().getNumberOfLeapSeconds());
421         Assertions.assertEquals(102,                                  file.getHeader().getMergedFiles());
422 
423         // Verify data
424         checkFieldConversion(file);
425         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
426         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
427         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
428         Assertions.assertEquals(2, file.getBeidouLegacyNavigationMessages().size());
429         Assertions.assertEquals(1, file.getBeidouCivilianNavigationMessages().size());
430         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
431         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
432         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
433         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
434         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
435 
436         final BeidouLegacyNavigationMessage bdtL = file.getBeidouLegacyNavigationMessages().get("C06").get(0);
437         Assertions.assertEquals(0.0, bdtL.getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 0, 0, 0, TimeScalesFactory.getBDT())), Double.MIN_VALUE);
438 
439         final List<BeidouCivilianNavigationMessage> list = file.getBeidouCivilianNavigationMessages("C19");
440         Assertions.assertEquals(6, list.size());
441         Assertions.assertEquals(0.0, list.get(0).getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 0, 0, 0, TimeScalesFactory.getBDT())), Double.MIN_VALUE);
442         Assertions.assertTrue(list.get(0).getRadioWave().closeTo(PredefinedGnssSignal.B1C, 1.0e-6));
443         Assertions.assertEquals(-1.139640808105e-02, list.get(0).getADot(),       1.0e-15);
444         Assertions.assertEquals(-1.300156250000e+02, list.get(0).getCrs(),        1.0e-15);
445         Assertions.assertEquals(3.453536710809e-09,  list.get(0).getDeltaN0(),    1.0e-15);
446         Assertions.assertEquals(-8.439895553698e-01, list.get(0).getM0(),         1.0e-15);
447         Assertions.assertEquals(-6.432645022869e-06, list.get(0).getCuc(),        1.0e-15);
448         Assertions.assertEquals(5.305649829097e-04,  list.get(0).getE(),          1.0e-15);
449         Assertions.assertEquals(8.089467883110e-06,  list.get(0).getCus(),        1.0e-15);
450         Assertions.assertEquals(5.282638737345e+03,  list.get(0).getSqrtA(),      1.0e-15);
451         Assertions.assertEquals(2.592000000000e+05,  list.get(0).getTime(),       1.0e-15);
452         Assertions.assertEquals(-4.377216100693e-08, list.get(0).getCic(),        1.0e-15);
453         Assertions.assertEquals(1.698788226948e+00,  list.get(0).getOmega0(),     1.0e-15);
454         Assertions.assertEquals(-1.303851604462e-08, list.get(0).getCis(),        1.0e-15);
455         Assertions.assertEquals(9.703601465722e-01,  list.get(0).getI0(),         1.0e-15);
456         Assertions.assertEquals(2.000742187500e+02,  list.get(0).getCrc(),        1.0e-15);
457         Assertions.assertEquals(-1.021547253715e+00, list.get(0).getPa(),         1.0e-15);
458         Assertions.assertEquals(-6.782425372384e-09, list.get(0).getOmegaDot(),   1.0e-15);
459         Assertions.assertEquals(-8.911085468192e-11, list.get(0).getIDot(),       1.0e-15);
460         Assertions.assertEquals(9.367106834964e-14,  list.get(0).getDeltaN0Dot(), 1.0e-15);
461         Assertions.assertEquals(BeidouSatelliteType.MEO, list.get(0).getSatelliteType());
462         Assertions.assertEquals(2.592000000000e+05,  list.get(0).getTime(),       1.0e-15);
463         Assertions.assertEquals( 0, list.get(0).getSisaiOe());
464         Assertions.assertEquals(-5, list.get(0).getSisaiOcb());
465         Assertions.assertEquals(-1, list.get(0).getSisaiOc1());
466         Assertions.assertEquals(-1, list.get(0).getSisaiOc2());
467         Assertions.assertEquals(-8.731149137020e-10, list.get(0).getIscB1CD(),    1.0e-15);
468         Assertions.assertEquals(0.0,                 list.get(0).getIscB2AD(),    1.0e-15);
469         Assertions.assertEquals(9.487848728895e-09,  list.get(0).getTgdB1Cp(),    1.0e-15);
470         Assertions.assertEquals(-5.820766091347e-09, list.get(0).getTgdB2ap(),    1.0e-15);
471         Assertions.assertEquals(-1, list.get(0).getSismai());
472         Assertions.assertEquals(0, list.get(0).getHealth());
473         Assertions.assertEquals(0, list.get(0).getIntegrityFlags());
474         Assertions.assertEquals(16, list.get(0).getIODC());
475         Assertions.assertEquals(259200.0, list.get(0).getTransmissionTime(), 1.0e-10);
476         Assertions.assertEquals(16, list.get(0).getIODE());
477 
478         Assertions.assertEquals(0.0, list.get(1).getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 1, 0, 0, TimeScalesFactory.getBDT())), Double.MIN_VALUE);
479         Assertions.assertTrue(list.get(1).getRadioWave().closeTo(PredefinedGnssSignal.B1C, 1.0e-6));
480         Assertions.assertEquals(0.0, list.get(2).getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 0, 0, 0, TimeScalesFactory.getBDT())), Double.MIN_VALUE);
481         Assertions.assertTrue(list.get(2).getRadioWave().closeTo(PredefinedGnssSignal.B2A, 1.0e-6));
482         Assertions.assertEquals(0.0,                 list.get(2).getIscB1CD(),    1.0e-15);
483         Assertions.assertEquals(-2.735760062933e-09, list.get(2).getIscB2AD(),    1.0e-15);
484         Assertions.assertEquals(0.0, list.get(3).getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 1, 0, 0, TimeScalesFactory.getBDT())), Double.MIN_VALUE);
485         Assertions.assertTrue(list.get(3).getRadioWave().closeTo(PredefinedGnssSignal.B2A));
486         Assertions.assertEquals(0.0, list.get(4).getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 0, 0, 0, TimeScalesFactory.getBDT())), Double.MIN_VALUE);
487         Assertions.assertTrue(list.get(4).getRadioWave().closeTo(PredefinedGnssSignal.B2B));
488         Assertions.assertEquals(0.0, list.get(5).getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 1, 0, 0, TimeScalesFactory.getBDT())), Double.MIN_VALUE);
489         Assertions.assertTrue(list.get(5).getRadioWave().closeTo(PredefinedGnssSignal.B2B));
490 
491     }
492 
493     @Test
494     public void testGalileoRinex302() throws IOException {
495 
496         // Parse file
497         final String ex = "/gnss/navigation/Example_Galileo_Rinex302.n";
498         final RinexNavigation file = new RinexNavigationParser().
499                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
500 
501         // Verify Header
502         Assertions.assertEquals(3.02,                          file.getHeader().getFormatVersion(), Double.MIN_VALUE);
503         Assertions.assertEquals(RinexFileType.NAVIGATION,      file.getHeader().getFileType());
504         Assertions.assertEquals(SatelliteSystem.GALILEO,       file.getHeader().getSatelliteSystem());
505         Assertions.assertEquals("sbf2rin-10.2.0",              file.getHeader().getProgramName());
506         Assertions.assertEquals("",                            file.getHeader().getRunByName());
507         Assertions.assertEquals("2016-04-28T00:36:37.0",       file.getHeader().getCreationDateComponents().toStringWithoutUtcOffset(60, 1));
508         Assertions.assertEquals("LCL",                         file.getHeader().getCreationTimeZone());
509         Assertions.assertEquals(IonosphericCorrectionType.GAL, file.getHeader().getIonosphericCorrectionType());
510         Assertions.assertEquals(3.5500E+01,                    file.getNeQuickAlpha()[0], Double.MIN_VALUE);
511         Assertions.assertEquals(-2.3438E-02,                   file.getNeQuickAlpha()[1], Double.MIN_VALUE);
512         Assertions.assertEquals(1.6632E-02,                    file.getNeQuickAlpha()[2], Double.MIN_VALUE);
513         Assertions.assertEquals(0.0000E+00,                    file.getNeQuickAlpha()[3], Double.MIN_VALUE);
514         Assertions.assertEquals("GPGA", file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionType());
515         Assertions.assertEquals("GAUT", file.getHeader().getTimeSystemCorrections().get(1).getTimeSystemCorrectionType());
516         Assertions.assertEquals(-2.9103830457E-11,             file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionA0(), Double.MIN_VALUE);
517         Assertions.assertEquals(-4.440892099E-16,              file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionA1(), Double.MIN_VALUE);
518         GNSSDate date = new GNSSDate(file.getHeader().getTimeSystemCorrections().get(0).getReferenceDate(), SatelliteSystem.GPS);
519         Assertions.assertEquals(313200,                        date.getSecondsInWeek());
520         Assertions.assertEquals(1920,                          date.getWeekNumber());
521 
522         Assertions.assertTrue(file.getComments().isEmpty());
523         Assertions.assertEquals(17, file.getHeader().getNumberOfLeapSeconds());
524 
525         // Verify data
526         checkFieldConversion(file);
527         Assertions.assertEquals(2, file.getGalileoNavigationMessages().size());
528         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
529         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
530         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
531         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
532         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
533         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
534         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
535         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
536         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
537 
538         final GalileoNavigationMessage gal = file.getGalileoNavigationMessages("E08").get(3);
539         Assertions.assertEquals(0.0, gal.getEpochToc().durationFrom(new AbsoluteDate(2016, 4, 26, 5, 50, 0, TimeScalesFactory.getGST())), Double.MIN_VALUE);
540         Assertions.assertEquals(1.646681921557E-03,  gal.getAf0(), 1.0e-15);
541         Assertions.assertEquals(3.988276375821E-10,  gal.getAf1(), 1.0e-15);
542         Assertions.assertEquals(0.000000000000e+00,  gal.getAf2(), 1.0e-15);
543         Assertions.assertEquals(285,                 gal.getIODNav());
544         Assertions.assertEquals(-1.550000000000E+01, gal.getCrs(), 1.0e-15);
545         Assertions.assertEquals(-1.881713322719E+00, gal.getM0(), 1.0e-15);
546         Assertions.assertEquals(-9.220093488693E-07, gal.getCuc(), 1.0e-15);
547         Assertions.assertEquals(2.031255280599E-04,  gal.getE(), 1.0e-15);
548         Assertions.assertEquals(8.771196007729E-06,  gal.getCus(), 1.0e-15);
549         Assertions.assertEquals(5.440611787796E+03,  FastMath.sqrt(gal.getSma()), 1.0e-15);
550         Assertions.assertEquals(1.938000000000E+05,  gal.getTime(), 1.0e-15);
551         Assertions.assertEquals(7.450580596924E-09,  gal.getCic(), 1.0e-15);
552         Assertions.assertEquals(-1.589621838359E-01, gal.getOmega0(), 1.0e-15);
553         Assertions.assertEquals(5.401670932770E-08,  gal.getCis(), 1.0e-15);
554         Assertions.assertEquals(9.594902351453E-01,  gal.getI0(), 1.0e-15);
555         Assertions.assertEquals(1.494687500000E+02,  gal.getCrc(), 1.0e-15);
556         Assertions.assertEquals(-1.602015041031E+00, gal.getPa(), 1.0e-15);
557         Assertions.assertEquals(-5.460941755858E-09, gal.getOmegaDot(), 1.0e-15);
558         Assertions.assertEquals(-6.350264514006E-10, gal.getIDot(), 1.0e-15);
559         Assertions.assertEquals(1894,                gal.getWeek());
560         Assertions.assertEquals(3.120000000000E+00,  gal.getSisa(), 1.0e-15);
561         Assertions.assertEquals(0.000000000000e+00,  gal.getSvHealth(), 1.0e-15);
562         Assertions.assertEquals(-7.450580596924E-09, gal.getBGDE1E5a(), 1.0e-15);
563         Assertions.assertEquals(0.000000000000E+00,  gal.getBGDE5bE1(), 1.0e-15);
564 
565         // check weeks reference in Rinex navigation are aligned with GPS weeks
566         final AbsoluteDate obsRebuiltDate = new GNSSDate(gal.getWeek(), gal.getTime(), SatelliteSystem.GPS).
567                                             getDate();
568         final double relativeTime = obsRebuiltDate.durationFrom(gal.getEpochToc());
569         Assertions.assertEquals(0.0, relativeTime / Constants.JULIAN_DAY, 7.0);
570         Assertions.assertEquals(0.0, obsRebuiltDate.durationFrom(gal.getDate()), 1.0e-15);
571 
572         // check the propagator
573         final GNSSPropagator propagator = gal.getPropagator(DataContext.getDefault().getFrames());
574         final AbsoluteDate date0 = gal.getDate();
575         final Vector3D p0 = propagator.propagateInEcef(date0).getPosition();
576         final double gpsCycleDuration = gal.getCycleDuration();
577         final AbsoluteDate date1 = date0.shiftedBy(gpsCycleDuration);
578         final Vector3D p1 = propagator.propagateInEcef(date1).getPosition();
579         Assertions.assertEquals(0., p0.distance(p1), 0.);
580 
581     }
582 
583     @Test
584     public void testGalileoRinex400() throws IOException {
585 
586         // Parse file
587         final String ex = "/gnss/navigation/Example_Galileo_Rinex400.n";
588         final RinexNavigation file = new RinexNavigationParser().
589                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
590 
591         // Verify Header
592         Assertions.assertEquals(4.00,                                 file.getHeader().getFormatVersion(), Double.MIN_VALUE);
593         Assertions.assertEquals(RinexFileType.NAVIGATION,             file.getHeader().getFileType());
594         Assertions.assertEquals(SatelliteSystem.MIXED,                file.getHeader().getSatelliteSystem());
595         Assertions.assertEquals("BCEmerge",                           file.getHeader().getProgramName());
596         Assertions.assertEquals("congo",                              file.getHeader().getRunByName());
597         Assertions.assertEquals("https://doi.org/10.57677/BRD400DLR", file.getHeader().getDoi());
598         Assertions.assertNull(file.getHeader().getLicense());
599         Assertions.assertNull(file.getHeader().getStationInformation());
600         Assertions.assertEquals(18,                                   file.getHeader().getNumberOfLeapSeconds());
601         Assertions.assertEquals(102,                                  file.getHeader().getMergedFiles());
602 
603         // Verify data
604         checkFieldConversion(file);
605         Assertions.assertEquals(1, file.getGalileoNavigationMessages().size());
606         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
607         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
608         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
609         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
610         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
611         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
612         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
613         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
614         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
615 
616         final GalileoNavigationMessage galL = file.getGalileoNavigationMessages().get("E01").get(0);
617         Assertions.assertEquals(0.0, galL.getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 0, 30, 0, TimeScalesFactory.getGPS())), Double.MIN_VALUE);
618         Assertions.assertEquals(516, galL.getDataSource());
619 
620     }
621 
622     @Test
623     public void testQZSSRinex302() throws IOException {
624 
625         final String ex = "/gnss/navigation/Example_QZSS_Rinex302.n";
626         final RinexNavigation file = new RinexNavigationParser().
627                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
628 
629         // Verify Header
630         Assertions.assertEquals(3.02,                          file.getHeader().getFormatVersion(), Double.MIN_VALUE);
631         Assertions.assertEquals(RinexFileType.NAVIGATION,      file.getHeader().getFileType());
632         Assertions.assertEquals(SatelliteSystem.QZSS,          file.getHeader().getSatelliteSystem());
633         Assertions.assertEquals("NetR9 5.45",                  file.getHeader().getProgramName());
634         Assertions.assertEquals("Receiver Operator",           file.getHeader().getRunByName());
635         Assertions.assertEquals("2020-06-09T00:00:00.0",       file.getHeader().getCreationDateComponents().toStringWithoutUtcOffset(60, 1));
636         Assertions.assertEquals("UTC",                         file.getHeader().getCreationTimeZone());
637         Assertions.assertEquals(IonosphericCorrectionType.QZS, file.getHeader().getIonosphericCorrectionType());
638         Assertions.assertEquals(0.5588e-08,                    file.getKlobucharAlpha()[0], Double.MIN_VALUE);
639         Assertions.assertEquals(0.7451e-08,                    file.getKlobucharAlpha()[1], Double.MIN_VALUE);
640         Assertions.assertEquals(-0.4768e-06,                   file.getKlobucharAlpha()[2], Double.MIN_VALUE);
641         Assertions.assertEquals(-0.1013e-05,                   file.getKlobucharAlpha()[3], Double.MIN_VALUE);
642         Assertions.assertEquals(0.8602e+05,                    file.getKlobucharBeta()[0],  Double.MIN_VALUE);
643         Assertions.assertEquals(-0.4096e+06,                   file.getKlobucharBeta()[1],  Double.MIN_VALUE);
644         Assertions.assertEquals(-0.8389e+07,                   file.getKlobucharBeta()[2],  Double.MIN_VALUE);
645         Assertions.assertEquals(-0.8389e+07,                   file.getKlobucharBeta()[3],  Double.MIN_VALUE);
646         Assertions.assertEquals("QZUT", file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionType());
647         Assertions.assertEquals(0.0,                           file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionA0(), Double.MIN_VALUE);
648         Assertions.assertEquals(0.0,                           file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionA1(), Double.MIN_VALUE);
649         GNSSDate date = new GNSSDate(file.getHeader().getTimeSystemCorrections().get(0).getReferenceDate(), SatelliteSystem.GPS);
650         Assertions.assertEquals(356352,                        date.getSecondsInWeek());
651         Assertions.assertEquals(2109,                          date.getWeekNumber());
652         Assertions.assertEquals(0,                             file.getComments().size());
653         Assertions.assertEquals(18,                            file.getHeader().getNumberOfLeapSeconds());
654 
655         // Verify data
656         checkFieldConversion(file);
657         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
658         Assertions.assertEquals(3, file.getQZSSLegacyNavigationMessages().size());
659         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
660         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
661         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
662         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
663         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
664         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
665         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
666         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
667 
668         final QZSSLegacyNavigationMessage qzs = file.getQZSSLegacyNavigationMessages("J07").get(0);
669         Assertions.assertEquals(0.0, qzs.getEpochToc().durationFrom(new AbsoluteDate(2020, 6, 9, 0, 0, 0, TimeScalesFactory.getQZSS())), Double.MIN_VALUE);
670         Assertions.assertEquals(-0.214204192162e-07, qzs.getAf0(), 1.0e-15);
671         Assertions.assertEquals(0.000000000000e+00,  qzs.getAf1(), 1.0e-15);
672         Assertions.assertEquals(0.000000000000e+00,  qzs.getAf2(), 1.0e-15);
673         Assertions.assertEquals(189,                 qzs.getIODE());
674         Assertions.assertEquals(-0.580312500000e+03, qzs.getCrs(), 1.0e-15);
675         Assertions.assertEquals(-0.104204506497e+01, qzs.getM0(), 1.0e-15);
676         Assertions.assertEquals(-0.190474092960e-04, qzs.getCuc(), 1.0e-15);
677         Assertions.assertEquals(0.140047399327e-03,  qzs.getE(), 1.0e-15);
678         Assertions.assertEquals(0.936537981033e-05,  qzs.getCus(), 1.0e-15);
679         Assertions.assertEquals(0.649355915070e+04,  FastMath.sqrt(qzs.getSma()), 1.0e-15);
680         Assertions.assertEquals(0.172800000000e+06,  qzs.getTime(), 1.0e-15);
681         Assertions.assertEquals(-0.241957604885e-05, qzs.getCic(), 1.0e-15);
682         Assertions.assertEquals(-0.102838327972e-01, qzs.getOmega0(), 1.0e-15);
683         Assertions.assertEquals(0.251457095146e-06,  qzs.getCis(), 1.0e-15);
684         Assertions.assertEquals(0.107314257498e-02,  qzs.getI0(), 1.0e-15);
685         Assertions.assertEquals(-0.291156250000e+03, qzs.getCrc(), 1.0e-15);
686         Assertions.assertEquals(-0.298090621453e+01, qzs.getPa(), 1.0e-15);
687         Assertions.assertEquals(0.116790579082e-08,  qzs.getOmegaDot(), 1.0e-15);
688         Assertions.assertEquals(0.000000000000e+00,  qzs.getIDot(), 1.0e-15);
689         Assertions.assertEquals(2109,                qzs.getWeek());
690         Assertions.assertEquals(0.280000000000e+01,  qzs.getSvAccuracy(), 1.0e-15);
691         Assertions.assertEquals(0.620000000000e+02,  qzs.getSvHealth(), 1.0e-15);
692         Assertions.assertEquals(-0.605359673500e-08, qzs.getTGD(), 1.0e-15);
693         Assertions.assertEquals(957,                 qzs.getIODC(), 1.0e-15);
694 
695         // check weeks reference in Rinex navigation are aligned with GPS weeks
696         final AbsoluteDate obsRebuiltDate = new GNSSDate(qzs.getWeek(), qzs.getTime(), SatelliteSystem.GPS).
697                                             getDate();
698         final double relativeTime = obsRebuiltDate.durationFrom(qzs.getEpochToc());
699         Assertions.assertEquals(0.0, relativeTime / Constants.JULIAN_DAY, 7.0);
700         Assertions.assertEquals(0.0, obsRebuiltDate.durationFrom(qzs.getDate()), 1.0e-15);
701 
702         // check the propagator
703         final Frames frames = DataContext.getDefault().getFrames();
704         final GNSSPropagator propagator = qzs.getPropagator(DataContext.getDefault().getFrames(), Propagator.getDefaultLaw(frames),
705                 FramesFactory.getEME2000(), FramesFactory.getITRF(IERSConventions.IERS_2010, true), Propagator.DEFAULT_MASS);
706         final AbsoluteDate date0 = qzs.getDate();
707         final Vector3D p0 = propagator.propagateInEcef(date0).getPosition();
708         final double gpsCycleDuration = qzs.getCycleDuration();
709         final AbsoluteDate date1 = date0.shiftedBy(gpsCycleDuration);
710         final Vector3D p1 = propagator.propagateInEcef(date1).getPosition();
711         Assertions.assertEquals(0., p0.distance(p1), 0.);
712 
713     }
714 
715     @Test
716     public void testQZSSRinex400() throws IOException {
717 
718         // Parse file
719         final String ex = "/gnss/navigation/Example_QZSS_Rinex400.n";
720         final RinexNavigation file = new RinexNavigationParser().
721                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
722 
723         // Verify Header
724         Assertions.assertEquals(4.00,                                 file.getHeader().getFormatVersion(), Double.MIN_VALUE);
725         Assertions.assertEquals(RinexFileType.NAVIGATION,             file.getHeader().getFileType());
726         Assertions.assertEquals(SatelliteSystem.MIXED,                file.getHeader().getSatelliteSystem());
727         Assertions.assertEquals("BCEmerge",                           file.getHeader().getProgramName());
728         Assertions.assertEquals("congo",                              file.getHeader().getRunByName());
729         Assertions.assertEquals("https://doi.org/10.57677/BRD400DLR", file.getHeader().getDoi());
730         Assertions.assertNull(file.getHeader().getLicense());
731         Assertions.assertNull(file.getHeader().getStationInformation());
732         Assertions.assertEquals(18,                                   file.getHeader().getNumberOfLeapSeconds());
733         Assertions.assertEquals(102,                                  file.getHeader().getMergedFiles());
734 
735         // Verify data
736         checkFieldConversion(file);
737         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
738         Assertions.assertEquals(1, file.getQZSSLegacyNavigationMessages().size());
739         Assertions.assertEquals(1, file.getQZSSCivilianNavigationMessages().size());
740         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
741         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
742         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
743         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
744         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
745         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
746         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
747 
748         final QZSSLegacyNavigationMessage qzssl = file.getQZSSLegacyNavigationMessages("J02").get(0);
749         Assertions.assertEquals(0.0, qzssl.getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 0, 0, 0, TimeScalesFactory.getQZSS())), Double.MIN_VALUE);
750         Assertions.assertEquals(0, qzssl.getSvHealth());
751         Assertions.assertEquals(0, qzssl.getFitInterval());
752 
753         final List<QZSSCivilianNavigationMessage> list = file.getQZSSCivilianNavigationMessages("J02");
754         Assertions.assertEquals(4, list.size());
755         Assertions.assertEquals(0.0, list.get(0).getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 0, 0, 0, TimeScalesFactory.getGPS())), Double.MIN_VALUE);
756         Assertions.assertEquals(-3, list.get(0).getUraiNed0());
757         Assertions.assertEquals( 0, list.get(0).getUraiNed1());
758         Assertions.assertEquals( 0, list.get(0).getUraiNed2());
759         Assertions.assertEquals(-8, list.get(0).getUraiEd());
760         Assertions.assertEquals( 0.000000000000e+00, list.get(0).getIscL1CA(), 1.0e-20);
761         Assertions.assertEquals(-3.783497959375e-10, list.get(0).getIscL2C(),  1.0e-20);
762         Assertions.assertEquals(1.600710675120e-09,  list.get(0).getIscL5I5(), 1.0e-20);
763         Assertions.assertEquals(1.688022166491e-09,  list.get(0).getIscL5Q5(), 1.0e-20);
764         Assertions.assertEquals(255606.0, list.get(0).getTransmissionTime(), 1.0e-10);
765         Assertions.assertEquals(2230, list.get(0).getWeek());
766         Assertions.assertEquals(0.0, list.get(1).getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 1, 0, 0, TimeScalesFactory.getGPS())), Double.MIN_VALUE);
767 
768     }
769 
770     @Test
771     public void testGLONASSRinex303() throws IOException {
772 
773         // Parse file
774         final String ex = "/gnss/navigation/Example_Glonass_Rinex303.n";
775         final RinexNavigation file = new RinexNavigationParser().
776                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
777 
778         // Verify Header
779         Assertions.assertEquals(3.03,                    file.getHeader().getFormatVersion(), Double.MIN_VALUE);
780         Assertions.assertEquals(RinexFileType.NAVIGATION,file.getHeader().getFileType());
781         Assertions.assertEquals(SatelliteSystem.GLONASS, file.getHeader().getSatelliteSystem());
782         Assertions.assertEquals("GR25 V4.30",            file.getHeader().getProgramName());
783         Assertions.assertEquals("Institute of Astrono",  file.getHeader().getRunByName());
784         Assertions.assertEquals("2021-02-17T23:59:47.0", file.getHeader().getCreationDateComponents().toStringWithoutUtcOffset(60, 1));
785         Assertions.assertEquals("UTC",                   file.getHeader().getCreationTimeZone());
786         Assertions.assertEquals("GLUT", file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionType());
787         Assertions.assertEquals(6.0535967350e-09,        file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionA0(), Double.MIN_VALUE);
788         Assertions.assertEquals(0.000000000e+00,         file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionA1(), Double.MIN_VALUE);
789         Assertions.assertNull(file.getHeader().getTimeSystemCorrections().get(0).getReferenceDate());
790         Assertions.assertEquals(0,                       file.getComments().size());
791         Assertions.assertEquals(18,                      file.getHeader().getNumberOfLeapSeconds());
792 
793         // Verify data
794         checkFieldConversion(file);
795         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
796         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
797         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
798         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
799         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
800         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
801         Assertions.assertEquals(3, file.getGlonassNavigationMessages().size());
802         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
803         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
804         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
805 
806         final GLONASSNavigationMessage glo = file.getGlonassNavigationMessages("R02").get(0);
807         Assertions.assertEquals(0.0, glo.getEpochToc().durationFrom(new AbsoluteDate(2021, 2, 17, 23, 45, 0.0, TimeScalesFactory.getUTC())), Double.MIN_VALUE);
808         Assertions.assertEquals(-4.674419760704e-04, glo.getTN(), 1.0e-10);
809         Assertions.assertEquals(9.094947017729e-13,  glo.getGammaN(), 1.0e-10);
810         Assertions.assertEquals(84600.0,             glo.getTime(), 1.0e-10);
811         Assertions.assertEquals(-1252.090332031e+04, glo.getX(), 1.0e-10);
812         Assertions.assertEquals(-2661.552429199e+00, glo.getXDot(), 1.0e-10);
813         Assertions.assertEquals(0.000000000000e+00,  glo.getXDotDot(), 1.0e-10);
814         Assertions.assertEquals(0.000000000000e+00,  glo.getHealth(), 1.0e-10);
815         Assertions.assertEquals(1045.030761719e+04,  glo.getY(), 1.0e-10);
816         Assertions.assertEquals(3342.580795288e-01,  glo.getYDot(), 1.0e-10);
817         Assertions.assertEquals(0.000000000000e+00,  glo.getYDotDot(), 1.0e-10);
818         Assertions.assertEquals(-4,                  glo.getFrequencyNumber());
819         Assertions.assertEquals(1963.127978516e+04,  glo.getZ(), 1.0e-10);
820         Assertions.assertEquals(-1884.816169739e+00, glo.getZDot(), 1.0e-10);
821         Assertions.assertEquals(-1862.645149231e-09, glo.getZDotDot(), 1.0e-10);
822 
823         // check the propagator
824         final GLONASSNumericalPropagator propagator1 = glo.getPropagator(60.0);
825         final GLONASSNumericalPropagator propagator2 = glo.getPropagator(60, DataContext.getDefault());
826         final GLONASSNumericalPropagator propagator3 = glo.getPropagator(60, DataContext.getDefault(),
827                 Propagator.getDefaultLaw(DataContext.getDefault().getFrames()),
828                 FramesFactory.getEME2000(), Propagator.DEFAULT_MASS);
829         Assertions.assertNotNull(propagator1);
830         Assertions.assertNotNull(propagator2);
831         Assertions.assertNotNull(propagator3);
832         
833     }
834 
835     @Test
836     public void testNavICRinex303() throws IOException {
837 
838         final String ex = "/gnss/navigation/Example_NavIC_Rinex303.n";
839         final RinexNavigation file = new RinexNavigationParser().
840                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
841 
842         // Verify Header
843         Assertions.assertEquals(3.03,                    file.getHeader().getFormatVersion(), Double.MIN_VALUE);
844         Assertions.assertEquals(RinexFileType.NAVIGATION,file.getHeader().getFileType());
845         Assertions.assertEquals(SatelliteSystem.NAVIC, file.getHeader().getSatelliteSystem());
846         Assertions.assertEquals("JPS2RIN v.2.0.168",     file.getHeader().getProgramName());
847         Assertions.assertEquals("JAVAD GNSS",            file.getHeader().getRunByName());
848         Assertions.assertEquals("2019-10-28T00:56:48.0", file.getHeader().getCreationDateComponents().toStringWithoutUtcOffset(60, 1));
849         Assertions.assertEquals("UTC",                   file.getHeader().getCreationTimeZone());
850         Assertions.assertEquals(18,                      file.getHeader().getNumberOfLeapSeconds());
851 
852         // Verify data
853         checkFieldConversion(file);
854         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
855         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
856         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
857         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
858         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
859         Assertions.assertEquals(3, file.getNavICLegacyNavigationMessages().size());
860         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
861         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
862         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
863         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
864 
865         final NavICLegacyNavigationMessage navic = file.getNavICLegacyNavigationMessages("I05").get(0);
866         Assertions.assertEquals(0.0, navic.getEpochToc().durationFrom(new AbsoluteDate(2019, 10, 27, 0, 0, 0, TimeScalesFactory.getNavIC())), Double.MIN_VALUE);
867         Assertions.assertEquals(4.232432693243e-04,  navic.getAf0(), 1.0e-15);
868         Assertions.assertEquals(2.000888343900e-11,  navic.getAf1(), 1.0e-15);
869         Assertions.assertEquals(0.000000000000e+00,  navic.getAf2(), 1.0e-15);
870         Assertions.assertEquals(0,                   navic.getIODC());
871         Assertions.assertEquals(4.608125000000e+02,  navic.getCrs(), 1.0e-15);
872         Assertions.assertEquals(-2.259193667639e+00, navic.getM0(), 1.0e-15);
873         Assertions.assertEquals(1.492351293564e-05,  navic.getCuc(), 1.0e-15);
874         Assertions.assertEquals(2.073186333291e-03,  navic.getE(), 1.0e-15);
875         Assertions.assertEquals(-2.183392643929e-05, navic.getCus(), 1.0e-15);
876         Assertions.assertEquals(6.493289260864e+03,  FastMath.sqrt(navic.getSma()), 1.0e-15);
877         Assertions.assertEquals(0.000000000000e+00,  navic.getTime(), 1.0e-15);
878         Assertions.assertEquals(-2.868473529816e-07, navic.getCic(), 1.0e-15);
879         Assertions.assertEquals(1.135843714918e+00,  navic.getOmega0(), 1.0e-15);
880         Assertions.assertEquals(-5.215406417847e-08, navic.getCis(), 1.0e-15);
881         Assertions.assertEquals(5.007869522210e-01,  navic.getI0(), 1.0e-15);
882         Assertions.assertEquals(7.530000000000e+02,  navic.getCrc(), 1.0e-15);
883         Assertions.assertEquals(3.073412769875e+00,  navic.getPa(), 1.0e-15);
884         Assertions.assertEquals(-5.227360597694e-09, navic.getOmegaDot(), 1.0e-15);
885         Assertions.assertEquals(4.421612749348e-10,  navic.getIDot(), 1.0e-15);
886         Assertions.assertEquals(2077,                navic.getWeek());
887         Assertions.assertEquals(4.85,                navic.getSvAccuracy(), 1.0e-15);
888         Assertions.assertEquals(0.000000000000e+00,  navic.getSvHealth(), 1.0e-15);
889         Assertions.assertEquals(-4.656613000000e-10, navic.getTGD(), 1.0e-15);
890 
891         // check weeks reference in Rinex navigation are aligned with GPS weeks
892         final AbsoluteDate obsRebuiltDate = new GNSSDate(navic.getWeek(), navic.getTime(), SatelliteSystem.GPS).
893                                             getDate();
894         final double relativeTime = obsRebuiltDate.durationFrom(navic.getEpochToc());
895         Assertions.assertEquals(0.0, relativeTime / Constants.JULIAN_DAY, 7.0);
896         Assertions.assertEquals(0.0, obsRebuiltDate.durationFrom(navic.getDate()), 1.0e-15);
897 
898         // check the propagator
899         final GNSSPropagator propagator = navic.getPropagator();
900         final AbsoluteDate date0 = navic.getDate();
901         final Vector3D p0 = propagator.propagateInEcef(date0).getPosition();
902         final double gpsCycleDuration = navic.getCycleDuration();
903         final AbsoluteDate date1 = date0.shiftedBy(gpsCycleDuration);
904         final Vector3D p1 = propagator.propagateInEcef(date1).getPosition();
905         Assertions.assertEquals(0., p0.distance(p1), 0.);
906 
907     }
908 
909     @Test
910     public void testNavICRinex400() throws IOException {
911 
912         // Parse file
913         final String ex = "/gnss/navigation/Example_NavIC_Rinex400.n";
914         final RinexNavigation file = new RinexNavigationParser().
915                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
916 
917         // Verify Header
918         Assertions.assertEquals(4.00,                                 file.getHeader().getFormatVersion(), Double.MIN_VALUE);
919         Assertions.assertEquals(RinexFileType.NAVIGATION,             file.getHeader().getFileType());
920         Assertions.assertEquals(SatelliteSystem.MIXED,                file.getHeader().getSatelliteSystem());
921         Assertions.assertEquals("BCEmerge",                           file.getHeader().getProgramName());
922         Assertions.assertEquals("congo",                              file.getHeader().getRunByName());
923         Assertions.assertEquals("https://doi.org/10.57677/BRD400DLR", file.getHeader().getDoi());
924         Assertions.assertNull(file.getHeader().getLicense());
925         Assertions.assertNull(file.getHeader().getStationInformation());
926         Assertions.assertEquals(18,                                   file.getHeader().getNumberOfLeapSeconds());
927         Assertions.assertEquals(102,                                  file.getHeader().getMergedFiles());
928 
929         // Verify data
930         checkFieldConversion(file);
931         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
932         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
933         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
934         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
935         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
936         Assertions.assertEquals(1, file.getNavICLegacyNavigationMessages().size());
937         Assertions.assertEquals(0, file.getNavICL1NVNavigationMessages().size());
938         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
939         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
940         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
941         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
942 
943         final NavICLegacyNavigationMessage navICL = file.getNavICLegacyNavigationMessages().get("I02").get(0);
944         Assertions.assertEquals(0.0, navICL.getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 0, 5, 36, TimeScalesFactory.getNavIC())), Double.MIN_VALUE);
945     }
946 
947     @Test
948     public void testNavICRinex402() throws IOException {
949 
950         // Parse file
951         final String ex = "/gnss/navigation/Example_NavIC_Rinex402.n";
952         final RinexNavigation file = new RinexNavigationParser().
953                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
954 
955         // Verify Header
956         Assertions.assertEquals(4.02,                                 file.getHeader().getFormatVersion(), Double.MIN_VALUE);
957         Assertions.assertEquals(RinexFileType.NAVIGATION,             file.getHeader().getFileType());
958         Assertions.assertEquals(SatelliteSystem.MIXED,                file.getHeader().getSatelliteSystem());
959         Assertions.assertEquals("editor",                             file.getHeader().getProgramName());
960         Assertions.assertEquals("developer",                          file.getHeader().getRunByName());
961         Assertions.assertNull(file.getHeader().getDoi());
962         Assertions.assertNull(file.getHeader().getLicense());
963         Assertions.assertNull(file.getHeader().getStationInformation());
964 
965         // Verify data
966         checkFieldConversion(file);
967         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
968         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
969         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
970         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
971         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
972         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
973         Assertions.assertEquals(1, file.getNavICL1NVNavigationMessages().size());
974         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
975         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
976         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
977         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
978 
979         final NavICL1NVNavigationMessage navICL1 = file.getNavICL1NVNavigationMessages("I10").get(0);
980         Assertions.assertEquals(0.0,
981                                 navICL1.getEpochToc().durationFrom(new AbsoluteDate(2023, 6, 24, 0, 5, 0,
982                                                                                     TimeScalesFactory.getNavIC())),
983                                 Double.MIN_VALUE);
984         Assertions.assertEquals( 0.000000000000e+00, navICL1.getADot(),       1.0e-15);
985         Assertions.assertEquals(-2.593125000000e+02, navICL1.getCrs(),        1.0e-10);
986         Assertions.assertEquals( 7.028864208979e-09, navICL1.getDeltaN0(),    1.0e-21);
987         Assertions.assertEquals( 2.300305834983e+00, navICL1.getM0(),         1.0e-12);
988         Assertions.assertEquals(-8.691102266312e-06, navICL1.getCuc(),        1.0e-18);
989         Assertions.assertEquals( 4.531537415460e-04, navICL1.getE(),          1.0e-16);
990         Assertions.assertEquals(-3.855675458908e-06, navICL1.getCus(),        1.0e-18);
991         Assertions.assertEquals( 6.493495117188e+03, navICL1.getSqrtA(),      1.0e-15);
992         Assertions.assertEquals( 7.000000000000e+00, navICL1.getTime(),       1.0e-15);
993         Assertions.assertEquals( 1.341104507446e-07, navICL1.getCic(),        1.0e-19);
994         Assertions.assertEquals( 1.359342162629e-01, navICL1.getOmega0(),     1.0e-13);
995         Assertions.assertEquals(-7.078051567078e-08, navICL1.getCis(),        1.0e-20);
996         Assertions.assertEquals( 8.594830530333e-02, navICL1.getI0(),         1.0e-14);
997         Assertions.assertEquals( 1.214375000000e+02, navICL1.getCrc(),        1.0e-10);
998         Assertions.assertEquals(-5.136403830694e-02, navICL1.getPa(),         1.0e-14);
999         Assertions.assertEquals(-5.858815471753e-09, navICL1.getOmegaDot(),   1.0e-21);
1000         Assertions.assertEquals(-4.846630453041e-10, navICL1.getIDot(),       1.0e-22);
1001         Assertions.assertEquals( 0.000000000000e+00, navICL1.getDeltaN0Dot(), 1.0e-15);
1002         Assertions.assertEquals( 1,                  navICL1.getReferenceSignalFlag());
1003         Assertions.assertEquals(0, navICL1.getSvHealth());
1004         Assertions.assertTrue(Double.isNaN(navICL1.getSvAccuracy()));
1005 
1006         // as reference signal flag is set to 1, ISC S are *not* broadcast
1007         Assertions.assertTrue(Double.isNaN(navICL1.getTGD()));
1008         Assertions.assertTrue(Double.isNaN(navICL1.getIscSL1P()));
1009         Assertions.assertTrue(Double.isNaN(navICL1.getIscL1DL1P()));
1010 
1011         // as reference signal flag is set to 1, ISC L1P are broadcast*
1012         Assertions.assertEquals(-3.608874976635e-09, navICL1.getTGDSL5(),  1.0e-21);
1013         Assertions.assertEquals( 6.984919309616e-09, navICL1.getIscL1PS(), 1.0e-21);
1014         Assertions.assertEquals( 5.995389074087e-09, navICL1.getIscL1DS(), 1.0e-21);
1015 
1016         Assertions.assertEquals( 5.191380000000e+05, navICL1.getTransmissionTime(), 1.0e-07);
1017 
1018     }
1019 
1020     @Test
1021     public void testMixedRinex304() throws IOException {
1022 
1023         // Parse file
1024         final String ex = "/gnss/navigation/Example_Mixed_Rinex304.n";
1025         final RinexNavigation file = new RinexNavigationParser().
1026                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
1027 
1028         // Verify Header
1029         Assertions.assertEquals(3.04,                    file.getHeader().getFormatVersion(), Double.MIN_VALUE);
1030         Assertions.assertEquals(RinexFileType.NAVIGATION,file.getHeader().getFileType());
1031         Assertions.assertEquals(SatelliteSystem.MIXED,   file.getHeader().getSatelliteSystem());
1032         Assertions.assertEquals("Alloy 5.37",            file.getHeader().getProgramName());
1033         Assertions.assertEquals("Receiver Operator",     file.getHeader().getRunByName());
1034         Assertions.assertEquals("2020-02-11T00:00:00.0", file.getHeader().getCreationDateComponents().toStringWithoutUtcOffset(60, 1));
1035         Assertions.assertEquals("UTC",                   file.getHeader().getCreationTimeZone());
1036         Assertions.assertEquals(0.8382E-08,              file.getKlobucharAlpha()[0], Double.MIN_VALUE);
1037         Assertions.assertEquals(-0.7451E-08,             file.getKlobucharAlpha()[1], Double.MIN_VALUE);
1038         Assertions.assertEquals(-0.5960E-07,             file.getKlobucharAlpha()[2], Double.MIN_VALUE);
1039         Assertions.assertEquals(0.5960E-07,              file.getKlobucharAlpha()[3], Double.MIN_VALUE);
1040         Assertions.assertEquals(0.8806E+05,              file.getKlobucharBeta()[0],  Double.MIN_VALUE);
1041         Assertions.assertEquals(-0.1638E+05,             file.getKlobucharBeta()[1],  Double.MIN_VALUE);
1042         Assertions.assertEquals(-0.1966E+06,             file.getKlobucharBeta()[2],  Double.MIN_VALUE);
1043         Assertions.assertEquals(0.6554E+05,              file.getKlobucharBeta()[3],  Double.MIN_VALUE);
1044         Assertions.assertEquals(0.4200E+02,              file.getNeQuickAlpha()[0], Double.MIN_VALUE);
1045         Assertions.assertEquals(0.1563E-01,              file.getNeQuickAlpha()[1], Double.MIN_VALUE);
1046         Assertions.assertEquals(0.2045E-02,              file.getNeQuickAlpha()[2], Double.MIN_VALUE);
1047         Assertions.assertEquals(0.0000E+00,              file.getNeQuickAlpha()[3], Double.MIN_VALUE);
1048         Assertions.assertEquals("GPUT", file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionType());
1049         Assertions.assertEquals("GAUT", file.getHeader().getTimeSystemCorrections().get(1).getTimeSystemCorrectionType());
1050         Assertions.assertEquals("GPGA", file.getHeader().getTimeSystemCorrections().get(2).getTimeSystemCorrectionType());
1051         Assertions.assertEquals(18,                      file.getHeader().getNumberOfLeapSeconds());
1052 
1053         // Verify data
1054         checkFieldConversion(file);
1055         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
1056         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
1057         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
1058         Assertions.assertEquals(2, file.getBeidouLegacyNavigationMessages().size());
1059         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
1060         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
1061         Assertions.assertEquals(1, file.getGlonassNavigationMessages().size());
1062         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
1063         Assertions.assertEquals(2, file.getGPSLegacyNavigationMessages().size());
1064         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
1065 
1066         final GLONASSNavigationMessage glo = file.getGlonassNavigationMessages("R05").get(0);
1067         Assertions.assertEquals(0.0, glo.getEpochToc().durationFrom(new AbsoluteDate(2020, 2, 10, 23, 45, 0.0, TimeScalesFactory.getUTC())), Double.MIN_VALUE);
1068         Assertions.assertEquals(-0.447863712907e-04, glo.getTN(), 1.0e-10);
1069         Assertions.assertEquals(0.909494701773e-12,  glo.getGammaN(), 1.0e-10);
1070         Assertions.assertEquals(86370.0,             glo.getTime(), 1.0e-10);
1071         Assertions.assertEquals(0182.817373047e+05,  glo.getX(), 1.0e-10);
1072         Assertions.assertEquals(-176.770305634e+01,  glo.getXDot(), 1.0e-10);
1073         Assertions.assertEquals(651.925802231e-08,   glo.getXDotDot(), 1.0e-10);
1074         Assertions.assertEquals(0.000000000000e+00,  glo.getHealth(), 1.0e-10);
1075         Assertions.assertEquals(0114.389570312e+05,  glo.getY(), 1.0e-10);
1076         Assertions.assertEquals(-619.493484497e+00,  glo.getYDot(), 1.0e-10);
1077         Assertions.assertEquals(279.396772385e-08,   glo.getYDotDot(), 1.0e-10);
1078         Assertions.assertEquals(1,                   glo.getFrequencyNumber());
1079         Assertions.assertEquals(136.489028320e+05,   glo.getZ(), 1.0e-10);
1080         Assertions.assertEquals(288.632869720e+01,   glo.getZDot(), 1.0e-10);
1081         Assertions.assertEquals(0.000000000000e+00,  glo.getZDotDot(), 1.0e-10);
1082 
1083     }
1084 
1085     @Test
1086     public void testMixedRinex305() throws IOException {
1087 
1088         // Parse file
1089         final String ex = "/gnss/navigation/Example_Mixed_Rinex305.n";
1090         final RinexNavigation file = new RinexNavigationParser().
1091                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
1092 
1093         // Verify Header
1094         Assertions.assertEquals(3.05,                    file.getHeader().getFormatVersion(), Double.MIN_VALUE);
1095         Assertions.assertEquals(RinexFileType.NAVIGATION,file.getHeader().getFileType());
1096         Assertions.assertEquals(SatelliteSystem.MIXED,   file.getHeader().getSatelliteSystem());
1097         Assertions.assertEquals("XXRINEXN V3",           file.getHeader().getProgramName());
1098         Assertions.assertEquals("AIUB",                  file.getHeader().getRunByName());
1099         Assertions.assertEquals("2006-10-02T00:01:23.0", file.getHeader().getCreationDateComponents().toStringWithoutUtcOffset(60, 1));
1100         Assertions.assertEquals("UTC",                   file.getHeader().getCreationTimeZone());
1101         Assertions.assertEquals(0.1025E-07,              file.getKlobucharAlpha()[0], Double.MIN_VALUE);
1102         Assertions.assertEquals(0.7451E-08,              file.getKlobucharAlpha()[1], Double.MIN_VALUE);
1103         Assertions.assertEquals(-0.5960E-07,             file.getKlobucharAlpha()[2], Double.MIN_VALUE);
1104         Assertions.assertEquals(-0.5960E-07,             file.getKlobucharAlpha()[3], Double.MIN_VALUE);
1105         Assertions.assertEquals(0.8806E+05,              file.getKlobucharBeta()[0],  Double.MIN_VALUE);
1106         Assertions.assertEquals(0.0000E+00,              file.getKlobucharBeta()[1],  Double.MIN_VALUE);
1107         Assertions.assertEquals(-0.1966E+06,             file.getKlobucharBeta()[2],  Double.MIN_VALUE);
1108         Assertions.assertEquals(-0.6554E+05,             file.getKlobucharBeta()[3],  Double.MIN_VALUE);
1109         Assertions.assertEquals("GPUT", file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionType());
1110         Assertions.assertEquals("GLUT", file.getHeader().getTimeSystemCorrections().get(1).getTimeSystemCorrectionType());
1111         Assertions.assertEquals(14,                      file.getHeader().getNumberOfLeapSeconds());
1112 
1113         // Verify data
1114         checkFieldConversion(file);
1115         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
1116         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
1117         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
1118         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
1119         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
1120         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
1121         Assertions.assertEquals(2, file.getGlonassNavigationMessages().size());
1122         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
1123         Assertions.assertEquals(2, file.getGPSLegacyNavigationMessages().size());
1124         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
1125 
1126         final GLONASSNavigationMessage glo = file.getGlonassNavigationMessages("R01").get(0);
1127         Assertions.assertEquals(0.0, glo.getEpochToc().durationFrom(new AbsoluteDate(2006, 10, 1, 0, 15, 0.0, TimeScalesFactory.getUTC())), Double.MIN_VALUE);
1128         Assertions.assertEquals( 0.137668102980E-04,  glo.getTN(),      1.0e-10);
1129         Assertions.assertEquals(-0.454747350886E-11,  glo.getGammaN(),  1.0e-10);
1130         Assertions.assertEquals(90.0,                 glo.getTime(),    1.0e-10);
1131         Assertions.assertEquals(0.157594921875E+08,   glo.getX(),       1.0e-6);
1132         Assertions.assertEquals(-0.145566368103E+04,  glo.getXDot(),    1.0e-9);
1133         Assertions.assertEquals(0.000000000000E+00,   glo.getXDotDot(), 1.0e-12);
1134         Assertions.assertEquals(0.000000000000e+00,   glo.getHealth(),  1.0e-10);
1135         Assertions.assertEquals(-0.813711474609E+07,  glo.getY(),       1.0e-6);
1136         Assertions.assertEquals(0.205006790161E+04,   glo.getYDot(),    1.0e-9);
1137         Assertions.assertEquals(0.931322574615E-06,   glo.getYDotDot(), 1.0e-12);
1138         Assertions.assertEquals(7,                    glo.getFrequencyNumber());
1139         Assertions.assertEquals(0.183413398438E+08,   glo.getZ(),       1.0e-6);
1140         Assertions.assertEquals(0.215388488770E+04,   glo.getZDot(),    1.0e-9);
1141         Assertions.assertEquals(-0.186264514923E-05,  glo.getZDotDot(), 1.0e-12);
1142         Assertions.assertEquals(179,  glo.getStatusFlags());
1143         Assertions.assertEquals(8.381903171539E-09,  glo.getGroupDelayDifference(), 1.0e-15);
1144         Assertions.assertEquals(2.0,  glo.getURA(), 1.0e-10);
1145         Assertions.assertEquals(3,  glo.getHealthFlags());
1146 
1147     }
1148 
1149     @Test
1150     public void testQZSSRinex304() throws IOException {
1151 
1152         final String ex = "/gnss/navigation/Example_QZSS_Rinex304.n";
1153         final RinexNavigation file = new RinexNavigationParser().
1154                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
1155 
1156         // Verify Header
1157         Assertions.assertEquals(3.04,                    file.getHeader().getFormatVersion(), Double.MIN_VALUE);
1158         Assertions.assertEquals(RinexFileType.NAVIGATION,file.getHeader().getFileType());
1159         Assertions.assertEquals(SatelliteSystem.QZSS,    file.getHeader().getSatelliteSystem());
1160         Assertions.assertEquals("JPS2RIN v.2.0.191",     file.getHeader().getProgramName());
1161         Assertions.assertEquals("JAVAD GNSS",            file.getHeader().getRunByName());
1162         Assertions.assertEquals("2020-06-10T00:32:46.0", file.getHeader().getCreationDateComponents().toStringWithoutUtcOffset(60, 1));
1163         Assertions.assertEquals("UTC",                   file.getHeader().getCreationTimeZone());
1164         Assertions.assertEquals(18,                      file.getHeader().getNumberOfLeapSeconds());
1165 
1166         // Verify data
1167         checkFieldConversion(file);
1168         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
1169         Assertions.assertEquals(3, file.getQZSSLegacyNavigationMessages().size());
1170         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
1171         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
1172         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
1173         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
1174         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
1175         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
1176         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
1177         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
1178 
1179         final QZSSLegacyNavigationMessage qzs = file.getQZSSLegacyNavigationMessages("J03").get(0);
1180         Assertions.assertEquals(0.0, qzs.getEpochToc().durationFrom(new AbsoluteDate(2020, 6, 9, 1, 0, 0, TimeScalesFactory.getQZSS())), Double.MIN_VALUE);
1181         Assertions.assertEquals(-3.880355507135e-06, qzs.getAf0(), 1.0e-15);
1182         Assertions.assertEquals(-4.547473508865e-13, qzs.getAf1(), 1.0e-15);
1183         Assertions.assertEquals(0.000000000000e+00,  qzs.getAf2(), 1.0e-15);
1184         Assertions.assertEquals(193,                 qzs.getIODE());
1185         Assertions.assertEquals(3.106250000000e+02,  qzs.getCrs(), 1.0e-15);
1186         Assertions.assertEquals(2.226495657955e+00,  qzs.getM0(), 1.0e-15);
1187         Assertions.assertEquals(7.346272468567e-06,  qzs.getCuc(), 1.0e-15);
1188         Assertions.assertEquals(7.470769551583e-02,  qzs.getE(), 1.0e-15);
1189         Assertions.assertEquals(-2.568960189819e-05, qzs.getCus(), 1.0e-15);
1190         Assertions.assertEquals(6.493781688690e+03,  FastMath.sqrt(qzs.getSma()), 1.0e-15);
1191         Assertions.assertEquals(1.764000000000e+05,  qzs.getTime(), 1.0e-15);
1192         Assertions.assertEquals(-1.853331923485e-06, qzs.getCic(), 1.0e-15);
1193         Assertions.assertEquals(2.023599801546e+00,  qzs.getOmega0(), 1.0e-15);
1194         Assertions.assertEquals(1.644715666771e-06,  qzs.getCis(), 1.0e-15);
1195         Assertions.assertEquals(7.122509413449e-01,  qzs.getI0(), 1.0e-15);
1196         Assertions.assertEquals(9.670937500000e+02,  qzs.getCrc(), 1.0e-15);
1197         Assertions.assertEquals(-1.550179221884e+00, qzs.getPa(), 1.0e-15);
1198         Assertions.assertEquals(-1.478633019572e-09, qzs.getOmegaDot(), 1.0e-15);
1199         Assertions.assertEquals(-7.193156766709e-10, qzs.getIDot(), 1.0e-15);
1200         Assertions.assertEquals(2109,                qzs.getWeek());
1201         Assertions.assertEquals(2.000000000000e+00,  qzs.getSvAccuracy(), 1.0e-15);
1202         Assertions.assertEquals(0.000000000000e+00,  qzs.getSvHealth(), 1.0e-15);
1203         Assertions.assertEquals(0.000000000000e+00,  qzs.getTGD(), 1.0e-15);
1204         Assertions.assertEquals(961,                 qzs.getIODC(), 1.0e-15);
1205 
1206         // check weeks reference in Rinex navigation are aligned with GPS weeks
1207         final AbsoluteDate obsRebuiltDate = new GNSSDate(qzs.getWeek(), qzs.getTime(), SatelliteSystem.GPS).
1208                                             getDate();
1209         final double relativeTime = obsRebuiltDate.durationFrom(qzs.getEpochToc());
1210         Assertions.assertEquals(0.0, relativeTime / Constants.JULIAN_DAY, 7.0);
1211         Assertions.assertEquals(0.0, obsRebuiltDate.durationFrom(qzs.getDate()), 1.0e-15);
1212 
1213         // check the propagator
1214         final GNSSPropagator propagator = qzs.getPropagator(DataContext.getDefault().getFrames());
1215         final AbsoluteDate date0 = qzs.getDate();
1216         final Vector3D p0 = propagator.propagateInEcef(date0).getPosition();
1217         final double gpsCycleDuration = qzs.getCycleDuration();
1218         final AbsoluteDate date1 = date0.shiftedBy(gpsCycleDuration);
1219         final Vector3D p1 = propagator.propagateInEcef(date1).getPosition();
1220         Assertions.assertEquals(0., p0.distance(p1), 0.);
1221 
1222     }
1223 
1224     @Test
1225     public void testGpsRinex304() throws IOException {
1226 
1227         // Parse file
1228         final String ex = "/gnss/navigation/Example_GPS_Rinex304.n";
1229         final RinexNavigation file = new RinexNavigationParser().
1230                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
1231 
1232         // Verify Header
1233         Assertions.assertEquals(3.04,                          file.getHeader().getFormatVersion(), Double.MIN_VALUE);
1234         Assertions.assertEquals(RinexFileType.NAVIGATION,      file.getHeader().getFileType());
1235         Assertions.assertEquals(SatelliteSystem.GPS,           file.getHeader().getSatelliteSystem());
1236         Assertions.assertEquals("sbf2rin-13.8.0",              file.getHeader().getProgramName());
1237         Assertions.assertEquals("",                            file.getHeader().getRunByName());
1238         Assertions.assertEquals("2021-03-07T00:08:19.0",       file.getHeader().getCreationDateComponents().toStringWithoutUtcOffset(60, 1));
1239         Assertions.assertEquals("UTC",                         file.getHeader().getCreationTimeZone());
1240         Assertions.assertEquals(0.0,                           file.getHeader().getCreationDate().durationFrom(new AbsoluteDate(2021, 3, 7, 0, 8, 19.0, TimeScalesFactory.getUTC())), 0.0);
1241         Assertions.assertEquals(IonosphericCorrectionType.GPS, file.getHeader().getIonosphericCorrectionType());
1242         Assertions.assertEquals(1.0245E-08,                    file.getKlobucharAlpha()[0], Double.MIN_VALUE);
1243         Assertions.assertEquals(0.0000E+00,                    file.getKlobucharAlpha()[1], Double.MIN_VALUE);
1244         Assertions.assertEquals(-5.9605E-08,                   file.getKlobucharAlpha()[2], Double.MIN_VALUE);
1245         Assertions.assertEquals(0.0000E+00,                    file.getKlobucharAlpha()[3], Double.MIN_VALUE);
1246         Assertions.assertEquals(9.0112E+04,                    file.getKlobucharBeta()[0],  Double.MIN_VALUE);
1247         Assertions.assertEquals(0.0000E+00,                    file.getKlobucharBeta()[1],  Double.MIN_VALUE);
1248         Assertions.assertEquals(-1.9661E+05,                   file.getKlobucharBeta()[2],  Double.MIN_VALUE);
1249         Assertions.assertEquals(0.0000E+00,                    file.getKlobucharBeta()[3],  Double.MIN_VALUE);
1250         Assertions.assertEquals("GPUT",                        file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionType());
1251         Assertions.assertEquals(0.0000000000E+00,              file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionA0(), Double.MIN_VALUE);
1252         Assertions.assertEquals(9.769962617E-15,               file.getHeader().getTimeSystemCorrections().get(0).getTimeSystemCorrectionA1(), Double.MIN_VALUE);
1253         GNSSDate date = new GNSSDate(file.getHeader().getTimeSystemCorrections().get(0).getReferenceDate(), SatelliteSystem.GPS);
1254         Assertions.assertEquals(233472,                        date.getSecondsInWeek());
1255         Assertions.assertEquals(2148,                          date.getWeekNumber());
1256         Assertions.assertEquals(18,                            file.getHeader().getNumberOfLeapSeconds());
1257 
1258         // Verify data
1259         checkFieldConversion(file);
1260         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
1261         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
1262         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
1263         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
1264         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
1265         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
1266         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
1267         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
1268         Assertions.assertEquals(3, file.getGPSLegacyNavigationMessages().size());
1269         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
1270 
1271         final GPSLegacyNavigationMessage gps = file.getGPSLegacyNavigationMessages("G01").get(0);
1272         Assertions.assertEquals(0.0, gps.getEpochToc().durationFrom(new AbsoluteDate(2021, 3, 5, 23, 59, 44, TimeScalesFactory.getGPS())), Double.MIN_VALUE);
1273         Assertions.assertEquals(7.477793842554E-04,  gps.getAf0(), 1.0e-15);
1274         Assertions.assertEquals(-8.412825991400E-12, gps.getAf1(), 1.0e-15);
1275         Assertions.assertEquals(0.000000000000e+00,  gps.getAf2(), 1.0e-15);
1276         Assertions.assertEquals(9,                   gps.getIODE());
1277         Assertions.assertEquals(-7.434375000000E+01, gps.getCrs(), 1.0e-15);
1278         Assertions.assertEquals(1.258707807055E+00,  gps.getM0(), 1.0e-15);
1279         Assertions.assertEquals(-3.753229975700E-06, gps.getCuc(), 1.0e-15);
1280         Assertions.assertEquals(1.047585485503E-02,  gps.getE(), 1.0e-15);
1281         Assertions.assertEquals(7.394701242447E-06,  gps.getCus(), 1.0e-15);
1282         Assertions.assertEquals(5.153690633774E+03,  FastMath.sqrt(gps.getSma()), 1.0e-15);
1283         Assertions.assertEquals(5.183840000000E+05,  gps.getTime(), 1.0e-15);
1284         Assertions.assertEquals(-1.359730958939E-07, gps.getCic(), 1.0e-15);
1285         Assertions.assertEquals(-1.936900950511E+00, gps.getOmega0(), 1.0e-15);
1286         Assertions.assertEquals(1.136213541031E-07,  gps.getCis(), 1.0e-15);
1287         Assertions.assertEquals(9.833041013284E-01,  gps.getI0(), 1.0e-15);
1288         Assertions.assertEquals(2.525937500000E+02,  gps.getCrc(), 1.0e-15);
1289         Assertions.assertEquals(8.208058952773E-01,  gps.getPa(), 1.0e-15);
1290         Assertions.assertEquals(-8.015691028563E-09, gps.getOmegaDot(), 1.0e-15);
1291         Assertions.assertEquals(-1.053615315878E-10, gps.getIDot(), 1.0e-15);
1292         Assertions.assertEquals(2147,                gps.getWeek());
1293         Assertions.assertEquals(2.000000000000E+00,  gps.getSvAccuracy(), 1.0e-15);
1294         Assertions.assertEquals(0,                   gps.getSvHealth());
1295         Assertions.assertEquals(4.656612873077E-09,  gps.getTGD(), 1.0e-15);
1296         Assertions.assertEquals(9,                   gps.getIODC());
1297 
1298         // check weeks reference in Rinex navigation are aligned with GPS weeks
1299         final AbsoluteDate obsRebuiltDate = new GNSSDate(gps.getWeek(), gps.getTime(), SatelliteSystem.GPS).
1300                                             getDate();
1301         final double relativeTime = obsRebuiltDate.durationFrom(gps.getEpochToc());
1302         Assertions.assertEquals(0.0, relativeTime / Constants.JULIAN_DAY, 7.0);
1303         Assertions.assertEquals(0.0, obsRebuiltDate.durationFrom(gps.getDate()), 1.0e-15);
1304 
1305         // check the propagator
1306         final Frames frames = DataContext.getDefault().getFrames();
1307         final GNSSPropagator propagator = gps.getPropagator(DataContext.getDefault().getFrames(), Propagator.getDefaultLaw(frames),
1308                 FramesFactory.getEME2000(), FramesFactory.getITRF(IERSConventions.IERS_2010, true), Propagator.DEFAULT_MASS);
1309         final AbsoluteDate date0 = gps.getDate();
1310         final Vector3D p0 = propagator.propagateInEcef(date0).getPosition();
1311         final double gpsCycleDuration = gps.getCycleDuration();
1312         final AbsoluteDate date1 = date0.shiftedBy(gpsCycleDuration);
1313         final Vector3D p1 = propagator.propagateInEcef(date1).getPosition();
1314         Assertions.assertEquals(0., p0.distance(p1), 0.);
1315 
1316     }
1317 
1318     @Test
1319     public void testGalileoRinex304() throws IOException {
1320 
1321         // Parse file
1322         final String ex = "/gnss/navigation/Example_Galileo_Rinex304.n";
1323         final RinexNavigation file = new RinexNavigationParser().
1324                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
1325 
1326         // Verify Header
1327         Assertions.assertEquals(3.04,                          file.getHeader().getFormatVersion(), Double.MIN_VALUE);
1328         Assertions.assertEquals(RinexFileType.NAVIGATION,      file.getHeader().getFileType());
1329         Assertions.assertEquals(SatelliteSystem.GALILEO,       file.getHeader().getSatelliteSystem());
1330         Assertions.assertEquals("JPS2RIN v.2.0.191",           file.getHeader().getProgramName());
1331         Assertions.assertEquals("JAVAD GNSS",                  file.getHeader().getRunByName());
1332         Assertions.assertEquals("2021-03-07T00:02:45.0",       file.getHeader().getCreationDateComponents().toStringWithoutUtcOffset(60, 1));
1333         Assertions.assertEquals("UTC",                         file.getHeader().getCreationTimeZone());
1334         Assertions.assertEquals(IonosphericCorrectionType.GAL, file.getHeader().getIonosphericCorrectionType());
1335         Assertions.assertEquals(5.0500E+01,                    file.getNeQuickAlpha()[0], Double.MIN_VALUE);
1336         Assertions.assertEquals(2.7344E-02,                    file.getNeQuickAlpha()[1], Double.MIN_VALUE);
1337         Assertions.assertEquals(-1.5869E-03,                   file.getNeQuickAlpha()[2], Double.MIN_VALUE);
1338         Assertions.assertEquals(0.0000E+00,                    file.getNeQuickAlpha()[3], Double.MIN_VALUE);
1339         Assertions.assertEquals(18,                            file.getHeader().getNumberOfLeapSeconds());
1340 
1341         // Verify data
1342         checkFieldConversion(file);
1343         Assertions.assertEquals(1, file.getGalileoNavigationMessages().size());
1344         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
1345         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
1346         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
1347         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
1348         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
1349         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
1350         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
1351         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
1352         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
1353 
1354         final GalileoNavigationMessage gal = file.getGalileoNavigationMessages("E13").get(1);
1355         Assertions.assertEquals(0.0, gal.getEpochToc().durationFrom(new AbsoluteDate(2021, 3, 5, 22, 30, 0, TimeScalesFactory.getGST())), Double.MIN_VALUE);
1356         Assertions.assertEquals(4.131024470553e-04,  gal.getAf0(), 1.0e-15);
1357         Assertions.assertEquals(5.400124791777e-13,  gal.getAf1(), 1.0e-15);
1358         Assertions.assertEquals(0.000000000000e+00,  gal.getAf2(), 1.0e-15);
1359         Assertions.assertEquals(87,                  gal.getIODNav());
1360         Assertions.assertEquals(-1.010000000000e+02, gal.getCrs(), 1.0e-15);
1361         Assertions.assertEquals(1.781709410229e+00,  gal.getM0(), 1.0e-15);
1362         Assertions.assertEquals(-4.542991518974e-06, gal.getCuc(), 1.0e-15);
1363         Assertions.assertEquals(3.459260333329e-04,  gal.getE(), 1.0e-15);
1364         Assertions.assertEquals(5.345791578293e-06,  gal.getCus(), 1.0e-15);
1365         Assertions.assertEquals(5.440610326767e+03,  FastMath.sqrt(gal.getSma()), 1.0e-15);
1366         Assertions.assertEquals(5.130000000000e+05,  gal.getTime(), 1.0e-15);
1367         Assertions.assertEquals(6.332993507385e-08,  gal.getCic(), 1.0e-15);
1368         Assertions.assertEquals(-2.165492556291e+00, gal.getOmega0(), 1.0e-15);
1369         Assertions.assertEquals(-4.842877388000e-08, gal.getCis(), 1.0e-15);
1370         Assertions.assertEquals(9.941388485934e-01,  gal.getI0(), 1.0e-15);
1371         Assertions.assertEquals(2.392812500000e+02,  gal.getCrc(), 1.0e-15);
1372         Assertions.assertEquals(-9.613560467153e-01, gal.getPa(), 1.0e-15);
1373         Assertions.assertEquals(-5.551302662610e-09, gal.getOmegaDot(), 1.0e-15);
1374         Assertions.assertEquals(-8.321775206769e-11, gal.getIDot(), 1.0e-15);
1375         Assertions.assertEquals(2147,                gal.getWeek());
1376         Assertions.assertEquals(3.119999885559e+00,  gal.getSisa(), 1.0e-15);
1377         Assertions.assertEquals(0.000000000000e+00,  gal.getSvHealth(), 1.0e-15);
1378         Assertions.assertEquals(4.656612873077e-10,  gal.getBGDE1E5a(), 1.0e-15);
1379         Assertions.assertEquals(2.328306436539e-10,  gal.getBGDE5bE1(), 1.0e-15);
1380 
1381         // check weeks reference in Rinex navigation are aligned with GPS weeks
1382         final AbsoluteDate obsRebuiltDate = new GNSSDate(gal.getWeek(), gal.getTime(), SatelliteSystem.GPS).
1383                                             getDate();
1384         final double relativeTime = obsRebuiltDate.durationFrom(gal.getEpochToc());
1385         Assertions.assertEquals(0.0, relativeTime / Constants.JULIAN_DAY, 7.0);
1386         Assertions.assertEquals(0.0, obsRebuiltDate.durationFrom(gal.getDate()), 1.0e-15);
1387 
1388         // check the propagator
1389         final Frames frames = DataContext.getDefault().getFrames();
1390         final GNSSPropagator propagator = gal.getPropagator(DataContext.getDefault().getFrames(), Propagator.getDefaultLaw(frames),
1391                 FramesFactory.getEME2000(), FramesFactory.getITRF(IERSConventions.IERS_2010, true), Propagator.DEFAULT_MASS);
1392         final AbsoluteDate date0 = gal.getDate();
1393         final Vector3D p0 = propagator.propagateInEcef(date0).getPosition();
1394         final double gpsCycleDuration = gal.getCycleDuration();
1395         final AbsoluteDate date1 = date0.shiftedBy(gpsCycleDuration);
1396         final Vector3D p1 = propagator.propagateInEcef(date1).getPosition();
1397         Assertions.assertEquals(0., p0.distance(p1), 0.);
1398         
1399     }
1400 
1401     @Test
1402     public void testSBASRinex304() throws IOException {
1403 
1404         // Parse file
1405         final String ex = "/gnss/navigation/Example_SBAS_Rinex304.n";
1406         final RinexNavigation file = new RinexNavigationParser().
1407                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
1408 
1409         // Verify Header
1410         Assertions.assertEquals(3.04,                    file.getHeader().getFormatVersion(), Double.MIN_VALUE);
1411         Assertions.assertEquals(RinexFileType.NAVIGATION,file.getHeader().getFileType());
1412         Assertions.assertEquals(SatelliteSystem.SBAS,    file.getHeader().getSatelliteSystem());
1413         Assertions.assertEquals("sbf2rin-13.4.5",        file.getHeader().getProgramName());
1414         Assertions.assertEquals("RIGTC, GO PECNY",       file.getHeader().getRunByName());
1415         Assertions.assertEquals("2021-02-19T00:26:27.0", file.getHeader().getCreationDateComponents().toStringWithoutUtcOffset(60, 1));
1416         Assertions.assertEquals("SBAS NAVIGATION DATA FROM STATION GOP6 (RIGTC, GO PECNY)", file.getComments().get(0).getText());
1417         Assertions.assertEquals("UTC",                   file.getHeader().getCreationTimeZone());
1418 
1419         // Verify data
1420         checkFieldConversion(file);
1421         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
1422         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
1423         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
1424         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
1425         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
1426         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
1427         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
1428         Assertions.assertEquals(3, file.getSBASNavigationMessages().size());
1429         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
1430         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
1431 
1432         final SBASNavigationMessage sbas = file.getSBASNavigationMessages("S36").get(0);
1433         Assertions.assertEquals(0.0, sbas.getEpochToc().durationFrom(new AbsoluteDate(2021, 2, 17, 23, 58, 56.0, TimeScalesFactory.getGPS())), Double.MIN_VALUE);
1434         Assertions.assertEquals(0.000000000000E+00, sbas.getAGf0(), 1.0e-10);
1435         Assertions.assertEquals(0.000000000000E+00, sbas.getAGf1(), 1.0e-10);
1436         Assertions.assertEquals(3.456150000000E+05, sbas.getTime(), 1.0e-10);
1437         Assertions.assertEquals(4200.368800000E+04, sbas.getX(), 1.0e-10);
1438         Assertions.assertEquals(0.000000000000E+00, sbas.getXDot(), 1.0e-10);
1439         Assertions.assertEquals(0.000000000000E+00, sbas.getXDotDot(), 1.0e-10);
1440         Assertions.assertEquals(6.300000000000E+01, sbas.getHealth(), 1.0e-10);
1441         Assertions.assertEquals(3674.846960000E+03, sbas.getY(), 1.0e-10);
1442         Assertions.assertEquals(0.000000000000E+00, sbas.getYDot(), 1.0e-10);
1443         Assertions.assertEquals(0.000000000000E+00, sbas.getYDotDot(), 1.0e-10);
1444         Assertions.assertEquals(3.276700000000E+04, sbas.getURA(), 1.0e-10);
1445         Assertions.assertEquals(0.000000000000E+00, sbas.getZ(), 1.0e-10);
1446         Assertions.assertEquals(0.000000000000E+00, sbas.getZDot(), 1.0e-10);
1447         Assertions.assertEquals(0.000000000000E+00, sbas.getZDotDot(), 1.0e-10);
1448         Assertions.assertEquals(155,                sbas.getIODN(), 1.0e-10);
1449 
1450         // check the propagator
1451         final Frames frames = DataContext.getDefault().getFrames();
1452         final SBASPropagator propagator = sbas.getPropagator(frames, Propagator.getDefaultLaw(frames),
1453                 FramesFactory.getEME2000(), FramesFactory.getITRF(IERSConventions.IERS_2010, true),
1454                 Propagator.DEFAULT_MASS, GNSSConstants.SBAS_MU);
1455         final PVCoordinates pv = propagator.propagateInEcef(sbas.getDate());
1456         final Vector3D position = pv.getPosition();
1457         final Vector3D velocity = pv.getVelocity();
1458         final Vector3D acceleration = pv.getAcceleration();
1459         double eps = 1.0e-15;
1460         Assertions.assertEquals(sbas.getX(),       position.getX(),     eps);
1461         Assertions.assertEquals(sbas.getY(),       position.getY(),     eps);
1462         Assertions.assertEquals(sbas.getZ(),       position.getZ(),     eps);
1463         Assertions.assertEquals(sbas.getXDot(),    velocity.getX(),     eps);
1464         Assertions.assertEquals(sbas.getYDot(),    velocity.getY(),     eps);
1465         Assertions.assertEquals(sbas.getZDot(),    velocity.getZ(),     eps);
1466         Assertions.assertEquals(sbas.getXDotDot(), acceleration.getX(), eps);
1467         Assertions.assertEquals(sbas.getYDotDot(), acceleration.getY(), eps);
1468         Assertions.assertEquals(sbas.getZDotDot(), acceleration.getZ(), eps);
1469 
1470     }
1471 
1472     @Test
1473     public void testSBASRinex400() throws IOException {
1474 
1475         // Parse file
1476         final String ex = "/gnss/navigation/Example_SBAS_Rinex400.n";
1477         final RinexNavigation file = new RinexNavigationParser().
1478                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
1479 
1480         // Verify Header
1481         Assertions.assertEquals(4.00,                                 file.getHeader().getFormatVersion(), Double.MIN_VALUE);
1482         Assertions.assertEquals(RinexFileType.NAVIGATION,             file.getHeader().getFileType());
1483         Assertions.assertEquals(SatelliteSystem.MIXED,                file.getHeader().getSatelliteSystem());
1484         Assertions.assertEquals("BCEmerge",                           file.getHeader().getProgramName());
1485         Assertions.assertEquals("congo",                              file.getHeader().getRunByName());
1486         Assertions.assertEquals("https://doi.org/10.57677/BRD400DLR", file.getHeader().getDoi());
1487         Assertions.assertNull(file.getHeader().getLicense());
1488         Assertions.assertNull(file.getHeader().getStationInformation());
1489         Assertions.assertEquals(18,                                   file.getHeader().getNumberOfLeapSeconds());
1490         Assertions.assertEquals(102,                                  file.getHeader().getMergedFiles());
1491 
1492         // Verify data
1493         checkFieldConversion(file);
1494         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
1495         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
1496         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
1497         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
1498         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
1499         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
1500         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
1501         Assertions.assertEquals(1, file.getSBASNavigationMessages().size());
1502         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
1503         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
1504 
1505         final SBASNavigationMessage sbas = file.getSBASNavigationMessages().get("S22").get(0);
1506         Assertions.assertEquals(0.0, sbas.getEpochToc().durationFrom(new AbsoluteDate(2022, 10, 5, 0, 0, 32, TimeScalesFactory.getGPS())), Double.MIN_VALUE);
1507 
1508     }
1509 
1510     @Test
1511     public void testNavICRinex304() throws IOException {
1512 
1513         final String ex = "/gnss/navigation/Example_NavIC_Rinex304.n";
1514         final RinexNavigation file = new RinexNavigationParser().
1515                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
1516 
1517         // Verify Header
1518         Assertions.assertEquals(3.04,                    file.getHeader().getFormatVersion(), Double.MIN_VALUE);
1519         Assertions.assertEquals(RinexFileType.NAVIGATION,file.getHeader().getFileType());
1520         Assertions.assertEquals(SatelliteSystem.NAVIC, file.getHeader().getSatelliteSystem());
1521         Assertions.assertEquals("JPS2RIN v.2.0.191",     file.getHeader().getProgramName());
1522         Assertions.assertEquals("JAVAD GNSS",            file.getHeader().getRunByName());
1523         Assertions.assertEquals("2021-03-08T00:03:04.0", file.getHeader().getCreationDateComponents().toStringWithoutUtcOffset(60, 1));
1524         Assertions.assertEquals("UTC",                   file.getHeader().getCreationTimeZone());
1525         Assertions.assertEquals(18,                      file.getHeader().getNumberOfLeapSeconds());
1526 
1527         // Verify data
1528         checkFieldConversion(file);
1529         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
1530         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
1531         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
1532         Assertions.assertEquals(0, file.getBeidouLegacyNavigationMessages().size());
1533         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
1534         Assertions.assertEquals(2, file.getNavICLegacyNavigationMessages().size());
1535         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
1536         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
1537         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
1538         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
1539 
1540         final NavICLegacyNavigationMessage navic = file.getNavICLegacyNavigationMessages("I05").get(0);
1541         Assertions.assertEquals(0.0, navic.getEpochToc().durationFrom(new AbsoluteDate(2021, 3, 7, 0, 0, 0, TimeScalesFactory.getNavIC())), Double.MIN_VALUE);
1542         Assertions.assertEquals(6.514852866530e-04,  navic.getAf0(), 1.0e-15);
1543         Assertions.assertEquals(-7.560174708487e-11, navic.getAf1(), 1.0e-15);
1544         Assertions.assertEquals(0.000000000000e+00,  navic.getAf2(), 1.0e-15);
1545         Assertions.assertEquals(0,                   navic.getIODC());
1546         Assertions.assertEquals(-3.893125000000e+02, navic.getCrs(), 1.0e-15);
1547         Assertions.assertEquals(-7.075087446362e-02, navic.getM0(), 1.0e-15);
1548         Assertions.assertEquals(-1.282989978790e-05, navic.getCuc(), 1.0e-15);
1549         Assertions.assertEquals(1.970665412955e-03,  navic.getE(), 1.0e-15);
1550         Assertions.assertEquals(1.581013202667e-05,  navic.getCus(), 1.0e-15);
1551         Assertions.assertEquals(6.493357162476e+03,  FastMath.sqrt(navic.getSma()), 1.0e-15);
1552         Assertions.assertEquals(0.000000000000e+00,  navic.getTime(), 1.0e-15);
1553         Assertions.assertEquals(-7.078051567078e-08, navic.getCic(), 1.0e-15);
1554         Assertions.assertEquals(-1.270986014126e+00, navic.getOmega0(), 1.0e-15);
1555         Assertions.assertEquals(2.160668373108e-07,  navic.getCis(), 1.0e-15);
1556         Assertions.assertEquals(5.051932936599e-01,  navic.getI0(), 1.0e-15);
1557         Assertions.assertEquals(-4.082500000000e+02, navic.getCrc(), 1.0e-15);
1558         Assertions.assertEquals(-2.990028662993e+00, navic.getPa(), 1.0e-15);
1559         Assertions.assertEquals(-2.734399613005e-09, navic.getOmegaDot(), 1.0e-15);
1560         Assertions.assertEquals(6.389551864768e-10,  navic.getIDot(), 1.0e-15);
1561         Assertions.assertEquals(2148,                navic.getWeek());
1562         Assertions.assertEquals(9.65,                navic.getSvAccuracy(), 1.0e-15);
1563         Assertions.assertEquals(0.000000000000e+00,  navic.getSvHealth(), 1.0e-15);
1564         Assertions.assertEquals(-4.656613000000e-10, navic.getTGD(), 1.0e-15);
1565 
1566         // check weeks reference in Rinex navigation are aligned with GPS weeks
1567         final AbsoluteDate obsRebuiltDate = new GNSSDate(navic.getWeek(), navic.getTime(), SatelliteSystem.GPS).
1568                                             getDate();
1569         final double relativeTime = obsRebuiltDate.durationFrom(navic.getEpochToc());
1570         Assertions.assertEquals(0.0, relativeTime / Constants.JULIAN_DAY, 7.0);
1571         Assertions.assertEquals(0.0, obsRebuiltDate.durationFrom(navic.getDate()), 1.0e-15);
1572 
1573         // check the propagator
1574         final GNSSPropagator propagator = navic.getPropagator();
1575         final AbsoluteDate date0 = navic.getDate();
1576         final Vector3D p0 = propagator.propagateInEcef(date0).getPosition();
1577         final double gpsCycleDuration = navic.getCycleDuration();
1578         final AbsoluteDate date1 = date0.shiftedBy(gpsCycleDuration);
1579         final Vector3D p1 = propagator.propagateInEcef(date1).getPosition();
1580         Assertions.assertEquals(0., p0.distance(p1), 0.);
1581 
1582     }
1583 
1584     @Test
1585     public void testBeidouRinex304() throws IOException {
1586 
1587         final String ex = "/gnss/navigation/Example_Beidou_Rinex304.n";
1588         final RinexNavigation file = new RinexNavigationParser().
1589                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
1590 
1591         // Verify Header
1592         Assertions.assertEquals(3.04,                    file.getHeader().getFormatVersion(), Double.MIN_VALUE);
1593         Assertions.assertEquals(RinexFileType.NAVIGATION,file.getHeader().getFileType());
1594         Assertions.assertEquals(SatelliteSystem.BEIDOU,  file.getHeader().getSatelliteSystem());
1595         Assertions.assertEquals("JPS2RIN v.2.0.191",     file.getHeader().getProgramName());
1596         Assertions.assertEquals("JAVAD GNSS",            file.getHeader().getRunByName());
1597         Assertions.assertEquals("2021-02-24T00:07:15.0", file.getHeader().getCreationDateComponents().toStringWithoutUtcOffset(60, 1));
1598         Assertions.assertEquals("UTC",                   file.getHeader().getCreationTimeZone());
1599         Assertions.assertEquals(18,                      file.getHeader().getNumberOfLeapSeconds());
1600 
1601         // Verify data
1602         checkFieldConversion(file);
1603         Assertions.assertEquals(0, file.getGalileoNavigationMessages().size());
1604         Assertions.assertEquals(0, file.getQZSSLegacyNavigationMessages().size());
1605         Assertions.assertEquals(0, file.getQZSSCivilianNavigationMessages().size());
1606         Assertions.assertEquals(1, file.getBeidouLegacyNavigationMessages().size());
1607         Assertions.assertEquals(0, file.getBeidouCivilianNavigationMessages().size());
1608         Assertions.assertEquals(0, file.getNavICLegacyNavigationMessages().size());
1609         Assertions.assertEquals(0, file.getGlonassNavigationMessages().size());
1610         Assertions.assertEquals(0, file.getSBASNavigationMessages().size());
1611         Assertions.assertEquals(0, file.getGPSLegacyNavigationMessages().size());
1612         Assertions.assertEquals(0, file.getGPSCivilianNavigationMessages().size());
1613 
1614         final BeidouLegacyNavigationMessage bdt = file.getBeidouLegacyNavigationMessages("C19").get(0);
1615         Assertions.assertEquals(0.0, bdt.getEpochToc().durationFrom(new AbsoluteDate(2021, 2, 23, 0, 0, 0, TimeScalesFactory.getBDT())), Double.MIN_VALUE);
1616         Assertions.assertEquals(7.378066657111e-04,  bdt.getAf0(), 1.0e-15);
1617         Assertions.assertEquals(1.382893799473e-11,  bdt.getAf1(), 1.0e-15);
1618         Assertions.assertEquals(0.000000000000e+00,  bdt.getAf2(), 1.0e-15);
1619         Assertions.assertEquals(1,                   bdt.getAODE());
1620         Assertions.assertEquals(0,                   bdt.getAODC());
1621         Assertions.assertEquals(-7.420312500000e+01, bdt.getCrs(), 1.0e-15);
1622         Assertions.assertEquals(-2.379681558032e-01, bdt.getM0(), 1.0e-15);
1623         Assertions.assertEquals(-3.555789589882e-06, bdt.getCuc(), 1.0e-15);
1624         Assertions.assertEquals(8.384847315028e-04,  bdt.getE(), 1.0e-15);
1625         Assertions.assertEquals(1.072138547897e-05,  bdt.getCus(), 1.0e-15);
1626         Assertions.assertEquals(5.282626970291e+03,  FastMath.sqrt(bdt.getSma()), 1.0e-15);
1627         Assertions.assertEquals(1.728000000000e+05,  bdt.getTime(), 1.0e-15);
1628         Assertions.assertEquals(-2.607703208923e-08, bdt.getCic(), 1.0e-15);
1629         Assertions.assertEquals(-4.071039898353e-01, bdt.getOmega0(), 1.0e-15);
1630         Assertions.assertEquals(-6.519258022308e-09, bdt.getCis(), 1.0e-15);
1631         Assertions.assertEquals(9.657351895813e-01,  bdt.getI0(), 1.0e-15);
1632         Assertions.assertEquals(1.491093750000e+02,  bdt.getCrc(), 1.0e-15);
1633         Assertions.assertEquals(-1.225716188251e+00, bdt.getPa(), 1.0e-15);
1634         Assertions.assertEquals(-6.454554572392e-09, bdt.getOmegaDot(), 1.0e-15);
1635         Assertions.assertEquals(2.217949529358e-10,  bdt.getIDot(), 1.0e-15);
1636         Assertions.assertEquals(790,                 bdt.getWeek());
1637         Assertions.assertEquals(2.000000000000e+00,  bdt.getSvAccuracy(), 1.0e-15);
1638         Assertions.assertEquals(1.220000000000e-08,  bdt.getTGD1(), 1.0e-15);
1639         Assertions.assertEquals(1.220000000000e-08,  bdt.getTGD2(), 1.0e-15);
1640 
1641         // check weeks reference in Rinex navigation are aligned with Beidou weeks (not GPS weeks as other systems)
1642         final AbsoluteDate obsRebuiltDate = new GNSSDate(bdt.getWeek(), bdt.getTime(), SatelliteSystem.BEIDOU).
1643                                             getDate();
1644         final double relativeTime = obsRebuiltDate.durationFrom(bdt.getEpochToc());
1645         Assertions.assertEquals(0.0, relativeTime / Constants.JULIAN_DAY, 7.0);
1646 
1647         // check the propagator
1648         final GNSSPropagator propagator = bdt.getPropagator();
1649         final AbsoluteDate date0 = bdt.getDate();
1650         final Vector3D p0 = propagator.propagateInEcef(date0).getPosition();
1651         final double gpsCycleDuration = bdt.getCycleDuration();
1652         final AbsoluteDate date1 = date0.shiftedBy(gpsCycleDuration);
1653         final Vector3D p1 = propagator.propagateInEcef(date1).getPosition();
1654         Assertions.assertEquals(0., p0.distance(p1), 0.);
1655 
1656     }
1657 
1658     @Test
1659     public void testStoRinex400() throws IOException {
1660 
1661         // Parse file
1662         final String ex = "/gnss/navigation/Example_Sto_Rinex400.n";
1663         final RinexNavigation file = new RinexNavigationParser().
1664                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
1665 
1666         // Verify Header
1667         Assertions.assertEquals(4.00,                                 file.getHeader().getFormatVersion(), Double.MIN_VALUE);
1668         Assertions.assertEquals(RinexFileType.NAVIGATION,             file.getHeader().getFileType());
1669         Assertions.assertEquals(SatelliteSystem.MIXED,                file.getHeader().getSatelliteSystem());
1670         Assertions.assertEquals("BCEmerge",                           file.getHeader().getProgramName());
1671         Assertions.assertEquals("congo",                              file.getHeader().getRunByName());
1672         Assertions.assertEquals("https://doi.org/10.57677/BRD400DLR", file.getHeader().getDoi());
1673         Assertions.assertNull(file.getHeader().getLicense());
1674         Assertions.assertNull(file.getHeader().getStationInformation());
1675         Assertions.assertEquals(18,                                   file.getHeader().getNumberOfLeapSeconds());
1676         Assertions.assertEquals(102,                                  file.getHeader().getMergedFiles());
1677 
1678         // Verify data
1679         checkFieldConversion(file);
1680         Assertions.assertEquals(0,  file.getGalileoNavigationMessages().size());
1681         Assertions.assertEquals(0,  file.getQZSSLegacyNavigationMessages().size());
1682         Assertions.assertEquals(0,  file.getQZSSCivilianNavigationMessages().size());
1683         Assertions.assertEquals(0,  file.getBeidouLegacyNavigationMessages().size());
1684         Assertions.assertEquals(0,  file.getBeidouCivilianNavigationMessages().size());
1685         Assertions.assertEquals(0,  file.getNavICLegacyNavigationMessages().size());
1686         Assertions.assertEquals(0,  file.getGlonassNavigationMessages().size());
1687         Assertions.assertEquals(0,  file.getSBASNavigationMessages().size());
1688         Assertions.assertEquals(0,  file.getGPSLegacyNavigationMessages().size());
1689         Assertions.assertEquals(0,  file.getGPSCivilianNavigationMessages().size());
1690         Assertions.assertEquals(16, file.getSystemTimeOffsets().size());
1691         Assertions.assertEquals(0,  file.getEarthOrientationParameters().size());
1692         Assertions.assertEquals(0,  file.getKlobucharMessages().size());
1693         Assertions.assertEquals(0,  file.getNequickGMessages().size());
1694         Assertions.assertEquals(0,  file.getBDGIMMessages().size());
1695 
1696         List<SystemTimeOffsetMessage> list = file.getSystemTimeOffsets();
1697         Assertions.assertEquals(SatelliteSystem.BEIDOU, list.get(0).getSystem());
1698         Assertions.assertEquals(35, list.get(0).getPrn());
1699         Assertions.assertEquals("CNVX", list.get(0).getNavigationMessageType());
1700         Assertions.assertEquals(TimeSystem.BEIDOU, list.get(0).getDefinedTimeSystem());
1701         Assertions.assertEquals(TimeSystem.GALILEO, list.get(0).getReferenceTimeSystem());
1702         Assertions.assertNull(list.get(0).getSbasId());
1703         Assertions.assertNull(list.get(0).getUtcId());
1704         Assertions.assertEquals(0.0,
1705                                 list.get(0).getReferenceEpoch().durationFrom(new AbsoluteDate(2022, 10, 4, 23, 20, 0.0,
1706                                                                                               TimeScalesFactory.getBDT())),
1707                                 1.0e-15);
1708         Assertions.assertEquals(259230.0,            list.get( 0).getTransmissionTime(), 1.0e-15);
1709         Assertions.assertEquals(-2.657179720700e-08, list.get( 0).getA0(), 1.0e-17);
1710         Assertions.assertEquals( 4.884981308351e-14, list.get( 0).getA1(), 1.0e-23);
1711         Assertions.assertEquals( 2.066760391300e-19, list.get( 0).getA2(), 1.0e-28);
1712 
1713         Assertions.assertEquals(TimeSystem.BEIDOU,   list.get( 1).getDefinedTimeSystem());
1714         Assertions.assertEquals(TimeSystem.GLONASS,  list.get( 1).getReferenceTimeSystem());
1715         Assertions.assertEquals(TimeSystem.BEIDOU,   list.get( 2).getDefinedTimeSystem());
1716         Assertions.assertEquals(TimeSystem.GPS,      list.get( 2).getReferenceTimeSystem());
1717         Assertions.assertEquals(TimeSystem.BEIDOU,   list.get( 3).getDefinedTimeSystem());
1718         Assertions.assertEquals("BDT",               list.get( 3).getDefinedTimeSystem().getKey());
1719         Assertions.assertEquals("BD",                list.get( 3).getDefinedTimeSystem().getTwoLettersCode());
1720         Assertions.assertEquals("C",                 list.get( 3).getDefinedTimeSystem().getOneLetterCode());
1721         Assertions.assertEquals(TimeSystem.UTC,      list.get( 3).getReferenceTimeSystem());
1722         Assertions.assertEquals("UTC",               list.get( 3).getReferenceTimeSystem().getKey());
1723         Assertions.assertEquals("UT",                list.get( 3).getReferenceTimeSystem().getTwoLettersCode());
1724         Assertions.assertNull(                       list.get( 3).getReferenceTimeSystem().getOneLetterCode());
1725         Assertions.assertEquals(UtcId.NTSC,          list.get( 3).getUtcId());
1726         Assertions.assertEquals(TimeSystem.GALILEO,  list.get( 4).getDefinedTimeSystem());
1727         Assertions.assertEquals(TimeSystem.GPS,      list.get( 4).getReferenceTimeSystem());
1728         Assertions.assertEquals(TimeSystem.GLONASS,  list.get( 5).getDefinedTimeSystem());
1729         Assertions.assertEquals(TimeSystem.GPS,      list.get( 5).getReferenceTimeSystem());
1730         Assertions.assertEquals(TimeSystem.GLONASS,  list.get( 6).getDefinedTimeSystem());
1731         Assertions.assertEquals(TimeSystem.GPS,      list.get( 6).getReferenceTimeSystem());
1732         Assertions.assertEquals(TimeSystem.GLONASS,  list.get( 7).getDefinedTimeSystem());
1733         Assertions.assertEquals(TimeSystem.UTC,      list.get( 7).getReferenceTimeSystem());
1734         Assertions.assertEquals(UtcId.SU,            list.get( 7).getUtcId());
1735         Assertions.assertEquals(TimeSystem.GPS,      list.get( 8).getDefinedTimeSystem());
1736         Assertions.assertEquals(TimeSystem.UTC,      list.get( 8).getReferenceTimeSystem());
1737         Assertions.assertEquals(UtcId.USNO,          list.get( 8).getUtcId());
1738         Assertions.assertEquals(TimeSystem.NAVIC,    list.get(9).getDefinedTimeSystem());
1739         Assertions.assertEquals(TimeSystem.GLONASS,  list.get( 9).getReferenceTimeSystem());
1740         Assertions.assertEquals(TimeSystem.NAVIC,    list.get(10).getDefinedTimeSystem());
1741         Assertions.assertEquals(TimeSystem.GPS,      list.get(10).getReferenceTimeSystem());
1742         Assertions.assertEquals(TimeSystem.NAVIC,    list.get(11).getDefinedTimeSystem());
1743         Assertions.assertEquals(TimeSystem.UTC,      list.get(11).getReferenceTimeSystem());
1744         Assertions.assertEquals(UtcId.IRN,           list.get(11).getUtcId());
1745         Assertions.assertEquals(TimeSystem.NAVIC,    list.get(12).getDefinedTimeSystem());
1746         Assertions.assertEquals(TimeSystem.UTC,      list.get(12).getReferenceTimeSystem());
1747         Assertions.assertEquals(UtcId.IRN,           list.get(12).getUtcId());
1748         Assertions.assertEquals(TimeSystem.QZSS,     list.get(13).getDefinedTimeSystem());
1749         Assertions.assertEquals(TimeSystem.GPS,      list.get(13).getReferenceTimeSystem());
1750         Assertions.assertEquals(TimeSystem.QZSS,     list.get(14).getDefinedTimeSystem());
1751         Assertions.assertEquals(TimeSystem.UTC,      list.get(14).getReferenceTimeSystem());
1752         Assertions.assertEquals(UtcId.NICT,          list.get(14).getUtcId());
1753         Assertions.assertEquals(TimeSystem.SBAS,     list.get(15).getDefinedTimeSystem());
1754         Assertions.assertEquals(TimeSystem.UTC,      list.get(15).getReferenceTimeSystem());
1755         Assertions.assertEquals(SbasId.EGNOS,        list.get(15).getSbasId());
1756         Assertions.assertEquals(UtcId.OP,            list.get(15).getUtcId());
1757 
1758     }
1759 
1760     @Test
1761     public void testEopRinex400() throws IOException {
1762 
1763         // Parse file
1764         final String ex = "/gnss/navigation/Example_Eop_Rinex400.n";
1765         final RinexNavigation file = new RinexNavigationParser().
1766                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
1767 
1768         // Verify Header
1769         Assertions.assertEquals(4.00,                                 file.getHeader().getFormatVersion(), Double.MIN_VALUE);
1770         Assertions.assertEquals(RinexFileType.NAVIGATION,             file.getHeader().getFileType());
1771         Assertions.assertEquals(SatelliteSystem.MIXED,                file.getHeader().getSatelliteSystem());
1772         Assertions.assertEquals("BCEmerge",                           file.getHeader().getProgramName());
1773         Assertions.assertEquals("congo",                              file.getHeader().getRunByName());
1774         Assertions.assertEquals("https://doi.org/10.57677/BRD400DLR", file.getHeader().getDoi());
1775         Assertions.assertNull(file.getHeader().getLicense());
1776         Assertions.assertNull(file.getHeader().getStationInformation());
1777         Assertions.assertEquals(18,                                   file.getHeader().getNumberOfLeapSeconds());
1778         Assertions.assertEquals(102,                                  file.getHeader().getMergedFiles());
1779 
1780         // Verify data
1781         checkFieldConversion(file);
1782         Assertions.assertEquals(0,  file.getGalileoNavigationMessages().size());
1783         Assertions.assertEquals(0,  file.getQZSSLegacyNavigationMessages().size());
1784         Assertions.assertEquals(0,  file.getQZSSCivilianNavigationMessages().size());
1785         Assertions.assertEquals(0,  file.getBeidouLegacyNavigationMessages().size());
1786         Assertions.assertEquals(0,  file.getBeidouCivilianNavigationMessages().size());
1787         Assertions.assertEquals(0,  file.getNavICLegacyNavigationMessages().size());
1788         Assertions.assertEquals(0,  file.getGlonassNavigationMessages().size());
1789         Assertions.assertEquals(0,  file.getSBASNavigationMessages().size());
1790         Assertions.assertEquals(0,  file.getGPSLegacyNavigationMessages().size());
1791         Assertions.assertEquals(0,  file.getGPSCivilianNavigationMessages().size());
1792         Assertions.assertEquals(0,  file.getSystemTimeOffsets().size());
1793         Assertions.assertEquals(3,  file.getEarthOrientationParameters().size());
1794         Assertions.assertEquals(0,  file.getKlobucharMessages().size());
1795         Assertions.assertEquals(0,  file.getNequickGMessages().size());
1796         Assertions.assertEquals(0,  file.getBDGIMMessages().size());
1797 
1798         List<EarthOrientationParameterMessage> list = file.getEarthOrientationParameters();
1799 
1800         Assertions.assertEquals(SatelliteSystem.GPS, list.get(0).getSystem());
1801         Assertions.assertEquals(15, list.get(0).getPrn());
1802         Assertions.assertEquals("CNVX", list.get(0).getNavigationMessageType());
1803         Assertions.assertEquals(0.0,
1804                                 new AbsoluteDate(2022, 10, 6, 16, 38, 24.0, TimeScalesFactory.getGPS()).durationFrom(list.get(0).getReferenceEpoch()),
1805                                 1.0e-15);
1806         Assertions.assertEquals( 2.734127044678e-01, Unit.ARC_SECOND.fromSI(list.get(0).getXp()),            1.0e-10);
1807         Assertions.assertEquals(-1.487731933594e-03, Unit.parse("as/d").fromSI(list.get(0).getXpDot()),      1.0e-10);
1808         Assertions.assertEquals( 0.000000000000e+00, Unit.parse("as/d²").fromSI(list.get(0).getXpDotDot()),   1.0e-10);
1809         Assertions.assertEquals( 2.485857009888e-01, Unit.ARC_SECOND.fromSI(list.get(0).getYp()),            1.0e-10);
1810         Assertions.assertEquals(-1.955032348633e-03, Unit.parse("as/d").fromSI(list.get(0).getYpDot()),      1.0e-10);
1811         Assertions.assertEquals( 0.000000000000e+00, Unit.parse("as/d²").fromSI(list.get(0).getYpDotDot()),  1.0e-10);
1812         Assertions.assertEquals(259728.0,            Unit.SECOND.fromSI(list.get(0).getTransmissionTime()),  1.0e-10);
1813         Assertions.assertEquals(-3.280282020569e-03, Unit.SECOND.fromSI(list.get(0).getDut1()),              1.0e-10);
1814         Assertions.assertEquals( 1.151263713837e-04, Unit.parse("s/d").fromSI(list.get(0).getDut1Dot()),     1.0e-10);
1815         Assertions.assertEquals( 0.000000000000e+00, Unit.parse("s/d²").fromSI(list.get(0).getDut1DotDot()), 1.0e-10);
1816 
1817         Assertions.assertEquals(SatelliteSystem.QZSS, list.get(1).getSystem());
1818         Assertions.assertEquals(4, list.get(1).getPrn());
1819         Assertions.assertEquals("CNVX", list.get(1).getNavigationMessageType());
1820         Assertions.assertEquals(0.0,
1821                                 new AbsoluteDate(2022, 10, 6, 0, 0, 0.0, TimeScalesFactory.getQZSS()).durationFrom(list.get(1).getReferenceEpoch()),
1822                                 1.0e-15);
1823         Assertions.assertEquals( 2.723026275635e-01, Unit.ARC_SECOND.fromSI(list.get(1).getXp()),            1.0e-10);
1824         Assertions.assertEquals(-2.049922943115e-03, Unit.parse("as/d").fromSI(list.get(1).getXpDot()),      1.0e-10);
1825         Assertions.assertEquals( 0.000000000000e+00, Unit.parse("as/d²").fromSI(list.get(1).getXpDotDot()),   1.0e-10);
1826         Assertions.assertEquals( 2.491779327393e-01, Unit.ARC_SECOND.fromSI(list.get(1).getYp()),            1.0e-10);
1827         Assertions.assertEquals(-1.977920532227e-03, Unit.parse("as/d").fromSI(list.get(1).getYpDot()),      1.0e-10);
1828         Assertions.assertEquals( 0.000000000000e+00, Unit.parse("as/d²").fromSI(list.get(1).getYpDotDot()),  1.0e-10);
1829         Assertions.assertEquals(342186.0,            Unit.SECOND.fromSI(list.get(1).getTransmissionTime()),  1.0e-10);
1830         Assertions.assertEquals(-3.003299236298e-03, Unit.SECOND.fromSI(list.get(1).getDut1()),              1.0e-10);
1831         Assertions.assertEquals( 2.534389495850e-04, Unit.parse("s/d").fromSI(list.get(1).getDut1Dot()),     1.0e-10);
1832         Assertions.assertEquals( 0.000000000000e+00, Unit.parse("s/d²").fromSI(list.get(1).getDut1DotDot()), 1.0e-10);
1833 
1834         Assertions.assertEquals(SatelliteSystem.NAVIC, list.get(2).getSystem());
1835         Assertions.assertEquals(3, list.get(2).getPrn());
1836         Assertions.assertEquals("LNAV", list.get(2).getNavigationMessageType());
1837         Assertions.assertEquals(0.0,
1838                                 new AbsoluteDate(2022, 10, 5, 0, 0, 0.0, TimeScalesFactory.getNavIC()).durationFrom(list.get(2).getReferenceEpoch()),
1839                                 1.0e-15);
1840         Assertions.assertEquals( 2.751779556274e-01, Unit.ARC_SECOND.fromSI(list.get(2).getXp()),            1.0e-10);
1841         Assertions.assertEquals(-1.739501953125e-03, Unit.parse("as/d").fromSI(list.get(2).getXpDot()),      1.0e-10);
1842         Assertions.assertEquals( 0.000000000000e+00, Unit.parse("as/d²").fromSI(list.get(2).getXpDotDot()),   1.0e-10);
1843         Assertions.assertEquals( 2.516956329346e-01, Unit.ARC_SECOND.fromSI(list.get(2).getYp()),            1.0e-10);
1844         Assertions.assertEquals(-1.918315887451e-03, Unit.parse("as/d").fromSI(list.get(2).getYpDot()),      1.0e-10);
1845         Assertions.assertEquals( 0.000000000000e+00, Unit.parse("as/d²").fromSI(list.get(2).getYpDotDot()),  1.0e-10);
1846         Assertions.assertEquals(259248.0,            Unit.SECOND.fromSI(list.get(2).getTransmissionTime()),  1.0e-10);
1847         Assertions.assertEquals(-3.213942050934e-03, Unit.SECOND.fromSI(list.get(2).getDut1()),              1.0e-10);
1848         Assertions.assertEquals( 1.052916049957e-04, Unit.parse("s/d").fromSI(list.get(2).getDut1Dot()),     1.0e-10);
1849         Assertions.assertEquals( 0.000000000000e+00, Unit.parse("s/d²").fromSI(list.get(2).getDut1DotDot()), 1.0e-10);
1850 
1851     }
1852 
1853     @Test
1854     public void testIonRinex400() throws IOException {
1855 
1856         // Parse file
1857         final String ex = "/gnss/navigation/Example_Ion_Rinex400.n";
1858         final RinexNavigation file = new RinexNavigationParser().
1859                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
1860 
1861         // Verify Header
1862         Assertions.assertEquals(4.00,                                 file.getHeader().getFormatVersion(), Double.MIN_VALUE);
1863         Assertions.assertEquals(RinexFileType.NAVIGATION,             file.getHeader().getFileType());
1864         Assertions.assertEquals(SatelliteSystem.MIXED,                file.getHeader().getSatelliteSystem());
1865         Assertions.assertEquals("BCEmerge",                           file.getHeader().getProgramName());
1866         Assertions.assertEquals("congo",                              file.getHeader().getRunByName());
1867         Assertions.assertEquals("https://doi.org/10.57677/BRD400DLR", file.getHeader().getDoi());
1868         Assertions.assertNull(file.getHeader().getLicense());
1869         Assertions.assertNull(file.getHeader().getStationInformation());
1870         Assertions.assertEquals(18,                                   file.getHeader().getNumberOfLeapSeconds());
1871         Assertions.assertEquals(102,                                  file.getHeader().getMergedFiles());
1872 
1873         // Verify data
1874         checkFieldConversion(file);
1875         Assertions.assertEquals(0,  file.getGalileoNavigationMessages().size());
1876         Assertions.assertEquals(0,  file.getQZSSLegacyNavigationMessages().size());
1877         Assertions.assertEquals(0,  file.getQZSSCivilianNavigationMessages().size());
1878         Assertions.assertEquals(0,  file.getBeidouLegacyNavigationMessages().size());
1879         Assertions.assertEquals(0,  file.getBeidouCivilianNavigationMessages().size());
1880         Assertions.assertEquals(0,  file.getNavICLegacyNavigationMessages().size());
1881         Assertions.assertEquals(0,  file.getGlonassNavigationMessages().size());
1882         Assertions.assertEquals(0,  file.getSBASNavigationMessages().size());
1883         Assertions.assertEquals(0,  file.getGPSLegacyNavigationMessages().size());
1884         Assertions.assertEquals(0,  file.getGPSCivilianNavigationMessages().size());
1885         Assertions.assertEquals(0,  file.getSystemTimeOffsets().size());
1886         Assertions.assertEquals(0,  file.getEarthOrientationParameters().size());
1887         Assertions.assertEquals(6,  file.getKlobucharMessages().size());
1888         Assertions.assertEquals(1,  file.getNequickGMessages().size());
1889         Assertions.assertEquals(2,  file.getBDGIMMessages().size());
1890 
1891         List<IonosphereKlobucharMessage> listK = file.getKlobucharMessages();
1892         List<IonosphereNequickGMessage>  listN = file.getNequickGMessages();
1893         List<IonosphereBDGIMMessage>     listB = file.getBDGIMMessages();
1894 
1895         Assertions.assertEquals(SatelliteSystem.GPS, listK.get(0).getSystem());
1896         Assertions.assertEquals(17, listK.get(0).getPrn());
1897         Assertions.assertEquals("LNAV", listK.get(0).getNavigationMessageType());
1898         Assertions.assertEquals(0.0,
1899                                 new AbsoluteDate(2022, 10, 5, 23, 33, 54.0, TimeScalesFactory.getGPS()).durationFrom(listK.get(0).getTransmitTime()),
1900                                 1.0e-15);
1901         Assertions.assertEquals( 2.514570951462e-08, IonosphereKlobucharMessage.S_PER_SC_N[0].fromSI(listK.get(0).getAlpha()[0]), 1.0e-16);
1902         Assertions.assertEquals( 1.490116119385e-08, IonosphereKlobucharMessage.S_PER_SC_N[1].fromSI(listK.get(0).getAlpha()[1]), 1.0e-16);
1903         Assertions.assertEquals(-1.192092895508e-07, IonosphereKlobucharMessage.S_PER_SC_N[2].fromSI(listK.get(0).getAlpha()[2]), 1.0e-16);
1904         Assertions.assertEquals(-5.960464477539e-08, IonosphereKlobucharMessage.S_PER_SC_N[3].fromSI(listK.get(0).getAlpha()[3]), 1.0e-16);
1905         Assertions.assertEquals( 1.331200000000e+05, IonosphereKlobucharMessage.S_PER_SC_N[0].fromSI(listK.get(0).getBeta()[0]),  1.0e-10);
1906         Assertions.assertEquals(-1.638400000000e+04, IonosphereKlobucharMessage.S_PER_SC_N[1].fromSI(listK.get(0).getBeta()[1]),  1.0e-10);
1907         Assertions.assertEquals(-2.621440000000e+05, IonosphereKlobucharMessage.S_PER_SC_N[2].fromSI(listK.get(0).getBeta()[2]),  1.0e-10);
1908         Assertions.assertEquals( 1.966080000000e+05, IonosphereKlobucharMessage.S_PER_SC_N[3].fromSI(listK.get(0).getBeta()[3]),  1.0e-10);
1909 
1910         Assertions.assertEquals(SatelliteSystem.GPS, listK.get(1).getSystem());
1911         Assertions.assertEquals(25, listK.get(1).getPrn());
1912         Assertions.assertEquals("CNVX", listK.get(1).getNavigationMessageType());
1913         Assertions.assertEquals(0.0,
1914                                 new AbsoluteDate(2022, 10, 5, 23, 30, 42.0, TimeScalesFactory.getGPS()).durationFrom(listK.get(1).getTransmitTime()),
1915                                 1.0e-15);
1916         Assertions.assertEquals( 2.514570951462e-08, IonosphereKlobucharMessage.S_PER_SC_N[0].fromSI(listK.get(1).getAlpha()[0]), 1.0e-16);
1917         Assertions.assertEquals( 1.490116119385e-08, IonosphereKlobucharMessage.S_PER_SC_N[1].fromSI(listK.get(1).getAlpha()[1]), 1.0e-16);
1918         Assertions.assertEquals(-1.192092895508e-07, IonosphereKlobucharMessage.S_PER_SC_N[2].fromSI(listK.get(1).getAlpha()[2]), 1.0e-16);
1919         Assertions.assertEquals(-5.960464477539e-08, IonosphereKlobucharMessage.S_PER_SC_N[3].fromSI(listK.get(1).getAlpha()[3]), 1.0e-16);
1920         Assertions.assertEquals( 1.331200000000e+05, IonosphereKlobucharMessage.S_PER_SC_N[0].fromSI(listK.get(1).getBeta()[0]),  1.0e-10);
1921         Assertions.assertEquals(-1.638400000000e+04, IonosphereKlobucharMessage.S_PER_SC_N[1].fromSI(listK.get(1).getBeta()[1]),  1.0e-10);
1922         Assertions.assertEquals(-2.621440000000e+05, IonosphereKlobucharMessage.S_PER_SC_N[2].fromSI(listK.get(1).getBeta()[2]),  1.0e-10);
1923         Assertions.assertEquals( 1.966080000000e+05, IonosphereKlobucharMessage.S_PER_SC_N[3].fromSI(listK.get(1).getBeta()[3]),  1.0e-10);
1924 
1925         Assertions.assertEquals(SatelliteSystem.GALILEO, listN.get(0).getSystem());
1926         Assertions.assertEquals(2, listN.get(0).getPrn());
1927         Assertions.assertEquals("IFNV", listN.get(0).getNavigationMessageType());
1928         Assertions.assertEquals(0.0,
1929                                 new AbsoluteDate(2022, 10, 5, 6, 21, 4.0, TimeScalesFactory.getGPS()).durationFrom(listN.get(0).getTransmitTime()),
1930                                 1.0e-15);
1931         Assertions.assertEquals( 1.207500000000e+02, IonosphereNequickGMessage.SFU.fromSI(listN.get(0).getAi0()),          1.0e-16);
1932         Assertions.assertEquals( -1.953125000000e-01, IonosphereNequickGMessage.SFU_PER_DEG.fromSI(listN.get(0).getAi1()), 1.0e-16);
1933         Assertions.assertEquals(-7.629394531250e-04, IonosphereNequickGMessage.SFU_PER_DEG2.fromSI(listN.get(0).getAi2()), 1.0e-16);
1934         Assertions.assertEquals(0, listN.get(0).getFlags());
1935 
1936         Assertions.assertEquals(SatelliteSystem.BEIDOU, listB.get(0).getSystem());
1937         Assertions.assertEquals(29, listB.get(0).getPrn());
1938         Assertions.assertEquals("CNVX", listB.get(0).getNavigationMessageType());
1939         Assertions.assertEquals(0.0,
1940                                 new AbsoluteDate(2022, 10, 5, 2, 0, 0.0, TimeScalesFactory.getBDT()).durationFrom(listB.get(0).getTransmitTime()),
1941                                 1.0e-15);
1942         Assertions.assertEquals( 2.662500000000e+01, Unit.TOTAL_ELECTRON_CONTENT_UNIT.fromSI(listB.get(0).getAlpha()[0]), 1.0e-16);
1943         Assertions.assertEquals(-1.250000000000e-01, Unit.TOTAL_ELECTRON_CONTENT_UNIT.fromSI(listB.get(0).getAlpha()[1]), 1.0e-16);
1944         Assertions.assertEquals( 9.875000000000e+00, Unit.TOTAL_ELECTRON_CONTENT_UNIT.fromSI(listB.get(0).getAlpha()[2]), 1.0e-16);
1945         Assertions.assertEquals( 8.375000000000e+00, Unit.TOTAL_ELECTRON_CONTENT_UNIT.fromSI(listB.get(0).getAlpha()[3]), 1.0e-16);
1946         Assertions.assertEquals(-1.025000000000e+01, Unit.TOTAL_ELECTRON_CONTENT_UNIT.fromSI(listB.get(0).getAlpha()[4]), 1.0e-10);
1947         Assertions.assertEquals( 8.750000000000e-01, Unit.TOTAL_ELECTRON_CONTENT_UNIT.fromSI(listB.get(0).getAlpha()[5]), 1.0e-10);
1948         Assertions.assertEquals( 3.750000000000e-01, Unit.TOTAL_ELECTRON_CONTENT_UNIT.fromSI(listB.get(0).getAlpha()[6]), 1.0e-10);
1949         Assertions.assertEquals( 2.125000000000e+00, Unit.TOTAL_ELECTRON_CONTENT_UNIT.fromSI(listB.get(0).getAlpha()[7]), 1.0e-10);
1950         Assertions.assertEquals( 1.000000000000e+00, Unit.TOTAL_ELECTRON_CONTENT_UNIT.fromSI(listB.get(0).getAlpha()[8]), 1.0e-10);
1951 
1952     }
1953 
1954     @Test
1955     public void testGPSRinex2() throws IOException {
1956 
1957         // Parse file
1958         final String ex = "/gnss/navigation/brdc0130.22n";
1959         final RinexNavigation file = new RinexNavigationParser().
1960                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
1961 
1962         // Verify Header
1963         Assertions.assertEquals(2.00,                                 file.getHeader().getFormatVersion(), Double.MIN_VALUE);
1964         Assertions.assertEquals(RinexFileType.NAVIGATION,             file.getHeader().getFileType());
1965         Assertions.assertEquals(SatelliteSystem.GPS,                  file.getHeader().getSatelliteSystem());
1966         Assertions.assertEquals("CCRINEXN V1.6.0 UX",                 file.getHeader().getProgramName());
1967         Assertions.assertEquals("CDDIS",                              file.getHeader().getRunByName());
1968         Assertions.assertEquals(18,                                   file.getHeader().getNumberOfLeapSeconds());
1969 
1970         // Verify data
1971         checkFieldConversion(file);
1972         Assertions.assertEquals(0,  file.getGalileoNavigationMessages().size());
1973         Assertions.assertEquals(0,  file.getQZSSLegacyNavigationMessages().size());
1974         Assertions.assertEquals(0,  file.getQZSSCivilianNavigationMessages().size());
1975         Assertions.assertEquals(0,  file.getBeidouLegacyNavigationMessages().size());
1976         Assertions.assertEquals(0,  file.getBeidouCivilianNavigationMessages().size());
1977         Assertions.assertEquals(0,  file.getNavICLegacyNavigationMessages().size());
1978         Assertions.assertEquals(0,  file.getGlonassNavigationMessages().size());
1979         Assertions.assertEquals(0,  file.getSBASNavigationMessages().size());
1980         Assertions.assertEquals(3,  file.getGPSLegacyNavigationMessages().size());
1981         Assertions.assertEquals(0,  file.getGPSCivilianNavigationMessages().size());
1982         Assertions.assertEquals(0,  file.getSystemTimeOffsets().size());
1983         Assertions.assertEquals(0,  file.getEarthOrientationParameters().size());
1984         Assertions.assertEquals(0,  file.getKlobucharMessages().size());
1985         Assertions.assertEquals(0,  file.getNequickGMessages().size());
1986         Assertions.assertEquals(0,  file.getBDGIMMessages().size());
1987 
1988         Assertions.assertEquals(0, file.getKlobucharMessages().size());
1989         Assertions.assertEquals(0, file.getNequickGMessages().size());
1990         Assertions.assertEquals(0, file.getBDGIMMessages().size());
1991         Assertions.assertEquals( 0.1118e-07, file.getKlobucharAlpha()[0], 1.0e-20);
1992         Assertions.assertEquals(-0.7451e-08, file.getKlobucharAlpha()[1], 1.0e-20);
1993         Assertions.assertEquals(-0.5960e-07, file.getKlobucharAlpha()[2], 1.0e-20);
1994         Assertions.assertEquals( 0.1192e-06, file.getKlobucharAlpha()[3], 1.0e-20);
1995         Assertions.assertEquals( 0.1147e+06, file.getKlobucharBeta()[0],  1.0e-7);
1996         Assertions.assertEquals(-0.1638e+06, file.getKlobucharBeta()[1],  1.0e-7);
1997         Assertions.assertEquals(-0.1966e+06, file.getKlobucharBeta()[2],  1.0e-7);
1998         Assertions.assertEquals( 0.9175e+06, file.getKlobucharBeta()[3],  1.0e-7);
1999 
2000         List<GPSLegacyNavigationMessage> list02 = file.getGPSLegacyNavigationMessages("G02");
2001         Assertions.assertEquals(3, list02.size());
2002 
2003         Assertions.assertEquals(0.0,
2004                                 list02.get(0).getDate().durationFrom(new AbsoluteDate(2022, 1, 13, 0, 0, 0.0,
2005                                                                                       TimeScalesFactory.getGPS())),
2006                                 1.0e-10);
2007         Assertions.assertEquals(50,              list02.get(0).getIODE());
2008         Assertions.assertEquals(0.0206718930276, list02.get(0).getE());
2009         Assertions.assertEquals(-1.37437210544,  list02.get(0).getOmega0());
2010 
2011     }
2012 
2013     @Test
2014     public void testGlonassRinex2() throws IOException {
2015 
2016         // Parse file
2017         final String ex = "/gnss/navigation/brdc0130.22g";
2018         final RinexNavigation file = new RinexNavigationParser().
2019                         parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
2020 
2021         // Verify Header
2022         Assertions.assertEquals(2.01,                                 file.getHeader().getFormatVersion(), Double.MIN_VALUE);
2023         Assertions.assertEquals(RinexFileType.NAVIGATION,             file.getHeader().getFileType());
2024         Assertions.assertEquals(SatelliteSystem.GLONASS,              file.getHeader().getSatelliteSystem());
2025         Assertions.assertEquals("CCRINEXG V1.4 UX",                   file.getHeader().getProgramName());
2026         Assertions.assertEquals("CDDIS",                              file.getHeader().getRunByName());
2027         Assertions.assertEquals(18,                                   file.getHeader().getNumberOfLeapSeconds());
2028 
2029         // Verify data
2030         checkFieldConversion(file);
2031         Assertions.assertEquals(0,  file.getGalileoNavigationMessages().size());
2032         Assertions.assertEquals(0,  file.getQZSSLegacyNavigationMessages().size());
2033         Assertions.assertEquals(0,  file.getQZSSCivilianNavigationMessages().size());
2034         Assertions.assertEquals(0,  file.getBeidouLegacyNavigationMessages().size());
2035         Assertions.assertEquals(0,  file.getBeidouCivilianNavigationMessages().size());
2036         Assertions.assertEquals(0,  file.getNavICLegacyNavigationMessages().size());
2037         Assertions.assertEquals(23, file.getGlonassNavigationMessages().size());
2038         Assertions.assertEquals(0,  file.getSBASNavigationMessages().size());
2039         Assertions.assertEquals(0,  file.getGPSLegacyNavigationMessages().size());
2040         Assertions.assertEquals(0,  file.getGPSCivilianNavigationMessages().size());
2041         Assertions.assertEquals(0,  file.getSystemTimeOffsets().size());
2042         Assertions.assertEquals(0,  file.getEarthOrientationParameters().size());
2043         Assertions.assertEquals(0,  file.getKlobucharMessages().size());
2044         Assertions.assertEquals(0,  file.getNequickGMessages().size());
2045         Assertions.assertEquals(0,  file.getBDGIMMessages().size());
2046 
2047         Assertions.assertEquals(0, file.getKlobucharMessages().size());
2048         Assertions.assertEquals(0, file.getNequickGMessages().size());
2049         Assertions.assertEquals(0, file.getBDGIMMessages().size());
2050 
2051         List<GLONASSNavigationMessage> list04 = file.getGlonassNavigationMessages("R04");
2052         Assertions.assertEquals(48, list04.size());
2053 
2054         Assertions.assertEquals(0.0,
2055                                 list04.get(0).getDate().durationFrom(new AbsoluteDate(2022, 1, 13, 0, 15, 0.0,
2056                                                                                       TimeScalesFactory.getUTC())),
2057                                 1.0e-10);
2058         Assertions.assertEquals(-995521.484375,              list04.get(0).getX(),       1.0e-6);
2059         Assertions.assertEquals(-3089.79511261,              list04.get(0).getXDot(),    1.0e-9);
2060         Assertions.assertEquals(0.0,                         list04.get(0).getXDotDot(), 1.0e-12);
2061         Assertions.assertEquals(10825711.4258,               list04.get(0).getY(),       1.0e-6);
2062         Assertions.assertEquals(-648.876190186,              list04.get(0).getYDot(),    1.0e-9);
2063         Assertions.assertEquals(-0.0,                        list04.get(0).getYDotDot(), 1.0e-12);
2064         Assertions.assertEquals(23099867.6758,               list04.get(0).getZ(),       1.0e-6);
2065         Assertions.assertEquals(169.882774353,               list04.get(0).getZDot(),    1.0e-9);
2066         Assertions.assertEquals(-1.86264514923e-06,          list04.get(0).getZDotDot(), 1.0e-12);
2067 
2068     }
2069 
2070     @Test
2071     public void testUnknownHeaderKey() throws IOException {
2072         try {
2073             final String ex = "/gnss/navigation/unknown-key-header.n";
2074             new RinexNavigationParser().
2075                             parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
2076             Assertions.fail("an exception should have been thrown");
2077         } catch (OrekitException oe) {
2078             Assertions.assertEquals(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
2079                                     oe.getSpecifier());
2080             Assertions.assertEquals(4,  oe.getParts()[0]);
2081         }
2082     }
2083 
2084     @Test
2085     public void testUnknownRinexVersion() throws IOException {
2086         final String ex = "/gnss/navigation/unknown-rinex-version.n";
2087         try {
2088             new RinexNavigationParser().
2089                             parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
2090             Assertions.fail("an exception should have been thrown");
2091         } catch (OrekitException oe) {
2092             Assertions.assertEquals(OrekitMessages.UNSUPPORTED_FILE_FORMAT_VERSION, oe.getSpecifier());
2093             Assertions.assertEquals(9.99, (Double) oe.getParts()[0], 1.0e-10);
2094             Assertions.assertEquals(ex, oe.getParts()[1]);
2095         }
2096     }
2097 
2098     @Test
2099     public void testUnknownEphemeris() throws IOException {
2100         try {
2101             final String ex = "/gnss/navigation/unknown-ephemeris.n";
2102             new RinexNavigationParser().
2103                             parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
2104             Assertions.fail("an exception should have been thrown");
2105         } catch (OrekitIllegalArgumentException oe) {
2106             Assertions.assertEquals(OrekitMessages.UNKNOWN_SATELLITE_SYSTEM, oe.getSpecifier());
2107             Assertions.assertEquals('Ω',  oe.getParts()[0]);
2108         }
2109     }
2110 
2111     @Test
2112     public void testDefensiveProgrammingExceptions() {
2113         // this test is really only meant to increase coverage with some reflection black magic
2114         // the methods tested here should not be called directly: they are overridden in concrete parsers
2115         try {
2116 
2117             // create ParseInfo
2118             final RinexNavigationParser rnp = new RinexNavigationParser();
2119             Class<?> parseInfoClass = null;
2120             for (Class<?> c : RinexNavigationParser.class.getDeclaredClasses()) {
2121                 if (c.getName().endsWith("ParseInfo")) {
2122                     parseInfoClass = c;
2123                 }
2124             }
2125             Constructor<?> ctr = parseInfoClass.getDeclaredConstructor(RinexNavigationParser.class, String.class);
2126             Object parseInfo = ctr.newInstance(rnp, "");
2127 
2128             Class<?> parserClass = null;
2129             for (Class<?> c : RinexNavigationParser.class.getDeclaredClasses()) {
2130                 if (c.getName().endsWith("SatelliteSystemLineParser")) {
2131                     parserClass = c;
2132                 }
2133             }
2134 
2135             // we select SBAS because it implements only the first 3 methods
2136             final Field sbasParserField = parserClass.getDeclaredField("SBAS");
2137 
2138             // get the methods inherited from base class
2139             for (String methodName : Arrays.asList("parseFourthBroadcastOrbit",
2140                                                    "parseFifthBroadcastOrbit",
2141                                                    "parseSixthBroadcastOrbit",
2142                                                    "parseSeventhBroadcastOrbit",
2143                                                    "parseEighthBroadcastOrbit",
2144                                                    "parseNinthBroadcastOrbit")) {
2145                 Method m = parserClass.getMethod(methodName, String.class, parseInfoClass);
2146                 m.setAccessible(true);
2147                 try {
2148                     // call the method, triggering the internal error exception
2149                     m.invoke(sbasParserField.get(null), "", parseInfo);
2150                     Assertions.fail("an exception should have been thrown");
2151                 } catch (InvocationTargetException e) {
2152                     Assertions.assertInstanceOf(OrekitInternalError.class, e.getCause());
2153                 }
2154             }
2155 
2156         } catch (NoSuchFieldException | NoSuchMethodException | SecurityException |
2157                  IllegalAccessException | IllegalArgumentException | InvocationTargetException |
2158                  InstantiationException e) {
2159             Assertions.fail(e.getLocalizedMessage());
2160         }
2161     }
2162 
2163     @Test
2164     public void testWrongFormat() throws IOException {
2165         try {
2166             final String ex = "/gnss/navigation/wrong-format.n";
2167             new RinexNavigationParser().
2168                             parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
2169             Assertions.fail("an exception should have been thrown");
2170         } catch (OrekitException oe) {
2171             Assertions.assertEquals(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
2172                                 oe.getSpecifier());
2173             Assertions.assertEquals(4,  oe.getParts()[0]);
2174         }
2175     }
2176 
2177     @Test
2178     public void testWrongTypeBeidou() throws IOException {
2179         doTestWrongType("/gnss/navigation/wrong-type-Beidou.n");
2180     }
2181 
2182     @Test
2183     public void testWrongTypeGalileo() throws IOException {
2184         doTestWrongType("/gnss/navigation/wrong-type-Galileo.n");
2185     }
2186 
2187     @Test
2188     public void testWrongTypeGlonass() throws IOException {
2189         doTestWrongType("/gnss/navigation/wrong-type-Glonass.n");
2190     }
2191 
2192     @Test
2193     public void testWrongTypeGPS() throws IOException {
2194         doTestWrongType("/gnss/navigation/wrong-type-GPS.n");
2195     }
2196 
2197     @Test
2198     public void testWrongTypeNavIC() throws IOException {
2199         doTestWrongType("/gnss/navigation/wrong-type-NavIC.n");
2200     }
2201 
2202     @Test
2203     public void testWrongTypeQZSS() throws IOException {
2204         doTestWrongType("/gnss/navigation/wrong-type-QZSS.n");
2205     }
2206 
2207     @Test
2208     public void testWrongTypeSBAS() throws IOException {
2209         doTestWrongType("/gnss/navigation/wrong-type-SBAS.n");
2210     }
2211 
2212     private void doTestWrongType(final String ex) throws IOException {
2213         try {
2214             new RinexNavigationParser().
2215                             parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
2216             Assertions.fail("an exception should have been thrown");
2217         } catch (OrekitException oe) {
2218             Assertions.assertEquals(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE, oe.getSpecifier());
2219             Assertions.assertTrue(((String) oe.getParts()[2]).endsWith("XXXX"));
2220         }
2221     }
2222 
2223     @Test
2224     public void testMissingRunBy305() throws IOException {
2225         final String ex = "/gnss/navigation/missing-run-by-305.n";
2226         try {
2227             new RinexNavigationParser().
2228                             parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
2229             Assertions.fail("an exception should have been thrown");
2230         } catch (OrekitException oe) {
2231             Assertions.assertEquals(OrekitMessages.INCOMPLETE_HEADER, oe.getSpecifier());
2232         }
2233     }
2234 
2235     @Test
2236     public void testMissingRunBy400() throws IOException {
2237         final String ex = "/gnss/navigation/missing-run-by-400.n";
2238         try {
2239             new RinexNavigationParser().
2240                             parse(new DataSource(ex, () -> getClass().getResourceAsStream(ex)));
2241             Assertions.fail("an exception should have been thrown");
2242         } catch (OrekitException oe) {
2243             Assertions.assertEquals(OrekitMessages.INCOMPLETE_HEADER, oe.getSpecifier());
2244             Assertions.assertEquals(ex, oe.getParts()[0]);
2245         }
2246     }
2247 
2248     private void checkFieldConversion(final RinexNavigation file) {
2249         for (final List<GalileoNavigationMessage> messages : file.getGalileoNavigationMessages().values()) {
2250             messages.forEach(GnssTestUtils::checkFieldConversion);
2251         }
2252        for (final List<QZSSLegacyNavigationMessage> messages : file.getQZSSLegacyNavigationMessages().values()) {
2253             messages.forEach(GnssTestUtils::checkFieldConversion);
2254         }
2255         for (final List<QZSSCivilianNavigationMessage> messages : file.getQZSSCivilianNavigationMessages().values()) {
2256             messages.forEach(GnssTestUtils::checkFieldConversion);
2257         }
2258         for (final List<BeidouLegacyNavigationMessage> messages : file.getBeidouLegacyNavigationMessages().values()) {
2259             messages.forEach(GnssTestUtils::checkFieldConversion);
2260         }
2261         for (final List<BeidouCivilianNavigationMessage> messages : file.getBeidouCivilianNavigationMessages().values()) {
2262             messages.forEach(GnssTestUtils::checkFieldConversion);
2263         }
2264         for (final List<NavICLegacyNavigationMessage> messages : file.getNavICLegacyNavigationMessages().values()) {
2265             messages.forEach(GnssTestUtils::checkFieldConversion);
2266         }
2267         for (final List<NavICL1NVNavigationMessage> messages : file.getNavICL1NVNavigationMessages().values()) {
2268             messages.forEach(GnssTestUtils::checkFieldConversion);
2269         }
2270         for (final List<GPSLegacyNavigationMessage> messages : file.getGPSLegacyNavigationMessages().values()) {
2271             messages.forEach(GnssTestUtils::checkFieldConversion);
2272         }
2273         for (final List<GPSCivilianNavigationMessage> messages : file.getGPSCivilianNavigationMessages().values()) {
2274             messages.forEach(GnssTestUtils::checkFieldConversion);
2275         }
2276 
2277     }
2278 
2279 }