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 <iostream>
40 #include "TestUtil.hpp"
41 #include "OrbElem.hpp"
42 
43 using namespace std;
44 
45 /** Threshold for how much different our velocities can be between
46  * being computed directly via svXvt and computed via differencing
47  * svXvt positions over time. */
48 double velDiffThresh = 0.0008;
49 
50 // we have to make a class that isn't abstract to test with.
51 class OrbElemNonAbstract : public gpstk::OrbElem
52 {
53 public:
54    OrbElemNonAbstract() = default;
clone() const55    gpstk::OrbElem* clone() const override
56    { return nullptr; }
getName() const57    std::string getName() const override
58    { return "foo"; }
getNameLong() const59    std::string getNameLong() const override
60    { return "bar"; }
adjustBeginningValidity()61    void adjustBeginningValidity() override
62    { GPSTK_ASSERT(false); } // don't call this.
dumpTerse(std::ostream & s=std::cout) const63    void dumpTerse(std::ostream& s = std::cout) const
64       override
65    { s << "terse" << endl; }
66 };
67 
68 
69 class OrbElem_T
70 {
71 public:
72    unsigned testSvXvt();
73 };
74 
75 
76 unsigned OrbElem_T ::
testSvXvt()77 testSvXvt()
78 {
79    TUDEF("OrbElem", "svXvt");
80       // Hard code orbital parameters mostly so we can copy and paste
81       // the data into other similar tests with minimal changes.
82    OrbElemNonAbstract oe;
83    oe.Cuc    = -.324845314026e-05;
84    oe.Cus    =  .101532787085e-04;
85    oe.Crc    =  .168968750000e+03;
86    oe.Crs    = -.646250000000e+02;
87    oe.Cic    =  .320374965668e-06;
88    oe.Cis    =  .117346644402e-06;
89    oe.M0     = -.136404614938e+01;
90    oe.dn     =  .489591822036e-08;
91    oe.dndot  = 0;
92    oe.ecc    =  .146582192974e-01;
93    oe.A      =  .515359719276e+04 * .515359719276e+04;
94    oe.Adot   = 0;
95    oe.OMEGA0 = -.296605403382e+01;
96    oe.i0     =  .941587707856e+00;
97    oe.w      = -.224753761329e+01;
98    oe.OMEGAdot = -.804390648956e-08;
99    oe.idot     =  .789318592573e-10;
100    oe.ctToc    = gpstk::CivilTime(2015,7,19,1,59,28.0,gpstk::TimeSystem::GPS);
101    oe.af0      =  .579084269702e-03;
102    oe.af1      =  .227373675443e-11;
103    oe.af2      =  .000000000000e+00;
104    oe.dataLoadedFlag = true;
105    oe.satID = gpstk::SatID(2, gpstk::SatelliteSystem::GPS);
106    oe.ctToe    = gpstk::GPSWeekSecond(1854,.716800000000e+04);
107    oe.setHealthy(true);
108       // iode .700000000000e+01
109       // codes on L2 .100000000000e+01
110       // L2 P data .000000000000e+00
111       // sv accuracy .240000000000e+01
112       // sv health .000000000000e+00
113       // tgd -.204890966415e-07
114       // iodc .700000000000e+01
115       // xmit time .360000000000e+04
116       // fit int .400000000000e+01
117    bool testFailed = false;
118    try
119    {
120          // first compute Xvt
121       static const unsigned SECONDS = 7200;
122       gpstk::Xvt zeroth_array[SECONDS];
123       for (unsigned ii = 0; ii < SECONDS; ii++)
124       {
125          zeroth_array[ii] = oe.svXvt(oe.ctToc + ii);
126       }
127          // then compute first derivative of position, i.e. velocity
128       gpstk::Triple deriv[SECONDS];
129       double h = 1; // time step size in seconds
130       for (unsigned ii = 0; ii < SECONDS; ii++)
131       {
132          if (ii == 0)
133          {
134             deriv[ii] = (1/h)*(-1.5*zeroth_array[ii].getPos() +
135                                2.0*zeroth_array[ii+1].getPos() -
136                                0.5*zeroth_array[ii+2].getPos());
137          }
138          else if ((ii == 1) || (ii == (SECONDS-2)))
139          {
140             deriv[ii] = (1/h)*(-0.5*zeroth_array[ii-1].getPos() +
141                                0.5*zeroth_array[ii+1].getPos());
142          }
143          else if (ii == (SECONDS-1))
144          {
145             deriv[ii] = (1/h)*(0.5*zeroth_array[ii-2].getPos() -
146                                2.0*zeroth_array[ii-1].getPos() +
147                                1.5*zeroth_array[ii].getPos());
148          }
149          else
150          {
151             deriv[ii] = (1/h)*((1.0/12.0)*zeroth_array[ii-2].getPos() -
152                                (2.0/3.0)*zeroth_array[ii-1].getPos() +
153                                (2.0/3.0)*zeroth_array[ii+1].getPos() -
154                                (1.0/12.0)*zeroth_array[ii+2].getPos());
155          }
156       }
157          // then check the difference between derived and computed velocity
158       for (unsigned ii = 0; ii < SECONDS; ii++)
159       {
160          double derivedMag = deriv[ii].mag();
161          double computedMag = zeroth_array[ii].getVel().mag();
162             // If you want to print the data e.g. to plot, uncomment
163             // this stream output statement and comment out tbe break
164             // statement below.
165             // Just don't check it in that way, please.
166             // cerr << ii << " " << (computedMag - derivedMag) << endl;
167          if (fabs(computedMag - derivedMag) > velDiffThresh)
168          {
169                // no sense in printing 7200 success/fail messages.
170             testFailed = true;
171             break;
172          }
173       }
174       if (testFailed)
175       {
176          TUFAIL("computed velocity is significantly different from derived"
177                 " velocity");
178       }
179       else
180       {
181          TUPASS("velocity check");
182       }
183    }
184    catch (gpstk::Exception& exc)
185    {
186       cerr << exc;
187       TUFAIL("Exception");
188    }
189    catch (...)
190    {
191       TUFAIL("Exception");
192    }
193    TURETURN();
194 }
195 
196 
main()197 int main()
198 {
199    unsigned total = 0;
200    OrbElem_T testClass;
201    total += testClass.testSvXvt();
202 
203    cout << "Total Failures for " << __FILE__ << ": " << total << endl;
204    return total;
205 }
206