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

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