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

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