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

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