source: ntrip/trunk/BNC/src/rinex/rnxobsfile.cpp@ 6223

Last change on this file since 6223 was 6223, checked in by mervart, 10 years ago
File size: 31.2 KB
Line 
1// Part of BNC, a utility for retrieving decoding and
2// converting GNSS data streams from NTRIP broadcasters.
3//
4// Copyright (C) 2007
5// German Federal Agency for Cartography and Geodesy (BKG)
6// http://www.bkg.bund.de
7// Czech Technical University Prague, Department of Geodesy
8// http://www.fsv.cvut.cz
9//
10// Email: euref-ip@bkg.bund.de
11//
12// This program is free software; you can redistribute it and/or
13// modify it under the terms of the GNU General Public License
14// as published by the Free Software Foundation, version 2.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25/* -------------------------------------------------------------------------
26 * BKG NTRIP Client
27 * -------------------------------------------------------------------------
28 *
29 * Class: t_rnxObsFile
30 *
31 * Purpose: Reads RINEX Observation File
32 *
33 * Author: L. Mervart
34 *
35 * Created: 24-Jan-2012
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <iostream>
42#include <iomanip>
43#include <sstream>
44#include "rnxobsfile.h"
45#include "bncutils.h"
46#include "bnccore.h"
47
48using namespace std;
49
50const QString t_rnxObsHeader::defaultSystems = "GRES";
51
52// Constructor
53////////////////////////////////////////////////////////////////////////////
54t_rnxObsHeader::t_rnxObsHeader() {
55 _antNEU.ReSize(3); _antNEU = 0.0;
56 _antXYZ.ReSize(3); _antXYZ = 0.0;
57 _antBSG.ReSize(3); _antBSG = 0.0;
58 _xyz.ReSize(3); _xyz = 0.0;
59 _version = 0.0;
60 _interval = 0.0;
61 for (unsigned iPrn = 1; iPrn <= t_prn::MAXPRN_GPS; iPrn++) {
62 _wlFactorsL1[iPrn] = 1;
63 _wlFactorsL2[iPrn] = 1;
64 }
65}
66
67// Destructor
68////////////////////////////////////////////////////////////////////////////
69t_rnxObsHeader::~t_rnxObsHeader() {
70}
71
72// Read Header
73////////////////////////////////////////////////////////////////////////////
74t_irc t_rnxObsHeader::read(QTextStream* stream, int maxLines) {
75 _comments.clear();
76 int numLines = 0;
77 while ( stream->status() == QTextStream::Ok && !stream->atEnd() ) {
78 QString line = stream->readLine(); ++ numLines;
79 if (line.isEmpty()) {
80 continue;
81 }
82 if (line.indexOf("END OF FILE") != -1) {
83 break;
84 }
85 QString value = line.mid(0,60).trimmed();
86 QString key = line.mid(60).trimmed();
87 if (key == "END OF HEADER") {
88 break;
89 }
90 else if (key == "RINEX VERSION / TYPE") {
91 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
92 in >> _version;
93 }
94 else if (key == "MARKER NAME") {
95 _markerName = value;
96 }
97 else if (key == "MARKER NUMBER") {
98 _markerNumber = line.mid(0,20).trimmed();
99 }
100 else if (key == "ANT # / TYPE") {
101 _antennaNumber = line.mid( 0,20).trimmed();
102 _antennaName = line.mid(20,20).trimmed();
103 }
104 else if (key == "OBSERVER / AGENCY") {
105 _observer = line.mid( 0,20).trimmed();
106 _agency = line.mid(20,40).trimmed();
107 }
108 else if (key == "REC # / TYPE / VERS") {
109 _receiverNumber = line.mid( 0,20).trimmed();
110 _receiverType = line.mid(20,20).trimmed();
111 _receiverVersion = line.mid(40,20).trimmed();
112 }
113 else if (key == "INTERVAL") {
114 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
115 in >> _interval;
116 }
117 else if (key == "COMMENT") {
118 _comments << line.mid(0,60).trimmed();
119 }
120 else if (key == "WAVELENGTH FACT L1/2") {
121 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
122 int wlFactL1 = 0;
123 int wlFactL2 = 0;
124 int numSat = 0;
125 in >> wlFactL1 >> wlFactL2 >> numSat;
126 if (numSat == 0) {
127 for (unsigned iPrn = 1; iPrn <= t_prn::MAXPRN_GPS; iPrn++) {
128 _wlFactorsL1[iPrn] = wlFactL1;
129 _wlFactorsL2[iPrn] = wlFactL2;
130 }
131 }
132 else {
133 for (int ii = 0; ii < numSat; ii++) {
134 QString prn; in >> prn;
135 if (prn[0] == 'G') {
136 int iPrn;
137 readInt(prn, 1, 2, iPrn);
138 _wlFactorsL1[iPrn] = wlFactL1;
139 _wlFactorsL2[iPrn] = wlFactL2;
140 }
141 }
142 }
143 }
144 else if (key == "APPROX POSITION XYZ") {
145 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
146 in >> _xyz[0] >> _xyz[1] >> _xyz[2];
147 }
148 else if (key == "ANTENNA: DELTA H/E/N") {
149 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
150 in >> _antNEU[2] >> _antNEU[1] >> _antNEU[0];
151 }
152 else if (key == "ANTENNA: DELTA X/Y/Z") {
153 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
154 in >> _antXYZ[0] >> _antXYZ[1] >> _antXYZ[2];
155 }
156 else if (key == "ANTENNA: B.SIGHT XYZ") {
157 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
158 in >> _antBSG[0] >> _antBSG[1] >> _antBSG[2];
159 }
160 else if (key == "# / TYPES OF OBSERV") {
161 if (_version == 0.0) {
162 _version = t_rnxObsHeader::defaultRnxObsVersion2;
163 }
164 QTextStream* in = new QTextStream(value.toAscii(), QIODevice::ReadOnly);
165 int nTypes;
166 *in >> nTypes;
167 char sys0 = defaultSystems[0].toAscii();
168 _obsTypes[sys0].clear();
169 for (int ii = 0; ii < nTypes; ii++) {
170 if (ii > 0 && ii % 9 == 0) {
171 line = stream->readLine(); ++numLines;
172 delete in;
173 in = new QTextStream(line.left(60).toAscii(), QIODevice::ReadOnly);
174 }
175 QString hlp;
176 *in >> hlp;
177 _obsTypes[sys0].append(hlp);
178 }
179 for (int ii = 1; ii < defaultSystems.length(); ii++) {
180 char sysI = defaultSystems[ii].toAscii();
181 _obsTypes[sysI] = _obsTypes[sys0];
182 }
183 }
184 else if (key == "SYS / # / OBS TYPES") {
185 if (_version == 0.0) {
186 _version = t_rnxObsHeader::defaultRnxObsVersion2;
187 }
188 QTextStream* in = new QTextStream(value.toAscii(), QIODevice::ReadOnly);
189 char sys;
190 int nTypes;
191 *in >> sys >> nTypes;
192 _obsTypes[sys].clear();
193 for (int ii = 0; ii < nTypes; ii++) {
194 if (ii > 0 && ii % 13 == 0) {
195 line = stream->readLine(); ++numLines;
196 delete in;
197 in = new QTextStream(line.toAscii(), QIODevice::ReadOnly);
198 }
199 QString hlp;
200 *in >> hlp;
201 _obsTypes[sys].push_back(hlp);
202 }
203 delete in;
204 }
205 else if (key == "TIME OF FIRST OBS") {
206 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
207 int year, month, day, hour, min;
208 double sec;
209 in >> year >> month >> day >> hour >> min >> sec;
210 _startTime.set(year, month, day, hour, min, sec);
211 }
212 if (maxLines > 0 && numLines == maxLines) {
213 break;
214 }
215 }
216
217 return success;
218}
219
220// Set Default Header
221////////////////////////////////////////////////////////////////////////////
222void t_rnxObsHeader::setDefault(const QString& markerName, int version) {
223
224 _markerName = markerName;
225
226 if (version <= 2) {
227 _version = t_rnxObsHeader::defaultRnxObsVersion2;
228 }
229 else {
230 _version = t_rnxObsHeader::defaultRnxObsVersion3;
231 }
232
233 _comments << "Default set of observation types used";
234
235 _obsTypes.clear();
236 if (_version < 3.0) {
237 _obsTypes['G'] << "C1" << "P1" << "L1" << "S1"
238 << "C2" << "P2" << "L2" << "S2";
239 _obsTypes['R'] = _obsTypes['G'];
240 _obsTypes['E'] = _obsTypes['G'];
241 _obsTypes['J'] = _obsTypes['G'];
242 _obsTypes['S'] = _obsTypes['G'];
243 _obsTypes['C'] = _obsTypes['G'];
244 }
245 else {
246 _obsTypes['G'] << "C1C" << "L1C" << "S1C"
247 << "C2W" << "L2W" << "S2W"
248 << "C5" << "L5" << "S5";
249
250 _obsTypes['J'] = _obsTypes['G'];
251
252 _obsTypes['R'] << "C1C" << "L1C" << "S1C"
253 << "C2P" << "L2P" << "S2P";
254
255 _obsTypes['E'] << "C1" << "L1" << "S1"
256 << "C5" << "L5" << "S5"
257 << "C7" << "L7" << "S7"
258 << "C8" << "L8" << "S8";
259
260 _obsTypes['S'] << "C1" << "L1" << "S1"
261 << "C5" << "L5" << "S5";
262
263 _obsTypes['C'] << "C1" << "L1" << "S1"
264 << "C6" << "L6" << "S6"
265 << "C7" << "L7" << "S7";
266 }
267}
268
269// Copy header
270////////////////////////////////////////////////////////////////////////////
271void t_rnxObsHeader::set(const t_rnxObsHeader& header, int version,
272 const QStringList* useObsTypes) {
273
274 if (version <= 2) {
275 _version = t_rnxObsHeader::defaultRnxObsVersion2;
276 }
277 else {
278 _version = t_rnxObsHeader::defaultRnxObsVersion3;
279 }
280 _interval = header._interval;
281 _antennaNumber = header._antennaNumber;
282 _antennaName = header._antennaName;
283 _markerName = header._markerName;
284 _markerNumber = header._markerNumber;
285 _antNEU = header._antNEU;
286 _antXYZ = header._antXYZ;
287 _antBSG = header._antBSG;
288 _xyz = header._xyz;
289 _observer = header._observer;
290 _agency = header._agency;
291 _receiverNumber = header._receiverNumber;
292 _receiverType = header._receiverType;
293 _receiverVersion = header._receiverVersion;
294 _startTime = header._startTime;
295 for (unsigned iPrn = 1; iPrn <= t_prn::MAXPRN_GPS; iPrn++) {
296 _wlFactorsL1[iPrn] = header._wlFactorsL1[iPrn];
297 _wlFactorsL2[iPrn] = header._wlFactorsL2[iPrn];
298 }
299
300 // Set observation types
301 // ---------------------
302 _obsTypes.clear();
303 if (!useObsTypes || useObsTypes->size() == 0) {
304 if (int(_version) == int(header._version)) {
305 _obsTypes = header._obsTypes;
306 }
307 else {
308 for (int iSys = 0; iSys < header.numSys(); iSys++) {
309 char sys = header.system(iSys);
310 for (int iType = 0; iType < header.nTypes(sys); iType++) {
311 _obsTypes[sys].push_back(header.obsType(sys, iType, _version));
312 }
313 }
314 }
315 }
316 else {
317 for (int iType = 0; iType < useObsTypes->size(); iType++) {
318 if (useObsTypes->at(iType).indexOf(":") != -1) {
319 QStringList hlp = useObsTypes->at(iType).split(":", QString::SkipEmptyParts);
320 if (hlp.size() == 2 && hlp[0].length() == 1) {
321 char sys = hlp[0][0].toAscii();
322 QString type = hlp[1];
323 _obsTypes[sys].push_back(type);
324 }
325 }
326 else {
327 for (int iSys = 0; iSys < t_rnxObsHeader::defaultSystems.length(); iSys++) {
328 char sys = t_rnxObsHeader::defaultSystems[iSys].toAscii();
329 _obsTypes[sys].push_back(useObsTypes->at(iType));
330 }
331 }
332 }
333 }
334}
335
336// Write Header
337////////////////////////////////////////////////////////////////////////////
338void t_rnxObsHeader::write(QTextStream* stream,
339 const QMap<QString, QString>* txtMap) const {
340
341 QStringList newComments;
342 QString runBy = BNC_CORE->userName();
343
344 if (txtMap) {
345 QMapIterator<QString, QString> it(*txtMap);
346 while (it.hasNext()) {
347 it.next();
348 if (it.key() == "RUN BY") {
349 runBy = it.value();
350 }
351 else if (it.key() == "COMMENT") {
352 newComments = it.value().split("\\n", QString::SkipEmptyParts);
353 }
354 }
355 }
356
357 *stream << QString("%1 Observation data Mixed")
358 .arg(_version, 9, 'f', 2)
359 .leftJustified(60)
360 << "RINEX VERSION / TYPE\n";
361
362 const QString fmtDate = (_version < 3.0) ? "dd-MMM-yy hh:mm"
363 : "yyyyMMdd hhmmss UTC";
364 *stream << QString("%1%2%3")
365 .arg(BNC_CORE->pgmName(), -20)
366 .arg(runBy.trimmed().left(20), -20)
367 .arg(QDateTime::currentDateTime().toUTC().toString(fmtDate), -20)
368 .leftJustified(60)
369 << "PGM / RUN BY / DATE\n";
370
371 QStringListIterator itCmnt(_comments + newComments);
372 while (itCmnt.hasNext()) {
373 *stream << itCmnt.next().trimmed().left(60).leftJustified(60) << "COMMENT\n";
374 }
375
376 *stream << QString("%1")
377 .arg(_markerName, -60)
378 .leftJustified(60)
379 << "MARKER NAME\n";
380
381 if (!_markerNumber.isEmpty()) {
382 *stream << QString("%1")
383 .arg(_markerNumber, -20)
384 .leftJustified(60)
385 << "MARKER NUMBER\n";
386 }
387
388 *stream << QString("%1%2")
389 .arg(_observer, -20)
390 .arg(_agency, -40)
391 .leftJustified(60)
392 << "OBSERVER / AGENCY\n";
393
394 *stream << QString("%1%2%3")
395 .arg(_receiverNumber, -20)
396 .arg(_receiverType, -20)
397 .arg(_receiverVersion, -20)
398 .leftJustified(60)
399 << "REC # / TYPE / VERS\n";
400
401 *stream << QString("%1%2")
402 .arg(_antennaNumber, -20)
403 .arg(_antennaName, -20)
404 .leftJustified(60)
405 << "ANT # / TYPE\n";
406
407 *stream << QString("%1%2%3")
408 .arg(_xyz(1), 14, 'f', 4)
409 .arg(_xyz(2), 14, 'f', 4)
410 .arg(_xyz(3), 14, 'f', 4)
411 .leftJustified(60)
412 << "APPROX POSITION XYZ\n";
413
414 *stream << QString("%1%2%3")
415 .arg(_antNEU(3), 14, 'f', 4)
416 .arg(_antNEU(2), 14, 'f', 4)
417 .arg(_antNEU(1), 14, 'f', 4)
418 .leftJustified(60)
419 << "ANTENNA: DELTA H/E/N\n";
420
421 if (_version < 3.0) {
422 int defaultWlFact1 = _wlFactorsL1[1];
423 int defaultWlFact2 = _wlFactorsL2[1]; // TODO check all prns
424 *stream << QString("%1%2")
425 .arg(defaultWlFact1, 6)
426 .arg(defaultWlFact2, 6)
427 .leftJustified(60)
428 << "WAVELENGTH FACT L1/2\n";
429 }
430
431 *stream << obsTypesStrings().join("");
432
433 if (_interval > 0) {
434 *stream << QString("%1")
435 .arg(_interval, 10, 'f', 3)
436 .leftJustified(60)
437 << "INTERVAL\n";
438 }
439
440 unsigned year, month, day, hour, min;
441 double sec;
442 _startTime.civil_date(year, month, day);
443 _startTime.civil_time(hour, min, sec);
444 *stream << QString("%1%2%3%4%5%6%7")
445 .arg(year, 6)
446 .arg(month, 6)
447 .arg(day, 6)
448 .arg(hour, 6)
449 .arg(min, 6)
450 .arg(sec, 13, 'f', 7)
451 .arg("GPS", 8)
452 .leftJustified(60)
453 << "TIME OF FIRST OBS\n";
454
455 *stream << QString()
456 .leftJustified(60)
457 << "END OF HEADER\n";
458}
459
460// Number of Different Systems
461////////////////////////////////////////////////////////////////////////////
462int t_rnxObsHeader::numSys() const {
463 return _obsTypes.size();
464}
465
466//
467////////////////////////////////////////////////////////////////////////////
468char t_rnxObsHeader::system(int iSys) const {
469 int iSysLocal = -1;
470 QMapIterator<char, QVector<QString> > it(_obsTypes);
471 while (it.hasNext()) {
472 ++iSysLocal;
473 it.next();
474 if (iSysLocal == iSys) {
475 return it.key();
476 }
477 }
478 return ' ';
479}
480
481// Number of Observation Types (satellite-system specific)
482////////////////////////////////////////////////////////////////////////////
483int t_rnxObsHeader::nTypes(char sys) const {
484 if (_obsTypes.contains(sys)) {
485 return _obsTypes[sys].size();
486 }
487 else {
488 return 0;
489 }
490}
491
492// Observation Type (satellite-system specific)
493////////////////////////////////////////////////////////////////////////////
494QString t_rnxObsHeader::obsType(char sys, int index, double version) const {
495
496 if (version == 0.0) {
497 version = _version;
498 }
499 if (_obsTypes.contains(sys)) {
500 QString origType = _obsTypes[sys].at(index);
501 if (int(version) == int(_version)) {
502 return origType;
503 }
504 else if (int(version) == 2) {
505 return t_rnxObsFile::type3to2(sys, origType);
506 }
507 else if (int(version) == 3) {
508 return t_rnxObsFile::type2to3(sys, origType);
509 }
510 }
511 return "";
512}
513
514// Write Observation Types
515////////////////////////////////////////////////////////////////////////////
516QStringList t_rnxObsHeader::obsTypesStrings() const {
517
518 QStringList strList;
519
520 if (_version < 3.0) {
521 char sys0 = defaultSystems[0].toAscii();
522 QString hlp;
523 QTextStream(&hlp) << QString("%1").arg(_obsTypes[sys0].size(), 6);
524 for (int ii = 0; ii < _obsTypes[sys0].size(); ii++) {
525 QTextStream(&hlp) << QString("%1").arg(_obsTypes[sys0][ii], 6);
526 if ((ii+1) % 9 == 0 || ii == _obsTypes[sys0].size()-1) {
527 strList.append(hlp.leftJustified(60) + "# / TYPES OF OBSERV\n");
528 hlp = QString().leftJustified(6);
529 }
530 }
531 }
532 else {
533 for (int iSys = 0; iSys < numSys(); iSys++) {
534 char sys = system(iSys);
535 QString hlp;
536 QTextStream(&hlp) << QString("%1 %2").arg(sys).arg(nTypes(sys), 3);
537 for (int iType = 0; iType < nTypes(sys); iType++) {
538 QString type = obsType(sys, iType);
539 QTextStream(&hlp) << QString(" %1").arg(type, -3);
540 if ((iType+1) % 13 == 0 || iType == nTypes(sys)-1) {
541 strList.append(hlp.leftJustified(60) + "SYS / # / OBS TYPES\n");
542 hlp = QString().leftJustified(6);
543 }
544 }
545 }
546 }
547
548 return strList;
549}
550
551// Constructor
552////////////////////////////////////////////////////////////////////////////
553t_rnxObsFile::t_rnxObsFile(const QString& fileName, e_inpOut inpOut) {
554 _inpOut = inpOut;
555 _stream = 0;
556 _flgPowerFail = false;
557 if (_inpOut == input) {
558 openRead(fileName);
559 }
560 else {
561 openWrite(fileName);
562 }
563}
564
565// Open for input
566////////////////////////////////////////////////////////////////////////////
567void t_rnxObsFile::openRead(const QString& fileName) {
568
569 _fileName = fileName; expandEnvVar(_fileName);
570 _file = new QFile(_fileName);
571 _file->open(QIODevice::ReadOnly | QIODevice::Text);
572 _stream = new QTextStream();
573 _stream->setDevice(_file);
574
575 _header.read(_stream);
576
577 // Guess Observation Interval
578 // --------------------------
579 if (_header._interval == 0.0) {
580 bncTime ttPrev;
581 for (int iEpo = 0; iEpo < 10; iEpo++) {
582 const t_rnxEpo* rnxEpo = nextEpoch();
583 if (!rnxEpo) {
584 throw QString("t_rnxObsFile: not enough epochs");
585 }
586 if (iEpo > 0) {
587 double dt = rnxEpo->tt - ttPrev;
588 if (_header._interval == 0.0 || dt < _header._interval) {
589 _header._interval = dt;
590 }
591 }
592 ttPrev = rnxEpo->tt;
593 }
594 _stream->seek(0);
595 _header.read(_stream);
596 }
597
598 // Time of first observation
599 // -------------------------
600 if (!_header._startTime.valid()) {
601 const t_rnxEpo* rnxEpo = nextEpoch();
602 if (!rnxEpo) {
603 throw QString("t_rnxObsFile: not enough epochs");
604 }
605 _header._startTime = rnxEpo->tt;
606 _stream->seek(0);
607 _header.read(_stream);
608 }
609}
610
611// Open for output
612////////////////////////////////////////////////////////////////////////////
613void t_rnxObsFile::openWrite(const QString& fileName) {
614
615 _fileName = fileName; expandEnvVar(_fileName);
616 _file = new QFile(_fileName);
617 _file->open(QIODevice::WriteOnly | QIODevice::Text);
618 _stream = new QTextStream();
619 _stream->setDevice(_file);
620}
621
622// Destructor
623////////////////////////////////////////////////////////////////////////////
624t_rnxObsFile::~t_rnxObsFile() {
625 close();
626}
627
628// Close
629////////////////////////////////////////////////////////////////////////////
630void t_rnxObsFile::close() {
631 delete _stream; _stream = 0;
632 delete _file; _file = 0;
633}
634
635// Handle Special Epoch Flag
636////////////////////////////////////////////////////////////////////////////
637void t_rnxObsFile::handleEpochFlag(int flag, const QString& line,
638 bool& headerReRead) {
639
640 headerReRead = false;
641
642 // Power Failure
643 // -------------
644 if (flag == 1) {
645 _flgPowerFail = true;
646 }
647
648 // Start moving antenna
649 // --------------------
650 else if (flag == 2) {
651 // no action
652 }
653
654 // Re-Read Header
655 // --------------
656 else if (flag == 3 || flag == 4 || flag == 5) {
657 int numLines = 0;
658 if (version() < 3.0) {
659 readInt(line, 29, 3, numLines);
660 }
661 else {
662 readInt(line, 32, 3, numLines);
663 }
664 if (flag == 3 || flag == 4) {
665 _header.read(_stream, numLines);
666 headerReRead = true;
667 }
668 else {
669 for (int ii = 0; ii < numLines; ii++) {
670 _stream->readLine();
671 }
672 }
673 }
674
675 // Unhandled Flag
676 // --------------
677 else {
678 throw QString("t_rnxObsFile: unhandled flag\n" + line);
679 }
680}
681
682// Retrieve single Epoch
683////////////////////////////////////////////////////////////////////////////
684t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpoch() {
685 _currEpo.clear();
686 if (version() < 3.0) {
687 return nextEpochV2();
688 }
689 else {
690 return nextEpochV3();
691 }
692}
693
694// Retrieve single Epoch (RINEX Version 3)
695////////////////////////////////////////////////////////////////////////////
696t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV3() {
697
698 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
699
700 QString line = _stream->readLine();
701
702 if (line.isEmpty()) {
703 continue;
704 }
705
706 int flag = 0;
707 readInt(line, 31, 1, flag);
708 if (flag > 0) {
709 bool headerReRead = false;
710 handleEpochFlag(flag, line, headerReRead);
711 if (headerReRead) {
712 continue;
713 }
714 }
715
716 QTextStream in(line.mid(1).toAscii(), QIODevice::ReadOnly);
717
718 // Epoch Time
719 // ----------
720 int year, month, day, hour, min;
721 double sec;
722 in >> year >> month >> day >> hour >> min >> sec;
723 _currEpo.tt.set(year, month, day, hour, min, sec);
724
725 // Number of Satellites
726 // --------------------
727 int numSat;
728 readInt(line, 32, 3, numSat);
729
730 _currEpo.rnxSat.resize(numSat);
731
732 // Observations
733 // ------------
734 for (int iSat = 0; iSat < numSat; iSat++) {
735 line = _stream->readLine();
736 t_prn prn; prn.set(line.left(3).toAscii().data());
737 _currEpo.rnxSat[iSat].prn = prn;
738 char sys = prn.system();
739 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
740 int pos = 3 + 16*iType;
741 double obsValue = 0.0;
742 int lli = 0;
743 int snr = 0;
744 readDbl(line, pos, 14, obsValue);
745 readInt(line, pos + 14, 1, lli);
746 readInt(line, pos + 15, 1, snr);
747 if (_flgPowerFail) {
748 lli |= 1;
749 }
750 QString type = obsType(sys, iType);
751 _currEpo.rnxSat[iSat].obs[type].value = obsValue;
752 _currEpo.rnxSat[iSat].obs[type].lli = lli;
753 _currEpo.rnxSat[iSat].obs[type].snr = snr;
754 }
755 }
756
757 _flgPowerFail = false;
758
759 return &_currEpo;
760 }
761
762 return 0;
763}
764
765// Retrieve single Epoch (RINEX Version 2)
766////////////////////////////////////////////////////////////////////////////
767t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV2() {
768
769 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
770
771 QString line = _stream->readLine();
772
773 if (line.isEmpty()) {
774 continue;
775 }
776
777 int flag = 0;
778 readInt(line, 28, 1, flag);
779 if (flag > 0) {
780 bool headerReRead = false;
781 handleEpochFlag(flag, line, headerReRead);
782 if (headerReRead) {
783 continue;
784 }
785 }
786
787 QTextStream in(line.toAscii(), QIODevice::ReadOnly);
788
789 // Epoch Time
790 // ----------
791 int year, month, day, hour, min;
792 double sec;
793 in >> year >> month >> day >> hour >> min >> sec;
794 if (year < 80) {
795 year += 2000;
796 }
797 else if (year < 100) {
798 year += 1900;
799 }
800 _currEpo.tt.set(year, month, day, hour, min, sec);
801
802 // Number of Satellites
803 // --------------------
804 int numSat;
805 readInt(line, 29, 3, numSat);
806
807 _currEpo.rnxSat.resize(numSat);
808
809 // Read Satellite Numbers
810 // ----------------------
811 int pos = 32;
812 for (int iSat = 0; iSat < numSat; iSat++) {
813 if (iSat > 0 && iSat % 12 == 0) {
814 line = _stream->readLine();
815 pos = 32;
816 }
817
818 char sys = line.toAscii()[pos];
819 int satNum; readInt(line, pos + 1, 2, satNum);
820 _currEpo.rnxSat[iSat].prn.set(sys, satNum);
821
822 pos += 3;
823 }
824
825 // Read Observation Records
826 // ------------------------
827 for (int iSat = 0; iSat < numSat; iSat++) {
828 char sys = _currEpo.rnxSat[iSat].prn.system();
829 line = _stream->readLine();
830 pos = 0;
831 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
832 if (iType > 0 && iType % 5 == 0) {
833 line = _stream->readLine();
834 pos = 0;
835 }
836 double obsValue = 0.0;
837 int lli = 0;
838 int snr = 0;
839 readDbl(line, pos, 14, obsValue);
840 readInt(line, pos + 14, 1, lli);
841 readInt(line, pos + 15, 1, snr);
842
843 if (_flgPowerFail) {
844 lli |= 1;
845 }
846
847 QString type = obsType(sys, iType);
848 _currEpo.rnxSat[iSat].obs[type].value = obsValue;
849 _currEpo.rnxSat[iSat].obs[type].lli = lli;
850 _currEpo.rnxSat[iSat].obs[type].snr = snr;
851
852 pos += 16;
853 }
854 }
855
856 _flgPowerFail = false;
857
858 return &_currEpo;
859 }
860
861 return 0;
862}
863
864// Write Data Epoch
865////////////////////////////////////////////////////////////////////////////
866void t_rnxObsFile::writeEpoch(const t_rnxEpo* epo) {
867 if (version() < 3.0) {
868 return writeEpochV2(_stream, _header, epo);
869 }
870 else {
871 return writeEpochV3(_stream, _header, epo);
872 }
873}
874
875// Write Data Epoch (RINEX Version 2)
876////////////////////////////////////////////////////////////////////////////
877void t_rnxObsFile::writeEpochV2(QTextStream* stream, const t_rnxObsHeader& header,
878 const t_rnxEpo* epo) {
879
880 unsigned year, month, day, hour, min;
881 double sec;
882 epo->tt.civil_date(year, month, day);
883 epo->tt.civil_time(hour, min, sec);
884
885 QString dateStr;
886 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
887 .arg(int(fmod(year, 100)), 2, 10, QChar('0'))
888 .arg(month, 2, 10, QChar('0'))
889 .arg(day, 2, 10, QChar('0'))
890 .arg(hour, 2, 10, QChar('0'))
891 .arg(min, 2, 10, QChar('0'))
892 .arg(sec, 11, 'f', 7);
893
894 int flag = 0;
895 *stream << dateStr << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
896 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
897 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
898 if (iSat > 0 && iSat % 12 == 0) {
899 *stream << endl << QString().leftJustified(32);
900 }
901 *stream << rnxSat.prn.toString().c_str();
902 }
903 *stream << endl;
904 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
905
906 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
907 char sys = rnxSat.prn.system();
908
909 for (int iTypeV2 = 0; iTypeV2 < header.nTypes(sys); iTypeV2++) {
910 if (iTypeV2 > 0 && iTypeV2 % 5 == 0) {
911 *stream << endl;
912 }
913 QString typeV2 = header.obsType(sys, iTypeV2);
914 bool found = false;
915 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
916 while (itObs.hasNext()) {
917 itObs.next();
918 const QString& type = itObs.key();
919 const t_rnxObs& rnxObs = itObs.value();
920 if (typeV2 == type3to2(sys, type)) {
921 found = true;
922 if (rnxObs.value == 0.0) {
923 *stream << QString().leftJustified(16);
924 }
925 else {
926 *stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
927 if (rnxObs.lli != 0.0) {
928 *stream << QString("%1").arg(rnxObs.lli,1);
929 }
930 else {
931 *stream << ' ';
932 }
933 if (rnxObs.snr != 0.0) {
934 *stream << QString("%1").arg(rnxObs.snr,1);
935 }
936 else {
937 *stream << ' ';
938 }
939 }
940 break;
941 }
942 }
943 if (!found) {
944 *stream << QString().leftJustified(16);
945 }
946 }
947 *stream << endl;
948 }
949}
950
951// Write Data Epoch (RINEX Version 3)
952////////////////////////////////////////////////////////////////////////////
953void t_rnxObsFile::writeEpochV3(QTextStream* stream, const t_rnxObsHeader& header,
954 const t_rnxEpo* epo) {
955
956 unsigned year, month, day, hour, min;
957 double sec;
958 epo->tt.civil_date(year, month, day);
959 epo->tt.civil_time(hour, min, sec);
960
961 QString dateStr;
962 QTextStream(&dateStr) << QString("> %1 %2 %3 %4 %5%6")
963 .arg(year, 4)
964 .arg(month, 2, 10, QChar('0'))
965 .arg(day, 2, 10, QChar('0'))
966 .arg(hour, 2, 10, QChar('0'))
967 .arg(min, 2, 10, QChar('0'))
968 .arg(sec, 11, 'f', 7);
969
970 int flag = 0;
971 *stream << dateStr << QString("%1%2\n").arg(flag, 3).arg(epo->rnxSat.size(), 3);
972
973 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
974 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
975 char sys = rnxSat.prn.system();
976
977 *stream << rnxSat.prn.toString().c_str();
978
979 for (int iTypeV3 = 0; iTypeV3 < header.nTypes(sys); iTypeV3++) {
980 QString typeV3 = header.obsType(sys, iTypeV3);
981 bool found = false;
982 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
983 while (itObs.hasNext()) {
984 itObs.next();
985 const QString& type = itObs.key();
986 const t_rnxObs& rnxObs = itObs.value();
987 if (typeV3 == type2to3(sys, type)) {
988 found = true;
989 if (rnxObs.value == 0.0) {
990 *stream << QString().leftJustified(16);
991 }
992 else {
993 *stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
994 if (rnxObs.lli != 0.0) {
995 *stream << QString("%1").arg(rnxObs.lli,1);
996 }
997 else {
998 *stream << ' ';
999 }
1000 if (rnxObs.snr != 0.0) {
1001 *stream << QString("%1").arg(rnxObs.snr,1);
1002 }
1003 else {
1004 *stream << ' ';
1005 }
1006 }
1007 }
1008 }
1009 if (!found) {
1010 *stream << QString().leftJustified(16);
1011 }
1012 }
1013 *stream << endl;
1014 }
1015}
1016
1017// Translate Observation Type v2 --> v3
1018////////////////////////////////////////////////////////////////////////////
1019QString t_rnxObsFile::type2to3(char sys, const QString& typeV2) {
1020 if (typeV2 == "P1") {
1021 return (sys == 'G') ? "C1W" : "C1P";
1022 }
1023 else if (typeV2 == "P2") {
1024 return (sys == 'G') ? "C2W" : "C2P";
1025 }
1026 return typeV2;
1027}
1028
1029// Translate Observation Type v3 --> v2
1030////////////////////////////////////////////////////////////////////////////
1031QString t_rnxObsFile::type3to2(char /* sys */, const QString& typeV3) {
1032 if (typeV3 == "C1P" || typeV3 == "C1W") {
1033 return "P1";
1034 }
1035 else if (typeV3 == "C2P" || typeV3 == "C2W") {
1036 return "P2";
1037 }
1038 return typeV3.left(2);
1039}
1040
1041// Set Observations from RINEX File
1042////////////////////////////////////////////////////////////////////////////
1043void t_rnxObsFile::setObsFromRnx(const t_rnxObsFile* rnxObsFile, const t_rnxObsFile::t_rnxEpo* epo,
1044 const t_rnxObsFile::t_rnxSat& rnxSat, t_satObs& obs) {
1045
1046 obs._staID = rnxObsFile->markerName().toAscii().constData();
1047 obs._prn = rnxSat.prn;
1048 obs._time = epo->tt;
1049
1050 char sys = rnxSat.prn.system();
1051
1052 for (int iType = 0; iType < rnxObsFile->nTypes(sys); iType++) {
1053 QString type = rnxObsFile->obsType(sys, iType);
1054 if (rnxSat.obs.contains(type)) {
1055 const t_rnxObs& rnxObs = rnxSat.obs[type];
1056 if (rnxObs.value != 0.0) {
1057 string type2ch(type.mid(1).toAscii().data());
1058
1059 t_frqObs* frqObs = 0;
1060 for (unsigned iFrq = 0; iFrq < obs._obs.size(); iFrq++) {
1061 if (obs._obs[iFrq]->_rnxType2ch == type2ch) {
1062 frqObs = obs._obs[iFrq];
1063 break;
1064 }
1065 }
1066 if (frqObs == 0) {
1067 frqObs = new t_frqObs;
1068 frqObs->_rnxType2ch = type2ch;
1069 obs._obs.push_back(frqObs);
1070 }
1071
1072 switch( type.toAscii().data()[0] ) {
1073 case 'C':
1074 frqObs->_codeValid = true;
1075 frqObs->_code = rnxObs.value;
1076 break;
1077 case 'L':
1078 frqObs->_phaseValid = true;
1079 frqObs->_phase = rnxObs.value;
1080 frqObs->_slip = (rnxObs.lli & 1);
1081 break;
1082 case 'D':
1083 frqObs->_dopplerValid = true;
1084 frqObs->_doppler = rnxObs.value;
1085 break;
1086 case 'S':
1087 frqObs->_snrValid = true;
1088 frqObs->_snr = rnxObs.value;
1089 break;
1090 }
1091 }
1092 }
1093 }
1094}
1095
Note: See TracBrowser for help on using the repository browser.