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

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