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

Last change on this file since 4493 was 4493, 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 QStringList newComments;
213 QString runBy = app->userName();
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 newComments = 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 + newComments);
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 if (_interval > 0) {
305 *stream << QString("%1")
306 .arg(_interval, 10, 'f', 3)
307 .leftJustified(60)
308 << "INTERVAL\n";
309 }
310
311 unsigned year, month, day, hour, min;
312 double sec;
313 _startTime.civil_date(year, month, day);
314 _startTime.civil_time(hour, min, sec);
315 *stream << QString("%1%2%3%4%5%6%7")
316 .arg(year, 6)
317 .arg(month, 6)
318 .arg(day, 6)
319 .arg(hour, 6)
320 .arg(min, 6)
321 .arg(sec, 13, 'f', 7)
322 .arg("GPS", 8)
323 .leftJustified(60)
324 << "TIME OF FIRST OBS\n";
325
326 *stream << QString()
327 .leftJustified(60)
328 << "END OF HEADER\n";
329}
330
331// Number of Observation Types (satellite-system specific)
332////////////////////////////////////////////////////////////////////////////
333int t_rnxObsHeader::nTypes(char sys) const {
334 if (_version < 3.0) {
335 return _obsTypesV2.size();
336 }
337 else {
338 if (_obsTypesV3.contains(sys)) {
339 return _obsTypesV3[sys].size();
340 }
341 else {
342 return 0;
343 }
344 }
345}
346
347// Observation Type (satellite-system specific)
348////////////////////////////////////////////////////////////////////////////
349const QString& t_rnxObsHeader::obsType(char sys, int index) const {
350 if (_version < 3.0) {
351 return _obsTypesV2.at(index);
352 }
353 else {
354 if (_obsTypesV3.contains(sys)) {
355 return _obsTypesV3[sys].at(index);
356 }
357 else {
358 return _emptyStr;
359 }
360 }
361}
362
363// Write Observation Types
364////////////////////////////////////////////////////////////////////////////
365QStringList t_rnxObsHeader::obsTypesStrings() const {
366
367 QStringList strList;
368
369 if (_version < 3.0) {
370 QString hlp;
371 QTextStream(&hlp) << QString("%1").arg(_obsTypesV2.size(), 6);
372 for (int ii = 0; ii < _obsTypesV2.size(); ii++) {
373 QTextStream(&hlp) << QString("%1").arg(_obsTypesV2[ii], 6);
374 if ((ii+1) % 9 == 0 || ii == _obsTypesV2.size()-1) {
375 strList.append(hlp.leftJustified(60) + "# / TYPES OF OBSERV\n");
376 hlp = QString().leftJustified(6);
377 }
378 }
379 }
380 else {
381 QMapIterator<char, QVector<QString> > it(_obsTypesV3);
382 while (it.hasNext()) {
383 it.next();
384 char sys = it.key();
385 const QVector<QString>& types = it.value();
386 QString hlp;
387 QTextStream(&hlp) << QString("%1 %2").arg(sys).arg(types.size(), 3);
388 for (int ii = 0; ii < types.size(); ii++) {
389 QTextStream(&hlp) << QString(" %1").arg(types[ii], -3);
390 if ((ii+1) % 13 == 0 || ii == types.size()-1) {
391 strList.append(hlp.leftJustified(60) + "SYS / # / OBS TYPES\n");
392 hlp = QString().leftJustified(6);
393 }
394 }
395 }
396 }
397
398 return strList;
399}
400
401// Constructor
402////////////////////////////////////////////////////////////////////////////
403t_rnxObsFile::t_rnxObsFile(const QString& fileName, e_inpOut inpOut) {
404 _inpOut = inpOut;
405 _stream = 0;
406 _flgPowerFail = false;
407 _trafo = trafoNone;
408 if (_inpOut == input) {
409 openRead(fileName);
410 }
411 else {
412 openWrite(fileName);
413 }
414}
415
416// Open for input
417////////////////////////////////////////////////////////////////////////////
418void t_rnxObsFile::openRead(const QString& fileName) {
419
420 _fileName = fileName; expandEnvVar(_fileName);
421 _file = new QFile(_fileName);
422 _file->open(QIODevice::ReadOnly | QIODevice::Text);
423 _stream = new QTextStream();
424 _stream->setDevice(_file);
425
426 _header.read(_stream);
427
428 // Guess Observation Interval
429 // --------------------------
430 if (_header._interval == 0.0) {
431 bncTime ttPrev;
432 for (int iEpo = 0; iEpo < 10; iEpo++) {
433 const t_rnxEpo* rnxEpo = nextEpoch();
434 if (!rnxEpo) {
435 throw QString("t_rnxObsFile: not enough epochs");
436 }
437 if (iEpo > 0) {
438 double dt = rnxEpo->tt - ttPrev;
439 if (_header._interval == 0.0 || dt < _header._interval) {
440 _header._interval = dt;
441 }
442 }
443 ttPrev = rnxEpo->tt;
444 }
445 _stream->seek(0);
446 _header.read(_stream);
447 }
448
449 // Time of first observation
450 // -------------------------
451 if (!_header._startTime.valid()) {
452 const t_rnxEpo* rnxEpo = nextEpoch();
453 if (!rnxEpo) {
454 throw QString("t_rnxObsFile: not enough epochs");
455 }
456 _header._startTime = rnxEpo->tt;
457 _stream->seek(0);
458 _header.read(_stream);
459 }
460}
461
462// Open for output
463////////////////////////////////////////////////////////////////////////////
464void t_rnxObsFile::openWrite(const QString& fileName) {
465
466 _fileName = fileName; expandEnvVar(_fileName);
467 _file = new QFile(_fileName);
468 _file->open(QIODevice::WriteOnly | QIODevice::Text);
469 _stream = new QTextStream();
470 _stream->setDevice(_file);
471}
472
473// Destructor
474////////////////////////////////////////////////////////////////////////////
475t_rnxObsFile::~t_rnxObsFile() {
476 close();
477}
478
479// Close
480////////////////////////////////////////////////////////////////////////////
481void t_rnxObsFile::close() {
482 delete _stream; _stream = 0;
483 delete _file; _file = 0;
484}
485
486// Handle Special Epoch Flag
487////////////////////////////////////////////////////////////////////////////
488void t_rnxObsFile::handleEpochFlag(int flag, const QString& line) {
489
490 // Power Failure
491 // -------------
492 if (flag == 1) {
493 _flgPowerFail = true;
494 }
495
496 // Start moving antenna
497 // --------------------
498 else if (flag == 2) {
499 // no action
500 }
501
502 // Re-Read Header
503 // --------------
504 else if (flag == 3 || flag == 4) {
505 int numLines = 0;
506 if (version() < 3.0) {
507 readInt(line, 29, 3, numLines);
508 }
509 else {
510 readInt(line, 32, 3, numLines);
511 }
512 _header.read(_stream, numLines);
513 }
514
515 // Unhandled Flag
516 // --------------
517 else {
518 throw QString("t_rnxObsFile: unhandled flag\n" + line);
519 }
520}
521
522// Retrieve single Epoch
523////////////////////////////////////////////////////////////////////////////
524t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpoch() {
525
526 _currEpo.clear();
527
528 if (version() < 3.0) {
529 return nextEpochV2();
530 }
531 else {
532 return nextEpochV3();
533 }
534}
535
536// Retrieve single Epoch (RINEX Version 3)
537////////////////////////////////////////////////////////////////////////////
538t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV3() {
539
540 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
541
542 QString line = _stream->readLine();
543
544 if (line.isEmpty()) {
545 continue;
546 }
547
548 int flag = 0;
549 readInt(line, 31, 1, flag);
550 if (flag > 0) {
551 handleEpochFlag(flag, line);
552 continue;
553 }
554
555 QTextStream in(line.mid(1).toAscii(), QIODevice::ReadOnly);
556
557 // Epoch Time
558 // ----------
559 int year, month, day, hour, min;
560 double sec;
561 in >> year >> month >> day >> hour >> min >> sec;
562 _currEpo.tt.set(year, month, day, hour, min, sec);
563
564 // Number of Satellites
565 // --------------------
566 int numSat;
567 readInt(line, 32, 3, numSat);
568
569 _currEpo.rnxSat.resize(numSat);
570
571 // Observations
572 // ------------
573 for (int iSat = 0; iSat < numSat; iSat++) {
574 line = _stream->readLine();
575 _currEpo.rnxSat[iSat].satSys = line.toAscii()[0];
576 readInt(line, 1, 2, _currEpo.rnxSat[iSat].satNum);
577 char sys = line.toAscii()[0];
578 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
579 int pos = 3 + 16*iType;
580 double obsValue = 0.0;
581 int lli = 0;
582 int snr = 0;
583 readDbl(line, pos, 14, obsValue);
584 readInt(line, pos + 14, 1, lli);
585 readInt(line, pos + 15, 1, snr);
586
587 if (_flgPowerFail) {
588 lli |= 1;
589 }
590
591 _currEpo.rnxSat[iSat].obs.push_back(obsValue);
592 _currEpo.rnxSat[iSat].lli.push_back(lli);
593 _currEpo.rnxSat[iSat].snr.push_back(snr);
594 }
595 }
596
597 _flgPowerFail = false;
598
599 return &_currEpo;
600 }
601
602 return 0;
603}
604
605// Retrieve single Epoch (RINEX Version 2)
606////////////////////////////////////////////////////////////////////////////
607t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV2() {
608
609 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
610
611 QString line = _stream->readLine();
612
613 if (line.isEmpty()) {
614 continue;
615 }
616
617 int flag = 0;
618 readInt(line, 28, 1, flag);
619 if (flag > 0) {
620 handleEpochFlag(flag, line);
621 continue;
622 }
623
624 QTextStream in(line.toAscii(), QIODevice::ReadOnly);
625
626 // Epoch Time
627 // ----------
628 int year, month, day, hour, min;
629 double sec;
630 in >> year >> month >> day >> hour >> min >> sec;
631 if (year < 80) {
632 year += 2000;
633 }
634 else if (year < 100) {
635 year += 1900;
636 }
637 _currEpo.tt.set(year, month, day, hour, min, sec);
638
639 // Number of Satellites
640 // --------------------
641 int numSat;
642 readInt(line, 29, 3, numSat);
643
644 _currEpo.rnxSat.resize(numSat);
645
646 // Read Satellite Numbers
647 // ----------------------
648 int pos = 32;
649 for (int iSat = 0; iSat < numSat; iSat++) {
650 if (iSat > 0 && iSat % 12 == 0) {
651 line = _stream->readLine();
652 pos = 32;
653 }
654
655 _currEpo.rnxSat[iSat].satSys = line.toAscii()[pos];
656 readInt(line, pos + 1, 2, _currEpo.rnxSat[iSat].satNum);
657
658 pos += 3;
659 }
660
661 // Read Observation Records
662 // ------------------------
663 for (int iSat = 0; iSat < numSat; iSat++) {
664 line = _stream->readLine();
665 pos = 0;
666 for (int iType = 0; iType < _header.nTypes(_currEpo.rnxSat[iSat].satSys); iType++) {
667 if (iType > 0 && iType % 5 == 0) {
668 line = _stream->readLine();
669 pos = 0;
670 }
671 double obsValue = 0.0;
672 int lli = 0;
673 int snr = 0;
674 readDbl(line, pos, 14, obsValue);
675 readInt(line, pos + 14, 1, lli);
676 readInt(line, pos + 15, 1, snr);
677
678 if (_flgPowerFail) {
679 lli |= 1;
680 }
681
682 _currEpo.rnxSat[iSat].obs.push_back(obsValue);
683 _currEpo.rnxSat[iSat].lli.push_back(lli);
684 _currEpo.rnxSat[iSat].snr.push_back(snr);
685
686 pos += 16;
687 }
688 }
689
690 _flgPowerFail = false;
691
692 return &_currEpo;
693 }
694
695 return 0;
696}
697
698// Set Header Information
699////////////////////////////////////////////////////////////////////////////
700void t_rnxObsFile::setHeader(const t_rnxObsHeader& header, double version) {
701
702 if (int(header._version) == int(version)) {
703 _trafo = trafoNone;
704 _header._version = header._version;
705 }
706 else if (version >= 3.0) {
707 _trafo = trafo2to3;
708 _header._version = 3.01;
709 }
710 else {
711 _trafo = trafo3to2;
712 _header._version = 2.11;
713 }
714
715 _header._interval = header._interval;
716 _header._antennaNumber = header._antennaNumber;
717 _header._antennaName = header._antennaName;
718 _header._markerName = header._markerName;
719 _header._markerNumber = header._markerNumber;
720 _header._antNEU = header._antNEU;
721 _header._antXYZ = header._antXYZ;
722 _header._antBSG = header._antBSG;
723 _header._xyz = header._xyz;
724 _header._observer = header._observer;
725 _header._agency = header._agency;
726 _header._receiverNumber = header._receiverNumber;
727 _header._receiverType = header._receiverType;
728 _header._receiverVersion = header._receiverVersion;
729
730 for (unsigned iPrn = 1; iPrn <= MAXPRN_GPS; iPrn++) {
731 _header._wlFactorsL1[iPrn] = header._wlFactorsL1[iPrn];
732 _header._wlFactorsL2[iPrn] = header._wlFactorsL2[iPrn];
733 }
734
735 _header._startTime = header._startTime;
736
737 static const string systems = "GRES";
738
739 _header._obsTypesV2.clear();
740 _header._obsTypesV3.clear();
741
742 // Copy Observation Types
743 // ----------------------
744 if (_trafo == trafoNone) {
745 for (int ii = 0; ii < header._obsTypesV2.size(); ii++) {
746 _header._obsTypesV2.append(header._obsTypesV2[ii]);
747 }
748 QMapIterator<char, QVector<QString> > it(header._obsTypesV3);
749 while (it.hasNext()) {
750 it.next();
751 char sys = it.key();
752 const QVector<QString>& typesV3 = it.value();
753 for (int ii = 0; ii < typesV3.size(); ii++) {
754 _header._obsTypesV3[sys].push_back(typesV3[ii]);
755 }
756 }
757 }
758
759 // Translate Observation Types v2 --> v3
760 // -------------------------------------
761 else if (_trafo == trafo2to3) {
762 for (int i2 = 0; i2 < header._obsTypesV2.size(); i2++) {
763 const QString& typeV2 = header._obsTypesV2[i2];
764 for (unsigned iSys = 0; iSys < systems.length(); iSys++) {
765 char sys = systems[iSys];
766 QString typeV3 = type2to3(sys, typeV2);
767 if (!typeV3.isEmpty()) {
768 _header._obsTypesV3[sys].push_back(typeV3);
769 int i3 = _header._obsTypesV3[sys].size() - 1;
770 _indexMap3to2[sys][i3] = i2;
771 }
772 }
773 }
774 }
775
776 // Translate Observation Types v3 --> v2
777 // -------------------------------------
778 else if (_trafo == trafo3to2) {
779 for (unsigned iSys = 0; iSys < systems.length(); iSys++) {
780 char sys = systems[iSys];
781 if (header._obsTypesV3.contains(sys)) {
782 const QVector<QString>& typesV3 = header._obsTypesV3[sys];
783 for (int i3 = 0; i3 < typesV3.size(); i3++) {
784 const QString& typeV3 = typesV3[i3];
785 QString typeV2 = type3to2(typeV3);
786 if (!typeV2.isEmpty()) {
787 bool found = false;
788 for (int i2 = 0; i2 < _header._obsTypesV2.size(); i2++) {
789 if (_header._obsTypesV2[i2] == typeV2) {
790 found = true;
791 if (_indexMap2to3[sys].find(i2) == _indexMap2to3[sys].end()) {
792 _indexMap2to3[sys][i2] = i3;
793 }
794 break;
795 }
796 }
797 if (!found) {
798 _header._obsTypesV2.append(typeV2);
799 int i2 = _header._obsTypesV2.size() - 1;
800 _indexMap2to3[sys][i2] = i3;
801 }
802 }
803 }
804 }
805 }
806 }
807}
808
809// Write Data Epoch
810////////////////////////////////////////////////////////////////////////////
811void t_rnxObsFile::writeEpoch(const t_rnxEpo* epo) {
812 if (version() < 3.0) {
813 return writeEpochV2(epo);
814 }
815 else {
816 return writeEpochV3(epo);
817 }
818}
819
820// Write Data Epoch (RINEX Version 2)
821////////////////////////////////////////////////////////////////////////////
822void t_rnxObsFile::writeEpochV2(const t_rnxEpo* epo) {
823
824 unsigned year, month, day, hour, min;
825 double sec;
826 epo->tt.civil_date(year, month, day);
827 epo->tt.civil_time(hour, min, sec);
828
829 QString dateStr;
830 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
831 .arg(int(fmod(year, 100)), 2, 10, QChar('0'))
832 .arg(month, 2, 10, QChar('0'))
833 .arg(day, 2, 10, QChar('0'))
834 .arg(hour, 2, 10, QChar('0'))
835 .arg(min, 2, 10, QChar('0'))
836 .arg(sec, 11, 'f', 7);
837
838 int flag = 0;
839 *_stream << dateStr
840 << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
841 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
842 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
843 if (iSat > 0 && iSat % 12 == 0) {
844 *_stream << endl << QString().leftJustified(32);
845 }
846 *_stream << rnxSat.satSys << QString("%1").arg(rnxSat.satNum, 2);
847 }
848 *_stream << endl;
849 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
850
851 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
852 char sys = rnxSat.satSys;
853
854 for (int iTypeV2 = 0; iTypeV2 < nTypes(sys); iTypeV2++) {
855
856 if (iTypeV2 > 0 && iTypeV2 % 5 == 0) {
857 *_stream << endl;
858 }
859
860 int iType = -1;
861 if (_trafo == trafoNone) {
862 iType = iTypeV2;
863 }
864 else {
865 if (_indexMap2to3[sys].find(iTypeV2) != _indexMap2to3[sys].end()) {
866 iType = _indexMap2to3[sys][iTypeV2];
867 }
868 }
869
870 if (iType == -1 || rnxSat.obs[iType] == 0.0) {
871 *_stream << QString().leftJustified(16);
872 }
873 else {
874 *_stream << QString("%1").arg(rnxSat.obs[iType], 14, 'f', 3);
875 if (rnxSat.lli[iType] != 0.0) {
876 *_stream << QString("%1").arg(rnxSat.lli[iType],1);
877 }
878 else {
879 *_stream << ' ';
880 }
881 if (rnxSat.snr[iType] != 0.0) {
882 *_stream << QString("%1").arg(rnxSat.snr[iType],1);
883 }
884 else {
885 *_stream << ' ';
886 }
887 }
888 }
889 *_stream << endl;
890 }
891}
892
893// Write Data Epoch (RINEX Version 3)
894////////////////////////////////////////////////////////////////////////////
895void t_rnxObsFile::writeEpochV3(const t_rnxEpo* epo) {
896
897 unsigned year, month, day, hour, min;
898 double sec;
899 epo->tt.civil_date(year, month, day);
900 epo->tt.civil_time(hour, min, sec);
901
902 QString dateStr;
903 QTextStream(&dateStr) << QString("> %1 %2 %3 %4 %5%6")
904 .arg(year, 4)
905 .arg(month, 2, 10, QChar('0'))
906 .arg(day, 2, 10, QChar('0'))
907 .arg(hour, 2, 10, QChar('0'))
908 .arg(min, 2, 10, QChar('0'))
909 .arg(sec, 11, 'f', 7);
910
911 int flag = 0;
912 *_stream << dateStr
913 << QString("%1%2\n").arg(flag, 3).arg(epo->rnxSat.size(), 3);
914
915 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
916 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
917 char sys = rnxSat.satSys;
918 *_stream << sys
919 << QString("%1").arg(rnxSat.satNum, 2, 10, QChar('0'));
920
921 for (int iTypeV3 = 0; iTypeV3 < nTypes(sys); iTypeV3++) {
922
923 int iType = -1;
924 if (_trafo == trafoNone) {
925 iType = iTypeV3;
926 }
927 else {
928 if (_indexMap3to2[sys].find(iTypeV3) != _indexMap3to2[sys].end()) {
929 iType = _indexMap3to2[sys][iTypeV3];
930 }
931 }
932
933 if (iType == -1 || rnxSat.obs[iType] == 0.0) {
934 *_stream << QString().leftJustified(16);
935 }
936 else {
937 *_stream << QString("%1").arg(rnxSat.obs[iType], 14, 'f', 3);
938 if (rnxSat.lli[iType] != 0.0) {
939 *_stream << QString("%1").arg(rnxSat.lli[iType],1);
940 }
941 else {
942 *_stream << ' ';
943 }
944 if (rnxSat.snr[iType] != 0.0) {
945 *_stream << QString("%1").arg(rnxSat.snr[iType],1);
946 }
947 else {
948 *_stream << ' ';
949 }
950 }
951 }
952 *_stream << endl;
953 }
954}
955
956// Translate Observation Type v2 --> v3
957////////////////////////////////////////////////////////////////////////////
958QString t_rnxObsFile::type2to3(char sys, const QString& typeV2) {
959
960 if (sys == 'G') {
961 if (typeV2 == "C1") return "C1C";
962 if (typeV2 == "C2") return "C2C";
963 if (typeV2 == "C5") return "C5C";
964 if (typeV2 == "P1") return "C1P";
965 if (typeV2 == "P2") return "C2P";
966 if (typeV2 == "L1") return "L1";
967 if (typeV2 == "L2") return "L2";
968 if (typeV2 == "L5") return "L5";
969 if (typeV2 == "D1") return "D1";
970 if (typeV2 == "D2") return "D2";
971 if (typeV2 == "D5") return "D5";
972 if (typeV2 == "S1") return "S1";
973 if (typeV2 == "S2") return "S2";
974 if (typeV2 == "S5") return "S5";
975 }
976
977 else if (sys == 'R') {
978 if (typeV2 == "C1") return "C1C";
979 if (typeV2 == "C2") return "C2C";
980 if (typeV2 == "P1") return "C1P";
981 if (typeV2 == "P2") return "C2P";
982 if (typeV2 == "L1") return "L1";
983 if (typeV2 == "L2") return "L2";
984 if (typeV2 == "D1") return "D1";
985 if (typeV2 == "D2") return "D2";
986 if (typeV2 == "S1") return "S1";
987 if (typeV2 == "S2") return "S2";
988 }
989
990 else if (sys == 'E') {
991 if (typeV2 == "C1") return "C1";
992 if (typeV2 == "C5") return "C5";
993 if (typeV2 == "C6") return "C6";
994 if (typeV2 == "C7") return "C7";
995 if (typeV2 == "C8") return "C8";
996 if (typeV2 == "L1") return "L1";
997 if (typeV2 == "L5") return "L5";
998 if (typeV2 == "L6") return "L6";
999 if (typeV2 == "L7") return "L7";
1000 if (typeV2 == "L8") return "L8";
1001 if (typeV2 == "D1") return "D1";
1002 if (typeV2 == "D5") return "D5";
1003 if (typeV2 == "D6") return "D6";
1004 if (typeV2 == "D7") return "D7";
1005 if (typeV2 == "D8") return "D8";
1006 if (typeV2 == "S1") return "S1";
1007 if (typeV2 == "S5") return "S5";
1008 if (typeV2 == "S6") return "S6";
1009 if (typeV2 == "S7") return "S7";
1010 if (typeV2 == "S8") return "S8";
1011 }
1012
1013 else if (sys == 'S') {
1014 if (typeV2 == "C1") return "C1C";
1015 if (typeV2 == "C5") return "C5C";
1016 if (typeV2 == "L1") return "L1";
1017 if (typeV2 == "L5") return "L5";
1018 if (typeV2 == "D1") return "D1";
1019 if (typeV2 == "D5") return "D5";
1020 if (typeV2 == "S1") return "S1";
1021 if (typeV2 == "S5") return "S5";
1022 }
1023
1024 return "";
1025}
1026
1027// Translate Observation Type v3 --> v2
1028////////////////////////////////////////////////////////////////////////////
1029QString t_rnxObsFile::type3to2(const QString& typeV3) {
1030 if (typeV3 == "C1P") {
1031 return "P1";
1032 }
1033 else if (typeV3 == "C2P") {
1034 return "P2";
1035 }
1036 else {
1037 return typeV3.left(2);
1038 }
1039
1040 return "";
1041}
1042
1043// Check for Changes in Header
1044////////////////////////////////////////////////////////////////////////////
1045void t_rnxObsFile::checkNewHeader(const t_rnxObsHeader& header) {
1046
1047 t_rnxObsHeader oldHeader(_header);
1048 setHeader(header, oldHeader._version);
1049
1050 // Check Observation Types
1051 // -----------------------
1052 bool same = true;
1053 if (_header._version < 3.0) {
1054 if (_header._obsTypesV2 != oldHeader._obsTypesV2) {
1055 same = false;
1056 }
1057 }
1058 else {
1059 QMapIterator<char, QVector<QString> > it(_header._obsTypesV3);
1060 while (it.hasNext()) {
1061 it.next();
1062 char sys = it.key();
1063 const QVector<QString>& typesV3 = it.value();
1064 if (!oldHeader._obsTypesV3.contains(sys) ||
1065 oldHeader._obsTypesV3[sys] != typesV3) {
1066 same = false;
1067 break;
1068 }
1069 }
1070 }
1071
1072 if (!same) {
1073 QStringList strLst = _header.obsTypesStrings();
1074 int numBlanks = _header._version < 3.0 ? 26 : 29;
1075 *_stream << QString().leftJustified(numBlanks)
1076 << QString(" 4%1\n").arg(strLst.size(), 3)
1077 << strLst.join("");
1078 }
1079}
Note: See TracBrowser for help on using the repository browser.