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

Last change on this file since 6704 was 6704, checked in by stuerze, 7 years ago

set default observation types if empty in skl file

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