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

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