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

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