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

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