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

Last change on this file since 6231 was 6231, checked in by mervart, 10 years ago
File size: 31.5 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::defaultRnxObsVersion3;
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 _comments = header._comments;
296 for (unsigned iPrn = 1; iPrn <= t_prn::MAXPRN_GPS; iPrn++) {
297 _wlFactorsL1[iPrn] = header._wlFactorsL1[iPrn];
298 _wlFactorsL2[iPrn] = header._wlFactorsL2[iPrn];
299 }
300
301 // Set observation types
302 // ---------------------
303 _obsTypes.clear();
304 if (!useObsTypes || useObsTypes->size() == 0) {
305 if (int(_version) == int(header._version)) {
306 _obsTypes = header._obsTypes;
307 }
308 else {
309 for (int iSys = 0; iSys < header.numSys(); iSys++) {
310 char sys = header.system(iSys);
311 for (int iType = 0; iType < header.nTypes(sys); iType++) {
312 _obsTypes[sys].push_back(header.obsType(sys, iType, _version));
313 }
314 _obsTypes[sys].removeDuplicates();
315 }
316 }
317 }
318 else {
319 for (int iType = 0; iType < useObsTypes->size(); iType++) {
320 if (useObsTypes->at(iType).indexOf(":") != -1) {
321 QStringList hlp = useObsTypes->at(iType).split(":", QString::SkipEmptyParts);
322 if (hlp.size() == 2 && hlp[0].length() == 1) {
323 char sys = hlp[0][0].toAscii();
324 QString type = hlp[1];
325 _obsTypes[sys].push_back(type);
326 }
327 }
328 else {
329 for (int iSys = 0; iSys < t_rnxObsHeader::defaultSystems.length(); iSys++) {
330 char sys = t_rnxObsHeader::defaultSystems[iSys].toAscii();
331 _obsTypes[sys].push_back(useObsTypes->at(iType));
332 }
333 }
334 }
335 }
336}
337
338// Write Header
339////////////////////////////////////////////////////////////////////////////
340void t_rnxObsHeader::write(QTextStream* stream,
341 const QMap<QString, QString>* txtMap) const {
342
343 QStringList newComments;
344 QString runBy = BNC_CORE->userName();
345
346 if (txtMap) {
347 QMapIterator<QString, QString> it(*txtMap);
348 while (it.hasNext()) {
349 it.next();
350 if (it.key() == "RUN BY") {
351 runBy = it.value();
352 }
353 else if (it.key() == "COMMENT") {
354 newComments = it.value().split("\\n", QString::SkipEmptyParts);
355 }
356 }
357 }
358
359 *stream << QString("%1 Observation data Mixed")
360 .arg(_version, 9, 'f', 2)
361 .leftJustified(60)
362 << "RINEX VERSION / TYPE\n";
363
364 const QString fmtDate = (_version < 3.0) ? "dd-MMM-yy hh:mm"
365 : "yyyyMMdd hhmmss UTC";
366 *stream << QString("%1%2%3")
367 .arg(BNC_CORE->pgmName(), -20)
368 .arg(runBy.trimmed().left(20), -20)
369 .arg(QDateTime::currentDateTime().toUTC().toString(fmtDate), -20)
370 .leftJustified(60)
371 << "PGM / RUN BY / DATE\n";
372
373 QStringListIterator itCmnt(_comments + newComments);
374 while (itCmnt.hasNext()) {
375 *stream << itCmnt.next().trimmed().left(60).leftJustified(60) << "COMMENT\n";
376 }
377
378 *stream << QString("%1")
379 .arg(_markerName, -60)
380 .leftJustified(60)
381 << "MARKER NAME\n";
382
383 if (!_markerNumber.isEmpty()) {
384 *stream << QString("%1")
385 .arg(_markerNumber, -20)
386 .leftJustified(60)
387 << "MARKER NUMBER\n";
388 }
389
390 *stream << QString("%1%2")
391 .arg(_observer, -20)
392 .arg(_agency, -40)
393 .leftJustified(60)
394 << "OBSERVER / AGENCY\n";
395
396 *stream << QString("%1%2%3")
397 .arg(_receiverNumber, -20)
398 .arg(_receiverType, -20)
399 .arg(_receiverVersion, -20)
400 .leftJustified(60)
401 << "REC # / TYPE / VERS\n";
402
403 *stream << QString("%1%2")
404 .arg(_antennaNumber, -20)
405 .arg(_antennaName, -20)
406 .leftJustified(60)
407 << "ANT # / TYPE\n";
408
409 *stream << QString("%1%2%3")
410 .arg(_xyz(1), 14, 'f', 4)
411 .arg(_xyz(2), 14, 'f', 4)
412 .arg(_xyz(3), 14, 'f', 4)
413 .leftJustified(60)
414 << "APPROX POSITION XYZ\n";
415
416 *stream << QString("%1%2%3")
417 .arg(_antNEU(3), 14, 'f', 4)
418 .arg(_antNEU(2), 14, 'f', 4)
419 .arg(_antNEU(1), 14, 'f', 4)
420 .leftJustified(60)
421 << "ANTENNA: DELTA H/E/N\n";
422
423 if (_version < 3.0) {
424 int defaultWlFact1 = _wlFactorsL1[1];
425 int defaultWlFact2 = _wlFactorsL2[1]; // TODO check all prns
426 *stream << QString("%1%2")
427 .arg(defaultWlFact1, 6)
428 .arg(defaultWlFact2, 6)
429 .leftJustified(60)
430 << "WAVELENGTH FACT L1/2\n";
431 }
432
433 *stream << obsTypesStrings().join("");
434
435 if (_interval > 0) {
436 *stream << QString("%1")
437 .arg(_interval, 10, 'f', 3)
438 .leftJustified(60)
439 << "INTERVAL\n";
440 }
441
442 unsigned year, month, day, hour, min;
443 double sec;
444 _startTime.civil_date(year, month, day);
445 _startTime.civil_time(hour, min, sec);
446 *stream << QString("%1%2%3%4%5%6%7")
447 .arg(year, 6)
448 .arg(month, 6)
449 .arg(day, 6)
450 .arg(hour, 6)
451 .arg(min, 6)
452 .arg(sec, 13, 'f', 7)
453 .arg("GPS", 8)
454 .leftJustified(60)
455 << "TIME OF FIRST OBS\n";
456
457 *stream << QString()
458 .leftJustified(60)
459 << "END OF HEADER\n";
460}
461
462// Number of Different Systems
463////////////////////////////////////////////////////////////////////////////
464int t_rnxObsHeader::numSys() const {
465 return _obsTypes.size();
466}
467
468//
469////////////////////////////////////////////////////////////////////////////
470char t_rnxObsHeader::system(int iSys) const {
471 int iSysLocal = -1;
472 QMapIterator<char, QStringList> it(_obsTypes);
473 while (it.hasNext()) {
474 ++iSysLocal;
475 it.next();
476 if (iSysLocal == iSys) {
477 return it.key();
478 }
479 }
480 return ' ';
481}
482
483// Number of Observation Types (satellite-system specific)
484////////////////////////////////////////////////////////////////////////////
485int t_rnxObsHeader::nTypes(char sys) const {
486 if (_obsTypes.contains(sys)) {
487 return _obsTypes[sys].size();
488 }
489 else {
490 return 0;
491 }
492}
493
494// Observation Type (satellite-system specific)
495////////////////////////////////////////////////////////////////////////////
496QString t_rnxObsHeader::obsType(char sys, int index, double version) const {
497
498 if (version == 0.0) {
499 version = _version;
500 }
501 if (_obsTypes.contains(sys)) {
502 QString origType = _obsTypes[sys].at(index);
503 if (int(version) == int(_version)) {
504 return origType;
505 }
506 else if (int(version) == 2) {
507 return t_rnxObsFile::type3to2(sys, origType);
508 }
509 else if (int(version) == 3) {
510 return t_rnxObsFile::type2to3(sys, origType);
511 }
512 }
513 return "";
514}
515
516// Write Observation Types
517////////////////////////////////////////////////////////////////////////////
518QStringList t_rnxObsHeader::obsTypesStrings() const {
519
520 QStringList strList;
521
522 if (_version < 3.0) {
523 char sys0 = defaultSystems[0].toAscii();
524 QString hlp;
525 QTextStream(&hlp) << QString("%1").arg(_obsTypes[sys0].size(), 6);
526 for (int ii = 0; ii < _obsTypes[sys0].size(); ii++) {
527 QTextStream(&hlp) << QString("%1").arg(_obsTypes[sys0][ii], 6);
528 if ((ii+1) % 9 == 0 || ii == _obsTypes[sys0].size()-1) {
529 strList.append(hlp.leftJustified(60) + "# / TYPES OF OBSERV\n");
530 hlp = QString().leftJustified(6);
531 }
532 }
533 }
534 else {
535 for (int iSys = 0; iSys < numSys(); iSys++) {
536 char sys = system(iSys);
537 QString hlp;
538 QTextStream(&hlp) << QString("%1 %2").arg(sys).arg(nTypes(sys), 3);
539 for (int iType = 0; iType < nTypes(sys); iType++) {
540 QString type = obsType(sys, iType);
541 QTextStream(&hlp) << QString(" %1").arg(type, -3);
542 if ((iType+1) % 13 == 0 || iType == nTypes(sys)-1) {
543 strList.append(hlp.leftJustified(60) + "SYS / # / OBS TYPES\n");
544 hlp = QString().leftJustified(6);
545 }
546 }
547 }
548 }
549
550 return strList;
551}
552
553// Constructor
554////////////////////////////////////////////////////////////////////////////
555t_rnxObsFile::t_rnxObsFile(const QString& fileName, e_inpOut inpOut) {
556 _inpOut = inpOut;
557 _stream = 0;
558 _flgPowerFail = false;
559 if (_inpOut == input) {
560 openRead(fileName);
561 }
562 else {
563 openWrite(fileName);
564 }
565}
566
567// Open for input
568////////////////////////////////////////////////////////////////////////////
569void t_rnxObsFile::openRead(const QString& fileName) {
570
571 _fileName = fileName; expandEnvVar(_fileName);
572 _file = new QFile(_fileName);
573 _file->open(QIODevice::ReadOnly | QIODevice::Text);
574 _stream = new QTextStream();
575 _stream->setDevice(_file);
576
577 _header.read(_stream);
578
579 // Guess Observation Interval
580 // --------------------------
581 if (_header._interval == 0.0) {
582 bncTime ttPrev;
583 for (int iEpo = 0; iEpo < 10; iEpo++) {
584 const t_rnxEpo* rnxEpo = nextEpoch();
585 if (!rnxEpo) {
586 throw QString("t_rnxObsFile: not enough epochs");
587 }
588 if (iEpo > 0) {
589 double dt = rnxEpo->tt - ttPrev;
590 if (_header._interval == 0.0 || dt < _header._interval) {
591 _header._interval = dt;
592 }
593 }
594 ttPrev = rnxEpo->tt;
595 }
596 _stream->seek(0);
597 _header.read(_stream);
598 }
599
600 // Time of first observation
601 // -------------------------
602 if (!_header._startTime.valid()) {
603 const t_rnxEpo* rnxEpo = nextEpoch();
604 if (!rnxEpo) {
605 throw QString("t_rnxObsFile: not enough epochs");
606 }
607 _header._startTime = rnxEpo->tt;
608 _stream->seek(0);
609 _header.read(_stream);
610 }
611}
612
613// Open for output
614////////////////////////////////////////////////////////////////////////////
615void t_rnxObsFile::openWrite(const QString& fileName) {
616
617 _fileName = fileName; expandEnvVar(_fileName);
618 _file = new QFile(_fileName);
619 _file->open(QIODevice::WriteOnly | QIODevice::Text);
620 _stream = new QTextStream();
621 _stream->setDevice(_file);
622}
623
624// Destructor
625////////////////////////////////////////////////////////////////////////////
626t_rnxObsFile::~t_rnxObsFile() {
627 close();
628}
629
630// Close
631////////////////////////////////////////////////////////////////////////////
632void t_rnxObsFile::close() {
633 delete _stream; _stream = 0;
634 delete _file; _file = 0;
635}
636
637// Handle Special Epoch Flag
638////////////////////////////////////////////////////////////////////////////
639void t_rnxObsFile::handleEpochFlag(int flag, const QString& line,
640 bool& headerReRead) {
641
642 headerReRead = false;
643
644 // Power Failure
645 // -------------
646 if (flag == 1) {
647 _flgPowerFail = true;
648 }
649
650 // Start moving antenna
651 // --------------------
652 else if (flag == 2) {
653 // no action
654 }
655
656 // Re-Read Header
657 // --------------
658 else if (flag == 3 || flag == 4 || flag == 5) {
659 int numLines = 0;
660 if (version() < 3.0) {
661 readInt(line, 29, 3, numLines);
662 }
663 else {
664 readInt(line, 32, 3, numLines);
665 }
666 if (flag == 3 || flag == 4) {
667 _header.read(_stream, numLines);
668 headerReRead = true;
669 }
670 else {
671 for (int ii = 0; ii < numLines; ii++) {
672 _stream->readLine();
673 }
674 }
675 }
676
677 // Unhandled Flag
678 // --------------
679 else {
680 throw QString("t_rnxObsFile: unhandled flag\n" + line);
681 }
682}
683
684// Retrieve single Epoch
685////////////////////////////////////////////////////////////////////////////
686t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpoch() {
687 _currEpo.clear();
688 if (version() < 3.0) {
689 return nextEpochV2();
690 }
691 else {
692 return nextEpochV3();
693 }
694}
695
696// Retrieve single Epoch (RINEX Version 3)
697////////////////////////////////////////////////////////////////////////////
698t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV3() {
699
700 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
701
702 QString line = _stream->readLine();
703
704 if (line.isEmpty()) {
705 continue;
706 }
707
708 int flag = 0;
709 readInt(line, 31, 1, flag);
710 if (flag > 0) {
711 bool headerReRead = false;
712 handleEpochFlag(flag, line, headerReRead);
713 if (headerReRead) {
714 continue;
715 }
716 }
717
718 QTextStream in(line.mid(1).toAscii(), QIODevice::ReadOnly);
719
720 // Epoch Time
721 // ----------
722 int year, month, day, hour, min;
723 double sec;
724 in >> year >> month >> day >> hour >> min >> sec;
725 _currEpo.tt.set(year, month, day, hour, min, sec);
726
727 // Number of Satellites
728 // --------------------
729 int numSat;
730 readInt(line, 32, 3, numSat);
731
732 _currEpo.rnxSat.resize(numSat);
733
734 // Observations
735 // ------------
736 for (int iSat = 0; iSat < numSat; iSat++) {
737 line = _stream->readLine();
738 t_prn prn; prn.set(line.left(3).toAscii().data());
739 _currEpo.rnxSat[iSat].prn = prn;
740 char sys = prn.system();
741 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
742 int pos = 3 + 16*iType;
743 double obsValue = 0.0;
744 int lli = 0;
745 int snr = 0;
746 readDbl(line, pos, 14, obsValue);
747 readInt(line, pos + 14, 1, lli);
748 readInt(line, pos + 15, 1, snr);
749 if (_flgPowerFail) {
750 lli |= 1;
751 }
752 QString type = obsType(sys, iType);
753 _currEpo.rnxSat[iSat].obs[type].value = obsValue;
754 _currEpo.rnxSat[iSat].obs[type].lli = lli;
755 _currEpo.rnxSat[iSat].obs[type].snr = snr;
756 }
757 }
758
759 _flgPowerFail = false;
760
761 return &_currEpo;
762 }
763
764 return 0;
765}
766
767// Retrieve single Epoch (RINEX Version 2)
768////////////////////////////////////////////////////////////////////////////
769t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV2() {
770
771 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
772
773 QString line = _stream->readLine();
774
775 if (line.isEmpty()) {
776 continue;
777 }
778
779 int flag = 0;
780 readInt(line, 28, 1, flag);
781 if (flag > 0) {
782 bool headerReRead = false;
783 handleEpochFlag(flag, line, headerReRead);
784 if (headerReRead) {
785 continue;
786 }
787 }
788
789 QTextStream in(line.toAscii(), QIODevice::ReadOnly);
790
791 // Epoch Time
792 // ----------
793 int year, month, day, hour, min;
794 double sec;
795 in >> year >> month >> day >> hour >> min >> sec;
796 if (year < 80) {
797 year += 2000;
798 }
799 else if (year < 100) {
800 year += 1900;
801 }
802 _currEpo.tt.set(year, month, day, hour, min, sec);
803
804 // Number of Satellites
805 // --------------------
806 int numSat;
807 readInt(line, 29, 3, numSat);
808
809 _currEpo.rnxSat.resize(numSat);
810
811 // Read Satellite Numbers
812 // ----------------------
813 int pos = 32;
814 for (int iSat = 0; iSat < numSat; iSat++) {
815 if (iSat > 0 && iSat % 12 == 0) {
816 line = _stream->readLine();
817 pos = 32;
818 }
819
820 char sys = line.toAscii()[pos];
821 int satNum; readInt(line, pos + 1, 2, satNum);
822 _currEpo.rnxSat[iSat].prn.set(sys, satNum);
823
824 pos += 3;
825 }
826
827 // Read Observation Records
828 // ------------------------
829 for (int iSat = 0; iSat < numSat; iSat++) {
830 char sys = _currEpo.rnxSat[iSat].prn.system();
831 line = _stream->readLine();
832 pos = 0;
833 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
834 if (iType > 0 && iType % 5 == 0) {
835 line = _stream->readLine();
836 pos = 0;
837 }
838 double obsValue = 0.0;
839 int lli = 0;
840 int snr = 0;
841 readDbl(line, pos, 14, obsValue);
842 readInt(line, pos + 14, 1, lli);
843 readInt(line, pos + 15, 1, snr);
844
845 if (_flgPowerFail) {
846 lli |= 1;
847 }
848
849 QString type = obsType(sys, iType);
850 _currEpo.rnxSat[iSat].obs[type].value = obsValue;
851 _currEpo.rnxSat[iSat].obs[type].lli = lli;
852 _currEpo.rnxSat[iSat].obs[type].snr = snr;
853
854 pos += 16;
855 }
856 }
857
858 _flgPowerFail = false;
859
860 return &_currEpo;
861 }
862
863 return 0;
864}
865
866// Write Data Epoch
867////////////////////////////////////////////////////////////////////////////
868void t_rnxObsFile::writeEpoch(const t_rnxEpo* epo) {
869 if (version() < 3.0) {
870 return writeEpochV2(_stream, _header, epo);
871 }
872 else {
873 return writeEpochV3(_stream, _header, epo);
874 }
875}
876
877// Write Data Epoch (RINEX Version 2)
878////////////////////////////////////////////////////////////////////////////
879void t_rnxObsFile::writeEpochV2(QTextStream* stream, const t_rnxObsHeader& header,
880 const t_rnxEpo* epo) {
881
882 unsigned year, month, day, hour, min;
883 double sec;
884 epo->tt.civil_date(year, month, day);
885 epo->tt.civil_time(hour, min, sec);
886
887 QString dateStr;
888 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
889 .arg(int(fmod(year, 100)), 2, 10, QChar('0'))
890 .arg(month, 2, 10, QChar('0'))
891 .arg(day, 2, 10, QChar('0'))
892 .arg(hour, 2, 10, QChar('0'))
893 .arg(min, 2, 10, QChar('0'))
894 .arg(sec, 11, 'f', 7);
895
896 int flag = 0;
897 *stream << dateStr << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
898 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
899 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
900 if (iSat > 0 && iSat % 12 == 0) {
901 *stream << endl << QString().leftJustified(32);
902 }
903 *stream << rnxSat.prn.toString().c_str();
904 }
905 *stream << endl;
906 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
907
908 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
909 char sys = rnxSat.prn.system();
910
911 for (int iTypeV2 = 0; iTypeV2 < header.nTypes(sys); iTypeV2++) {
912 if (iTypeV2 > 0 && iTypeV2 % 5 == 0) {
913 *stream << endl;
914 }
915 QString typeV2 = header.obsType(sys, iTypeV2);
916 bool found = false;
917
918 const QString preferredAttrib = "CWPX_";
919 for (int iPref = 0; iPref < preferredAttrib.length(); iPref++) {
920 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
921 while (itObs.hasNext()) {
922 itObs.next();
923 const QString& type = itObs.key();
924 const t_rnxObs& rnxObs = itObs.value();
925 if (typeV2 == type3to2(sys, type)) {
926 found = true;
927 if (rnxObs.value == 0.0) {
928 *stream << QString().leftJustified(16);
929 }
930 else {
931 *stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
932 if (rnxObs.lli != 0.0) {
933 *stream << QString("%1").arg(rnxObs.lli,1);
934 }
935 else {
936 *stream << ' ';
937 }
938 if (rnxObs.snr != 0.0) {
939 *stream << QString("%1").arg(rnxObs.snr,1);
940 }
941 else {
942 *stream << ' ';
943 }
944 }
945 break;
946 }
947 }
948 if (found) {
949 break;
950 }
951 }
952 if (!found) {
953 *stream << QString().leftJustified(16);
954 }
955 }
956 *stream << endl;
957 }
958}
959
960// Write Data Epoch (RINEX Version 3)
961////////////////////////////////////////////////////////////////////////////
962void t_rnxObsFile::writeEpochV3(QTextStream* stream, const t_rnxObsHeader& header,
963 const t_rnxEpo* epo) {
964
965 unsigned year, month, day, hour, min;
966 double sec;
967 epo->tt.civil_date(year, month, day);
968 epo->tt.civil_time(hour, min, sec);
969
970 QString dateStr;
971 QTextStream(&dateStr) << QString("> %1 %2 %3 %4 %5%6")
972 .arg(year, 4)
973 .arg(month, 2, 10, QChar('0'))
974 .arg(day, 2, 10, QChar('0'))
975 .arg(hour, 2, 10, QChar('0'))
976 .arg(min, 2, 10, QChar('0'))
977 .arg(sec, 11, 'f', 7);
978
979 int flag = 0;
980 *stream << dateStr << QString("%1%2\n").arg(flag, 3).arg(epo->rnxSat.size(), 3);
981
982 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
983 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
984 char sys = rnxSat.prn.system();
985
986 *stream << rnxSat.prn.toString().c_str();
987
988 for (int iTypeV3 = 0; iTypeV3 < header.nTypes(sys); iTypeV3++) {
989 QString typeV3 = header.obsType(sys, iTypeV3);
990 bool found = false;
991 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
992 while (itObs.hasNext()) {
993 itObs.next();
994 const QString& type = itObs.key();
995 const t_rnxObs& rnxObs = itObs.value();
996 if (typeV3 == type2to3(sys, type)) {
997 found = true;
998 if (rnxObs.value == 0.0) {
999 *stream << QString().leftJustified(16);
1000 }
1001 else {
1002 *stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
1003 if (rnxObs.lli != 0.0) {
1004 *stream << QString("%1").arg(rnxObs.lli,1);
1005 }
1006 else {
1007 *stream << ' ';
1008 }
1009 if (rnxObs.snr != 0.0) {
1010 *stream << QString("%1").arg(rnxObs.snr,1);
1011 }
1012 else {
1013 *stream << ' ';
1014 }
1015 }
1016 }
1017 }
1018 if (!found) {
1019 *stream << QString().leftJustified(16);
1020 }
1021 }
1022 *stream << endl;
1023 }
1024}
1025
1026// Translate Observation Type v2 --> v3
1027////////////////////////////////////////////////////////////////////////////
1028QString t_rnxObsFile::type2to3(char sys, const QString& typeV2) {
1029 if (typeV2 == "P1") {
1030 return (sys == 'G') ? "C1W" : "C1P";
1031 }
1032 else if (typeV2 == "P2") {
1033 return (sys == 'G') ? "C2W" : "C2P";
1034 }
1035 return typeV2;
1036}
1037
1038// Translate Observation Type v3 --> v2
1039////////////////////////////////////////////////////////////////////////////
1040QString t_rnxObsFile::type3to2(char /* sys */, const QString& typeV3) {
1041 if (typeV3 == "C1P" || typeV3 == "C1W") {
1042 return "P1";
1043 }
1044 else if (typeV3 == "C2P" || typeV3 == "C2W") {
1045 return "P2";
1046 }
1047 return typeV3.left(2);
1048}
1049
1050// Set Observations from RINEX File
1051////////////////////////////////////////////////////////////////////////////
1052void t_rnxObsFile::setObsFromRnx(const t_rnxObsFile* rnxObsFile, const t_rnxObsFile::t_rnxEpo* epo,
1053 const t_rnxObsFile::t_rnxSat& rnxSat, t_satObs& obs) {
1054
1055 obs._staID = rnxObsFile->markerName().toAscii().constData();
1056 obs._prn = rnxSat.prn;
1057 obs._time = epo->tt;
1058
1059 char sys = rnxSat.prn.system();
1060
1061 for (int iType = 0; iType < rnxObsFile->nTypes(sys); iType++) {
1062 QString type = rnxObsFile->obsType(sys, iType);
1063 if (rnxSat.obs.contains(type)) {
1064 const t_rnxObs& rnxObs = rnxSat.obs[type];
1065 if (rnxObs.value != 0.0) {
1066 string type2ch(type.mid(1).toAscii().data());
1067
1068 t_frqObs* frqObs = 0;
1069 for (unsigned iFrq = 0; iFrq < obs._obs.size(); iFrq++) {
1070 if (obs._obs[iFrq]->_rnxType2ch == type2ch) {
1071 frqObs = obs._obs[iFrq];
1072 break;
1073 }
1074 }
1075 if (frqObs == 0) {
1076 frqObs = new t_frqObs;
1077 frqObs->_rnxType2ch = type2ch;
1078 obs._obs.push_back(frqObs);
1079 }
1080
1081 switch( type.toAscii().data()[0] ) {
1082 case 'C':
1083 frqObs->_codeValid = true;
1084 frqObs->_code = rnxObs.value;
1085 break;
1086 case 'L':
1087 frqObs->_phaseValid = true;
1088 frqObs->_phase = rnxObs.value;
1089 frqObs->_slip = (rnxObs.lli & 1);
1090 break;
1091 case 'D':
1092 frqObs->_dopplerValid = true;
1093 frqObs->_doppler = rnxObs.value;
1094 break;
1095 case 'S':
1096 frqObs->_snrValid = true;
1097 frqObs->_snr = rnxObs.value;
1098 break;
1099 }
1100 }
1101 }
1102 }
1103}
1104
Note: See TracBrowser for help on using the repository browser.