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

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