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

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