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

Last change on this file since 3967 was 3967, checked in by mervart, 12 years ago
File size: 27.8 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.push_back(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 map<char, vector<QString> >::const_iterator it = _obsTypesV3.find(sys);
213 if (it != _obsTypesV3.end()) {
214 return it->second.size();
215 }
216 else {
217 return 0;
218 }
219 }
220}
221
222// Observation Type (satellite-system specific)
223////////////////////////////////////////////////////////////////////////////
224const QString& t_rnxObsFile::t_rnxObsHeader::obsType(char sys, int index) const {
225 if (_version < 3.0) {
226 return _obsTypesV2.at(index);
227 }
228 else {
229 map<char, vector<QString> >::const_iterator it = _obsTypesV3.find(sys);
230 if (it != _obsTypesV3.end()) {
231 return it->second.at(index);
232 }
233 else {
234 return _emptyStr;
235 }
236 }
237}
238
239// Constructor
240////////////////////////////////////////////////////////////////////////////
241t_rnxObsFile::t_rnxObsFile(const QString& fileName, e_inpOut inpOut) {
242 _inpOut = inpOut;
243 _stream = 0;
244 _flgPowerFail = false;
245 _trafo = trafoNone;
246 if (_inpOut == input) {
247 openRead(fileName);
248 }
249 else {
250 openWrite(fileName);
251 }
252}
253
254// Open for input
255////////////////////////////////////////////////////////////////////////////
256void t_rnxObsFile::openRead(const QString& fileName) {
257
258 _fileName = fileName; expandEnvVar(_fileName);
259 _file = new QFile(_fileName);
260 _file->open(QIODevice::ReadOnly | QIODevice::Text);
261 _stream = new QTextStream();
262 _stream->setDevice(_file);
263
264 _header.read(_stream);
265
266 // Guess Observation Interval
267 // --------------------------
268 if (_header._interval == 0.0) {
269 bncTime ttPrev;
270 for (int iEpo = 0; iEpo < 10; iEpo++) {
271 const t_rnxEpo* rnxEpo = nextEpoch();
272 if (!rnxEpo) {
273 throw QString("t_rnxObsFile: not enough epochs");
274 }
275 if (iEpo > 0) {
276 double dt = rnxEpo->tt - ttPrev;
277 if (_header._interval == 0.0 || dt < _header._interval) {
278 _header._interval = dt;
279 }
280 }
281 ttPrev = rnxEpo->tt;
282 }
283 _stream->seek(0);
284 _header.read(_stream);
285 }
286
287 // Time of first observation
288 // -------------------------
289 if (!_header._startTime.valid()) {
290 const t_rnxEpo* rnxEpo = nextEpoch();
291 if (!rnxEpo) {
292 throw QString("t_rnxObsFile: not enough epochs");
293 }
294 _header._startTime = rnxEpo->tt;
295 _stream->seek(0);
296 _header.read(_stream);
297 }
298}
299
300// Open for output
301////////////////////////////////////////////////////////////////////////////
302void t_rnxObsFile::openWrite(const QString& fileName) {
303
304 _fileName = fileName; expandEnvVar(_fileName);
305 _file = new QFile(_fileName);
306 _file->open(QIODevice::WriteOnly | QIODevice::Text);
307 _stream = new QTextStream();
308 _stream->setDevice(_file);
309}
310
311// Destructor
312////////////////////////////////////////////////////////////////////////////
313t_rnxObsFile::~t_rnxObsFile() {
314 close();
315}
316
317// Close
318////////////////////////////////////////////////////////////////////////////
319void t_rnxObsFile::close() {
320 delete _stream; _stream = 0;
321 delete _file; _file = 0;
322}
323
324// Handle Special Epoch Flag
325////////////////////////////////////////////////////////////////////////////
326void t_rnxObsFile::handleEpochFlag(int flag, const QString& line) {
327
328 // Power Failure
329 // -------------
330 if (flag == 1) {
331 _flgPowerFail = true;
332 }
333
334 // Start moving antenna
335 // --------------------
336 else if (flag == 2) {
337 // no action
338 }
339
340 // Re-Read Header
341 // --------------
342 else if (flag == 3 || flag == 4) {
343 int numLines = 0;
344 if (version() < 3.0) {
345 readInt(line, 29, 3, numLines);
346 }
347 else {
348 readInt(line, 32, 3, numLines);
349 }
350 _header.read(_stream, numLines);
351 }
352
353 // Unhandled Flag
354 // --------------
355 else {
356 throw QString("t_rnxObsFile: unhandled flag\n" + line);
357 }
358}
359
360// Retrieve single Epoch
361////////////////////////////////////////////////////////////////////////////
362const t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpoch() {
363
364 _currEpo.clear();
365
366 if (version() < 3.0) {
367 return nextEpochV2();
368 }
369 else {
370 return nextEpochV3();
371 }
372}
373
374// Retrieve single Epoch (RINEX Version 3)
375////////////////////////////////////////////////////////////////////////////
376const t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV3() {
377
378 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
379
380 QString line = _stream->readLine();
381
382 if (line.isEmpty()) {
383 continue;
384 }
385
386 int flag = 0;
387 readInt(line, 31, 1, flag);
388 if (flag > 0) {
389 handleEpochFlag(flag, line);
390 continue;
391 }
392
393 QTextStream in(line.mid(1).toAscii(), QIODevice::ReadOnly);
394
395 // Epoch Time
396 // ----------
397 int year, month, day, hour, min;
398 double sec;
399 in >> year >> month >> day >> hour >> min >> sec;
400 _currEpo.tt.set(year, month, day, hour, min, sec);
401
402 // Number of Satellites
403 // --------------------
404 int numSat;
405 readInt(line, 32, 3, numSat);
406
407 _currEpo.rnxSat.resize(numSat);
408
409 // Observations
410 // ------------
411 for (int iSat = 0; iSat < numSat; iSat++) {
412 line = _stream->readLine();
413 _currEpo.rnxSat[iSat].satSys = line.toAscii()[0];
414 readInt(line, 1, 2, _currEpo.rnxSat[iSat].satNum);
415 char sys = line.toAscii()[0];
416 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
417 int pos = 3 + 16*iType;
418 double obsValue = 0.0;
419 int lli = 0;
420 int snr = 0;
421 readDbl(line, pos, 14, obsValue);
422 readInt(line, pos + 14, 1, lli);
423 readInt(line, pos + 15, 1, snr);
424
425 if (_flgPowerFail) {
426 lli |= 1;
427 }
428
429 _currEpo.rnxSat[iSat].obs.push_back(obsValue);
430 _currEpo.rnxSat[iSat].lli.push_back(lli);
431 _currEpo.rnxSat[iSat].snr.push_back(snr);
432 }
433 }
434
435 _flgPowerFail = false;
436
437 return &_currEpo;
438 }
439
440 return 0;
441}
442
443// Retrieve single Epoch (RINEX Version 2)
444////////////////////////////////////////////////////////////////////////////
445const t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV2() {
446
447 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
448
449 QString line = _stream->readLine();
450
451 if (line.isEmpty()) {
452 continue;
453 }
454
455 int flag = 0;
456 readInt(line, 28, 1, flag);
457 if (flag > 0) {
458 handleEpochFlag(flag, line);
459 continue;
460 }
461
462 QTextStream in(line.toAscii(), QIODevice::ReadOnly);
463
464 // Epoch Time
465 // ----------
466 int year, month, day, hour, min;
467 double sec;
468 in >> year >> month >> day >> hour >> min >> sec;
469 if (year < 80) {
470 year += 2000;
471 }
472 else if (year < 100) {
473 year += 1900;
474 }
475 _currEpo.tt.set(year, month, day, hour, min, sec);
476
477 // Number of Satellites
478 // --------------------
479 int numSat;
480 readInt(line, 29, 3, numSat);
481
482 _currEpo.rnxSat.resize(numSat);
483
484 // Read Satellite Numbers
485 // ----------------------
486 int pos = 32;
487 for (int iSat = 0; iSat < numSat; iSat++) {
488 if (iSat > 0 && iSat % 12 == 0) {
489 line = _stream->readLine();
490 pos = 32;
491 }
492
493 _currEpo.rnxSat[iSat].satSys = line.toAscii()[pos];
494 readInt(line, pos + 1, 2, _currEpo.rnxSat[iSat].satNum);
495
496 pos += 3;
497 }
498
499 // Read Observation Records
500 // ------------------------
501 for (int iSat = 0; iSat < numSat; iSat++) {
502 line = _stream->readLine();
503 pos = 0;
504 for (int iType = 0; iType < _header.nTypes(_currEpo.rnxSat[iSat].satSys); iType++) {
505 if (iType > 0 && iType % 5 == 0) {
506 line = _stream->readLine();
507 pos = 0;
508 }
509 double obsValue = 0.0;
510 int lli = 0;
511 int snr = 0;
512 readDbl(line, pos, 14, obsValue);
513 readInt(line, pos + 14, 1, lli);
514 readInt(line, pos + 15, 1, snr);
515
516 if (_flgPowerFail) {
517 lli |= 1;
518 }
519
520 _currEpo.rnxSat[iSat].obs.push_back(obsValue);
521 _currEpo.rnxSat[iSat].lli.push_back(lli);
522 _currEpo.rnxSat[iSat].snr.push_back(snr);
523
524 pos += 16;
525 }
526 }
527
528 _flgPowerFail = false;
529
530 return &_currEpo;
531 }
532
533 return 0;
534}
535
536// Set Header Information
537////////////////////////////////////////////////////////////////////////////
538void t_rnxObsFile::setHeader(const t_rnxObsHeader& header, double version) {
539
540 if (int(header._version) == int(version)) {
541 _trafo = trafoNone;
542 _header._version = header._version;
543 }
544 else if (version >= 3.0) {
545 _trafo = trafo2to3;
546 _header._version = 3.01;
547 }
548 else {
549 _trafo = trafo3to2;
550 _header._version = 2.11;
551 }
552
553 _header._interval = header._interval;
554 _header._antennaNumber = header._antennaNumber;
555 _header._antennaName = header._antennaName;
556 _header._markerName = header._markerName;
557 _header._markerNumber = header._markerNumber;
558 _header._antNEU = header._antNEU;
559 _header._antXYZ = header._antXYZ;
560 _header._antBSG = header._antBSG;
561 _header._xyz = header._xyz;
562 _header._observer = header._observer;
563 _header._agency = header._agency;
564 _header._receiverNumber = header._receiverNumber;
565 _header._receiverType = header._receiverType;
566 _header._receiverVersion = header._receiverVersion;
567
568 for (unsigned iPrn = 1; iPrn <= MAXPRN_GPS; iPrn++) {
569 _header._wlFactorsL1[iPrn] = header._wlFactorsL1[iPrn];
570 _header._wlFactorsL2[iPrn] = header._wlFactorsL2[iPrn];
571 }
572
573 _header._startTime = header._startTime;
574
575 static const string systems = "GRES";
576
577 // Copy Observation Types
578 // ----------------------
579 if (_trafo == trafoNone) {
580 for (unsigned ii = 0; ii < header._obsTypesV2.size(); ii++) {
581 _header._obsTypesV2.push_back(header._obsTypesV2[ii]);
582 }
583 map<char, vector<QString> >::const_iterator it;
584 for (it = header._obsTypesV3.begin(); it != header._obsTypesV3.end(); it++) {
585 char sys = it->first;
586 const vector<QString>& typesV3 = it->second;
587 for (unsigned ii = 0; ii < typesV3.size(); ii++) {
588 _header._obsTypesV3[sys].push_back(typesV3[ii]);
589 }
590 }
591 }
592
593 // Translate Observation Types v2 --> v3
594 // -------------------------------------
595 else if (_trafo == trafo2to3) {
596 for (unsigned i2 = 0; i2 < header._obsTypesV2.size(); i2++) {
597 const QString& typeV2 = header._obsTypesV2[i2];
598 for (unsigned iSys = 0; iSys < systems.length(); iSys++) {
599 char sys = systems[iSys];
600 QString typeV3 = type2to3(sys, typeV2);
601 if (!typeV3.isEmpty()) {
602 _header._obsTypesV3[sys].push_back(typeV3);
603 int i3 = _header._obsTypesV3[sys].size() - 1;
604 _indexMap3to2[sys][i3] = i2;
605 }
606 }
607 }
608 }
609
610 // Translate Observation Types v3 --> v2
611 // -------------------------------------
612 else if (_trafo == trafo3to2) {
613 for (unsigned iSys = 0; iSys < systems.length(); iSys++) {
614 char sys = systems[iSys];
615 map<char, vector<QString> >::const_iterator it = header._obsTypesV3.find(sys);
616 if (it != header._obsTypesV3.end()) {
617 const vector<QString>& typesV3 = it->second;
618 for (unsigned i3 = 0; i3 < typesV3.size(); i3++) {
619 const QString& typeV3 = typesV3[i3];
620 QString typeV2 = type3to2(typeV3);
621 bool found = false;
622 for (unsigned i2 = 0; i2 < _header._obsTypesV2.size(); i2++) {
623 if (_header._obsTypesV2[i2] == typeV2) {
624 found = true;
625 _indexMap2to3[sys][i2] = i3;
626 break;
627 }
628 }
629 if (!found) {
630 _header._obsTypesV2.push_back(typeV2);
631 int i2 = _header._obsTypesV2.size() - 1;
632 _indexMap2to3[sys][i2] = i3;
633 }
634 }
635 }
636 }
637 }
638}
639
640// Write Header
641////////////////////////////////////////////////////////////////////////////
642void t_rnxObsFile::writeHeader() {
643
644 bncApp* app = (bncApp*) qApp;
645
646 *_stream << QString("%1 Observation data Mixed")
647 .arg(_header._version, 9, 'f', 2)
648 .leftJustified(60)
649 << "RINEX VERSION / TYPE\n";
650
651 *_stream << QString("%1%2%3")
652 .arg(app->pgmName(), -20)
653 .arg(app->userName(), -20)
654 .arg(currentDateAndTimeGPS().date().toString("dd-MMM-yyyy"), -20)
655 .leftJustified(60)
656 << "PGM / RUN BY / DATE\n";
657
658 *_stream << QString("%1")
659 .arg(_header._markerName, -60)
660 .leftJustified(60)
661 << "MARKER NAME\n";
662
663 if (!_header._markerNumber.isEmpty()) {
664 *_stream << QString("%1")
665 .arg(_header._markerNumber, -20)
666 .leftJustified(60)
667 << "MARKER NUMBER\n";
668 }
669
670 *_stream << QString("%1%2")
671 .arg(_header._observer, -20)
672 .arg(_header._agency, -40)
673 .leftJustified(60)
674 << "OBSERVER / AGENCY\n";
675
676 *_stream << QString("%1%2%3")
677 .arg(_header._receiverNumber, -20)
678 .arg(_header._receiverType, -20)
679 .arg(_header._receiverVersion, -20)
680 .leftJustified(60)
681 << "REC # / TYPE / VERS\n";
682
683 *_stream << QString("%1%2")
684 .arg(_header._antennaNumber, -20)
685 .arg(_header._antennaName, -20)
686 .leftJustified(60)
687 << "ANT # / TYPE\n";
688
689 *_stream << QString("%1%2%3")
690 .arg(_header._xyz(1), 14, 'f', 4)
691 .arg(_header._xyz(2), 14, 'f', 4)
692 .arg(_header._xyz(3), 14, 'f', 4)
693 .leftJustified(60)
694 << "APPROX POSITION XYZ\n";
695
696 *_stream << QString("%1%2%3")
697 .arg(_header._antNEU(3), 14, 'f', 4)
698 .arg(_header._antNEU(2), 14, 'f', 4)
699 .arg(_header._antNEU(1), 14, 'f', 4)
700 .leftJustified(60)
701 << "ANTENNA: DELTA H/E/N\n";
702
703 if (_header._version < 3.0) {
704 int defaultWlFact1 = _header._wlFactorsL1[1];
705 int defaultWlFact2 = _header._wlFactorsL2[1]; // TODO check all prns
706 *_stream << QString("%1%2")
707 .arg(defaultWlFact1, 6)
708 .arg(defaultWlFact2, 6)
709 .leftJustified(60)
710 << "WAVELENGTH FACT L1/2\n";
711 }
712
713 if (_header._version < 3.0) {
714 QString hlp;
715 QTextStream(&hlp) << QString("%1").arg(_header._obsTypesV2.size(), 6);
716 for (unsigned ii = 0; ii < _header._obsTypesV2.size(); ii++) {
717 QTextStream(&hlp) << QString("%1").arg(_header._obsTypesV2[ii], 6);
718 if (ii > 0 && (ii % 8 == 0 || ii == _header._obsTypesV2.size()-1)) {
719 *_stream << hlp.leftJustified(60) << "# / TYPES OF OBSERV\n";
720 hlp = QString().leftJustified(6);
721 }
722 }
723 }
724 else {
725 map<char, vector<QString> >::const_iterator it;
726 for (it = _header._obsTypesV3.begin(); it != _header._obsTypesV3.end(); it++) {
727 char sys = it->first;
728 const vector<QString>& types = it->second;
729 QString hlp;
730 QTextStream(&hlp) << QString("%1 %2").arg(sys).arg(types.size(), 3);
731 for (unsigned ii = 0; ii < types.size(); ii++) {
732 QTextStream(&hlp) << QString(" %1").arg(types[ii], -3);
733 if (ii > 0 && (ii % 12 == 0 || ii == types.size()-1)) {
734 *_stream << hlp.leftJustified(60) << "SYS / # / OBS TYPES\n";
735 hlp = QString().leftJustified(6);
736 }
737 }
738 }
739 }
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 Data Epoch
767////////////////////////////////////////////////////////////////////////////
768void t_rnxObsFile::writeEpoch(const t_rnxEpo* epo) {
769 if (version() < 3.0) {
770 return writeEpochV2(epo);
771 }
772 else {
773 return writeEpochV3(epo);
774 }
775}
776
777// Write Data Epoch (RINEX Version 2)
778////////////////////////////////////////////////////////////////////////////
779void t_rnxObsFile::writeEpochV2(const t_rnxEpo* epo) {
780
781 unsigned year, month, day, hour, min;
782 double sec;
783 epo->tt.civil_date(year, month, day);
784 epo->tt.civil_time(hour, min, sec);
785
786 QString dateStr;
787 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
788 .arg(int(fmod(year, 100)), 2, 10, QChar('0'))
789 .arg(month, 2, 10, QChar('0'))
790 .arg(day, 2, 10, QChar('0'))
791 .arg(hour, 2, 10, QChar('0'))
792 .arg(min, 2, 10, QChar('0'))
793 .arg(sec, 11, 'f', 7);
794
795 int flag = 0;
796 *_stream << dateStr
797 << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
798 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
799 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
800 if (iSat > 0 && iSat % 12 == 0) {
801 *_stream << endl << QString().leftJustified(32);
802 }
803 *_stream << rnxSat.satSys << QString("%1").arg(rnxSat.satNum, 2);
804 }
805 *_stream << endl;
806 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
807
808 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
809
810 for (int iTypeV2 = 0; iTypeV2 < nTypes(rnxSat.satSys); iTypeV2++) {
811
812 if (iTypeV2 > 0 && iTypeV2 % 5 == 0) {
813 *_stream << endl;
814 }
815
816 int iType;
817 if (_trafo == trafoNone) {
818 iType = iTypeV2;
819 }
820 else {
821 iType = _indexMap2to3[rnxSat.satSys][iTypeV2];
822 }
823
824 if (rnxSat.obs[iType] == 0.0) {
825 *_stream << QString().leftJustified(16);
826 }
827 else {
828 *_stream << QString("%1%2%3")
829 .arg(rnxSat.obs[iType], 14, 'f', 3)
830 .arg(rnxSat.lli[iType],1)
831 .arg(rnxSat.snr[iType],1);
832 }
833 }
834 *_stream << endl;
835 }
836}
837
838// Write Data Epoch (RINEX Version 3)
839////////////////////////////////////////////////////////////////////////////
840void t_rnxObsFile::writeEpochV3(const t_rnxEpo* epo) {
841
842 unsigned year, month, day, hour, min;
843 double sec;
844 epo->tt.civil_date(year, month, day);
845 epo->tt.civil_time(hour, min, sec);
846
847 QString dateStr;
848 QTextStream(&dateStr) << QString("> %1 %2 %3 %4 %5%6")
849 .arg(year, 4)
850 .arg(month, 2, 10, QChar('0'))
851 .arg(day, 2, 10, QChar('0'))
852 .arg(hour, 2, 10, QChar('0'))
853 .arg(min, 2, 10, QChar('0'))
854 .arg(sec, 11, 'f', 7);
855
856 int flag = 0;
857 *_stream << dateStr
858 << QString("%1%2\n").arg(flag, 3).arg(epo->rnxSat.size(), 3);
859
860 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
861 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
862 *_stream << rnxSat.satSys
863 << QString("%1").arg(rnxSat.satNum, 2, 10, QChar('0'));
864
865 for (int iTypeV3 = 0; iTypeV3 < nTypes(rnxSat.satSys); iTypeV3++) {
866
867 int iType;
868 if (_trafo == trafoNone) {
869 iType = iTypeV3;
870 }
871 else {
872 iType = _indexMap3to2[rnxSat.satSys][iTypeV3];
873 }
874
875 if (rnxSat.obs[iType] == 0.0) {
876 *_stream << QString().leftJustified(16);
877 }
878 else {
879 *_stream << QString("%1%2%3")
880 .arg(rnxSat.obs[iType], 14, 'f', 3)
881 .arg(rnxSat.lli[iType],1)
882 .arg(rnxSat.snr[iType],1);
883 }
884 }
885 *_stream << endl;
886 }
887}
888
889// Translate Observation Type v2 --> v3
890////////////////////////////////////////////////////////////////////////////
891QString t_rnxObsFile::type2to3(char sys, const QString& typeV2) {
892
893 if (sys == 'G') {
894 if (typeV2 == "C1") return "C1C";
895 if (typeV2 == "C2") return "C2C";
896 if (typeV2 == "C5") return "C5C";
897 if (typeV2 == "P1") return "C1P";
898 if (typeV2 == "P2") return "C2P";
899 if (typeV2 == "L1") return "L1";
900 if (typeV2 == "L2") return "L2";
901 if (typeV2 == "L5") return "L5";
902 if (typeV2 == "D1") return "D1";
903 if (typeV2 == "D2") return "D2";
904 if (typeV2 == "D5") return "D5";
905 if (typeV2 == "S1") return "S1";
906 if (typeV2 == "S2") return "S2";
907 if (typeV2 == "S5") return "S5";
908 }
909
910 else if (sys == 'R') {
911 if (typeV2 == "C1") return "C1C";
912 if (typeV2 == "C2") return "C2C";
913 if (typeV2 == "P1") return "C1P";
914 if (typeV2 == "P2") return "C2P";
915 if (typeV2 == "L1") return "L1";
916 if (typeV2 == "L2") return "L2";
917 if (typeV2 == "D1") return "D1";
918 if (typeV2 == "D2") return "D2";
919 if (typeV2 == "S1") return "S1";
920 if (typeV2 == "S2") return "S2";
921 }
922
923 else if (sys == 'E') {
924 if (typeV2 == "C1") return "C1";
925 if (typeV2 == "C5") return "C5";
926 if (typeV2 == "C6") return "C6";
927 if (typeV2 == "C7") return "C7";
928 if (typeV2 == "C8") return "C8";
929 if (typeV2 == "L1") return "L1";
930 if (typeV2 == "L5") return "L5";
931 if (typeV2 == "L6") return "L6";
932 if (typeV2 == "L7") return "L7";
933 if (typeV2 == "L8") return "L8";
934 if (typeV2 == "D1") return "D1";
935 if (typeV2 == "D5") return "D5";
936 if (typeV2 == "D6") return "D6";
937 if (typeV2 == "D7") return "D7";
938 if (typeV2 == "D8") return "D8";
939 if (typeV2 == "S1") return "S1";
940 if (typeV2 == "S5") return "S5";
941 if (typeV2 == "S6") return "S6";
942 if (typeV2 == "S7") return "S7";
943 if (typeV2 == "S8") return "S8";
944 }
945
946 else if (sys == 'S') {
947 if (typeV2 == "C1") return "C1C";
948 if (typeV2 == "C5") return "C5C";
949 if (typeV2 == "L1") return "L1";
950 if (typeV2 == "L5") return "L5";
951 if (typeV2 == "D1") return "D1";
952 if (typeV2 == "D5") return "D5";
953 if (typeV2 == "S1") return "S1";
954 if (typeV2 == "S5") return "S5";
955 }
956
957 return "";
958}
959
960// Translate Observation Type v3 --> v2
961////////////////////////////////////////////////////////////////////////////
962QString t_rnxObsFile::type3to2(const QString& typeV3) {
963 if (typeV3 == "C1P") {
964 return "P1";
965 }
966 else if (typeV3 == "C2P") {
967 return "P2";
968 }
969 else {
970 return typeV3.left(2);
971 }
972
973 return "";
974}
Note: See TracBrowser for help on using the repository browser.