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.gnss.metric.messages.ssr;
18  
19  import org.junit.jupiter.api.Assertions;
20  import org.junit.jupiter.api.Test;
21  import org.orekit.data.DataContext;
22  import org.orekit.errors.OrekitException;
23  import org.orekit.errors.OrekitMessages;
24  import org.orekit.gnss.metric.messages.ssr.subtype.SsrIm201;
25  import org.orekit.gnss.metric.messages.ssr.subtype.SsrIm201Data;
26  import org.orekit.gnss.metric.parser.ByteArrayEncodedMessage;
27  import org.orekit.gnss.metric.parser.EncodedMessage;
28  import org.orekit.gnss.metric.parser.IgsSsrMessagesParser;
29  
30  import java.util.ArrayList;
31  
32  public class SsrIm201Test {
33  
34      private double eps = 1.0e-13;
35  
36      @Test
37      public void testPerfectValue() {
38  
39          final String m = "010000100100" +                     // RTCM Message number: 1060
40                           "001" +                              // IGS SSR version
41                           "11001001" +                         // IGS Message number: 201 (VTEC)
42                           "01111110011000111111" +             // Epoch Time 1s
43                           "0101" +                             // SSR Update Interval
44                           "0" +                                // Multiple Message Indicator
45                           "0111" +                             // IOD SSR
46                           "0000111101101111" +                 // SSR Provider ID
47                           "0001" +                             // SSR Solution ID
48                           "000000001" +                        // VTEC Quality Indicator
49                           "00" +                               // Number of Ionospheric Layers: 1
50                           "01000001" +                         // Height of ionospheric layer
51                           "0010" +                             // Spherical Harmonics Degree
52                           "0001" +                             // Spherical Harmonics Order
53                           "0100101000101101"+                  // C00
54                           "0101011001101101"+                  // C10
55                           "0110101010001100"+                  // C20
56                           "0100001100101111"+                  // C30
57                           "0100101011101101"+                  // C11
58                           "0100101000111110"+                  // C21
59                           "0010100110101101"+                  // C31
60                           "0000111101101101"+                  // C22
61                           "0111101000101100"+                  // C32
62                           "0111101110101101"+                  // S11
63                           "0000101000101100"+                  // S21
64                           "0110101000101001"+                  // S31
65                           "0110101000100100"+                  // S22
66                           "001100100010110100000";             // S32
67  
68          final EncodedMessage message = new ByteArrayEncodedMessage(byteArrayFromBinary(m));
69          message.start();
70  
71          ArrayList<Integer> messages = new ArrayList<>();
72          messages.add(201);
73  
74          final SsrIm201 im201 = (SsrIm201) new IgsSsrMessagesParser(messages, DataContext.getDefault().getTimeScales()).
75                                 parse(message, false);
76  
77          // Ionospheric model
78          Assertions.assertNotNull(im201.getIonosphericModel());
79  
80          // Verify size
81          Assertions.assertEquals(1,                            im201.getData().size());
82  
83          // Verify header
84          Assertions.assertEquals(201,                          im201.getTypeCode());
85          Assertions.assertEquals(517695.0,                     im201.getHeader().getSsrEpoch1s(), eps);
86          Assertions.assertEquals(30.0,                         im201.getHeader().getSsrUpdateInterval(), eps);
87          Assertions.assertEquals(0,                            im201.getHeader().getSsrMultipleMessageIndicator());
88          Assertions.assertEquals(7,                            im201.getHeader().getIodSsr());
89          Assertions.assertEquals(3951,                         im201.getHeader().getSsrProviderId());
90          Assertions.assertEquals(1,                            im201.getHeader().getSsrSolutionId());
91          Assertions.assertEquals(0.05,                         im201.getHeader().getVtecQualityIndicator(), eps);
92          Assertions.assertEquals(1,                            im201.getHeader().getNumberOfIonosphericLayers());
93  
94          // Verify data
95          final SsrIm201Data data = im201.getData().get(0);
96          final double[][] cnm = data.getCnm();
97          final double[][] snm = data.getSnm();
98          Assertions.assertEquals(650000,            data.getHeightIonosphericLayer(), eps);
99          Assertions.assertEquals(3,                 data.getSphericalHarmonicsDegree());
100         Assertions.assertEquals(2,                 data.getSphericalHarmonicsOrder());
101         Assertions.assertEquals(94.945,            cnm[0][0], eps);
102         Assertions.assertEquals(110.625,           cnm[1][0], eps);
103         Assertions.assertEquals(136.380,           cnm[2][0], eps);
104         Assertions.assertEquals(85.995,            cnm[3][0], eps);
105         Assertions.assertEquals(0.0,               cnm[0][1], eps);
106         Assertions.assertEquals(95.905,            cnm[1][1], eps);
107         Assertions.assertEquals(95.030,            cnm[2][1], eps);
108         Assertions.assertEquals(53.345,            cnm[3][1], eps);
109         Assertions.assertEquals(0.0,               cnm[0][2], eps);
110         Assertions.assertEquals(0.0,               cnm[1][2], eps);
111         Assertions.assertEquals(19.745,            cnm[2][2], eps);
112         Assertions.assertEquals(156.380,           cnm[3][2], eps);
113         Assertions.assertEquals(0.0,               snm[0][0], eps);
114         Assertions.assertEquals(0.0,               snm[1][0], eps);
115         Assertions.assertEquals(0.0,               snm[2][0], eps);
116         Assertions.assertEquals(0.0,               snm[3][0], eps);
117         Assertions.assertEquals(0.0,               snm[0][1], eps);
118         Assertions.assertEquals(158.305,           snm[1][1], eps);
119         Assertions.assertEquals(13.020,            snm[2][1], eps);
120         Assertions.assertEquals(135.885,           snm[3][1], eps);
121         Assertions.assertEquals(0.0,               snm[0][2], eps);
122         Assertions.assertEquals(0.0,               snm[1][2], eps);
123         Assertions.assertEquals(135.860,           snm[2][2], eps);
124         Assertions.assertEquals(64.225,            snm[3][2], eps);
125 
126     }
127 
128     @Test
129     public void testPerfectValue2() {
130 
131         final String m = "010000100100" +                     // RTCM Message number: 1060
132                          "001" +                              // IGS SSR version
133                          "11001001" +                         // IGS Message number: 201 (VTEC)
134                          "01111110011000111111" +             // Epoch Time 1s
135                          "1110" +                             // SSR Update Interval
136                          "0" +                                // Multiple Message Indicator
137                          "0111" +                             // IOD SSR
138                          "0000111101101111" +                 // SSR Provider ID
139                          "0001" +                             // SSR Solution ID
140                          "000000001" +                        // VTEC Quality Indicator
141                          "00" +                               // Number of Ionospheric Layers: 1
142                          "01000001" +                         // Height of ionospheric layer
143                          "0010" +                             // Spherical Harmonics Degree
144                          "0001" +                             // Spherical Harmonics Order
145                          "0100101000101101"+                  // C00
146                          "0101011001101101"+                  // C10
147                          "0110101010001100"+                  // C20
148                          "0100001100101111"+                  // C30
149                          "0100101011101101"+                  // C11
150                          "0100101000111110"+                  // C21
151                          "0010100110101101"+                  // C31
152                          "0000111101101101"+                  // C22
153                          "0111101000101100"+                  // C32
154                          "0111101110101101"+                  // S11
155                          "0000101000101100"+                  // S21
156                          "0110101000101001"+                  // S31
157                          "0110101000100100"+                  // S22
158                          "001100100010110100000";             // S32
159 
160         final EncodedMessage message = new ByteArrayEncodedMessage(byteArrayFromBinary(m));
161         message.start();
162 
163         ArrayList<Integer> messages = new ArrayList<>();
164         messages.add(201);
165 
166         final SsrIm201 im201 = (SsrIm201) new IgsSsrMessagesParser(messages, DataContext.getDefault().getTimeScales()).
167                                parse(message, false);
168 
169         // Verify size
170         Assertions.assertEquals(1,                            im201.getData().size());
171 
172         // Verify header
173         Assertions.assertEquals(201,                          im201.getTypeCode());
174         Assertions.assertEquals(517695.0,                     im201.getHeader().getSsrEpoch1s(), eps);
175         Assertions.assertEquals(7200.0,                       im201.getHeader().getSsrUpdateInterval(), eps);
176         Assertions.assertEquals(0,                            im201.getHeader().getSsrMultipleMessageIndicator());
177         Assertions.assertEquals(7,                            im201.getHeader().getIodSsr());
178         Assertions.assertEquals(3951,                         im201.getHeader().getSsrProviderId());
179         Assertions.assertEquals(1,                            im201.getHeader().getSsrSolutionId());
180         Assertions.assertEquals(0.05,                         im201.getHeader().getVtecQualityIndicator(), eps);
181         Assertions.assertEquals(1,                            im201.getHeader().getNumberOfIonosphericLayers());
182 
183         // Verify data
184         final SsrIm201Data data = im201.getData().get(0);
185         final double[][] cnm = data.getCnm();
186         final double[][] snm = data.getSnm();
187         Assertions.assertEquals(650000,            data.getHeightIonosphericLayer(), eps);
188         Assertions.assertEquals(3,                 data.getSphericalHarmonicsDegree());
189         Assertions.assertEquals(2,                 data.getSphericalHarmonicsOrder());
190         Assertions.assertEquals(94.945,            cnm[0][0], eps);
191         Assertions.assertEquals(110.625,           cnm[1][0], eps);
192         Assertions.assertEquals(136.380,           cnm[2][0], eps);
193         Assertions.assertEquals(85.995,            cnm[3][0], eps);
194         Assertions.assertEquals(0.0,               cnm[0][1], eps);
195         Assertions.assertEquals(95.905,            cnm[1][1], eps);
196         Assertions.assertEquals(95.030,            cnm[2][1], eps);
197         Assertions.assertEquals(53.345,            cnm[3][1], eps);
198         Assertions.assertEquals(0.0,               cnm[0][2], eps);
199         Assertions.assertEquals(0.0,               cnm[1][2], eps);
200         Assertions.assertEquals(19.745,            cnm[2][2], eps);
201         Assertions.assertEquals(156.380,           cnm[3][2], eps);
202         Assertions.assertEquals(0.0,               snm[0][0], eps);
203         Assertions.assertEquals(0.0,               snm[1][0], eps);
204         Assertions.assertEquals(0.0,               snm[2][0], eps);
205         Assertions.assertEquals(0.0,               snm[3][0], eps);
206         Assertions.assertEquals(0.0,               snm[0][1], eps);
207         Assertions.assertEquals(158.305,           snm[1][1], eps);
208         Assertions.assertEquals(13.020,            snm[2][1], eps);
209         Assertions.assertEquals(135.885,           snm[3][1], eps);
210         Assertions.assertEquals(0.0,               snm[0][2], eps);
211         Assertions.assertEquals(0.0,               snm[1][2], eps);
212         Assertions.assertEquals(135.860,           snm[2][2], eps);
213         Assertions.assertEquals(64.225,            snm[3][2], eps);
214 
215     }
216 
217     @Test
218     public void testNullMessage() {
219 
220         final String m = "010000100100" +                     // RTCM Message number: 1060
221                         "001" +                              // IGS SSR version
222                         "11001001" +                         // IGS Message number: 201 (VTEC)
223                         "01111110011000111111" +             // Epoch Time 1s
224                         "0101" +                             // SSR Update Interval
225                         "0" +                                // Multiple Message Indicator
226                         "0111" +                             // IOD SSR
227                         "0000111101101111" +                 // SSR Provider ID
228                         "0001" +                             // SSR Solution ID
229                         "000000001" +                        // VTEC Quality Indicator
230                         "00" +                               // Number of Ionospheric Layers: 1
231                         "01000001" +                         // Height of ionospheric layer
232                         "0010" +                             // Spherical Harmonics Degree
233                         "0001" +                             // Spherical Harmonics Order
234                         "0100101000101101"+                  // C00
235                         "0101011001101101"+                  // C10
236                         "0110101010001100"+                  // C20
237                         "0100001100101111"+                  // C30
238                         "0100101011101101"+                  // C11
239                         "0100101000111110"+                  // C21
240                         "0010100110101101"+                  // C31
241                         "0000111101101101"+                  // C22
242                         "0111101000101100"+                  // C32
243                         "0111101110101101"+                  // S11
244                         "0000101000101100"+                  // S21
245                         "0110101000101001"+                  // S31
246                         "0110101000100100"+                  // S22
247                         "001100100010110100000";             // S32
248 
249 
250        final EncodedMessage message = new ByteArrayEncodedMessage(byteArrayFromBinary(m));
251        message.start();
252 
253        ArrayList<Integer> messages = new ArrayList<>();
254        messages.add(9999999);
255 
256        final SsrIm201 im201 = (SsrIm201) new IgsSsrMessagesParser(messages, DataContext.getDefault().getTimeScales()).
257                               parse(message, false);
258 
259        Assertions.assertNull(im201);
260     }
261 
262     @Test
263     public void testEmptyMessage() {
264         try {
265             final byte[] array = new byte[0];
266             final EncodedMessage emptyMessage = new ByteArrayEncodedMessage(array);
267             new IgsSsrMessagesParser(new ArrayList<>(), DataContext.getDefault().getTimeScales()).
268                 parse(emptyMessage, false);
269             Assertions.fail("an exception should have been thrown");
270         } catch (OrekitException oe) {
271             Assertions.assertEquals(OrekitMessages.END_OF_ENCODED_MESSAGE, oe.getSpecifier());
272         }
273 
274     }
275 
276     private byte[] byteArrayFromBinary(String radix2Value) {
277         final byte[] array = new byte[radix2Value.length() / 8];
278         for (int i = 0; i < array.length; ++i) {
279             for (int j = 0; j < 8; ++j) {
280                 if (radix2Value.charAt(8 * i + j) != '0') {
281                     array[i] |= 0x1 << (7 - j);
282                 }
283             }
284         }
285         return array;
286     }
287 
288 }