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

Last change on this file since 6587 was 6587, checked in by mervart, 9 years ago
File size: 36.0 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 _usedSystems = "GREJCS";
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 = _usedSystems[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 < _usedSystems.length(); ii++) {
180 char sysI = _usedSystems[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 if (sys == 'C') {
202 hlp.replace('2', '1');
203 }
204 _obsTypes[sys].push_back(hlp);
205 }
206 delete in;
207 }
208 else if (key == "TIME OF FIRST OBS") {
209 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
210 int year, month, day, hour, min;
211 double sec;
212 in >> year >> month >> day >> hour >> min >> sec;
213 _startTime.set(year, month, day, hour, min, sec);
214 }
215 if (maxLines > 0 && numLines == maxLines) {
216 break;
217 }
218 }
219
220 // Systems used
221 // ------------
222 _usedSystems.clear();
223 QMapIterator<char, QStringList> it(_obsTypes);
224 while (it.hasNext()) {
225 it.next();
226 _usedSystems += QChar(it.key());
227 }
228
229 return success;
230}
231
232// Set Default Header
233////////////////////////////////////////////////////////////////////////////
234void t_rnxObsHeader::setDefault(const QString& markerName, int version) {
235
236 _markerName = markerName;
237
238 if (version <= 2) {
239 _version = t_rnxObsHeader::defaultRnxObsVersion2;
240 }
241 else {
242 _version = t_rnxObsHeader::defaultRnxObsVersion3;
243 }
244
245 _comments << "Default set of observation types used";
246
247 _obsTypes.clear();
248 if (_version < 3.0) {
249 _obsTypes['G'] << "C1" << "P1" << "L1" << "S1"
250 << "C2" << "P2" << "L2" << "S2";
251 _obsTypes['R'] = _obsTypes['G'];
252 _obsTypes['E'] = _obsTypes['G'];
253 _obsTypes['J'] = _obsTypes['G'];
254 _obsTypes['S'] = _obsTypes['G'];
255 _obsTypes['C'] = _obsTypes['G'];
256 }
257 else {
258 _obsTypes['G'] << "C1C" << "L1C" << "S1C"
259 << "C2W" << "L2W" << "S2W"
260 << "C5" << "L5" << "S5";
261
262 _obsTypes['J'] = _obsTypes['G'];
263
264 _obsTypes['R'] << "C1C" << "L1C" << "S1C"
265 << "C2P" << "L2P" << "S2P";
266
267 _obsTypes['E'] << "C1" << "L1" << "S1"
268 << "C5" << "L5" << "S5"
269 << "C7" << "L7" << "S7"
270 << "C8" << "L8" << "S8";
271
272 _obsTypes['S'] << "C1" << "L1" << "S1"
273 << "C5" << "L5" << "S5";
274
275 _obsTypes['C'] << "C1" << "L1" << "S1"
276 << "C6" << "L6" << "S6"
277 << "C7" << "L7" << "S7";
278 }
279}
280
281// Copy header
282////////////////////////////////////////////////////////////////////////////
283void t_rnxObsHeader::set(const t_rnxObsHeader& header, int version,
284 const QStringList* useObsTypes) {
285
286 if (version <= 2) {
287 _version = t_rnxObsHeader::defaultRnxObsVersion2;
288 }
289 else {
290 _version = t_rnxObsHeader::defaultRnxObsVersion3;
291 }
292 _interval = header._interval;
293 _antennaNumber = header._antennaNumber;
294 _antennaName = header._antennaName;
295 _markerName = header._markerName;
296 _markerNumber = header._markerNumber;
297 _antNEU = header._antNEU;
298 _antXYZ = header._antXYZ;
299 _antBSG = header._antBSG;
300 _xyz = header._xyz;
301 _observer = header._observer;
302 _agency = header._agency;
303 _receiverNumber = header._receiverNumber;
304 _receiverType = header._receiverType;
305 _receiverVersion = header._receiverVersion;
306 _startTime = header._startTime;
307 _comments = header._comments;
308 _usedSystems = header._usedSystems;
309 for (unsigned iPrn = 1; iPrn <= t_prn::MAXPRN_GPS; iPrn++) {
310 _wlFactorsL1[iPrn] = header._wlFactorsL1[iPrn];
311 _wlFactorsL2[iPrn] = header._wlFactorsL2[iPrn];
312 }
313
314 // Set observation types
315 // ---------------------
316 _obsTypes.clear();
317 if (!useObsTypes || useObsTypes->size() == 0) {
318 if (int(_version) == int(header._version)) {
319 _obsTypes = header._obsTypes;
320 }
321 else {
322 if (_version >= 3.0) {
323 for (int iSys = 0; iSys < header.numSys(); iSys++) {
324 char sys = header.system(iSys);
325 for (int iType = 0; iType < header.nTypes(sys); iType++) {
326 QString type = header.obsType(sys, iType, _version);
327 if (!_obsTypes[sys].contains(type)) {
328 _obsTypes[sys].push_back(type);
329 }
330 }
331 }
332 }
333 else {
334 for (int iSys = 0; iSys < header.numSys(); iSys++) {
335 char sys = header.system(iSys);
336 for (int iType = 0; iType < header.nTypes(sys); iType++) {
337 QString type = header.obsType(sys, iType, _version);
338 for (int jSys = 0; jSys < _usedSystems.length(); jSys++) {
339 char thisSys = _usedSystems[jSys].toAscii();
340 if (!_obsTypes[thisSys].contains(type)) {
341 _obsTypes[thisSys].push_back(type);
342 }
343 }
344 }
345 }
346 }
347 }
348 }
349 else {
350 for (int iType = 0; iType < useObsTypes->size(); iType++) {
351 if (useObsTypes->at(iType).indexOf(":") != -1) {
352 QStringList hlp = useObsTypes->at(iType).split(":", QString::SkipEmptyParts);
353 if (hlp.size() == 2 && hlp[0].length() == 1) {
354 if (_version >= 3.0) {
355 char sys = hlp[0][0].toAscii();
356 QString type = t_rnxObsFile::type2to3(sys, hlp[1]);
357 if (!_obsTypes[sys].contains(type)) {
358 _obsTypes[sys].push_back(type);
359 }
360 }
361 else {
362 for (int iSys = 0; iSys < _usedSystems.length(); iSys++) {
363 char sys = _usedSystems[iSys].toAscii();
364 QString type = t_rnxObsFile::type3to2(sys, hlp[1]);
365 if (!_obsTypes[sys].contains(type)) {
366 _obsTypes[sys].push_back(type);
367 }
368 }
369 }
370 }
371 }
372 else {
373 for (int iSys = 0; iSys < _usedSystems.length(); iSys++) {
374 char sys = _usedSystems[iSys].toAscii();
375 QString type = _version >= 3.0 ? t_rnxObsFile::type2to3(sys, useObsTypes->at(iType)) :
376 t_rnxObsFile::type3to2(sys, useObsTypes->at(iType));
377 if (!_obsTypes[sys].contains(type)) {
378 _obsTypes[sys].push_back(type);
379 }
380 }
381 }
382 }
383 _usedSystems.clear();
384 QMapIterator<char, QStringList> it(_obsTypes);
385 while (it.hasNext()) {
386 it.next();
387 _usedSystems += QChar(it.key());
388 }
389 }
390}
391
392// Write Header
393////////////////////////////////////////////////////////////////////////////
394void t_rnxObsHeader::write(QTextStream* stream,
395 const QMap<QString, QString>* txtMap) const {
396
397 QStringList newComments;
398 QString runBy = BNC_CORE->userName();
399
400 if (txtMap) {
401 QMapIterator<QString, QString> it(*txtMap);
402 while (it.hasNext()) {
403 it.next();
404 if (it.key() == "RUN BY") {
405 runBy = it.value();
406 }
407 else if (it.key() == "COMMENT") {
408 newComments = it.value().split("\\n", QString::SkipEmptyParts);
409 }
410 }
411 }
412
413 *stream << QString("%1 Observation data Mixed")
414 .arg(_version, 9, 'f', 2)
415 .leftJustified(60)
416 << "RINEX VERSION / TYPE\n";
417
418 const QString fmtDate = (_version < 3.0) ? "dd-MMM-yy hh:mm"
419 : "yyyyMMdd hhmmss UTC";
420 *stream << QString("%1%2%3")
421 .arg(BNC_CORE->pgmName(), -20)
422 .arg(runBy.trimmed().left(20), -20)
423 .arg(QDateTime::currentDateTime().toUTC().toString(fmtDate), -20)
424 .leftJustified(60)
425 << "PGM / RUN BY / DATE\n";
426
427 QStringListIterator itCmnt(_comments + newComments);
428 while (itCmnt.hasNext()) {
429 *stream << itCmnt.next().trimmed().left(60).leftJustified(60) << "COMMENT\n";
430 }
431
432 *stream << QString("%1")
433 .arg(_markerName, -60)
434 .leftJustified(60)
435 << "MARKER NAME\n";
436
437 if (!_markerNumber.isEmpty()) {
438 *stream << QString("%1")
439 .arg(_markerNumber, -20)
440 .leftJustified(60)
441 << "MARKER NUMBER\n";
442 }
443
444 *stream << QString("%1%2")
445 .arg(_observer, -20)
446 .arg(_agency, -40)
447 .leftJustified(60)
448 << "OBSERVER / AGENCY\n";
449
450 *stream << QString("%1%2%3")
451 .arg(_receiverNumber, -20)
452 .arg(_receiverType, -20)
453 .arg(_receiverVersion, -20)
454 .leftJustified(60)
455 << "REC # / TYPE / VERS\n";
456
457 *stream << QString("%1%2")
458 .arg(_antennaNumber, -20)
459 .arg(_antennaName, -20)
460 .leftJustified(60)
461 << "ANT # / TYPE\n";
462
463 *stream << QString("%1%2%3")
464 .arg(_xyz(1), 14, 'f', 4)
465 .arg(_xyz(2), 14, 'f', 4)
466 .arg(_xyz(3), 14, 'f', 4)
467 .leftJustified(60)
468 << "APPROX POSITION XYZ\n";
469
470 *stream << QString("%1%2%3")
471 .arg(_antNEU(3), 14, 'f', 4)
472 .arg(_antNEU(2), 14, 'f', 4)
473 .arg(_antNEU(1), 14, 'f', 4)
474 .leftJustified(60)
475 << "ANTENNA: DELTA H/E/N\n";
476
477 if (_version < 3.0) {
478 int defaultWlFact1 = _wlFactorsL1[1];
479 int defaultWlFact2 = _wlFactorsL2[1]; // TODO check all prns
480 *stream << QString("%1%2")
481 .arg(defaultWlFact1, 6)
482 .arg(defaultWlFact2, 6)
483 .leftJustified(60)
484 << "WAVELENGTH FACT L1/2\n";
485 }
486
487 *stream << obsTypesStrings().join("");
488
489 if (_interval > 0) {
490 *stream << QString("%1")
491 .arg(_interval, 10, 'f', 3)
492 .leftJustified(60)
493 << "INTERVAL\n";
494 }
495
496 unsigned year, month, day, hour, min;
497 double sec;
498 _startTime.civil_date(year, month, day);
499 _startTime.civil_time(hour, min, sec);
500 *stream << QString("%1%2%3%4%5%6%7")
501 .arg(year, 6)
502 .arg(month, 6)
503 .arg(day, 6)
504 .arg(hour, 6)
505 .arg(min, 6)
506 .arg(sec, 13, 'f', 7)
507 .arg("GPS", 8)
508 .leftJustified(60)
509 << "TIME OF FIRST OBS\n";
510
511 *stream << QString()
512 .leftJustified(60)
513 << "END OF HEADER\n";
514}
515
516// Number of Different Systems
517////////////////////////////////////////////////////////////////////////////
518int t_rnxObsHeader::numSys() const {
519 return _obsTypes.size();
520}
521
522//
523////////////////////////////////////////////////////////////////////////////
524char t_rnxObsHeader::system(int iSys) const {
525 int iSysLocal = -1;
526 QMapIterator<char, QStringList> it(_obsTypes);
527 while (it.hasNext()) {
528 ++iSysLocal;
529 it.next();
530 if (iSysLocal == iSys) {
531 return it.key();
532 }
533 }
534 return ' ';
535}
536
537// Number of Observation Types (satellite-system specific)
538////////////////////////////////////////////////////////////////////////////
539int t_rnxObsHeader::nTypes(char sys) const {
540 if (_obsTypes.contains(sys)) {
541 return _obsTypes[sys].size();
542 }
543 else {
544 return 0;
545 }
546}
547
548// Observation Type (satellite-system specific)
549////////////////////////////////////////////////////////////////////////////
550QString t_rnxObsHeader::obsType(char sys, int index, double version) const {
551
552 if (version == 0.0) {
553 version = _version;
554 }
555 if (_obsTypes.contains(sys)) {
556 QString origType = _obsTypes[sys].at(index);
557 if (int(version) == int(_version)) {
558 return origType;
559 }
560 else if (int(version) == 2) {
561 return t_rnxObsFile::type3to2(sys, origType);
562 }
563 else if (int(version) == 3) {
564 return t_rnxObsFile::type2to3(sys, origType);
565 }
566 }
567 return "";
568}
569
570// Write Observation Types
571////////////////////////////////////////////////////////////////////////////
572QStringList t_rnxObsHeader::obsTypesStrings() const {
573
574 QStringList strList;
575
576 if (_version < 3.0) {
577 char sys0 = _usedSystems[0].toAscii();
578 QString hlp;
579 QTextStream(&hlp) << QString("%1").arg(_obsTypes[sys0].size(), 6);
580 for (int ii = 0; ii < _obsTypes[sys0].size(); ii++) {
581 QTextStream(&hlp) << QString("%1").arg(_obsTypes[sys0][ii], 6);
582 if ((ii+1) % 9 == 0 || ii == _obsTypes[sys0].size()-1) {
583 strList.append(hlp.leftJustified(60) + "# / TYPES OF OBSERV\n");
584 hlp = QString().leftJustified(6);
585 }
586 }
587 }
588 else {
589 for (int iSys = 0; iSys < numSys(); iSys++) {
590 char sys = system(iSys);
591 QString hlp;
592 QTextStream(&hlp) << QString("%1 %2").arg(sys).arg(nTypes(sys), 3);
593 for (int iType = 0; iType < nTypes(sys); iType++) {
594 QString type = obsType(sys, iType);
595 QTextStream(&hlp) << QString(" %1").arg(type, -3);
596 if ((iType+1) % 13 == 0 || iType == nTypes(sys)-1) {
597 strList.append(hlp.leftJustified(60) + "SYS / # / OBS TYPES\n");
598 hlp = QString().leftJustified(6);
599 }
600 }
601 }
602 }
603
604 return strList;
605}
606
607// Constructor
608////////////////////////////////////////////////////////////////////////////
609t_rnxObsFile::t_rnxObsFile(const QString& fileName, e_inpOut inpOut) {
610 _inpOut = inpOut;
611 _stream = 0;
612 _flgPowerFail = false;
613 if (_inpOut == input) {
614 openRead(fileName);
615 }
616 else {
617 openWrite(fileName);
618 }
619}
620
621// Open for input
622////////////////////////////////////////////////////////////////////////////
623void t_rnxObsFile::openRead(const QString& fileName) {
624
625 _fileName = fileName; expandEnvVar(_fileName);
626 _file = new QFile(_fileName);
627 _file->open(QIODevice::ReadOnly | QIODevice::Text);
628 _stream = new QTextStream();
629 _stream->setDevice(_file);
630
631 _header.read(_stream);
632
633 // Guess Observation Interval
634 // --------------------------
635 if (_header._interval == 0.0) {
636 bncTime ttPrev;
637 for (int iEpo = 0; iEpo < 10; iEpo++) {
638 const t_rnxEpo* rnxEpo = nextEpoch();
639 if (!rnxEpo) {
640 throw QString("t_rnxObsFile: not enough epochs");
641 }
642 if (iEpo > 0) {
643 double dt = rnxEpo->tt - ttPrev;
644 if (_header._interval == 0.0 || dt < _header._interval) {
645 _header._interval = dt;
646 }
647 }
648 ttPrev = rnxEpo->tt;
649 }
650 _stream->seek(0);
651 _header.read(_stream);
652 }
653
654 // Time of first observation
655 // -------------------------
656 if (!_header._startTime.valid()) {
657 const t_rnxEpo* rnxEpo = nextEpoch();
658 if (!rnxEpo) {
659 throw QString("t_rnxObsFile: not enough epochs");
660 }
661 _header._startTime = rnxEpo->tt;
662 _stream->seek(0);
663 _header.read(_stream);
664 }
665}
666
667// Open for output
668////////////////////////////////////////////////////////////////////////////
669void t_rnxObsFile::openWrite(const QString& fileName) {
670
671 _fileName = fileName; expandEnvVar(_fileName);
672 _file = new QFile(_fileName);
673 _file->open(QIODevice::WriteOnly | QIODevice::Text);
674 _stream = new QTextStream();
675 _stream->setDevice(_file);
676}
677
678// Destructor
679////////////////////////////////////////////////////////////////////////////
680t_rnxObsFile::~t_rnxObsFile() {
681 close();
682}
683
684// Close
685////////////////////////////////////////////////////////////////////////////
686void t_rnxObsFile::close() {
687 delete _stream; _stream = 0;
688 delete _file; _file = 0;
689}
690
691// Handle Special Epoch Flag
692////////////////////////////////////////////////////////////////////////////
693void t_rnxObsFile::handleEpochFlag(int flag, const QString& line,
694 bool& headerReRead) {
695
696 headerReRead = false;
697
698 // Power Failure
699 // -------------
700 if (flag == 1) {
701 _flgPowerFail = true;
702 }
703
704 // Start moving antenna
705 // --------------------
706 else if (flag == 2) {
707 // no action
708 }
709
710 // Re-Read Header
711 // --------------
712 else if (flag == 3 || flag == 4 || flag == 5) {
713 int numLines = 0;
714 if (version() < 3.0) {
715 readInt(line, 29, 3, numLines);
716 }
717 else {
718 readInt(line, 32, 3, numLines);
719 }
720 if (flag == 3 || flag == 4) {
721 _header.read(_stream, numLines);
722 headerReRead = true;
723 }
724 else {
725 for (int ii = 0; ii < numLines; ii++) {
726 _stream->readLine();
727 }
728 }
729 }
730
731 // Unhandled Flag
732 // --------------
733 else {
734 throw QString("t_rnxObsFile: unhandled flag\n" + line);
735 }
736}
737
738// Retrieve single Epoch
739////////////////////////////////////////////////////////////////////////////
740t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpoch() {
741 _currEpo.clear();
742 if (version() < 3.0) {
743 return nextEpochV2();
744 }
745 else {
746 return nextEpochV3();
747 }
748}
749
750// Retrieve single Epoch (RINEX Version 3)
751////////////////////////////////////////////////////////////////////////////
752t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV3() {
753
754 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
755
756 QString line = _stream->readLine();
757
758 if (line.isEmpty()) {
759 continue;
760 }
761
762 int flag = 0;
763 readInt(line, 31, 1, flag);
764 if (flag > 0) {
765 bool headerReRead = false;
766 handleEpochFlag(flag, line, headerReRead);
767 if (headerReRead) {
768 continue;
769 }
770 }
771
772 QTextStream in(line.mid(1).toAscii(), QIODevice::ReadOnly);
773
774 // Epoch Time
775 // ----------
776 int year, month, day, hour, min;
777 double sec;
778 in >> year >> month >> day >> hour >> min >> sec;
779 _currEpo.tt.set(year, month, day, hour, min, sec);
780
781 // Number of Satellites
782 // --------------------
783 int numSat;
784 readInt(line, 32, 3, numSat);
785
786 _currEpo.rnxSat.resize(numSat);
787
788 // Observations
789 // ------------
790 for (int iSat = 0; iSat < numSat; iSat++) {
791 line = _stream->readLine();
792 t_prn prn; prn.set(line.left(3).toAscii().data());
793 _currEpo.rnxSat[iSat].prn = prn;
794 char sys = prn.system();
795 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
796 int pos = 3 + 16*iType;
797 double obsValue = 0.0;
798 int lli = 0;
799 int snr = 0;
800 readDbl(line, pos, 14, obsValue);
801 readInt(line, pos + 14, 1, lli);
802 readInt(line, pos + 15, 1, snr);
803 if (_flgPowerFail) {
804 lli |= 1;
805 }
806 QString type = obsType(sys, iType);
807 _currEpo.rnxSat[iSat].obs[type].value = obsValue;
808 _currEpo.rnxSat[iSat].obs[type].lli = lli;
809 _currEpo.rnxSat[iSat].obs[type].snr = snr;
810 }
811 }
812
813 _flgPowerFail = false;
814
815 return &_currEpo;
816 }
817
818 return 0;
819}
820
821// Retrieve single Epoch (RINEX Version 2)
822////////////////////////////////////////////////////////////////////////////
823t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV2() {
824
825 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
826
827 QString line = _stream->readLine();
828
829 if (line.isEmpty()) {
830 continue;
831 }
832
833 int flag = 0;
834 readInt(line, 28, 1, flag);
835 if (flag > 0) {
836 bool headerReRead = false;
837 handleEpochFlag(flag, line, headerReRead);
838 if (headerReRead) {
839 continue;
840 }
841 }
842
843 QTextStream in(line.toAscii(), QIODevice::ReadOnly);
844
845 // Epoch Time
846 // ----------
847 int year, month, day, hour, min;
848 double sec;
849 in >> year >> month >> day >> hour >> min >> sec;
850 if (year < 80) {
851 year += 2000;
852 }
853 else if (year < 100) {
854 year += 1900;
855 }
856 _currEpo.tt.set(year, month, day, hour, min, sec);
857
858 // Number of Satellites
859 // --------------------
860 int numSat;
861 readInt(line, 29, 3, numSat);
862
863 _currEpo.rnxSat.resize(numSat);
864
865 // Read Satellite Numbers
866 // ----------------------
867 int pos = 32;
868 for (int iSat = 0; iSat < numSat; iSat++) {
869 if (iSat > 0 && iSat % 12 == 0) {
870 line = _stream->readLine();
871 pos = 32;
872 }
873
874 char sys = line.toAscii()[pos];
875 if (sys == ' ') {
876 sys = 'G';
877 }
878 int satNum; readInt(line, pos + 1, 2, satNum);
879 _currEpo.rnxSat[iSat].prn.set(sys, satNum);
880
881 pos += 3;
882 }
883
884 // Read Observation Records
885 // ------------------------
886 for (int iSat = 0; iSat < numSat; iSat++) {
887 char sys = _currEpo.rnxSat[iSat].prn.system();
888 line = _stream->readLine();
889 pos = 0;
890 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
891 if (iType > 0 && iType % 5 == 0) {
892 line = _stream->readLine();
893 pos = 0;
894 }
895 double obsValue = 0.0;
896 int lli = 0;
897 int snr = 0;
898 readDbl(line, pos, 14, obsValue);
899 readInt(line, pos + 14, 1, lli);
900 readInt(line, pos + 15, 1, snr);
901
902 if (_flgPowerFail) {
903 lli |= 1;
904 }
905
906 QString type = obsType(sys, iType);
907 _currEpo.rnxSat[iSat].obs[type].value = obsValue;
908 _currEpo.rnxSat[iSat].obs[type].lli = lli;
909 _currEpo.rnxSat[iSat].obs[type].snr = snr;
910
911 pos += 16;
912 }
913 }
914
915 _flgPowerFail = false;
916
917 return &_currEpo;
918 }
919
920 return 0;
921}
922
923// Write Data Epoch
924////////////////////////////////////////////////////////////////////////////
925void t_rnxObsFile::writeEpoch(const t_rnxEpo* epo) {
926 if (epo == 0) {
927 return;
928 }
929 t_rnxEpo epoLocal;
930 epoLocal.tt = epo->tt;
931 for (unsigned ii = 0; ii < epo->rnxSat.size(); ii++) {
932 const t_rnxSat& rnxSat = epo->rnxSat[ii];
933 if (_header._obsTypes[rnxSat.prn.system()].size() > 0) {
934 epoLocal.rnxSat.push_back(rnxSat);
935 }
936 }
937
938 if (version() < 3.0) {
939 return writeEpochV2(_stream, _header, &epoLocal);
940 }
941 else {
942 return writeEpochV3(_stream, _header, &epoLocal);
943 }
944}
945
946// Write Data Epoch (RINEX Version 2)
947////////////////////////////////////////////////////////////////////////////
948void t_rnxObsFile::writeEpochV2(QTextStream* stream, const t_rnxObsHeader& header,
949 const t_rnxEpo* epo) {
950
951 unsigned year, month, day, hour, min;
952 double sec;
953 epo->tt.civil_date(year, month, day);
954 epo->tt.civil_time(hour, min, sec);
955
956 QString dateStr;
957 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
958 .arg(int(fmod(year, 100)), 2, 10, QChar('0'))
959 .arg(month, 2, 10, QChar('0'))
960 .arg(day, 2, 10, QChar('0'))
961 .arg(hour, 2, 10, QChar('0'))
962 .arg(min, 2, 10, QChar('0'))
963 .arg(sec, 11, 'f', 7);
964
965 int flag = 0;
966 *stream << dateStr << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
967 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
968 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
969 if (iSat > 0 && iSat % 12 == 0) {
970 *stream << endl << QString().leftJustified(32);
971 }
972 *stream << rnxSat.prn.toString().c_str();
973 }
974 *stream << endl;
975 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
976
977 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
978 char sys = rnxSat.prn.system();
979
980 for (int iTypeV2 = 0; iTypeV2 < header.nTypes(sys); iTypeV2++) {
981 if (iTypeV2 > 0 && iTypeV2 % 5 == 0) {
982 *stream << endl;
983 }
984 QString typeV2 = header.obsType(sys, iTypeV2);
985 bool found = false;
986
987 QString preferredAttrib = signalPriorities(sys);
988 for (int iPref = 0; iPref < preferredAttrib.length(); iPref++) {
989 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
990 while (itObs.hasNext()) {
991 itObs.next();
992 const QString& type = itObs.key();
993 const t_rnxObs& rnxObs = itObs.value();
994 if ( preferredAttrib[iPref] == '?' ||
995 (type.length() == 2 && preferredAttrib[iPref] == '_' ) ||
996 (type.length() == 3 && preferredAttrib[iPref] == type[2]) ) {
997 if (typeV2 == type3to2(sys, type)) {
998 found = true;
999 if (rnxObs.value == 0.0) {
1000 *stream << QString().leftJustified(16);
1001 }
1002 else {
1003 *stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
1004 if (rnxObs.lli != 0.0) {
1005 *stream << QString("%1").arg(rnxObs.lli,1);
1006 }
1007 else {
1008 *stream << ' ';
1009 }
1010 if (rnxObs.snr != 0.0) {
1011 *stream << QString("%1").arg(rnxObs.snr,1);
1012 }
1013 else {
1014 *stream << ' ';
1015 }
1016 }
1017 goto end_loop_iPref;
1018 }
1019 }
1020 }
1021 } end_loop_iPref:
1022 if (!found) {
1023 *stream << QString().leftJustified(16);
1024 }
1025 }
1026 *stream << endl;
1027 }
1028}
1029
1030// Write Data Epoch (RINEX Version 3)
1031////////////////////////////////////////////////////////////////////////////
1032void t_rnxObsFile::writeEpochV3(QTextStream* stream, const t_rnxObsHeader& header,
1033 const t_rnxEpo* epo) {
1034
1035 unsigned year, month, day, hour, min;
1036 double sec;
1037 epo->tt.civil_date(year, month, day);
1038 epo->tt.civil_time(hour, min, sec);
1039
1040 QString dateStr;
1041 QTextStream(&dateStr) << QString("> %1 %2 %3 %4 %5%6")
1042 .arg(year, 4)
1043 .arg(month, 2, 10, QChar('0'))
1044 .arg(day, 2, 10, QChar('0'))
1045 .arg(hour, 2, 10, QChar('0'))
1046 .arg(min, 2, 10, QChar('0'))
1047 .arg(sec, 11, 'f', 7);
1048
1049 int flag = 0;
1050 *stream << dateStr << QString("%1%2\n").arg(flag, 3).arg(epo->rnxSat.size(), 3);
1051
1052 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
1053 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
1054 char sys = rnxSat.prn.system();
1055 bool sysFound = false;
1056
1057 const t_rnxObs* hlp[header.nTypes(sys)];
1058 for (int iTypeV3 = 0; iTypeV3 < header.nTypes(sys); iTypeV3++) {
1059 hlp[iTypeV3] = 0;
1060 QString typeV3 = header.obsType(sys, iTypeV3);
1061 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
1062
1063 // Exact match
1064 // -----------
1065 while (itObs.hasNext()) {
1066 itObs.next();
1067 const QString& type = itObs.key();
1068 const t_rnxObs& rnxObs = itObs.value();
1069 if (typeV3 == type2to3(sys, type) && rnxObs.value != 0.0) {
1070 hlp[iTypeV3] = &itObs.value();
1071 sysFound = true;
1072 }
1073 }
1074
1075 // Non-Exact match
1076 // ---------------
1077 itObs.toFront();
1078 while (itObs.hasNext()) {
1079 itObs.next();
1080 const QString& type = itObs.key();
1081 const t_rnxObs& rnxObs = itObs.value();
1082 if (hlp[iTypeV3] == 0 && typeV3 == type2to3(sys, type).left(2) && rnxObs.value != 0.0) {
1083 hlp[iTypeV3] = &itObs.value();
1084 sysFound = true;
1085 }
1086 }
1087 }
1088
1089 if (!sysFound) {
1090 continue;
1091 }
1092
1093 *stream << rnxSat.prn.toString().c_str();
1094
1095 for (int iTypeV3 = 0; iTypeV3 < header.nTypes(sys); iTypeV3++) {
1096 const t_rnxObs* rnxObs = hlp[iTypeV3];
1097 if (rnxObs == 0) {
1098 *stream << QString().leftJustified(16);
1099 }
1100 else {
1101 *stream << QString("%1").arg(rnxObs->value, 14, 'f', 3);
1102 if (rnxObs->lli != 0.0) {
1103 *stream << QString("%1").arg(rnxObs->lli,1);
1104 }
1105 else {
1106 *stream << ' ';
1107 }
1108 if (rnxObs->snr != 0.0) {
1109 *stream << QString("%1").arg(rnxObs->snr,1);
1110 }
1111 else {
1112 *stream << ' ';
1113 }
1114 }
1115 }
1116 *stream << endl;
1117 }
1118}
1119
1120// Translate Observation Type v2 --> v3
1121////////////////////////////////////////////////////////////////////////////
1122QString t_rnxObsFile::type2to3(char sys, const QString& typeV2) {
1123 if (typeV2 == "P1") {
1124 return (sys == 'G') ? "C1W" : "C1P";
1125 }
1126 else if (typeV2 == "P2") {
1127 return (sys == 'G') ? "C2W" : "C2P";
1128 }
1129 return typeV2;
1130}
1131
1132// Translate Observation Type v3 --> v2
1133////////////////////////////////////////////////////////////////////////////
1134QString t_rnxObsFile::type3to2(char /* sys */, const QString& typeV3) {
1135 if (typeV3 == "C1P" || typeV3 == "C1W") {
1136 return "P1";
1137 }
1138 else if (typeV3 == "C2P" || typeV3 == "C2W") {
1139 return "P2";
1140 }
1141 return typeV3.left(2);
1142}
1143
1144// Set Observations from RINEX File
1145////////////////////////////////////////////////////////////////////////////
1146void t_rnxObsFile::setObsFromRnx(const t_rnxObsFile* rnxObsFile, const t_rnxObsFile::t_rnxEpo* epo,
1147 const t_rnxObsFile::t_rnxSat& rnxSat, t_satObs& obs) {
1148 obs._staID = rnxObsFile->markerName().toAscii().constData();
1149 obs._prn = rnxSat.prn;
1150 obs._time = epo->tt;
1151
1152 char sys = rnxSat.prn.system();
1153
1154 QChar addToL2;
1155 for (int iType = 0; iType < rnxObsFile->nTypes(sys); iType++) {
1156 QString type = rnxObsFile->obsType(sys, iType);
1157 QString typeV3 = rnxObsFile->obsType(sys, iType, 3.0); // may or may not differ from type
1158 if (rnxSat.obs.contains(type) && rnxSat.obs[type].value != 0.0) {
1159 if (type == "P2" && typeV3.length() > 2) {
1160 addToL2 = typeV3[2];
1161 break;
1162 }
1163 }
1164 }
1165
1166 for (int iType = 0; iType < rnxObsFile->nTypes(sys); iType++) {
1167 QString type = rnxObsFile->obsType(sys, iType);
1168 QString typeV3 = rnxObsFile->obsType(sys, iType, 3.0); // may or may not differ from type
1169 if (type == "L2") {
1170 typeV3 += addToL2;
1171 }
1172 if (rnxSat.obs.contains(type)) {
1173 const t_rnxObs& rnxObs = rnxSat.obs[type];
1174 if (rnxObs.value != 0.0) {
1175 string type2ch(typeV3.mid(1).toAscii().data());
1176
1177 t_frqObs* frqObs = 0;
1178 for (unsigned iFrq = 0; iFrq < obs._obs.size(); iFrq++) {
1179 if (obs._obs[iFrq]->_rnxType2ch == type2ch) {
1180 frqObs = obs._obs[iFrq];
1181 break;
1182 }
1183 }
1184 if (frqObs == 0) {
1185 frqObs = new t_frqObs;
1186 frqObs->_rnxType2ch = type2ch;
1187 obs._obs.push_back(frqObs);
1188 }
1189
1190 switch( typeV3.toAscii().data()[0] ) {
1191 case 'C':
1192 frqObs->_codeValid = true;
1193 frqObs->_code = rnxObs.value;
1194 break;
1195 case 'L':
1196 frqObs->_phaseValid = true;
1197 frqObs->_phase = rnxObs.value;
1198 frqObs->_slip = (rnxObs.lli & 1);
1199 break;
1200 case 'D':
1201 frqObs->_dopplerValid = true;
1202 frqObs->_doppler = rnxObs.value;
1203 break;
1204 case 'S':
1205 frqObs->_snrValid = true;
1206 frqObs->_snr = rnxObs.value;
1207 break;
1208 }
1209
1210 // Handle old-fashioned SNR values
1211 // -------------------------------
1212 if (rnxObs.snr != 0 && !frqObs->_snrValid) {
1213 frqObs->_snrValid = true;
1214 frqObs->_snr = rnxObs.snr * 6.0 + 2.5;
1215 }
1216 }
1217 }
1218 }
1219}
1220
1221// Tracking Mode Priorities
1222////////////////////////////////////////////////////////////////////////////
1223QString t_rnxObsFile::signalPriorities(char sys) {
1224
1225 bncSettings settings;
1226 QStringList priorList = settings.value("rnxV2Priority").toString().split(" ", QString::SkipEmptyParts);
1227 if (priorList.empty()) {
1228 priorList << "CWPX_?";
1229 }
1230
1231 QString result;
1232 for (int ii = 0; ii < priorList.size(); ii++) {
1233 if (priorList[ii].indexOf(":") != -1) {
1234 QStringList hlp = priorList[ii].split(":", QString::SkipEmptyParts);
1235 if (hlp.size() == 2 && hlp[0].length() == 1 && hlp[0][0] == sys) {
1236 result = hlp[1];
1237 break;
1238 }
1239 }
1240 else {
1241 result = priorList[ii];
1242 }
1243 }
1244
1245 return result;
1246}
Note: See TracBrowser for help on using the repository browser.