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

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