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

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