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

Last change on this file since 5468 was 5468, checked in by mervart, 11 years ago
File size: 30.9 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 || flag == 5) {
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 if (flag == 3 || flag == 4) {
518 _header.read(_stream, numLines);
519 headerReRead = true;
520 }
521 else {
522 for (int ii = 0; ii < numLines; ii++) {
523 _stream->readLine();
524 }
525 }
526 }
527
528 // Unhandled Flag
529 // --------------
530 else {
531 throw QString("t_rnxObsFile: unhandled flag\n" + line);
532 }
533}
534
535// Retrieve single Epoch
536////////////////////////////////////////////////////////////////////////////
537t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpoch() {
538
539 _currEpo.clear();
540
541 if (version() < 3.0) {
542 return nextEpochV2();
543 }
544 else {
545 return nextEpochV3();
546 }
547}
548
549// Retrieve single Epoch (RINEX Version 3)
550////////////////////////////////////////////////////////////////////////////
551t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV3() {
552
553 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
554
555 QString line = _stream->readLine();
556
557 if (line.isEmpty()) {
558 continue;
559 }
560
561 int flag = 0;
562 readInt(line, 31, 1, flag);
563 if (flag > 0) {
564 bool headerReRead = false;
565 handleEpochFlag(flag, line, headerReRead);
566 if (headerReRead) {
567 continue;
568 }
569 }
570
571 QTextStream in(line.mid(1).toAscii(), QIODevice::ReadOnly);
572
573 // Epoch Time
574 // ----------
575 int year, month, day, hour, min;
576 double sec;
577 in >> year >> month >> day >> hour >> min >> sec;
578 _currEpo.tt.set(year, month, day, hour, min, sec);
579
580 // Number of Satellites
581 // --------------------
582 int numSat;
583 readInt(line, 32, 3, numSat);
584
585 _currEpo.rnxSat.resize(numSat);
586
587 // Observations
588 // ------------
589 for (int iSat = 0; iSat < numSat; iSat++) {
590 line = _stream->readLine();
591 _currEpo.rnxSat[iSat].satSys = line.toAscii()[0];
592 readInt(line, 1, 2, _currEpo.rnxSat[iSat].satNum);
593 char sys = line.toAscii()[0];
594 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
595 int pos = 3 + 16*iType;
596 double obsValue = 0.0;
597 int lli = 0;
598 int snr = 0;
599 readDbl(line, pos, 14, obsValue);
600 readInt(line, pos + 14, 1, lli);
601 readInt(line, pos + 15, 1, snr);
602
603 if (_flgPowerFail) {
604 lli |= 1;
605 }
606
607 _currEpo.rnxSat[iSat].obs.push_back(obsValue);
608 _currEpo.rnxSat[iSat].lli.push_back(lli);
609 _currEpo.rnxSat[iSat].snr.push_back(snr);
610 }
611 }
612
613 _flgPowerFail = false;
614
615 return &_currEpo;
616 }
617
618 return 0;
619}
620
621// Retrieve single Epoch (RINEX Version 2)
622////////////////////////////////////////////////////////////////////////////
623t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV2() {
624
625 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
626
627 QString line = _stream->readLine();
628
629 if (line.isEmpty()) {
630 continue;
631 }
632
633 int flag = 0;
634 readInt(line, 28, 1, flag);
635 if (flag > 0) {
636 bool headerReRead = false;
637 handleEpochFlag(flag, line, headerReRead);
638 if (headerReRead) {
639 continue;
640 }
641 }
642
643 QTextStream in(line.toAscii(), QIODevice::ReadOnly);
644
645 // Epoch Time
646 // ----------
647 int year, month, day, hour, min;
648 double sec;
649 in >> year >> month >> day >> hour >> min >> sec;
650 if (year < 80) {
651 year += 2000;
652 }
653 else if (year < 100) {
654 year += 1900;
655 }
656 _currEpo.tt.set(year, month, day, hour, min, sec);
657
658 // Number of Satellites
659 // --------------------
660 int numSat;
661 readInt(line, 29, 3, numSat);
662
663 _currEpo.rnxSat.resize(numSat);
664
665 // Read Satellite Numbers
666 // ----------------------
667 int pos = 32;
668 for (int iSat = 0; iSat < numSat; iSat++) {
669 if (iSat > 0 && iSat % 12 == 0) {
670 line = _stream->readLine();
671 pos = 32;
672 }
673
674 _currEpo.rnxSat[iSat].satSys = line.toAscii()[pos];
675 if (_currEpo.rnxSat[iSat].satSys == ' ') {
676 _currEpo.rnxSat[iSat].satSys = 'G';
677 }
678 readInt(line, pos + 1, 2, _currEpo.rnxSat[iSat].satNum);
679
680 pos += 3;
681 }
682
683 // Read Observation Records
684 // ------------------------
685 for (int iSat = 0; iSat < numSat; iSat++) {
686 line = _stream->readLine();
687 pos = 0;
688 for (int iType = 0; iType < _header.nTypes(_currEpo.rnxSat[iSat].satSys); iType++) {
689 if (iType > 0 && iType % 5 == 0) {
690 line = _stream->readLine();
691 pos = 0;
692 }
693 double obsValue = 0.0;
694 int lli = 0;
695 int snr = 0;
696 readDbl(line, pos, 14, obsValue);
697 readInt(line, pos + 14, 1, lli);
698 readInt(line, pos + 15, 1, snr);
699
700 if (_flgPowerFail) {
701 lli |= 1;
702 }
703
704 _currEpo.rnxSat[iSat].obs.push_back(obsValue);
705 _currEpo.rnxSat[iSat].lli.push_back(lli);
706 _currEpo.rnxSat[iSat].snr.push_back(snr);
707
708 pos += 16;
709 }
710 }
711
712 _flgPowerFail = false;
713
714 return &_currEpo;
715 }
716
717 return 0;
718}
719
720// Set Header Information
721////////////////////////////////////////////////////////////////////////////
722void t_rnxObsFile::setHeader(const t_rnxObsHeader& header, double version) {
723
724 if (int(header._version) == int(version)) {
725 _trafo = trafoNone;
726 _header._version = header._version;
727 }
728 else if (version >= 3.0) {
729 _trafo = trafo2to3;
730 _header._version = t_rnxObsHeader::defaultRnxObsVersion3;
731 }
732 else {
733 _trafo = trafo3to2;
734 _header._version = t_rnxObsHeader::defaultRnxObsVersion2;
735 }
736
737 _header._interval = header._interval;
738 _header._antennaNumber = header._antennaNumber;
739 _header._antennaName = header._antennaName;
740 _header._markerName = header._markerName;
741 _header._markerNumber = header._markerNumber;
742 _header._antNEU = header._antNEU;
743 _header._antXYZ = header._antXYZ;
744 _header._antBSG = header._antBSG;
745 _header._xyz = header._xyz;
746 _header._observer = header._observer;
747 _header._agency = header._agency;
748 _header._receiverNumber = header._receiverNumber;
749 _header._receiverType = header._receiverType;
750 _header._receiverVersion = header._receiverVersion;
751
752 for (unsigned iPrn = 1; iPrn <= MAXPRN_GPS; iPrn++) {
753 _header._wlFactorsL1[iPrn] = header._wlFactorsL1[iPrn];
754 _header._wlFactorsL2[iPrn] = header._wlFactorsL2[iPrn];
755 }
756
757 _header._startTime = header._startTime;
758
759 static const string systems = "GRES";
760
761 _header._obsTypesV2.clear();
762 _header._obsTypesV3.clear();
763
764 // Copy Observation Types
765 // ----------------------
766 if (_trafo == trafoNone) {
767 for (int ii = 0; ii < header._obsTypesV2.size(); ii++) {
768 _header._obsTypesV2.append(header._obsTypesV2[ii]);
769 }
770 QMapIterator<char, QVector<QString> > it(header._obsTypesV3);
771 while (it.hasNext()) {
772 it.next();
773 char sys = it.key();
774 const QVector<QString>& typesV3 = it.value();
775 for (int ii = 0; ii < typesV3.size(); ii++) {
776 _header._obsTypesV3[sys].push_back(typesV3[ii]);
777 }
778 }
779 }
780
781 // Translate Observation Types v2 --> v3
782 // -------------------------------------
783 else if (_trafo == trafo2to3) {
784 for (int i2 = 0; i2 < header._obsTypesV2.size(); i2++) {
785 const QString& typeV2 = header._obsTypesV2[i2];
786 for (unsigned iSys = 0; iSys < systems.length(); iSys++) {
787 char sys = systems[iSys];
788 QString typeV3 = type2to3(sys, typeV2);
789 if (!typeV3.isEmpty()) {
790 _header._obsTypesV3[sys].push_back(typeV3);
791 int i3 = _header._obsTypesV3[sys].size() - 1;
792 _indexMap3to2[sys][i3] = i2;
793 }
794 }
795 }
796 }
797
798 // Translate Observation Types v3 --> v2
799 // -------------------------------------
800 else if (_trafo == trafo3to2) {
801 for (unsigned iSys = 0; iSys < systems.length(); iSys++) {
802 char sys = systems[iSys];
803 if (header._obsTypesV3.contains(sys)) {
804 const QVector<QString>& typesV3 = header._obsTypesV3[sys];
805 for (int i3 = 0; i3 < typesV3.size(); i3++) {
806 const QString& typeV3 = typesV3[i3];
807 QString typeV2 = type3to2(typeV3);
808 if (!typeV2.isEmpty()) {
809 bool found = false;
810 for (int i2 = 0; i2 < _header._obsTypesV2.size(); i2++) {
811 if (_header._obsTypesV2[i2] == typeV2) {
812 found = true;
813 if (_indexMap2to3[sys].find(i2) == _indexMap2to3[sys].end()) {
814 _indexMap2to3[sys][i2] = i3;
815 }
816 break;
817 }
818 }
819 if (!found) {
820 _header._obsTypesV2.append(typeV2);
821 int i2 = _header._obsTypesV2.size() - 1;
822 _indexMap2to3[sys][i2] = i3;
823 }
824 }
825 }
826 }
827 }
828 }
829}
830
831// Write Data Epoch
832////////////////////////////////////////////////////////////////////////////
833void t_rnxObsFile::writeEpoch(const t_rnxEpo* epo) {
834 if (version() < 3.0) {
835 return writeEpochV2(epo);
836 }
837 else {
838 return writeEpochV3(epo);
839 }
840}
841
842// Write Data Epoch (RINEX Version 2)
843////////////////////////////////////////////////////////////////////////////
844void t_rnxObsFile::writeEpochV2(const t_rnxEpo* epo) {
845
846 unsigned year, month, day, hour, min;
847 double sec;
848 epo->tt.civil_date(year, month, day);
849 epo->tt.civil_time(hour, min, sec);
850
851 QString dateStr;
852 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
853 .arg(int(fmod(year, 100)), 2, 10, QChar('0'))
854 .arg(month, 2, 10, QChar('0'))
855 .arg(day, 2, 10, QChar('0'))
856 .arg(hour, 2, 10, QChar('0'))
857 .arg(min, 2, 10, QChar('0'))
858 .arg(sec, 11, 'f', 7);
859
860 int flag = 0;
861 *_stream << dateStr
862 << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
863 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
864 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
865 if (iSat > 0 && iSat % 12 == 0) {
866 *_stream << endl << QString().leftJustified(32);
867 }
868 *_stream << rnxSat.satSys << QString("%1").arg(rnxSat.satNum, 2);
869 }
870 *_stream << endl;
871 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
872
873 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
874 char sys = rnxSat.satSys;
875
876 for (int iTypeV2 = 0; iTypeV2 < nTypes(sys); iTypeV2++) {
877
878 if (iTypeV2 > 0 && iTypeV2 % 5 == 0) {
879 *_stream << endl;
880 }
881
882 int iType = -1;
883 if (_trafo == trafoNone) {
884 iType = iTypeV2;
885 }
886 else {
887 if (_indexMap2to3[sys].find(iTypeV2) != _indexMap2to3[sys].end()) {
888 iType = _indexMap2to3[sys][iTypeV2];
889 }
890 }
891
892 if (iType == -1 || rnxSat.obs[iType] == 0.0) {
893 *_stream << QString().leftJustified(16);
894 }
895 else {
896 *_stream << QString("%1").arg(rnxSat.obs[iType], 14, 'f', 3);
897 if (rnxSat.lli[iType] != 0.0) {
898 *_stream << QString("%1").arg(rnxSat.lli[iType],1);
899 }
900 else {
901 *_stream << ' ';
902 }
903 if (rnxSat.snr[iType] != 0.0) {
904 *_stream << QString("%1").arg(rnxSat.snr[iType],1);
905 }
906 else {
907 *_stream << ' ';
908 }
909 }
910 }
911 *_stream << endl;
912 }
913}
914
915// Write Data Epoch (RINEX Version 3)
916////////////////////////////////////////////////////////////////////////////
917void t_rnxObsFile::writeEpochV3(const t_rnxEpo* epo) {
918
919 unsigned year, month, day, hour, min;
920 double sec;
921 epo->tt.civil_date(year, month, day);
922 epo->tt.civil_time(hour, min, sec);
923
924 QString dateStr;
925 QTextStream(&dateStr) << QString("> %1 %2 %3 %4 %5%6")
926 .arg(year, 4)
927 .arg(month, 2, 10, QChar('0'))
928 .arg(day, 2, 10, QChar('0'))
929 .arg(hour, 2, 10, QChar('0'))
930 .arg(min, 2, 10, QChar('0'))
931 .arg(sec, 11, 'f', 7);
932
933 int flag = 0;
934 *_stream << dateStr
935 << QString("%1%2\n").arg(flag, 3).arg(epo->rnxSat.size(), 3);
936
937 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
938 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
939 char sys = rnxSat.satSys;
940 *_stream << sys
941 << QString("%1").arg(rnxSat.satNum, 2, 10, QChar('0'));
942
943 for (int iTypeV3 = 0; iTypeV3 < nTypes(sys); iTypeV3++) {
944
945 int iType = -1;
946 if (_trafo == trafoNone) {
947 iType = iTypeV3;
948 }
949 else {
950 if (_indexMap3to2[sys].find(iTypeV3) != _indexMap3to2[sys].end()) {
951 iType = _indexMap3to2[sys][iTypeV3];
952 }
953 }
954
955 if (iType == -1 || rnxSat.obs[iType] == 0.0) {
956 *_stream << QString().leftJustified(16);
957 }
958 else {
959 *_stream << QString("%1").arg(rnxSat.obs[iType], 14, 'f', 3);
960 if (rnxSat.lli[iType] != 0.0) {
961 *_stream << QString("%1").arg(rnxSat.lli[iType],1);
962 }
963 else {
964 *_stream << ' ';
965 }
966 if (rnxSat.snr[iType] != 0.0) {
967 *_stream << QString("%1").arg(rnxSat.snr[iType],1);
968 }
969 else {
970 *_stream << ' ';
971 }
972 }
973 }
974 *_stream << endl;
975 }
976}
977
978// Translate Observation Type v2 --> v3
979////////////////////////////////////////////////////////////////////////////
980QString t_rnxObsFile::type2to3(char sys, const QString& typeV2) {
981
982 if (sys == 'G') {
983 if (typeV2 == "C1") return "C1C";
984 if (typeV2 == "C2") return "C2C";
985 if (typeV2 == "C5") return "C5C";
986 if (typeV2 == "P1") return "C1P";
987 if (typeV2 == "P2") return "C2P";
988 if (typeV2 == "L1") return "L1";
989 if (typeV2 == "L2") return "L2";
990 if (typeV2 == "L5") return "L5";
991 if (typeV2 == "D1") return "D1";
992 if (typeV2 == "D2") return "D2";
993 if (typeV2 == "D5") return "D5";
994 if (typeV2 == "S1") return "S1";
995 if (typeV2 == "S2") return "S2";
996 if (typeV2 == "S5") return "S5";
997 }
998
999 else if (sys == 'R') {
1000 if (typeV2 == "C1") return "C1C";
1001 if (typeV2 == "C2") return "C2C";
1002 if (typeV2 == "P1") return "C1P";
1003 if (typeV2 == "P2") return "C2P";
1004 if (typeV2 == "L1") return "L1";
1005 if (typeV2 == "L2") return "L2";
1006 if (typeV2 == "D1") return "D1";
1007 if (typeV2 == "D2") return "D2";
1008 if (typeV2 == "S1") return "S1";
1009 if (typeV2 == "S2") return "S2";
1010 }
1011
1012 else if (sys == 'E') {
1013 if (typeV2 == "C1") return "C1";
1014 if (typeV2 == "C5") return "C5";
1015 if (typeV2 == "C6") return "C6";
1016 if (typeV2 == "C7") return "C7";
1017 if (typeV2 == "C8") return "C8";
1018 if (typeV2 == "L1") return "L1";
1019 if (typeV2 == "L5") return "L5";
1020 if (typeV2 == "L6") return "L6";
1021 if (typeV2 == "L7") return "L7";
1022 if (typeV2 == "L8") return "L8";
1023 if (typeV2 == "D1") return "D1";
1024 if (typeV2 == "D5") return "D5";
1025 if (typeV2 == "D6") return "D6";
1026 if (typeV2 == "D7") return "D7";
1027 if (typeV2 == "D8") return "D8";
1028 if (typeV2 == "S1") return "S1";
1029 if (typeV2 == "S5") return "S5";
1030 if (typeV2 == "S6") return "S6";
1031 if (typeV2 == "S7") return "S7";
1032 if (typeV2 == "S8") return "S8";
1033 }
1034
1035 else if (sys == 'S') {
1036 if (typeV2 == "C1") return "C1C";
1037 if (typeV2 == "C5") return "C5C";
1038 if (typeV2 == "L1") return "L1";
1039 if (typeV2 == "L5") return "L5";
1040 if (typeV2 == "D1") return "D1";
1041 if (typeV2 == "D5") return "D5";
1042 if (typeV2 == "S1") return "S1";
1043 if (typeV2 == "S5") return "S5";
1044 }
1045
1046 return "";
1047}
1048
1049// Translate Observation Type v3 --> v2
1050////////////////////////////////////////////////////////////////////////////
1051QString t_rnxObsFile::type3to2(const QString& typeV3) {
1052 if (typeV3 == "C1P") {
1053 return "P1";
1054 }
1055 else if (typeV3 == "C2P") {
1056 return "P2";
1057 }
1058 else {
1059 return typeV3.left(2);
1060 }
1061
1062 return "";
1063}
1064
1065// Check for Changes in Header
1066////////////////////////////////////////////////////////////////////////////
1067void t_rnxObsFile::checkNewHeader(const t_rnxObsHeader& header) {
1068
1069 t_rnxObsHeader oldHeader(_header);
1070 setHeader(header, oldHeader._version);
1071
1072 // Check Observation Types
1073 // -----------------------
1074 bool same = true;
1075 if (_header._version < 3.0) {
1076 if (_header._obsTypesV2 != oldHeader._obsTypesV2) {
1077 same = false;
1078 }
1079 }
1080 else {
1081 QMapIterator<char, QVector<QString> > it(_header._obsTypesV3);
1082 while (it.hasNext()) {
1083 it.next();
1084 char sys = it.key();
1085 const QVector<QString>& typesV3 = it.value();
1086 if (!oldHeader._obsTypesV3.contains(sys) ||
1087 oldHeader._obsTypesV3[sys] != typesV3) {
1088 same = false;
1089 break;
1090 }
1091 }
1092 }
1093
1094 if (!same) {
1095 QStringList strLst = _header.obsTypesStrings();
1096 if (_header._version < 3.0) {
1097 *_stream << QString().leftJustified(26);
1098 }
1099 else {
1100 *_stream << '>' << QString().leftJustified(28);
1101 }
1102 *_stream << QString(" 4%1\n").arg(strLst.size(), 3)
1103 << strLst.join("");
1104 }
1105}
Note: See TracBrowser for help on using the repository browser.