RinexObsData.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: RinexObsData.cpp 2558 2011-04-18 21:06:12Z architest $"
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 
00044 #include "StringUtils.hpp"
00045 #include "RinexObsData.hpp"
00046 #include "RinexObsStream.hpp"
00047 
00048 using namespace gpstk::StringUtils;
00049 using namespace std;
00050 
00051 namespace gpstk
00052 {
00053 
00054       // Definition of static variable to be used across RinexObsData objects
00055    DayTime gpstk::RinexObsData::previousTime;
00056         
00057    void RinexObsData::reallyPutRecord(FFStream& ffs) const 
00058       throw(std::exception, FFStreamError, StringException)
00059    {
00060       // is there anything to write?
00061       if( (epochFlag==0 || epochFlag==1 || epochFlag==6)
00062          && (numSvs==0 || obs.empty()) ) return;
00063       if((epochFlag>=2 && epochFlag<=5) &&
00064             auxHeader.NumberHeaderRecordsToBeWritten()==0) return;
00065 
00066       RinexObsStream& strm = dynamic_cast<RinexObsStream&>(ffs);
00067       string line;
00068 
00069       // first the epoch line to 'line'
00070       line  = writeTime(time);
00071       line += string(2, ' ');
00072       line += rightJustify(asString<short>(epochFlag), 1);
00073       line += rightJustify(asString<short>(numSvs), 3);
00074          
00075       // write satellite ids to 'line'
00076       const int maxPrnsPerLine = 12;
00077       int satsWritten = 0;
00078       RinexSatMap::const_iterator obsItr = obs.begin();
00079       if(epochFlag==0 || epochFlag==1 || epochFlag==6) {
00080          while ((obsItr != obs.end()) && (satsWritten < maxPrnsPerLine))
00081          {
00082             RinexSatID prn((*obsItr).first);
00083             line += prn.toString();
00084             satsWritten++;
00085             obsItr++;
00086          }
00087 
00088             // add clock offset
00089          if(clockOffset != 0.0) {
00090             line += string(68 - line.size(), ' ');
00091             line += rightJustify(asString(clockOffset, 9), 12);
00092          }
00093       
00094         // continuation lines
00095          while (satsWritten != obs.size())
00096          {
00097             if ((satsWritten % maxPrnsPerLine) == 0)
00098             {
00099                strm << line << endl;
00100                strm.lineNumber++;
00101                line  = string(32, ' ');
00102             }
00103             RinexSatID prn(obsItr->first);
00104             line += prn.toString();
00105             satsWritten++;
00106             obsItr++;
00107          }
00108       }
00109 
00110       // write the epoch line
00111       strm << line << endl;
00112       strm.lineNumber++;         
00113       
00114       // write the auxiliary header records, if any
00115       if(epochFlag >= 2 && epochFlag <= 5)
00116       {
00117          try {
00118             auxHeader.WriteHeaderRecords(strm);
00119          }
00120          catch(FFStreamError& e)
00121          {
00122             GPSTK_RETHROW(e);
00123          }
00124          catch(StringException& e)
00125          {
00126             GPSTK_RETHROW(e);
00127          }
00128       }
00129       
00130       // write the obs data
00131       else if (!obs.empty())
00132       {
00133             // write out the observations themselves
00134          obsItr = obs.begin();
00135          
00136          const int maxObsPerLine = 5;
00137          
00138          while(obsItr != obs.end())
00139          {
00140             vector<RinexObsHeader::RinexObsType>::iterator obsTypeItr = 
00141                strm.header.obsTypeList.begin();
00142             
00143             line.erase();
00144             int obsWritten = 0;
00145             
00146             while (obsTypeItr != strm.header.obsTypeList.end())
00147             {
00148                if (  ((obsWritten % maxObsPerLine) == 0) &&
00149                      (obsWritten != 0))
00150                {
00151                   strm << line << endl;
00152                   strm.lineNumber++;
00153                   line.erase();
00154                }
00155 
00156                RinexObsTypeMap::const_iterator rotmi(obsItr->second.find(*obsTypeItr));
00157                RinexDatum thisData;
00158                if (rotmi != obsItr->second.end())
00159                   thisData = rotmi->second;
00160                line += rightJustify(asString(thisData.data,3),14);
00161                if (thisData.lli == 0)
00162                   line += string(1, ' ');
00163                else
00164                   line += rightJustify(asString<short>(thisData.lli),1);
00165                if (thisData.ssi == 0)
00166                   line += string(1, ' ');
00167                else
00168                   line += rightJustify(asString<short>(thisData.ssi),1);
00169                obsWritten++;
00170                obsTypeItr++;
00171             }
00172             strm << line << endl;
00173             strm.lineNumber++;
00174             obsItr++;
00175          }  
00176       }      
00177    }   // end RinexObsData::reallyPutRecord
00178 
00179 
00180    void RinexObsData::reallyGetRecord(FFStream& ffs) 
00181       throw(exception, FFStreamError, gpstk::StringUtils::StringException)
00182    {
00183       RinexObsStream& strm = dynamic_cast<RinexObsStream&>(ffs);
00184       
00185          // If the header hasn't been read, read it...
00186       if(!strm.headerRead) strm >> strm.header;
00187       
00188          // Clear out this object
00189       RinexObsHeader& hdr = strm.header;
00190       
00191       RinexObsData rod;
00192       *this=rod;
00193       
00194       string line;
00195 
00196          // The following block handles Rinex2 observation files that have
00197          // empty (but otherwise valid) epoch lines and comments in the middle
00198          // of the observation section. This is frequent in Rinex2 files that
00199          // are 'spliced' every hour.
00200       bool isValidEpochLine(false);
00201       while( !isValidEpochLine )
00202       {
00203             // Get line
00204          strm.formattedGetLine(line, true);
00205 
00206          isValidEpochLine = true;
00207 
00208          try
00209          {
00210                // Rinex2 observation lines have a 80 characters length limit
00211             if( line.size()>80 ) isValidEpochLine = false;
00212 
00213                // Try to read the epoch
00214             DayTime tempEpoch = parseTime(line, hdr);
00215 
00216                // We also have to check if the epoch is valid
00217             if( tempEpoch == DayTime::BEGINNING_OF_TIME )
00218             {
00219                isValidEpochLine = false;
00220             }
00221             
00222                // Check if it is a number; if not, an exception will be thrown
00223             short tempNumSat = asInt(line.substr(29,3));
00224             
00225          }
00226          catch(...)
00227          {
00228                // Any problem will cause the loop to be repeated
00229             isValidEpochLine = false;
00230          }
00231 
00232       }  // End of 'while( !isValidEpochLine )'
00233       
00234          // process the epoch line, including SV list and clock bias
00235       epochFlag = asInt(line.substr(28,1));
00236       if ((epochFlag < 0) || (epochFlag > 6))
00237       {
00238          FFStreamError e("Invalid epoch flag: " + asString(epochFlag));
00239          GPSTK_THROW(e);
00240       }
00241 
00242          // Not all epoch flags are required to have a time.
00243          // Specifically, 0, 1, 5, 6 must have an epoch time and
00244          // it is optional for 2, 3, 4.
00245          // If there is and epoch time, parse it and load it in
00246          // the member "time".
00247          // If epoch flag = 0, 1, 5, or 6 and there is NO epoch time,
00248          // then throw an error.
00249          // If epoch flag = 2, 3, or 4 and there is no epoch time,
00250          // use the time of the previous record.
00251       bool noEpochTime = (line.substr(0,26) == string(26, ' ')); 
00252       if (noEpochTime &&
00253           (epochFlag==0 || epochFlag==1 || epochFlag==5 || epochFlag==6 ))
00254       {
00255          FFStreamError e("Required epoch time missing: " + line);
00256          GPSTK_THROW(e);
00257       }
00258       else if (noEpochTime)
00259       {
00260          time = previousTime;
00261       }
00262       else
00263       {
00264          time = parseTime(line, hdr);
00265          previousTime = time;
00266       }
00267 
00268       numSvs = asInt(line.substr(29,3));
00269       
00270       if( line.size() > 68 )
00271          clockOffset = asDouble(line.substr(68, 12));
00272       else
00273          clockOffset = 0.0;
00274       
00275          // Now read the observations ...
00276       if(epochFlag==0 || epochFlag==1 || epochFlag==6) {
00277          int isv, ndx, line_ndx;
00278          vector<SatID> satIndex(numSvs);
00279          int col=30;
00280          for (isv=1, ndx=0; ndx<numSvs; isv++, ndx++) {
00281             if(! (isv % 13)) {
00282                strm.formattedGetLine(line);
00283                isv = 1;
00284                if(line.size() > 80) {
00285                   FFStreamError err("Invalid line size:" + asString(line.size()));
00286                   GPSTK_THROW(err);
00287                }
00288             }
00289             try {
00290                satIndex[ndx] = RinexSatID(line.substr(col+isv*3-1, 3));
00291             }
00292             catch (Exception& e)
00293             { 
00294                FFStreamError ffse(e);
00295                GPSTK_THROW(ffse);
00296             }
00297          }
00298       
00299          for (isv=0; isv < numSvs; isv++)
00300          {
00301             short numObs = hdr.obsTypeList.size();
00302             for (ndx=0, line_ndx=0; ndx < numObs; ndx++, line_ndx++)
00303             {
00304                SatID sat = satIndex[isv];
00305                RinexObsHeader::RinexObsType obs_type = hdr.obsTypeList[ndx];
00306                if (! (line_ndx % 5))
00307                {
00308                   strm.formattedGetLine(line);
00309                   line_ndx = 0;
00310                   if (line.size() > 80)
00311                   {
00312                      FFStreamError err("Invalid line size:" + asString(line.size()));
00313                      GPSTK_THROW(err);
00314                   }
00315                }
00316                
00317                line.resize(80, ' ');
00318                
00319                obs[sat][obs_type].data = asDouble(line.substr(line_ndx*16,   14));
00320                obs[sat][obs_type].lli = asInt(    line.substr(line_ndx*16+14, 1));
00321                obs[sat][obs_type].ssi = asInt(    line.substr(line_ndx*16+15, 1));
00322             }
00323          }
00324       }
00325          // ... or the auxiliary header information
00326       else if(numSvs > 0) {
00327          auxHeader.clear();
00328          for(int i=0; i<numSvs; i++) {
00329             strm.formattedGetLine(line);
00330             StringUtils::stripTrailing(line);
00331             try {
00332                auxHeader.ParseHeaderRecord(line);
00333             }
00334             catch(FFStreamError& e)
00335             {
00336                GPSTK_RETHROW(e);
00337             }
00338             catch(StringException& e)
00339             {
00340                GPSTK_RETHROW(e);
00341             }
00342          }
00343       }
00344 
00345       return;
00346       
00347    } // end of reallyGetRecord()
00348 
00349 
00350    DayTime RinexObsData::parseTime(const string& line, 
00351                                    const RinexObsHeader& hdr) const
00352       throw(FFStreamError)
00353    {
00354       try
00355       {
00356             // check if the spaces are in the right place - an easy
00357             // way to check if there's corruption in the file
00358          if ( (line[0] != ' ') ||
00359               (line[3] != ' ') ||
00360               (line[6] != ' ') ||
00361               (line[9] != ' ') ||
00362               (line[12] != ' ') ||
00363               (line[15] != ' '))
00364          {
00365             FFStreamError e("Invalid time format");
00366             GPSTK_THROW(e);
00367          }
00368 
00369             // if there's no time, just return a bad time
00370          if (line.substr(0,26) == string(26, ' '))
00371          {
00372             return DayTime(DayTime::BEGINNING_OF_TIME);
00373          }
00374 
00375          int year, month, day, hour, min;
00376          double sec;
00377          int yy = hdr.firstObs.year()/100;
00378          yy *= 100;
00379    
00380          year  = asInt(   line.substr(1,  2 ));
00381          month = asInt(   line.substr(4,  2 ));
00382          day   = asInt(   line.substr(7,  2 ));
00383          hour  = asInt(   line.substr(10, 2 ));
00384          min   = asInt(   line.substr(13, 2 ));
00385          sec   = asDouble(line.substr(15, 11));
00386 
00387          // Real Rinex has epochs 'yy mm dd hr 59 60.0' surprisingly often....
00388          double ds=0;
00389          if(sec >= 60.) { ds=sec; sec=0.0; }
00390          DayTime rv(yy+year, month, day, hour, min, sec);
00391          if(ds != 0) rv += ds;
00392 
00393          return rv;
00394       }
00395          // string exceptions for substr are caught here
00396       catch (std::exception &e)
00397       {
00398          FFStreamError err("std::exception: " + string(e.what()));
00399          GPSTK_THROW(err);
00400       }
00401       catch (gpstk::Exception& e)
00402       {
00403          std::string text;
00404          for(int i=0; i<e.getTextCount(); i++) text += e.getText(i);
00405          FFStreamError err("gpstk::Exception in parseTime(): " + text);
00406          GPSTK_THROW(err);
00407       }
00408 
00409    }
00410 
00411    string RinexObsData::writeTime(const DayTime& dt) const
00412       throw(StringException)
00413    {
00414       if (dt == DayTime::BEGINNING_OF_TIME)
00415       {
00416          return string(26, ' ');
00417       }
00418 
00419       string line;
00420       line  = string(1, ' ');
00421       line += rightJustify(asString<short>(dt.year()),2);
00422       line += string(1, ' ');
00423       line += rightJustify(asString<short>(dt.month()),2);
00424       line += string(1, ' ');
00425       line += rightJustify(asString<short>(dt.day()),2);
00426       line += string(1, ' ');
00427       line += rightJustify(asString<short>(dt.hour()),2);
00428       line += string(1, ' ');
00429       line += rightJustify(asString<short>(dt.minute()),2);
00430       line += rightJustify(asString(dt.second(), 7),11);
00431 
00432       return line;
00433    }
00434 
00435 
00436    void RinexObsData::dump(ostream& s) const
00437    {
00438       if (obs.empty())
00439          return;
00440 
00441       s << "Dump of RinexObsData - time: ";
00442       s << writeTime(time) << " epochFlag: "
00443         << " " << epochFlag << " numSvs: " << numSvs 
00444         << fixed << setprecision(6)
00445         << " clk offset: " << clockOffset << endl;
00446       if(epochFlag == 0 || epochFlag == 1) 
00447       {
00448          RinexSatMap::const_iterator it;
00449          for(it=obs.begin(); it!=obs.end(); it++) {
00450             s << "Sat " << setw(2) << RinexSatID(it->first);
00451             RinexObsTypeMap::const_iterator jt;
00452             for(jt=it->second.begin(); jt!=it->second.end(); jt++) 
00453             {
00454                s << " " << jt->first.type << ":" << fixed << setprecision(3)
00455                  << " " << setw(12) << jt->second.data
00456                  << "/" << jt->second.lli << "/" << jt->second.ssi;
00457             }
00458             s << endl;
00459          }
00460       }
00461       else {
00462          s << "aux. header info:\n";
00463          auxHeader.dump(s);
00464       }
00465    }
00466 
00467 } // namespace

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