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.estimation.measurements.gnss;
18  
19  import org.junit.jupiter.api.Assertions;
20  import org.junit.jupiter.api.BeforeEach;
21  import org.junit.jupiter.api.Test;
22  import org.orekit.Utils;
23  import org.orekit.data.DataFilter;
24  import org.orekit.data.DataSource;
25  import org.orekit.data.GzipFilter;
26  import org.orekit.data.UnixCompressFilter;
27  import org.orekit.files.rinex.HatanakaCompressFilter;
28  import org.orekit.files.rinex.observation.ObservationDataSet;
29  import org.orekit.files.rinex.observation.RinexObservationParser;
30  import org.orekit.gnss.PredefinedGnssSignal;
31  import org.orekit.time.AbsoluteDate;
32  import org.orekit.time.TimeScalesFactory;
33  
34  import java.io.File;
35  import java.io.FileInputStream;
36  import java.io.IOException;
37  import java.net.URISyntaxException;
38  import java.nio.file.Files;
39  import java.util.Arrays;
40  import java.util.List;
41  
42  public class GeometryFreeCycleSlipDetectorTest {
43  
44      @BeforeEach
45      public void setUp() {
46          Utils.setDataRoot("regular-data");
47      }
48  
49      @Test
50      public void testTheBasicData() throws URISyntaxException, IOException {
51  
52          final String inputPath = GeometryFreeCycleSlipDetectorTest.class.getClassLoader().getResource("gnss/cycleSlip/shld0440.16d.Z").toURI().getPath();
53          final File input  = new File(inputPath);
54          String fileName = "shld0440.16d.Z";
55          DataSource nd = new DataSource(fileName,
56                                       () -> new FileInputStream(new File(input.getParentFile(), fileName)));
57          for (final DataFilter filter : Arrays.asList(new GzipFilter(),
58                                                       new UnixCompressFilter(),
59                                                       new HatanakaCompressFilter())) {
60              nd = filter.filter(nd);
61          }
62          final RinexObservationParser parser = new RinexObservationParser();
63          //RinexLoader  loader = loadCompressed("cycleSlip/shld0440.16d.Z");
64          final List<ObservationDataSet> obserDataSets = parser.parse(nd).getObservationDataSets();
65          GeometryFreeCycleSlipDetector slipDetectors =
66              new GeometryFreeCycleSlipDetector(31, 31.0, 10);
67          final List<CycleSlipDetectorResults> results = slipDetectors.detect(obserDataSets);
68          for(CycleSlipDetectorResults d: results) {
69              switch(getPrn(d)) {
70  
71                  case 1:
72                      Assertions.assertEquals(19.0, d.getEndDate(PredefinedGnssSignal.G01).durationFrom(new AbsoluteDate(2016,  2, 13,  5,  0,  0.0000000, TimeScalesFactory.getTAI())),1e-9);
73                      Assertions.assertEquals(19.0, d.getBeginDate(PredefinedGnssSignal.G01).durationFrom(new AbsoluteDate(2016,2, 13  ,2  ,8 ,30.0000000, TimeScalesFactory.getTAI())),1e-9);
74                      break;
75                  case 5:
76                      Assertions.assertEquals(19.0, d.getEndDate(PredefinedGnssSignal.G01).durationFrom(new AbsoluteDate(2016,  2, 13,  2, 48, 30.0000000, TimeScalesFactory.getTAI())),1e-9);
77                      Assertions.assertEquals(19.0, d.getBeginDate(PredefinedGnssSignal.G01).durationFrom(new AbsoluteDate(2016,2, 13  ,2  ,8 ,30.0000000, TimeScalesFactory.getTAI())),1e-9);
78                      break;
79  
80                  case 6:
81                      Assertions.assertEquals(19.0, d.getEndDate(PredefinedGnssSignal.G01).durationFrom(new AbsoluteDate(2016, 2, 13,  5,  0,  0.0000000, TimeScalesFactory.getTAI())),1e-9);
82                      Assertions.assertEquals(19.0, d.getBeginDate(PredefinedGnssSignal.G01).durationFrom(new AbsoluteDate(2016,  2, 13,  4, 15,  0.0000000, TimeScalesFactory.getTAI())),1e-9);
83                      break;
84  
85                  case 7:
86                      Assertions.assertEquals(19.0, d.getEndDate(PredefinedGnssSignal.G01).durationFrom(new AbsoluteDate(2016,  2, 13,  4, 27,  30.0000000, TimeScalesFactory.getTAI())),1e-9);
87                      Assertions.assertEquals(19.0, d.getBeginDate(PredefinedGnssSignal.G01).durationFrom(new AbsoluteDate(2016,2, 13  ,2  ,8 ,30.0000000, TimeScalesFactory.getTAI())),1e-9);
88                      break;
89  
90                  case 9:
91                      Assertions.assertEquals(19.0, d.getEndDate(PredefinedGnssSignal.G01).durationFrom(new AbsoluteDate(2016, 2, 13,  2, 45,  30.0000000, TimeScalesFactory.getTAI())),1e-9);
92                      Assertions.assertEquals(19.0, d.getBeginDate(PredefinedGnssSignal.G01).durationFrom(new AbsoluteDate(2016,2, 13  ,2  ,8 ,30.0000000, TimeScalesFactory.getTAI())),1e-9);
93                      break;
94  
95                  case 11:
96                      Assertions.assertEquals(19.0, d.getEndDate(PredefinedGnssSignal.G01).durationFrom(new AbsoluteDate(2016,  2, 13,  5,  0,  0.0000000, TimeScalesFactory.getTAI())),1e-9);
97                      Assertions.assertEquals(19.0, d.getBeginDate(PredefinedGnssSignal.G01).durationFrom(new AbsoluteDate(2016,2, 13  ,2  ,8 ,30.0000000, TimeScalesFactory.getTAI())),1e-9);
98                      break;
99  
100                 default:   break;
101             }
102         }
103     }
104 
105     @Test
106     public void testTimeCycleSlip() throws URISyntaxException, IOException {
107         final String inputPath = GeometryFreeCycleSlipDetectorTest.class.getClassLoader().getResource("gnss/cycleSlip/WithCycleSlip.16o").toURI().getPath();
108         final File input  = new File(inputPath);
109         String fileName = "WithCycleSlip.16o";
110         DataSource nd = new DataSource(fileName,
111                                      () -> Files.newInputStream(new File(input.getParentFile(), fileName).toPath()));
112         for (final DataFilter filter : Arrays.asList(new GzipFilter(),
113                                                      new UnixCompressFilter(),
114                                                      new HatanakaCompressFilter())) {
115             nd = filter.filter(nd);
116         }
117         final RinexObservationParser parser = new RinexObservationParser();
118         final List<ObservationDataSet>  obserDataSets = parser.parse(nd).getObservationDataSets();
119         //With dt = 31 s, cycle slip should not exist, a very huge threshold is used to not detect cycle-slip
120         GeometryFreeCycleSlipDetector slipDetectors =
121             new GeometryFreeCycleSlipDetector(31, 31.0, 10);
122         final List<CycleSlipDetectorResults> results = slipDetectors.detect(obserDataSets);
123         for(CycleSlipDetectorResults d: results) {
124             Assertions.assertFalse(d.getCycleSlipMap().get(PredefinedGnssSignal.G01).isEmpty());
125         }
126         //With dt = 29 s, a cycle-slip should occur at each new measurement (97 times)
127         GeometryFreeCycleSlipDetector slipDetectors2 =
128                         new GeometryFreeCycleSlipDetector(29, 29.0, 10);
129         final List<CycleSlipDetectorResults> results2 = slipDetectors2.detect(obserDataSets);
130         for(CycleSlipDetectorResults d: results2) {
131             Assertions.assertEquals(97, d.getCycleSlipMap().get(PredefinedGnssSignal.G01).size());
132         }
133     }
134 
135     @Test
136     public void testCycleSlip() throws URISyntaxException, IOException {
137         final String inputPath = GeometryFreeCycleSlipDetectorTest.class.getClassLoader().getResource("gnss/cycleSlip/WithCycleSlip.16o").toURI().getPath();
138         final File input  = new File(inputPath);
139         String fileName = "WithCycleSlip.16o";
140         DataSource nd = new DataSource(fileName,
141                                      () -> Files.newInputStream(new File(input.getParentFile(), fileName).toPath()));
142         for (final DataFilter filter : Arrays.asList(new GzipFilter(),
143                                                      new UnixCompressFilter(),
144                                                      new HatanakaCompressFilter())) {
145             nd = filter.filter(nd);
146         }
147         final RinexObservationParser parser = new RinexObservationParser();
148         final List<ObservationDataSet> obserDataSets = parser.parse(nd).getObservationDataSets();
149         //With dt = 31 s, cycle slip for time gap cannot be detected (see previous test).
150         //We use T0 = 60s for threshold time constant as advice from Navipedia page.
151         GeometryFreeCycleSlipDetector slipDetectors =
152             new GeometryFreeCycleSlipDetector(31, 31.0, 9);
153         final List<CycleSlipDetectorResults> results = slipDetectors.detect(obserDataSets);
154         //According to excel graph, cycle-slip occur at 1 h 59m 43s
155         AbsoluteDate trueDate = new AbsoluteDate(2016, 2, 13, 1, 59, 43, TimeScalesFactory.getUTC());
156         final int size = results.get(0).getCycleSlipMap().get(PredefinedGnssSignal.G01).size();
157         Assertions.assertEquals(1, size);
158         final AbsoluteDate computedDate = results.get(0).getCycleSlipMap().get(PredefinedGnssSignal.G01).get(0);
159         Assertions.assertEquals(0.0, trueDate.durationFrom(computedDate),  1e-9);
160    }
161 
162     private int getPrn(final CycleSlipDetectorResults d) {
163 
164         if(d.getSatelliteName().substring(6).compareTo("1")==0) {return 1;}
165         if(d.getSatelliteName().substring(6).compareTo("2")==0) {return 2;}
166         if(d.getSatelliteName().substring(6).compareTo("3")==0) {return 3;}
167         if(d.getSatelliteName().substring(6).compareTo("4")==0) {return 4;}
168         if(d.getSatelliteName().substring(6).compareTo("5")==0) {return 5;}
169         if(d.getSatelliteName().substring(6).compareTo("6")==0) {return 6;}
170         if(d.getSatelliteName().substring(6).compareTo("7")==0) {return 7;}
171         if(d.getSatelliteName().substring(6).compareTo("8")==0) {return 8;}
172         if(d.getSatelliteName().substring(6).compareTo("9")==0) {return 9;}
173         if(d.getSatelliteName().substring(6).compareTo("10")==0) {return 10;}
174         if(d.getSatelliteName().substring(6).compareTo("11")==0) {return 11;}
175         if(d.getSatelliteName().substring(6).compareTo("12")==0) {return 12;}
176         if(d.getSatelliteName().substring(6).compareTo("13")==0) {return 13;}
177         if(d.getSatelliteName().substring(6).compareTo("14")==0) {return 14;}
178         if(d.getSatelliteName().substring(6).compareTo("15")==0) {return 15;}
179         if(d.getSatelliteName().substring(6).compareTo("16")==0) {return 16;}
180         if(d.getSatelliteName().substring(6).compareTo("17")==0) {return 17;}
181         if(d.getSatelliteName().substring(6).compareTo("18")==0) {return 18;}
182         if(d.getSatelliteName().substring(6).compareTo("19")==0) {return 19;}
183         if(d.getSatelliteName().substring(6).compareTo("20")==0) {return 20;}
184         if(d.getSatelliteName().substring(6).compareTo("21")==0) {return 21;}
185         if(d.getSatelliteName().substring(6).compareTo("22")==0) {return 22;}
186         if(d.getSatelliteName().substring(6).compareTo("23")==0) {return 23;}
187         if(d.getSatelliteName().substring(6).compareTo("24")==0) {return 24;}
188         if(d.getSatelliteName().substring(6).compareTo("25")==0) {return 25;}
189         if(d.getSatelliteName().substring(6).compareTo("26")==0) {return 26;}
190         if(d.getSatelliteName().substring(6).compareTo("27")==0) {return 27;}
191         if(d.getSatelliteName().substring(6).compareTo("28")==0) {return 28;}
192         if(d.getSatelliteName().substring(6).compareTo("29")==0) {return 29;}
193         if(d.getSatelliteName().substring(6).compareTo("30")==0) {return 30;}
194         if(d.getSatelliteName().substring(6).compareTo("31")==0) {return 31;}
195         else {return 32;}
196 
197     }
198 
199 }