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

Last change on this file since 6242 was 6242, checked in by mervart, 10 years ago
File size: 32.5 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
51const QString t_rnxObsHeader::defaultSystems = "GRES";
52
53// Constructor
54////////////////////////////////////////////////////////////////////////////
55t_rnxObsHeader::t_rnxObsHeader() {
56 _antNEU.ReSize(3); _antNEU = 0.0;
57 _antXYZ.ReSize(3); _antXYZ = 0.0;
58 _antBSG.ReSize(3); _antBSG = 0.0;
59 _xyz.ReSize(3); _xyz = 0.0;
60 _version = 0.0;
61 _interval = 0.0;
62 for (unsigned iPrn = 1; iPrn <= t_prn::MAXPRN_GPS; iPrn++) {
63 _wlFactorsL1[iPrn] = 1;
64 _wlFactorsL2[iPrn] = 1;
65 }
66}
67
68// Destructor
69////////////////////////////////////////////////////////////////////////////
70t_rnxObsHeader::~t_rnxObsHeader() {
71}
72
73// Read Header
74////////////////////////////////////////////////////////////////////////////
75t_irc t_rnxObsHeader::read(QTextStream* stream, int maxLines) {
76 _comments.clear();
77 int numLines = 0;
78 while ( stream->status() == QTextStream::Ok && !stream->atEnd() ) {
79 QString line = stream->readLine(); ++ numLines;
80 if (line.isEmpty()) {
81 continue;
82 }
83 if (line.indexOf("END OF FILE") != -1) {
84 break;
85 }
86 QString value = line.mid(0,60).trimmed();
87 QString key = line.mid(60).trimmed();
88 if (key == "END OF HEADER") {
89 break;
90 }
91 else if (key == "RINEX VERSION / TYPE") {
92 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
93 in >> _version;
94 }
95 else if (key == "MARKER NAME") {
96 _markerName = value;
97 }
98 else if (key == "MARKER NUMBER") {
99 _markerNumber = line.mid(0,20).trimmed();
100 }
101 else if (key == "ANT # / TYPE") {
102 _antennaNumber = line.mid( 0,20).trimmed();
103 _antennaName = line.mid(20,20).trimmed();
104 }
105 else if (key == "OBSERVER / AGENCY") {
106 _observer = line.mid( 0,20).trimmed();
107 _agency = line.mid(20,40).trimmed();
108 }
109 else if (key == "REC # / TYPE / VERS") {
110 _receiverNumber = line.mid( 0,20).trimmed();
111 _receiverType = line.mid(20,20).trimmed();
112 _receiverVersion = line.mid(40,20).trimmed();
113 }
114 else if (key == "INTERVAL") {
115 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
116 in >> _interval;
117 }
118 else if (key == "COMMENT") {
119 _comments << line.mid(0,60).trimmed();
120 }
121 else if (key == "WAVELENGTH FACT L1/2") {
122 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
123 int wlFactL1 = 0;
124 int wlFactL2 = 0;
125 int numSat = 0;
126 in >> wlFactL1 >> wlFactL2 >> numSat;
127 if (numSat == 0) {
128 for (unsigned iPrn = 1; iPrn <= t_prn::MAXPRN_GPS; iPrn++) {
129 _wlFactorsL1[iPrn] = wlFactL1;
130 _wlFactorsL2[iPrn] = wlFactL2;
131 }
132 }
133 else {
134 for (int ii = 0; ii < numSat; ii++) {
135 QString prn; in >> prn;
136 if (prn[0] == 'G') {
137 int iPrn;
138 readInt(prn, 1, 2, iPrn);
139 _wlFactorsL1[iPrn] = wlFactL1;
140 _wlFactorsL2[iPrn] = wlFactL2;
141 }
142 }
143 }
144 }
145 else if (key == "APPROX POSITION XYZ") {
146 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
147 in >> _xyz[0] >> _xyz[1] >> _xyz[2];
148 }
149 else if (key == "ANTENNA: DELTA H/E/N") {
150 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
151 in >> _antNEU[2] >> _antNEU[1] >> _antNEU[0];
152 }
153 else if (key == "ANTENNA: DELTA X/Y/Z") {
154 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
155 in >> _antXYZ[0] >> _antXYZ[1] >> _antXYZ[2];
156 }
157 else if (key == "ANTENNA: B.SIGHT XYZ") {
158 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
159 in >> _antBSG[0] >> _antBSG[1] >> _antBSG[2];
160 }
161 else if (key == "# / TYPES OF OBSERV") {
162 if (_version == 0.0) {
163 _version = t_rnxObsHeader::defaultRnxObsVersion2;
164 }
165 QTextStream* in = new QTextStream(value.toAscii(), QIODevice::ReadOnly);
166 int nTypes;
167 *in >> nTypes;
168 char sys0 = defaultSystems[0].toAscii();
169 _obsTypes[sys0].clear();
170 for (int ii = 0; ii < nTypes; ii++) {
171 if (ii > 0 && ii % 9 == 0) {
172 line = stream->readLine(); ++numLines;
173 delete in;
174 in = new QTextStream(line.left(60).toAscii(), QIODevice::ReadOnly);
175 }
176 QString hlp;
177 *in >> hlp;
178 _obsTypes[sys0].append(hlp);
179 }
180 for (int ii = 1; ii < defaultSystems.length(); ii++) {
181 char sysI = defaultSystems[ii].toAscii();
182 _obsTypes[sysI] = _obsTypes[sys0];
183 }
184 }
185 else if (key == "SYS / # / OBS TYPES") {
186 if (_version == 0.0) {
187 _version = t_rnxObsHeader::defaultRnxObsVersion3;
188 }
189 QTextStream* in = new QTextStream(value.toAscii(), QIODevice::ReadOnly);
190 char sys;
191 int nTypes;
192 *in >> sys >> nTypes;
193 _obsTypes[sys].clear();
194 for (int ii = 0; ii < nTypes; ii++) {
195 if (ii > 0 && ii % 13 == 0) {
196 line = stream->readLine(); ++numLines;
197 delete in;
198 in = new QTextStream(line.toAscii(), QIODevice::ReadOnly);
199 }
200 QString hlp;
201 *in >> hlp;
202 _obsTypes[sys].push_back(hlp);
203 }
204 delete in;
205 }
206 else if (key == "TIME OF FIRST OBS") {
207 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
208 int year, month, day, hour, min;
209 double sec;
210 in >> year >> month >> day >> hour >> min >> sec;
211 _startTime.set(year, month, day, hour, min, sec);
212 }
213 if (maxLines > 0 && numLines == maxLines) {
214 break;
215 }
216 }
217
218 return success;
219}
220
221// Set Default Header
222////////////////////////////////////////////////////////////////////////////
223void t_rnxObsHeader::setDefault(const QString& markerName, int version) {
224
225 _markerName = markerName;
226
227 if (version <= 2) {
228 _version = t_rnxObsHeader::defaultRnxObsVersion2;
229 }
230 else {
231 _version = t_rnxObsHeader::defaultRnxObsVersion3;
232 }
233
234 _comments << "Default set of observation types used";
235
236 _obsTypes.clear();
237 if (_version < 3.0) {
238 _obsTypes['G'] << "C1" << "P1" << "L1" << "S1"
239 << "C2" << "P2" << "L2" << "S2";
240 _obsTypes['R'] = _obsTypes['G'];
241 _obsTypes['E'] = _obsTypes['G'];
242 _obsTypes['J'] = _obsTypes['G'];
243 _obsTypes['S'] = _obsTypes['G'];
244 _obsTypes['C'] = _obsTypes['G'];
245 }
246 else {
247 _obsTypes['G'] << "C1C" << "L1C" << "S1C"
248 << "C2W" << "L2W" << "S2W"
249 << "C5" << "L5" << "S5";
250
251 _obsTypes['J'] = _obsTypes['G'];
252
253 _obsTypes['R'] << "C1C" << "L1C" << "S1C"
254 << "C2P" << "L2P" << "S2P";
255
256 _obsTypes['E'] << "C1" << "L1" << "S1"
257 << "C5" << "L5" << "S5"
258 << "C7" << "L7" << "S7"
259 << "C8" << "L8" << "S8";
260
261 _obsTypes['S'] << "C1" << "L1" << "S1"
262 << "C5" << "L5" << "S5";
263
264 _obsTypes['C'] << "C1" << "L1" << "S1"
265 << "C6" << "L6" << "S6"
266 << "C7" << "L7" << "S7";
267 }
268}
269
270// Copy header
271////////////////////////////////////////////////////////////////////////////
272void t_rnxObsHeader::set(const t_rnxObsHeader& header, int version,
273 const QStringList* useObsTypes) {
274
275 if (version <= 2) {
276 _version = t_rnxObsHeader::defaultRnxObsVersion2;
277 }
278 else {
279 _version = t_rnxObsHeader::defaultRnxObsVersion3;
280 }
281 _interval = header._interval;
282 _antennaNumber = header._antennaNumber;
283 _antennaName = header._antennaName;
284 _markerName = header._markerName;
285 _markerNumber = header._markerNumber;
286 _antNEU = header._antNEU;
287 _antXYZ = header._antXYZ;
288 _antBSG = header._antBSG;
289 _xyz = header._xyz;
290 _observer = header._observer;
291 _agency = header._agency;
292 _receiverNumber = header._receiverNumber;
293 _receiverType = header._receiverType;
294 _receiverVersion = header._receiverVersion;
295 _startTime = header._startTime;
296 _comments = header._comments;
297 for (unsigned iPrn = 1; iPrn <= t_prn::MAXPRN_GPS; iPrn++) {
298 _wlFactorsL1[iPrn] = header._wlFactorsL1[iPrn];
299 _wlFactorsL2[iPrn] = header._wlFactorsL2[iPrn];
300 }
301
302 // Set observation types
303 // ---------------------
304 _obsTypes.clear();
305 if (!useObsTypes || useObsTypes->size() == 0) {
306 if (int(_version) == int(header._version)) {
307 _obsTypes = header._obsTypes;
308 }
309 else {
310 for (int iSys = 0; iSys < header.numSys(); iSys++) {
311 char sys = header.system(iSys);
312 for (int iType = 0; iType < header.nTypes(sys); iType++) {
313 _obsTypes[sys].push_back(header.obsType(sys, iType, _version));
314 }
315 _obsTypes[sys].removeDuplicates();
316 }
317 }
318 }
319 else {
320 for (int iType = 0; iType < useObsTypes->size(); iType++) {
321 if (useObsTypes->at(iType).indexOf(":") != -1) {
322 QStringList hlp = useObsTypes->at(iType).split(":", QString::SkipEmptyParts);
323 if (hlp.size() == 2 && hlp[0].length() == 1) {
324 char sys = hlp[0][0].toAscii();
325 QString type = hlp[1];
326 _obsTypes[sys].push_back(type);
327 }
328 }
329 else {
330 for (int iSys = 0; iSys < t_rnxObsHeader::defaultSystems.length(); iSys++) {
331 char sys = t_rnxObsHeader::defaultSystems[iSys].toAscii();
332 _obsTypes[sys].push_back(useObsTypes->at(iType));
333 }
334 }
335 }
336 }
337}
338
339// Write Header
340////////////////////////////////////////////////////////////////////////////
341void t_rnxObsHeader::write(QTextStream* stream,
342 const QMap<QString, QString>* txtMap) const {
343
344 QStringList newComments;
345 QString runBy = BNC_CORE->userName();
346
347 if (txtMap) {
348 QMapIterator<QString, QString> it(*txtMap);
349 while (it.hasNext()) {
350 it.next();
351 if (it.key() == "RUN BY") {
352 runBy = it.value();
353 }
354 else if (it.key() == "COMMENT") {
355 newComments = it.value().split("\\n", QString::SkipEmptyParts);
356 }
357 }
358 }
359
360 *stream << QString("%1 Observation data Mixed")
361 .arg(_version, 9, 'f', 2)
362 .leftJustified(60)
363 << "RINEX VERSION / TYPE\n";
364
365 const QString fmtDate = (_version < 3.0) ? "dd-MMM-yy hh:mm"
366 : "yyyyMMdd hhmmss UTC";
367 *stream << QString("%1%2%3")
368 .arg(BNC_CORE->pgmName(), -20)
369 .arg(runBy.trimmed().left(20), -20)
370 .arg(QDateTime::currentDateTime().toUTC().toString(fmtDate), -20)
371 .leftJustified(60)
372 << "PGM / RUN BY / DATE\n";
373
374 QStringListIterator itCmnt(_comments + newComments);
375 while (itCmnt.hasNext()) {
376 *stream << itCmnt.next().trimmed().left(60).leftJustified(60) << "COMMENT\n";
377 }
378
379 *stream << QString("%1")
380 .arg(_markerName, -60)
381 .leftJustified(60)
382 << "MARKER NAME\n";
383
384 if (!_markerNumber.isEmpty()) {
385 *stream << QString("%1")
386 .arg(_markerNumber, -20)
387 .leftJustified(60)
388 << "MARKER NUMBER\n";
389 }
390
391 *stream << QString("%1%2")
392 .arg(_observer, -20)
393 .arg(_agency, -40)
394 .leftJustified(60)
395 << "OBSERVER / AGENCY\n";
396
397 *stream << QString("%1%2%3")
398 .arg(_receiverNumber, -20)
399 .arg(_receiverType, -20)
400 .arg(_receiverVersion, -20)
401 .leftJustified(60)
402 << "REC # / TYPE / VERS\n";
403
404 *stream << QString("%1%2")
405 .arg(_antennaNumber, -20)
406 .arg(_antennaName, -20)
407 .leftJustified(60)
408 << "ANT # / TYPE\n";
409
410 *stream << QString("%1%2%3")
411 .arg(_xyz(1), 14, 'f', 4)
412 .arg(_xyz(2), 14, 'f', 4)
413 .arg(_xyz(3), 14, 'f', 4)
414 .leftJustified(60)
415 << "APPROX POSITION XYZ\n";
416
417 *stream << QString("%1%2%3")
418 .arg(_antNEU(3), 14, 'f', 4)
419 .arg(_antNEU(2), 14, 'f', 4)
420 .arg(_antNEU(1), 14, 'f', 4)
421 .leftJustified(60)
422 << "ANTENNA: DELTA H/E/N\n";
423
424 if (_version < 3.0) {
425 int defaultWlFact1 = _wlFactorsL1[1];
426 int defaultWlFact2 = _wlFactorsL2[1]; // TODO check all prns
427 *stream << QString("%1%2")
428 .arg(defaultWlFact1, 6)
429 .arg(defaultWlFact2, 6)
430 .leftJustified(60)
431 << "WAVELENGTH FACT L1/2\n";
432 }
433
434 *stream << obsTypesStrings().join("");
435
436 if (_interval > 0) {
437 *stream << QString("%1")
438 .arg(_interval, 10, 'f', 3)
439 .leftJustified(60)
440 << "INTERVAL\n";
441 }
442
443 unsigned year, month, day, hour, min;
444 double sec;
445 _startTime.civil_date(year, month, day);
446 _startTime.civil_time(hour, min, sec);
447 *stream << QString("%1%2%3%4%5%6%7")
448 .arg(year, 6)
449 .arg(month, 6)
450 .arg(day, 6)
451 .arg(hour, 6)
452 .arg(min, 6)
453 .arg(sec, 13, 'f', 7)
454 .arg("GPS", 8)
455 .leftJustified(60)
456 << "TIME OF FIRST OBS\n";
457
458 *stream << QString()
459 .leftJustified(60)
460 << "END OF HEADER\n";
461}
462
463// Number of Different Systems
464////////////////////////////////////////////////////////////////////////////
465int t_rnxObsHeader::numSys() const {
466 return _obsTypes.size();
467}
468
469//
470////////////////////////////////////////////////////////////////////////////
471char t_rnxObsHeader::system(int iSys) const {
472 int iSysLocal = -1;
473 QMapIterator<char, QStringList> it(_obsTypes);
474 while (it.hasNext()) {
475 ++iSysLocal;
476 it.next();
477 if (iSysLocal == iSys) {
478 return it.key();
479 }
480 }
481 return ' ';
482}
483
484// Number of Observation Types (satellite-system specific)
485////////////////////////////////////////////////////////////////////////////
486int t_rnxObsHeader::nTypes(char sys) const {
487 if (_obsTypes.contains(sys)) {
488 return _obsTypes[sys].size();
489 }
490 else {
491 return 0;
492 }
493}
494
495// Observation Type (satellite-system specific)
496////////////////////////////////////////////////////////////////////////////
497QString t_rnxObsHeader::obsType(char sys, int index, double version) const {
498
499 if (version == 0.0) {
500 version = _version;
501 }
502 if (_obsTypes.contains(sys)) {
503 QString origType = _obsTypes[sys].at(index);
504 if (int(version) == int(_version)) {
505 return origType;
506 }
507 else if (int(version) == 2) {
508 return t_rnxObsFile::type3to2(sys, origType);
509 }
510 else if (int(version) == 3) {
511 return t_rnxObsFile::type2to3(sys, origType);
512 }
513 }
514 return "";
515}
516
517// Write Observation Types
518////////////////////////////////////////////////////////////////////////////
519QStringList t_rnxObsHeader::obsTypesStrings() const {
520
521 QStringList strList;
522
523 if (_version < 3.0) {
524 char sys0 = defaultSystems[0].toAscii();
525 QString hlp;
526 QTextStream(&hlp) << QString("%1").arg(_obsTypes[sys0].size(), 6);
527 for (int ii = 0; ii < _obsTypes[sys0].size(); ii++) {
528 QTextStream(&hlp) << QString("%1").arg(_obsTypes[sys0][ii], 6);
529 if ((ii+1) % 9 == 0 || ii == _obsTypes[sys0].size()-1) {
530 strList.append(hlp.leftJustified(60) + "# / TYPES OF OBSERV\n");
531 hlp = QString().leftJustified(6);
532 }
533 }
534 }
535 else {
536 for (int iSys = 0; iSys < numSys(); iSys++) {
537 char sys = system(iSys);
538 QString hlp;
539 QTextStream(&hlp) << QString("%1 %2").arg(sys).arg(nTypes(sys), 3);
540 for (int iType = 0; iType < nTypes(sys); iType++) {
541 QString type = obsType(sys, iType);
542 QTextStream(&hlp) << QString(" %1").arg(type, -3);
543 if ((iType+1) % 13 == 0 || iType == nTypes(sys)-1) {
544 strList.append(hlp.leftJustified(60) + "SYS / # / OBS TYPES\n");
545 hlp = QString().leftJustified(6);
546 }
547 }
548 }
549 }
550
551 return strList;
552}
553
554// Constructor
555////////////////////////////////////////////////////////////////////////////
556t_rnxObsFile::t_rnxObsFile(const QString& fileName, e_inpOut inpOut) {
557 _inpOut = inpOut;
558 _stream = 0;
559 _flgPowerFail = false;
560 if (_inpOut == input) {
561 openRead(fileName);
562 }
563 else {
564 openWrite(fileName);
565 }
566}
567
568// Open for input
569////////////////////////////////////////////////////////////////////////////
570void t_rnxObsFile::openRead(const QString& fileName) {
571
572 _fileName = fileName; expandEnvVar(_fileName);
573 _file = new QFile(_fileName);
574 _file->open(QIODevice::ReadOnly | QIODevice::Text);
575 _stream = new QTextStream();
576 _stream->setDevice(_file);
577
578 _header.read(_stream);
579
580 // Guess Observation Interval
581 // --------------------------
582 if (_header._interval == 0.0) {
583 bncTime ttPrev;
584 for (int iEpo = 0; iEpo < 10; iEpo++) {
585 const t_rnxEpo* rnxEpo = nextEpoch();
586 if (!rnxEpo) {
587 throw QString("t_rnxObsFile: not enough epochs");
588 }
589 if (iEpo > 0) {
590 double dt = rnxEpo->tt - ttPrev;
591 if (_header._interval == 0.0 || dt < _header._interval) {
592 _header._interval = dt;
593 }
594 }
595 ttPrev = rnxEpo->tt;
596 }
597 _stream->seek(0);
598 _header.read(_stream);
599 }
600
601 // Time of first observation
602 // -------------------------
603 if (!_header._startTime.valid()) {
604 const t_rnxEpo* rnxEpo = nextEpoch();
605 if (!rnxEpo) {
606 throw QString("t_rnxObsFile: not enough epochs");
607 }
608 _header._startTime = rnxEpo->tt;
609 _stream->seek(0);
610 _header.read(_stream);
611 }
612}
613
614// Open for output
615////////////////////////////////////////////////////////////////////////////
616void t_rnxObsFile::openWrite(const QString& fileName) {
617
618 _fileName = fileName; expandEnvVar(_fileName);
619 _file = new QFile(_fileName);
620 _file->open(QIODevice::WriteOnly | QIODevice::Text);
621 _stream = new QTextStream();
622 _stream->setDevice(_file);
623}
624
625// Destructor
626////////////////////////////////////////////////////////////////////////////
627t_rnxObsFile::~t_rnxObsFile() {
628 close();
629}
630
631// Close
632////////////////////////////////////////////////////////////////////////////
633void t_rnxObsFile::close() {
634 delete _stream; _stream = 0;
635 delete _file; _file = 0;
636}
637
638// Handle Special Epoch Flag
639////////////////////////////////////////////////////////////////////////////
640void t_rnxObsFile::handleEpochFlag(int flag, const QString& line,
641 bool& headerReRead) {
642
643 headerReRead = false;
644
645 // Power Failure
646 // -------------
647 if (flag == 1) {
648 _flgPowerFail = true;
649 }
650
651 // Start moving antenna
652 // --------------------
653 else if (flag == 2) {
654 // no action
655 }
656
657 // Re-Read Header
658 // --------------
659 else if (flag == 3 || flag == 4 || flag == 5) {
660 int numLines = 0;
661 if (version() < 3.0) {
662 readInt(line, 29, 3, numLines);
663 }
664 else {
665 readInt(line, 32, 3, numLines);
666 }
667 if (flag == 3 || flag == 4) {
668 _header.read(_stream, numLines);
669 headerReRead = true;
670 }
671 else {
672 for (int ii = 0; ii < numLines; ii++) {
673 _stream->readLine();
674 }
675 }
676 }
677
678 // Unhandled Flag
679 // --------------
680 else {
681 throw QString("t_rnxObsFile: unhandled flag\n" + line);
682 }
683}
684
685// Retrieve single Epoch
686////////////////////////////////////////////////////////////////////////////
687t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpoch() {
688 _currEpo.clear();
689 if (version() < 3.0) {
690 return nextEpochV2();
691 }
692 else {
693 return nextEpochV3();
694 }
695}
696
697// Retrieve single Epoch (RINEX Version 3)
698////////////////////////////////////////////////////////////////////////////
699t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV3() {
700
701 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
702
703 QString line = _stream->readLine();
704
705 if (line.isEmpty()) {
706 continue;
707 }
708
709 int flag = 0;
710 readInt(line, 31, 1, flag);
711 if (flag > 0) {
712 bool headerReRead = false;
713 handleEpochFlag(flag, line, headerReRead);
714 if (headerReRead) {
715 continue;
716 }
717 }
718
719 QTextStream in(line.mid(1).toAscii(), QIODevice::ReadOnly);
720
721 // Epoch Time
722 // ----------
723 int year, month, day, hour, min;
724 double sec;
725 in >> year >> month >> day >> hour >> min >> sec;
726 _currEpo.tt.set(year, month, day, hour, min, sec);
727
728 // Number of Satellites
729 // --------------------
730 int numSat;
731 readInt(line, 32, 3, numSat);
732
733 _currEpo.rnxSat.resize(numSat);
734
735 // Observations
736 // ------------
737 for (int iSat = 0; iSat < numSat; iSat++) {
738 line = _stream->readLine();
739 t_prn prn; prn.set(line.left(3).toAscii().data());
740 _currEpo.rnxSat[iSat].prn = prn;
741 char sys = prn.system();
742 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
743 int pos = 3 + 16*iType;
744 double obsValue = 0.0;
745 int lli = 0;
746 int snr = 0;
747 readDbl(line, pos, 14, obsValue);
748 readInt(line, pos + 14, 1, lli);
749 readInt(line, pos + 15, 1, snr);
750 if (_flgPowerFail) {
751 lli |= 1;
752 }
753 QString type = obsType(sys, iType);
754 _currEpo.rnxSat[iSat].obs[type].value = obsValue;
755 _currEpo.rnxSat[iSat].obs[type].lli = lli;
756 _currEpo.rnxSat[iSat].obs[type].snr = snr;
757 }
758 }
759
760 _flgPowerFail = false;
761
762 return &_currEpo;
763 }
764
765 return 0;
766}
767
768// Retrieve single Epoch (RINEX Version 2)
769////////////////////////////////////////////////////////////////////////////
770t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV2() {
771
772 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
773
774 QString line = _stream->readLine();
775
776 if (line.isEmpty()) {
777 continue;
778 }
779
780 int flag = 0;
781 readInt(line, 28, 1, flag);
782 if (flag > 0) {
783 bool headerReRead = false;
784 handleEpochFlag(flag, line, headerReRead);
785 if (headerReRead) {
786 continue;
787 }
788 }
789
790 QTextStream in(line.toAscii(), QIODevice::ReadOnly);
791
792 // Epoch Time
793 // ----------
794 int year, month, day, hour, min;
795 double sec;
796 in >> year >> month >> day >> hour >> min >> sec;
797 if (year < 80) {
798 year += 2000;
799 }
800 else if (year < 100) {
801 year += 1900;
802 }
803 _currEpo.tt.set(year, month, day, hour, min, sec);
804
805 // Number of Satellites
806 // --------------------
807 int numSat;
808 readInt(line, 29, 3, numSat);
809
810 _currEpo.rnxSat.resize(numSat);
811
812 // Read Satellite Numbers
813 // ----------------------
814 int pos = 32;
815 for (int iSat = 0; iSat < numSat; iSat++) {
816 if (iSat > 0 && iSat % 12 == 0) {
817 line = _stream->readLine();
818 pos = 32;
819 }
820
821 char sys = line.toAscii()[pos];
822 int satNum; readInt(line, pos + 1, 2, satNum);
823 _currEpo.rnxSat[iSat].prn.set(sys, satNum);
824
825 pos += 3;
826 }
827
828 // Read Observation Records
829 // ------------------------
830 for (int iSat = 0; iSat < numSat; iSat++) {
831 char sys = _currEpo.rnxSat[iSat].prn.system();
832 line = _stream->readLine();
833 pos = 0;
834 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
835 if (iType > 0 && iType % 5 == 0) {
836 line = _stream->readLine();
837 pos = 0;
838 }
839 double obsValue = 0.0;
840 int lli = 0;
841 int snr = 0;
842 readDbl(line, pos, 14, obsValue);
843 readInt(line, pos + 14, 1, lli);
844 readInt(line, pos + 15, 1, snr);
845
846 if (_flgPowerFail) {
847 lli |= 1;
848 }
849
850 QString type = obsType(sys, iType);
851 _currEpo.rnxSat[iSat].obs[type].value = obsValue;
852 _currEpo.rnxSat[iSat].obs[type].lli = lli;
853 _currEpo.rnxSat[iSat].obs[type].snr = snr;
854
855 pos += 16;
856 }
857 }
858
859 _flgPowerFail = false;
860
861 return &_currEpo;
862 }
863
864 return 0;
865}
866
867// Write Data Epoch
868////////////////////////////////////////////////////////////////////////////
869void t_rnxObsFile::writeEpoch(const t_rnxEpo* epo) {
870 if (version() < 3.0) {
871 return writeEpochV2(_stream, _header, epo);
872 }
873 else {
874 return writeEpochV3(_stream, _header, epo);
875 }
876}
877
878// Write Data Epoch (RINEX Version 2)
879////////////////////////////////////////////////////////////////////////////
880void t_rnxObsFile::writeEpochV2(QTextStream* stream, const t_rnxObsHeader& header,
881 const t_rnxEpo* epo) {
882
883 unsigned year, month, day, hour, min;
884 double sec;
885 epo->tt.civil_date(year, month, day);
886 epo->tt.civil_time(hour, min, sec);
887
888 QString dateStr;
889 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
890 .arg(int(fmod(year, 100)), 2, 10, QChar('0'))
891 .arg(month, 2, 10, QChar('0'))
892 .arg(day, 2, 10, QChar('0'))
893 .arg(hour, 2, 10, QChar('0'))
894 .arg(min, 2, 10, QChar('0'))
895 .arg(sec, 11, 'f', 7);
896
897 int flag = 0;
898 *stream << dateStr << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
899 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
900 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
901 if (iSat > 0 && iSat % 12 == 0) {
902 *stream << endl << QString().leftJustified(32);
903 }
904 *stream << rnxSat.prn.toString().c_str();
905 }
906 *stream << endl;
907 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
908
909 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
910 char sys = rnxSat.prn.system();
911
912 for (int iTypeV2 = 0; iTypeV2 < header.nTypes(sys); iTypeV2++) {
913 if (iTypeV2 > 0 && iTypeV2 % 5 == 0) {
914 *stream << endl;
915 }
916 QString typeV2 = header.obsType(sys, iTypeV2);
917 bool found = false;
918
919 QString preferredAttrib = signalPriorities(sys);
920 for (int iPref = 0; iPref < preferredAttrib.length(); iPref++) {
921 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
922 while (itObs.hasNext()) {
923 itObs.next();
924 const QString& type = itObs.key();
925 const t_rnxObs& rnxObs = itObs.value();
926 if ( preferredAttrib[iPref] == '?' ||
927 (type.length() == 2 && preferredAttrib[iPref] == '_' ) ||
928 (type.length() == 3 && preferredAttrib[iPref] == type[2]) ) {
929 if (typeV2 == type3to2(sys, type)) {
930 found = true;
931 if (rnxObs.value == 0.0) {
932 *stream << QString().leftJustified(16);
933 }
934 else {
935 *stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
936 if (rnxObs.lli != 0.0) {
937 *stream << QString("%1").arg(rnxObs.lli,1);
938 }
939 else {
940 *stream << ' ';
941 }
942 if (rnxObs.snr != 0.0) {
943 *stream << QString("%1").arg(rnxObs.snr,1);
944 }
945 else {
946 *stream << ' ';
947 }
948 }
949 break;
950 }
951 }
952 }
953 if (found) {
954 break;
955 }
956 }
957 if (!found) {
958 *stream << QString().leftJustified(16);
959 }
960 }
961 *stream << endl;
962 }
963}
964
965// Write Data Epoch (RINEX Version 3)
966////////////////////////////////////////////////////////////////////////////
967void t_rnxObsFile::writeEpochV3(QTextStream* stream, const t_rnxObsHeader& header,
968 const t_rnxEpo* epo) {
969
970 unsigned year, month, day, hour, min;
971 double sec;
972 epo->tt.civil_date(year, month, day);
973 epo->tt.civil_time(hour, min, sec);
974
975 QString dateStr;
976 QTextStream(&dateStr) << QString("> %1 %2 %3 %4 %5%6")
977 .arg(year, 4)
978 .arg(month, 2, 10, QChar('0'))
979 .arg(day, 2, 10, QChar('0'))
980 .arg(hour, 2, 10, QChar('0'))
981 .arg(min, 2, 10, QChar('0'))
982 .arg(sec, 11, 'f', 7);
983
984 int flag = 0;
985 *stream << dateStr << QString("%1%2\n").arg(flag, 3).arg(epo->rnxSat.size(), 3);
986
987 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
988 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
989 char sys = rnxSat.prn.system();
990
991 *stream << rnxSat.prn.toString().c_str();
992
993 for (int iTypeV3 = 0; iTypeV3 < header.nTypes(sys); iTypeV3++) {
994 QString typeV3 = header.obsType(sys, iTypeV3);
995 bool found = false;
996 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
997 while (itObs.hasNext()) {
998 itObs.next();
999 const QString& type = itObs.key();
1000 const t_rnxObs& rnxObs = itObs.value();
1001 if (typeV3 == type2to3(sys, type)) {
1002 found = true;
1003 if (rnxObs.value == 0.0) {
1004 *stream << QString().leftJustified(16);
1005 }
1006 else {
1007 *stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
1008 if (rnxObs.lli != 0.0) {
1009 *stream << QString("%1").arg(rnxObs.lli,1);
1010 }
1011 else {
1012 *stream << ' ';
1013 }
1014 if (rnxObs.snr != 0.0) {
1015 *stream << QString("%1").arg(rnxObs.snr,1);
1016 }
1017 else {
1018 *stream << ' ';
1019 }
1020 }
1021 }
1022 }
1023 if (!found) {
1024 *stream << QString().leftJustified(16);
1025 }
1026 }
1027 *stream << endl;
1028 }
1029}
1030
1031// Translate Observation Type v2 --> v3
1032////////////////////////////////////////////////////////////////////////////
1033QString t_rnxObsFile::type2to3(char sys, const QString& typeV2) {
1034 if (typeV2 == "P1") {
1035 return (sys == 'G') ? "C1W" : "C1P";
1036 }
1037 else if (typeV2 == "P2") {
1038 return (sys == 'G') ? "C2W" : "C2P";
1039 }
1040 return typeV2;
1041}
1042
1043// Translate Observation Type v3 --> v2
1044////////////////////////////////////////////////////////////////////////////
1045QString t_rnxObsFile::type3to2(char /* sys */, const QString& typeV3) {
1046 if (typeV3 == "C1P" || typeV3 == "C1W") {
1047 return "P1";
1048 }
1049 else if (typeV3 == "C2P" || typeV3 == "C2W") {
1050 return "P2";
1051 }
1052 return typeV3.left(2);
1053}
1054
1055// Set Observations from RINEX File
1056////////////////////////////////////////////////////////////////////////////
1057void t_rnxObsFile::setObsFromRnx(const t_rnxObsFile* rnxObsFile, const t_rnxObsFile::t_rnxEpo* epo,
1058 const t_rnxObsFile::t_rnxSat& rnxSat, t_satObs& obs) {
1059
1060 obs._staID = rnxObsFile->markerName().toAscii().constData();
1061 obs._prn = rnxSat.prn;
1062 obs._time = epo->tt;
1063
1064 char sys = rnxSat.prn.system();
1065
1066 for (int iType = 0; iType < rnxObsFile->nTypes(sys); iType++) {
1067 QString type = rnxObsFile->obsType(sys, iType);
1068 if (rnxSat.obs.contains(type)) {
1069 const t_rnxObs& rnxObs = rnxSat.obs[type];
1070 if (rnxObs.value != 0.0) {
1071 string type2ch(type.mid(1).toAscii().data());
1072
1073 t_frqObs* frqObs = 0;
1074 for (unsigned iFrq = 0; iFrq < obs._obs.size(); iFrq++) {
1075 if (obs._obs[iFrq]->_rnxType2ch == type2ch) {
1076 frqObs = obs._obs[iFrq];
1077 break;
1078 }
1079 }
1080 if (frqObs == 0) {
1081 frqObs = new t_frqObs;
1082 frqObs->_rnxType2ch = type2ch;
1083 obs._obs.push_back(frqObs);
1084 }
1085
1086 switch( type.toAscii().data()[0] ) {
1087 case 'C':
1088 frqObs->_codeValid = true;
1089 frqObs->_code = rnxObs.value;
1090 break;
1091 case 'L':
1092 frqObs->_phaseValid = true;
1093 frqObs->_phase = rnxObs.value;
1094 frqObs->_slip = (rnxObs.lli & 1);
1095 break;
1096 case 'D':
1097 frqObs->_dopplerValid = true;
1098 frqObs->_doppler = rnxObs.value;
1099 break;
1100 case 'S':
1101 frqObs->_snrValid = true;
1102 frqObs->_snr = rnxObs.value;
1103 break;
1104 }
1105 }
1106 }
1107 }
1108}
1109
1110// Tracking Mode Priorities
1111////////////////////////////////////////////////////////////////////////////
1112QString t_rnxObsFile::signalPriorities(char sys) {
1113
1114 bncSettings settings;
1115 QStringList priorList = settings.value("rnxV2Priority").toString().split(" ", QString::SkipEmptyParts);
1116
1117 QString result;
1118 for (int ii = 0; ii < priorList.size(); ii++) {
1119 if (priorList[ii].indexOf(":") != -1) {
1120 QStringList hlp = priorList[ii].split(":", QString::SkipEmptyParts);
1121 if (hlp.size() == 2 && hlp[0].length() == 1 && hlp[0][0] == sys) {
1122 result = hlp[1];
1123 break;
1124 }
1125 }
1126 else {
1127 result = priorList[ii];
1128 }
1129 }
1130
1131 if (result.isEmpty()) {
1132 result = "CWPX_?";
1133 }
1134
1135 return result;
1136}
Note: See TracBrowser for help on using the repository browser.