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

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