EarthOrientation.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: EarthOrientation.cpp 2741 2011-06-22 16:37:02Z nwu $"
00002 
00003 //============================================================================
00004 //
00005 //  This file is part of GPSTk, the GPS Toolkit.
00006 //
00007 //  The GPSTk is free software; you can redistribute it and/or modify
00008 //  it under the terms of the GNU Lesser General Public License as published
00009 //  by the Free Software Foundation; either version 2.1 of the License, or
00010 //  any later version.
00011 //
00012 //  The GPSTk is distributed in the hope that it will be useful,
00013 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //  GNU Lesser General Public License for more details.
00016 //
00017 //  You should have received a copy of the GNU Lesser General Public
00018 //  License along with GPSTk; if not, write to the Free Software Foundation,
00019 //  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 //
00021 //  Copyright 2004, The University of Texas at Austin
00022 //
00023 //============================================================================
00024 
00025 //============================================================================
00026 //
00027 //This software developed by Applied Research Laboratories at the University of
00028 //Texas at Austin, under contract to an agency or agencies within the U.S.
00029 //Department of Defense. The U.S. Government retains all rights to use,
00030 //duplicate, distribute, disclose, or release this software.
00031 //
00032 //Pursuant to DoD Directive 523024
00033 //
00034 // DISTRIBUTION STATEMENT A: This software has been approved for public
00035 //                           release, distribution is unlimited.
00036 //
00037 //=============================================================================
00038 
00048 //------------------------------------------------------------------------------------
00049 // system includes
00050 #include <fstream>
00051 // GPSTk
00052 #include "icd_200_constants.hpp"    // for TWO_PI
00053 #include "EarthOrientation.hpp"
00054 
00055 //------------------------------------------------------------------------------------
00056 using namespace std;
00057 
00058 namespace gpstk
00059 {
00060    //---------------------------------------------------------------------------------
00061    ostream& operator<<(ostream& os, const EarthOrientation& eo)
00062    {
00063       os << " " << setw(17) << setprecision(6) << eo.xp
00064          << " " << setw(17) << setprecision(6) << eo.yp
00065          << " " << setw(17) << setprecision(7) << eo.UT1mUTC;
00066       return os;
00067    }
00068 
00069    //---------------------------------------------------------------------------------
00070    // class EOPPrediction
00071    //---------------------------------------------------------------------------------
00072    // load the EOPPrediction in the given file
00073    // return  0 if ok, -1 if error reading file
00074    int EOPPrediction::loadFile(string filename)
00075       throw(FileMissingException)
00076    {
00077       bool ok;
00078       int n;
00079       string line,word;
00080       ifstream inpf(filename.c_str());
00081       if(!inpf) {
00082          FileMissingException fme("Could not open EOPP file " + filename);
00083          GPSTK_THROW(fme);
00084       }
00085 
00086       ok = true;
00087       n = 0;         // n is line number
00088       while(!inpf.eof() && inpf.good()) {
00089          getline(inpf,line);
00090          StringUtils::stripTrailing(line,'\r');
00091          if(inpf.bad()) break;
00092          if(line.size() > 80) { ok=false; break; }
00093          switch(n) {
00094             case 0:
00095                if(line.size() < 76) { ok=false; break; }
00096                word = line.substr( 0,10); ta = StringUtils::asDouble(word);
00097                word = line.substr(10,10);  A = StringUtils::asDouble(word);
00098                word = line.substr(20,10);  B = StringUtils::asDouble(word);
00099                word = line.substr(30,10); C1 = StringUtils::asDouble(word);
00100                word = line.substr(40,10); C2 = StringUtils::asDouble(word);
00101                word = line.substr(50,10); D1 = StringUtils::asDouble(word);
00102                word = line.substr(60,10); D2 = StringUtils::asDouble(word);
00103                word = line.substr(70, 6); P1 = StringUtils::asDouble(word);
00104                break;
00105             case 1:
00106                if(line.size() < 78) { ok=false; break; }
00107                word = line.substr( 0, 6); P2 = StringUtils::asDouble(word);
00108                word = line.substr( 6,10);  E = StringUtils::asDouble(word);
00109                word = line.substr(16,10);  F = StringUtils::asDouble(word);
00110                word = line.substr(26,10); G1 = StringUtils::asDouble(word);
00111                word = line.substr(36,10); G2 = StringUtils::asDouble(word);
00112                word = line.substr(46,10); H1 = StringUtils::asDouble(word);
00113                word = line.substr(56,10); H2 = StringUtils::asDouble(word);
00114                word = line.substr(66, 6); Q1 = StringUtils::asDouble(word);
00115                word = line.substr(72, 6); Q2 = StringUtils::asDouble(word);
00116                break;
00117             case 2:
00118                if(line.size() < 70) { ok=false; break; }
00119                word = line.substr( 0,10); tb = StringUtils::asDouble(word);
00120                word = line.substr(10,10);  I = StringUtils::asDouble(word);
00121                word = line.substr(20,10);  J = StringUtils::asDouble(word);
00122                word = line.substr(30,10); K1 = StringUtils::asDouble(word);
00123                word = line.substr(40,10); K2 = StringUtils::asDouble(word);
00124                word = line.substr(50,10); K3 = StringUtils::asDouble(word);
00125                word = line.substr(60,10); K4 = StringUtils::asDouble(word);
00126                break;
00127             case 3:
00128                if(line.size() < 76) { ok=false; break; }
00129                word = line.substr( 0,10); L1 = StringUtils::asDouble(word);
00130                word = line.substr(10,10); L2 = StringUtils::asDouble(word);
00131                word = line.substr(20,10); L3 = StringUtils::asDouble(word);
00132                word = line.substr(30,10); L4 = StringUtils::asDouble(word);
00133                word = line.substr(40, 9); R1 = StringUtils::asDouble(word);
00134                word = line.substr(49, 9); R2 = StringUtils::asDouble(word);
00135                word = line.substr(58, 9); R3 = StringUtils::asDouble(word);
00136                word = line.substr(67, 9); R4 = StringUtils::asDouble(word);
00137                break;
00138             case 4:
00139                if(line.size() < 16) { ok=false; break; }
00140                word = line.substr( 0, 4);  TAIUTC = StringUtils::asInt(word);
00141                word = line.substr( 4, 5);  SerialNo = StringUtils::asInt(word);
00142                // this actually integer : mjd of begin valid period
00143                word = line.substr( 9, 7);  tv = StringUtils::asDouble(word);
00144                Info = line.substr(16,19);
00145                break;
00146          }     // end switch on n=line number
00147          if(!ok) break;
00148          n++;
00149       };
00150       inpf.close();
00151       if(!ok) {
00152          FileMissingException fme("EOPP File " + filename
00153             + " is corrupted or wrong format");
00154          GPSTK_THROW(fme);
00155       }
00156       if(inpf.bad()) return -1;
00157       return 0;
00158    }
00159 
00160    //---------------------------------------------------------------------------------
00161    // generate serial number (NGA files are named EOPP<sn>.txt) from epoch
00162    // SN = Year (1 digit) + week of year
00163    int EOPPrediction::getSerialNumber(DayTime& t)
00164       throw(DayTime::DayTimeException)
00165    {
00166       int w2 = t.GPSfullweek()-1;            // the previous week
00167       if(w2 < 0) {
00168          using namespace StringUtils;
00169          DayTime::DayTimeException dte("Invalid week in EOPP file: "
00170                + asString<short>(w2));
00171          GPSTK_THROW(dte);
00172       }
00173 
00174       int yr,w1;
00175       try {
00176          DayTime ht;
00177          ht.setGPSfullweek(w2,475200.0);     // Friday (noon) of previous week
00178          yr = ht.year();                     // save the year for later
00179          ht.setYMDHMS(yr,1,1,0,0,0.0);       // first day of that year
00180          w1 = ht.GPSfullweek();
00181          if(ht.dayOfWeek() == 6) w1++;       // GPS week of first Friday in the year
00182          yr = yr % 10;                       // last digit of the year
00183       }
00184       catch(DayTime::DayTimeException& dte) {
00185          GPSTK_RETHROW(dte);
00186       }
00187       return (100*yr + w2-w1+1);             // SN = Year (1 digit) + week of year
00188    }
00189 
00190    //---------------------------------------------------------------------------------
00191    // Compute the Earth orientation parameters at the given epoch.
00192    // TD how to warn if input is outside limits of validity?
00193    EarthOrientation EOPPrediction::computeEOP(int& mjd) const
00194       throw(DayTime::DayTimeException)
00195    {
00196       DayTime t;
00197       try { t.setMJD(double(mjd)); }
00198       catch(DayTime::DayTimeException& dte) { GPSTK_RETHROW(dte); }
00199       return computeEOP(t);
00200    }
00201 
00202    //---------------------------------------------------------------------------------
00203    //                      2                           2
00204    // xp(t)= A + B(t-ta) + SUM(Cj sin[2pi(t-ta)/Pj]) + SUM(Dj cos[2pi(t-ta)/Pj])
00205    //                     j=1                         j=1
00206    //
00207    //                      2                           2
00208    // yp(t)= E + F(t-ta) + SUM(Gk sin[2pi(t-ta)/Qk]) + SUM(Hk cos[2pi(t-ta)/Qk])
00209    //                     k=1                         k=1
00210    //
00211    //                          4                           4
00212    // UT1-UTC(t)= I+J(t-tb) + SUM(Km sin[2pi(t-tb)/Rm]) + SUM(Lm cos[2pi(t-tb)/Rm])
00213    //                         m=1                         m=1
00214    //---------------------------------------------------------------------------------
00215    EarthOrientation EOPPrediction::computeEOP(DayTime& ep) const
00216       throw()
00217    {
00218       double t,dt,arg;
00219       EarthOrientation eo;
00220 
00221       t = ep.MJD() + ep.secOfDay()/86400.0;
00222       //if(t < tv || t > tv+7) // TD warn - outside valid range
00223       //
00224       dt = t - ta;
00225       arg = TWO_PI*dt;
00226       eo.xp = A + B*dt + C1*sin(arg/P1) + D1*cos(arg/P1)
00227                        + C2*sin(arg/P2) + D2*cos(arg/P2);
00228       eo.yp = E + F*dt + G1*sin(arg/Q1) + H1*cos(arg/Q1)
00229                        + G2*sin(arg/Q2) + H2*cos(arg/Q2);
00230 
00231       dt = t - tb;
00232       arg = TWO_PI*dt;
00233       eo.UT1mUTC = I + J*dt
00234          + K1*sin(arg/R1) + L1*cos(arg/R1)
00235          + K2*sin(arg/R2) + L2*cos(arg/R2)
00236          + K3*sin(arg/R3) + L3*cos(arg/R3)
00237          + K4*sin(arg/R4) + L4*cos(arg/R4);
00238 
00239       return eo;
00240    }
00241 
00242    //---------------------------------------------------------------------------------
00243    // straight from the doc
00244    ostream& operator<<(ostream& os, const EOPPrediction& eopp)
00245    {
00246       os << fixed
00247          << setw(10) << setprecision(2) << eopp.ta
00248          << setw(10) << setprecision(6) << eopp.A
00249          << setw(10) << setprecision(6) << eopp.B
00250          << setw(10) << setprecision(6) << eopp.C1
00251          << setw(10) << setprecision(6) << eopp.C2
00252          << setw(10) << setprecision(6) << eopp.D1
00253          << setw(10) << setprecision(6) << eopp.D2
00254          << setw( 6) << setprecision(2) << eopp.P1
00255          << "    " << endl;
00256       os << setw( 6) << setprecision(2) << eopp.P2
00257          << setw(10) << setprecision(6) << eopp.E
00258          << setw(10) << setprecision(6) << eopp.F
00259          << setw(10) << setprecision(6) << eopp.G1
00260          << setw(10) << setprecision(6) << eopp.G2
00261          << setw(10) << setprecision(6) << eopp.H1
00262          << setw(10) << setprecision(6) << eopp.H2
00263          << setw( 6) << setprecision(2) << eopp.Q1
00264          << setw( 6) << setprecision(2) << eopp.Q2
00265          << "  " << endl;
00266       os << setw(10) << setprecision(2) << eopp.tb
00267          << setw(10) << setprecision(6) << eopp.I
00268          << setw(10) << setprecision(6) << eopp.J
00269          << setw(10) << setprecision(6) << eopp.K1
00270          << setw(10) << setprecision(6) << eopp.K2
00271          << setw(10) << setprecision(6) << eopp.K3
00272          << setw(10) << setprecision(6) << eopp.K4
00273          << "          " << endl;
00274       os << setw(10) << setprecision(6) << eopp.L1
00275          << setw(10) << setprecision(6) << eopp.L2
00276          << setw(10) << setprecision(6) << eopp.L3
00277          << setw(10) << setprecision(6) << eopp.L4
00278          << setw( 9) << setprecision(4) << eopp.R1
00279          << setw( 9) << setprecision(4) << eopp.R2
00280          << setw( 9) << setprecision(4) << eopp.R3
00281          << setw( 9) << setprecision(4) << eopp.R4
00282          << "    " << endl;
00283       os << setw(4) << eopp.TAIUTC
00284          << setw(5) << eopp.SerialNo
00285          << setw(6) << int(eopp.tv+0.5)
00286          << " " << eopp.Info
00287          << "                    "
00288          << "                    "
00289          << "      ";
00290       return os;
00291    }
00292 
00293    //---------------------------------------------------------------------------------
00294    // class EOPStore
00295    //---------------------------------------------------------------------------------
00296    // Add to the store directly -- not recommended,
00297    // use the form that takes EOPPrediction
00298    void EOPStore::addEOP(int mjd, EarthOrientation& eop)
00299       throw()
00300    {
00301       mapMJD_EOP[mjd] = eop;
00302 
00303       if(begMJD == -1 || endMJD == -1) {
00304          begMJD = endMJD = mjd;
00305       }
00306       else if(mjd < begMJD) {
00307          begMJD = mjd;
00308       }
00309       else if(mjd > endMJD) {
00310          endMJD = mjd;
00311       }
00312    }
00313 
00314    //---------------------------------------------------------------------------------
00315    // Add to the store by computing using an EOPPrediction,
00316    // this is the usual way.
00317    // @param MJD integer MJD at which to add EOPs
00318    // @return non-0 if MJD is outside range
00319    int EOPStore::addEOP(int mjd, EOPPrediction& eopp)
00320       throw(DayTime::DayTimeException)
00321    {
00322       EarthOrientation eo;
00323       try {
00324          eo = eopp.computeEOP(mjd);
00325       }
00326       catch(DayTime::DayTimeException& dte)
00327       {
00328          GPSTK_RETHROW(dte);
00329       }
00330 
00331       addEOP(mjd,eo);
00332 
00333       return 0;
00334    }
00335 
00336    //---------------------------------------------------------------------------------
00337    // Add EOPs to the store via an inpu file: either an EOPP file
00338    // or a flat file produced by USNO (see http://maia.usno.navy.mil/
00339    // and get either file 'finals.data' or finals2000A.data').
00340    // @param filename Name of file to read, including path.
00341    void EOPStore::addFile(const string& filename)
00342       throw(FileMissingException)
00343    {
00344       try {
00345          addEOPPFile(filename);
00346       }
00347       catch(FileMissingException& fme)
00348       {
00349          if(StringUtils::matches(fme.getText(),string("wrong format")).empty()) {
00350             GPSTK_RETHROW(fme);
00351          }
00352 
00353          // try other format
00354          try {
00355             addIERSFile(filename);
00356          }
00357          catch(FileMissingException& fme)
00358          {
00359             GPSTK_RETHROW(fme);
00360          }
00361       }
00362    }
00363 
00364    //---------------------------------------------------------------------------------
00365    // Add EOPs to the store via an EOPP file:
00366    // read the EOPPrediction from the file and then compute EOPs
00367    // for all days within the valid range.
00368    // @param filename Name of file to read, including path.
00369    void EOPStore::addEOPPFile(const string& filename)
00370       throw(FileMissingException)
00371    {
00372       // read the file into an EOPPrediction
00373       EOPPrediction eopp;
00374       try {
00375          eopp.loadFile(filename);
00376       }
00377       catch(FileMissingException& fme)
00378       {
00379          GPSTK_RETHROW(fme);
00380       }
00381 
00382       // pull out the beginning of the valid time range
00383       int mjd;
00384       mjd = eopp.getValidTime();
00385       // add all 7 days
00386       for(int i=0; i<7; i++) {
00387          EarthOrientation eo;
00388          eo = eopp.computeEOP(mjd);
00389          addEOP(mjd,eo);
00390          mjd++;
00391       }
00392    }
00393 
00394    //---------------------------------------------------------------------------------
00395    // see http://maia.usno.navy.mil/readme.finals
00396    void EOPStore::addIERSFile(const string& filename)
00397       throw(FileMissingException)
00398    {
00399       bool ok;
00400       int n,mjd;
00401       double fracmjd;
00402       string line,word;
00403 
00404       ifstream inpf(filename.c_str());
00405       if(!inpf) {
00406          FileMissingException fme("Could not open IERS file " + filename);
00407          GPSTK_THROW(fme);
00408       }
00409 
00410       ok = true;
00411       while(!inpf.eof() && inpf.good()) {
00412          getline(inpf,line);
00413          StringUtils::stripTrailing(line,'\r');
00414          if(inpf.eof()) break;
00415             // line length is actually 187
00416          if(inpf.bad() || line.size() < 70) { ok = false; break; }
00417          EarthOrientation eo;
00418          mjd = StringUtils::asInt(line.substr(7,5));
00419          eo.xp = StringUtils::asDouble(line.substr(18,9));       // arcseconds
00420          eo.yp = StringUtils::asDouble(line.substr(37,9));       // arcseconds
00421          eo.UT1mUTC = StringUtils::asDouble(line.substr(58,10)); // seconds
00422 
00423          addEOP(mjd,eo);
00424       };
00425       inpf.close();
00426 
00427       if(!ok) {
00428          FileMissingException fme("IERS File " + filename
00429             + " is corrupted or wrong format");
00430          GPSTK_THROW(fme);
00431       }
00432    }
00433 
00434    //---------------------------------------------------------------------------------
00435    // Edit the store by deleting all entries before(after)
00436    //  the given min(max) MJDs. If mjdmin is later than mjdmax,
00437    //  the two times are switched.
00438    //  @param mjdmin integer MJD desired earliest store time.
00439    //  @param mjdmax integer MJD desired latest store time.
00440    void EOPStore::edit(int mjdmin, int mjdmax)
00441       throw()
00442    {
00443       if(mjdmin > mjdmax) {
00444          int m=mjdmin;
00445          mjdmin = mjdmax;
00446          mjdmax = m;
00447       }
00448 
00449       if(mjdmin > endMJD) return;
00450       if(mjdmax < begMJD) return;
00451 
00452       map<int,EarthOrientation>::iterator it;
00453       it = mapMJD_EOP.lower_bound(mjdmin);
00454       if(it != mapMJD_EOP.begin())
00455          mapMJD_EOP.erase(mapMJD_EOP.begin(), it);
00456 
00457       it = mapMJD_EOP.upper_bound(mjdmax);
00458       if(it != mapMJD_EOP.end())
00459          mapMJD_EOP.erase(it, mapMJD_EOP.end());
00460 
00461       it = mapMJD_EOP.begin();
00462       if(it == mapMJD_EOP.end())
00463          begMJD = -1;
00464       else
00465          begMJD = it->first;
00466 
00467       it = mapMJD_EOP.end();
00468       if(--it == mapMJD_EOP.end())
00469          endMJD = -1;
00470       else
00471          endMJD = it->first;
00472    }
00473 
00474    //---------------------------------------------------------------------------------
00475    // Dump the store to cout.
00476    // @param detail determines how much detail to include in the output
00477    //   0 start and stop times (MJD), and number of EOPs.
00478    //   1 list of all times and EOPs.
00479    void EOPStore::dump(short detail, ostream& os) const
00480       throw()
00481    {
00482       DayTime tt;
00483       os << "EOPStore dump (" << mapMJD_EOP.size() << " entries):\n";
00484       os << " Time limits: [MJD " << begMJD << " - " << endMJD << "]";
00485       tt.setMJD(double(begMJD));
00486       os << " = [m/d/y " << tt.printf("%m/%d/%Y");
00487       tt.setMJD(double(endMJD));
00488       os << " - " << tt.printf("%m/%d/%Y") << "]" << endl;
00489       if(detail > 0) {
00490          int lastmjd=-1;
00491          map<int,EarthOrientation>::const_iterator it;
00492          for(it=mapMJD_EOP.begin(); it != mapMJD_EOP.end(); it++) {
00493             if(lastmjd != -1 && it->first - lastmjd > 1)
00494                os << " ....." << endl;
00495             os << " " << it->first << " " << it->second
00496                << "     (" << setfill('0') << setw(3)
00497                << EOPPrediction::getSerialNumber(it->first) << setfill(' ') << ")"
00498                << endl;
00499             lastmjd = it->first;
00500          }
00501       }
00502    }
00503 
00504    //---------------------------------------------------------------------------------
00505    // Get the EOP at the given epoch and return it.
00506    // @param t DayTime at which to compute the EOPs.
00507    // @return EarthOrientation EOPs at time t.
00508    // @throw InvalidRequest if the (int) MJDs on either side of t
00509    // cannot be found in the map.
00510    EarthOrientation EOPStore::getEOP(DayTime& t) const
00511       throw(InvalidRequest)
00512    {
00513          // find the EOs before and after epoch
00514       int loMJD = int(t.MJD());
00515       int hiMJD = loMJD + 1;
00516          // find these EOPs
00517       map<int,EarthOrientation>::const_iterator hit,lit;
00518       lit = mapMJD_EOP.find(loMJD);
00519       hit = mapMJD_EOP.find(hiMJD);
00520       if(lit == mapMJD_EOP.end() || hit == mapMJD_EOP.end()) {
00521          InvalidRequest ire(string("Time tag (MJD=")
00522          + (lit == mapMJD_EOP.end() ?
00523                StringUtils::asString(loMJD) : StringUtils::asString(hiMJD))
00524          + string(") not found within the EOP store - EOPP files are out-of-date"));
00525          GPSTK_THROW(ire);
00526       }
00527          // linearly interpolate to get EOP at the desired time
00528       EarthOrientation eo;
00529       double dt=t.MJD()-double(loMJD);
00530       eo.xp = (1.0-dt) * lit->second.xp + dt * hit->second.xp;
00531       eo.yp = (1.0-dt) * lit->second.yp + dt * hit->second.yp;
00532       eo.UT1mUTC = (1.0-dt) * lit->second.UT1mUTC + dt * hit->second.UT1mUTC;
00533 
00534       return eo;
00535    }
00536 
00537 } // end namespace gpstk
00538 //------------------------------------------------------------------------------------

Generated on Wed Feb 8 03:30:59 2012 for GPS ToolKit Software Library by  doxygen 1.3.9.1