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

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