source: ntrip/trunk/BNC/rinex/rnxobsfile.cpp@ 4116

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