00001 #pragma ident "$Id: Rinex3ClockHeader.cpp 3319 2012-09-19 16:58:10Z prestonherrmann $"
00002
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include<cmath>
00033
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
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 }
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 }
00120
00121
00122
00123
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
00132 if (strm.headerRead == true)
00133 return;
00134
00135
00136
00137
00138
00139
00140 clear();
00141
00142
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 }
00171
00172
00173
00174 strm.header = *this;
00175 strm.headerRead = true;
00176
00177 return;
00178
00179 }
00180
00181
00182
00183
00184 void Rinex3ClockHeader::ParseHeaderRecord(string& line)
00185 throw(FFStreamError)
00186 {
00187
00188 string label(line, 60, 20);
00189
00190
00191 if ( label == versionString )
00192 {
00193
00194 version = asDouble(line.substr(0,9));
00195 fileType = strip(line.substr(20, 20));
00196
00197
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
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
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
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
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
00253 else if ( label == numObsString )
00254 {
00255
00256 numObsTyp = asInt( line.substr(3,3) );
00257
00258
00259
00260 valid |= numObsValid;
00261
00262 }
00263
00264 else if ( label == timeSystemString )
00265 {
00266
00267 timeSystem = line.substr(3,3);
00268 valid |= timeSystemValid;
00269
00270 }
00271
00272 else if ( label == leapSecondsString )
00273 {
00274
00275 leapSeconds = asInt(line.substr(0,6));
00276
00277 valid |= leapSecondsValid;
00278
00279 }
00280
00281 else if ( label == sysDCBString )
00282 {
00283
00284 valid |= sysDCBsValid;
00285
00286 }
00287
00288 else if ( label == sysPCVString )
00289 {
00290
00291 valid |= sysPCVsValid;
00292
00293 }
00294
00295 else if ( label == dataTypesString )
00296 {
00297
00298
00299 int nTyp = asInt(line.substr(0,6));
00300
00301 dataTypeList.resize(nTyp);
00302
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
00312 else if ( label == stationNameString )
00313 {
00314
00315 clk0Name = line.substr(0,4);
00316
00317 valid |= stationNameValid;
00318
00319 }
00320
00321 else if ( label == calibrationClkString )
00322 {
00323 calName = strip( line.substr(0,60) );
00324
00325 valid |= calibrationClkValid;
00326
00327 }
00328
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
00340 else if ( label == numRefClkString )
00341 {
00342
00343
00344 Rinex3ClockHeader::RefClkRecord ref;
00345
00346 ref.nRef = asInt( line.substr(0,6) );
00347
00348 if( asInt(line.substr(7,4)) )
00349 {
00350 CommonTime T0 = parseTime( line.substr(7,26) );
00351
00352 if( timeFirst == CommonTime::BEGINNING_OF_TIME )
00353 {
00354 timeFirst = T0;
00355 }
00356
00357 ref.refWin[0] = T0 - timeFirst;
00358
00359 T0 = parseTime( line.substr(34,26) );
00360 ref.refWin[1] = T0 - timeFirst;
00361
00362
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
00373 refClkList.push_back(ref);
00374
00375 valid |= numRefClkValid;
00376
00377 }
00379 else if ( label == analysisClkRefString )
00380 {
00381
00382
00383 std::list<RefClkRecord>::iterator iRef = refClkList.end();
00384 --iRef;
00385
00386
00387 size_t nClks = iRef->clk.size();
00388
00389
00390 if ( nClks < iRef->nRef )
00391 {
00392
00393 Rinex3ClockHeader::RefClk refclk;
00394
00395 refclk.name = line.substr(0,4);
00396 refclk.sigma = asDouble( strip( line.substr(40,20) ) );
00397 refclk.sigma *= 1e6;
00398
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
00427 string name = line.substr(0,4);
00428
00429 clkNameList.push_back( name );
00430
00431
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
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
00447 double radius = std::sqrt(x*x+y*y+z*z);
00448
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
00462 else if ( label == numSatsString )
00463 {
00464
00465 numSVs = asInt(line.substr(0,6));
00466
00467 valid |= numSatsValid;
00468
00469 }
00470
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
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 }
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 }
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 }
00550
00551
00552
00553
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 }
00645
00646
00647 }