Rinex3ClockHeader.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: Rinex3ClockHeader.cpp 3319 2012-09-19 16:58:10Z prestonherrmann $"
00002 
00009 //============================================================================
00010 //
00011 //  This file is part of GPSTk, the GPS Toolkit.
00012 //
00013 //  The GPSTk is free software; you can redistribute it and/or modify
00014 //  it under the terms of the GNU Lesser General Public License as published
00015 //  by the Free Software Foundation; either version 2.1 of the License, or
00016 //  any later version.
00017 //
00018 //  The GPSTk is distributed in the hope that it will be useful,
00019 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00020 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021 //  GNU Lesser General Public License for more details.
00022 //
00023 //  You should have received a copy of the GNU Lesser General Public
00024 //  License along with GPSTk; if not, write to the Free Software Foundation,
00025 //  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
00026 //
00027 //  Octavian Andrei - FGI ( http://www.fgi.fi ). 2008-2010
00028 //
00029 //============================================================================
00030 
00031 //system
00032 #include<cmath>
00033 //GPSTk
00034 #include "CivilTime.hpp"
00035 #include "Rinex3ClockHeader.hpp"
00036 #include "Rinex3ClockStream.hpp"
00037 #include "StringUtils.hpp"
00038 
00039 using namespace std;
00040 using namespace gpstk::StringUtils;
00041 
00042 namespace gpstk
00043 {
00044    const string Rinex3ClockHeader::versionString     =  "RINEX VERSION / TYPE";
00045    const string Rinex3ClockHeader::runByString       =  "PGM / RUN BY / DATE";
00046    const string Rinex3ClockHeader::commentString     =  "COMMENT";
00047    const string Rinex3ClockHeader::numObsString      =  "SYS / # / OBS TYPES";
00048    const string Rinex3ClockHeader::timeSystemString  =  "TIME SYSTEM ID";
00049    const string Rinex3ClockHeader::leapSecondsString =  "LEAP SECONDS";
00050    const string Rinex3ClockHeader::sysDCBString      =  "SYS / DCBS APPLIED";
00051    const string Rinex3ClockHeader::sysPCVString      =  "SYS / PCVS APPLIED";
00052    const string Rinex3ClockHeader::dataTypesString   =  "# / TYPES OF DATA";
00053    const string Rinex3ClockHeader::stationNameString =  "STATION NAME / NUM";
00054    const string Rinex3ClockHeader::calibrationClkString = "STATION CLK REF";
00055    const string Rinex3ClockHeader::acNameString      =   "ANALYSIS CENTER";
00056    const string Rinex3ClockHeader::numRefClkString   =  "# OF CLK REF";
00057    const string Rinex3ClockHeader::analysisClkRefString = "ANALYSIS CLK REF";
00058    const string Rinex3ClockHeader::numStationsString = "# OF SOLN STA / TRF";
00059    const string Rinex3ClockHeader::solnStaNameString =  "SOLN STA NAME / NUM";
00060    const string Rinex3ClockHeader::numSatsString     =  "# OF SOLN SATS";
00061    const string Rinex3ClockHeader::prnListString     =  "PRN LIST";
00062    const string Rinex3ClockHeader::endOfHeader       =  "END OF HEADER";
00063 
00064 
00065    const Rinex3ClockHeader::RinexClkType 
00066       Rinex3ClockHeader::UN("UN", "Unknown or Invalid");
00067    const Rinex3ClockHeader::RinexClkType 
00068       Rinex3ClockHeader::AR("AR", "analysis data for receiver clocks");
00069    const Rinex3ClockHeader::RinexClkType 
00070       Rinex3ClockHeader::AS("AS", "analysis data for satellite clocks");
00071    const Rinex3ClockHeader::RinexClkType 
00072       Rinex3ClockHeader::CR("CR", "calibration data");
00073    const Rinex3ClockHeader::RinexClkType 
00074       Rinex3ClockHeader::DR("DR", "discontinuity data");
00075    const Rinex3ClockHeader::RinexClkType 
00076       Rinex3ClockHeader::MS("MS", "monitor data");
00077 
00078       // Clear (empty out) header
00079    void Rinex3ClockHeader::clear(void)
00080    {
00081 
00082       version = 0.0;
00083       valid = 0;
00084       numObsTyp = 0;
00085       numSta = 0;
00086       numSVs = 0;
00087       leapSeconds = 0;
00088       ac = "";
00089       acName = "";
00090       fileProgram = "";
00091       fileAgency = "";
00092       date = "";
00093       clk0Name = "";
00094       calName = "";
00095       trfName = "";
00096       commentList.clear();
00097       obsTypeList.clear();
00098       dataTypeList.clear();
00099       refClkList.clear();
00100       clkNameList.clear();
00101       staCoordList.clear();
00102       timeFirst = CommonTime::BEGINNING_OF_TIME;
00103 
00104       return;
00105 
00106    }  // End of method 'Rinex3ClockHeader::clear()'
00107 
00108 
00109 
00110    void Rinex3ClockHeader::reallyPutRecord(FFStream& ffs) const 
00111       throw(std::exception, FFStreamError, StringException)
00112    {
00113       cout << "WARNING: There is no implementation for "
00114            << "Rinex3ClockHeader::reallyPutRecord()"
00115            << endl;
00116 
00117       return;
00118 
00119    }  // End of method 'Rinex3ClockHeader::reallyPutRecord()'
00120 
00121 
00122 
00123       // This function parses the entire header from the given stream
00124    void Rinex3ClockHeader::reallyGetRecord(FFStream& ffs)
00125       throw(std::exception, FFStreamError, 
00126             StringUtils::StringException)
00127    {
00128 
00129       Rinex3ClockStream& strm = dynamic_cast<Rinex3ClockStream&>(ffs);
00130 
00131          // if already read, just return
00132       if (strm.headerRead == true)
00133          return;
00134 
00135          // since we're reading a new header, we need to reinitialize
00136          // all our list structures.  all the other objects should be ok.
00137          // this also applies if we threw an exception the first time we read
00138          // the header and are now re-reading it. some of these could be full
00139          // and we need to empty them.
00140       clear();
00141 
00142          // one file line
00143       string line;
00144 
00145       while ( !(valid & endValid) )
00146       {
00147          strm.formattedGetLine(line);
00148          StringUtils::stripTrailing(line);
00149 
00150          if ( line.length() == 0 )
00151          {
00152             FFStreamError ffse("No data read!");
00153             GPSTK_THROW(ffse);
00154          }
00155          else if ( line.length() < 60 || line.length() > 80 )
00156          {
00157             FFStreamError ffse("Invalid line length");
00158             GPSTK_THROW(ffse);
00159          }
00160 
00161          try
00162          {
00163             ParseHeaderRecord(line);
00164          }
00165          catch(FFStreamError& ffse)
00166          {
00167             GPSTK_RETHROW(ffse);
00168          }
00169          
00170       }   // end while(not end of header)
00171 
00172 
00173          // If we get here, we should have reached the end of header line
00174       strm.header = *this;
00175       strm.headerRead = true;
00176 
00177       return;
00178 
00179    }  // End of method 'Rinex3ClockHeader::reallyGetRecord(FFStream& ffs)'
00180 
00181 
00182 
00183       // this function parses a single header record
00184    void Rinex3ClockHeader::ParseHeaderRecord(string& line)
00185       throw(FFStreamError)
00186    {
00187 
00188       string label(line, 60, 20);
00189 
00190          // RINEX VERSION / TYPE
00191       if ( label == versionString )
00192       {
00193 
00194          version  =  asDouble(line.substr(0,9));
00195          fileType =  strip(line.substr(20, 20));
00196 
00197             // check version 
00198          if ( version <= 0.0 || 
00199               version > 3.0 )
00200          {
00201             FFStreamError e( "This isn't an anticipated version number." + 
00202                               asString(version) );
00203             GPSTK_THROW(e);
00204          }
00205 
00206             // check type
00207          if ( (fileType[0] != 'C') &&
00208               (fileType[0] != 'c'))
00209          {
00210             FFStreamError e( "This isn't a Rinex3 Clock file type." );
00211             GPSTK_THROW(e);
00212          }
00213 
00214             // get satellite system
00215          string system_str = strip(line.substr(40, 20));
00216          try
00217          {
00218             system.fromString(system_str);
00219          }
00220          catch (Exception& e)
00221          {
00222             FFStreamError ffse( "Input satellite system is unsupported: " 
00223                                  + system_str + e.getText() );
00224             GPSTK_THROW(ffse);
00225          }
00226 
00227          valid |= versionValid;
00228 
00229       }
00230          // PGM / RUN BY / DATE
00231       else if ( label == runByString )
00232       {
00233 
00234          fileProgram =  strip(line.substr( 0, 20));
00235          fileAgency  =  strip(line.substr(20, 20));
00236          date        =  strip(line.substr(40, 20));
00237          isPGM = true;
00238 
00239          valid |= runByValid;
00240 
00241       }
00242          // COMMENT
00243       else if ( label == commentString )
00244       {
00245 
00246          string s = strip(line.substr(0, 60));
00247          commentList.push_back(s);
00248 
00249          valid |= commentValid;
00250 
00251       }
00252          // SYS / # / OBS TYPES
00253       else if ( label == numObsString )
00254       {
00255 
00256          numObsTyp   =  asInt( line.substr(3,3) );
00257 
00258          // TODO: more work needed
00259 
00260          valid |= numObsValid;
00261 
00262       }
00263          // TIME SYSTEM ID
00264       else if ( label == timeSystemString )
00265       {
00266 
00267          timeSystem = line.substr(3,3);
00268          valid |= timeSystemValid;
00269 
00270       }
00271          // LEAP SECONDS
00272       else if ( label == leapSecondsString )
00273       {
00274 
00275          leapSeconds = asInt(line.substr(0,6));
00276 
00277          valid |= leapSecondsValid;
00278 
00279       }
00280          // DCBS APPLIED
00281       else if ( label == sysDCBString )
00282       {
00283 
00284          valid |= sysDCBsValid;
00285 
00286       }
00287          // PCVS APPLIED
00288       else if ( label == sysPCVString )
00289       {
00290 
00291          valid |= sysPCVsValid;
00292 
00293       }
00294          // # / TYPES OF DATA
00295       else if ( label == dataTypesString )
00296       {
00297 
00298             // number of clock data types
00299          int nTyp = asInt(line.substr(0,6));
00300             // allocate memory
00301          dataTypeList.resize(nTyp);
00302             // add clock data types
00303          for( int iTyp = 0; iTyp < nTyp; iTyp++ )
00304          {
00305             dataTypeList[iTyp] = strip( line.substr(6*(iTyp+1),6) );
00306          }
00307 
00308          valid |= dataTypesValid;
00309 
00310       }
00311          // STATION NAME / NUM
00312       else if ( label == stationNameString )
00313       {
00314 
00315          clk0Name = line.substr(0,4);
00316 
00317          valid |= stationNameValid;
00318 
00319       }
00320          // STATION CLK REF
00321       else if ( label == calibrationClkString )
00322       {
00323          calName = strip( line.substr(0,60) );
00324 
00325          valid |= calibrationClkValid;
00326 
00327       }
00328          // ANALYSIS CENTER
00329       else if ( label == acNameString )
00330       {
00331 
00332          ac       =  line.substr(0, 3);
00333          acName   =  strip(line.substr(5,55));
00334          isAC     =  true;
00335 
00336          valid |= acNameValid;
00337 
00338       }
00339          // # OF CLK REF
00340       else if ( label == numRefClkString )
00341       {
00342 
00343             // new reference clock record
00344          Rinex3ClockHeader::RefClkRecord ref;
00345             // get the number of reference clocks for this record
00346          ref.nRef = asInt( line.substr(0,6) );
00347             // epoch
00348          if( asInt(line.substr(7,4)) )
00349          {
00350             CommonTime T0 = parseTime( line.substr(7,26) );
00351                // only one time
00352             if( timeFirst == CommonTime::BEGINNING_OF_TIME )
00353             {
00354                timeFirst = T0;
00355             }
00356                // left boundary
00357             ref.refWin[0] = T0 - timeFirst;
00358                // right boundary
00359             T0 = parseTime( line.substr(34,26) );
00360             ref.refWin[1] = T0 - timeFirst;
00361 
00362                // time inconsistency 
00363             if (T0 < timeFirst)
00364             {
00365                FFStreamError e( "Wrong epoch of file, expected epoch: " +
00366                                  timeFirst.asString() + " detected epoch: " +
00367                                  T0.asString() );
00368                GPSTK_THROW(e);
00369             }
00370          }
00371 
00372             // add the ref clk record to the list
00373          refClkList.push_back(ref);
00374 
00375          valid |= numRefClkValid;
00376 
00377       }
00379       else if ( label == analysisClkRefString )
00380       {
00381 
00382             // get the previous reference clock record
00383          std::list<RefClkRecord>::iterator iRef = refClkList.end();
00384          --iRef;
00385 
00386             // how many ref clk have been stored
00387          size_t nClks = iRef->clk.size();
00388 
00389             // is there any inconsistency?
00390          if ( nClks < iRef->nRef )
00391          {
00392 
00393             Rinex3ClockHeader::RefClk refclk;
00394                // reference clock info
00395             refclk.name    =  line.substr(0,4);
00396             refclk.sigma   =  asDouble( strip( line.substr(40,20) ) );
00397             refclk.sigma   *= 1e6; // ms^2
00398                // add into the list
00399             iRef->clk.push_back(refclk);
00400 
00401          }
00402          else
00403          {
00404             FFStreamError e( string("Number of items found in header ") +
00405                              "is inconsitent to the entry in header" );
00406             GPSTK_THROW(e);
00407          }
00408 
00409          valid |= analysisClkRefValid;
00410 
00411       }
00413       else if ( label == numStationsString )
00414       {
00415 
00416          numSta   =  asInt(line.substr( 0,  6));
00417          trfName  =  strip(line.substr(10, 50));
00418 
00419          valid |= numStationsValid;
00420 
00421       }
00423       else if ( label == solnStaNameString )
00424       {
00425 
00426             // get 4-character station name
00427          string name = line.substr(0,4);
00428             // add it into the list
00429          clkNameList.push_back( name );
00430 
00431             // get integer & decimal part of the coordinates
00432          int X    =  asInt( strip(line.substr(25,8)) );
00433          int Xf   =  asInt( strip(line.substr(33,3)) );
00434 
00435          int Y    =  asInt( strip(line.substr(37,8)) );
00436          int Yf   =  asInt( strip(line.substr(45,3)) );
00437 
00438          int Z    =  asInt( strip(line.substr(49,8)) );
00439          int Zf   =  asInt( strip(line.substr(57,3)) );
00440 
00441             // geocentric coordinates (be careful to the sign)
00442          double x = X>0 ? X*1.0+Xf*1e-3 : X*1.0-Xf*1e-3;
00443          double y = Y>0 ? Y*1.0+Yf*1e-3 : Y*1.0-Yf*1e-3;
00444          double z = Z>0 ? Z*1.0+Zf*1e-3 : Z*1.0-Zf*1e-3;
00445 
00446             // check the coordinates
00447          double radius = std::sqrt(x*x+y*y+z*z);
00448             // add them into the map
00449          if (radius >= 5000.0e3 && radius < 12000.0e3)
00450          {
00451             staCoordList.push_back( Triple(X,Y,Z) );
00452          }
00453          else
00454          {
00455             staCoordList.push_back( Triple(0.0,0.0,0.0) );
00456          }
00457 
00458          valid |= solnStaNameValid;
00459 
00460       }
00461          // # OF SOLN SATS
00462       else if ( label == numSatsString )
00463       {
00464 
00465          numSVs = asInt(line.substr(0,6));
00466 
00467          valid |= numSatsValid;
00468 
00469       }
00470          // PRN LIST
00471       else if ( label == prnListString )
00472       {
00473 
00474          string s    =  line.substr(0,60);
00475          string word =  stripFirstWord(s);
00476 
00477          while ( !word.empty() )
00478          {
00479             clkNameList.push_back( word.append(" ") );
00480             word = stripFirstWord(s);
00481          }
00482 
00483          valid |= prnListValid;
00484 
00485       }
00486          // END OF HEADER
00487       else if ( label == endOfHeader )
00488       {
00489 
00490          valid |= endValid;
00491 
00492       }
00493       else
00494       {
00495 
00496          FFStreamError e("Unidentified label: " + label);
00497          GPSTK_THROW(e);
00498 
00499       }
00500 
00501       return;
00502 
00503    }   // End of method 'Rinex3ClockHeader::ParseHeaderRecord(string& line)'
00504 
00505 
00506 
00510    CommonTime Rinex3ClockHeader::parseTime(const string& line) const
00511    {
00512 
00513       int year, month, day, hour, min;
00514       double sec;
00515    
00516       year  = asInt(   line.substr( 0, 4 ));
00517       month = asInt(   line.substr( 4, 3 ));
00518       day   = asInt(   line.substr( 7, 3 ));
00519       hour  = asInt(   line.substr(10, 3 ));
00520       min   = asInt(   line.substr(13, 3 ));
00521       sec   = asDouble(line.substr(16, 10));
00522 
00523       return CivilTime(year, month, day, hour, min, sec).convertToCommonTime();
00524 
00525    }  // End of method 'Rinex3ClockHeader::parseTime(const string& line)'
00526 
00527 
00530    string Rinex3ClockHeader::writeTime(const CommonTime& dt) const
00531    {
00532 
00533       if (dt == CommonTime::BEGINNING_OF_TIME)
00534       {
00535          return string(36, ' ');
00536       }
00537 
00538       string line;
00539       CivilTime civTime(dt);
00540       line  = rightJustify(asString<short>(civTime.year), 4);
00541       line += rightJustify(asString<short>(civTime.month), 3);
00542       line += rightJustify(asString<short>(civTime.day), 3);
00543       line += rightJustify(asString<short>(civTime.hour), 3);
00544       line += rightJustify(asString<short>(civTime.minute), 3);
00545       line += rightJustify(asString(civTime.second, 6), 10);
00546 
00547       return line;
00548 
00549    }  // End of method 'Rinex3ClockHeader::writeTime(const CommonTime& dt)'
00550 
00551 
00552 
00553       // Debug output function.
00554    void Rinex3ClockHeader::dump(ostream& s) const
00555    {
00556       size_t i;
00557       s << "---------------------------------- REQUIRED ----------------------------------\n";
00558       string str;
00559       str = system.systemChar();
00560       str = str + " (" + system.systemString() + ")";
00561       s << "Rinex Version " << fixed << setw(4) << setprecision(1) << version
00562          << ",  File type " << fileType
00563          << ",  System " << str
00564          << endl;
00565       s << "Prgm: " << fileProgram
00566          << ",  Run: " << date
00567          << ",  By: " << fileAgency
00568         << endl;
00569       s << "Clock data types (" << dataTypeList.size() << ") :" << endl;
00570       for(i=0; i<dataTypeList.size(); i++) 
00571          s << " Type #" << i << " = "
00572             << " " << dataTypeList[i] << endl;
00573       if(valid & acNameValid)
00574          s << "Analysis Center: " << ac << " (" << acName << ")" << endl;
00575       if(valid & numRefClkValid)
00576          s << "Number of analysis clock references: " << refClkList.size() << endl;
00577       if(valid & analysisClkRefValid) {
00578          for(std::list<RefClkRecord>::const_iterator it = refClkList.begin();
00579             it != refClkList.end();
00580             it++)
00581          {
00582             s << "CLK REF  ";
00583             for(std::list<RefClk>::const_iterator jt = it->clk.begin();
00584             jt != it->clk.end();
00585             jt++)
00586             {
00587                s << setw(5) << jt->name;
00588                s << " from " << setw(7) << it->refWin[0] 
00589                  << " to "   << setw(7) << it->refWin[1];
00590             }
00591             s << endl;
00592          }
00593          s << endl;
00594       }
00595       if(valid & numStationsValid)
00596          s << "Number of Stations with data : " << numSta << endl;
00597       if(valid & solnStaNameValid) {
00598          s << "STA  ";
00599          for(i=0; i < numSta; i++)
00600             s << setw(5) << clkNameList[i];
00601          s << endl;
00602       }
00603       if(valid & numSatsValid)
00604          s << "Number of Satellites with data : " << numSVs << endl;
00605       if(valid & prnListValid) {
00606          s << "SAT  ";
00607          for(i=numSta; i<clkNameList.size(); i++)
00608             s << setw(5) << clkNameList[i];
00609          s << endl;
00610       }
00611       s << "(This header is ";
00612       if(valid) 
00613       { 
00614          if (version == 3.0) s << "VALID 3.0";
00615          if (version == 2.0) s << "VALID 2.0";
00616       }
00617       else s << "NOT VALID";
00618       s << " Rinex Clock.)\n";
00619 
00620       if(!(valid & versionValid)) s << " Version is NOT valid\n";
00621       if(!(valid & runByValid)) s << " Run by is NOT valid\n";
00622       if(!(valid & numObsValid)) s << " Observation type is NOT valid\n";
00623       if(!(valid & timeSystemValid)) s << " Time system is NOT valid\n";
00624       if(!(valid & sysDCBsValid)) s << " DCBs applied is NOT valid\n";
00625       if(!(valid & sysPCVsValid)) s << " PCVs applied is NOT valid\n";
00626       if(!(valid & stationNameValid)) s << " Station name is NOT valid\n";
00627       if(!(valid & calibrationClkValid)) s << " External reference clock is NOT valid\n";
00628       if(!(valid & acNameValid)) s << " Analysis Center is NOT valid\n";
00629       if(!(valid & numRefClkValid)) s << " Number of analysis clock references is NOT valid\n";
00630       if(!(valid & analysisClkRefValid)) s << " List of the analysis clock references is NOT valid\n";
00631       if(!(valid & solnStaNameValid)) s << " Number of receivers is NOT valid\n";
00632       if(!(valid & numSatsValid)) s << " Number of satellites is NOT valid\n";
00633       if(!(valid & prnListValid)) s << " PRN list is NOT valid\n";
00634       if(!(valid & endValid)) s << " End is NOT valid\n";
00635 
00636       s << "---------------------------------- OPTIONAL ----------------------------------\n";
00637       if(valid & leapSecondsValid) s << "Leap seconds: " << leapSeconds << endl;
00638       if(commentList.size() && !(valid & commentValid)) s << " Comment is NOT valid\n";
00639       s << "Comments (" << commentList.size() << ") :\n";
00640       for(i=0; i<commentList.size(); i++)
00641          s << commentList[i] << endl;
00642       s << "-------------------------------- END OF HEADER -------------------------------\n";
00643 
00644    }  // End of method 'Rinex3ClockHeader::dump(ostream& s)'
00645 
00646 
00647 }  // End of namespace gpstk

Generated on Tue May 21 03:31:13 2013 for GPS ToolKit Software Library by  doxygen 1.3.9.1