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

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