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

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