1 //==============================================================================
2 //
3 // This file is part of GPSTk, the GPS Toolkit.
4 //
5 // The GPSTk is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published
7 // by the Free Software Foundation; either version 3.0 of the License, or
8 // any later version.
9 //
10 // The GPSTk is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with GPSTk; if not, write to the Free Software Foundation,
17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 // This software was developed by Applied Research Laboratories at the
20 // University of Texas at Austin.
21 // Copyright 2004-2020, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24
25 //==============================================================================
26 //
27 // This software was developed by Applied Research Laboratories at the
28 // University of Texas at Austin, under contract to an agency or agencies
29 // within the U.S. Department of Defense. The U.S. Government retains all
30 // rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 // Pursuant to DoD Directive 523024
33 //
34 // DISTRIBUTION STATEMENT A: This software has been approved for public
35 // release, distribution is unlimited.
36 //
37 //==============================================================================
38
39 #include "EngNav.hpp"
40 #include "TestUtil.hpp"
41 #include "TimeString.hpp"
42 #include "GPSWeekSecond.hpp"
43 #include <math.h>
44 #include <iostream>
45
46 using namespace std;
47
48 class EngNav_T
49 {
50 public:
EngNav_T()51 EngNav_T() // Default Constructor, set the precision value
52 {
53 // lower precision value, accuracy of some values is lost in
54 // binary conversion
55 eps = 1E-10;
56 b10 = 10;
57 }
~EngNav_T()58 ~EngNav_T() {}
59
60
getSubframePatternTest(void)61 unsigned getSubframePatternTest(void)
62 {
63 TUDEF("EngNav", "getSubframePattern");
64 string testMesg;
65
66 const uint32_t subframe1P[10] =
67 { 0x22c000e4, 0x215ba160, 0x00180012, 0x1fffffc0, 0x3fffffc3,
68 0x3ffffffc, 0x3fffc009, 0x16d904f0, 0x003fdbac, 0x247c139c };
69 const uint32_t subframe2P[10] =
70 { 0x22c000e4, 0x215bc2f0, 0x16c2eb4d, 0x032c41a0, 0x26abc7e0,
71 0x0289c0dd, 0x0d5ecc38, 0x036b6842, 0x034f4df0, 0x1904c0b4 };
72 const uint32_t subframe3P[10] =
73 { 0x22c000e4, 0x215be378, 0x3ffcc344, 0x1a8441f1, 0x3ff80b74,
74 0x1c8deb5e, 0x0a34d52d, 0x14a5013e, 0x3fee8c2f, 0x16c35c80 };
75
76 testMesg = "Subframe Pattern obtained was incorrect";
77 TUASSERTE(short,1,gpstk::EngNav::getSubframePattern(subframe1P));
78 TUASSERTE(short,2,gpstk::EngNav::getSubframePattern(subframe2P));
79 TUASSERTE(short,3,gpstk::EngNav::getSubframePattern(subframe3P));
80
81 TURETURN();
82 }
83
84
computeParityTest(void)85 unsigned computeParityTest(void)
86 {
87 TUDEF("EngNav", "Compute Parity");
88 string testMesg;
89
90 // data taken from
91 // http://www.gpscreations.com/NewFiles/GPS%20Parity%20Checking.pdf
92
93 //Feed in 30bit word with 0's as the parity
94 uint32_t zero = 0x00000000;
95 uint32_t data1 = 0x22C000C0;
96 uint32_t data2 = 0x17344000;
97 uint32_t data3 = 0x2142EF00;
98 uint32_t data4 = 0x15E67180;
99
100 testMesg = "Parity computed was incorrect";
101 TUASSERTE(uint32_t, 0x24, gpstk::EngNav::computeParity(data1, zero));
102
103 data1 |= 0x24;
104
105 TUASSERTE(uint32_t, 0x22, gpstk::EngNav::computeParity(data2, data1));
106
107 data2 |= 0x22;
108
109 TUASSERTE(uint32_t, 0x1b, gpstk::EngNav::computeParity(data3, data2));
110
111 data3 |= 0x1B;
112
113 TUASSERTE(uint32_t, 0x02,
114 gpstk::EngNav::computeParity(data4, data3, false));
115
116 TURETURN();
117 }
118
fixParityTest(void)119 unsigned fixParityTest(void)
120 {
121 TUDEF("EngNav", "Fix Parity");
122 string testMesg;
123
124 // 3 cases of regular parity computation
125 uint32_t data1 = 0x22C000C0;
126 uint32_t data2 = 0x17344000;
127 uint32_t data3 = 0x2142EF00;
128 uint32_t data4 = 0x15E67180;
129 // test word with the non-informational parity bits, set to 0
130 uint32_t data5 = 0x32098100; //taken from EngEphemeris
131 uint32_t CompareData1 = 0x22C000C0 | 0x0000024;
132 uint32_t CompareData2 = 0x17344000 | 0x0000022;
133 uint32_t CompareData3 = 0x2142EF00 | 0x000001B;
134 uint32_t CompareData4 = 0x15E67180 | 0x0000002;
135 // non-informational parity bits included in this
136 uint32_t CompareData5 = 0x32098100 | 0x00000DC;
137
138 // (word to overwrite with parity, previous word, add 2
139 // parity computation bits(word 2 & 10))
140 testMesg = "Parity computed is incorrect";
141 TUASSERTE(uint32_t, CompareData1,
142 gpstk::EngNav::fixParity(data1, 0, false));
143 TUASSERTE(uint32_t, CompareData2,
144 gpstk::EngNav::fixParity(data2, CompareData1, false));
145 TUASSERTE(uint32_t, CompareData3,
146 gpstk::EngNav::fixParity(data3, CompareData2, false));
147 TUASSERTE(uint32_t, CompareData4,
148 gpstk::EngNav::fixParity(data4, CompareData3, false, false));
149 TUASSERTE(uint32_t, CompareData5,
150 gpstk::EngNav::fixParity(data5, 0, true));
151
152 TURETURN();
153 }
154
155
checkParityTest(void)156 unsigned checkParityTest(void)
157 {
158 TUDEF("EngNav", "Check Parity");
159 string testMesg;
160
161 //Data is from EngEphemeris addSubframe test
162
163 const uint32_t subframe1P[10] =
164 { 0x22c000e4, 0x215ba160, 0x00180012, 0x1fffffc0, 0x3fffffc3,
165 0x3fffffff, 0x3fffc035, 0x16d904f3, 0x003fdb90, 0x247c1339 };
166 const uint32_t subframe2P[10] =
167 { 0x22c000e4, 0x215bc2f0, 0x16c2eb4d, 0x032c41a3, 0x26abc7dc,
168 0x0289c0dd, 0x0d5ecc3b, 0x0036b67f, 0x034f4de5, 0x1904c0a1 };
169 const uint32_t subframe3P[10] =
170 { 0x22c000e4, 0x215be378, 0x3ffcc344, 0x1a8441f1, 0x3ff80b61,
171 0x1c8deb4b, 0x0a34d530, 0x14a50138, 0x3fee8c2f, 0x16c35c83 };
172
173 testMesg = "Parity computed is incorrect";
174 testFramework.assert(gpstk::EngNav::checkParity(subframe1P, false),
175 testMesg, __LINE__);
176 testFramework.assert(gpstk::EngNav::checkParity(subframe2P, false),
177 testMesg, __LINE__);
178 testFramework.assert(gpstk::EngNav::checkParity(subframe3P, false),
179 testMesg, __LINE__);
180
181 TURETURN();
182 }
183
184
getHOWTimeTest(void)185 unsigned getHOWTimeTest(void)
186 {
187 //wrong, fix later
188 TUDEF("EngNav", "getHOWTime");
189 string testMesg;
190
191 uint32_t how1 = 0x215ba160;
192 uint32_t how2 = 0x215bc2f0;
193 uint32_t how3 = 0x215be378;
194
195 testMesg = "Returned TOW time from the HOW is incorrect";
196 TUASSERTE(unsigned long, 409902, gpstk::EngNav::getHOWTime(how1));
197 TUASSERTE(unsigned long, 409908, gpstk::EngNav::getHOWTime(how2));
198 TUASSERTE(unsigned long, 409914, gpstk::EngNav::getHOWTime(how3));
199
200 TURETURN();
201 }
202
203
getSFIDTest(void)204 unsigned getSFIDTest(void)
205 {
206 TUDEF("EngNav", "getSFID");
207 string testMesg;
208
209 uint32_t how1 = 0x215ba160;
210 uint32_t how2 = 0x215bc2f0;
211 uint32_t how3 = 0x215be378;
212
213 testMesg = "Returned subframe ID was incorrect";
214 TUASSERTE(short, 1, gpstk::EngNav::getSFID(how1));
215 TUASSERTE(short, 2, gpstk::EngNav::getSFID(how2));
216 TUASSERTE(short, 3, gpstk::EngNav::getSFID(how3));
217
218 TURETURN();
219 }
220
221 //converts subframe binary data to FIC.
subframeConvertTest(void)222 unsigned subframeConvertTest(void) //calls getsubframePattern and convertQuant
223 {
224 TUDEF("EngNav", "Subframe Convert");
225 string testMesg;
226
227 double output1[60], output2[60], output3[60];
228 const uint32_t subframe1P[10] =
229 { 0x22c000e4, 0x215ba160, 0x00180012, 0x1fffffc0, 0x3fffffc3,
230 0x3ffffffc, 0x3fffc009, 0x16d904f0, 0x003fdbac, 0x247c139c };
231 const uint32_t subframe2P[10] =
232 { 0x22c000e4, 0x215bc2f0, 0x16c2eb4d, 0x032c41a0, 0x26abc7e0,
233 0x0289c0dd, 0x0d5ecc38, 0x036b6842, 0x034f4df0, 0x1904c0b4 };
234 const uint32_t subframe3P[10] =
235 { 0x22c000e4, 0x215be378, 0x3ffcc344, 0x1a8441f1, 0x3ff80b76,
236 0x1c8deb5e, 0x0a34d52d, 0x14a5013e, 0x3fee8c2f, 0x16c35c80 };
237 gpstk::EngNav EngNavThing;
238
239 testMesg = "Subframe Convert function failed";
240 testFramework.assert(
241 EngNavThing.subframeConvert(subframe1P, 1025, output1),
242 testMesg, __LINE__);
243
244 testMesg = "TLM Preamble is incorrect";
245 testFramework.assert(output1[0] == 0x8B, testMesg, __LINE__);
246 testMesg = "TLM Message is incorrect";
247 testFramework.assert(output1[1] == 0, testMesg, __LINE__);
248 testMesg = "How Word (time?) is incorrect";
249 testFramework.assert(output1[2] == 409902, testMesg, __LINE__);
250 testMesg = "Alert flag is incorrect";
251 testFramework.assert(output1[3] == 0, testMesg, __LINE__);
252 testMesg = "Subframe ID is incorrect";
253 testFramework.assert(output1[4] == 1, testMesg, __LINE__);
254 testMesg = "Transmit Week Number is incorrect";
255 testFramework.assert(output1[5] == 1025, testMesg, __LINE__);
256 testMesg = "L2 code flag is incorrect";
257 testFramework.assert(output1[6] == 2, testMesg, __LINE__);
258 testMesg = "SV Accuracy is incorrect";
259 testFramework.assert(output1[7] == 0, testMesg, __LINE__);
260 testMesg = "SV Health is incorrect";
261 testFramework.assert(output1[8] == 0, testMesg, __LINE__);
262 testMesg = "IODC flag is incorrect";
263 testFramework.assert(output1[9]/2048 == 0x5B, testMesg,
264 __LINE__); //AODC to IODC conversion, pg 15 of GR-SGL-99-14 FIC Definiton file
265 testMesg = "L2 code flag is incorrect";
266 testFramework.assert(output1[10] == 0, testMesg, __LINE__);
267 testMesg = "Group Delay Differential is incorrect";
268 testFramework.assert(output1[11] == 0, testMesg, __LINE__);
269 testMesg = "Clock Epoch is incorrect";
270 testFramework.assert(output1[12] == 409904, testMesg, __LINE__);
271 testMesg = "Clock Drift Rate is incorrect";
272 testFramework.assert(output1[13] == 0, testMesg, __LINE__);
273 testMesg = "Clock Drift is incorrect";
274 testFramework.assert(abs(output1[14] + .165982783074E-10)*pow(b10,10) < eps,
275 testMesg, __LINE__);
276 testMesg = "Clock Bias is incorrect";
277 testFramework.assert(abs(output1[15] + .839701388031E-03)*pow(b10,3) < eps,
278 testMesg, __LINE__);
279
280 testMesg = "Subframe Convert function failed";
281 testFramework.assert(EngNavThing.subframeConvert(subframe2P, 1025, output2),
282 testMesg, __LINE__);
283
284 testMesg = "TLM Preamble is incorrect";
285 testFramework.assert(output2[0] == 0x8B, testMesg, __LINE__);
286 testMesg = "TLM Message is incorrect";
287 testFramework.assert(output2[1] == 0, testMesg, __LINE__);
288 testMesg = "How Word (time?) is incorrect";
289 testFramework.assert(output2[2] == 409908, testMesg, __LINE__);
290 testMesg = "Alert flag is incorrect";
291 testFramework.assert(output2[3] == 0, testMesg, __LINE__);
292 testMesg = "Subframe ID is incorrect";
293 testFramework.assert(output2[4] == 2, testMesg, __LINE__);
294 testMesg = "IODE is incorrect";
295 testFramework.assert(output2[5]/2048 == 91, testMesg,
296 __LINE__); //AODE to IODE conversion, pg 15 of GR-SGL-99-14 FIC Definiton file
297 testMesg = "CRS is incorrect";
298 testFramework.assert(abs(output2[6] - 93.40625) < eps, testMesg, __LINE__);
299 testMesg = "Correction to Mean Motion is incorrect";
300 testFramework.assert(abs(output2[7] - (.11604054784E-8))*pow(b10,8) < eps,
301 testMesg, __LINE__);
302 testMesg = "Mean Anomaly at Epoch is incorrect";
303 testFramework.assert(abs(output2[8] - 0.162092304801) < eps, testMesg,
304 __LINE__);
305 testMesg = "CUC is incorrect";
306 testFramework.assert(abs(output2[9] - .484101474285E-5)*pow(b10,5) < eps,
307 testMesg, __LINE__);
308 testMesg = "Eccentricity is incorrect";
309 testFramework.assert(abs(output2[10] - .626740418375E-2)*pow(b10,2) < eps,
310 testMesg, __LINE__);
311 testMesg = "CUS is incorrect";
312 testFramework.assert(abs(output2[11] - .652112066746E-5)*pow(b10,5) < eps,
313 testMesg, __LINE__);
314 testMesg = "Square Root of Semi-Major Axis is incorrect";
315 testFramework.assert(abs(output2[12] - .515365489006E4)*pow(b10,-4) < eps,
316 testMesg, __LINE__);
317 testMesg = "Time of Epoch is incorrect";
318 testFramework.assert(output2[13] == 409904, testMesg, __LINE__);
319 testMesg = "Fit interval flag is incorrect";
320 testFramework.assert(output2[14] == 0, testMesg, __LINE__);
321
322 testMesg = "Subframe Convert function failed";
323 testFramework.assert(EngNavThing.subframeConvert(subframe3P, 1025, output3),
324 testMesg, __LINE__);
325
326 testMesg = "TLM Preamble is incorrect";
327 testFramework.assert(output3[0] == 0x8B, testMesg, __LINE__);
328 testMesg = "TLM Message is incorrect";
329 testFramework.assert(output3[1] == 0, testMesg, __LINE__);
330 testMesg = "How Word (time?) is incorrect";
331 testFramework.assert(output3[2] == 409914, testMesg, __LINE__);
332 testMesg = "Alert flag is incorrect";
333 testFramework.assert(output3[3] == 0, testMesg, __LINE__);
334 testMesg = "Subframe ID is incorrect";
335 testFramework.assert(output3[4] == 3, testMesg, __LINE__);
336 testMesg = "CIC is incorrect";
337 testFramework.assert(abs(output3[5] + .242143869400E-7)*pow(b10,7) < eps,
338 testMesg, __LINE__);
339 testMesg = "Right ascension of ascending node is incorrect";
340 testFramework.assert(abs(output3[6] - .329237003460) < eps, testMesg,
341 __LINE__);
342 testMesg = "CIS is incorrect";
343 testFramework.assert(abs(output3[7] + .596046447754E-7)*pow(b10,7) < eps,
344 testMesg, __LINE__);
345 testMesg = "Inclination is incorrect";
346 testFramework.assert(abs(output3[8] - 1.11541663136) < eps, testMesg,
347 __LINE__);
348 testMesg = "CRC is incorrect";
349 testFramework.assert(abs(output3[9] - 326.59375)*pow(b10, -3) < eps, testMesg,
350 __LINE__);
351 testMesg =
352 "Arguement of perigee is incorrect"; // All other values needed to be converted to semi-circles, IDK why this one wasn't
353 testFramework.assert(abs(output3[10] - 2.06958726335)*pow(b10, -1) < eps,
354 testMesg, __LINE__);
355 testMesg = "Right ascension of ascending node time derivative is incorrect";
356 testFramework.assert(abs(output3[11] + .638312302555E-8)*pow(b10,10) < eps,
357 testMesg, __LINE__);
358 testMesg = "AODE? is incorrect";
359 testFramework.assert(output3[12]/2048 == 91, testMesg, __LINE__);
360 testMesg = "Inclination time derivative is incorrect";
361 testFramework.assert(abs(output3[13] - .307155651409E-9)*pow(b10,9) < eps,
362 testMesg, __LINE__);//AODE to IODE conversion, pg 15 of GR-SGL-99-14 FIC Definiton file
363
364 TURETURN();
365 }
366
367
368 /** Reads a subframe 2 along with truth data from a file and
369 * makes sure everything matches up. */
nmctValidityTest()370 unsigned nmctValidityTest()
371 {
372 using gpstk::StringUtils::x2uint;
373 using gpstk::StringUtils::word;
374 using gpstk::StringUtils::numWords;
375 using gpstk::StringUtils::asUnsigned;
376 using gpstk::StringUtils::asDouble;
377 TUDEF("EngNav", "getNMCTValidity");
378 // Here's the input file to look at for the actual test data
379 string infilename = gpstk::getPathData() +
380 gpstk::getFileSep() + "test_getNMCTValidity.txt";
381 ifstream infile(infilename.c_str());
382 string line;
383 uint32_t sf2[10];
384 unsigned lineNo = 0;
385 unsigned howWeek;
386 uint32_t aodoExp, aodoGot;
387 gpstk::CommonTime tnmctExp, tnmctGot, toeExp, toeGot, totGot;
388 bool gotData = false; // make sure something was processed
389 // tmp values for reading from file
390 unsigned tmpU;
391 double tmpD;
392 while (infile)
393 {
394 lineNo++;
395 getline(infile, line);
396 if ((line[0] == '#') || (numWords(line) != 16))
397 continue;
398 //cout << "Line # " << lineNo << endl;
399 gotData = true;
400 // process the subframe data
401 for (unsigned wordnum = 0; wordnum < 10; wordnum++)
402 {
403 sf2[wordnum] = x2uint(word(line, wordnum));
404 }
405 // process the week number and expected values
406 howWeek = asUnsigned(word(line, 10));
407 aodoExp = asUnsigned(word(line, 11));
408 tmpU = asUnsigned(word(line, 12));
409 tmpD = asDouble(word(line, 13));
410 tnmctExp = gpstk::GPSWeekSecond(tmpU, tmpD);
411 tmpU = asUnsigned(word(line, 14));
412 tmpD = asDouble(word(line, 15));
413 toeExp = gpstk::GPSWeekSecond(tmpU, tmpD);
414 // Compare the truth data with the results from the function
415 if (aodoExp == 27900)
416 {
417 testFramework.assert(
418 !gpstk::EngNav::getNMCTValidity(
419 sf2, howWeek, aodoGot, tnmctGot, toeGot, totGot),
420 "Unexpected return value", __LINE__);
421 TUASSERTE(uint32_t, aodoExp, aodoGot);
422 TUASSERTE(gpstk::CommonTime, toeExp, toeGot);
423 }
424 else
425 {
426 testFramework.assert(
427 gpstk::EngNav::getNMCTValidity(
428 sf2, howWeek, aodoGot, tnmctGot, toeGot, totGot),
429 "Unexpected return value", __LINE__);
430 TUASSERTE(uint32_t, aodoExp, aodoGot);
431 TUASSERTE(gpstk::CommonTime, tnmctExp, tnmctGot);
432 TUASSERTE(gpstk::CommonTime, toeExp, toeGot);
433 }
434 }
435 testFramework.assert(gotData, "Did not test any NMCT data", __LINE__);
436
437 TURETURN();
438 }
439
440
441 private:
442 double eps;
443 double b10;
444 };
445
446
main()447 int main() //Main function to initialize and run all tests above
448 {
449 EngNav_T testClass;
450 unsigned errorTotal = 0;
451
452 errorTotal += testClass.computeParityTest();
453 errorTotal += testClass.fixParityTest();
454 errorTotal += testClass.getHOWTimeTest();
455 errorTotal += testClass.getSFIDTest();
456 errorTotal += testClass.checkParityTest();
457 errorTotal += testClass.getSubframePatternTest();
458 errorTotal += testClass.subframeConvertTest();
459 errorTotal += testClass.nmctValidityTest();
460
461 cout << "Total Failures for " << __FILE__ << ": " << errorTotal
462 << endl;
463
464 return errorTotal;
465 }
466