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

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