EngEphemeris.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: EngEphemeris.cpp 2972 2011-11-10 12:10:39Z yanweignss $"
00002 
00003 
00004 
00005 //============================================================================
00006 //
00007 //  This file is part of GPSTk, the GPS Toolkit.
00008 //
00009 //  The GPSTk is free software; you can redistribute it and/or modify
00010 //  it under the terms of the GNU Lesser General Public License as published
00011 //  by the Free Software Foundation; either version 2.1 of the License, or
00012 //  any later version.
00013 //
00014 //  The GPSTk is distributed in the hope that it will be useful,
00015 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 //  GNU Lesser General Public License for more details.
00018 //
00019 //  You should have received a copy of the GNU Lesser General Public
00020 //  License along with GPSTk; if not, write to the Free Software Foundation,
00021 //  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //
00023 //  Copyright 2004, The University of Texas at Austin
00024 //
00025 //============================================================================
00026 
00027 //============================================================================
00028 //
00029 //This software developed by Applied Research Laboratories at the University of
00030 //Texas at Austin, under contract to an agency or agencies within the U.S.
00031 //Department of Defense. The U.S. Government retains all rights to use,
00032 //duplicate, distribute, disclose, or release this software.
00033 //
00034 //Pursuant to DoD Directive 523024
00035 //
00036 // DISTRIBUTION STATEMENT A: This software has been approved for public
00037 //                           release, distribution is unlimited.
00038 //
00039 //=============================================================================
00040 
00041 
00042 
00043 
00044 
00045 
00051 #include "StringUtils.hpp"
00052 #include "icd_200_constants.hpp"
00053 #include "GPSGeoid.hpp"
00054 #include "EngEphemeris.hpp"
00055 
00056 #include <cmath>
00057 
00058 namespace gpstk
00059 {
00060    using namespace std;
00061    using namespace gpstk;
00062 
00063    EngEphemeris::EngEphemeris()
00064       throw()
00065    {
00066       haveSubframe[0] = haveSubframe[1] = haveSubframe[2] = false;
00067 
00068       tlm_message[0] = tlm_message[1] = tlm_message[2] = 0;
00069 
00070       PRNID = tracker = ASalert[0] = ASalert[1] = ASalert[2] = weeknum =
00071         codeflags = accFlag = health = L2Pdata = 0;
00072 
00073       HOWtime[0] = HOWtime[1] = HOWtime[2] = 0;
00074 
00075       IODC = IODE = 0;
00076       Toc = af0 = af1 = af2 = Tgd = Cuc = Cus = Crc = Crs =
00077          Cic = Cis = Toe = M0 = dn = ecc = Ahalf = OMEGA0 = i0 = w =
00078          OMEGAdot = idot = accuracy = 0.0;
00079 
00080       fitint = 0;
00081    }
00082 
00083    bool EngEphemeris::addSubframe(const long subframe[10], const int gpsWeek,
00084                                   short PRN, short track)
00085       throw(InvalidParameter)
00086    {
00087       double ficked[60];
00088 
00089       if (!subframeConvert(subframe, gpsWeek, ficked))
00090          return false;
00091 
00092       int sfnum = static_cast<int>( ficked[4] );
00093       InvalidParameter exc("Subframe "+StringUtils::asString(sfnum)+
00094                            " not ephemeris subframe.");
00095 
00096       switch (sfnum)
00097       {
00098          case 1:
00099             tlm_message[0] = (subframe[0] >> 8) & 0x3fff;
00100             HOWtime[0] = static_cast<long>( ficked[2] );
00101             ASalert[0] = static_cast<short>( ficked[3] );
00102             weeknum    = static_cast<short>( ficked[5] );
00103             codeflags  = static_cast<short>( ficked[6] );
00104             accFlag    = static_cast<short>( ficked[7] );
00105             health     = static_cast<short>( ficked[8] );
00106             IODC       = static_cast<short>( ldexp( ficked[9], -11 ) );
00107             L2Pdata    = static_cast<short>( ficked[10] );
00108             Tgd        = ficked[11];
00109             Toc        = ficked[12];
00110             af2        = ficked[13];
00111             af1        = ficked[14];
00112             af0        = ficked[15];
00113             tracker    = track;
00114             PRNID      = PRN;
00115             haveSubframe[0] = true;
00116             // convert the accuracy flag to a value...
00117             accuracy = gpstk::ura2accuracy(accFlag);
00118             break;
00119 
00120          case 2:
00121             tlm_message[1] = (subframe[0] >> 8) & 0x3fff;
00122             HOWtime[1] = static_cast<long>( ficked[2] );
00123             ASalert[1] = static_cast<short>( ficked[3] );
00124             IODE       = static_cast<short>( ldexp( ficked[5], -11 ) );
00125             Crs        = ficked[6];
00126             dn         = ficked[7];
00127             M0         = ficked[8];
00128             Cuc        = ficked[9];
00129             ecc        = ficked[10];
00130             Cus        = ficked[11];
00131             Ahalf      = ficked[12];
00132             Toe        = ficked[13];
00133             fitint     = static_cast<short>( ficked[14] );
00134             AODO       = static_cast<long>( ficked[15] );
00135             haveSubframe[1] = true;
00136             break;
00137 
00138          case 3:
00139             tlm_message[2] = (subframe[0] >> 8) & 0x3fff;
00140             HOWtime[2] = static_cast<long>( ficked[2] );
00141             ASalert[2] = static_cast<short>( ficked[3] );
00142             Cic        = ficked[5];
00143             OMEGA0     = ficked[6];
00144             Cis        = ficked[7];
00145             i0         = ficked[8];
00146             Crc        = ficked[9];
00147             w          = ficked[10];
00148             OMEGAdot   = ficked[11];
00149             idot       = ficked[13];
00150             haveSubframe[2] = true;
00151             break;
00152 
00153          default:
00154             GPSTK_THROW(exc);
00155             break;
00156       } // switch (sfnum)
00157 
00158       return true;
00159    }
00160 
00161    bool EngEphemeris::addSubframeNoParity(const long subframe[10],
00162                                const long gpsWeek,
00163                                const short PRN,
00164                                const short track)
00165       throw(InvalidParameter)
00166    {
00167       long paddedSF[10];
00168       short PRNArg;
00169       short trackArg;
00170 
00171       for (int i=0;i<10;++i)
00172       {
00173          paddedSF[i] = subframe[i];
00174          paddedSF[i] <<= 6;
00175          paddedSF[i] &= 0x3FFFFFC0;    // Guarantee 2 msb and 6 lsb are zeroes
00176       }
00177       PRNArg = PRN;
00178       trackArg = track;
00179       return( addSubframe( paddedSF, gpsWeek, PRNArg, trackArg ));
00180    }
00181 
00182    bool EngEphemeris::addIncompleteSF1Thru3(
00183       const long sf1[8], const long sf2[8], const long sf3[8],
00184       const long sf1TransmitSOW, const int gpsWeek,
00185       const short PRN, const short track)
00186    {
00187       double ficked[60];
00188 
00189          // Need to provide a valid subframe number in the handover word.
00190          // While we're at it, we'll fake the A-S bit such that it
00191          // appears A-S is ON, even though we warn the user NOT to trust
00192          // returns from the getASAlert() method.
00193       const long sf1Lead[2] = { 0x00000000, 0x00000900 };
00194       const long sf2Lead[2] = { 0x00000000, 0x00000A00 };
00195       const long sf3Lead[2] = { 0x00000000, 0x00000B00 };
00196       long subframe[10];
00197 
00198          // Handover word times represent the time of the leading edge of the
00199          // NEXT subframe.  Therefore, HOW should always correspond to
00200          //   :06/:36 for SF 1
00201          //   :12/:42 for SF 2
00202          //   :18/:48 for SF 3
00203          // This method hasn't a clue about the accuracy of the SOW input by the
00204          // user, but it WILL enforce this relationship.
00205       long frameCount = sf1TransmitSOW / 30;
00206       long SF1HOWTime = (frameCount * 30) + 6;
00207 
00208          // Convert subframe 1 parameters
00209       subframe[0] = sf1Lead[0];
00210       subframe[1] = sf1Lead[1];
00211       int i;
00212       for (i=0; i<8; ++i) subframe[i+2] = sf1[i];
00213 
00214       if (!subframeConvert(subframe, gpsWeek, ficked))
00215          return false;
00216 
00217       tlm_message[0] = 0;
00218       HOWtime[0] = SF1HOWTime;
00219       ASalert[0] = (short)ficked[3];
00220       weeknum    = (short)ficked[5];
00221       codeflags  = (short)ficked[6];
00222       accFlag    = (short)ficked[7];
00223       health     = (short)ficked[8];
00224       IODC       = (short)ldexp(ficked[9],-11);
00225       L2Pdata    = (short)ficked[10];
00226       Tgd        = ficked[11];
00227       Toc        = ficked[12];
00228       af2        = ficked[13];
00229       af1        = ficked[14];
00230       af0        = ficked[15];
00231       tracker    = track;
00232       PRNID      = PRN;
00233       haveSubframe[0] = true;
00234          // convert the accuracy flag to a value...
00235       accuracy = gpstk::ura2accuracy(accFlag);
00236 
00237 
00238          // Convert subframe 2 parameters
00239       subframe[0] = sf2Lead[0];
00240       subframe[1] = sf2Lead[1];
00241       for (i=0; i<8; ++i) subframe[i+2] = sf2[i];
00242 
00243       if (!subframeConvert(subframe, gpsWeek, ficked))
00244          return false;
00245 
00246       tlm_message[1] = 0;
00247       HOWtime[1] = SF1HOWTime + 6;
00248       ASalert[1] = (short)ficked[3];
00249       IODE       = (short)ldexp(ficked[5],-11);
00250       Crs        = ficked[6];
00251       dn         = ficked[7];
00252       M0         = ficked[8];
00253       Cuc        = ficked[9];
00254       ecc        = ficked[10];
00255       Cus        = ficked[11];
00256       Ahalf      = ficked[12];
00257       Toe        = ficked[13];
00258       fitint     = (short)ficked[14];
00259       haveSubframe[1] = true;
00260 
00261          // Convert subframe 3 parameters
00262       subframe[0] = sf3Lead[0];
00263       subframe[1] = sf3Lead[1];
00264       for (i=0; i<8; ++i) subframe[i+2] = sf3[i];
00265 
00266       if (!subframeConvert(subframe, gpsWeek, ficked))
00267          return false;
00268 
00269       tlm_message[2] = 0;
00270       HOWtime[2] = SF1HOWTime + 12;
00271       ASalert[2] = (short)ficked[3];
00272       Cic        = ficked[5];
00273       OMEGA0     = ficked[6];
00274       Cis        = ficked[7];
00275       i0         = ficked[8];
00276       Crc        = ficked[9];
00277       w          = ficked[10];
00278       OMEGAdot   = ficked[11];
00279       idot       = ficked[13];
00280       haveSubframe[2] = true;
00281 
00282       return true;
00283    }
00284 
00285    bool EngEphemeris :: isData(short subframe) const
00286       throw(gpstk::InvalidRequest)
00287    {
00288       if ((subframe < 1) || (subframe > 3))
00289       {
00290          InvalidRequest exc("Subframe "+StringUtils::asString(subframe)+
00291                             " is not a valid ephemeris subframe.");
00292          GPSTK_THROW(exc);
00293       }
00294 
00295       return haveSubframe[subframe-1];
00296    }
00297 
00298    void EngEphemeris :: setAccuracy(const double& acc)
00299       throw(gpstk::InvalidParameter)
00300    {
00301       if( acc < 0 )
00302       {
00303          InvalidParameter exc("SV Accuracy of " + StringUtils::asString(acc) +
00304                               " meters is invalid.");
00305          GPSTK_THROW(exc);
00306       }
00307       accuracy = acc;
00308       accFlag = gpstk::accuracy2ura(acc);
00309    }
00310 
00311    Xvt EngEphemeris :: svXvt(const DayTime& t) const
00312       throw(InvalidRequest)
00313    {
00314       Xvt sv;
00315 
00316       double ea;              /* eccentric anomaly */
00317       double delea;           /* delta eccentric anomaly during iteration */
00318       double elapte;          /* elapsed time since Toe */
00319       double elaptc;          /* elapsed time since Toc */
00320       double dtc,dtr,q,sinea,cosea;
00321       double GSTA,GCTA;
00322       double A;               /* semi-major axis */
00323       double amm;
00324       double meana;           /* mean anomaly */
00325       double F,G;             /* temporary real variables */
00326       double alat,talat,c2al,s2al,du,dr,di,U,R,truea,AINC;
00327       double ANLON,cosu,sinu,xip,yip,can,san,cinc,sinc;
00328       double xef,yef,zef,dek,dlk,div,domk,duv,drv;
00329       double dxp,dyp,vxef,vyef,vzef;
00330       GPSGeoid geoid;
00331 
00332       double sqrtgm = ::sqrt(geoid.gm());
00333 
00334          // Check for ground transmitter
00335       double twoPI = 2.0e0 * PI;
00336       bool igtran;              // ground transmitter flag
00337       double lecc;               // eccentricity
00338       double tdrinc;            // dt inclination
00339       if (getAhalf() < 2550.0e0 )
00340       {
00341          igtran = true;
00342          lecc = 0.0e0;
00343          tdrinc = 0.0e0;
00344       }
00345       else
00346       {
00347          igtran = false;
00348          lecc = getEcc();
00349          tdrinc = getIDot();
00350       }
00351 
00352          // Compute time since ephemeris & clock epochs
00353       elapte = t - getEphemerisEpoch();
00354       elaptc = t - getEpochTime();
00355 
00356 
00357          // Compute mean motion
00358       A = getA();
00359       amm  = (sqrtgm / (A*getAhalf())) + getDn();
00360 
00361 
00362          // In-plane angles
00363          //     meana - Mean anomaly
00364          //     ea    - Eccentric anomaly
00365          //     truea - True anomaly
00366       if (!igtran)
00367          meana = getM0() + elapte * amm;
00368       else
00369          meana = getM0();
00370       meana = fmod(meana, twoPI);
00371 
00372       ea = meana + lecc * ::sin(meana);
00373 
00374       int loop_cnt = 1;
00375       do  {
00376          F = meana - ( ea - lecc * ::sin(ea));
00377          G = 1.0 - lecc * ::cos(ea);
00378          delea = F/G;
00379          ea = ea + delea;
00380          loop_cnt++;
00381       } while ( (::fabs(delea) > 1.0e-11 ) && (loop_cnt <= 20) );
00382 
00383          // Compute clock corrections
00384       sv.ddtime = getAf1() + elaptc * getAf2();
00385       dtc = getAf0() + elaptc * ( sv.ddtime );
00386       dtr = REL_CONST * lecc * getAhalf() * ::sin(ea);
00387       sv.dtime = dtc + dtr;
00388 
00389          // Compute true anomaly
00390       q = ::sqrt ( 1.0e0 - lecc*lecc);
00391       sinea = ::sin(ea);
00392       cosea = ::cos(ea);
00393       G = 1.0e0 - lecc * cosea;
00394 
00395          //  G*SIN(TA) AND G*COS(TA)
00396       GSTA  = q * sinea;
00397       GCTA  = cosea - lecc;
00398 
00399          //  True anomaly
00400       truea = ::atan2 ( GSTA, GCTA );
00401 
00402          // Argument of lat and correction terms (2nd harmonic)
00403       alat = truea + getW();
00404       talat = 2.0e0 * alat;
00405       c2al = ::cos( talat );
00406       s2al = ::sin( talat );
00407 
00408       du  = c2al * getCuc() +  s2al * getCus();
00409       dr  = c2al * getCrc() +  s2al * getCrs();
00410       di  = c2al * getCic() +  s2al * getCis();
00411 
00412          // U = updated argument of lat, R = radius, AINC = inclination
00413       U    = alat + du;
00414       R    = getA()*G  + dr;
00415       AINC = getI0() + tdrinc * elapte  +  di;
00416 
00417          //  Longitude of ascending node (ANLON)
00418       if (!igtran)
00419          ANLON = getOmega0() + (getOmegaDot() - geoid.angVelocity()) *
00420             elapte - geoid.angVelocity() * getToe();
00421       else
00422          ANLON = getOmega0() - getOmegaDot() * getToe();
00423 
00424          // In plane location
00425       cosu = ::cos( U );
00426       sinu = ::sin( U );
00427 
00428       xip  = R * cosu;
00429       yip  = R * sinu;
00430 
00431          //  Angles for rotation to earth fixed
00432       can  = ::cos( ANLON );
00433       san  = ::sin( ANLON );
00434       cinc = ::cos( AINC  );
00435       sinc = ::sin( AINC  );
00436 
00437          // Earth fixed - meters
00438       xef  =  xip*can  -  yip*cinc*san;
00439       yef  =  xip*san  +  yip*cinc*can;
00440       zef  =              yip*sinc;
00441 
00442       sv.x[0] = xef;
00443       sv.x[1] = yef;
00444       sv.x[2] = zef;
00445 
00446          // Compute velocity of rotation coordinates
00447       dek = amm * A / R;
00448       dlk = getAhalf() * q * sqrtgm / (R*R);
00449       div = tdrinc - 2.0e0 * dlk *
00450          ( getCic()  * s2al - getCis() * c2al );
00451       domk = getOmegaDot() - geoid.angVelocity();
00452       duv = dlk*(1.e0+ 2.e0 * (getCus()*c2al - getCuc()*s2al) );
00453       drv = A * lecc * dek * sinea - 2.e0 * dlk *
00454          ( getCrc() * s2al - getCrs() * c2al );
00455 
00456       dxp = drv*cosu - R*sinu*duv;
00457       dyp = drv*sinu + R*cosu*duv;
00458 
00459          // Calculate velocities
00460       vxef = dxp*can - xip*san*domk - dyp*cinc*san
00461          + yip*( sinc*san*div - cinc*can*domk);
00462       vyef = dxp*san + xip*can*domk + dyp*cinc*can
00463          - yip*( sinc*can*div + cinc*san*domk);
00464       vzef = dyp*sinc + yip*cinc*div;
00465 
00466          // Move results into output variables
00467       sv.v[0] = vxef;
00468       sv.v[1] = vyef;
00469       sv.v[2] = vzef;
00470 
00471       return sv;
00472    }
00473 
00474    double EngEphemeris::svRelativity(const DayTime& t) const
00475       throw(gpstk::InvalidRequest)
00476    {
00477       GPSGeoid geoid;
00478       double twoPI = 2.0e0 * PI;
00479       double sqrtgm = ::sqrt(geoid.gm());
00480       double elapte = t - getEphemerisEpoch();
00481       double elaptc = t - getEpochTime();
00482       double A = getA();
00483       double amm  = (sqrtgm / (A*getAhalf())) + getDn();
00484       double meana,lecc,F,G,delea;
00485 
00486       if (getAhalf() < 2550.0e0 ) { lecc = 0.0e0; meana = getM0(); }
00487       else { lecc = getEcc(); meana = getM0() + elapte * amm; }
00488       meana = ::fmod(meana, twoPI);
00489       double ea = meana + lecc * ::sin(meana);
00490 
00491       int loop_cnt = 1;
00492       do  {
00493          F = meana - ( ea - lecc * ::sin(ea));
00494          G = 1.0 - lecc * ::cos(ea);
00495          delea = F/G;
00496          ea = ea + delea;
00497          loop_cnt++;
00498       } while ( (::fabs(delea) > 1.0e-11 ) && (loop_cnt <= 20) );
00499       double dtr = REL_CONST * lecc * getAhalf() * ::sin(ea);
00500       return dtr;
00501    }
00502 
00503    double EngEphemeris::svClockBias(const DayTime& t) const
00504       throw(gpstk::InvalidRequest)
00505    {
00506       double dtc,elaptc;
00507       elaptc = t - getEpochTime();
00508       dtc = getAf0() + elaptc * ( getAf1() + elaptc * getAf2() );
00509 
00510       return dtc;
00511    }
00512 
00513    double EngEphemeris::svClockDrift(const DayTime& t) const
00514       throw(gpstk::InvalidRequest)
00515    {
00516       double drift,elaptc;
00517       elaptc = t - getEpochTime();
00518       drift = getAf1() + elaptc * getAf2();
00519       return drift;
00520    }
00521 
00522    short EngEphemeris :: getFitInterval() const
00523       throw(InvalidRequest)
00524    {
00525       short iodc = getIODC();
00526       short fiti = getFitInt();
00527 
00528          /* check the IODC */
00529       if (iodc < 0 || iodc > 1023)
00530       {
00531             /* error in iodc, return minimum fit */
00532          return 4;
00533       }
00534 
00535       if (((fiti == 0) &&
00536            (iodc & 0xFF) < 240 || (iodc & 0xFF) > 255 ))
00537       {
00538             /* fit interval of 4 hours */
00539          return 4;
00540       }
00541       else if (fiti == 1)
00542       {
00543          if( ((iodc & 0xFF) < 240 || (iodc & 0xFF) > 255))
00544          {
00545                /* fit interval of 6 hours */
00546             return 6;
00547          }
00548          else if(iodc >=240 && iodc <=247)
00549          {
00550                /* fit interval of 8 hours */
00551             return 8;
00552          }
00553          else if(iodc >= 248 && iodc <= 255 || iodc == 496)
00554          {
00555                /* fit interval of 14 hours */
00556             return 14;
00557          }
00558          // Revised in IS-GPS-200 Revision D for Block IIR/IIR-M/IIF
00559          else if(iodc >= 497 && iodc <=503 || iodc >= 1021 && iodc <= 1023)
00560          {
00561                /* fit interval of 26 hours */
00562             return 26;
00563          }
00564          else if(iodc >= 504 && iodc <=510)
00565          {
00566                /* fit interval of 50 hours */
00567             return 50;
00568          }
00569          else if(iodc == 511 || iodc >= 752 && iodc <= 756)
00570          {
00571                /* fit interval of 74 hours */
00572             return 74;
00573          }
00574          /* NOTE:
00575           * The following represents old fit intervals for Block II (not IIA)
00576           * and is present only in old versions of the ICD-GPS-200 Rev. C.
00577           * Please do not remove them as there are still people that may
00578           * want to process old Block II data and none of the IODC intervals
00579           * overlap (so far) so there is no need to remove them.
00580           */
00581          else if(iodc >= 757 && iodc <= 763)
00582          {
00583                /* fit interval of 98 hours */
00584             return 98;
00585          }
00586          else if(iodc >= 764 && iodc <=767 || iodc >=1008 && iodc <=1010)
00587          {
00588                /* fit interval of 122 hours */
00589             return 122;
00590          }
00591          else if(iodc >= 1011 && iodc <=1020)
00592          {
00593                /* fit interval of 146 hours */
00594             return 146;
00595          }
00596          else
00597          {
00598                /* error in the iodc or ephemeris, return minimum
00599                   fit */
00600             return 4;
00601          }
00602       }
00603       else
00604       {
00605             /* error in ephemeris/iodc, return minimum fit */
00606          return 4;
00607       }
00608 
00609       return 0; // never reached
00610    }
00611 
00612    unsigned EngEphemeris::getTLMMessage(short subframe) const
00613       throw(InvalidRequest)
00614    {
00615       if (!haveSubframe[subframe-1])
00616       {
00617          InvalidRequest exc("Subframe "+StringUtils::asString(subframe)+
00618                             " not stored.");
00619          GPSTK_THROW(exc);
00620       }
00621       return tlm_message[subframe-1];
00622    }
00623 
00624     DayTime EngEphemeris::getTransmitTime() const
00625        throw(InvalidRequest)
00626     {
00627        DayTime toReturn(0.L);
00628        toReturn.setGPSfullweek(getFullWeek(), (double)getTot());
00629        return toReturn;
00630     }
00631 
00632    DayTime EngEphemeris::getEpochTime() const
00633       throw(InvalidRequest)
00634    {
00635       DayTime toReturn(0.L);
00636       if ( (getToc() - getHOWTime(1)) < -DayTime::HALFWEEK)
00637          toReturn.setGPSfullweek(getFullWeek() + 1, getToc());
00638       else if ( (getToc() - getHOWTime(1)) > DayTime::HALFWEEK)
00639          toReturn.setGPSfullweek(getFullWeek() - 1, getToc());
00640       else
00641          toReturn.setGPSfullweek(getFullWeek(), getToc());
00642       return toReturn;
00643    }
00644 
00645    DayTime EngEphemeris::getEphemerisEpoch() const
00646       throw(InvalidRequest)
00647    {
00648       DayTime toReturn(0.L);
00649       if ( (getToe() - getHOWTime(1)) < -DayTime::HALFWEEK)
00650          toReturn.setGPSfullweek(getFullWeek() + 1, getToe());
00651       else if ( (getToe() - getHOWTime(1)) > DayTime::HALFWEEK)
00652          toReturn.setGPSfullweek(getFullWeek() - 1, getToe());
00653       else
00654          toReturn.setGPSfullweek(getFullWeek(), getToe());
00655       return toReturn;
00656    }
00657 
00658    short EngEphemeris::getPRNID() const
00659       throw(InvalidRequest)
00660    {
00661       if(!haveSubframe[0])
00662       {
00663          InvalidRequest exc("Required subframe 1 not stored.");
00664          GPSTK_THROW(exc);
00665       }
00666       return PRNID;
00667    }
00668 
00669    short EngEphemeris::getTracker() const
00670       throw(InvalidRequest)
00671    {
00672       if(!haveSubframe[0])
00673       {
00674          InvalidRequest exc("Required subframe 1 not stored.");
00675          GPSTK_THROW(exc);
00676       }
00677       return tracker;
00678    }
00679 
00680    double EngEphemeris::getHOWTime(short subframe) const
00681       throw(InvalidRequest)
00682    {
00683       if (!haveSubframe[subframe-1])
00684       {
00685          InvalidRequest exc("Subframe "+StringUtils::asString(subframe)+
00686                             " not stored.");
00687          GPSTK_THROW(exc);
00688       }
00689          // this return as a double is necessary for sets into DayTime
00690          // to not get confused.  Ints are Zcounts whereas doubles are seconds
00691       return (double) HOWtime[subframe-1];
00692    }
00693 
00694    short EngEphemeris::getASAlert(short subframe)  const
00695       throw(InvalidRequest)
00696    {
00697       if (!haveSubframe[subframe-1])
00698       {
00699          InvalidRequest exc("Subframe "+StringUtils::asString(subframe)+
00700                             " not stored.");
00701          GPSTK_THROW(exc);
00702       }
00703       return ASalert[subframe-1];
00704    }
00705 
00706    short EngEphemeris::getFullWeek()  const
00707       throw(InvalidRequest)
00708    {
00709       if (!haveSubframe[0])
00710       {
00711          InvalidRequest exc("Required subframe 1 not stored.");
00712          GPSTK_THROW(exc);
00713       }
00714       return weeknum;
00715    }
00716 
00717    short EngEphemeris::getCodeFlags()  const
00718       throw(InvalidRequest)
00719    {
00720       if (!haveSubframe[0])
00721       {
00722          InvalidRequest exc("Required subframe 1 not stored.");
00723          GPSTK_THROW(exc);
00724       }
00725       return codeflags;
00726    }
00727 
00728    double EngEphemeris::getAccuracy()  const
00729       throw(InvalidRequest)
00730    {
00731       if (!haveSubframe[0])
00732       {
00733          InvalidRequest exc("Required subframe 1 not stored.");
00734          GPSTK_THROW(exc);
00735       }
00736       return accuracy;
00737    }
00738 
00739    short EngEphemeris::getAccFlag()  const
00740       throw(InvalidRequest)
00741    {
00742       if (!haveSubframe[0])
00743       {
00744          InvalidRequest exc("Required subframe 1 not stored.");
00745          GPSTK_THROW(exc);
00746       }
00747       return accFlag;
00748    }
00749 
00750    short EngEphemeris::getHealth() const
00751       throw(InvalidRequest)
00752    {
00753       if (!haveSubframe[0])
00754       {
00755          InvalidRequest exc("Required subframe 1 not stored.");
00756          GPSTK_THROW(exc);
00757       }
00758       return health;
00759    }
00760 
00761    short EngEphemeris::getL2Pdata() const
00762       throw(InvalidRequest)
00763    {
00764       if (!haveSubframe[0])
00765       {
00766          InvalidRequest exc("Required subframe 1 not stored.");
00767          GPSTK_THROW(exc);
00768       }
00769       return L2Pdata;
00770    }
00771 
00772    short EngEphemeris::getIODC() const
00773       throw(InvalidRequest)
00774    {
00775       if (!haveSubframe[0])
00776       {
00777          InvalidRequest exc("Required subframe 1 not stored.");
00778          GPSTK_THROW(exc);
00779       }
00780       return (short)IODC;
00781    }
00782 
00783    short EngEphemeris::getIODE() const
00784       throw(InvalidRequest)
00785    {
00786       if (!haveSubframe[1])
00787       {
00788          InvalidRequest exc("Required subframe 2 not stored.");
00789          GPSTK_THROW(exc);
00790       }
00791       return (short)IODE;
00792    }
00793 
00794    long EngEphemeris::getAODO() const
00795       throw(InvalidRequest)
00796    {
00797       if (!haveSubframe[1])
00798       {
00799          InvalidRequest exc("Required subframe 2 not stored.");
00800          GPSTK_THROW(exc);
00801       }
00802       return AODO;
00803    }
00804 
00805    double EngEphemeris::getToc() const
00806       throw(InvalidRequest)
00807    {
00808       if (!haveSubframe[0])
00809       {
00810          InvalidRequest exc("Required subframe 1 not stored.");
00811          GPSTK_THROW(exc);
00812       }
00813       return Toc;
00814    }
00815 
00816    double EngEphemeris::getAf0() const
00817       throw(InvalidRequest)
00818    {
00819       if (!haveSubframe[0])
00820       {
00821          InvalidRequest exc("Required subframe 1 not stored.");
00822          GPSTK_THROW(exc);
00823       }
00824       return af0;
00825    }
00826 
00827    double EngEphemeris::getAf1() const
00828       throw(InvalidRequest)
00829    {
00830       if (!haveSubframe[0])
00831       {
00832          InvalidRequest exc("Required subframe 1 not stored.");
00833          GPSTK_THROW(exc);
00834       }
00835       return af1;
00836    }
00837 
00838    double EngEphemeris::getAf2() const
00839       throw(InvalidRequest)
00840    {
00841       if (!haveSubframe[0])
00842       {
00843          InvalidRequest exc("Required subframe 1 not stored.");
00844          GPSTK_THROW(exc);
00845       }
00846       return af2;
00847    }
00848 
00849    double EngEphemeris::getTgd() const
00850       throw(InvalidRequest)
00851    {
00852       if (!haveSubframe[0])
00853       {
00854          InvalidRequest exc("Required subframe 1 not stored.");
00855          GPSTK_THROW(exc);
00856       }
00857       return Tgd;
00858    }
00859 
00860    double EngEphemeris::getCus() const
00861       throw(InvalidRequest)
00862    {
00863       if (!haveSubframe[1])
00864       {
00865          InvalidRequest exc("Required subframe 2 not stored.");
00866          GPSTK_THROW(exc);
00867       }
00868       return Cus;
00869    }
00870 
00871    double EngEphemeris::getCrs() const
00872       throw(InvalidRequest)
00873    {
00874       if (!haveSubframe[1])
00875       {
00876          InvalidRequest exc("Required subframe 2 not stored.");
00877          GPSTK_THROW(exc);
00878       }
00879       return Crs;
00880    }
00881 
00882    double EngEphemeris::getCis() const
00883       throw(InvalidRequest)
00884    {
00885       if (!haveSubframe[2])
00886       {
00887          InvalidRequest exc("Required subframe 3 not stored.");
00888          GPSTK_THROW(exc);
00889       }
00890       return Cis;
00891    }
00892 
00893    double EngEphemeris::getCrc() const
00894       throw(InvalidRequest)
00895    {
00896       if (!haveSubframe[2])
00897       {
00898          InvalidRequest exc("Required subframe 3 not stored.");
00899          GPSTK_THROW(exc);
00900       }
00901       return Crc;
00902    }
00903 
00904    double EngEphemeris::getCuc() const
00905       throw(InvalidRequest)
00906    {
00907       if (!haveSubframe[1])
00908       {
00909          InvalidRequest exc("Required subframe 2 not stored.");
00910          GPSTK_THROW(exc);
00911       }
00912       return Cuc;
00913    }
00914 
00915    double EngEphemeris::getCic() const
00916       throw(InvalidRequest)
00917    {
00918       if (!haveSubframe[2])
00919       {
00920          InvalidRequest exc("Required subframe 3 not stored.");
00921          GPSTK_THROW(exc);
00922       }
00923       return Cic;
00924    }
00925 
00926    double EngEphemeris::getToe() const
00927       throw(InvalidRequest)
00928    {
00929       if (!haveSubframe[1])
00930       {
00931          InvalidRequest exc("Required subframe 2 not stored.");
00932          GPSTK_THROW(exc);
00933       }
00934       return Toe;
00935    }
00936 
00937    double EngEphemeris::getM0() const
00938       throw(InvalidRequest)
00939    {
00940       if (!haveSubframe[1])
00941       {
00942          InvalidRequest exc("Required subframe 2 not stored.");
00943          GPSTK_THROW(exc);
00944       }
00945       return M0;
00946    }
00947 
00948    double EngEphemeris::getDn() const
00949       throw(InvalidRequest)
00950    {
00951       if (!haveSubframe[1])
00952       {
00953          InvalidRequest exc("Required subframe 2 not stored.");
00954          GPSTK_THROW(exc);
00955       }
00956       return dn;
00957    }
00958 
00959    double EngEphemeris::getEcc() const
00960       throw(InvalidRequest)
00961    {
00962       if (!haveSubframe[1])
00963       {
00964          InvalidRequest exc("Required subframe 2 not stored.");
00965          GPSTK_THROW(exc);
00966       }
00967       return ecc;
00968    }
00969 
00970    double EngEphemeris::getAhalf() const
00971       throw(InvalidRequest)
00972    {
00973       if (!haveSubframe[1])
00974       {
00975          InvalidRequest exc("Required subframe 2 not stored.");
00976          GPSTK_THROW(exc);
00977       }
00978       return Ahalf;
00979    }
00980 
00981    double EngEphemeris::getA() const
00982       throw(InvalidRequest)
00983    {
00984       if (!haveSubframe[1])
00985       {
00986          InvalidRequest exc("Required subframe 2 not stored.");
00987          GPSTK_THROW(exc);
00988       }
00989       return Ahalf * Ahalf;
00990    }
00991 
00992    double EngEphemeris::getOmega0() const
00993       throw(InvalidRequest)
00994    {
00995       if (!haveSubframe[2])
00996       {
00997          InvalidRequest exc("Required subframe 3 not stored.");
00998          GPSTK_THROW(exc);
00999       }
01000       return OMEGA0;
01001    }
01002 
01003    double EngEphemeris::getI0() const
01004       throw(InvalidRequest)
01005    {
01006       if (!haveSubframe[2])
01007       {
01008          InvalidRequest exc("Required subframe 3 not stored.");
01009          GPSTK_THROW(exc);
01010       }
01011       return i0;
01012    }
01013 
01014    double EngEphemeris::getW() const
01015       throw(InvalidRequest)
01016    {
01017       if (!haveSubframe[2])
01018       {
01019          InvalidRequest exc("Required subframe 3 not stored.");
01020          GPSTK_THROW(exc);
01021       }
01022       return w;
01023    }
01024 
01025    double EngEphemeris::getOmegaDot() const
01026       throw(InvalidRequest)
01027    {
01028       if (!haveSubframe[2])
01029       {
01030          InvalidRequest exc("Required subframe 3 not stored.");
01031          GPSTK_THROW(exc);
01032       }
01033       return OMEGAdot;
01034    }
01035 
01036    double EngEphemeris::getIDot() const
01037       throw(InvalidRequest)
01038    {
01039       if (!haveSubframe[2])
01040       {
01041          InvalidRequest exc("Required subframe 3 not stored.");
01042          GPSTK_THROW(exc);
01043       }
01044       return idot;
01045    }
01046 
01047    short EngEphemeris::getFitInt() const
01048       throw(InvalidRequest)
01049    {
01050       if (!haveSubframe[1])
01051       {
01052          InvalidRequest exc("Required subframe 2 not stored.");
01053          GPSTK_THROW(exc);
01054       }
01055       return fitint;
01056    }
01057 
01058    long EngEphemeris::getTot() const
01059       throw(InvalidRequest)
01060    {
01061       if(!haveSubframe[0])
01062       {
01063          InvalidRequest exc("Required subframe 1 not stored.");
01064          GPSTK_THROW(exc);
01065       }
01066       if(!haveSubframe[1])
01067       {
01068          InvalidRequest exc("Required subframe 2 not stored.");
01069          GPSTK_THROW(exc);
01070       }
01071       if(!haveSubframe[2])
01072       {
01073          InvalidRequest exc("Required subframe 3 not stored.");
01074          GPSTK_THROW(exc);
01075       }
01076 
01077       // MSVC
01078 #ifdef _MSC_VER
01079       long foo = static_cast<long>( getHOWTime(1) < getHOWTime(2) ) ? getHOWTime(1) : getHOWTime(2);
01080       foo = ( foo < getHOWTime(3) ) ? foo : getHOWTime(3) ;
01081 #else
01082       long foo =
01083          static_cast<long>( std::min( getHOWTime(1),
01084                             std::min( getHOWTime(2), getHOWTime(3) ) ) );
01085 #endif
01086          // The ephemeris comes on 30 second boundaries, so...
01087       foo/=30;
01088       foo*=30;
01089       return foo;
01090    }
01091 
01092    EngEphemeris& EngEphemeris::setSF1( unsigned tlm, double how, short asalert,
01093                                        short fullweek, short cflags, short acc,
01094                                        short svhealth, short iodc, short l2pdata,
01095                                        double tgd, double toc, double Af2,
01096                                        double Af1, double Af0, short Tracker,
01097                                        short prn )
01098       throw()
01099    {
01100 
01101       tlm_message[0] = tlm;
01102       HOWtime[0] = static_cast<long>( how );
01103       ASalert[0] = asalert;
01104       weeknum    = fullweek;
01105       codeflags  = cflags;
01106       accFlag    = acc;
01107       health     = svhealth;
01108       IODC       = iodc;
01109       L2Pdata    = l2pdata;
01110       Tgd        = tgd;
01111       Toc        = toc;
01112       af2        = Af2;
01113       af1        = Af1;
01114       af0        = Af0;
01115       tracker    = Tracker;
01116       PRNID      = prn;
01117       haveSubframe[0] = true;
01118       // convert the accuracy flag to a value...
01119       accuracy = gpstk::ura2accuracy(accFlag);
01120       return *this;
01121    }
01122 
01123    EngEphemeris& EngEphemeris::setSF2( unsigned tlm, double how, short asalert,
01124                                        short iode, double crs, double Dn,
01125                                        double m0, double cuc, double Ecc,
01126                                        double cus, double ahalf, double toe,
01127                                        short fitInt )
01128       throw()
01129    {
01130       tlm_message[1] = tlm;
01131       HOWtime[1] = static_cast<long>( how );
01132       ASalert[1] = asalert;
01133       IODE       = iode;
01134       Crs        = crs;
01135       dn         = Dn;
01136       M0         = m0;
01137       Cuc        = cuc;
01138       ecc        = Ecc;
01139       Cus        = cus;
01140       Ahalf      = ahalf;
01141       Toe        = toe;
01142       fitint     = fitInt;
01143       haveSubframe[1] = true;
01144       return *this;
01145    }
01146 
01147 
01148    EngEphemeris& EngEphemeris::setSF3( unsigned tlm, double how, short asalert,
01149                                        double cic, double Omega0, double cis,
01150                                        double I0, double crc, double W,
01151                                        double OmegaDot, double IDot )
01152       throw()
01153    {
01154       tlm_message[2] = tlm;
01155       HOWtime[2] = static_cast<long>( how );
01156       ASalert[2] = asalert;
01157       Cic        = cic;
01158       OMEGA0     = Omega0;
01159       Cis        = cis;
01160       i0         = I0;
01161       Crc        = crc;
01162       w          = W;
01163       OMEGAdot   = OmegaDot;
01164       idot       = IDot;
01165       haveSubframe[2] = true;
01166       return *this;
01167    }
01168 
01169    static void timeDisplay( ostream & os, const gpstk::DayTime& t)
01170    {
01171          // Convert to daytime struct from GPS wk,SOW to M/D/Y, H:M:S.
01172       os << setw(4) << t.GPSfullweek() << "(";
01173       os << setw(4) << t.GPS10bitweek() << ")  ";
01174       os << setw(6) << setfill(' ') << t.GPSsecond() << "   ";
01175 
01176       switch (t.GPSday())
01177       {
01178          case 0: os << "Sun-0"; break;
01179          case 1: os << "Mon-1"; break;
01180          case 2: os << "Tue-2"; break;
01181          case 3: os << "Wed-3"; break;
01182          case 4: os << "Thu-4"; break;
01183          case 5: os << "Fri-5"; break;
01184          case 6: os << "Sat-6"; break;
01185          default: break;
01186       }
01187       os << "   " << t.printf("%3j   %5.0s   %02m/%02d/%04Y   %02H:%02M:%02S");
01188    }
01189 
01190 
01191    static void shortcut(ostream & os, const long HOW )
01192    {
01193       short DOW, hour, min, sec;
01194       long SOD, SOW;
01195       short SOH;
01196 
01197       SOW = static_cast<long>( HOW );
01198       DOW = static_cast<short>( SOW / DayTime::SEC_DAY );
01199       SOD = SOW - static_cast<long>( DOW * DayTime::SEC_DAY );
01200       hour = static_cast<short>( SOD/3600 );
01201 
01202       SOH = static_cast<short>( SOD - (hour*3600) );
01203       min = SOH/60;
01204 
01205       sec = SOH - min * 60;
01206       switch (DOW)
01207       {
01208          case 0: os << "Sun-0"; break;
01209          case 1: os << "Mon-1"; break;
01210          case 2: os << "Tue-2"; break;
01211          case 3: os << "Wed-3"; break;
01212          case 4: os << "Thu-4"; break;
01213          case 5: os << "Fri-5"; break;
01214          case 6: os << "Sat-6"; break;
01215          default: break;
01216       }
01217 
01218       os << ":" << setfill('0')
01219          << setw(2) << hour
01220          << ":" << setw(2) << min
01221          << ":" << setw(2) << sec
01222          << setfill(' ');
01223    }
01224 
01225    void EngEphemeris :: dump(ostream& s) const
01226    {
01227       ios::fmtflags oldFlags = s.flags();
01228 
01229       s.setf(ios::fixed, ios::floatfield);
01230       s.setf(ios::right, ios::adjustfield);
01231       s.setf(ios::uppercase);
01232       s.precision(0);
01233       s.fill(' ');
01234 
01235       s << "****************************************************************"
01236         << "************" << endl
01237         << "Broadcast Ephemeris (Engineering Units)" << endl
01238         << endl
01239         << "PRN : " << setw(2) << PRNID << endl
01240         << endl;
01241 
01242 
01243       s << "              Week(10bt)     SOW     DOW   UTD     SOD"
01244         << "   MM/DD/YYYY   HH:MM:SS\n";
01245       s << "Clock Epoch:  ";
01246       timeDisplay(s, getEpochTime());
01247       s << endl;
01248       s << "Eph Epoch:    ";
01249       timeDisplay(s, getEphemerisEpoch());
01250       s << endl;
01251 
01252 #if 0
01253          // FIX when moved from sf123, the tot got zapped.. because in
01254          // order for engephemeris to be able to use such a thing, it
01255          // needs to be pulled out of as-broadcast bits somehow.
01256       s << "Transmit time:" << setw(4) << weeknum << ", sow=" << Tot.GPSsecond() << endl
01257         << "Fit interval flag :  " << setw(2) << fitint
01258         << " (" << fitintlen << " hours)" << endl;
01259 #elsif 0
01260       s << "Transmit time:" << setw(4) << weeknum << endl
01261         << "Fit interval flag :  " << setw(2) << fitint
01262         << " (" << getFitInt() << " hours)" << endl;
01263 #endif
01264          // nuts to the above, let's just make it look like navdump output
01265       s << "Transmit Week:" << setw(4) << weeknum << endl
01266         << "Fit interval flag :  " << fitint << endl;
01267 
01268       s << endl
01269         << "          SUBFRAME OVERHEAD"
01270         << endl
01271         << endl
01272         << "               SOW    DOW:HH:MM:SS     IOD    ALERT   A-S\n";
01273       for (int i=0;i<3;i++)
01274       {
01275          s << "SF" << setw(1) << (i+1)
01276            << " HOW:   " << setw(7) << HOWtime[i]
01277            << "  ";
01278 
01279          shortcut( s, HOWtime[i]);
01280          if (i==0)
01281             s << "   ";
01282          else
01283             s << "    ";
01284 
01285          s << "0x" << setfill('0') << hex;
01286 
01287          if (i==0)
01288             s << setw(3) << IODC;
01289          else
01290             s << setw(2) << IODE;
01291 
01292          s << dec << "      " << setfill(' ');
01293 
01294          if (ASalert[i] & 0x0002)    // "Alert" bit handling
01295             s << "1     ";
01296          else
01297             s << "0     ";
01298 
01299          if (ASalert[i] & 0x0001)     // A-S flag handling
01300             s << " on";
01301          else
01302             s << "off";
01303          s << endl;
01304       }
01305 
01306       s.setf(ios::scientific, ios::floatfield);
01307       s.precision(8);
01308 
01309       s << endl
01310         << "           CLOCK"
01311         << endl
01312         << endl
01313         << "Bias T0:     " << setw(16) << af0 << " sec" << endl
01314         << "Drift:       " << setw(16) << af1 << " sec/sec" << endl
01315         << "Drift rate:  " << setw(16) << af2 << " sec/(sec**2)" << endl
01316         << "Group delay: " << setw(16) << Tgd << " sec" << endl;
01317 
01318       s << endl
01319         << "           ORBIT PARAMETERS"
01320         << endl
01321         << endl
01322         << "Semi-major axis:       " << setw(16) << Ahalf  << " m**.5" << endl
01323         << "Motion correction:     " << setw(16) << dn     << " rad/sec"
01324         << endl
01325         << "Eccentricity:          " << setw(16) << ecc    << endl
01326         << "Arg of perigee:        " << setw(16) << w      << " rad" << endl
01327         << "Mean anomaly at epoch: " << setw(16) << M0     << " rad" << endl
01328         << "Right ascension:       " << setw(16) << OMEGA0 << " rad    "
01329         << setw(16) << OMEGAdot << " rad/sec" << endl
01330         << "Inclination:           " << setw(16) << i0     << " rad    "
01331         << setw(16) << idot     << " rad/sec" << endl;
01332 
01333       s << endl
01334         << "           HARMONIC CORRECTIONS"
01335         << endl
01336         << endl
01337         << "Radial        Sine: " << setw(16) << Crs << " m    Cosine: "
01338         << setw(16) << Crc << " m" << endl
01339         << "Inclination   Sine: " << setw(16) << Cis << " rad  Cosine: "
01340         << setw(16) << Cic << " rad" << endl
01341         << "In-track      Sine: " << setw(16) << Cus << " rad  Cosine: "
01342         << setw(16) << Cuc << " rad" << endl;
01343 
01344       s << endl
01345         << "           SV STATUS"
01346         << endl
01347         << endl
01348         << "Health bits:   0x" << setfill('0')  << setw(2) << health
01349         << "      URA index: " << setfill(' ') << setw(4) << accFlag << endl
01350         << "Code on L2:   ";
01351 
01352       switch (codeflags)
01353       {
01354          case 0:
01355             s << "reserved ";
01356             break;
01357 
01358          case 1:
01359             s << " P only  ";
01360             break;
01361 
01362          case 2:
01363             s << " C/A only";
01364             break;
01365 
01366          case 3:
01367             s << " P & C/A ";
01368             break;
01369 
01370          default:
01371             break;
01372 
01373       }
01374 
01375       s << "    L2 P Nav data:          ";
01376       if (L2Pdata!=0)
01377          s << "off";
01378       else
01379          s << "on";
01380 
01381       s << endl
01382         << endl;
01383       s.flags(oldFlags);
01384 
01385    } // end of SF123::dump()
01386 
01387    ostream& operator<<(ostream& s, const EngEphemeris& eph)
01388    {
01389       eph.dump(s);
01390       return s;
01391 
01392 /* this appears to be more like the dump_eph_table routine of gappc
01393  * which dumped the bce table.
01394 
01395       s.setf(ios::right);
01396       s << "prn:" << setw(2) << eph.PRNID
01397         << ", HOW[0]:" << hex  << setfill('0') << setw(5) << eph.getHOWTime(1)
01398         << ", IODC:" << hex << setw(3) << eph.getIODC()
01399         << dec << setfill(' ') << setw(0)
01400         << ", Toe: [" << eph.getToc()-1800*eph.getFitInt()
01401         << "..." << eph.getToc()+1800*eph.getFitInt()
01402         << ")";
01403 */
01404    } // end of operator<<
01405 
01406 } // namespace

Generated on Thu Feb 9 03:30:56 2012 for GPS ToolKit Software Library by  doxygen 1.3.9.1