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

Last change on this file since 3960 was 3960, checked in by mervart, 12 years ago
File size: 26.2 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 // Copy Observation Types
576 // ----------------------
577 for (unsigned ii = 0; ii < header._obsTypesV2.size(); ii++) {
578 _header._obsTypesV2.push_back(header._obsTypesV2[ii]);
579 }
580 map<char, vector<QString> >::const_iterator it;
581 for (it = header._obsTypesV3.begin(); it != header._obsTypesV3.end(); it++) {
582 char sys = it->first;
583 const vector<QString>& typesV3 = it->second;
584 for (unsigned ii = 0; ii < typesV3.size(); ii++) {
585 _header._obsTypesV3[sys].push_back(typesV3[ii]);
586 }
587 }
588
589 static const string systems = "GRES";
590
591 // Translate Observation Types v2 --> v3
592 // -------------------------------------
593 if (_trafo == trafo2to3) {
594 for (unsigned ii = 0; ii < header._obsTypesV2.size(); ii++) {
595 const QString& typeV2 = header._obsTypesV2[ii];
596 for (unsigned iSys = 0; iSys < systems.length(); iSys++) {
597 char sys = systems[iSys];
598 QString typeV3 = type2to3(sys, typeV2);
599 if (!typeV3.isEmpty()) {
600 _header._obsTypesV3[sys].push_back(typeV3);
601 _indexMap2to3[sys][ii] = _header._obsTypesV3[sys].size() - 1;
602 }
603 else {
604 _indexMap2to3[sys][ii] = -1;
605 }
606 }
607 }
608 }
609
610 // Translate Observation Types v3 --> v2
611 // -------------------------------------
612 else if (_trafo == trafo3to2) {
613
614 }
615}
616
617// Write Header
618////////////////////////////////////////////////////////////////////////////
619void t_rnxObsFile::writeHeader() {
620
621 bncApp* app = (bncApp*) qApp;
622
623 *_stream << QString("%1 Observation data Mixed")
624 .arg(_header._version, 9, 'f', 2)
625 .leftJustified(60)
626 << "RINEX VERSION / TYPE\n";
627
628 *_stream << QString("%1%2%3")
629 .arg(app->pgmName(), -20)
630 .arg(app->userName(), -20)
631 .arg(currentDateAndTimeGPS().date().toString("dd-MMM-yyyy"), -20)
632 .leftJustified(60)
633 << "PGM / RUN BY / DATE\n";
634
635 *_stream << QString("%1")
636 .arg(_header._markerName, -60)
637 .leftJustified(60)
638 << "MARKER NAME\n";
639
640 if (!_header._markerNumber.isEmpty()) {
641 *_stream << QString("%1")
642 .arg(_header._markerNumber, -20)
643 .leftJustified(60)
644 << "MARKER NUMBER\n";
645 }
646
647 *_stream << QString("%1%2")
648 .arg(_header._observer, -20)
649 .arg(_header._agency, -40)
650 .leftJustified(60)
651 << "OBSERVER / AGENCY\n";
652
653 *_stream << QString("%1%2%3")
654 .arg(_header._receiverNumber, -20)
655 .arg(_header._receiverType, -20)
656 .arg(_header._receiverVersion, -20)
657 .leftJustified(60)
658 << "REC # / TYPE / VERS\n";
659
660 *_stream << QString("%1%2")
661 .arg(_header._antennaNumber, -20)
662 .arg(_header._antennaName, -20)
663 .leftJustified(60)
664 << "ANT # / TYPE\n";
665
666 *_stream << QString("%1%2%3")
667 .arg(_header._xyz(1), 14, 'f', 4)
668 .arg(_header._xyz(2), 14, 'f', 4)
669 .arg(_header._xyz(3), 14, 'f', 4)
670 .leftJustified(60)
671 << "APPROX POSITION XYZ\n";
672
673 *_stream << QString("%1%2%3")
674 .arg(_header._antNEU(3), 14, 'f', 4)
675 .arg(_header._antNEU(2), 14, 'f', 4)
676 .arg(_header._antNEU(1), 14, 'f', 4)
677 .leftJustified(60)
678 << "ANTENNA: DELTA H/E/N\n";
679
680 if (_header._version < 3.0) {
681 int defaultWlFact1 = _header._wlFactorsL1[1];
682 int defaultWlFact2 = _header._wlFactorsL2[1]; // TODO check all prns
683 *_stream << QString("%1%2")
684 .arg(defaultWlFact1, 6)
685 .arg(defaultWlFact2, 6)
686 .leftJustified(60)
687 << "WAVELENGTH FACT L1/2\n";
688 }
689
690 if (_header._version < 3.0) {
691 QString hlp;
692 QTextStream(&hlp) << QString("%1").arg(_header._obsTypesV2.size(), 6);
693 for (unsigned ii = 0; ii < _header._obsTypesV2.size(); ii++) {
694 QTextStream(&hlp) << QString("%1").arg(_header._obsTypesV2[ii], 6);
695 if (ii > 0 && (ii % 8 == 0 || ii == _header._obsTypesV2.size()-1)) {
696 *_stream << hlp.leftJustified(60) << "# / TYPES OF OBSERV\n";
697 hlp = QString().leftJustified(6);
698 }
699 }
700 }
701 else {
702 map<char, vector<QString> >::const_iterator it;
703 for (it = _header._obsTypesV3.begin(); it != _header._obsTypesV3.end(); it++) {
704 char sys = it->first;
705 const vector<QString>& types = it->second;
706 QString hlp;
707 QTextStream(&hlp) << QString("%1 %2").arg(sys).arg(types.size(), 3);
708 for (unsigned ii = 0; ii < types.size(); ii++) {
709 QTextStream(&hlp) << QString(" %1").arg(types[ii], -3);
710 if (ii > 0 && (ii % 12 == 0 || ii == types.size()-1)) {
711 *_stream << hlp.leftJustified(60) << "SYS / # / OBS TYPES\n";
712 hlp = QString().leftJustified(6);
713 }
714 }
715 }
716 }
717
718 *_stream << QString("%1")
719 .arg(_header._interval, 10, 'f', 3)
720 .leftJustified(60)
721 << "INTERVAL\n";
722
723 unsigned year, month, day, hour, min;
724 double sec;
725 _header._startTime.civil_date(year, month, day);
726 _header._startTime.civil_time(hour, min, sec);
727 *_stream << QString("%1%2%3%4%5%6%7")
728 .arg(year, 6)
729 .arg(month, 6)
730 .arg(day, 6)
731 .arg(hour, 6)
732 .arg(min, 6)
733 .arg(sec, 13, 'f', 7)
734 .arg("GPS", 8)
735 .leftJustified(60)
736 << "TIME OF FIRST OBS\n";
737
738 *_stream << QString()
739 .leftJustified(60)
740 << "END OF HEADER\n";
741}
742
743// Write Data Epoch
744////////////////////////////////////////////////////////////////////////////
745void t_rnxObsFile::writeEpoch(const t_rnxEpo* epo) {
746 if (version() < 3.0) {
747 return writeEpochV2(epo);
748 }
749 else {
750 return writeEpochV3(epo);
751 }
752}
753
754// Write Data Epoch (RINEX Version 2)
755////////////////////////////////////////////////////////////////////////////
756void t_rnxObsFile::writeEpochV2(const t_rnxEpo* epo) {
757
758 unsigned year, month, day, hour, min;
759 double sec;
760 epo->tt.civil_date(year, month, day);
761 epo->tt.civil_time(hour, min, sec);
762
763 QString dateStr;
764 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
765 .arg(int(fmod(year, 100)), 2, 10, QChar('0'))
766 .arg(month, 2, 10, QChar('0'))
767 .arg(day, 2, 10, QChar('0'))
768 .arg(hour, 2, 10, QChar('0'))
769 .arg(min, 2, 10, QChar('0'))
770 .arg(sec, 11, 'f', 7);
771
772 int flag = 0;
773 *_stream << dateStr
774 << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
775 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
776 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
777 if (iSat > 0 && iSat % 12 == 0) {
778 *_stream << endl << QString().leftJustified(32);
779 }
780 *_stream << rnxSat.satSys << QString("%1").arg(rnxSat.satNum, 2);
781 }
782 *_stream << endl;
783 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
784 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
785 for (unsigned iType = 0; iType < rnxSat.obs.size(); iType++) {
786 if (iType > 0 && iType % 5 == 0) {
787 *_stream << endl;
788 }
789 if (rnxSat.obs[iType] == 0.0) {
790 *_stream << QString().leftJustified(16);
791 }
792 else {
793 *_stream << QString("%1%2%3")
794 .arg(rnxSat.obs[iType], 14, 'f', 3)
795 .arg(rnxSat.lli[iType],1)
796 .arg(rnxSat.snr[iType],1);
797 }
798 }
799 *_stream << endl;
800 }
801}
802
803// Write Data Epoch (RINEX Version 3)
804////////////////////////////////////////////////////////////////////////////
805void t_rnxObsFile::writeEpochV3(const t_rnxEpo* epo) {
806
807 unsigned year, month, day, hour, min;
808 double sec;
809 epo->tt.civil_date(year, month, day);
810 epo->tt.civil_time(hour, min, sec);
811
812 QString dateStr;
813 QTextStream(&dateStr) << QString("> %1 %2 %3 %4 %5%6")
814 .arg(year, 4)
815 .arg(month, 2, 10, QChar('0'))
816 .arg(day, 2, 10, QChar('0'))
817 .arg(hour, 2, 10, QChar('0'))
818 .arg(min, 2, 10, QChar('0'))
819 .arg(sec, 11, 'f', 7);
820
821 int flag = 0;
822 *_stream << dateStr
823 << QString("%1%2\n").arg(flag, 3).arg(epo->rnxSat.size(), 3);
824
825 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
826 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
827 *_stream << rnxSat.satSys
828 << QString("%1").arg(rnxSat.satNum, 2, 10, QChar('0'));
829 for (unsigned iType = 0; iType < rnxSat.obs.size(); iType++) {
830 if (rnxSat.obs[iType] == 0.0) {
831 *_stream << QString().leftJustified(16);
832 }
833 else {
834 *_stream << QString("%1%2%3")
835 .arg(rnxSat.obs[iType], 14, 'f', 3)
836 .arg(rnxSat.lli[iType],1)
837 .arg(rnxSat.snr[iType],1);
838 }
839 }
840 *_stream << endl;
841 }
842}
843
844// Translate Observation Type v2 --> v3
845////////////////////////////////////////////////////////////////////////////
846QString t_rnxObsFile::type2to3(char sys, const QString& typeV2) {
847
848 if (sys == 'G') {
849 if (typeV2 == "C1") return "C1C";
850 if (typeV2 == "C2") return "C2C";
851 if (typeV2 == "C5") return "C5C";
852 if (typeV2 == "P1") return "C1P";
853 if (typeV2 == "P2") return "C2P";
854 if (typeV2 == "L1") return "L1";
855 if (typeV2 == "L2") return "L2";
856 if (typeV2 == "L5") return "L5";
857 if (typeV2 == "D1") return "D1";
858 if (typeV2 == "D2") return "D2";
859 if (typeV2 == "D5") return "D5";
860 if (typeV2 == "S1") return "S1";
861 if (typeV2 == "S2") return "S2";
862 if (typeV2 == "S5") return "S5";
863 }
864
865 else if (sys == 'R') {
866 if (typeV2 == "C1") return "C1C";
867 if (typeV2 == "C2") return "C2C";
868 if (typeV2 == "P1") return "C1P";
869 if (typeV2 == "P2") return "C2P";
870 if (typeV2 == "L1") return "L1";
871 if (typeV2 == "L2") return "L2";
872 if (typeV2 == "D1") return "D1";
873 if (typeV2 == "D2") return "D2";
874 if (typeV2 == "S1") return "S1";
875 if (typeV2 == "S2") return "S2";
876 }
877
878 else if (sys == 'E') {
879 if (typeV2 == "C1") return "C1";
880 if (typeV2 == "C5") return "C5";
881 if (typeV2 == "C6") return "C6";
882 if (typeV2 == "C7") return "C7";
883 if (typeV2 == "C8") return "C8";
884 if (typeV2 == "L1") return "L1";
885 if (typeV2 == "L5") return "L5";
886 if (typeV2 == "L6") return "L6";
887 if (typeV2 == "L7") return "L7";
888 if (typeV2 == "L8") return "L8";
889 if (typeV2 == "D1") return "D1";
890 if (typeV2 == "D5") return "D5";
891 if (typeV2 == "D6") return "D6";
892 if (typeV2 == "D7") return "D7";
893 if (typeV2 == "D8") return "D8";
894 if (typeV2 == "S1") return "S1";
895 if (typeV2 == "S5") return "S5";
896 if (typeV2 == "S6") return "S6";
897 if (typeV2 == "S7") return "S7";
898 if (typeV2 == "S8") return "S8";
899 }
900
901 else if (sys == 'S') {
902 if (typeV2 == "C1") return "C1C";
903 if (typeV2 == "C5") return "C5C";
904 if (typeV2 == "L1") return "L1";
905 if (typeV2 == "L5") return "L5";
906 if (typeV2 == "D1") return "D1";
907 if (typeV2 == "D5") return "D5";
908 if (typeV2 == "S1") return "S1";
909 if (typeV2 == "S5") return "S5";
910 }
911
912 return "";
913}
Note: See TracBrowser for help on using the repository browser.