Rinex3ObsHeader.cpp
Go to the documentation of this file.
1 //==============================================================================
2 //
3 // This file is part of GNSSTk, the ARL:UT GNSS Toolkit.
4 //
5 // The GNSSTk is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published
7 // by the Free Software Foundation; either version 3.0 of the License, or
8 // any later version.
9 //
10 // The GNSSTk is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with GNSSTk; if not, write to the Free Software Foundation,
17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 // This software was developed by Applied Research Laboratories at the
20 // University of Texas at Austin.
21 // Copyright 2004-2022, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24 
25 //==============================================================================
26 //
27 // This software was developed by Applied Research Laboratories at the
28 // University of Texas at Austin, under contract to an agency or agencies
29 // within the U.S. Department of Defense. The U.S. Government retains all
30 // rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 // Pursuant to DoD Directive 523024
33 //
34 // DISTRIBUTION STATEMENT A: This software has been approved for public
35 // release, distribution is unlimited.
36 //
37 //==============================================================================
38 
44 #include <sstream>
45 #include <algorithm>
46 #include <set>
47 #include <string.h>
48 
49 #include "StringUtils.hpp"
50 #include "SystemTime.hpp"
51 #include "TimeString.hpp"
52 #include "Rinex3ObsStream.hpp"
53 #include "Rinex3ObsHeader.hpp"
54 
55 using namespace std;
56 using namespace gnsstk::StringUtils;
57 
58 namespace gnsstk
59 {
60  const string Rinex3ObsHeader::hsVersion = "RINEX VERSION / TYPE";
61  const string Rinex3ObsHeader::hsRunBy = "PGM / RUN BY / DATE";
62  const string Rinex3ObsHeader::hsComment = "COMMENT";
63  const string Rinex3ObsHeader::hsMarkerName = "MARKER NAME";
64  const string Rinex3ObsHeader::hsMarkerNumber = "MARKER NUMBER";
65  const string Rinex3ObsHeader::hsMarkerType = "MARKER TYPE";
66  const string Rinex3ObsHeader::hsObserver = "OBSERVER / AGENCY";
67  const string Rinex3ObsHeader::hsReceiver = "REC # / TYPE / VERS";
68  const string Rinex3ObsHeader::hsAntennaType = "ANT # / TYPE";
69  const string Rinex3ObsHeader::hsAntennaPosition = "APPROX POSITION XYZ";
70  const string Rinex3ObsHeader::hsAntennaDeltaHEN = "ANTENNA: DELTA H/E/N";
71  const string Rinex3ObsHeader::hsAntennaDeltaXYZ = "ANTENNA: DELTA X/Y/Z";
72  const string Rinex3ObsHeader::hsAntennaPhaseCtr = "ANTENNA: PHASECENTER";
73  const string Rinex3ObsHeader::hsAntennaBsightXYZ = "ANTENNA: B.SIGHT XYZ";
74  const string Rinex3ObsHeader::hsAntennaZeroDirAzi = "ANTENNA: ZERODIR AZI";
75  const string Rinex3ObsHeader::hsAntennaZeroDirXYZ = "ANTENNA: ZERODIR XYZ";
76  const string Rinex3ObsHeader::hsCenterOfMass = "CENTER OF MASS: XYZ";
77  const string Rinex3ObsHeader::hsNumObs = "# / TYPES OF OBSERV";
78  const string Rinex3ObsHeader::hsSystemNumObs = "SYS / # / OBS TYPES";
79  const string Rinex3ObsHeader::hsWaveFact = "WAVELENGTH FACT L1/2";
80  const string Rinex3ObsHeader::hsSigStrengthUnit = "SIGNAL STRENGTH UNIT";
81  const string Rinex3ObsHeader::hsInterval = "INTERVAL";
82  const string Rinex3ObsHeader::hsFirstTime = "TIME OF FIRST OBS";
83  const string Rinex3ObsHeader::hsLastTime = "TIME OF LAST OBS";
84  const string Rinex3ObsHeader::hsReceiverOffset = "RCV CLOCK OFFS APPL";
85  const string Rinex3ObsHeader::hsSystemDCBSapplied = "SYS / DCBS APPLIED";
86  const string Rinex3ObsHeader::hsSystemPCVSapplied = "SYS / PCVS APPLIED";
87  const string Rinex3ObsHeader::hsSystemScaleFac = "SYS / SCALE FACTOR";
88  const string Rinex3ObsHeader::hsSystemPhaseShift = "SYS / PHASE SHIFT";
89  const string Rinex3ObsHeader::hsGlonassSlotFreqNo = "GLONASS SLOT / FRQ #";
90  const string Rinex3ObsHeader::hsGlonassCodPhsBias = "GLONASS COD/PHS/BIS";
91  const string Rinex3ObsHeader::hsLeapSeconds = "LEAP SECONDS";
92  const string Rinex3ObsHeader::hsNumSats = "# OF SATELLITES";
93  const string Rinex3ObsHeader::hsPrnObs = "PRN / # OF OBS";
94  const string Rinex3ObsHeader::hsEoH = "END OF HEADER";
95 
96  // Text to look for in COMMENT headers that isn't RINEX-defined.
97  const string Rinex3ObsHeader::hsAntennaStandard = "TRANSMITTER STANDARD";
98  const string Rinex3ObsHeader::hsAntennaRegional = "TRANSMITTER REGIONAL";
99 
100  int Rinex3ObsHeader::debug = 0;
101 
102  const Rinex3ObsHeader::Fields Rinex3ObsHeader::allValid2({
103  Rinex3ObsHeader::validVersion,
104  Rinex3ObsHeader::validRunBy,
105  Rinex3ObsHeader::validMarkerName,
106  Rinex3ObsHeader::validObserver,
107  Rinex3ObsHeader::validReceiver,
108  Rinex3ObsHeader::validAntennaType,
109  Rinex3ObsHeader::validAntennaPosition,
110  Rinex3ObsHeader::validAntennaDeltaHEN,
111  Rinex3ObsHeader::validNumObs,
112  Rinex3ObsHeader::validFirstTime
113  });
114  const Rinex3ObsHeader::Fields Rinex3ObsHeader::allValid30({
115  Rinex3ObsHeader::validVersion,
116  Rinex3ObsHeader::validRunBy,
117  Rinex3ObsHeader::validMarkerName,
121  //Rinex3ObsHeader::validMarkerType,
122  Rinex3ObsHeader::validObserver,
123  Rinex3ObsHeader::validReceiver,
124  Rinex3ObsHeader::validAntennaType,
125  Rinex3ObsHeader::validAntennaPosition,
126  Rinex3ObsHeader::validAntennaDeltaHEN,
127  Rinex3ObsHeader::validSystemNumObs,
128  Rinex3ObsHeader::validFirstTime
129  });
130  const Rinex3ObsHeader::Fields Rinex3ObsHeader::allValid301({
131  Rinex3ObsHeader::validVersion,
132  Rinex3ObsHeader::validRunBy,
133  Rinex3ObsHeader::validMarkerName,
134  //Rinex3ObsHeader::validMarkerType,
135  Rinex3ObsHeader::validObserver,
136  Rinex3ObsHeader::validReceiver,
137  Rinex3ObsHeader::validAntennaType,
138  Rinex3ObsHeader::validAntennaPosition,
139  Rinex3ObsHeader::validAntennaDeltaHEN,
140  Rinex3ObsHeader::validSystemNumObs,
141  Rinex3ObsHeader::validFirstTime,
142  Rinex3ObsHeader::validSystemPhaseShift
143  });
144  const Rinex3ObsHeader::Fields Rinex3ObsHeader::allValid302({
145  Rinex3ObsHeader::validVersion,
146  Rinex3ObsHeader::validRunBy,
147  Rinex3ObsHeader::validMarkerName,
148  //Rinex3ObsHeader::validMarkerType,
149  Rinex3ObsHeader::validObserver,
150  Rinex3ObsHeader::validReceiver,
151  Rinex3ObsHeader::validAntennaType,
152  Rinex3ObsHeader::validAntennaPosition,
153  Rinex3ObsHeader::validAntennaDeltaHEN,
154  Rinex3ObsHeader::validSystemNumObs,
155  Rinex3ObsHeader::validFirstTime,
156  Rinex3ObsHeader::validSystemPhaseShift
157  });
158  const Rinex3ObsHeader::Fields Rinex3ObsHeader::allValid303({
159  Rinex3ObsHeader::validVersion,
160  Rinex3ObsHeader::validRunBy,
161  Rinex3ObsHeader::validMarkerName,
162  //Rinex3ObsHeader::validMarkerType,
163  Rinex3ObsHeader::validObserver,
164  Rinex3ObsHeader::validReceiver,
165  Rinex3ObsHeader::validAntennaType,
166  Rinex3ObsHeader::validAntennaPosition,
167  Rinex3ObsHeader::validAntennaDeltaHEN,
168  Rinex3ObsHeader::validSystemNumObs,
169  Rinex3ObsHeader::validFirstTime,
170  Rinex3ObsHeader::validSystemPhaseShift
171  });
172 
173  Rinex3ObsHeader::Rinex3ObsHeader()
174  : PisY(false)
175  {
176  clear();
177  }
178 
179 
181  {
182  R2ObsTypes.clear();
183  mapSysR2toR3ObsID.clear();
185  fileType = "O"; // observation data
186  fileSys = "G"; // GPS only by default
187  preserveVerType = false; // let the write methods chose the above
189  fileProgram.clear();
190  fileAgency.clear();
191  date.clear();
192  preserveDate = false;
193  commentList.clear();
194  markerName.clear();
195  markerNumber.clear();
196  markerType.clear();
197  observer.clear();
198  agency.clear();
199  recNo.clear();
200  recType.clear();
201  recVers.clear();
202  antNo.clear();
203  antType.clear();
207  antennaSatSys.clear();
208  antennaObsCode.clear();
211  antennaZeroDirAzi = 0.;
213  centerOfMass = Triple();
214  mapObsTypes.clear();
216  extraWaveFactList.clear();
217  sigStrengthUnit.clear();
218  interval = 0.;
219  firstObs = CivilTime();
220  lastObs = CivilTime();
221  receiverOffset = 0;
222  infoDCBS.clear();
223  infoPCVS.clear();
224  sysSfacMap.clear();
225  sysPhaseShift.clear();
226  glonassFreqNo.clear();
227  glonassCodPhsBias.clear();
228  leapSeconds = 0;
229  numSVs = 0;
230  numObsForSat.clear();
231  obsTypeList.clear();
232  valid.clear();
233  validEoH = false;
234  // Only do this in the constructor so the desired handling of
235  // "P" code in RINEX 2 stays the same.
236  //PisY = false;
238  satSysTemp.clear();
239  satSysPrev.clear();
240  numObs = 0;
241  numObsPrev = 0;
242  lastPRN = RinexSatID();
243  factor = 0;
244  factorPrev = 0;
246  }
247 
248 
250  {
252  Rinex3ObsStream& strm = dynamic_cast<Rinex3ObsStream&>(ffs);
253 
254  strm.header = *this;
255 
256  Fields allValid = Fields::getRequired(version);
257  if (allValid.empty())
258  {
259  FFStreamError err("Unknown RINEX version: " +
261  err.addText("Make sure to set the version correctly.");
262  GNSSTK_THROW(err);
263  }
264 
265  if((valid & allValid) != allValid)
266  {
267  FFStreamError err("Incomplete or invalid header.");
268  err.addText("Make sure you set all header valid bits for all of the"
269  " available data.");
270  allValid.describeMissing(valid, err);
271  GNSSTK_THROW(err);
272  }
273 
274  try
275  {
276  writeHeaderRecords(strm);
277  }
278  catch(FFStreamError& e)
279  {
280  GNSSTK_RETHROW(e);
281  }
282  catch(StringException& e)
283  {
284  GNSSTK_RETHROW(e);
285  }
286 
287  } // end reallyPutRecord
288 
289 
290  // This function computes the number of valid header records
291  // which writeHeaderRecords will write.
292  // NB not used in Rinex3Obs....
294  {
295  int n = 0;
296 
297  if(valid & validVersion ) n++;
298  if(valid & validRunBy ) n++;
299  if(valid & validComment ) n += commentList.size();
300  if(valid & validMarkerName ) n++;
301  if(valid & validMarkerNumber ) n++;
302  if(version >= 3 && (valid & validMarkerType)) n++;
303  if(valid & validObserver ) n++;
304  if(valid & validReceiver ) n++;
305  if(valid & validAntennaType ) n++;
306  if(valid & validAntennaPosition ) n++;
307  if(valid & validAntennaDeltaHEN ) n++;
308  if(version >= 3 && (valid & validAntennaDeltaXYZ)) n++;
309  if(version >= 3 && (valid & validAntennaPhaseCtr)) n++;
310  if(version >= 3 && (valid & validAntennaBsightXYZ)) n++;
311  if(version >= 3 && (valid & validAntennaZeroDirAzi)) n++;
312  if(version >= 3 && (valid & validAntennaZeroDirXYZ)) n++;
313  if(version >= 3 && (valid & validCenterOfMass)) n++;
314  if(version < 3 && (valid & validNumObs) && R2ObsTypes.size() != 0)
315  n += 1 + (R2ObsTypes.size()-1)/9;
316  if(version >= 3 && (valid & validSystemNumObs) && numObs != 0)
317  n += 1 + (numObs-1)/9;
318  if(version < 3 && (valid & validWaveFact))
319  {
320  n++;
321  if(extraWaveFactList.size() != 0) n += extraWaveFactList.size();
322  }
323  if(version >= 3 && (valid & validSigStrengthUnit)) n++;
324  if(valid & validInterval ) n++;
325  if(valid & validFirstTime ) n++;
326  if(valid & validLastTime ) n++;
327  if(valid & validReceiverOffset ) n++;
328  if(version >= 3 && (valid & validSystemDCBSapplied)) n++;
329  if(version >= 3 && (valid & validSystemPCVSapplied)) n++;
330  if(version >= 3 && (valid & validSystemScaleFac)) n++;
331  if(version >= 3.01 && (valid & validSystemPhaseShift)) n++; // one per system at least
332  if(version >= 3.01 && (valid & validGlonassSlotFreqNo)) n++; // TODO: continuation lines...
333  if(version >= 3.02 && (valid & validGlonassCodPhsBias)) n++;
334  if(valid & validLeapSeconds ) n++;
335  if(valid & validNumSats ) n++;
336  if(valid & validPrnObs )
337  n += numObsForSat.size() * (1+numObsForSat.begin()->second.size()/9);
338  if(validEoH ) n++;
339 
340  return n;
341  } // end numberHeaderRecordsToBeWritten
342 
343 
344  // This function writes all valid header records.
346  {
348  Rinex3ObsStream& strm = dynamic_cast<Rinex3ObsStream&>(ffs);
349  string line;
350 
351  if(valid & validVersion)
352  {
353  line = rightJustify(asString(version,2), 9);
354  line += string(11, ' ');
355 
356  if((fileType[0] != 'O') && (fileType[0] != 'o'))
357  {
358  FFStreamError err("File type is not Observation: " + fileType);
359  GNSSTK_THROW(err);
360  }
361 
362  if (preserveVerType)
363  {
364  line += leftJustify(fileType, 20);
365  line += leftJustify(fileSys, 20);
366  }
367  else
368  {
370  {
371  FFStreamError err("Invalid satellite system");
372  GNSSTK_THROW(err);
373  }
374 
375  line += leftJustify(string("OBSERVATION DATA"), 20);
376  string str;
378  str = "MIXED";
379  else
380  {
381  RinexSatID sat(fileSysSat);
382  str = sat.systemChar();
383  str = str + " (" + sat.systemString() + ")";
384  }
385  line += leftJustify(str, 20);
386  }
387  line += hsVersion;
388  strm << line << endl;
389  strm.lineNumber++;
390  }
391  if(valid & validRunBy)
392  {
393  line = leftJustify(fileProgram, 20);
394  line += leftJustify(fileAgency , 20);
395  if (preserveDate)
396  {
397  line += leftJustify(date, 20);
398  }
399  else
400  {
401  SystemTime sysTime;
402  string curDate;
403  curDate = printTime(sysTime,"%04Y%02m%02d %02H%02M%02S %P");
404  line += leftJustify(curDate, 20);
405  }
406  line += hsRunBy;
407  strm << line << endl;
408  strm.lineNumber++;
409  }
410  if(valid & validComment)
411  {
412  vector<string>::const_iterator itr = commentList.begin();
413  while (itr != commentList.end())
414  {
415  line = leftJustify((*itr), 60);
416  line += hsComment;
417  strm << line << endl;
418  strm.lineNumber++;
419  itr++;
420  }
421  }
422  if(!R2DisambiguityMap.empty())
423  {
424  DisAmbMap::const_iterator itr = R2DisambiguityMap.begin();
425  while (itr != R2DisambiguityMap.end())
426  {
427  line = leftJustify(itr->first.substr(0,1) + " Obs Type " + itr->first.substr(1) + " originated from " + itr->second, 60);
428  line += hsComment;
429  strm << line << endl;
430  strm.lineNumber++;
431  itr++;
432  }
433  }
434  if(valid & validMarkerName)
435  {
436  line = leftJustify(markerName, 60);
437  line += hsMarkerName;
438  strm << line << endl;
439  strm.lineNumber++;
440  }
442  {
443  line = leftJustify(markerNumber, 20);
444  line += string(40, ' ');
445  line += hsMarkerNumber;
446  strm << line << endl;
447  strm.lineNumber++;
448  }
449  if(version >= 3 && (valid & validMarkerType))
450  {
451  line = leftJustify(markerType, 20);
452  line += string(40, ' ');
453  line += hsMarkerType;
454  strm << line << endl;
455  strm.lineNumber++;
456  }
457  if(valid & validObserver)
458  {
459  line = leftJustify(observer, 20);
460  line += leftJustify(agency , 40);
461  line += hsObserver;
462  strm << line << endl;
463  strm.lineNumber++;
464  }
465  if(valid & validReceiver)
466  {
467  line = leftJustify(recNo , 20);
468  line += leftJustify(recType, 20);
469  line += leftJustify(recVers, 20);
470  line += hsReceiver;
471  strm << line << endl;
472  strm.lineNumber++;
473  }
474  if(valid & validAntennaType)
475  {
476  line = leftJustify(antNo , 20);
477  line += leftJustify(antType, 20);
478  line += string(20, ' ');
479  line += hsAntennaType;
480  strm << line << endl;
481  strm.lineNumber++;
482  }
484  {
485  line = rightJustify(asString(antennaPosition[0], 4), 14);
486  line += rightJustify(asString(antennaPosition[1], 4), 14);
487  line += rightJustify(asString(antennaPosition[2], 4), 14);
488  line += string(18, ' ');
489  line += hsAntennaPosition;
490  strm << line << endl;
491  strm.lineNumber++;
492  }
494  {
495  line = rightJustify(asString(antennaDeltaHEN[0], 4), 14);
496  line += rightJustify(asString(antennaDeltaHEN[1], 4), 14);
497  line += rightJustify(asString(antennaDeltaHEN[2], 4), 14);
498  line += string(18, ' ');
499  line += hsAntennaDeltaHEN;
500  strm << line << endl;
501  strm.lineNumber++;
502  }
503  if(version >= 3 && (valid & validAntennaDeltaXYZ))
504  {
505  line = rightJustify(asString(antennaDeltaXYZ[0], 4), 14);
506  line += rightJustify(asString(antennaDeltaXYZ[1], 4), 14);
507  line += rightJustify(asString(antennaDeltaXYZ[2], 4), 14);
508  line += string(18, ' ');
509  line += hsAntennaDeltaXYZ;
510  strm << line << endl;
511  strm.lineNumber++;
512  }
513  if(version >= 3 && (valid & validAntennaPhaseCtr))
514  {
515  line = leftJustify(antennaSatSys , 1);
516  line += string(1, ' ');
517  line += rightJustify(antennaObsCode, 3);
518  line += rightJustify(asString(antennaPhaseCtr[0], 4), 9);
519  line += rightJustify(asString(antennaPhaseCtr[1], 4), 14);
520  line += rightJustify(asString(antennaPhaseCtr[2], 4), 14);
521  line += string(18, ' ');
522  line += hsAntennaPhaseCtr;
523  strm << line << endl;
524  strm.lineNumber++;
525  }
526  if(version >= 3 && (valid & validAntennaBsightXYZ))
527  {
528  line = rightJustify(asString(antennaBsightXYZ[0], 4), 14);
529  line += rightJustify(asString(antennaBsightXYZ[1], 4), 14);
530  line += rightJustify(asString(antennaBsightXYZ[2], 4), 14);
531  line += string(18, ' ');
532  line += hsAntennaBsightXYZ;
533  strm << line << endl;
534  strm.lineNumber++;
535  }
536  if(version >= 3 && (valid & validAntennaZeroDirAzi))
537  {
538  line = rightJustify(asString(antennaZeroDirAzi, 4), 14);
539  line += string(46, ' ');
540  line += hsAntennaZeroDirAzi;
541  strm << line << endl;
542  strm.lineNumber++;
543  }
544  if(version >= 3 && (valid & validAntennaZeroDirXYZ))
545  {
546  line = rightJustify(asString(antennaZeroDirXYZ[0], 4), 14);
547  line += rightJustify(asString(antennaZeroDirXYZ[1], 4), 14);
548  line += rightJustify(asString(antennaZeroDirXYZ[2], 4), 14);
549  line += string(18, ' ');
550  line += hsAntennaZeroDirXYZ;
551  strm << line << endl;
552  strm.lineNumber++;
553  }
554  if(version >= 3 && (valid & validCenterOfMass))
555  {
556  line = rightJustify(asString(centerOfMass[0], 4), 14);
557  line += rightJustify(asString(centerOfMass[1], 4), 14);
558  line += rightJustify(asString(centerOfMass[2], 4), 14);
559  line += string(18, ' ');
560  line += hsCenterOfMass;
561  strm << line << endl;
562  strm.lineNumber++;
563  }
564  if(version < 3 && (valid & validNumObs)) // R2 only
565  {
566  if(R2ObsTypes.empty())
567  {
568  InvalidRequest er("Header contains no R2ObsTypes. "
569  "You must run prepareVer2Write before outputting an R2 file");
570  GNSSTK_THROW(er);
571  }
572  // write out RinexObsTypes
573  const int maxObsPerLine = 9;
574  int obsWritten = 0;
575  line = ""; // make sure the line contents are reset.
576 
577  for(size_t i=0; i<R2ObsTypes.size(); i++)
578  {
579  string val;
580  // the first line needs to have the # of obs
581  if(obsWritten == 0)
582  line = rightJustify(asString(R2ObsTypes.size()), 6);
583  // if you hit 9, write out the line and start a new one
584  else if((obsWritten % maxObsPerLine) == 0)
585  {
586  line += hsNumObs;
587  strm << line << endl;
588  strm.lineNumber++;
589  line = string(6, ' ');
590  }
591  val = R2ObsTypes[i];
592  line += rightJustify(val, 6);
593  obsWritten++;
594  }
595 
596  line += string(60 - line.size(), ' ');
597  line += hsNumObs;
598  strm << line << endl;
599  strm.lineNumber++;
600  }
601  if(version >= 3 && (valid & validSystemNumObs))
602  {
603  static const int maxObsPerLine = 13;
604 
605  map<string,vector<RinexObsID> >::const_iterator mapIter;
606 
607  // because of the way pseudo-observables are mapped from
608  // ObsID/RinexObsID to the RINEX file, we have to manually
609  // count the observables first.
610  map<string,unsigned> obsCount;
611  RinexObsMap dummy;
612  remapObsTypes(dummy, obsCount);
613  // now do the actual writing
614  for(mapIter = mapObsTypes.begin(); mapIter != mapObsTypes.end();
615  mapIter++)
616  {
617  bool addedChannel = false;
618  std::set<CarrierBand> addedIono;
619  int obsWritten = 0;
620  line = ""; // make sure the line contents are reset
621 
622  vector<RinexObsID> ObsTypeList = mapIter->second;
623 
624  for(size_t i = 0; i < ObsTypeList.size(); i++)
625  {
626  if (ObsTypeList[i].type == ObservationType::Iono)
627  {
628  if (addedIono.count(ObsTypeList[i].band) > 0)
629  continue; // only write this pseudo-obs once
630  addedIono.insert(ObsTypeList[i].band);
631  }
632  else if (ObsTypeList[i].type == ObservationType::Channel)
633  {
634  if (addedChannel)
635  continue; // only write this pseudo-obs once
636  addedChannel = true;
637  }
638  // the first line needs to have the GNSS type and # of obs
639  if(obsWritten == 0)
640  {
641  line = leftJustify(mapIter->first, 1);
642  line += string(2, ' ');
643  line += rightJustify(asString(obsCount[mapIter->first]), 3);
644  }
645  // if you hit 13, write out the line and start a new one
646  else if((obsWritten % maxObsPerLine) == 0)
647  {
648  line += string(2, ' ');
649  line += hsSystemNumObs;
650  strm << line << endl;
651  strm.lineNumber++;
652  line = string(6, ' ');
653  }
654  line += string(1, ' ');
655  line += rightJustify(ObsTypeList[i].asString(version), 3);
656  obsWritten++;
657  }
658  line += string(60 - line.size(), ' ');
659  line += hsSystemNumObs;
660  strm << line << endl;
661  strm.lineNumber++;
662  }
663 
664  }
665  if(version < 3 && (valid & validWaveFact))
666  {
667  line = rightJustify(asString<short>(wavelengthFactor[0]),6);
668  line += rightJustify(asString<short>(wavelengthFactor[1]),6);
669  line += string(48, ' ');
670  line += hsWaveFact;
671  strm << line << endl;
672  strm.lineNumber++;
673 
674  // handle continuation lines
675  if(!extraWaveFactList.empty())
676  {
677  vector<ExtraWaveFact>::const_iterator itr = extraWaveFactList.begin();
678 
679  while (itr != extraWaveFactList.end())
680  {
681  const int maxSatsPerLine = 7;
682  short satsWritten = 0, satsLeft = (*itr).satList.size(), satsThisLine;
683  vector<SatID>::const_iterator vecItr = (*itr).satList.begin();
684 
685  while ((vecItr != (*itr).satList.end()))
686  {
687  if(satsWritten == 0)
688  {
689  line = rightJustify(asString<short>((*itr).wavelengthFactor[0]),6);
690  line += rightJustify(asString<short>((*itr).wavelengthFactor[1]),6);
691  satsThisLine = (satsLeft > maxSatsPerLine ? maxSatsPerLine : satsLeft);
692  line += rightJustify(asString<short>(satsThisLine),6);
693  }
694  try
695  {
696  line += string(3, ' ') + RinexSatID(*vecItr).toString();
697  }
698  catch (Exception& e)
699  {
700  FFStreamError ffse(e);
701  GNSSTK_THROW(ffse);
702  }
703  satsWritten++;
704  satsLeft--;
705  if(satsWritten==maxSatsPerLine || satsLeft==0)
706  {
707  // output a complete line
708  line += string(60 - line.size(), ' ');
709  line += hsWaveFact;
710  strm << line << endl;
711  strm.lineNumber++;
712  satsWritten = 0;
713  }
714  vecItr++;
715  }
716  itr++;
717  }
718  }
719  }
720  if(version >= 3 && valid & validSigStrengthUnit)
721  {
722  line = leftJustify(sigStrengthUnit, 20);
723  line += string(40, ' ');
724  line += hsSigStrengthUnit;
725  strm << line << endl;
726  strm.lineNumber++;
727  }
728  if(valid & validInterval)
729  {
730  line = rightJustify(asString(interval, 3), 10);
731  line += string(50, ' ');
732  line += hsInterval;
733  strm << line << endl;
734  strm.lineNumber++;
735  }
736  if(valid & validFirstTime)
737  {
738  line = writeTime(firstObs);
739  line += string(60 - line.size(), ' ');
740  line += hsFirstTime;
741  strm << line << endl;
742  strm.lineNumber++;
743  }
744  if(valid & validLastTime)
745  {
746  line = writeTime(lastObs);
747  line += string(60 - line.size(), ' ');
748  line += hsLastTime;
749  strm << line << endl;
750  strm.lineNumber++;
751  }
753  {
755  line += string(54, ' ');
756  line += hsReceiverOffset;
757  strm << line << endl;
758  strm.lineNumber++;
759  }
760  if(version >= 3 && (valid & validSystemDCBSapplied))
761  {
762  for(size_t i = 0; i < infoDCBS.size(); i++)
763  {
764  line = leftJustify(infoDCBS[i].satSys, 1);
765  line += string(1, ' ');
766  line += leftJustify(infoDCBS[i].name , 17);
767  line += string(1, ' ');
768  line += leftJustify(infoDCBS[i].source, 40);
769  line += hsSystemDCBSapplied;
770  strm << line << endl;
771  strm.lineNumber++;
772  }
773  }
774  if(version >= 3 && (valid & validSystemPCVSapplied))
775  {
776  for(size_t i = 0; i < infoPCVS.size(); i++)
777  {
778  line = leftJustify(infoPCVS[i].satSys, 1);
779  line += string(1, ' ');
780  line += leftJustify(infoPCVS[i].name , 17);
781  line += string(1, ' ');
782  line += leftJustify(infoPCVS[i].source, 40);
783  line += hsSystemPCVSapplied;
784  strm << line << endl;
785  strm.lineNumber++;
786  }
787  }
788  if(version >= 3 && (valid & validSystemScaleFac))
789  {
790  static const int maxObsPerLine = 12;
791 
792  static const int size = 4;
793  static const int factors[size] = {1,10,100,1000};
794  vector<string> obsTypes;
795 
796  // loop over GNSSes
797  map<string, ScaleFacMap>::const_iterator mapIter;
798  for(mapIter = sysSfacMap.begin(); mapIter != sysSfacMap.end(); mapIter++)
799  {
800  map<RinexObsID, int>::const_iterator iter;
801 
802  for(int i = 0; i < size; i++) // loop over possible factors (above)
803  {
804  int count = 0;
805  obsTypes.clear(); // clear the list of Obs Types we're going to make
806 
807  for(iter = mapIter->second.begin(); // loop over scale factor map
808  iter != mapIter->second.end(); iter++)
809  {
810  if(iter->second == factors[i] )
811  {
812  count++;
813  obsTypes.push_back(iter->first.asString(version));
814  }
815  }
816 
817  if(count == 0 ) continue;
818 
819  line = leftJustify(mapIter->first , 1);
820  line += string(1, ' ');
821  line += rightJustify(asString(factors[i]), 4);
822  line += string(2, ' ');
823  line += rightJustify(asString(count ), 2);
824 
825  for(int j = 0; j < count; j++)
826  {
827  if(j > maxObsPerLine-1 && (j % maxObsPerLine) == 0 )
828  {
829  // need continuation; end current line
830  line += string(2, ' ');
831  line += hsSystemScaleFac;
832  strm << line << endl;
833  strm.lineNumber++;
834  line = string(10, ' ');
835  }
836  line += string(1, ' ');
837  line += rightJustify(obsTypes[j], 3);
838  }
839  int space = 60 - 10 - 4*(count % maxObsPerLine);
840  line += string(space, ' ');
841  line += hsSystemScaleFac;
842  strm << line << endl;
843  strm.lineNumber++;
844  }
845  }
846  }
847  if(version >= 3.01 && (valid & validSystemPhaseShift))
848  {
849  //map<string, map<RinexObsID, map<RinexSatID,double> > > sysPhaseShift;
850  map<string, map<RinexObsID, map<RinexSatID,double> > >::const_iterator it;
851  for(it=sysPhaseShift.begin(); it!=sysPhaseShift.end(); ++it)
852  {
853  string sys(it->first);
854  map<RinexObsID, map<RinexSatID,double> >::const_iterator jt(it->second.begin());
855  if(jt == it->second.end())
856  {
857  line = sys;
858  line += string(60-line.length(), ' ');
859  line += hsSystemPhaseShift;
860  strm << line << endl;
861  strm.lineNumber++;
862  }
863  else
864  {
865  for( ; jt!=it->second.end(); ++jt)
866  {
867  RinexSatID sat(jt->second.begin()->first);
868  double corr(jt->second.begin()->second);
869  if (jt->first.type != ObservationType::Phase)
870  {
871  // Phase shift only makes sense for phase measurements.
872  continue;
873  }
874  line = sys + " ";
875  line += leftJustify(jt->first.asString(version),3) + " ";
876  line += rightJustify(asString(corr,5),8);
877  if(sat.id == -1)
878  {
879  line += string(60-line.length(), ' ');
880  line += hsSystemPhaseShift;
881  strm << line << endl;
882  strm.lineNumber++;
883  }
884  else
885  {
886  // list of sats
887  setfill('0');
888  line += string(" ") + rightJustify(asString(jt->second.size()),2);
889  setfill(' ');
890 
891  int n(0);
892  map<RinexSatID,double>::const_iterator kt,lt;
893  for(kt=jt->second.begin(); kt!=jt->second.end(); ++kt)
894  {
895  line += string(" ") + kt->first.toString();
896  if(++n == 10 || ++(lt=kt) == jt->second.end())
897  {
898  // end this line
899  line += string(60-line.length(), ' ');
900  line += hsSystemPhaseShift;
901  strm << line << endl;
902  strm.lineNumber++;
903  n = 0;
904  // are there more for a continuation line?
905  if(lt != jt->second.end())
906  line = string(18,' ');
907  } // if(++n == 10 || ++(lt=kt) == jt->second.end())
908  } // for(kt=jt->second.begin(); kt!=jt->second.end(); ++kt)
909  } // else
910  } // for( ; jt!=it->second.end(); ++jt)
911  } // else
912  } // for(it=sysPhaseShift.begin(); it!=sysPhaseShift.end(); ++it)
913  } // if(version >= 3.01 && (valid & validSystemPhaseShift))
914  if(version >= 3.01)
915  {
917  {
918  size_t n(0), nsat(glonassFreqNo.size());
919  line = rightJustify(asString(nsat), 3) + " ";
920  GLOFreqNumMap::const_iterator it, kt;
921  for (it = glonassFreqNo.begin(); it != glonassFreqNo.end(); ++it) {
922  line += it->first.toString();
923  line += rightJustify(asString(it->second), 3) + " ";
924  if (++n == 8 || ++(kt = it) == glonassFreqNo.end()) {
925  // write it
926  line += string(60 - line.length(), ' ');
927  line += hsGlonassSlotFreqNo;
928  strm << line << endl;
929  strm.lineNumber++;
930  n = 0;
931  // are there more for a continuation line?
932  if (kt != glonassFreqNo.end())
933  line = string(4, ' ');
934  }
935  }
936  }
937  else if(mapObsTypes.find("R") != mapObsTypes.end())
938  {
939  FFStreamError err("Glonass Slot Freq No required for files containing Glonass Observations ");
940  GNSSTK_THROW(err);
941  }
942  }
943  if(version >= 3.02)
944  {
946  {
947  line.clear();
948  GLOCodPhsBias::const_iterator it;
949  const string labs[4] = {"C1C", "C1P", "C2C", "C2P"};
950  for (int i = 0; i < 4; i++) {
951  RinexObsID obsid(RinexObsID("R" + labs[i], version));
952  it = glonassCodPhsBias.find(obsid);
953  double bias = 0.0;
954  if (it != glonassCodPhsBias.end())
955  bias = it->second;
956  line += " " + labs[i] + " " + rightJustify(asString(bias, 3), 8);
957  }
958  line += string(60 - line.length(), ' ');
959  line += hsGlonassCodPhsBias;
960  strm << line << endl;
961  strm.lineNumber++;
962  }
963  else if(mapObsTypes.find("R") != mapObsTypes.end())
964  {
965  FFStreamError err("Glonass Code Phase Bias required for files containing Glonass Observations ");
966  GNSSTK_THROW(err);
967  }
968  }
969  if(valid & validLeapSeconds)
970  {
971  line = rightJustify(asString(leapSeconds), 6);
972  line += string(54, ' ');
973  line += hsLeapSeconds;
974  strm << line << endl;
975  strm.lineNumber++;
976  }
977  if(valid & validNumSats)
978  {
979  line = rightJustify(asString(numSVs), 6);
980  line += string(54, ' ');
981  line += hsNumSats;
982  strm << line << endl;
983  strm.lineNumber++;
984  }
985  if(valid & validPrnObs)
986  {
987  static const int maxObsPerLine = 9;
988  map<RinexSatID, vector<int> >::const_iterator itr(numObsForSat.begin());
989  // loop over satellites
990  while(itr != numObsForSat.end())
991  {
992  int numObsWritten = 0; // # of counts written for this sat
993  RinexSatID sat(itr->first); // the sat
994  const vector<int>& numObs(itr->second); // the vector of ints stored
995  vector<int> vec; // the vector of ints to write
996 
997  if(version >= 3)
998  vec = numObs;
999  else
1000  {
1001  // fill in zeros for version 2
1002  int j;
1003  size_t i;
1004  string sys(string(1,sat.systemChar()));
1005  map<string, map<string, RinexObsID> >::const_iterator jt(mapSysR2toR3ObsID.find(sys));
1006  const map<string, RinexObsID> mapVec(jt->second);
1007  map<string, RinexObsID>::const_iterator kt;
1008  for(i=0,j=0; i<R2ObsTypes.size(); i++)
1009  {
1010  kt = mapVec.find(R2ObsTypes[i]);
1011  string obsid(kt->second.asString(version));
1012  if(obsid == string(" ")) vec.push_back(0.0);
1013  else vec.push_back(numObs[j++]);
1014  }
1015  }
1016 
1017  vector<int>::const_iterator vecItr(vec.begin());
1018  while (vecItr != vec.end())
1019  {
1020  if(numObsWritten == 0)
1021  {
1022  // start of line
1023  try
1024  {
1025  line = string(3, ' ') + sat.toString(); // ' G01'
1026  }
1027  catch (Exception& e)
1028  {
1029  FFStreamError ffse(e);
1030  GNSSTK_RETHROW(ffse);
1031  }
1032  }
1033  else if((numObsWritten % maxObsPerLine) == 0)
1034  {
1035  // end of line
1036  line += hsPrnObs;
1037  strm << line << endl;
1038  strm.lineNumber++;
1039  line = string(6, ' ');
1040  }
1041 
1042  line += rightJustify(asString(*vecItr), 6); // add num obs to line
1043  ++vecItr;
1044  ++numObsWritten;
1045  }
1046 
1047  // finish last line
1048  line += string(60 - line.size(), ' ');
1049  line += hsPrnObs;
1050  strm << line << endl;
1051  strm.lineNumber++;
1052  itr++;
1053  }
1054  }
1055  if(validEoH)
1056  {
1057  line = string(60, ' ');
1058  line += hsEoH;
1059  strm << line << endl;
1060  strm.lineNumber++;
1061  }
1062  } // end writeHeaderRecords
1063 
1064 
1065  // This function parses a single header record.
1067  {
1068  int i;
1069  string label(line, 60, 20);
1070 
1071  if(label == hsVersion)
1072  {
1073  version = asDouble(line.substr( 0,20));
1074  fileType = strip( line.substr(20,20));
1075  fileSys = strip( line.substr(40,20));
1076 
1077  if(fileSys[0] != 'M' && fileSys[0] != 'm')
1078  {
1079  RinexSatID sat;
1080  sat.fromString(fileSys);
1081  fileSysSat = SatID(sat);
1082  }
1083  else
1085 
1086  if(fileType[0] != 'O' && fileType[0] != 'o')
1087  {
1088  FFStreamError e("This isn't a RINEX 3 Obs file.");
1089  GNSSTK_THROW(e);
1090  }
1091 
1092  valid |= validVersion;
1093  }
1094  else if(label == hsRunBy)
1095  {
1096  fileProgram = strip(line.substr( 0,20));
1097  fileAgency = strip(line.substr(20,20));
1098  date = strip(line.substr(40,20));
1099  valid |= validRunBy;
1100  }
1101  else if(label == hsComment)
1102  {
1103  std::string comment = strip(line.substr(0,60));
1104  if (comment == hsAntennaStandard)
1105  {
1107  }
1108  else if (comment == hsAntennaRegional)
1109  {
1111  }
1112  commentList.push_back(comment);
1113  valid |= validComment;
1114  }
1115  else if(label == hsMarkerName)
1116  {
1117  markerName = strip(line.substr(0,60));
1119  }
1120  else if(label == hsMarkerNumber)
1121  {
1122  markerNumber = strip(line.substr(0,20));
1124  }
1125  else if(label == hsMarkerType)
1126  {
1127  markerType = strip(line.substr(0,20));
1129  }
1130  else if(label == hsObserver)
1131  {
1132  observer = strip(line.substr( 0,20));
1133  agency = strip(line.substr(20,40));
1134  valid |= validObserver;
1135  }
1136  else if(label == hsReceiver)
1137  {
1138  recNo = strip(line.substr( 0,20));
1139  recType = strip(line.substr(20,20));
1140  recVers = strip(line.substr(40,20));
1141  valid |= validReceiver;
1142  }
1143  else if(label ==hsAntennaType)
1144  {
1145  antNo = strip(line.substr( 0,20));
1146  antType = strip(line.substr(20,20));
1148  }
1149  else if(label == hsAntennaPosition)
1150  {
1151  antennaPosition[0] = asDouble(line.substr( 0,14));
1152  antennaPosition[1] = asDouble(line.substr(14,14));
1153  antennaPosition[2] = asDouble(line.substr(28,14));
1155  }
1156  else if(label == hsAntennaDeltaHEN)
1157  {
1158  antennaDeltaHEN[0] = asDouble(line.substr( 0,14));
1159  antennaDeltaHEN[1] = asDouble(line.substr(14,14));
1160  antennaDeltaHEN[2] = asDouble(line.substr(28,14));
1162  }
1163  else if(label == hsAntennaDeltaXYZ)
1164  {
1165  antennaDeltaXYZ[0] = asDouble(line.substr( 0,14));
1166  antennaDeltaXYZ[1] = asDouble(line.substr(14,14));
1167  antennaDeltaXYZ[2] = asDouble(line.substr(28,14));
1169  }
1170  else if(label == hsAntennaPhaseCtr)
1171  {
1172  antennaSatSys = strip(line.substr(0,2));
1173  antennaObsCode = strip(line.substr(2,3));
1174  antennaPhaseCtr[0] = asDouble(line.substr( 5, 9));
1175  antennaPhaseCtr[1] = asDouble(line.substr(14,14));
1176  antennaPhaseCtr[2] = asDouble(line.substr(28,14));
1178  }
1179  else if(label == hsAntennaBsightXYZ)
1180  {
1181  antennaBsightXYZ[0] = asDouble(line.substr( 0,14));
1182  antennaBsightXYZ[1] = asDouble(line.substr(14,14));
1183  antennaBsightXYZ[2] = asDouble(line.substr(28,14));
1185  }
1186  else if(label == hsAntennaZeroDirAzi)
1187  {
1188  antennaZeroDirAzi = asDouble(line.substr(0,14));
1190  }
1191  else if(label == hsAntennaZeroDirXYZ)
1192  {
1193  antennaZeroDirXYZ[0] = asDouble(line.substr( 0,14));
1194  antennaZeroDirXYZ[1] = asDouble(line.substr(14,14));
1195  antennaZeroDirXYZ[2] = asDouble(line.substr(28,14));
1197  }
1198  else if(label == hsCenterOfMass)
1199  {
1200  centerOfMass[0] = asDouble(line.substr( 0,14));
1201  centerOfMass[1] = asDouble(line.substr(14,14));
1202  centerOfMass[2] = asDouble(line.substr(28,14));
1204  }
1205  else if(label == hsNumObs) // R2 only
1206  {
1207  if(version >= 3)
1208  {
1209  FFStreamError e("RINEX 2 record in RINEX 3 file: " + label);
1210  GNSSTK_THROW(e);
1211  }
1212 
1213  // process the first line
1214  if(!(valid & validNumObs))
1215  {
1216  numObs = asInt(line.substr(0,6));
1217  valid |= validNumObs;
1218  }
1219 
1220  const int maxObsPerLine = 9;
1221  for(i = 0; (R2ObsTypes.size() < numObs) && (i < maxObsPerLine); i++)
1222  R2ObsTypes.push_back(line.substr(i * 6 + 10, 2));
1223  }
1224  else if(label == hsSystemNumObs)
1225  {
1226  if(version < 3)
1227  {
1228  FFStreamError e("RINEX 3 record in RINEX 2 file: " + label);
1229  GNSSTK_THROW(e);
1230  }
1231 
1232  string satSys = strip(line.substr(0,1));
1233  if (satSys != "")
1234  {
1235  numObs = asInt(line.substr(3,3));
1237  satSysPrev = satSys;
1238  }
1239  else
1240  satSys = satSysPrev;
1241 
1242  try
1243  {
1244  const int maxObsPerLine = 13;
1245  for (int i=0;
1246  i < maxObsPerLine && mapObsTypes[satSys].size() < numObs; i++)
1247  {
1248  string obstype(line.substr(4 * i + 7, 3));
1249  mapObsTypes[satSys].push_back(
1250  RinexObsID(satSys+obstype,version));
1251  }
1252  }
1253  catch(InvalidParameter& ip)
1254  {
1255  FFStreamError fse("InvalidParameter: "+ip.what());
1256  GNSSTK_THROW(fse);
1257  }
1258  }
1259  else if(label == hsWaveFact) // R2 only
1260  {
1261  // first time reading this
1262  if(!(valid & validWaveFact))
1263  {
1264  wavelengthFactor[0] = asInt(line.substr(0,6));
1265  wavelengthFactor[1] = asInt(line.substr(6,6));
1266  valid |= validWaveFact;
1267  }
1268  else
1269  {
1270  // additional wave fact lines
1271  const int maxSatsPerLine = 7;
1272  int Nsats;
1273  ExtraWaveFact ewf;
1274  ewf.wavelengthFactor[0] = asInt(line.substr(0,6));
1275  ewf.wavelengthFactor[1] = asInt(line.substr(6,6));
1276  Nsats = asInt(line.substr(12,6));
1277 
1278  if(Nsats > maxSatsPerLine) // > not >=
1279  {
1280  FFStreamError e("Invalid number of Sats for " + hsWaveFact);
1281  GNSSTK_THROW(e);
1282  }
1283 
1284  for(i = 0; i < Nsats; i++)
1285  {
1286  try
1287  {
1288  RinexSatID prn(line.substr(21+i*6,3));
1289  ewf.satList.push_back(prn);
1290  }
1291  catch (Exception& e)
1292  {
1293  FFStreamError ffse(e);
1294  GNSSTK_RETHROW(ffse);
1295  }
1296  }
1297 
1298  extraWaveFactList.push_back(ewf);
1299  }
1300  }
1301  else if(label == hsSigStrengthUnit)
1302  {
1303  sigStrengthUnit = strip(line.substr(0,20));
1305  }
1306  else if(label == hsInterval)
1307  {
1308  interval = asDouble(line.substr(0,10));
1309  valid |= validInterval;
1310  }
1311  else if(label == hsFirstTime)
1312  {
1313  firstObs = parseTime(line);
1314  valid |= validFirstTime;
1315  }
1316  else if(label == hsLastTime)
1317  {
1318  lastObs = parseTime(line);
1319  valid |= validLastTime;
1320  }
1321  else if(label == hsReceiverOffset)
1322  {
1323  receiverOffset = asInt(line.substr(0,6));
1325  }
1326 
1327  else if(label == hsSystemDCBSapplied)
1328  {
1329  Rinex3CorrInfo tempInfo;
1330  tempInfo.satSys = strip(line.substr( 0, 1));
1331  tempInfo.name = strip(line.substr( 2,17));
1332  tempInfo.source = strip(line.substr(20,40));
1333  infoDCBS.push_back(tempInfo);
1335  }
1336  else if(label == hsSystemPCVSapplied)
1337  {
1338  Rinex3CorrInfo tempInfo;
1339  tempInfo.satSys = strip(line.substr( 0, 1));
1340  tempInfo.name = strip(line.substr( 2,17));
1341  tempInfo.source = strip(line.substr(20,40));
1342  infoPCVS.push_back(tempInfo);
1344  }
1345  else if(label == hsSystemScaleFac)
1346  {
1347  static const int maxObsPerLine = 12;
1348 
1349  satSysTemp = strip(line.substr(0,1));
1350  factor = asInt(line.substr(2,4));
1351  numObs = asInt(line.substr(8,2));
1352 
1353  int startPosition = 0;
1354 
1355  if(satSysTemp == "" )
1356  {
1357  // it's a continuation line; use prev. info., end pt. to start
1359  factor = factorPrev;
1360  numObs = numObsPrev;
1361 
1362  startPosition = sysSfacMap[satSysTemp].size();
1363  }
1364 
1365  // 0/blank numObs means factor applies to all obs types
1366  // in appropriate obsTypeList
1367  if(numObs == 0)
1368  numObs = mapObsTypes[satSysTemp].size();
1369 
1370  ScaleFacMap tempSfacMap = sysSfacMap[satSysTemp];
1371  for(i = startPosition;
1372  (i < numObs) && ((i % maxObsPerLine) < maxObsPerLine); i++)
1373  {
1374  int position = 4*(i % maxObsPerLine) + 10 + 1;
1375  RinexObsID tempType(satSysTemp+strip(line.substr(position,3)),
1376  version);
1377  tempSfacMap.insert(make_pair(tempType,factor));
1378  }
1379  sysSfacMap[satSysTemp] = tempSfacMap;
1380 
1381  ScaleFacMap::const_iterator iter;
1382  ScaleFacMap tempmap;
1383  tempmap = sysSfacMap[satSysTemp];
1384 
1385  // save values in case next line is a continuation line
1387  factorPrev = factor;
1388  numObsPrev = numObs;
1389 
1391  }
1392  else if(label == hsSystemPhaseShift || label == hsSystemPhaseShift+"S")
1393  {
1394  // The above +"S" is that some files pluralize this...
1395  RinexSatID sat;
1396  // system
1397  satSysTemp = strip(line.substr(0,1));
1398 
1399  if(satSysTemp.empty())
1400  {
1401  // continuation line
1403 
1405  == sysPhaseShift[satSysTemp].end())
1406  {
1407  //FFStreamError e("SYS / PHASE SHIFT: unexpected continuation line");
1408  //GNSSTK_THROW(e);
1409  // lenient - some writers have only a single blank record
1410  return;
1411  }
1412 
1413  map<RinexSatID,double>& satcorrmap(sysPhaseShift[satSysTemp][sysPhaseShiftObsID]);
1414  double cor(sysPhaseShift[satSysTemp][sysPhaseShiftObsID].begin()->second);
1415  for(i=0; i<10; i++)
1416  {
1417  string str = strip(line.substr(19+4*i,3));
1418  if(str.empty()) break;
1419  sat = RinexSatID(str);
1420  satcorrmap.insert(make_pair(sat,cor));
1421  }
1422  }
1423  else
1424  {
1425  // not a cont. line
1426  sat.fromString(satSysTemp);
1427  if(sysPhaseShift.find(satSysTemp) == sysPhaseShift.end())
1428  {
1429  map<RinexObsID, map<RinexSatID, double> > obssatcormap;
1430  sysPhaseShift.insert(make_pair(satSysTemp,obssatcormap));
1431  }
1432 
1433  // obs id
1434  string str = strip(line.substr(2,3));
1435 
1436  // obsid and correction may be blank <=> unknown: ignore this
1437  if(!str.empty())
1438  {
1439  RinexObsID obsid(satSysTemp+str, version);
1440  double cor(asDouble(strip(line.substr(6,8))));
1441  int nsat(asInt(strip(line.substr(16,2))));
1442  if(nsat > 0)
1443  {
1444  // list of sats
1445  map<RinexSatID,double> satcorrmap;
1446  for(i=0; i<(nsat < 10 ? nsat : 10); i++)
1447  {
1448  sat = RinexSatID(strip(line.substr(19+4*i,3)));
1449  satcorrmap.insert(make_pair(sat,cor));
1450  }
1451  sysPhaseShift[satSysTemp].insert(make_pair(obsid,satcorrmap));
1452  if(nsat > 10) // expect continuation
1453  sysPhaseShiftObsID = obsid;
1454  }
1455  else
1456  {
1457  // no sat, just system
1458  map<RinexSatID,double> satcorrmap;
1459  satcorrmap.insert(make_pair(sat,cor));
1460  sysPhaseShift[satSysTemp].insert(make_pair(obsid,satcorrmap));
1461  }
1462  }
1463 
1464  // save for continuation lines
1466 
1468  }
1469  }
1470  else if(label == hsGlonassSlotFreqNo)
1471  {
1472  //map<RinexSatID,int> glonassFreqNo;
1473  int tmp;
1474  RinexSatID sat;
1475  string str(strip(line.substr(0,3)));
1476 
1477  for(i=0; i<8; i++)
1478  {
1479  str = strip(line.substr(4+i*7,3));
1480  if(str.empty()) break;
1481  sat = RinexSatID(str);
1482  str = strip(line.substr(8+i*7,2));
1483  tmp = asInt(str);
1484  glonassFreqNo.insert(make_pair(sat,tmp));
1485  }
1486 
1488  }
1489  else if(label == hsGlonassCodPhsBias || label == hsGlonassCodPhsBias+"#")
1490  {
1491  // several IGS MGEX 3.02 files do the extra "#"
1492  //std::map<RinexObsID,double> glonassCodPhsBias; ///< "GLONASS COD/PHS/BIS" R3.02
1493  for(i=0; i<4; i++)
1494  {
1495  string str(strip(line.substr(i*13+1,3)));
1496  if(str.empty()) continue;
1497  RinexObsID obsid("R"+str, version);
1498  double bias(asDouble(strip(line.substr(i*13+5,8))));
1499  glonassCodPhsBias[obsid] = bias;
1500  }
1502  }
1503  else if(label == hsLeapSeconds)
1504  {
1505  leapSeconds = asInt(line.substr(0,6));
1507  }
1508  else if(label == hsNumSats)
1509  {
1510  numSVs = asInt(line.substr(0,6)) ;
1511  valid |= validNumSats;
1512  }
1513  else if(label == hsPrnObs)
1514  {
1515  // this assumes 'PRN / # OF OBS' comes after '# / TYPES OF OBSERV' or 'SYS / # / OBS TYPES'
1516  // NOT a good assumption for auxiliary header... ignore in that case
1517  if(version >= 3.0 && mapObsTypes.size() == 0)
1518  {
1519  commentList.push_back(
1520  string("Warning - can't read PRN/OBS in auxHeader: no"
1521  " mapObsTypes"));
1522  return;
1523  }
1524 
1525  static const int maxObsPerLine = 9;
1526 
1527  int j,otmax;
1528  RinexSatID PRN;
1529  string prn, GNSS;
1530  vector<int> numObsList;
1531 
1532  prn = strip(line.substr(3,3));
1533 
1534  if(prn == "" ) // this is a continuation line; use last PRN
1535  {
1536  PRN = lastPRN;
1537  GNSS = PRN.systemChar();
1538  if(version < 3)
1539  otmax = R2ObsTypes.size();
1540  else
1541  {
1542  if(mapObsTypes.find(GNSS) == mapObsTypes.end())
1543  {
1544  Exception e("PRN/#OBS for system "+PRN.toString()+" not found in SYS/#/OBS");
1545  GNSSTK_THROW(e);
1546  }
1547  otmax = mapObsTypes[GNSS].size();
1548  }
1549 
1550  numObsList = numObsForSat[PRN]; // grab the existing list
1551 
1552  for(j=0,i=numObsList.size(); j<maxObsPerLine && i<otmax; i++,j++)
1553  numObsList.push_back(asInt(line.substr(6*j+6,6)));
1554 
1555  numObsForSat[PRN] = numObsList;
1556  }
1557  else // this is a new PRN line
1558  {
1559  PRN = RinexSatID(prn);
1560  GNSS = PRN.systemChar();
1561  if(version < 3)
1562  otmax = R2ObsTypes.size();
1563  else
1564  {
1565  if(mapObsTypes.find(GNSS) == mapObsTypes.end())
1566  {
1567  Exception e("PRN/#OBS for system "+PRN.toString()+" not found in SYS/#/OBS");
1568  GNSSTK_THROW(e);
1569  }
1570  otmax = mapObsTypes[GNSS].size();
1571  }
1572 
1573  for(i=0; i<maxObsPerLine && i<otmax; i++)
1574  numObsList.push_back(asInt(line.substr(6*i+6,6)));
1575 
1576  numObsForSat[PRN] = numObsList;
1577 
1578  lastPRN = PRN;
1579  }
1580 
1581  valid |= validPrnObs;
1582  }
1583  else if(label == hsEoH)
1584  {
1585  validEoH = true;
1586  }
1587  else
1588  {
1589  FFStreamError e("Unidentified label: >" + label + "<");
1590  GNSSTK_THROW(e);
1591  }
1592  } // end of parseHeaderRecord
1593 
1594 
1595  // This function parses the entire header from the given stream
1597  {
1599  Rinex3ObsStream& strm = dynamic_cast<Rinex3ObsStream&>(ffs);
1600 
1601  // If already read, just return.
1602  if(strm.headerRead == true) return;
1603 
1604  // Since we're reading a new header, we need to reinitialize
1605  // all our list structures. All the other objects should be
1606  // ok. This also applies if we threw an exception the first
1607  // time we read the header and are now re-reading it. Some
1608  // of these could be full and we need to empty them.
1609  clear();
1610 
1611  string line;
1612 
1613  while (!validEoH)
1614  {
1615  strm.formattedGetLine(line);
1617 
1618  if(line.length() == 0)
1619  {
1620  FFStreamError e("No data read");
1621  GNSSTK_THROW(e);
1622  }
1623  else if(line.length() < 60 || line.length() > 80)
1624  {
1625  FFStreamError e("Invalid line length");
1626  GNSSTK_THROW(e);
1627  }
1628 
1629  try
1630  {
1631  parseHeaderRecord(line);
1632  }
1633  catch(FFStreamError& e)
1634  {
1635  GNSSTK_RETHROW(e);
1636  }
1637  catch(Exception& e)
1638  {
1639  FFStreamError fse("Exception: "+e.what());
1640  GNSSTK_THROW(fse);
1641  }
1642 
1643  } // end while(not end of header)
1644 
1645  // if RINEX 2, define mapObsTypes from R2ObsTypes and
1646  // system(s) this may have to be corrected later using
1647  // wavelengthFactor also define mapSysR2toR3ObsID in case
1648  // version 2 is written out later
1649  if(version < 3)
1650  {
1651  // try to determine systems included in the file
1652  vector<string> syss; // 1-char strings "G" "R" "E" ...
1653  if(numObsForSat.size() > 0)
1654  {
1655  // get syss from PRN/#OBS
1656  map<RinexSatID, vector<int> >::const_iterator it;
1657  for(it=numObsForSat.begin(); it != numObsForSat.end(); ++it)
1658  {
1659  string sys(string(1,(it->first).systemChar()));
1660  if(find(syss.begin(),syss.end(),sys) == syss.end())
1661  syss.push_back(sys);
1662  }
1663  }
1665  {
1666  // only one system in this file
1667  syss.push_back(string(1,RinexSatID(fileSysSat).systemChar()));
1668  }
1669  else
1670  {
1671  // have to replicate obs type list for all RINEX2 systems
1672  syss.push_back("G");
1673  syss.push_back("R");
1674  syss.push_back("S"); // ??
1675  syss.push_back("E");
1676  }
1677 
1678  // given systems and list of R2ObsTypes, compute
1679  // mapObsTypes and mapSysR2toR3ObsID
1680  mapSysR2toR3ObsID.clear();
1681  for(size_t i=0; i<syss.size(); i++)
1682  {
1683  const string s(syss[i]);
1684  vector<RinexObsID> obsids;
1685 
1686  try
1687  {
1688  if (s=="G")
1689  obsids = mapR2ObsToR3Obs_G();
1690  else if (s=="R")
1691  obsids = mapR2ObsToR3Obs_R();
1692  else if (s=="E")
1693  obsids = mapR2ObsToR3Obs_E();
1694  else if (s=="S")
1695  obsids = mapR2ObsToR3Obs_S();
1696  }
1697  catch(FFStreamError fse)
1698  {
1699  GNSSTK_RETHROW(fse);
1700  }
1701 
1702  // TD if GPS and have wavelengthFactors, add more
1703  // ObsIDs with tc=N
1704 
1705  mapObsTypes[syss[i]] = obsids;
1706  }
1707 
1708  // modify numObsForSat if necessary
1709  map<RinexSatID, vector<int> >::const_iterator it(numObsForSat.begin());
1710  for( ; it != numObsForSat.end(); ++it)
1711  {
1712  RinexSatID sat(it->first);
1713  string sys;
1714  sys = sat.systemChar();
1715  vector<int> vec;
1716  for(size_t i=0; i<R2ObsTypes.size(); i++)
1717  {
1718  if(mapSysR2toR3ObsID[sys][R2ObsTypes[i]].asString(version) == string(" "))
1719  ;
1720  else
1721  vec.push_back(it->second[i]);
1722  }
1723  numObsForSat[sat] = vec;
1724  }
1725  }
1726 
1727  // Since technically the Phase Shift record is required in ver 3.01,
1728  // create SystemPhaseShift record(s) if not present.
1729  //map<string, map<RinexObsID, map<RinexSatID,double> > > sysPhaseShift;
1730  if(version >= 3.01 && (valid & validSystemNumObs)
1731  && !(valid & validSystemPhaseShift))
1732  {
1733  // loop over obs types to get systems
1734  map<string,vector<RinexObsID> >::const_iterator iter;
1735  for(iter=mapObsTypes.begin(); iter != mapObsTypes.end(); iter++)
1736  {
1737  string sys(iter->first);
1738  if(sysPhaseShift.find(sys) == sysPhaseShift.end())
1739  {
1740  map<RinexObsID, map<RinexSatID, double> > dummy;
1741  sysPhaseShift.insert(make_pair(sys,dummy));
1742  }
1743  }
1745  }
1746 
1747  // is the header valid?
1748  Fields allValid = Fields::getRequired(version);
1749  if (allValid.empty())
1750  {
1751  FFStreamError e("Unknown or unsupported RINEX version " +
1752  asString(version,2));
1753  GNSSTK_THROW(e);
1754  }
1755 
1756  if((valid & allValid) != allValid)
1757  {
1758  FFStreamError e("Incomplete or invalid header");
1759  allValid.describeMissing(valid, e);
1760  GNSSTK_THROW(e);
1761  }
1762 
1763  // If we get here, we should have reached the end of header line.
1764  strm.header = *this;
1765  strm.headerRead = true;
1766 
1767  // determine the time system of epochs in this file; cf. R3.02 Table A2
1768  // 1.determine time system from time tag in TIME OF FIRST OBS record
1769  // 2.if not given, determine from type in RINEX VERSION / TYPE record
1770  // 3.(if the type is MIXED, the time system in firstObs is required by RINEX)
1772  if(strm.timesystem == TimeSystem::Any ||
1774  {
1776  {
1777  strm.timesystem = TimeSystem::GPS;
1779  }
1781  {
1782  strm.timesystem = TimeSystem::UTC;
1784  }
1786  {
1787  strm.timesystem = TimeSystem::GAL;
1789  }
1791  {
1792  strm.timesystem = TimeSystem::QZS;
1794  }
1796  {
1797  strm.timesystem = TimeSystem::BDT;
1799  }
1801  {
1802  // lenient
1803  strm.timesystem = TimeSystem::GPS;
1805  // RINEX 3 requires this
1806  //FFStreamError e("TimeSystem in MIXED files must be given by first obs");
1807  //GNSSTK_THROW(e);
1808  }
1809  else
1810  {
1811  FFStreamError e("Unknown file system type");
1812  GNSSTK_THROW(e);
1813  }
1814  }
1815 
1816  } // end reallyGetRecord
1817 
1818  // This method maps v2.11 GPS observation types to the v3 equivalent.
1819  // Since only GPS and only v2.11 are of interest, only L1/L2/L5
1820  // are considered.
1822  {
1823  vector<RinexObsID> obsids;
1824 
1825  // Assume D1, S1, and L1 come from C/A unless P is being treated as Y and P1 is present
1826  // Furthermore, if P1 is present and P is NOT being treated as Y, assume that P1
1827  // is some Z-mode or equivalent "smart" codeless process.
1828  //
1829  // Condition Result
1830  // PisY P1?
1831  // N Y L1,D1,S1 considered C, P1 becomes C1W
1832  // N N L1,D1,S1 considered C
1833  // Y Y L1,D1,S1 considered Y, P1 becomes C1Y
1834  // Y N L1,D1,S1 considered C
1835  //
1836  bool hasL1P = find(R2ObsTypes.begin(),R2ObsTypes.end(), string("P1")) != R2ObsTypes.end();
1837  string code1 = "C";
1838  string code1P = "W";
1839  if (PisY && hasL1P)
1840  {
1841  code1 = "Y";
1842  code1P = "Y";
1843  }
1844 
1845  // Assume D2, S2, and L2 come from Y if P is being treated as Y and P2 is present
1846  // codeless unless L2C is tracked.
1847  // If BOTH C2 and P2 are present, and P is NOT being treated as Y, assume C2
1848  // is code tracking the open signal and that P2 is codelessly tracking an
1849  // authorized signal.
1850  //
1851  // Condition Result
1852  // PisY C2? P2?
1853  // N Y N L2,D2,S2 considered X,
1854  // N Y Y L2,D2,S2 considered W, P2 becomes C2W**
1855  // N N Y L2,D2,S2 considered W, P2 becomes C2W
1856  // N N N L2,D2,S2 considered X*
1857  // Y Y N L2,D2,S2 considered X
1858  // Y Y Y L2,D2,S2 considered Y, P2 becomes C2Y
1859  // Y N Y L2,D2,S2 considered Y, P2 becomes C2Y
1860  // Y N N L2,D2,S2 considered X*
1861  // * - Probably not a reasonable set of conditions. It implies no L2 pseudoranges
1862  // were collected on any tracking code.
1863  // **- Interesting case. Currently presence of C2 in the header means
1864  // that the data MAY be present. However, since only some of the GPS
1865  // SVs have L2C, the C2 data field will frequently be empty.
1866  // Therefore, we'll go with "W" if P2 is present. The other option
1867  // would be to add smarts to the SV-by-SV record reading process to
1868  // coerce this to X if there are actually data in the C2 field at
1869  // the time the observations are read. That would really do violence
1870  // to the existing logic. Better to hope for a transition to Rinex 3
1871  // before this becomes a real issue.
1872  //
1873  // N.B.: This logic (both for P1 and P2) assumes P is NEVER P. If we want to allow for
1874  // live sky (or simulator capture) P code, we'll have to add more logic
1875  // to differentate between PisY, PisW, and PisP. That will have to be
1876  // "beyond RINEX v2.11" extra-special handling.
1877  //
1878  bool hasL2P = find(R2ObsTypes.begin(),R2ObsTypes.end(), string("P2")) != R2ObsTypes.end();
1879  bool hasL2C = find(R2ObsTypes.begin(),R2ObsTypes.end(), string("C2")) != R2ObsTypes.end();
1880 
1881  string code2 = "X"; // Correct condition as long as P2 is not in the list
1882  string code2P = "X"; // Condition is irrelvant unless P2 is in the list
1883  if (hasL2P)
1884  {
1885  if (PisY)
1886  {
1887  code2 = "Y";
1888  code2P = "Y";
1889  }
1890  else
1891  {
1892  code2 = "W";
1893  code2P = "W";
1894  }
1895  }
1896  string syss("G");
1897  for(size_t j=0; j<R2ObsTypes.size(); ++j)
1898  {
1899  string ot(R2ObsTypes[j]);
1900  string obsid(syss);
1901 
1902  if (ot == "C1") obsid += "C1C";
1903  else if (ot == "P1") obsid += "C1" + code1P;
1904  else if (ot == "L1") obsid += "L1" + code1;
1905  else if (ot == "D1") obsid += "D1" + code1;
1906  else if (ot == "S1") obsid += "S1" + code1;
1907 
1908  else if (ot == "C2") obsid += "C2X";
1909  else if (ot == "P2") obsid += "C2" + code2P;
1910  else if (ot == "L2") obsid += "L2" + code2;
1911  else if (ot == "D2") obsid += "D2" + code2;
1912  else if (ot == "S2") obsid += "S2" + code2;
1913 
1914  else if (ot == "C5") obsid += "C5X";
1915  else if (ot == "L5") obsid += "L5X";
1916  else if (ot == "D5") obsid += "D5X";
1917  else if (ot == "S5") obsid += "S5X";
1918 
1919  // If the obs type isn't valid for GPS, skip it.
1920  else continue;
1921 
1922  try
1923  {
1924  RinexObsID OT(obsid, version);
1925  obsids.push_back(OT);
1926  mapSysR2toR3ObsID[syss][ot] = OT; //map<string, map<string, RinexObsID> >
1927  }
1928  catch(InvalidParameter& ip)
1929  {
1930  FFStreamError fse("InvalidParameter: "+ip.what());
1931  GNSSTK_THROW(fse);
1932  }
1933  }
1934  return obsids;
1935  }
1936 
1937  // This method maps v2.11 GLONASS observation types to the v3 equivalent.
1938  // Since only GLONASS and only v2.11 are of interest, only L1/L2
1939  // are considered.
1941  {
1942  vector<RinexObsID> obsids;
1943 
1944  // Assume D1, S1, and L1 come from C/A
1945  // This assumes that any files claiming to track GLONASS P1 is
1946  // actually doing so with a codeless technique. There is no RINEX V3
1947  // "C1W" for GLONASS, so we'll leave P1 as C1P as the closest approximation.
1948  bool hasL1P = find(R2ObsTypes.begin(),R2ObsTypes.end(), string("P1")) != R2ObsTypes.end();
1949  string code1 = "C";
1950 
1951  // Assume D2, S2, and L2 come from C/A. Same logic as above.
1952  bool hasL2P = find(R2ObsTypes.begin(),R2ObsTypes.end(), string("P2")) != R2ObsTypes.end();
1953  string code2 = "C";
1954 
1955  string syss("R");
1956  for(size_t j=0; j<R2ObsTypes.size(); ++j)
1957  {
1958  string ot(R2ObsTypes[j]);
1959  string obsid(syss);
1960 
1961  if (ot == "C1") obsid += "C1C";
1962  else if (ot == "P1") obsid += "C1P";
1963  else if (ot == "L1") obsid += "L1" + code1;
1964  else if (ot == "D1") obsid += "D1" + code1;
1965  else if (ot == "S1") obsid += "S1" + code1;
1966 
1967  else if (ot == "C2") obsid += "C2C";
1968  else if (ot == "P2") obsid += "C2P";
1969  else if (ot == "L2") obsid += "L2" + code2;
1970  else if (ot == "D2") obsid += "D2" + code2;
1971  else if (ot == "S2") obsid += "S2" + code2;
1972 
1973  // If the obs type isn't valid for GLONASS, skip it.
1974  else continue;
1975 
1976  try
1977  {
1978  RinexObsID OT(obsid, version);
1979  obsids.push_back(OT);
1980  mapSysR2toR3ObsID[syss][ot] = OT; //map<string, map<string, RinexObsID> >
1981  }
1982  catch(InvalidParameter& ip)
1983  {
1984  FFStreamError fse("InvalidParameter: "+ip.what());
1985  GNSSTK_THROW(fse);
1986  }
1987  }
1988  return obsids;
1989  }
1990 
1991  // This method maps v2.11 Galileo observation types to the v3 equivalent.
1992  // Since only Galileo and only v2.11 are of interest no L2 types
1993  // are considered. Furthermore, Rinex v2.11 states that there is no
1994  // P for Galileo. (Where that leaves the PRS is a good question.)
1995  //
1996  // In RINEX v3, there are 3-5 tracking codes defined for each carrier.
1997  // Given the current lack of experience, the code makes some
1998  // guesses on what the v2.11 translations should mean.
2000  {
2001  vector<RinexObsID> obsids;
2002 
2003  string code1 = "B"; // Corresponds to the open service
2004  string code5 = "I"; // Corresponds to the open service
2005  string code7 = "X"; // Corresponds to I + Q tracking
2006  string code8 = "X"; // Corresponds to I + Q tracking
2007  string code6 = "X"; // Corresponds to B + C tracking
2008 
2009  string syss("E");
2010  for(size_t j=0; j<R2ObsTypes.size(); ++j)
2011  {
2012  string ot(R2ObsTypes[j]);
2013  string obsid(syss);
2014  if (ot == "C1") obsid += "C1" + code1;
2015  else if (ot == "L1") obsid += "L1" + code1;
2016  else if (ot == "D1") obsid += "D1" + code1;
2017  else if (ot == "S1") obsid += "S1" + code1;
2018 
2019  else if (ot == "C5") obsid += "C5" + code5;
2020  else if (ot == "L5") obsid += "L5" + code5;
2021  else if (ot == "D5") obsid += "D5" + code5;
2022  else if (ot == "S5") obsid += "S5" + code5;
2023 
2024  else if (ot == "C6") obsid += "C6" + code6;
2025  else if (ot == "L6") obsid += "L6" + code6;
2026  else if (ot == "D6") obsid += "D6" + code6;
2027  else if (ot == "S6") obsid += "S6" + code6;
2028 
2029  else if (ot == "C7") obsid += "C7" + code7;
2030  else if (ot == "L7") obsid += "L7" + code7;
2031  else if (ot == "D7") obsid += "D7" + code7;
2032  else if (ot == "S7") obsid += "S7" + code7;
2033 
2034  else if (ot == "C8") obsid += "C8" + code8;
2035  else if (ot == "L8") obsid += "L8" + code8;
2036  else if (ot == "D8") obsid += "D8" + code8;
2037  else if (ot == "S8") obsid += "S8" + code8;
2038 
2039  // If the obs type isn't valid for Galileo, skip it.
2040  else continue;
2041 
2042  try
2043  {
2044  RinexObsID OT(obsid, version);
2045  obsids.push_back(OT);
2046  mapSysR2toR3ObsID[syss][ot] = OT; //map<string, map<string, RinexObsID> >
2047  }
2048  catch(InvalidParameter& ip)
2049  {
2050  FFStreamError fse("InvalidParameter: "+ip.what());
2051  GNSSTK_THROW(fse);
2052  }
2053  }
2054  return obsids;
2055  }
2056 
2057 
2058  // This method maps v2.11 SBAS observation types to the v3 equivalent.
2059  // Since only SBAS and only v2.11 are of interest only L1/L5
2060  // are considered.
2062  {
2063  vector<RinexObsID> obsids;
2064 
2065  string code1 = "C"; // Only option
2066  string code5 = "X"; // Corresponds to I + Q tracking
2067 
2068  string syss("S");
2069  for(size_t j=0; j<R2ObsTypes.size(); ++j)
2070  {
2071  string ot(R2ObsTypes[j]);
2072  string obsid(syss);
2073  if (ot == "C1") obsid += "C1" + code1;
2074  else if (ot == "L1") obsid += "L1" + code1;
2075  else if (ot == "D1") obsid += "D1" + code1;
2076  else if (ot == "S1") obsid += "S1" + code1;
2077 
2078  else if (ot == "C5") obsid += "C5" + code5;
2079  else if (ot == "L5") obsid += "L5" + code5;
2080  else if (ot == "D5") obsid += "D5" + code5;
2081  else if (ot == "S5") obsid += "S5" + code5;
2082 
2083  // If the obs type isn't valid for SBAS, skip it.
2084  else continue;
2085 
2086  try
2087  {
2088  RinexObsID OT(obsid, version);
2089  obsids.push_back(OT);
2090  mapSysR2toR3ObsID[syss][ot] = OT; //map<string, map<string, RinexObsID> >
2091  }
2092  catch(InvalidParameter& ip)
2093  {
2094  FFStreamError fse("InvalidParameter: "+ip.what());
2095  GNSSTK_THROW(fse);
2096  }
2097  }
2098  return obsids;
2099  }
2100 
2101 
2102  CivilTime Rinex3ObsHeader::parseTime(const string& line) const
2103  {
2104  int year, month, day, hour, min;
2105  double sec;
2106  string tsys;
2107  TimeSystem ts;
2108 
2109  year = asInt( line.substr(0, 6));
2110  month = asInt( line.substr(6, 6));
2111  day = asInt( line.substr(12, 6));
2112  hour = asInt( line.substr(18, 6));
2113  min = asInt( line.substr(24, 6));
2114  sec = asDouble(line.substr(30, 13));
2115  tsys = line.substr(48, 3) ;
2116 
2118 
2119  return CivilTime(year, month, day, hour, min, sec, ts);
2120  } // end parseTime
2121 
2122 
2123  string Rinex3ObsHeader::writeTime(const CivilTime& civtime) const
2124  {
2126  string line, tsStr(gnsstk::StringUtils::asString(civtime.getTimeSystem()));
2127 
2128  line = rightJustify(asString<short>(civtime.year ) , 6);
2129  line += rightJustify(asString<short>(civtime.month ) , 6);
2130  line += rightJustify(asString<short>(civtime.day ) , 6);
2131  line += rightJustify(asString<short>(civtime.hour ) , 6);
2132  line += rightJustify(asString<short>(civtime.minute ) , 6);
2133  line += rightJustify(asString( civtime.second,7) , 13);
2134  line += rightJustify(tsStr, 8);
2135 
2136  return line;
2137  } // end writeTime
2138 
2139  // Compute map of obs types for use in writing version 2 header
2140  // and data, call before writing
2142  {
2143  if(version > 3)
2144  {
2145  version = 2.11;
2146  }
2149  {
2150  // change from RINEX 3 header to RINEX 2 equivalent
2153  }
2155 
2156  // make a list of R2 obstype strings, and a map R3ObsIDs <=
2157  // R2 obstypes for each system
2158  R2ObsTypes.clear();
2159  map<string,vector<RinexObsID> >::const_iterator mit;
2160  for (mit = mapObsTypes.begin(); mit != mapObsTypes.end(); mit++)
2161  {
2162  string sysString = mit->first;
2163  // Compass/BeiDou and QZSS and IRNSS are unsupported by RINEX 2.11.
2164  // Transit was deprecated in 2.11.
2165  // Skip them.
2166  if ((sysString == "I") || (sysString == "J") || (sysString == "C") ||
2167  (sysString == "T"))
2168  {
2169  continue;
2170  }
2171  // 2.11 supports only GPS, GLONASS, Geo/SBAS and Galileo
2172  if(sysString!="G" && sysString!="R" && sysString!="E" &&
2173  sysString!="S")
2174  {
2175  FFStreamError er(
2176  "Invalid system char string in header.mapObsTypes: "+sysString);
2177  GNSSTK_THROW(er);
2178  }
2179  // mit->first is system char as a 1-char string
2180  map<string, RinexObsID> mapR2toR3ObsID;
2181 
2182  vector<string> uniqueCheck;
2183  // loop over all ObsIDs for this system
2184  for(size_t i=0; i<mit->second.size(); i++)
2185  {
2186  string R2ot, lab(mit->second[i].asString(version));
2187  // the list of all tracking code characters for this sys, freq
2188  string allCodes(
2189  RinexObsID::validRinexTrackingCodes[mit->first[0]][lab[1]]);
2190 
2191  if (lab == string("C1C"))
2192  R2ot = string("C1");
2193  else if (lab == string("C2X") && mit->first == "G")
2194  R2ot = string("C2");
2195  else if (lab == string("C2C") && mit->first == "R")
2196  R2ot = string("C2");
2197  // R2 has C5 but not P5
2198  else if (lab.substr(0,2) == "C5")
2199  R2ot = string("C5");
2200  else if (lab[0] == 'C')
2201  R2ot = string("P")+string(1,lab[1]);
2202  else
2203  R2ot = lab.substr(0,2);
2204  // add to list, if not already there
2205  vector<string>::iterator it;
2206  it = find(R2ObsTypes.begin(),R2ObsTypes.end(),R2ot);
2207  if (it == R2ObsTypes.end())
2208  {
2209  // its not there - add it
2210  R2ObsTypes.push_back(R2ot);
2211  mapR2toR3ObsID[R2ot] = mit->second[i];
2212  }
2213  else
2214  {
2215  // its already there - in list of R2 ots
2216  if (mapR2toR3ObsID.find(R2ot) == mapR2toR3ObsID.end())
2217  {
2218  // must also add to sys map
2219  mapR2toR3ObsID[R2ot] = mit->second[i];
2220  }
2221  else
2222  {
2223  // its already in sys map ...
2224  // .. but is the new tc 'better'?
2225  string::size_type posold,posnew;
2226  posold = allCodes.find((mapR2toR3ObsID[R2ot].asString(version))[2]);
2227  posnew = allCodes.find(lab[2]);
2228  if(posnew < posold)
2229  {
2230  // replace the R3ObsID in the map
2231  mapR2toR3ObsID[R2ot] = mit->second[i];
2232  }
2233  if (R2DisambiguityMap.find(sysString + R2ot) ==
2234  R2DisambiguityMap.end())
2235  {
2236  R2DisambiguityMap.insert(
2237  std::pair<string,string>(
2238  sysString + R2ot,
2239  mapR2toR3ObsID[R2ot].asString(version)));
2240  }
2241  else
2242  {
2243  R2DisambiguityMap[sysString + R2ot] = lab;
2244  }
2245  }
2246  }
2247  }
2248  // save for this system
2249  mapSysR2toR3ObsID[mit->first] = mapR2toR3ObsID;
2250  }
2251  } // end prepareVer2Write()
2252 
2253  void Rinex3ObsHeader::dump(std::ostream& s, double dumpVersion) const
2254  {
2256  size_t i;
2257 
2258  string str;
2260  str = "MIXED";
2261  else
2262  {
2263  RinexSatID sat(fileSysSat);
2264  str = sat.systemChar();
2265  str = str + " (" + sat.systemString() + ")";
2266  }
2267 
2268  s << "---------------------------------- REQUIRED "
2269  << "----------------------------------" << endl;
2270  s << "Rinex Version " << fixed << setw(5) << setprecision(2) << dumpVersion
2271  << ", File type " << fileType << ", System " << str << "." << endl;
2272  s << "Prgm: " << fileProgram << ", Run: " << date
2273  << ", By: " << fileAgency << endl;
2274  s << "Marker name: " << markerName << ", ";
2275  s << "Marker type: " << markerType << "." << endl;
2276  s << "Observer : " << observer << ", Agency: " << agency << endl;
2277  s << "Rec#: " << recNo << ", Type: " << recType
2278  << ", Vers: " << recVers << endl;
2279  s << "Antenna # : " << antNo << ", Type : " << antType << endl;
2280  s << "Position (XYZ,m) : " << setprecision(4) << antennaPosition
2281  << "." << endl;
2282  s << "Antenna Delta (HEN,m) : " << setprecision(4) << antennaDeltaHEN
2283  << "." << endl;
2284  map<string,vector<RinexObsID> >::const_iterator iter;
2285  for(iter = mapObsTypes.begin(); iter != mapObsTypes.end(); iter++)
2286  {
2287  RinexSatID rsid;
2288  rsid.fromString(iter->first);
2289  s << rsid.systemString() << " Observation types ("
2290  << iter->second.size() << "):" << endl;
2291  for(i = 0; i < iter->second.size(); i++)
2292  {
2293  s << " Type #" << setw(2) << setfill('0') << i+1 << setfill(' ')
2294  << " (" << iter->second[i].asString(dumpVersion) << ") "
2295  << asString(static_cast<ObsID>(iter->second[i])) << endl;
2296  }
2297  }
2298 
2299  s << "R2ObsTypes: ";
2300  for (StringVec::const_iterator i=R2ObsTypes.begin(); i != R2ObsTypes.end(); i++)
2301  s << *i << " ";
2302  s << endl;
2303  for (VersionObsMap::const_iterator i = mapSysR2toR3ObsID.begin(); i != mapSysR2toR3ObsID.end(); i++)
2304  {
2305  s << "mapSysR2toR3ObsID[" << i->first << "] ";
2306  for (ObsIDMap::const_iterator j = i->second.begin(); j != i->second.end(); j++)
2307  s << j->first << ":" << j->second.asString(dumpVersion) << " ";
2308  s << endl;
2309  }
2310 
2311  s << "Time of first obs "
2312  << printTime(firstObs,"%04Y/%02m/%02d %02H:%02M:%06.3f %P") << endl;
2313 
2314  s << "(This header is ";
2315  if (Fields::isValid(dumpVersion, valid))
2316  s << "VALID)" << endl;
2317  else
2318  {
2319  s << "NOT VALID";
2320  s << " RINEX " << setprecision(2) << dumpVersion << ")" << endl;
2321  s << "valid = " << valid << endl;
2322  Fields required = Fields::getRequired(dumpVersion);
2323  s << "allValid = " << required << endl;
2324 
2325  s << "Invalid or missing header records:" << endl;
2326  // print all header fields in required not in valid
2327  for (const auto& reqi : required.fieldsSet)
2328  {
2329  if (valid.isSet(reqi) == 0)
2330  {
2331  s << " " << setw(2) << reqi << " "
2332  << Rinex3ObsHeader::asString(reqi) << endl;
2333  }
2334  }
2335  s << "END Invalid header records." << endl;
2336  }
2337 
2338  s << "---------------------------------- OPTIONAL "
2339  << "----------------------------------" << endl;
2340  if(valid & validMarkerNumber )
2341  s << "Marker number : " << markerNumber << endl;
2342  if(valid & validMarkerType )
2343  s << "Marker type : " << markerType << endl;
2345  s << "Antenna Delta (XYZ,m) : "
2346  << setprecision(4) << antennaDeltaXYZ << endl;
2348  s << "Antenna PhaseCtr (XYZ,m) : "
2349  << setprecision(4) << antennaPhaseCtr << endl;
2351  s << "Antenna B.sight (XYZ,m) : "
2352  << setprecision(4) << antennaBsightXYZ << endl;
2354  s << "Antenna ZeroDir (deg) : "
2355  << setprecision(4) << antennaZeroDirAzi << endl;
2357  s << "Antenna ZeroDir (XYZ,m) : "
2358  << setprecision(4) << antennaZeroDirXYZ << endl;
2359  if(valid & validCenterOfMass )
2360  s << "Center of Mass (XYZ,m) : "
2361  << setprecision(4) << antennaPhaseCtr << endl;
2363  s << "Signal Strength Unit = " << sigStrengthUnit << endl;
2364  if(valid & validInterval )
2365  s << "Interval = "
2366  << fixed << setw(7) << setprecision(3) << interval << endl;
2367  if(valid & validLastTime )
2368  s << "Time of Last Obs "
2369  << printTime(lastObs,"%04Y/%02m/%02d %02H:%02M:%06.3f %P") << endl;
2370  if(valid & validReceiverOffset )
2371  s << "Clock offset record is present and offsets "
2372  << (receiverOffset ? "ARE" : "are NOT") << " applied." << endl;
2373  if(dumpVersion < 3 && (valid & validWaveFact)) // TD extraWaveFactList
2374  s << "Wavelength factor L1: " << wavelengthFactor[0]
2375  << " L2: " << wavelengthFactor[1] << endl;
2377  {
2378  for(i = 0; i < infoDCBS.size(); i++)
2379  {
2380  RinexSatID rsid;
2381  rsid.fromString(infoDCBS[i].satSys);
2382  s << "System DCBS Correction Applied to " << rsid.systemString()
2383  << " data using program " << infoDCBS[i].name << endl;
2384  s << " from source " << infoDCBS[i].source << "." << endl;
2385  }
2386  }
2388  {
2389  for(i = 0; i < infoPCVS.size(); i++)
2390  {
2391  RinexSatID rsid;
2392  rsid.fromString(infoPCVS[i].satSys);
2393  s << "System PCVS Correction Applied to " << rsid.systemString()
2394  << " data using program " << infoPCVS[i].name << endl;
2395  s << " from source " << infoPCVS[i].source << "." << endl;
2396  }
2397  }
2398  if(valid & validSystemScaleFac )
2399  {
2400  map<string, ScaleFacMap>::const_iterator mapIter;
2401  // loop over GNSSes
2402  for(mapIter = sysSfacMap.begin(); mapIter != sysSfacMap.end(); mapIter++)
2403  {
2404  RinexSatID rsid;
2405  rsid.fromString(mapIter->first);
2406  s << rsid.systemString() << " scale factors applied:" << endl;
2407  map<RinexObsID,int>::const_iterator iter;
2408  // loop over scale factor map
2409  for(iter = mapIter->second.begin(); iter != mapIter->second.end(); iter++)
2410  s << " " << iter->first.asString(dumpVersion) << " " << iter->second << endl;
2411  }
2412  }
2414  {
2415  map<string, map<RinexObsID, map<RinexSatID,double> > >::const_iterator it;
2416  for(it=sysPhaseShift.begin(); it!=sysPhaseShift.end(); ++it)
2417  {
2418  string sys(it->first);
2419  map<RinexObsID, map<RinexSatID, double> >::const_iterator jt;
2420  jt = it->second.begin();
2421  if(jt == it->second.end())
2422  s << "Phase shift correction for system " << sys << " is empty." << endl;
2423  for( ; jt!=it->second.end(); ++jt)
2424  {
2425  map<RinexSatID,double>::const_iterator kt;
2426  for(kt=jt->second.begin(); kt!=jt->second.end(); ++kt)
2427  s << "Phase shift correction for system " << sys << ": "
2428  << fixed << setprecision(5)
2429  << setw(8) << kt->second << " cycles applied to obs type "
2430  << jt->first.asString(dumpVersion) << " "
2431  << RinexSatID(sys).systemString() << endl;
2432  }
2433  }
2434  }
2436  {
2437  int n(0);
2438  map<RinexSatID,int>::const_iterator it;
2439  s << "GLONASS frequency channels:\n";
2440  for(it=glonassFreqNo.begin(); it!=glonassFreqNo.end(); ++it)
2441  {
2442  s << " " << it->first.toString() << " " << setw(2) << it->second;
2443  if(++n > 1 && (n%8)==0) s << endl;
2444  }
2445  if((n%8) != 0) s << endl;
2446  }
2448  {
2449  map<RinexObsID,double>::const_iterator it;
2450  s << "GLONASS Code-phase biases:\n" << fixed << setprecision(3);
2451  for(it=glonassCodPhsBias.begin(); it!=glonassCodPhsBias.end(); ++it)
2452  s << " " << it->first.asString(dumpVersion) << " " << setw(8) << it->second;
2453  s << endl;
2454  }
2455  if(valid & validLeapSeconds)
2456  s << "Leap seconds: " << leapSeconds << endl;
2457  if(valid & validNumSats)
2458  s << "Number of Satellites with data : " << numSVs << endl;
2459  if(valid & validPrnObs)
2460  {
2461  RinexSatID sat, sys(-1,SatelliteSystem::Unknown);
2462  s << " PRN and number of observations for each obs type:" << endl;
2463  map<RinexSatID, vector<int> >::const_iterator it = numObsForSat.begin();
2464  while (it != numObsForSat.end())
2465  {
2466  sat = it->first;
2467  if(sat.system != sys.system)
2468  {
2469  // print a header: SYS OT OT OT ...
2470  s << " " << sat.systemString3() << " ";
2471  iter = mapObsTypes.find(string(1,sat.systemChar()));
2472  const vector<RinexObsID>& vec(iter->second);
2473  for(i=0; i<vec.size(); i++)
2474  s << setw(7) << vec[i].asString(dumpVersion);
2475  s << endl;
2476  sys = sat;
2477  }
2478  vector<int> obsvec = it->second;
2479  s << " " << sat.toString() << " ";
2480  for(i = 0; i < obsvec.size(); i++) // print the numbers of obss
2481  s << " " << setw(6) << obsvec[i];
2482  s << endl;
2483  it++;
2484  }
2485  }
2486  if(commentList.size())
2487  {
2488  if(!(valid & validComment)) s << " Comment list is NOT valid" << endl;
2489  s << "Comments (" << commentList.size() << ") :" << endl;
2490  for(i=0; i<commentList.size(); i++) s << commentList[i] << endl;
2491  }
2492 
2493  s << "-------------------------------- END OF HEADER "
2494  << "--------------------------------" << endl;
2495  } // end dump
2496 
2497 
2498  /* This method returns the numerical index of a given observation
2499  *
2500  * @param type String representing the observation type.
2501  */
2502  size_t Rinex3ObsHeader::getObsIndex( const std::string& type ) const
2503  {
2504  string newType(type);
2505 
2506  // 'old-style' type: Let's change it to 'new style'.
2507  if( newType.size() == 2 )
2508  {
2509  if( newType == "C1" ) newType = "C1C";
2510  else if( newType == "P1" ) newType = "C1P";
2511  else if( newType == "L1" ) newType = "L1P";
2512  else if( newType == "D1" ) newType = "D1P";
2513  else if( newType == "S1" ) newType = "S1P";
2514  else if( newType == "C2" ) newType = "C2C";
2515  else if( newType == "P2" ) newType = "C2P";
2516  else if( newType == "L2" ) newType = "L2P";
2517  else if( newType == "D2" ) newType = "D2P";
2518  else if( newType == "S2" ) newType = "S2P";
2519  else
2520  {
2521  InvalidRequest exc("Invalid type.");
2522  GNSSTK_THROW(exc);
2523  }
2524  }
2525 
2526  // Add GNSS code. By default the system is GPS
2527  if( newType.size() == 3 )
2528  {
2529  newType = "G" + newType;
2530  }
2531 
2532  // Check if resulting 'newType' is valid
2533  if( !isValidRinexObsID(newType) )
2534  {
2535  InvalidRequest ir(newType + " is not a valid RinexObsID!.");
2536  GNSSTK_THROW(ir);
2537  }
2538 
2539  // Extract the GNSS from the newType
2540  string sys( newType, 0, 1 );
2541  return getObsIndex(sys, RinexObsID(newType, version));
2542  }
2543 
2544 
2545  size_t Rinex3ObsHeader::getObsIndex(const std::string& sys,
2546  const RinexObsID& obsID ) const
2547  {
2551 
2552  // find the GNSS in the map
2553  RinexObsMap remapped;
2554  std::map<std::string,unsigned> obsCount;
2555  remapObsTypes(remapped, obsCount);
2556  RinexObsMap::const_iterator it = remapped.find(sys);
2557 
2558  if (it == remapped.end())
2559  {
2560  InvalidRequest ir("GNSS system " + sys + " not stored.");
2561  GNSSTK_THROW(ir);
2562  }
2563 
2564  const RinexObsVec& rov = it->second;
2565  for (size_t i=0; i<rov.size(); i++)
2566  {
2567  if (rov[i].equalIndex(obsID))
2568  return i;
2569  }
2570 
2571  InvalidRequest ir(obsID.asString(version) + " is not stored in system " + sys + ".");
2572  GNSSTK_THROW(ir);
2573  return 0;
2574  }
2575 
2576 
2578  std::vector<std::string>& diffs,
2579  const std::vector<std::string>& inclExclList,
2580  bool incl)
2581  {
2582  // map header token to comparison result
2583  std::map<std::string,bool> lineMap;
2584  std::map<std::string,bool>::const_iterator lmi;
2585  // Put the comments in a sorted set, we don't really care
2586  // about the ordering.
2587  std::set<std::string>
2588  lcomments(commentList.begin(), commentList.end()),
2589  rcomments(right.commentList.begin(), right.commentList.end());
2590  std::set<RinexObsID>
2591  lobs(obsTypeList.begin(), obsTypeList.end()),
2592  robs(right.obsTypeList.begin(), right.obsTypeList.end());
2593  // Compare everything first...
2594  // deliberately ignoring valid flags
2595 
2596  // only comparing first character of file type because that's
2597  // all that matters according to RINEX
2598  lineMap[hsVersion] =
2599  ((version == right.version) &&
2600  (fileType[0] == right.fileType[0]) &&
2601  (fileSysSat.system == right.fileSysSat.system));
2602  lineMap[hsRunBy] =
2603  ((fileProgram == right.fileProgram) &&
2604  (fileAgency == right.fileAgency) &&
2605  (date == right.date));
2606  lineMap[hsComment] = (lcomments == rcomments);
2607  lineMap[hsMarkerName] = (markerName == right.markerName);
2608  lineMap[hsMarkerNumber] = (markerNumber == right.markerNumber);
2609  lineMap[hsMarkerType] = (markerType == right.markerType);
2610  lineMap[hsObserver] =
2611  ((observer == right.observer) &&
2612  (agency == right.agency));
2613  lineMap[hsReceiver] =
2614  ((recNo == right.recNo) &&
2615  (recType == right.recType) &&
2616  (recVers == right.recVers));
2617  lineMap[hsAntennaType] =
2618  ((antNo == right.antNo) &&
2619  (antType == right.antType));
2620  lineMap[hsAntennaPosition] =
2621  (antennaPosition == right.antennaPosition);
2622  lineMap[hsAntennaDeltaHEN] =
2623  (antennaDeltaHEN == right.antennaDeltaHEN);
2624  lineMap[hsAntennaDeltaXYZ] =
2625  (antennaDeltaXYZ == right.antennaDeltaXYZ);
2626  lineMap[hsAntennaPhaseCtr] =
2627  (antennaPhaseCtr == right.antennaPhaseCtr);
2628  lineMap[hsAntennaBsightXYZ] =
2630  lineMap[hsAntennaZeroDirAzi] =
2632  lineMap[hsAntennaZeroDirXYZ] =
2634  lineMap[hsCenterOfMass] = (centerOfMass == right.centerOfMass);
2635  lineMap[hsNumObs] = (lobs == robs);
2636  lineMap[hsSystemNumObs] = true;
2637  lineMap[hsWaveFact] =
2638  (memcmp(wavelengthFactor, right.wavelengthFactor,
2639  sizeof(wavelengthFactor)) == 0);
2640  lineMap[hsSigStrengthUnit] =
2641  (sigStrengthUnit == right.sigStrengthUnit);
2642  lineMap[hsInterval] = (interval == right.interval);
2643  lineMap[hsFirstTime] = (firstObs == right.firstObs);
2644  lineMap[hsLastTime] = (lastObs == right.lastObs);
2645  lineMap[hsReceiverOffset] = (receiverOffset == right.receiverOffset);
2646  lineMap[hsSystemDCBSapplied] = true;
2647  lineMap[hsSystemPCVSapplied] = true;
2648  lineMap[hsSystemScaleFac] = true;
2649  lineMap[hsSystemPhaseShift] = true;
2650  lineMap[hsGlonassSlotFreqNo] = true;
2651  lineMap[hsGlonassCodPhsBias] = true;
2652  lineMap[hsLeapSeconds] = (leapSeconds == right.leapSeconds);
2653  lineMap[hsNumSats] = (numSVs == right.numSVs);
2654  lineMap[hsPrnObs] = true;
2655  // ...then filter by inclExclList later
2656  if (incl)
2657  {
2658  std::map<std::string,bool> oldLineMap(lineMap);
2659  std::map<std::string,bool>::const_iterator olmi;
2660  lineMap.clear();
2661  for (unsigned i = 0; i < inclExclList.size(); i++)
2662  {
2663  if ((olmi = oldLineMap.find(inclExclList[i])) != oldLineMap.end())
2664  {
2665  lineMap[olmi->first] = olmi->second;
2666  }
2667  }
2668  }
2669  else
2670  {
2671  // exclude, remove items in inclExclList
2672  for (unsigned i = 0; i < inclExclList.size(); i++)
2673  {
2674  lineMap.erase(inclExclList[i]);
2675  }
2676  }
2677  // check the equality of the final remaining set of header lines
2678  bool rv = true;
2679  for (lmi = lineMap.begin(); lmi != lineMap.end(); lmi++)
2680  {
2681  if (!lmi->second)
2682  {
2683  diffs.push_back(lmi->first);
2684  rv = false;
2685  }
2686  }
2687  return rv;
2688  } // bool Rinex3ObsHeader::compare
2689 
2690 
2693  {
2694  if (version < 3.00) return allValid2;
2695  else if(version < 3.01) return allValid30;
2696  else if(version < 3.02) return allValid301;
2697  else if(version < 3.03) return allValid302;
2698  else if(version < 3.04) return allValid303;
2699  else if(version < 3.05) return allValid303;
2700  else if(version < 3.06) return allValid303;
2701  return Fields();
2702  }
2703 
2704 
2707  {
2708  FieldSet results;
2709  set_intersection(fieldsSet.begin(), fieldsSet.end(),
2710  rhs.fieldsSet.begin(), rhs.fieldsSet.end(),
2711  inserter(results, results.begin()));
2712  return Rinex3ObsHeader::Fields(results);
2713  }
2714 
2717  {
2718  FieldSet results;
2719  set_union(fieldsSet.begin(), fieldsSet.end(),
2720  rhs.fieldsSet.begin(), rhs.fieldsSet.end(),
2721  inserter(results, results.begin()));
2722  return Rinex3ObsHeader::Fields(results);
2723  }
2724 
2725 
2728  {
2729  if (fieldsSet.count(rhs))
2730  return rhs;
2731  return validInvalid;
2732  }
2733 
2734 
2736  isValid(const Rinex3ObsHeader::Fields& present) const
2737  {
2738  FieldSet results;
2739  set_difference(fieldsSet.begin(), fieldsSet.end(),
2740  present.fieldsSet.begin(), present.fieldsSet.end(),
2741  inserter(results, results.begin()));
2742  return results.empty();
2743  }
2744 
2745 
2748  Exception& exc)
2749  {
2750  for (const auto& f : fieldsSet)
2751  {
2752  if (!valid.isSet(f))
2753  {
2754  exc.addText("Missing required header field: " + asString(f));
2755  }
2756  }
2757  }
2758 
2759 
2760  std::string Rinex3ObsHeader ::
2762  {
2763  switch (b)
2764  {
2765  case validVersion: return hsVersion;
2766  case validRunBy: return hsRunBy;
2767  case validComment: return hsComment;
2768  case validMarkerName: return hsMarkerName;
2769  case validMarkerNumber: return hsMarkerNumber;
2770  case validMarkerType: return hsMarkerType;
2771  case validObserver: return hsObserver;
2772  case validReceiver: return hsReceiver;
2773  case validAntennaType: return hsAntennaType;
2781  case validCenterOfMass: return hsCenterOfMass;
2782  case validNumObs: return hsNumObs;
2783  case validSystemNumObs: return hsSystemNumObs;
2784  case validWaveFact: return hsWaveFact;
2786  case validInterval: return hsInterval;
2787  case validFirstTime: return hsFirstTime;
2788  case validLastTime: return hsLastTime;
2796  case validLeapSeconds: return hsLeapSeconds;
2797  case validNumSats: return hsNumSats;
2798  case validPrnObs: return hsPrnObs;
2799  default: return "???";
2800  }
2801  }
2802 
2803 
2805  asField(const std::string& s)
2806  {
2807  if (s == hsVersion) return validVersion;
2808  if (s == hsRunBy) return validRunBy;
2809  if (s == hsComment) return validComment;
2810  if (s == hsMarkerName) return validMarkerName;
2811  if (s == hsMarkerNumber) return validMarkerNumber;
2812  if (s == hsMarkerType) return validMarkerType;
2813  if (s == hsObserver) return validObserver;
2814  if (s == hsReceiver) return validReceiver;
2815  if (s == hsAntennaType) return validAntennaType;
2816  if (s == hsAntennaPosition) return validAntennaPosition;
2817  if (s == hsAntennaDeltaHEN) return validAntennaDeltaHEN;
2818  if (s == hsAntennaDeltaXYZ) return validAntennaDeltaXYZ;
2819  if (s == hsAntennaPhaseCtr) return validAntennaPhaseCtr;
2820  if (s == hsAntennaBsightXYZ) return validAntennaBsightXYZ;
2823  if (s == hsCenterOfMass) return validCenterOfMass;
2824  if (s == hsNumObs) return validNumObs;
2825  if (s == hsSystemNumObs) return validSystemNumObs;
2826  if (s == hsWaveFact) return validWaveFact;
2827  if (s == hsSigStrengthUnit) return validSigStrengthUnit;
2828  if (s == hsInterval) return validInterval;
2829  if (s == hsFirstTime) return validFirstTime;
2830  if (s == hsLastTime) return validLastTime;
2831  if (s == hsReceiverOffset) return validReceiverOffset;
2834  if (s == hsSystemScaleFac) return validSystemScaleFac;
2835  if (s == hsSystemPhaseShift) return validSystemPhaseShift;
2838  if (s == hsLeapSeconds) return validLeapSeconds;
2839  if (s == hsNumSats) return validNumSats;
2840  if (s == hsPrnObs) return validPrnObs;
2841  return validInvalid;
2842  }
2843 
2844  std::ostream& operator<<(std::ostream& s, const Rinex3ObsHeader::Fields& v)
2845  {
2846  Rinex3ObsHeader::FieldSet::const_iterator i;
2847  for (i = v.fieldsSet.begin(); i != v.fieldsSet.end(); i++)
2848  {
2849  if (i != v.fieldsSet.begin())
2850  s << ",";
2851  s << *i;
2852  }
2853  return s;
2854  }
2855 
2856 
2857  void Rinex3ObsHeader ::
2858  remapObsTypes(RinexObsMap& remapped, map<string,unsigned>& obsCount)
2859  const
2860  {
2861  for (const auto& mapIter : mapObsTypes)
2862  {
2863  // I and X pseudo-observables are special cases, and can
2864  // only be listed once (or once per band in the case of
2865  // the ionospheric delay) in any sane manner.
2866  bool addedChannel = false;
2867  std::set<CarrierBand> addedIono;
2868  for(size_t i = 0; i < mapIter.second.size(); i++)
2869  {
2870  if (mapIter.second[i].type == ObservationType::Iono)
2871  {
2872  if (addedIono.count(mapIter.second[i].band) > 0)
2873  continue; // only write this pseudo-obs once
2874  addedIono.insert(mapIter.second[i].band);
2875  }
2876  else if (mapIter.second[i].type == ObservationType::Channel)
2877  {
2878  if (addedChannel)
2879  continue; // only write this pseudo-obs once
2880  addedChannel = true;
2881  }
2882  remapped[mapIter.first].push_back(mapIter.second[i]);
2883  obsCount[mapIter.first]++;
2884  }
2885  }
2886  }
2887 
2888 } // namespace gnsstk
gnsstk::Rinex3ObsHeader::validAntennaZeroDirXYZ
@ validAntennaZeroDirXYZ
ANTENNA: ZERODIR XYZ.
Definition: Rinex3ObsHeader.hpp:265
gnsstk::Rinex3ObsHeader::validSystemNumObs
@ validSystemNumObs
SYS / # / OBS TYPES.
Definition: Rinex3ObsHeader.hpp:268
gnsstk::Rinex3ObsHeader::commentList
StringVec commentList
comments in header
Definition: Rinex3ObsHeader.hpp:498
gnsstk::Rinex3ObsHeader::Fields::fieldsSet
FieldSet fieldsSet
All the header fields set in this object.
Definition: Rinex3ObsHeader.hpp:460
gnsstk::Rinex3ObsHeader::hsSigStrengthUnit
static const GNSSTK_EXPORT std::string hsSigStrengthUnit
SIGNAL STRENGTH UNIT.
Definition: Rinex3ObsHeader.hpp:209
gnsstk::StringUtils::asInt
long asInt(const std::string &s)
Definition: StringUtils.hpp:713
gnsstk::Rinex3ObsHeader::Fields::empty
bool empty() const
Return true if fieldsSet is empty, false otherwise.
Definition: Rinex3ObsHeader.hpp:399
gnsstk::Rinex3ObsHeader::numberHeaderRecordsToBeWritten
int numberHeaderRecordsToBeWritten(void) const noexcept
Definition: Rinex3ObsHeader.cpp:293
gnsstk::Rinex3ObsHeader::hsLeapSeconds
static const GNSSTK_EXPORT std::string hsLeapSeconds
LEAP SECONDS.
Definition: Rinex3ObsHeader.hpp:231
gnsstk::Rinex3ObsHeader::allValid301
static const GNSSTK_EXPORT Fields allValid301
Definition: Rinex3ObsHeader.hpp:464
gnsstk::Rinex3ObsHeader::validAntennaDeltaHEN
@ validAntennaDeltaHEN
ANTENNA: DELTA H/E/N.
Definition: Rinex3ObsHeader.hpp:260
gnsstk::RinexObsID::asString
std::string asString() const
Definition: RinexObsID.hpp:190
gnsstk::Rinex3ObsHeader::hsSystemNumObs
static const GNSSTK_EXPORT std::string hsSystemNumObs
SYS / # / OBS TYPES.
Definition: Rinex3ObsHeader.hpp:205
gnsstk::TimeTag::setTimeSystem
void setTimeSystem(const TimeSystem &timeSys)
Set method for internal variable timeSystem (enum).
Definition: TimeTag.hpp:165
gnsstk::Rinex3ObsHeader::fileAgency
std::string fileAgency
who ran program
Definition: Rinex3ObsHeader.hpp:492
gnsstk::Rinex3ObsHeader::validNumSats
@ validNumSats
Definition: Rinex3ObsHeader.hpp:282
gnsstk::Rinex3ObsHeader::fileSysSat
SatID fileSysSat
fileSys as a SatID
Definition: Rinex3ObsHeader.hpp:490
gnsstk::Rinex3ObsHeader::obsTypeList
RinexObsVec obsTypeList
Definition: Rinex3ObsHeader.hpp:541
gnsstk::SatID::id
int id
Satellite identifier, e.g. PRN.
Definition: SatID.hpp:154
gnsstk::Rinex3ObsHeader::hsRunBy
static const GNSSTK_EXPORT std::string hsRunBy
PGM / RUN BY / DATE.
Definition: Rinex3ObsHeader.hpp:171
example6.day
day
Definition: example6.py:66
gnsstk::Rinex3ObsHeader::validRunBy
@ validRunBy
PGM / RUN BY / DATE.
Definition: Rinex3ObsHeader.hpp:251
gnsstk::RinexSatID::fromString
void fromString(const std::string &s)
Definition: RinexSatID.cpp:122
gnsstk::Rinex3ObsHeader::validSigStrengthUnit
@ validSigStrengthUnit
SIGNAL STRENGTH UNIT.
Definition: Rinex3ObsHeader.hpp:270
gnsstk::CivilTime::year
int year
Definition: CivilTime.hpp:198
gnsstk::Rinex3ObsHeader::Fields::operator|
Fields operator|(const Fields &rhs) const
Definition: Rinex3ObsHeader.cpp:2716
gnsstk::Rinex3ObsHeader::parseTime
CivilTime parseTime(const std::string &line) const
Definition: Rinex3ObsHeader.cpp:2102
gnsstk::Rinex3ObsHeader::validLastTime
@ validLastTime
TIME OF LAST OBS.
Definition: Rinex3ObsHeader.hpp:273
gnsstk::Rinex3ObsHeader::leapSeconds
int leapSeconds
LEAP SECONDS.
Definition: Rinex3ObsHeader.hpp:533
gnsstk::FFStream
Definition: FFStream.hpp:119
gnsstk::Rinex3ObsHeader::hsMarkerType
static const GNSSTK_EXPORT std::string hsMarkerType
MARKER TYPE.
Definition: Rinex3ObsHeader.hpp:179
gnsstk::Rinex3ObsHeader::PisY
bool PisY
Map P to Y code observations in RINEX 2 files.
Definition: Rinex3ObsHeader.hpp:548
gnsstk::Rinex3ObsHeader::validInvalid
@ validInvalid
Not a valid field.
Definition: Rinex3ObsHeader.hpp:248
gnsstk::Rinex3ObsHeader::ScaleFacMap
std::map< RinexObsID, int > ScaleFacMap
Definition: Rinex3ObsHeader.hpp:332
gnsstk::Rinex3ObsHeader::ExtraWaveFact::wavelengthFactor
short wavelengthFactor[2]
vector of wavelength factor values
Definition: Rinex3ObsHeader.hpp:304
gnsstk::isValidRinexObsID
bool isValidRinexObsID(const std::string &strID)
Definition: RinexObsID.cpp:223
StringUtils.hpp
gnsstk::Rinex3ObsHeader::reallyGetRecord
virtual void reallyGetRecord(FFStream &s)
Definition: Rinex3ObsHeader.cpp:1596
gnsstk::RinexSatID::systemString
std::string systemString() const noexcept
Definition: RinexSatID.cpp:82
gnsstk::Rinex3ObsHeader::numSVs
short numSVs
Definition: Rinex3ObsHeader.hpp:534
example6.year
year
Definition: example6.py:64
gnsstk::Rinex3ObsHeader::Fields::Fields
Fields()=default
Only implicit constructors to do.
gnsstk::Rinex3ObsHeader::Fields::set
Fields & set(Field f)
Set a specific field.
Definition: Rinex3ObsHeader.hpp:387
gnsstk::Rinex3ObsHeader::antennaDeltaXYZ
gnsstk::Triple antennaDeltaXYZ
ANTENNA: DELTA X/Y/Z.
Definition: Rinex3ObsHeader.hpp:511
gnsstk::RinexSatID::systemString3
std::string systemString3() const noexcept
Definition: RinexSatID.cpp:102
gnsstk::Rinex3ObsHeader::validAntennaZeroDirAzi
@ validAntennaZeroDirAzi
ANTENNA: ZERODIR AZI.
Definition: Rinex3ObsHeader.hpp:264
gnsstk::Rinex3ObsHeader::preserveDate
bool preserveDate
Definition: Rinex3ObsHeader.hpp:497
gnsstk::ObservationType::Phase
@ Phase
accumulated phase, in cycles
gnsstk::Rinex3ObsHeader::valid
Fields valid
bits set when header rec.s present & valid
Definition: Rinex3ObsHeader.hpp:544
gnsstk::Rinex3ObsHeader
Definition: Rinex3ObsHeader.hpp:155
gnsstk::Rinex3ObsHeader::factor
int factor
Scale factor holding data for continuation lines.
Definition: Rinex3ObsHeader.hpp:726
gnsstk::FFTextStream::formattedGetLine
void formattedGetLine(std::string &line, const bool expectEOF=false)
Definition: FFTextStream.cpp:149
gnsstk::Rinex3ObsStream::headerRead
bool headerRead
Whether or not the Rinex3ObsHeader has been read.
Definition: Rinex3ObsStream.hpp:107
gnsstk::Rinex3ObsHeader::validReceiver
@ validReceiver
REC # / TYPE / VERS.
Definition: Rinex3ObsHeader.hpp:257
gnsstk::Rinex3ObsHeader::hsInterval
static const GNSSTK_EXPORT std::string hsInterval
INTERVAL.
Definition: Rinex3ObsHeader.hpp:211
gnsstk::Rinex3ObsHeader::validReceiverOffset
@ validReceiverOffset
RCV CLOCK OFFS APPL.
Definition: Rinex3ObsHeader.hpp:274
gnsstk::Rinex3ObsHeader::sysPhaseShiftObsID
RinexObsID sysPhaseShiftObsID
save ObsID for cont. "PHASE SHIFT" R3.01
Definition: Rinex3ObsHeader.hpp:714
gnsstk::Rinex3ObsHeader::Field
Field
Definition: Rinex3ObsHeader.hpp:246
gnsstk::Rinex3ObsHeader::writeHeaderRecords
void writeHeaderRecords(FFStream &s) const
Definition: Rinex3ObsHeader.cpp:345
gnsstk::Rinex3ObsHeader::getObsIndex
virtual std::size_t getObsIndex(const std::string &type) const
Definition: Rinex3ObsHeader.cpp:2502
gnsstk::Rinex3ObsHeader::hsGlonassCodPhsBias
static const GNSSTK_EXPORT std::string hsGlonassCodPhsBias
GLONASS COD/PHS/BIS.
Definition: Rinex3ObsHeader.hpp:229
gnsstk::Rinex3ObsHeader::glonassFreqNo
GLOFreqNumMap glonassFreqNo
GLONASS SLOT / FRQ #.
Definition: Rinex3ObsHeader.hpp:531
gnsstk::Exception::what
std::string what() const
Dump to a string.
Definition: Exception.cpp:193
gnsstk::Rinex3ObsHeader::hsMarkerNumber
static const GNSSTK_EXPORT std::string hsMarkerNumber
MARKER NUMBER.
Definition: Rinex3ObsHeader.hpp:177
gnsstk::Rinex3ObsHeader::hsSystemPCVSapplied
static const GNSSTK_EXPORT std::string hsSystemPCVSapplied
SYS / PCVS APPLIED.
Definition: Rinex3ObsHeader.hpp:221
gnsstk::FFTextStream::lineNumber
unsigned int lineNumber
Definition: FFTextStream.hpp:98
gnsstk::Rinex3ObsHeader::fileSys
std::string fileSys
file sys char: RinexSatID system OR Mixed
Definition: Rinex3ObsHeader.hpp:484
gnsstk::Rinex3ObsHeader::asString
static std::string asString(Field b)
Return the RINEX header label for the given field enumeration.
Definition: Rinex3ObsHeader.cpp:2761
gnsstk::Rinex3ObsHeader::hsPrnObs
static const GNSSTK_EXPORT std::string hsPrnObs
PRN / # OF OBS.
Definition: Rinex3ObsHeader.hpp:235
gnsstk::Rinex3ObsHeader::validGlonassSlotFreqNo
@ validGlonassSlotFreqNo
GLONASS SLOT / FRQ #.
Definition: Rinex3ObsHeader.hpp:279
example6.hour
hour
Definition: example6.py:67
gnsstk::SatID
Definition: SatID.hpp:89
gnsstk::Rinex3ObsHeader::Fields::clear
Fields & clear(Field f)
Clear a specific field.
Definition: Rinex3ObsHeader.hpp:390
gnsstk::TimeSystem::Any
@ Any
wildcard; allows comparison with any other type
gnsstk::ObservationType::Channel
@ Channel
Channel number.
gnsstk::Rinex3ObsHeader::hsAntennaDeltaHEN
static const GNSSTK_EXPORT std::string hsAntennaDeltaHEN
ANTENNA: DELTA H/E/N.
Definition: Rinex3ObsHeader.hpp:189
gnsstk::FFData::operator<<
friend std::ostream & operator<<(FFStream &o, const FFData &f)
Definition: FFData.cpp:59
gnsstk::StringUtils::asString
std::string asString(IonexStoreStrategy e)
Convert a IonexStoreStrategy to a whitespace-free string name.
Definition: IonexStoreStrategy.cpp:46
gnsstk::Rinex3ObsHeader::hsObserver
static const GNSSTK_EXPORT std::string hsObserver
OBSERVER / AGENCY.
Definition: Rinex3ObsHeader.hpp:181
gnsstk::CivilTime::day
int day
Definition: CivilTime.hpp:200
gnsstk::Rinex3ObsHeader::validSystemDCBSapplied
@ validSystemDCBSapplied
SYSTEM DCBS APPLIED.
Definition: Rinex3ObsHeader.hpp:275
gnsstk::Rinex3ObsHeader::hsSystemScaleFac
static const GNSSTK_EXPORT std::string hsSystemScaleFac
SYS / SCALE FACTOR.
Definition: Rinex3ObsHeader.hpp:223
gnsstk::Rinex3ObsHeader::allValid2
static const GNSSTK_EXPORT Fields allValid2
Definition: Rinex3ObsHeader.hpp:464
gnsstk::Rinex3ObsHeader::FieldSet
std::set< Field > FieldSet
Definition: Rinex3ObsHeader.hpp:363
gnsstk::Rinex3ObsHeader::mapR2ObsToR3Obs_S
std::vector< RinexObsID > mapR2ObsToR3Obs_S()
Definition: Rinex3ObsHeader.cpp:2061
gnsstk::Rinex3ObsBase::currentVersion
static const GNSSTK_EXPORT double currentVersion
Definition: Rinex3ObsBase.hpp:72
gnsstk::Rinex3ObsHeader::Fields::describeMissing
void describeMissing(const Fields &valid, Exception &exc)
Definition: Rinex3ObsHeader.cpp:2747
gnsstk::Rinex3ObsHeader::sigStrengthUnit
std::string sigStrengthUnit
SIGNAL STRENGTH UNIT.
Definition: Rinex3ObsHeader.hpp:522
gnsstk::Rinex3ObsHeader::validAntennaPosition
@ validAntennaPosition
APPROX POSITION XYZ.
Definition: Rinex3ObsHeader.hpp:259
gnsstk::Rinex3ObsHeader::dump
virtual void dump(std::ostream &s) const
Definition: Rinex3ObsHeader.hpp:568
gnsstk::Rinex3ObsHeader::hsAntennaZeroDirXYZ
static const GNSSTK_EXPORT std::string hsAntennaZeroDirXYZ
ANTENNA: ZERODIR XYZ.
Definition: Rinex3ObsHeader.hpp:199
gnsstk::Rinex3ObsHeader::validGlonassCodPhsBias
@ validGlonassCodPhsBias
GLONASS COD/PHS/BIS.
Definition: Rinex3ObsHeader.hpp:280
gnsstk::Rinex3ObsHeader::xmitAnt
XmitAnt xmitAnt
Non-standard, transmitter ID.
Definition: Rinex3ObsHeader.hpp:537
gnsstk::XmitAnt::Standard
@ Standard
Transmitting antenna is the primary for that signal.
gnsstk::Rinex3ObsHeader::numObsForSat
PRNNumObsMap numObsForSat
PRN / # OF OBS.
Definition: Rinex3ObsHeader.hpp:535
gnsstk::Rinex3ObsHeader::validAntennaType
@ validAntennaType
ANT # / TYPE.
Definition: Rinex3ObsHeader.hpp:258
gnsstk::Triple
Definition: Triple.hpp:68
gnsstk::Rinex3ObsHeader::hsReceiver
static const GNSSTK_EXPORT std::string hsReceiver
REC # / TYPE / VERS.
Definition: Rinex3ObsHeader.hpp:183
gnsstk::Rinex3ObsHeader::prepareVer2Write
void prepareVer2Write(void)
Definition: Rinex3ObsHeader.cpp:2141
gnsstk::TimeSystem::Unknown
@ Unknown
unknown time frame; for legacy code compatibility
gnsstk
For Sinex::InputHistory.
Definition: BasicFramework.cpp:50
gnsstk::Rinex3ObsHeader::antennaSatSys
std::string antennaSatSys
ANTENNA P.CTR BLOCK: SAT SYS.
Definition: Rinex3ObsHeader.hpp:512
gnsstk::Rinex3ObsHeader::validNumObs
@ validNumObs
Definition: Rinex3ObsHeader.hpp:267
gnsstk::Rinex3ObsHeader::hsMarkerName
static const GNSSTK_EXPORT std::string hsMarkerName
MARKER NAME.
Definition: Rinex3ObsHeader.hpp:175
gnsstk::Rinex3ObsHeader::antNo
std::string antNo
antenna number
Definition: Rinex3ObsHeader.hpp:507
gnsstk::Rinex3ObsHeader::receiverOffset
int receiverOffset
RCV CLOCK OFFS APPL.
Definition: Rinex3ObsHeader.hpp:526
gnsstk::Rinex3ObsHeader::interval
double interval
INTERVAL.
Definition: Rinex3ObsHeader.hpp:523
gnsstk::Rinex3ObsHeader::mapObsTypes
RinexObsMap mapObsTypes
SYS / # / OBS TYPES.
Definition: Rinex3ObsHeader.hpp:519
gnsstk::Rinex3ObsHeader::antennaObsCode
std::string antennaObsCode
ANTENNA P.CTR BLOCK: OBS CODE.
Definition: Rinex3ObsHeader.hpp:513
gnsstk::Exception
Definition: Exception.hpp:151
gnsstk::RinexObsID::validRinexTrackingCodes
static GNSSTK_EXPORT std::map< char, std::map< char, std::string > > validRinexTrackingCodes
Definition: RinexObsID.hpp:281
gnsstk::Rinex3ObsHeader::hsAntennaRegional
static const GNSSTK_EXPORT std::string hsAntennaRegional
Fixed comment xmit ant.
Definition: Rinex3ObsHeader.hpp:241
gnsstk::Rinex3ObsStream::header
Rinex3ObsHeader header
The header for this file.
Definition: Rinex3ObsStream.hpp:110
gnsstk::SatelliteSystem::GPS
@ GPS
gnsstk::StringUtils::stripTrailing
std::string & stripTrailing(std::string &s, const std::string &aString, std::string::size_type num=std::string::npos)
Definition: StringUtils.hpp:1453
gnsstk::Rinex3ObsHeader::satSysPrev
std::string satSysPrev
recall the prev sat. sys for continuation lines.
Definition: Rinex3ObsHeader.hpp:718
gnsstk::Rinex3ObsHeader::validAntennaDeltaXYZ
@ validAntennaDeltaXYZ
ANTENNA: DELTA X/Y/Z.
Definition: Rinex3ObsHeader.hpp:261
gnsstk::Rinex3ObsHeader::validCenterOfMass
@ validCenterOfMass
CENTER OF MASS: XYZ.
Definition: Rinex3ObsHeader.hpp:266
gnsstk::Rinex3ObsHeader::remapObsTypes
void remapObsTypes(RinexObsMap &remapped, std::map< std::string, unsigned > &obsCount) const
Definition: Rinex3ObsHeader.cpp:2858
gnsstk::Rinex3ObsHeader::wavelengthFactor
short wavelengthFactor[2]
WAVELENGTH FACT (system-wide)
Definition: Rinex3ObsHeader.hpp:520
example6.second
second
Definition: example6.py:69
gnsstk::Rinex3ObsHeader::validSystemPCVSapplied
@ validSystemPCVSapplied
SYSTEM PCVS APPLIED.
Definition: Rinex3ObsHeader.hpp:276
gnsstk::Rinex3ObsHeader::recNo
std::string recNo
receiver number
Definition: Rinex3ObsHeader.hpp:504
gnsstk::Rinex3ObsHeader::hsReceiverOffset
static const GNSSTK_EXPORT std::string hsReceiverOffset
RCV CLOCK OFFS APPL.
Definition: Rinex3ObsHeader.hpp:217
gnsstk::Rinex3ObsHeader::writeTime
std::string writeTime(const CivilTime &civtime) const
Definition: Rinex3ObsHeader.cpp:2123
gnsstk::Rinex3ObsHeader::validLeapSeconds
@ validLeapSeconds
LEAP SECONDS.
Definition: Rinex3ObsHeader.hpp:281
gnsstk::Rinex3ObsHeader::R2DisambiguityMap
DisAmbMap R2DisambiguityMap
Definition: Rinex3ObsHeader.hpp:478
gnsstk::StringUtils::asTimeSystem
TimeSystem asTimeSystem(const std::string &s)
Convert a string representation of TimeSystem to an enum.
Definition: TimeSystem.cpp:324
gnsstk::TimeSystem::QZS
@ QZS
QZSS system Time.
gnsstk::Rinex3ObsHeader::validAntennaBsightXYZ
@ validAntennaBsightXYZ
ANTENNA: B.SIGHT XYZ.
Definition: Rinex3ObsHeader.hpp:263
gnsstk::Rinex3ObsHeader::validFirstTime
@ validFirstTime
TIME OF FIRST OBS.
Definition: Rinex3ObsHeader.hpp:272
gnsstk::SatelliteSystem::Unknown
@ Unknown
debug
#define debug
Definition: Rinex3ClockHeader.cpp:51
gnsstk::TimeSystem::GAL
@ GAL
Galileo system time.
gnsstk::Rinex3ObsHeader::version
double version
RINEX 3 version/type.
Definition: Rinex3ObsHeader.hpp:481
SystemTime.hpp
gnsstk::Rinex3ObsHeader::hsAntennaDeltaXYZ
static const GNSSTK_EXPORT std::string hsAntennaDeltaXYZ
ANTENNA: DELTA X/Y/Z.
Definition: Rinex3ObsHeader.hpp:191
gnsstk::ObsID
Definition: ObsID.hpp:82
gnsstk::Rinex3ObsHeader::hsGlonassSlotFreqNo
static const GNSSTK_EXPORT std::string hsGlonassSlotFreqNo
GLONASS SLOT / FRQ #.
Definition: Rinex3ObsHeader.hpp:227
gnsstk::Rinex3ObsHeader::antennaZeroDirXYZ
gnsstk::Triple antennaZeroDirXYZ
ANTENNA ZERODIR XYZ.
Definition: Rinex3ObsHeader.hpp:517
gnsstk::Rinex3ObsHeader::validAntennaPhaseCtr
@ validAntennaPhaseCtr
ANTENNA: PHASECENTER.
Definition: Rinex3ObsHeader.hpp:262
example4.err
err
Definition: example4.py:126
gnsstk::Rinex3ObsHeader::validVersion
@ validVersion
RINEX VERSION / TYPE.
Definition: Rinex3ObsHeader.hpp:249
gnsstk::Rinex3ObsHeader::extraWaveFactList
FactorVector extraWaveFactList
WAVELENGTH FACT (per SV)
Definition: Rinex3ObsHeader.hpp:521
gnsstk::SystemTime
Definition: SystemTime.hpp:54
gnsstk::Rinex3ObsHeader::hsEoH
static const GNSSTK_EXPORT std::string hsEoH
END OF HEADER.
Definition: Rinex3ObsHeader.hpp:237
gnsstk::Rinex3ObsHeader::validInterval
@ validInterval
INTERVAL.
Definition: Rinex3ObsHeader.hpp:271
example6.validEoH
validEoH
Definition: example6.py:82
Rinex3ObsHeader.hpp
gnsstk::min
T min(const SparseMatrix< T > &SM)
Maximum element - return 0 if empty.
Definition: SparseMatrix.hpp:858
gnsstk::Rinex3ObsHeader::infoPCVS
CorrVec infoPCVS
PCVS INFO.
Definition: Rinex3ObsHeader.hpp:528
gnsstk::Rinex3ObsHeader::hsAntennaStandard
static const GNSSTK_EXPORT std::string hsAntennaStandard
Fixed comment xmit ant.
Definition: Rinex3ObsHeader.hpp:239
gnsstk::Rinex3ObsHeader::Fields::getRequired
static Fields getRequired(double version)
Definition: Rinex3ObsHeader.cpp:2692
gnsstk::Rinex3ObsHeader::markerName
std::string markerName
MARKER NAME.
Definition: Rinex3ObsHeader.hpp:499
gnsstk::Rinex3ObsHeader::validMarkerType
@ validMarkerType
MARKER TYPE.
Definition: Rinex3ObsHeader.hpp:255
gnsstk::TimeSystem
TimeSystem
Definition of various time systems.
Definition: TimeSystem.hpp:51
gnsstk::Rinex3ObsHeader::markerType
std::string markerType
MARKER TYPE.
Definition: Rinex3ObsHeader.hpp:501
gnsstk::Rinex3ObsHeader::hsAntennaPhaseCtr
static const GNSSTK_EXPORT std::string hsAntennaPhaseCtr
ANTENNA: PHASECENTER.
Definition: Rinex3ObsHeader.hpp:193
version
string version(string("2.4 9/23/15 rev"))
gnsstk::Rinex3ObsHeader::mapSysR2toR3ObsID
VersionObsMap mapSysR2toR3ObsID
Definition: Rinex3ObsHeader.hpp:475
example6.valid
valid
Definition: example6.py:20
gnsstk::Rinex3ObsHeader::RinexObsVec
std::vector< RinexObsID > RinexObsVec
Vector of obervables.
Definition: Rinex3ObsHeader.hpp:338
gnsstk::Rinex3ObsHeader::validSystemScaleFac
@ validSystemScaleFac
SYSTEM SCALE FACTOR.
Definition: Rinex3ObsHeader.hpp:277
gnsstk::RinexObsID
Definition: RinexObsID.hpp:102
gnsstk::Rinex3ObsHeader::Rinex3CorrInfo::source
std::string source
source of corrections (URL)
Definition: Rinex3ObsHeader.hpp:294
gnsstk::Rinex3ObsHeader::compare
bool compare(const Rinex3ObsHeader &right, StringVec &diffs, const StringVec &inclExclList, bool incl=false)
Definition: Rinex3ObsHeader.cpp:2577
gnsstk::StringUtils::asDouble
double asDouble(const std::string &s)
Definition: StringUtils.hpp:705
gnsstk::Rinex3ObsHeader::hsAntennaType
static const GNSSTK_EXPORT std::string hsAntennaType
ANT # / TYPE.
Definition: Rinex3ObsHeader.hpp:185
GNSSTK_RETHROW
#define GNSSTK_RETHROW(exc)
Definition: Exception.hpp:369
gnsstk::Rinex3ObsHeader::centerOfMass
gnsstk::Triple centerOfMass
vehicle CENTER OF MASS: XYZ
Definition: Rinex3ObsHeader.hpp:518
gnsstk::Rinex3ObsHeader::fileType
std::string fileType
Definition: Rinex3ObsHeader.hpp:482
gnsstk::SatID::system
SatelliteSystem system
System for this satellite.
Definition: SatID.hpp:156
gnsstk::Rinex3ObsHeader::validObserver
@ validObserver
OBSERVER / AGENCY.
Definition: Rinex3ObsHeader.hpp:256
gnsstk::CivilTime::minute
int minute
Definition: CivilTime.hpp:202
gnsstk::Rinex3ObsHeader::validSystemPhaseShift
@ validSystemPhaseShift
SYS / PHASE SHIFT.
Definition: Rinex3ObsHeader.hpp:278
gnsstk::Rinex3ObsHeader::R2ObsTypes
StringVec R2ObsTypes
Definition: Rinex3ObsHeader.hpp:471
gnsstk::TimeSystem::UTC
@ UTC
Coordinated Universal Time (e.g., from NTP)
gnsstk::Rinex3ObsHeader::infoDCBS
CorrVec infoDCBS
DCBS INFO.
Definition: Rinex3ObsHeader.hpp:527
gnsstk::Rinex3ObsHeader::antennaPhaseCtr
gnsstk::Triple antennaPhaseCtr
ANTENNA P.CTR BLOCK: PCTR POS.
Definition: Rinex3ObsHeader.hpp:514
gnsstk::Rinex3ObsHeader::Fields::isValid
bool isValid(const Fields &present) const
Definition: Rinex3ObsHeader.cpp:2736
gnsstk::Rinex3ObsStream
Definition: Rinex3ObsStream.hpp:65
gnsstk::Rinex3ObsHeader::recType
std::string recType
receiver type
Definition: Rinex3ObsHeader.hpp:505
gnsstk::Rinex3ObsHeader::observer
std::string observer
who collected the data
Definition: Rinex3ObsHeader.hpp:502
gnsstk::Rinex3ObsHeader::factorPrev
int factorPrev
Definition: Rinex3ObsHeader.hpp:726
gnsstk::Rinex3ObsHeader::antennaZeroDirAzi
double antennaZeroDirAzi
ANTENNA ZERODIR AZI.
Definition: Rinex3ObsHeader.hpp:516
gnsstk::CivilTime
Definition: CivilTime.hpp:55
gnsstk::Rinex3ObsHeader::hsFirstTime
static const GNSSTK_EXPORT std::string hsFirstTime
TIME OF FIRST OBS.
Definition: Rinex3ObsHeader.hpp:213
gnsstk::StringUtils
Definition: IonexStoreStrategy.cpp:44
gnsstk::Rinex3ObsHeader::preserveVerType
bool preserveVerType
Definition: Rinex3ObsHeader.hpp:489
gnsstk::Rinex3ObsHeader::Fields::isSet
bool isSet(Field f) const
Return true if the specific field is set (preferred to operator&).
Definition: Rinex3ObsHeader.hpp:393
Rinex3ObsStream.hpp
gnsstk::StringUtils::rightJustify
std::string & rightJustify(std::string &s, const std::string::size_type length, const char pad=' ')
Definition: StringUtils.hpp:1557
gnsstk::Rinex3ObsHeader::numObsPrev
int numObsPrev
recall the prev # obs for cont. lines
Definition: Rinex3ObsHeader.hpp:722
gnsstk::Rinex3ObsHeader::ExtraWaveFact
RINEX 2 extra "WAVELENGTH FACT" lines.
Definition: Rinex3ObsHeader.hpp:298
gnsstk::Rinex3ObsHeader::lastObs
CivilTime lastObs
TIME OF LAST OBS.
Definition: Rinex3ObsHeader.hpp:525
gnsstk::Rinex3ObsHeader::validMarkerNumber
@ validMarkerNumber
MARKER NUMBER.
Definition: Rinex3ObsHeader.hpp:254
gnsstk::Rinex3ObsHeader::agency
std::string agency
observer's agency
Definition: Rinex3ObsHeader.hpp:503
gnsstk::Rinex3ObsHeader::fileProgram
std::string fileProgram
program used to generate file
Definition: Rinex3ObsHeader.hpp:491
gnsstk::RinexSatID::toString
std::string toString() const noexcept
Definition: RinexSatID.cpp:204
gnsstk::printTime
std::string printTime(const CommonTime &t, const std::string &fmt)
Definition: TimeString.cpp:64
gnsstk::Rinex3ObsHeader::antType
std::string antType
antenna type
Definition: Rinex3ObsHeader.hpp:508
gnsstk::RinexSatID
Definition: RinexSatID.hpp:63
gnsstk::TimeSystem::GPS
@ GPS
GPS system time.
gnsstk::Rinex3ObsHeader::hsSystemDCBSapplied
static const GNSSTK_EXPORT std::string hsSystemDCBSapplied
SYS / DCBS APPLIED.
Definition: Rinex3ObsHeader.hpp:219
std
Definition: Angle.hpp:142
gnsstk::SatelliteSystem::Mixed
@ Mixed
gnsstk::CivilTime::month
int month
Definition: CivilTime.hpp:199
gnsstk::Rinex3ObsHeader::recVers
std::string recVers
receiver version
Definition: Rinex3ObsHeader.hpp:506
gnsstk::Rinex3ObsHeader::satSysTemp
std::string satSysTemp
save the syschar while reading ScaleFactor
Definition: Rinex3ObsHeader.hpp:716
gnsstk::Rinex3ObsHeader::sysPhaseShift
SysPhsShftMap sysPhaseShift
SYS / PHASE SHIFT.
Definition: Rinex3ObsHeader.hpp:530
gnsstk::Rinex3ObsHeader::clear
void clear()
Definition: Rinex3ObsHeader.cpp:180
gnsstk::Rinex3ObsHeader::date
std::string date
when program was run
Definition: Rinex3ObsHeader.hpp:493
gnsstk::Rinex3ObsHeader::hsAntennaBsightXYZ
static const GNSSTK_EXPORT std::string hsAntennaBsightXYZ
ANTENNA: B.SIGHT XYZ.
Definition: Rinex3ObsHeader.hpp:195
gnsstk::XmitAnt::Regional
@ Regional
Transmitting antenna is secondary, regional coverage.
gnsstk::Rinex3ObsHeader::mapR2ObsToR3Obs_E
std::vector< RinexObsID > mapR2ObsToR3Obs_E()
Definition: Rinex3ObsHeader.cpp:1999
gnsstk::Rinex3ObsHeader::glonassCodPhsBias
GLOCodPhsBias glonassCodPhsBias
GLONASS COD/PHS/BIS.
Definition: Rinex3ObsHeader.hpp:532
gnsstk::CivilTime::second
double second
Definition: CivilTime.hpp:203
gnsstk::StringUtils::strip
std::string & strip(std::string &s, const std::string &aString, std::string::size_type num=std::string::npos)
Definition: StringUtils.hpp:1482
gnsstk::Rinex3ObsHeader::reallyPutRecord
virtual void reallyPutRecord(FFStream &s) const
Definition: Rinex3ObsHeader.cpp:249
gnsstk::StringUtils::leftJustify
std::string & leftJustify(std::string &s, const std::string::size_type length, const char pad=' ')
Definition: StringUtils.hpp:1582
gnsstk::Rinex3ObsHeader::sysSfacMap
SysScaleFacMap sysSfacMap
SYS / SCALE FACTOR.
Definition: Rinex3ObsHeader.hpp:529
gnsstk::Exception::addText
Exception & addText(const std::string &errorText)
Definition: Exception.cpp:133
GNSSTK_THROW
#define GNSSTK_THROW(exc)
Definition: Exception.hpp:366
gnsstk::Rinex3ObsHeader::hsSystemPhaseShift
static const GNSSTK_EXPORT std::string hsSystemPhaseShift
SYS / PHASE SHIFT.
Definition: Rinex3ObsHeader.hpp:225
gnsstk::Rinex3ObsHeader::validPrnObs
@ validPrnObs
PRN / # OF OBS.
Definition: Rinex3ObsHeader.hpp:283
gnsstk::Rinex3ObsHeader::validEoH
bool validEoH
true if found END OF HEADER
Definition: Rinex3ObsHeader.hpp:546
gnsstk::Rinex3ObsHeader::hsCenterOfMass
static const GNSSTK_EXPORT std::string hsCenterOfMass
CENTER OF MASS: XYZ.
Definition: Rinex3ObsHeader.hpp:201
gnsstk::Rinex3ObsHeader::allValid303
static const GNSSTK_EXPORT Fields allValid303
Definition: Rinex3ObsHeader.hpp:465
gnsstk::Rinex3ObsHeader::hsNumSats
static const GNSSTK_EXPORT std::string hsNumSats
Definition: Rinex3ObsHeader.hpp:233
gnsstk::SatelliteSystem::Glonass
@ Glonass
gnsstk::Rinex3ObsHeader::hsLastTime
static const GNSSTK_EXPORT std::string hsLastTime
TIME OF LAST OBS.
Definition: Rinex3ObsHeader.hpp:215
gnsstk::Rinex3ObsHeader::antennaPosition
gnsstk::Triple antennaPosition
APPROX POSITION XYZ.
Definition: Rinex3ObsHeader.hpp:509
example6.month
month
Definition: example6.py:65
gnsstk::Rinex3ObsHeader::Fields::operator&
Fields operator&(const Fields &rhs) const
Definition: Rinex3ObsHeader.cpp:2706
gnsstk::SatelliteSystem::BeiDou
@ BeiDou
aka Compass
gnsstk::Rinex3ObsHeader::hsNumObs
static const GNSSTK_EXPORT std::string hsNumObs
Definition: Rinex3ObsHeader.hpp:203
gnsstk::ObservationType::Iono
@ Iono
Ionospheric delay.
gnsstk::Rinex3ObsHeader::Rinex3CorrInfo::name
std::string name
program name used to apply corrections
Definition: Rinex3ObsHeader.hpp:293
gnsstk::Rinex3ObsHeader::hsVersion
static const GNSSTK_EXPORT std::string hsVersion
RINEX VERSION / TYPE.
Definition: Rinex3ObsHeader.hpp:169
gnsstk::Rinex3ObsHeader::numObs
int numObs
save OBS # / TYPES and Sys / SCALE FACTOR for continuation lines.
Definition: Rinex3ObsHeader.hpp:720
gnsstk::Rinex3ObsHeader::lastPRN
RinexSatID lastPRN
save PRN while reading PRN/OBS cont. lines
Definition: Rinex3ObsHeader.hpp:724
gnsstk::Rinex3ObsHeader::Rinex3CorrInfo::satSys
std::string satSys
1-char SV system (G/R/E/S)
Definition: Rinex3ObsHeader.hpp:292
gnsstk::Rinex3ObsHeader::markerNumber
std::string markerNumber
MARKER NUMBER.
Definition: Rinex3ObsHeader.hpp:500
gnsstk::Rinex3ObsHeader::mapR2ObsToR3Obs_R
std::vector< RinexObsID > mapR2ObsToR3Obs_R()
Definition: Rinex3ObsHeader.cpp:1940
gnsstk::Rinex3ObsHeader::Fields
Definition: Rinex3ObsHeader.hpp:369
gnsstk::Rinex3ObsHeader::allValid302
static const GNSSTK_EXPORT Fields allValid302
Definition: Rinex3ObsHeader.hpp:464
gnsstk::Rinex3ObsHeader::validMarkerName
@ validMarkerName
MARKER NAME.
Definition: Rinex3ObsHeader.hpp:253
gnsstk::Rinex3ObsHeader::antennaDeltaHEN
gnsstk::Triple antennaDeltaHEN
ANTENNA: DELTA H/E/N.
Definition: Rinex3ObsHeader.hpp:510
gnsstk::Rinex3ObsHeader::hsAntennaPosition
static const GNSSTK_EXPORT std::string hsAntennaPosition
APPROX POSITION XYZ.
Definition: Rinex3ObsHeader.hpp:187
gnsstk::SatelliteSystem::QZSS
@ QZSS
gnsstk::Rinex3ObsHeader::RinexObsMap
std::map< std::string, RinexObsVec > RinexObsMap
Definition: Rinex3ObsHeader.hpp:342
gnsstk::TimeSystem::BDT
@ BDT
BeiDou system Time.
gnsstk::Rinex3ObsHeader::parseHeaderRecord
void parseHeaderRecord(std::string &line)
Definition: Rinex3ObsHeader.cpp:1066
gnsstk::TimeTag::getTimeSystem
TimeSystem getTimeSystem() const
Obtain time system info (enum).
Definition: TimeTag.hpp:169
gnsstk::Rinex3ObsHeader::hsAntennaZeroDirAzi
static const GNSSTK_EXPORT std::string hsAntennaZeroDirAzi
ANTENNA: ZERODIR AZI.
Definition: Rinex3ObsHeader.hpp:197
gnsstk::Rinex3ObsHeader::allValid30
static const GNSSTK_EXPORT Fields allValid30
Definition: Rinex3ObsHeader.hpp:464
gnsstk::Rinex3ObsHeader::antennaBsightXYZ
gnsstk::Triple antennaBsightXYZ
ANTENNA B.SIGHT XYZ.
Definition: Rinex3ObsHeader.hpp:515
gnsstk::Rinex3ObsHeader::validWaveFact
@ validWaveFact
WAVELENGTH FACT L1/2.
Definition: Rinex3ObsHeader.hpp:269
gnsstk::Rinex3ObsHeader::mapR2ObsToR3Obs_G
std::vector< RinexObsID > mapR2ObsToR3Obs_G()
Definition: Rinex3ObsHeader.cpp:1821
gnsstk::Rinex3ObsHeader::ExtraWaveFact::satList
std::vector< SatID > satList
List of Sats with this wavelength factor.
Definition: Rinex3ObsHeader.hpp:302
TimeString.hpp
gnsstk::Rinex3ObsHeader::hsWaveFact
static const GNSSTK_EXPORT std::string hsWaveFact
WAVELENGTH FACT L1/2.
Definition: Rinex3ObsHeader.hpp:207
gnsstk::Rinex3ObsHeader::validComment
@ validComment
COMMENT.
Definition: Rinex3ObsHeader.hpp:252
gnsstk::SatelliteSystem::Galileo
@ Galileo
gnsstk::Rinex3ObsStream::timesystem
TimeSystem timesystem
Time system for epochs in this file.
Definition: Rinex3ObsStream.hpp:113
gnsstk::Rinex3ObsHeader::Rinex3CorrInfo
Definition: Rinex3ObsHeader.hpp:289
gnsstk::RinexSatID::systemChar
char systemChar() const noexcept
Definition: RinexSatID.cpp:62
gnsstk::Rinex3ObsHeader::asField
static Field asField(const std::string &s)
Convert a RINEX header field label string into its matching enum.
Definition: Rinex3ObsHeader.cpp:2805
gnsstk::CivilTime::hour
int hour
Definition: CivilTime.hpp:201
gnsstk::Rinex3ObsHeader::hsComment
static const GNSSTK_EXPORT std::string hsComment
COMMENT.
Definition: Rinex3ObsHeader.hpp:173
gnsstk::Rinex3ObsHeader::firstObs
CivilTime firstObs
TIME OF FIRST OBS.
Definition: Rinex3ObsHeader.hpp:524


gnsstk
Author(s):
autogenerated on Wed Oct 25 2023 02:40:41