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

Last change on this file since 6120 was 6120, checked in by mervart, 10 years ago
File size: 30.7 KB
Line 
1// Part of BNC, a utility for retrieving decoding and
2// converting GNSS data streams from NTRIP broadcasters.
3//
4// Copyright (C) 2007
5// German Federal Agency for Cartography and Geodesy (BKG)
6// http://www.bkg.bund.de
7// Czech Technical University Prague, Department of Geodesy
8// http://www.fsv.cvut.cz
9//
10// Email: euref-ip@bkg.bund.de
11//
12// This program is free software; you can redistribute it and/or
13// modify it under the terms of the GNU General Public License
14// as published by the Free Software Foundation, version 2.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25/* -------------------------------------------------------------------------
26 * BKG NTRIP Client
27 * -------------------------------------------------------------------------
28 *
29 * Class: t_rnxObsFile
30 *
31 * Purpose: Reads RINEX Observation File
32 *
33 * Author: L. Mervart
34 *
35 * Created: 24-Jan-2012
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <iostream>
42#include <iomanip>
43#include <sstream>
44#include "rnxobsfile.h"
45#include "bncutils.h"
46#include "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 sys = defaultSystems[0].toAscii();
165 _obsTypes[sys].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[sys].append(hlp);
175 }
176 for (int ii = 1; ii < defaultSystems.length(); ii++) {
177 char sys = defaultSystems[ii].toAscii();
178 _obsTypes[sys] = _obsTypes[0];
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 sys = defaultSystems[0].toAscii();
374 QString hlp;
375 QTextStream(&hlp) << QString("%1").arg(_obsTypes[sys].size(), 6);
376 for (int ii = 0; ii < _obsTypes[sys].size(); ii++) {
377 QTextStream(&hlp) << QString("%1").arg(_obsTypes[sys][ii], 6);
378 if ((ii+1) % 9 == 0 || ii == _obsTypes[sys].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 sys = t_rnxObsHeader::defaultSystems[0].toAscii();
758 for (int ii = 0; ii < useObsTypes.size(); ii++) {
759 _header._obsTypes[sys].push_back(useObsTypes[ii]);
760 }
761 for (int ii = 1; ii < t_rnxObsHeader::defaultSystems.length(); ii++) {
762 char sys = t_rnxObsHeader::defaultSystems[ii].toAscii();
763 _header._obsTypes[sys] = _header._obsTypes[0];
764 }
765 }
766 else {
767 for (int ii = 0; ii < useObsTypes.size(); ii++) {
768 QStringList hlp = useObsTypes[ii].split(":", QString::SkipEmptyParts);
769 if (hlp.size() == 2 && hlp[0].length() == 1) {
770 char sys = hlp[0][0].toAscii();
771 QString type = hlp[1];
772 _header._obsTypes[sys].push_back(type);
773 }
774 }
775 }
776 }
777}
778
779// Write Data Epoch
780////////////////////////////////////////////////////////////////////////////
781void t_rnxObsFile::writeEpoch(const t_rnxEpo* epo) {
782 if (version() < 3.0) {
783 return writeEpochV2(epo);
784 }
785 else {
786 return writeEpochV3(epo);
787 }
788}
789
790// Write Data Epoch (RINEX Version 2)
791////////////////////////////////////////////////////////////////////////////
792void t_rnxObsFile::writeEpochV2(const t_rnxEpo* epo) {
793
794 unsigned year, month, day, hour, min;
795 double sec;
796 epo->tt.civil_date(year, month, day);
797 epo->tt.civil_time(hour, min, sec);
798
799 QString dateStr;
800 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
801 .arg(int(fmod(year, 100)), 2, 10, QChar('0'))
802 .arg(month, 2, 10, QChar('0'))
803 .arg(day, 2, 10, QChar('0'))
804 .arg(hour, 2, 10, QChar('0'))
805 .arg(min, 2, 10, QChar('0'))
806 .arg(sec, 11, 'f', 7);
807
808 int flag = 0;
809 *_stream << dateStr
810 << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
811 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
812 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
813 if (iSat > 0 && iSat % 12 == 0) {
814 *_stream << endl << QString().leftJustified(32);
815 }
816 *_stream << rnxSat.prn;
817 }
818 *_stream << endl;
819 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
820
821 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
822 char sys = rnxSat.prn.system();
823
824 for (int iType = 0; iType < nTypes(sys); iType++) {
825 if (iType > 0 && iType % 5 == 0) {
826 *_stream << endl;
827 }
828 QString type = obsType(sys, iType);
829 if (!rnxSat.obs.contains(type)) {
830 *_stream << QString().leftJustified(16);
831 }
832 else {
833 const t_rnxObs& rnxObs = rnxSat.obs[type];
834 *_stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
835 if (rnxObs.lli != 0.0) {
836 *_stream << QString("%1").arg(rnxObs.lli,1);
837 }
838 else {
839 *_stream << ' ';
840 }
841 if (rnxObs.snr != 0.0) {
842 *_stream << QString("%1").arg(rnxObs.snr,1);
843 }
844 else {
845 *_stream << ' ';
846 }
847 }
848 }
849 *_stream << endl;
850 }
851}
852
853// Write Data Epoch (RINEX Version 3)
854////////////////////////////////////////////////////////////////////////////
855void t_rnxObsFile::writeEpochV3(const t_rnxEpo* epo) {
856
857 unsigned year, month, day, hour, min;
858 double sec;
859 epo->tt.civil_date(year, month, day);
860 epo->tt.civil_time(hour, min, sec);
861
862 QString dateStr;
863 QTextStream(&dateStr) << QString("> %1 %2 %3 %4 %5%6")
864 .arg(year, 4)
865 .arg(month, 2, 10, QChar('0'))
866 .arg(day, 2, 10, QChar('0'))
867 .arg(hour, 2, 10, QChar('0'))
868 .arg(min, 2, 10, QChar('0'))
869 .arg(sec, 11, 'f', 7);
870
871 int flag = 0;
872 *_stream << dateStr
873 << QString("%1%2\n").arg(flag, 3).arg(epo->rnxSat.size(), 3);
874
875 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
876 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
877 char sys = rnxSat.prn.system();
878
879 *_stream << rnxSat.prn;
880 for (int iType = 0; iType < nTypes(sys); iType++) {
881 QString type = obsType(sys, iType);
882 if (!rnxSat.obs.contains(type)) {
883 *_stream << QString().leftJustified(16);
884 }
885 else {
886 const t_rnxObs& rnxObs = rnxSat.obs[type];
887 *_stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
888 if (rnxObs.lli != 0.0) {
889 *_stream << QString("%1").arg(rnxObs.lli,1);
890 }
891 else {
892 *_stream << ' ';
893 }
894 if (rnxObs.snr != 0.0) {
895 *_stream << QString("%1").arg(rnxObs.snr,1);
896 }
897 else {
898 *_stream << ' ';
899 }
900 }
901 }
902 *_stream << endl;
903 }
904}
905
906// Translate Observation Type v2 --> v3
907////////////////////////////////////////////////////////////////////////////
908QString t_rnxObsFile::type2to3(char sys, const QString& typeV2) {
909
910 if (sys == 'G') {
911 if (typeV2 == "C1") return "C1C";
912 if (typeV2 == "C2") return "C2C";
913 if (typeV2 == "C5") return "C5C";
914 if (typeV2 == "P1") return "C1P";
915 if (typeV2 == "P2") return "C2P";
916 if (typeV2 == "L1") return "L1";
917 if (typeV2 == "L2") return "L2";
918 if (typeV2 == "L5") return "L5";
919 if (typeV2 == "D1") return "D1";
920 if (typeV2 == "D2") return "D2";
921 if (typeV2 == "D5") return "D5";
922 if (typeV2 == "S1") return "S1";
923 if (typeV2 == "S2") return "S2";
924 if (typeV2 == "S5") return "S5";
925 }
926
927 else if (sys == 'R') {
928 if (typeV2 == "C1") return "C1C";
929 if (typeV2 == "C2") return "C2C";
930 if (typeV2 == "P1") return "C1P";
931 if (typeV2 == "P2") return "C2P";
932 if (typeV2 == "L1") return "L1";
933 if (typeV2 == "L2") return "L2";
934 if (typeV2 == "D1") return "D1";
935 if (typeV2 == "D2") return "D2";
936 if (typeV2 == "S1") return "S1";
937 if (typeV2 == "S2") return "S2";
938 }
939
940 else if (sys == 'E') {
941 if (typeV2 == "C1") return "C1";
942 if (typeV2 == "C5") return "C5";
943 if (typeV2 == "C6") return "C6";
944 if (typeV2 == "C7") return "C7";
945 if (typeV2 == "C8") return "C8";
946 if (typeV2 == "L1") return "L1";
947 if (typeV2 == "L5") return "L5";
948 if (typeV2 == "L6") return "L6";
949 if (typeV2 == "L7") return "L7";
950 if (typeV2 == "L8") return "L8";
951 if (typeV2 == "D1") return "D1";
952 if (typeV2 == "D5") return "D5";
953 if (typeV2 == "D6") return "D6";
954 if (typeV2 == "D7") return "D7";
955 if (typeV2 == "D8") return "D8";
956 if (typeV2 == "S1") return "S1";
957 if (typeV2 == "S5") return "S5";
958 if (typeV2 == "S6") return "S6";
959 if (typeV2 == "S7") return "S7";
960 if (typeV2 == "S8") return "S8";
961 }
962
963 else if (sys == 'S') {
964 if (typeV2 == "C1") return "C1C";
965 if (typeV2 == "C5") return "C5C";
966 if (typeV2 == "L1") return "L1";
967 if (typeV2 == "L5") return "L5";
968 if (typeV2 == "D1") return "D1";
969 if (typeV2 == "D5") return "D5";
970 if (typeV2 == "S1") return "S1";
971 if (typeV2 == "S5") return "S5";
972 }
973
974 return "";
975}
976
977// Translate Observation Type v3 --> v2
978////////////////////////////////////////////////////////////////////////////
979QString t_rnxObsFile::type3to2(const QString& typeV3) {
980 if (typeV3 == "C1P") {
981 return "P1";
982 }
983 else if (typeV3 == "C2P") {
984 return "P2";
985 }
986 else {
987 return typeV3.left(2);
988 }
989
990 return "";
991}
992
993// Check for Changes in Header
994////////////////////////////////////////////////////////////////////////////
995void t_rnxObsFile::checkNewHeader(const t_rnxObsHeader& header) {
996
997 t_rnxObsHeader oldHeader(_header);
998 setHeader(header, oldHeader._version, QStringList());
999
1000 // Check Observation Types
1001 // -----------------------
1002 bool same = true;
1003 QMapIterator<char, QVector<QString> > it(_header._obsTypes);
1004 while (it.hasNext()) {
1005 it.next();
1006 char sys = it.key();
1007 const QVector<QString>& types = it.value();
1008 if (!oldHeader._obsTypes.contains(sys) || oldHeader._obsTypes[sys] != types) {
1009 same = false;
1010 break;
1011 }
1012 }
1013
1014 if (!same) {
1015 QStringList strLst = _header.obsTypesStrings();
1016 if (_header._version < 3.0) {
1017 *_stream << QString().leftJustified(26);
1018 }
1019 else {
1020 *_stream << '>' << QString().leftJustified(28);
1021 }
1022 *_stream << QString(" 4%1\n").arg(strLst.size(), 3)
1023 << strLst.join("");
1024 }
1025}
1026
1027// Set Observations from RINEX File
1028////////////////////////////////////////////////////////////////////////////
1029void t_rnxObsFile::setObsFromRnx(const t_rnxObsFile* rnxObsFile,
1030 const t_rnxObsFile::t_rnxEpo* epo,
1031 const t_rnxObsFile::t_rnxSat& rnxSat,
1032 t_obs& obs) {
1033
1034 strncpy(obs.StatID, rnxObsFile->markerName().toAscii().constData(),
1035 sizeof(obs.StatID));
1036
1037 obs.satSys = rnxSat.prn.system();
1038 obs.satNum = rnxSat.prn.number();
1039 obs.GPSWeek = epo->tt.gpsw();
1040 obs.GPSWeeks = epo->tt.gpssec();
1041
1042 for (int iType = 0; iType < rnxObsFile->nTypes(obs.satSys); iType++) {
1043 QString type = rnxObsFile->obsType(obs.satSys, iType);
1044 if (rnxSat.obs.contains(type)) {
1045 const t_rnxObs& rnxObs = rnxSat.obs[type];
1046 obs.setMeasdata(type, rnxObsFile->version(), rnxObs.value);
1047 if (type.indexOf("L1") == 0) {
1048 obs.snrL1 = rnxObs.snr;
1049 obs.slipL1 = (rnxObs.lli & 1);
1050 }
1051 else if (type.indexOf("L2") == 0) {
1052 obs.snrL2 = rnxObs.snr;
1053 obs.slipL2 = (rnxObs.lli & 1);
1054 }
1055 else if (type.indexOf("L5") == 0) {
1056 obs.snrL5 = rnxObs.snr;
1057 obs.slipL5 = (rnxObs.lli & 1);
1058 }
1059 }
1060 }
1061}
1062
1063// Set Observations from RINEX File
1064////////////////////////////////////////////////////////////////////////////
1065bool t_rnxObsFile::useType(const QStringList& useObsTypes, const QString& type) {
1066
1067 if (useObsTypes.size() == 0) {
1068 return true;
1069 }
1070 for (int ii = 0; ii < useObsTypes.size(); ii++) {
1071 if (type.left(2) == useObsTypes[ii].left(2)) {
1072 return true;
1073 }
1074 }
1075 return false;
1076}
Note: See TracBrowser for help on using the repository browser.