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

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