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

Last change on this file since 3969 was 3969, checked in by mervart, 12 years ago
File size: 27.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.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 if (!typeV2.isEmpty()) {
622 bool found = false;
623 for (unsigned i2 = 0; i2 < _header._obsTypesV2.size(); i2++) {
624 if (_header._obsTypesV2[i2] == typeV2) {
625 found = true;
626 _indexMap2to3[sys][i2] = i3;
627 break;
628 }
629 }
630 if (!found) {
631 _header._obsTypesV2.push_back(typeV2);
632 int i2 = _header._obsTypesV2.size() - 1;
633 _indexMap2to3[sys][i2] = i3;
634 }
635 }
636 }
637 }
638 }
639 }
640}
641
642// Write Header
643////////////////////////////////////////////////////////////////////////////
644void t_rnxObsFile::writeHeader() {
645
646 bncApp* app = (bncApp*) qApp;
647
648 *_stream << QString("%1 Observation data Mixed")
649 .arg(_header._version, 9, 'f', 2)
650 .leftJustified(60)
651 << "RINEX VERSION / TYPE\n";
652
653 *_stream << QString("%1%2%3")
654 .arg(app->pgmName(), -20)
655 .arg(app->userName(), -20)
656 .arg(currentDateAndTimeGPS().date().toString("dd-MMM-yyyy"), -20)
657 .leftJustified(60)
658 << "PGM / RUN BY / DATE\n";
659
660 *_stream << QString("%1")
661 .arg(_header._markerName, -60)
662 .leftJustified(60)
663 << "MARKER NAME\n";
664
665 if (!_header._markerNumber.isEmpty()) {
666 *_stream << QString("%1")
667 .arg(_header._markerNumber, -20)
668 .leftJustified(60)
669 << "MARKER NUMBER\n";
670 }
671
672 *_stream << QString("%1%2")
673 .arg(_header._observer, -20)
674 .arg(_header._agency, -40)
675 .leftJustified(60)
676 << "OBSERVER / AGENCY\n";
677
678 *_stream << QString("%1%2%3")
679 .arg(_header._receiverNumber, -20)
680 .arg(_header._receiverType, -20)
681 .arg(_header._receiverVersion, -20)
682 .leftJustified(60)
683 << "REC # / TYPE / VERS\n";
684
685 *_stream << QString("%1%2")
686 .arg(_header._antennaNumber, -20)
687 .arg(_header._antennaName, -20)
688 .leftJustified(60)
689 << "ANT # / TYPE\n";
690
691 *_stream << QString("%1%2%3")
692 .arg(_header._xyz(1), 14, 'f', 4)
693 .arg(_header._xyz(2), 14, 'f', 4)
694 .arg(_header._xyz(3), 14, 'f', 4)
695 .leftJustified(60)
696 << "APPROX POSITION XYZ\n";
697
698 *_stream << QString("%1%2%3")
699 .arg(_header._antNEU(3), 14, 'f', 4)
700 .arg(_header._antNEU(2), 14, 'f', 4)
701 .arg(_header._antNEU(1), 14, 'f', 4)
702 .leftJustified(60)
703 << "ANTENNA: DELTA H/E/N\n";
704
705 if (_header._version < 3.0) {
706 int defaultWlFact1 = _header._wlFactorsL1[1];
707 int defaultWlFact2 = _header._wlFactorsL2[1]; // TODO check all prns
708 *_stream << QString("%1%2")
709 .arg(defaultWlFact1, 6)
710 .arg(defaultWlFact2, 6)
711 .leftJustified(60)
712 << "WAVELENGTH FACT L1/2\n";
713 }
714
715 if (_header._version < 3.0) {
716 QString hlp;
717 QTextStream(&hlp) << QString("%1").arg(_header._obsTypesV2.size(), 6);
718 for (unsigned ii = 0; ii < _header._obsTypesV2.size(); ii++) {
719 QTextStream(&hlp) << QString("%1").arg(_header._obsTypesV2[ii], 6);
720 if (ii > 0 && (ii % 8 == 0 || ii == _header._obsTypesV2.size()-1)) {
721 *_stream << hlp.leftJustified(60) << "# / TYPES OF OBSERV\n";
722 hlp = QString().leftJustified(6);
723 }
724 }
725 }
726 else {
727 map<char, vector<QString> >::const_iterator it;
728 for (it = _header._obsTypesV3.begin(); it != _header._obsTypesV3.end(); it++) {
729 char sys = it->first;
730 const vector<QString>& types = it->second;
731 QString hlp;
732 QTextStream(&hlp) << QString("%1 %2").arg(sys).arg(types.size(), 3);
733 for (unsigned ii = 0; ii < types.size(); ii++) {
734 QTextStream(&hlp) << QString(" %1").arg(types[ii], -3);
735 if (ii > 0 && (ii % 12 == 0 || ii == types.size()-1)) {
736 *_stream << hlp.leftJustified(60) << "SYS / # / OBS TYPES\n";
737 hlp = QString().leftJustified(6);
738 }
739 }
740 }
741 }
742
743 *_stream << QString("%1")
744 .arg(_header._interval, 10, 'f', 3)
745 .leftJustified(60)
746 << "INTERVAL\n";
747
748 unsigned year, month, day, hour, min;
749 double sec;
750 _header._startTime.civil_date(year, month, day);
751 _header._startTime.civil_time(hour, min, sec);
752 *_stream << QString("%1%2%3%4%5%6%7")
753 .arg(year, 6)
754 .arg(month, 6)
755 .arg(day, 6)
756 .arg(hour, 6)
757 .arg(min, 6)
758 .arg(sec, 13, 'f', 7)
759 .arg("GPS", 8)
760 .leftJustified(60)
761 << "TIME OF FIRST OBS\n";
762
763 *_stream << QString()
764 .leftJustified(60)
765 << "END OF HEADER\n";
766}
767
768// Write Data Epoch
769////////////////////////////////////////////////////////////////////////////
770void t_rnxObsFile::writeEpoch(const t_rnxEpo* epo) {
771 if (version() < 3.0) {
772 return writeEpochV2(epo);
773 }
774 else {
775 return writeEpochV3(epo);
776 }
777}
778
779// Write Data Epoch (RINEX Version 2)
780////////////////////////////////////////////////////////////////////////////
781void t_rnxObsFile::writeEpochV2(const t_rnxEpo* epo) {
782
783 unsigned year, month, day, hour, min;
784 double sec;
785 epo->tt.civil_date(year, month, day);
786 epo->tt.civil_time(hour, min, sec);
787
788 QString dateStr;
789 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
790 .arg(int(fmod(year, 100)), 2, 10, QChar('0'))
791 .arg(month, 2, 10, QChar('0'))
792 .arg(day, 2, 10, QChar('0'))
793 .arg(hour, 2, 10, QChar('0'))
794 .arg(min, 2, 10, QChar('0'))
795 .arg(sec, 11, 'f', 7);
796
797 int flag = 0;
798 *_stream << dateStr
799 << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
800 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
801 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
802 if (iSat > 0 && iSat % 12 == 0) {
803 *_stream << endl << QString().leftJustified(32);
804 }
805 *_stream << rnxSat.satSys << QString("%1").arg(rnxSat.satNum, 2);
806 }
807 *_stream << endl;
808 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
809
810 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
811
812 for (int iTypeV2 = 0; iTypeV2 < nTypes(rnxSat.satSys); iTypeV2++) {
813
814 if (iTypeV2 > 0 && iTypeV2 % 5 == 0) {
815 *_stream << endl;
816 }
817
818 int iType;
819 if (_trafo == trafoNone) {
820 iType = iTypeV2;
821 }
822 else {
823 iType = _indexMap2to3[rnxSat.satSys][iTypeV2];
824 }
825
826 if (rnxSat.obs[iType] == 0.0) {
827 *_stream << QString().leftJustified(16);
828 }
829 else {
830 *_stream << QString("%1%2%3")
831 .arg(rnxSat.obs[iType], 14, 'f', 3)
832 .arg(rnxSat.lli[iType],1)
833 .arg(rnxSat.snr[iType],1);
834 }
835 }
836 *_stream << endl;
837 }
838}
839
840// Write Data Epoch (RINEX Version 3)
841////////////////////////////////////////////////////////////////////////////
842void t_rnxObsFile::writeEpochV3(const t_rnxEpo* epo) {
843
844 unsigned year, month, day, hour, min;
845 double sec;
846 epo->tt.civil_date(year, month, day);
847 epo->tt.civil_time(hour, min, sec);
848
849 QString dateStr;
850 QTextStream(&dateStr) << QString("> %1 %2 %3 %4 %5%6")
851 .arg(year, 4)
852 .arg(month, 2, 10, QChar('0'))
853 .arg(day, 2, 10, QChar('0'))
854 .arg(hour, 2, 10, QChar('0'))
855 .arg(min, 2, 10, QChar('0'))
856 .arg(sec, 11, 'f', 7);
857
858 int flag = 0;
859 *_stream << dateStr
860 << QString("%1%2\n").arg(flag, 3).arg(epo->rnxSat.size(), 3);
861
862 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
863 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
864 *_stream << rnxSat.satSys
865 << QString("%1").arg(rnxSat.satNum, 2, 10, QChar('0'));
866
867 for (int iTypeV3 = 0; iTypeV3 < nTypes(rnxSat.satSys); iTypeV3++) {
868
869 int iType;
870 if (_trafo == trafoNone) {
871 iType = iTypeV3;
872 }
873 else {
874 iType = _indexMap3to2[rnxSat.satSys][iTypeV3];
875 }
876
877 if (rnxSat.obs[iType] == 0.0) {
878 *_stream << QString().leftJustified(16);
879 }
880 else {
881 *_stream << QString("%1%2%3")
882 .arg(rnxSat.obs[iType], 14, 'f', 3)
883 .arg(rnxSat.lli[iType],1)
884 .arg(rnxSat.snr[iType],1);
885 }
886 }
887 *_stream << endl;
888 }
889}
890
891// Translate Observation Type v2 --> v3
892////////////////////////////////////////////////////////////////////////////
893QString t_rnxObsFile::type2to3(char sys, const QString& typeV2) {
894
895 if (sys == 'G') {
896 if (typeV2 == "C1") return "C1C";
897 if (typeV2 == "C2") return "C2C";
898 if (typeV2 == "C5") return "C5C";
899 if (typeV2 == "P1") return "C1P";
900 if (typeV2 == "P2") return "C2P";
901 if (typeV2 == "L1") return "L1";
902 if (typeV2 == "L2") return "L2";
903 if (typeV2 == "L5") return "L5";
904 if (typeV2 == "D1") return "D1";
905 if (typeV2 == "D2") return "D2";
906 if (typeV2 == "D5") return "D5";
907 if (typeV2 == "S1") return "S1";
908 if (typeV2 == "S2") return "S2";
909 if (typeV2 == "S5") return "S5";
910 }
911
912 else if (sys == 'R') {
913 if (typeV2 == "C1") return "C1C";
914 if (typeV2 == "C2") return "C2C";
915 if (typeV2 == "P1") return "C1P";
916 if (typeV2 == "P2") return "C2P";
917 if (typeV2 == "L1") return "L1";
918 if (typeV2 == "L2") return "L2";
919 if (typeV2 == "D1") return "D1";
920 if (typeV2 == "D2") return "D2";
921 if (typeV2 == "S1") return "S1";
922 if (typeV2 == "S2") return "S2";
923 }
924
925 else if (sys == 'E') {
926 if (typeV2 == "C1") return "C1";
927 if (typeV2 == "C5") return "C5";
928 if (typeV2 == "C6") return "C6";
929 if (typeV2 == "C7") return "C7";
930 if (typeV2 == "C8") return "C8";
931 if (typeV2 == "L1") return "L1";
932 if (typeV2 == "L5") return "L5";
933 if (typeV2 == "L6") return "L6";
934 if (typeV2 == "L7") return "L7";
935 if (typeV2 == "L8") return "L8";
936 if (typeV2 == "D1") return "D1";
937 if (typeV2 == "D5") return "D5";
938 if (typeV2 == "D6") return "D6";
939 if (typeV2 == "D7") return "D7";
940 if (typeV2 == "D8") return "D8";
941 if (typeV2 == "S1") return "S1";
942 if (typeV2 == "S5") return "S5";
943 if (typeV2 == "S6") return "S6";
944 if (typeV2 == "S7") return "S7";
945 if (typeV2 == "S8") return "S8";
946 }
947
948 else if (sys == 'S') {
949 if (typeV2 == "C1") return "C1C";
950 if (typeV2 == "C5") return "C5C";
951 if (typeV2 == "L1") return "L1";
952 if (typeV2 == "L5") return "L5";
953 if (typeV2 == "D1") return "D1";
954 if (typeV2 == "D5") return "D5";
955 if (typeV2 == "S1") return "S1";
956 if (typeV2 == "S5") return "S5";
957 }
958
959 return "";
960}
961
962// Translate Observation Type v3 --> v2
963////////////////////////////////////////////////////////////////////////////
964QString t_rnxObsFile::type3to2(const QString& typeV3) {
965 if (typeV3 == "C1P") {
966 return "P1";
967 }
968 else if (typeV3 == "C2P") {
969 return "P2";
970 }
971 else {
972 return typeV3.left(2);
973 }
974
975 return "";
976}
Note: See TracBrowser for help on using the repository browser.