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

Last change on this file since 4748 was 4748, checked in by mervart, 12 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 "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 if (_currEpo.rnxSat[iSat].satSys == ' ') {
671 _currEpo.rnxSat[iSat].satSys = 'G';
672 }
673 readInt(line, pos + 1, 2, _currEpo.rnxSat[iSat].satNum);
674
675 pos += 3;
676 }
677
678 // Read Observation Records
679 // ------------------------
680 for (int iSat = 0; iSat < numSat; iSat++) {
681 line = _stream->readLine();
682 pos = 0;
683 for (int iType = 0; iType < _header.nTypes(_currEpo.rnxSat[iSat].satSys); iType++) {
684 if (iType > 0 && iType % 5 == 0) {
685 line = _stream->readLine();
686 pos = 0;
687 }
688 double obsValue = 0.0;
689 int lli = 0;
690 int snr = 0;
691 readDbl(line, pos, 14, obsValue);
692 readInt(line, pos + 14, 1, lli);
693 readInt(line, pos + 15, 1, snr);
694
695 if (_flgPowerFail) {
696 lli |= 1;
697 }
698
699 _currEpo.rnxSat[iSat].obs.push_back(obsValue);
700 _currEpo.rnxSat[iSat].lli.push_back(lli);
701 _currEpo.rnxSat[iSat].snr.push_back(snr);
702
703 pos += 16;
704 }
705 }
706
707 _flgPowerFail = false;
708
709 return &_currEpo;
710 }
711
712 return 0;
713}
714
715// Set Header Information
716////////////////////////////////////////////////////////////////////////////
717void t_rnxObsFile::setHeader(const t_rnxObsHeader& header, double version) {
718
719 if (int(header._version) == int(version)) {
720 _trafo = trafoNone;
721 _header._version = header._version;
722 }
723 else if (version >= 3.0) {
724 _trafo = trafo2to3;
725 _header._version = 3.01;
726 }
727 else {
728 _trafo = trafo3to2;
729 _header._version = 2.11;
730 }
731
732 _header._interval = header._interval;
733 _header._antennaNumber = header._antennaNumber;
734 _header._antennaName = header._antennaName;
735 _header._markerName = header._markerName;
736 _header._markerNumber = header._markerNumber;
737 _header._antNEU = header._antNEU;
738 _header._antXYZ = header._antXYZ;
739 _header._antBSG = header._antBSG;
740 _header._xyz = header._xyz;
741 _header._observer = header._observer;
742 _header._agency = header._agency;
743 _header._receiverNumber = header._receiverNumber;
744 _header._receiverType = header._receiverType;
745 _header._receiverVersion = header._receiverVersion;
746
747 for (unsigned iPrn = 1; iPrn <= MAXPRN_GPS; iPrn++) {
748 _header._wlFactorsL1[iPrn] = header._wlFactorsL1[iPrn];
749 _header._wlFactorsL2[iPrn] = header._wlFactorsL2[iPrn];
750 }
751
752 _header._startTime = header._startTime;
753
754 static const string systems = "GRES";
755
756 _header._obsTypesV2.clear();
757 _header._obsTypesV3.clear();
758
759 // Copy Observation Types
760 // ----------------------
761 if (_trafo == trafoNone) {
762 for (int ii = 0; ii < header._obsTypesV2.size(); ii++) {
763 _header._obsTypesV2.append(header._obsTypesV2[ii]);
764 }
765 QMapIterator<char, QVector<QString> > it(header._obsTypesV3);
766 while (it.hasNext()) {
767 it.next();
768 char sys = it.key();
769 const QVector<QString>& typesV3 = it.value();
770 for (int ii = 0; ii < typesV3.size(); ii++) {
771 _header._obsTypesV3[sys].push_back(typesV3[ii]);
772 }
773 }
774 }
775
776 // Translate Observation Types v2 --> v3
777 // -------------------------------------
778 else if (_trafo == trafo2to3) {
779 for (int i2 = 0; i2 < header._obsTypesV2.size(); i2++) {
780 const QString& typeV2 = header._obsTypesV2[i2];
781 for (unsigned iSys = 0; iSys < systems.length(); iSys++) {
782 char sys = systems[iSys];
783 QString typeV3 = type2to3(sys, typeV2);
784 if (!typeV3.isEmpty()) {
785 _header._obsTypesV3[sys].push_back(typeV3);
786 int i3 = _header._obsTypesV3[sys].size() - 1;
787 _indexMap3to2[sys][i3] = i2;
788 }
789 }
790 }
791 }
792
793 // Translate Observation Types v3 --> v2
794 // -------------------------------------
795 else if (_trafo == trafo3to2) {
796 for (unsigned iSys = 0; iSys < systems.length(); iSys++) {
797 char sys = systems[iSys];
798 if (header._obsTypesV3.contains(sys)) {
799 const QVector<QString>& typesV3 = header._obsTypesV3[sys];
800 for (int i3 = 0; i3 < typesV3.size(); i3++) {
801 const QString& typeV3 = typesV3[i3];
802 QString typeV2 = type3to2(typeV3);
803 if (!typeV2.isEmpty()) {
804 bool found = false;
805 for (int i2 = 0; i2 < _header._obsTypesV2.size(); i2++) {
806 if (_header._obsTypesV2[i2] == typeV2) {
807 found = true;
808 if (_indexMap2to3[sys].find(i2) == _indexMap2to3[sys].end()) {
809 _indexMap2to3[sys][i2] = i3;
810 }
811 break;
812 }
813 }
814 if (!found) {
815 _header._obsTypesV2.append(typeV2);
816 int i2 = _header._obsTypesV2.size() - 1;
817 _indexMap2to3[sys][i2] = i3;
818 }
819 }
820 }
821 }
822 }
823 }
824}
825
826// Write Data Epoch
827////////////////////////////////////////////////////////////////////////////
828void t_rnxObsFile::writeEpoch(const t_rnxEpo* epo) {
829 if (version() < 3.0) {
830 return writeEpochV2(epo);
831 }
832 else {
833 return writeEpochV3(epo);
834 }
835}
836
837// Write Data Epoch (RINEX Version 2)
838////////////////////////////////////////////////////////////////////////////
839void t_rnxObsFile::writeEpochV2(const t_rnxEpo* epo) {
840
841 unsigned year, month, day, hour, min;
842 double sec;
843 epo->tt.civil_date(year, month, day);
844 epo->tt.civil_time(hour, min, sec);
845
846 QString dateStr;
847 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
848 .arg(int(fmod(year, 100)), 2, 10, QChar('0'))
849 .arg(month, 2, 10, QChar('0'))
850 .arg(day, 2, 10, QChar('0'))
851 .arg(hour, 2, 10, QChar('0'))
852 .arg(min, 2, 10, QChar('0'))
853 .arg(sec, 11, 'f', 7);
854
855 int flag = 0;
856 *_stream << dateStr
857 << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
858 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
859 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
860 if (iSat > 0 && iSat % 12 == 0) {
861 *_stream << endl << QString().leftJustified(32);
862 }
863 *_stream << rnxSat.satSys << QString("%1").arg(rnxSat.satNum, 2);
864 }
865 *_stream << endl;
866 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
867
868 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
869 char sys = rnxSat.satSys;
870
871 for (int iTypeV2 = 0; iTypeV2 < nTypes(sys); iTypeV2++) {
872
873 if (iTypeV2 > 0 && iTypeV2 % 5 == 0) {
874 *_stream << endl;
875 }
876
877 int iType = -1;
878 if (_trafo == trafoNone) {
879 iType = iTypeV2;
880 }
881 else {
882 if (_indexMap2to3[sys].find(iTypeV2) != _indexMap2to3[sys].end()) {
883 iType = _indexMap2to3[sys][iTypeV2];
884 }
885 }
886
887 if (iType == -1 || rnxSat.obs[iType] == 0.0) {
888 *_stream << QString().leftJustified(16);
889 }
890 else {
891 *_stream << QString("%1").arg(rnxSat.obs[iType], 14, 'f', 3);
892 if (rnxSat.lli[iType] != 0.0) {
893 *_stream << QString("%1").arg(rnxSat.lli[iType],1);
894 }
895 else {
896 *_stream << ' ';
897 }
898 if (rnxSat.snr[iType] != 0.0) {
899 *_stream << QString("%1").arg(rnxSat.snr[iType],1);
900 }
901 else {
902 *_stream << ' ';
903 }
904 }
905 }
906 *_stream << endl;
907 }
908}
909
910// Write Data Epoch (RINEX Version 3)
911////////////////////////////////////////////////////////////////////////////
912void t_rnxObsFile::writeEpochV3(const t_rnxEpo* epo) {
913
914 unsigned year, month, day, hour, min;
915 double sec;
916 epo->tt.civil_date(year, month, day);
917 epo->tt.civil_time(hour, min, sec);
918
919 QString dateStr;
920 QTextStream(&dateStr) << QString("> %1 %2 %3 %4 %5%6")
921 .arg(year, 4)
922 .arg(month, 2, 10, QChar('0'))
923 .arg(day, 2, 10, QChar('0'))
924 .arg(hour, 2, 10, QChar('0'))
925 .arg(min, 2, 10, QChar('0'))
926 .arg(sec, 11, 'f', 7);
927
928 int flag = 0;
929 *_stream << dateStr
930 << QString("%1%2\n").arg(flag, 3).arg(epo->rnxSat.size(), 3);
931
932 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
933 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
934 char sys = rnxSat.satSys;
935 *_stream << sys
936 << QString("%1").arg(rnxSat.satNum, 2, 10, QChar('0'));
937
938 for (int iTypeV3 = 0; iTypeV3 < nTypes(sys); iTypeV3++) {
939
940 int iType = -1;
941 if (_trafo == trafoNone) {
942 iType = iTypeV3;
943 }
944 else {
945 if (_indexMap3to2[sys].find(iTypeV3) != _indexMap3to2[sys].end()) {
946 iType = _indexMap3to2[sys][iTypeV3];
947 }
948 }
949
950 if (iType == -1 || rnxSat.obs[iType] == 0.0) {
951 *_stream << QString().leftJustified(16);
952 }
953 else {
954 *_stream << QString("%1").arg(rnxSat.obs[iType], 14, 'f', 3);
955 if (rnxSat.lli[iType] != 0.0) {
956 *_stream << QString("%1").arg(rnxSat.lli[iType],1);
957 }
958 else {
959 *_stream << ' ';
960 }
961 if (rnxSat.snr[iType] != 0.0) {
962 *_stream << QString("%1").arg(rnxSat.snr[iType],1);
963 }
964 else {
965 *_stream << ' ';
966 }
967 }
968 }
969 *_stream << endl;
970 }
971}
972
973// Translate Observation Type v2 --> v3
974////////////////////////////////////////////////////////////////////////////
975QString t_rnxObsFile::type2to3(char sys, const QString& typeV2) {
976
977 if (sys == 'G') {
978 if (typeV2 == "C1") return "C1C";
979 if (typeV2 == "C2") return "C2C";
980 if (typeV2 == "C5") return "C5C";
981 if (typeV2 == "P1") return "C1P";
982 if (typeV2 == "P2") return "C2P";
983 if (typeV2 == "L1") return "L1";
984 if (typeV2 == "L2") return "L2";
985 if (typeV2 == "L5") return "L5";
986 if (typeV2 == "D1") return "D1";
987 if (typeV2 == "D2") return "D2";
988 if (typeV2 == "D5") return "D5";
989 if (typeV2 == "S1") return "S1";
990 if (typeV2 == "S2") return "S2";
991 if (typeV2 == "S5") return "S5";
992 }
993
994 else if (sys == 'R') {
995 if (typeV2 == "C1") return "C1C";
996 if (typeV2 == "C2") return "C2C";
997 if (typeV2 == "P1") return "C1P";
998 if (typeV2 == "P2") return "C2P";
999 if (typeV2 == "L1") return "L1";
1000 if (typeV2 == "L2") return "L2";
1001 if (typeV2 == "D1") return "D1";
1002 if (typeV2 == "D2") return "D2";
1003 if (typeV2 == "S1") return "S1";
1004 if (typeV2 == "S2") return "S2";
1005 }
1006
1007 else if (sys == 'E') {
1008 if (typeV2 == "C1") return "C1";
1009 if (typeV2 == "C5") return "C5";
1010 if (typeV2 == "C6") return "C6";
1011 if (typeV2 == "C7") return "C7";
1012 if (typeV2 == "C8") return "C8";
1013 if (typeV2 == "L1") return "L1";
1014 if (typeV2 == "L5") return "L5";
1015 if (typeV2 == "L6") return "L6";
1016 if (typeV2 == "L7") return "L7";
1017 if (typeV2 == "L8") return "L8";
1018 if (typeV2 == "D1") return "D1";
1019 if (typeV2 == "D5") return "D5";
1020 if (typeV2 == "D6") return "D6";
1021 if (typeV2 == "D7") return "D7";
1022 if (typeV2 == "D8") return "D8";
1023 if (typeV2 == "S1") return "S1";
1024 if (typeV2 == "S5") return "S5";
1025 if (typeV2 == "S6") return "S6";
1026 if (typeV2 == "S7") return "S7";
1027 if (typeV2 == "S8") return "S8";
1028 }
1029
1030 else if (sys == 'S') {
1031 if (typeV2 == "C1") return "C1C";
1032 if (typeV2 == "C5") return "C5C";
1033 if (typeV2 == "L1") return "L1";
1034 if (typeV2 == "L5") return "L5";
1035 if (typeV2 == "D1") return "D1";
1036 if (typeV2 == "D5") return "D5";
1037 if (typeV2 == "S1") return "S1";
1038 if (typeV2 == "S5") return "S5";
1039 }
1040
1041 return "";
1042}
1043
1044// Translate Observation Type v3 --> v2
1045////////////////////////////////////////////////////////////////////////////
1046QString t_rnxObsFile::type3to2(const QString& typeV3) {
1047 if (typeV3 == "C1P") {
1048 return "P1";
1049 }
1050 else if (typeV3 == "C2P") {
1051 return "P2";
1052 }
1053 else {
1054 return typeV3.left(2);
1055 }
1056
1057 return "";
1058}
1059
1060// Check for Changes in Header
1061////////////////////////////////////////////////////////////////////////////
1062void t_rnxObsFile::checkNewHeader(const t_rnxObsHeader& header) {
1063
1064 t_rnxObsHeader oldHeader(_header);
1065 setHeader(header, oldHeader._version);
1066
1067 // Check Observation Types
1068 // -----------------------
1069 bool same = true;
1070 if (_header._version < 3.0) {
1071 if (_header._obsTypesV2 != oldHeader._obsTypesV2) {
1072 same = false;
1073 }
1074 }
1075 else {
1076 QMapIterator<char, QVector<QString> > it(_header._obsTypesV3);
1077 while (it.hasNext()) {
1078 it.next();
1079 char sys = it.key();
1080 const QVector<QString>& typesV3 = it.value();
1081 if (!oldHeader._obsTypesV3.contains(sys) ||
1082 oldHeader._obsTypesV3[sys] != typesV3) {
1083 same = false;
1084 break;
1085 }
1086 }
1087 }
1088
1089 if (!same) {
1090 QStringList strLst = _header.obsTypesStrings();
1091 if (_header._version < 3.0) {
1092 *_stream << QString().leftJustified(26);
1093 }
1094 else {
1095 *_stream << '>' << QString().leftJustified(28);
1096 }
1097 *_stream << QString(" 4%1\n").arg(strLst.size(), 3)
1098 << strLst.join("");
1099 }
1100}
Note: See TracBrowser for help on using the repository browser.