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

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