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

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