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

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