source: ntrip/trunk/BNC/src/rinex/rnxobsfile.cpp@ 4352

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