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

Last change on this file since 6217 was 6217, checked in by mervart, 10 years ago
File size: 30.6 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 QMapIterator<char, QVector<QString> > it(_obsTypes);
412 while (it.hasNext()) {
413 it.next();
414 char sys = it.key();
415 const QVector<QString>& types = it.value();
416 QString hlp;
417 QTextStream(&hlp) << QString("%1 %2").arg(sys).arg(types.size(), 3);
418 for (int ii = 0; ii < types.size(); ii++) {
419 QTextStream(&hlp) << QString(" %1").arg(types[ii], -3);
420 if ((ii+1) % 13 == 0 || ii == types.size()-1) {
421 strList.append(hlp.leftJustified(60) + "SYS / # / OBS TYPES\n");
422 hlp = QString().leftJustified(6);
423 }
424 }
425 }
426 }
427
428 return strList;
429}
430
431// Constructor
432////////////////////////////////////////////////////////////////////////////
433t_rnxObsFile::t_rnxObsFile(const QString& fileName, e_inpOut inpOut) {
434 _inpOut = inpOut;
435 _stream = 0;
436 _flgPowerFail = false;
437 if (_inpOut == input) {
438 openRead(fileName);
439 }
440 else {
441 openWrite(fileName);
442 }
443}
444
445// Open for input
446////////////////////////////////////////////////////////////////////////////
447void t_rnxObsFile::openRead(const QString& fileName) {
448
449 _fileName = fileName; expandEnvVar(_fileName);
450 _file = new QFile(_fileName);
451 _file->open(QIODevice::ReadOnly | QIODevice::Text);
452 _stream = new QTextStream();
453 _stream->setDevice(_file);
454
455 _header.read(_stream);
456
457 // Guess Observation Interval
458 // --------------------------
459 if (_header._interval == 0.0) {
460 bncTime ttPrev;
461 for (int iEpo = 0; iEpo < 10; iEpo++) {
462 const t_rnxEpo* rnxEpo = nextEpoch();
463 if (!rnxEpo) {
464 throw QString("t_rnxObsFile: not enough epochs");
465 }
466 if (iEpo > 0) {
467 double dt = rnxEpo->tt - ttPrev;
468 if (_header._interval == 0.0 || dt < _header._interval) {
469 _header._interval = dt;
470 }
471 }
472 ttPrev = rnxEpo->tt;
473 }
474 _stream->seek(0);
475 _header.read(_stream);
476 }
477
478 // Time of first observation
479 // -------------------------
480 if (!_header._startTime.valid()) {
481 const t_rnxEpo* rnxEpo = nextEpoch();
482 if (!rnxEpo) {
483 throw QString("t_rnxObsFile: not enough epochs");
484 }
485 _header._startTime = rnxEpo->tt;
486 _stream->seek(0);
487 _header.read(_stream);
488 }
489}
490
491// Open for output
492////////////////////////////////////////////////////////////////////////////
493void t_rnxObsFile::openWrite(const QString& fileName) {
494
495 _fileName = fileName; expandEnvVar(_fileName);
496 _file = new QFile(_fileName);
497 _file->open(QIODevice::WriteOnly | QIODevice::Text);
498 _stream = new QTextStream();
499 _stream->setDevice(_file);
500}
501
502// Destructor
503////////////////////////////////////////////////////////////////////////////
504t_rnxObsFile::~t_rnxObsFile() {
505 close();
506}
507
508// Close
509////////////////////////////////////////////////////////////////////////////
510void t_rnxObsFile::close() {
511 delete _stream; _stream = 0;
512 delete _file; _file = 0;
513}
514
515// Handle Special Epoch Flag
516////////////////////////////////////////////////////////////////////////////
517void t_rnxObsFile::handleEpochFlag(int flag, const QString& line,
518 bool& headerReRead) {
519
520 headerReRead = false;
521
522 // Power Failure
523 // -------------
524 if (flag == 1) {
525 _flgPowerFail = true;
526 }
527
528 // Start moving antenna
529 // --------------------
530 else if (flag == 2) {
531 // no action
532 }
533
534 // Re-Read Header
535 // --------------
536 else if (flag == 3 || flag == 4 || flag == 5) {
537 int numLines = 0;
538 if (version() < 3.0) {
539 readInt(line, 29, 3, numLines);
540 }
541 else {
542 readInt(line, 32, 3, numLines);
543 }
544 if (flag == 3 || flag == 4) {
545 _header.read(_stream, numLines);
546 headerReRead = true;
547 }
548 else {
549 for (int ii = 0; ii < numLines; ii++) {
550 _stream->readLine();
551 }
552 }
553 }
554
555 // Unhandled Flag
556 // --------------
557 else {
558 throw QString("t_rnxObsFile: unhandled flag\n" + line);
559 }
560}
561
562// Retrieve single Epoch
563////////////////////////////////////////////////////////////////////////////
564t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpoch() {
565 _currEpo.clear();
566 if (version() < 3.0) {
567 return nextEpochV2();
568 }
569 else {
570 return nextEpochV3();
571 }
572}
573
574// Retrieve single Epoch (RINEX Version 3)
575////////////////////////////////////////////////////////////////////////////
576t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV3() {
577
578 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
579
580 QString line = _stream->readLine();
581
582 if (line.isEmpty()) {
583 continue;
584 }
585
586 int flag = 0;
587 readInt(line, 31, 1, flag);
588 if (flag > 0) {
589 bool headerReRead = false;
590 handleEpochFlag(flag, line, headerReRead);
591 if (headerReRead) {
592 continue;
593 }
594 }
595
596 QTextStream in(line.mid(1).toAscii(), QIODevice::ReadOnly);
597
598 // Epoch Time
599 // ----------
600 int year, month, day, hour, min;
601 double sec;
602 in >> year >> month >> day >> hour >> min >> sec;
603 _currEpo.tt.set(year, month, day, hour, min, sec);
604
605 // Number of Satellites
606 // --------------------
607 int numSat;
608 readInt(line, 32, 3, numSat);
609
610 _currEpo.rnxSat.resize(numSat);
611 _currEpo.version = _header._version;
612
613 // Observations
614 // ------------
615 for (int iSat = 0; iSat < numSat; iSat++) {
616 line = _stream->readLine();
617 t_prn prn; prn.set(line.left(3).toAscii().data());
618 _currEpo.rnxSat[iSat].prn = prn;
619 char sys = prn.system();
620 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
621 int pos = 3 + 16*iType;
622 double obsValue = 0.0;
623 int lli = 0;
624 int snr = 0;
625 readDbl(line, pos, 14, obsValue);
626 readInt(line, pos + 14, 1, lli);
627 readInt(line, pos + 15, 1, snr);
628 if (_flgPowerFail) {
629 lli |= 1;
630 }
631 QString type = obsType(sys, iType);
632 _currEpo.rnxSat[iSat].obs[type].value = obsValue;
633 _currEpo.rnxSat[iSat].obs[type].lli = lli;
634 _currEpo.rnxSat[iSat].obs[type].snr = snr;
635 }
636 }
637
638 _flgPowerFail = false;
639
640 return &_currEpo;
641 }
642
643 return 0;
644}
645
646// Retrieve single Epoch (RINEX Version 2)
647////////////////////////////////////////////////////////////////////////////
648t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV2() {
649
650 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
651
652 QString line = _stream->readLine();
653
654 if (line.isEmpty()) {
655 continue;
656 }
657
658 int flag = 0;
659 readInt(line, 28, 1, flag);
660 if (flag > 0) {
661 bool headerReRead = false;
662 handleEpochFlag(flag, line, headerReRead);
663 if (headerReRead) {
664 continue;
665 }
666 }
667
668 QTextStream in(line.toAscii(), QIODevice::ReadOnly);
669
670 // Epoch Time
671 // ----------
672 int year, month, day, hour, min;
673 double sec;
674 in >> year >> month >> day >> hour >> min >> sec;
675 if (year < 80) {
676 year += 2000;
677 }
678 else if (year < 100) {
679 year += 1900;
680 }
681 _currEpo.tt.set(year, month, day, hour, min, sec);
682
683 // Number of Satellites
684 // --------------------
685 int numSat;
686 readInt(line, 29, 3, numSat);
687
688 _currEpo.rnxSat.resize(numSat);
689 _currEpo.version = _header._version;
690
691 // Read Satellite Numbers
692 // ----------------------
693 int pos = 32;
694 for (int iSat = 0; iSat < numSat; iSat++) {
695 if (iSat > 0 && iSat % 12 == 0) {
696 line = _stream->readLine();
697 pos = 32;
698 }
699
700 char sys = line.toAscii()[pos];
701 int satNum; readInt(line, pos + 1, 2, satNum);
702 _currEpo.rnxSat[iSat].prn.set(sys, satNum);
703
704 pos += 3;
705 }
706
707 // Read Observation Records
708 // ------------------------
709 for (int iSat = 0; iSat < numSat; iSat++) {
710 char sys = _currEpo.rnxSat[iSat].prn.system();
711 line = _stream->readLine();
712 pos = 0;
713 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
714 if (iType > 0 && iType % 5 == 0) {
715 line = _stream->readLine();
716 pos = 0;
717 }
718 double obsValue = 0.0;
719 int lli = 0;
720 int snr = 0;
721 readDbl(line, pos, 14, obsValue);
722 readInt(line, pos + 14, 1, lli);
723 readInt(line, pos + 15, 1, snr);
724
725 if (_flgPowerFail) {
726 lli |= 1;
727 }
728
729 QString type = obsType(sys, iType);
730 _currEpo.rnxSat[iSat].obs[type].value = obsValue;
731 _currEpo.rnxSat[iSat].obs[type].lli = lli;
732 _currEpo.rnxSat[iSat].obs[type].snr = snr;
733
734 pos += 16;
735 }
736 }
737
738 _flgPowerFail = false;
739
740 return &_currEpo;
741 }
742
743 return 0;
744}
745
746// Set Header Information
747////////////////////////////////////////////////////////////////////////////
748void t_rnxObsFile::setHeader(const t_rnxObsHeader& header, double version,
749 const QStringList& useObsTypes) {
750
751 if (version < 3.0) {
752 _header._version = t_rnxObsHeader::defaultRnxObsVersion2;
753 }
754 else {
755 _header._version = t_rnxObsHeader::defaultRnxObsVersion3;
756 }
757 _header._interval = header._interval;
758 _header._antennaNumber = header._antennaNumber;
759 _header._antennaName = header._antennaName;
760 _header._markerName = header._markerName;
761 _header._markerNumber = header._markerNumber;
762 _header._antNEU = header._antNEU;
763 _header._antXYZ = header._antXYZ;
764 _header._antBSG = header._antBSG;
765 _header._xyz = header._xyz;
766 _header._observer = header._observer;
767 _header._agency = header._agency;
768 _header._receiverNumber = header._receiverNumber;
769 _header._receiverType = header._receiverType;
770 _header._receiverVersion = header._receiverVersion;
771 _header._startTime = header._startTime;
772 for (unsigned iPrn = 1; iPrn <= t_prn::MAXPRN_GPS; iPrn++) {
773 _header._wlFactorsL1[iPrn] = header._wlFactorsL1[iPrn];
774 _header._wlFactorsL2[iPrn] = header._wlFactorsL2[iPrn];
775 }
776
777 // Set observation types
778 // ---------------------
779 _header._obsTypes.clear();
780 if (useObsTypes.size() == 0) {
781 if (int(_header._version) == int(header._version)) {
782 _header._obsTypes = header._obsTypes;
783 }
784 else if (int(_header._version) == 2) {
785 char sys0 = t_rnxObsHeader::defaultSystems[0].toAscii();
786 for (int iObs = 0; iObs < header._obsTypes[sys0].size(); iObs++) {
787 for (int iSys = 0; iSys < t_rnxObsHeader::defaultSystems.length(); iSys++) {
788 char sysI = t_rnxObsHeader::defaultSystems[iSys].toAscii();
789 _header._obsTypes[sysI].push_back(header.obsType(sys0, iObs, _header._version));
790 }
791 }
792 }
793 else if (int(_header._version) == 3) {
794 char sys0 = t_rnxObsHeader::defaultSystems[0].toAscii();
795 for (int iSys = 0; iSys < t_rnxObsHeader::defaultSystems.length(); iSys++) {
796 char sysI = t_rnxObsHeader::defaultSystems[iSys].toAscii();
797 for (int iObs = 0; iObs < header._obsTypes[sys0].size(); iObs++) {
798 _header._obsTypes[sysI].push_back(header.obsType(sysI, iObs, _header._version));
799 }
800 }
801 }
802 }
803 else {
804 if (_header._version < 3.0) {
805 char sys0 = t_rnxObsHeader::defaultSystems[0].toAscii();
806 for (int iObs = 0; iObs < useObsTypes.size(); iObs++) {
807 _header._obsTypes[sys0].push_back(useObsTypes[iObs]);
808 }
809 for (int iSys = 1; iSys < t_rnxObsHeader::defaultSystems.length(); iSys++) {
810 char sysI = t_rnxObsHeader::defaultSystems[iSys].toAscii();
811 _header._obsTypes[sysI] = _header._obsTypes[sys0];
812 }
813 }
814 else {
815 for (int iObs = 0; iObs < useObsTypes.size(); iObs++) {
816 if (useObsTypes[iObs].indexOf(":") != -1) {
817 QStringList hlp = useObsTypes[iObs].split(":", QString::SkipEmptyParts);
818 if (hlp.size() == 2 && hlp[0].length() == 1) {
819 char sys = hlp[0][0].toAscii();
820 QString type = hlp[1];
821 _header._obsTypes[sys].push_back(type);
822 }
823 }
824 else {
825 QString type = useObsTypes[iObs];
826 for (int iSys = 0; iSys < t_rnxObsHeader::defaultSystems.length(); iSys++) {
827 char sys = t_rnxObsHeader::defaultSystems[iSys].toAscii();
828 _header._obsTypes[sys].push_back(type);
829 }
830 }
831 }
832 }
833 }
834}
835
836// Write Data Epoch
837////////////////////////////////////////////////////////////////////////////
838void t_rnxObsFile::writeEpoch(const t_rnxEpo* epo) {
839 if (version() < 3.0) {
840 return writeEpochV2(epo);
841 }
842 else {
843 return writeEpochV3(epo);
844 }
845}
846
847// Write Data Epoch (RINEX Version 2)
848////////////////////////////////////////////////////////////////////////////
849void t_rnxObsFile::writeEpochV2(const t_rnxEpo* epo) {
850
851 unsigned year, month, day, hour, min;
852 double sec;
853 epo->tt.civil_date(year, month, day);
854 epo->tt.civil_time(hour, min, sec);
855
856 QString dateStr;
857 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
858 .arg(int(fmod(year, 100)), 2, 10, QChar('0'))
859 .arg(month, 2, 10, QChar('0'))
860 .arg(day, 2, 10, QChar('0'))
861 .arg(hour, 2, 10, QChar('0'))
862 .arg(min, 2, 10, QChar('0'))
863 .arg(sec, 11, 'f', 7);
864
865 int flag = 0;
866 *_stream << dateStr << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
867 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
868 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
869 if (iSat > 0 && iSat % 12 == 0) {
870 *_stream << endl << QString().leftJustified(32);
871 }
872 *_stream << rnxSat.prn.toString().c_str();
873 }
874 *_stream << endl;
875 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
876
877 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
878 char sys = rnxSat.prn.system();
879
880 for (int iTypeV2 = 0; iTypeV2 < nTypes(sys); iTypeV2++) {
881 if (iTypeV2 > 0 && iTypeV2 % 5 == 0) {
882 *_stream << endl;
883 }
884 QString typeV2 = obsType(sys, iTypeV2);
885 bool found = false;
886 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
887 while (itObs.hasNext()) {
888 itObs.next();
889 const QString& type = itObs.key();
890 const t_rnxObs& rnxObs = itObs.value();
891 if (typeV2 == type3to2(sys, type)) {
892 found = true;
893 if (rnxObs.value == 0.0) {
894 *_stream << QString().leftJustified(16);
895 }
896 else {
897 *_stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
898 if (rnxObs.lli != 0.0) {
899 *_stream << QString("%1").arg(rnxObs.lli,1);
900 }
901 else {
902 *_stream << ' ';
903 }
904 if (rnxObs.snr != 0.0) {
905 *_stream << QString("%1").arg(rnxObs.snr,1);
906 }
907 else {
908 *_stream << ' ';
909 }
910 }
911 break;
912 }
913 }
914 if (!found) {
915 *_stream << QString().leftJustified(16);
916 }
917 }
918 *_stream << endl;
919 }
920}
921
922// Write Data Epoch (RINEX Version 3)
923////////////////////////////////////////////////////////////////////////////
924void t_rnxObsFile::writeEpochV3(const t_rnxEpo* epo) {
925
926 unsigned year, month, day, hour, min;
927 double sec;
928 epo->tt.civil_date(year, month, day);
929 epo->tt.civil_time(hour, min, sec);
930
931 QString dateStr;
932 QTextStream(&dateStr) << QString("> %1 %2 %3 %4 %5%6")
933 .arg(year, 4)
934 .arg(month, 2, 10, QChar('0'))
935 .arg(day, 2, 10, QChar('0'))
936 .arg(hour, 2, 10, QChar('0'))
937 .arg(min, 2, 10, QChar('0'))
938 .arg(sec, 11, 'f', 7);
939
940 int flag = 0;
941 *_stream << dateStr << QString("%1%2\n").arg(flag, 3).arg(epo->rnxSat.size(), 3);
942
943 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
944 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
945 char sys = rnxSat.prn.system();
946
947 *_stream << rnxSat.prn.toString().c_str();
948 for (int iType = 0; iType < nTypes(sys); iType++) {
949 QString type = obsType(sys, iType, epo->version);
950 if (!rnxSat.obs.contains(type)) {
951 *_stream << QString().leftJustified(16);
952 }
953 else {
954 const t_rnxObs& rnxObs = rnxSat.obs[type];
955 if (rnxObs.value == 0.0) {
956 *_stream << QString().leftJustified(16);
957 }
958 else {
959 *_stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
960 if (rnxObs.lli != 0.0) {
961 *_stream << QString("%1").arg(rnxObs.lli,1);
962 }
963 else {
964 *_stream << ' ';
965 }
966 if (rnxObs.snr != 0.0) {
967 *_stream << QString("%1").arg(rnxObs.snr,1);
968 }
969 else {
970 *_stream << ' ';
971 }
972 }
973 }
974 }
975 *_stream << endl;
976 }
977}
978
979// Translate Observation Type v2 --> v3
980////////////////////////////////////////////////////////////////////////////
981QString t_rnxObsFile::type2to3(char sys, const QString& typeV2) {
982 if (typeV2 == "P1") {
983 return (sys == 'G') ? "C1W" : "C1P";
984 }
985 else if (typeV2 == "P2") {
986 return (sys == 'G') ? "C2W" : "C2P";
987 }
988 return typeV2;
989}
990
991// Translate Observation Type v3 --> v2
992////////////////////////////////////////////////////////////////////////////
993QString t_rnxObsFile::type3to2(char /* sys */, const QString& typeV3) {
994 if (typeV3 == "C1P" || typeV3 == "C1W") {
995 return "P1";
996 }
997 else if (typeV3 == "C2P" || typeV3 == "C2W") {
998 return "P2";
999 }
1000 return typeV3.left(2);
1001}
1002
1003// Set Observations from RINEX File
1004////////////////////////////////////////////////////////////////////////////
1005void t_rnxObsFile::setObsFromRnx(const t_rnxObsFile* rnxObsFile, const t_rnxObsFile::t_rnxEpo* epo,
1006 const t_rnxObsFile::t_rnxSat& rnxSat, t_satObs& obs) {
1007
1008 obs._staID = rnxObsFile->markerName().toAscii().constData();
1009 obs._prn = rnxSat.prn;
1010 obs._time = epo->tt;
1011
1012 char sys = rnxSat.prn.system();
1013
1014 for (int iType = 0; iType < rnxObsFile->nTypes(sys); iType++) {
1015 QString type = rnxObsFile->obsType(sys, iType);
1016 if (rnxSat.obs.contains(type)) {
1017 const t_rnxObs& rnxObs = rnxSat.obs[type];
1018 if (rnxObs.value != 0.0) {
1019 string type2ch(type.mid(1).toAscii().data());
1020
1021 t_frqObs* frqObs = 0;
1022 for (unsigned iFrq = 0; iFrq < obs._obs.size(); iFrq++) {
1023 if (obs._obs[iFrq]->_rnxType2ch == type2ch) {
1024 frqObs = obs._obs[iFrq];
1025 break;
1026 }
1027 }
1028 if (frqObs == 0) {
1029 frqObs = new t_frqObs;
1030 frqObs->_rnxType2ch = type2ch;
1031 obs._obs.push_back(frqObs);
1032 }
1033
1034 switch( type.toAscii().data()[0] ) {
1035 case 'C':
1036 frqObs->_codeValid = true;
1037 frqObs->_code = rnxObs.value;
1038 break;
1039 case 'L':
1040 frqObs->_phaseValid = true;
1041 frqObs->_phase = rnxObs.value;
1042 frqObs->_slip = (rnxObs.lli & 1);
1043 break;
1044 case 'D':
1045 frqObs->_dopplerValid = true;
1046 frqObs->_doppler = rnxObs.value;
1047 break;
1048 case 'S':
1049 frqObs->_snrValid = true;
1050 frqObs->_snr = rnxObs.value;
1051 break;
1052 }
1053 }
1054 }
1055 }
1056}
1057
Note: See TracBrowser for help on using the repository browser.