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

Last change on this file since 6253 was 6253, checked in by mervart, 9 years ago
File size: 34.6 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 int satNum; readInt(line, pos + 1, 2, satNum);
873 _currEpo.rnxSat[iSat].prn.set(sys, satNum);
874
875 pos += 3;
876 }
877
878 // Read Observation Records
879 // ------------------------
880 for (int iSat = 0; iSat < numSat; iSat++) {
881 char sys = _currEpo.rnxSat[iSat].prn.system();
882 line = _stream->readLine();
883 pos = 0;
884 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
885 if (iType > 0 && iType % 5 == 0) {
886 line = _stream->readLine();
887 pos = 0;
888 }
889 double obsValue = 0.0;
890 int lli = 0;
891 int snr = 0;
892 readDbl(line, pos, 14, obsValue);
893 readInt(line, pos + 14, 1, lli);
894 readInt(line, pos + 15, 1, snr);
895
896 if (_flgPowerFail) {
897 lli |= 1;
898 }
899
900 QString type = obsType(sys, iType);
901 _currEpo.rnxSat[iSat].obs[type].value = obsValue;
902 _currEpo.rnxSat[iSat].obs[type].lli = lli;
903 _currEpo.rnxSat[iSat].obs[type].snr = snr;
904
905 pos += 16;
906 }
907 }
908
909 _flgPowerFail = false;
910
911 return &_currEpo;
912 }
913
914 return 0;
915}
916
917// Write Data Epoch
918////////////////////////////////////////////////////////////////////////////
919void t_rnxObsFile::writeEpoch(const t_rnxEpo* epo) {
920 if (epo == 0) {
921 return;
922 }
923 t_rnxEpo epoLocal;
924 epoLocal.tt = epo->tt;
925 for (unsigned ii = 0; ii < epo->rnxSat.size(); ii++) {
926 const t_rnxSat& rnxSat = epo->rnxSat[ii];
927 if (_header._obsTypes[rnxSat.prn.system()].size() > 0) {
928 epoLocal.rnxSat.push_back(rnxSat);
929 }
930 }
931
932 if (version() < 3.0) {
933 return writeEpochV2(_stream, _header, &epoLocal);
934 }
935 else {
936 return writeEpochV3(_stream, _header, &epoLocal);
937 }
938}
939
940// Write Data Epoch (RINEX Version 2)
941////////////////////////////////////////////////////////////////////////////
942void t_rnxObsFile::writeEpochV2(QTextStream* stream, const t_rnxObsHeader& header,
943 const t_rnxEpo* epo) {
944
945 unsigned year, month, day, hour, min;
946 double sec;
947 epo->tt.civil_date(year, month, day);
948 epo->tt.civil_time(hour, min, sec);
949
950 QString dateStr;
951 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
952 .arg(int(fmod(year, 100)), 2, 10, QChar('0'))
953 .arg(month, 2, 10, QChar('0'))
954 .arg(day, 2, 10, QChar('0'))
955 .arg(hour, 2, 10, QChar('0'))
956 .arg(min, 2, 10, QChar('0'))
957 .arg(sec, 11, 'f', 7);
958
959 int flag = 0;
960 *stream << dateStr << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
961 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
962 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
963 if (iSat > 0 && iSat % 12 == 0) {
964 *stream << endl << QString().leftJustified(32);
965 }
966 *stream << rnxSat.prn.toString().c_str();
967 }
968 *stream << endl;
969 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
970
971 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
972 char sys = rnxSat.prn.system();
973
974 for (int iTypeV2 = 0; iTypeV2 < header.nTypes(sys); iTypeV2++) {
975 if (iTypeV2 > 0 && iTypeV2 % 5 == 0) {
976 *stream << endl;
977 }
978 QString typeV2 = header.obsType(sys, iTypeV2);
979 bool found = false;
980
981 QString preferredAttrib = signalPriorities(sys);
982 for (int iPref = 0; iPref < preferredAttrib.length(); iPref++) {
983 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
984 while (itObs.hasNext()) {
985 itObs.next();
986 const QString& type = itObs.key();
987 const t_rnxObs& rnxObs = itObs.value();
988 if ( preferredAttrib[iPref] == '?' ||
989 (type.length() == 2 && preferredAttrib[iPref] == '_' ) ||
990 (type.length() == 3 && preferredAttrib[iPref] == type[2]) ) {
991 if (typeV2 == type3to2(sys, type)) {
992 found = true;
993 if (rnxObs.value == 0.0) {
994 *stream << QString().leftJustified(16);
995 }
996 else {
997 *stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
998 if (rnxObs.lli != 0.0) {
999 *stream << QString("%1").arg(rnxObs.lli,1);
1000 }
1001 else {
1002 *stream << ' ';
1003 }
1004 if (rnxObs.snr != 0.0) {
1005 *stream << QString("%1").arg(rnxObs.snr,1);
1006 }
1007 else {
1008 *stream << ' ';
1009 }
1010 }
1011 goto end_loop_iPref;
1012 }
1013 }
1014 }
1015 } end_loop_iPref:
1016 if (!found) {
1017 *stream << QString().leftJustified(16);
1018 }
1019 }
1020 *stream << endl;
1021 }
1022}
1023
1024// Write Data Epoch (RINEX Version 3)
1025////////////////////////////////////////////////////////////////////////////
1026void t_rnxObsFile::writeEpochV3(QTextStream* stream, const t_rnxObsHeader& header,
1027 const t_rnxEpo* epo) {
1028
1029 unsigned year, month, day, hour, min;
1030 double sec;
1031 epo->tt.civil_date(year, month, day);
1032 epo->tt.civil_time(hour, min, sec);
1033
1034 QString dateStr;
1035 QTextStream(&dateStr) << QString("> %1 %2 %3 %4 %5%6")
1036 .arg(year, 4)
1037 .arg(month, 2, 10, QChar('0'))
1038 .arg(day, 2, 10, QChar('0'))
1039 .arg(hour, 2, 10, QChar('0'))
1040 .arg(min, 2, 10, QChar('0'))
1041 .arg(sec, 11, 'f', 7);
1042
1043 int flag = 0;
1044 *stream << dateStr << QString("%1%2\n").arg(flag, 3).arg(epo->rnxSat.size(), 3);
1045
1046 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
1047 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
1048 char sys = rnxSat.prn.system();
1049
1050 *stream << rnxSat.prn.toString().c_str();
1051
1052 for (int iTypeV3 = 0; iTypeV3 < header.nTypes(sys); iTypeV3++) {
1053 QString typeV3 = header.obsType(sys, iTypeV3);
1054 bool found = false;
1055 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
1056 while (itObs.hasNext()) {
1057 itObs.next();
1058 const QString& type = itObs.key();
1059 const t_rnxObs& rnxObs = itObs.value();
1060 if (typeV3 == type2to3(sys, type)) {
1061 found = true;
1062 if (rnxObs.value == 0.0) {
1063 *stream << QString().leftJustified(16);
1064 }
1065 else {
1066 *stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
1067 if (rnxObs.lli != 0.0) {
1068 *stream << QString("%1").arg(rnxObs.lli,1);
1069 }
1070 else {
1071 *stream << ' ';
1072 }
1073 if (rnxObs.snr != 0.0) {
1074 *stream << QString("%1").arg(rnxObs.snr,1);
1075 }
1076 else {
1077 *stream << ' ';
1078 }
1079 }
1080 }
1081 }
1082 if (!found) {
1083 *stream << QString().leftJustified(16);
1084 }
1085 }
1086 *stream << endl;
1087 }
1088}
1089
1090// Translate Observation Type v2 --> v3
1091////////////////////////////////////////////////////////////////////////////
1092QString t_rnxObsFile::type2to3(char sys, const QString& typeV2) {
1093 if (typeV2 == "P1") {
1094 return (sys == 'G') ? "C1W" : "C1P";
1095 }
1096 else if (typeV2 == "P2") {
1097 return (sys == 'G') ? "C2W" : "C2P";
1098 }
1099 return typeV2;
1100}
1101
1102// Translate Observation Type v3 --> v2
1103////////////////////////////////////////////////////////////////////////////
1104QString t_rnxObsFile::type3to2(char /* sys */, const QString& typeV3) {
1105 if (typeV3 == "C1P" || typeV3 == "C1W") {
1106 return "P1";
1107 }
1108 else if (typeV3 == "C2P" || typeV3 == "C2W") {
1109 return "P2";
1110 }
1111 return typeV3.left(2);
1112}
1113
1114// Set Observations from RINEX File
1115////////////////////////////////////////////////////////////////////////////
1116void t_rnxObsFile::setObsFromRnx(const t_rnxObsFile* rnxObsFile, const t_rnxObsFile::t_rnxEpo* epo,
1117 const t_rnxObsFile::t_rnxSat& rnxSat, t_satObs& obs) {
1118
1119 obs._staID = rnxObsFile->markerName().toAscii().constData();
1120 obs._prn = rnxSat.prn;
1121 obs._time = epo->tt;
1122
1123 char sys = rnxSat.prn.system();
1124
1125 for (int iType = 0; iType < rnxObsFile->nTypes(sys); iType++) {
1126 QString type = rnxObsFile->obsType(sys, iType);
1127 QString typeV3 = rnxObsFile->obsType(sys, iType, 3.0); // may or may not differ from type
1128 if (rnxSat.obs.contains(type)) {
1129 const t_rnxObs& rnxObs = rnxSat.obs[type];
1130 if (rnxObs.value != 0.0) {
1131 string type2ch(typeV3.mid(1).toAscii().data());
1132
1133 t_frqObs* frqObs = 0;
1134 for (unsigned iFrq = 0; iFrq < obs._obs.size(); iFrq++) {
1135 if (obs._obs[iFrq]->_rnxType2ch == type2ch) {
1136 frqObs = obs._obs[iFrq];
1137 break;
1138 }
1139 }
1140 if (frqObs == 0) {
1141 frqObs = new t_frqObs;
1142 frqObs->_rnxType2ch = type2ch;
1143 obs._obs.push_back(frqObs);
1144 }
1145
1146 switch( typeV3.toAscii().data()[0] ) {
1147 case 'C':
1148 frqObs->_codeValid = true;
1149 frqObs->_code = rnxObs.value;
1150 break;
1151 case 'L':
1152 frqObs->_phaseValid = true;
1153 frqObs->_phase = rnxObs.value;
1154 frqObs->_slip = (rnxObs.lli & 1);
1155 break;
1156 case 'D':
1157 frqObs->_dopplerValid = true;
1158 frqObs->_doppler = rnxObs.value;
1159 break;
1160 case 'S':
1161 frqObs->_snrValid = true;
1162 frqObs->_snr = rnxObs.value;
1163 break;
1164 }
1165 }
1166 }
1167 }
1168}
1169
1170// Tracking Mode Priorities
1171////////////////////////////////////////////////////////////////////////////
1172QString t_rnxObsFile::signalPriorities(char sys) {
1173
1174 bncSettings settings;
1175 QStringList priorList = settings.value("rnxV2Priority").toString().split(" ", QString::SkipEmptyParts);
1176 if (priorList.empty()) {
1177 priorList << "CWPX_?";
1178 }
1179
1180 QString result;
1181 for (int ii = 0; ii < priorList.size(); ii++) {
1182 if (priorList[ii].indexOf(":") != -1) {
1183 QStringList hlp = priorList[ii].split(":", QString::SkipEmptyParts);
1184 if (hlp.size() == 2 && hlp[0].length() == 1 && hlp[0][0] == sys) {
1185 result = hlp[1];
1186 break;
1187 }
1188 }
1189 else {
1190 result = priorList[ii];
1191 }
1192 }
1193
1194 return result;
1195}
Note: See TracBrowser for help on using the repository browser.