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

Last change on this file since 7790 was 7790, checked in by stuerze, 8 years ago

minor additions regarding default GLONASS obs types

File size: 45.9 KB
RevLine 
[3716]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 *
[7474]37 * Changes:
[3716]38 *
39 * -----------------------------------------------------------------------*/
40
41#include <iostream>
42#include <iomanip>
43#include <sstream>
[3722]44#include "rnxobsfile.h"
[3716]45#include "bncutils.h"
[5070]46#include "bnccore.h"
[6242]47#include "bncsettings.h"
[3716]48
49using namespace std;
50
51// Constructor
52////////////////////////////////////////////////////////////////////////////
[4480]53t_rnxObsHeader::t_rnxObsHeader() {
[6247]54 _usedSystems = "GREJCS";
[3716]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;
[5742]61 for (unsigned iPrn = 1; iPrn <= t_prn::MAXPRN_GPS; iPrn++) {
[3716]62 _wlFactorsL1[iPrn] = 1;
63 _wlFactorsL2[iPrn] = 1;
64 }
[7665]65 bncSettings settings;
66 _writeRinexOnlyWithSklObsTypes = settings.value("rnxOnlyWithSKL").toBool();
[3716]67}
68
69// Destructor
70////////////////////////////////////////////////////////////////////////////
[4480]71t_rnxObsHeader::~t_rnxObsHeader() {
[3716]72}
73
74// Read Header
75////////////////////////////////////////////////////////////////////////////
[4480]76t_irc t_rnxObsHeader::read(QTextStream* stream, int maxLines) {
[4534]77 _comments.clear();
[3716]78 int numLines = 0;
[6815]79
[3718]80 while ( stream->status() == QTextStream::Ok && !stream->atEnd() ) {
81 QString line = stream->readLine(); ++ numLines;
82 if (line.isEmpty()) {
[3716]83 continue;
84 }
[3718]85 if (line.indexOf("END OF FILE") != -1) {
[3716]86 break;
87 }
[3718]88 QString value = line.mid(0,60).trimmed();
89 QString key = line.mid(60).trimmed();
[3716]90 if (key == "END OF HEADER") {
91 break;
92 }
93 else if (key == "RINEX VERSION / TYPE") {
[3718]94 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
[3716]95 in >> _version;
96 }
97 else if (key == "MARKER NAME") {
98 _markerName = value;
99 }
[6941]100 else if (key == "MARKER TYPE") {
101 _markerType = value;
102 }
[3930]103 else if (key == "MARKER NUMBER") {
104 _markerNumber = line.mid(0,20).trimmed();
105 }
[3716]106 else if (key == "ANT # / TYPE") {
[3930]107 _antennaNumber = line.mid( 0,20).trimmed();
108 _antennaName = line.mid(20,20).trimmed();
[3716]109 }
[3930]110 else if (key == "OBSERVER / AGENCY") {
111 _observer = line.mid( 0,20).trimmed();
112 _agency = line.mid(20,40).trimmed();
113 }
114 else if (key == "REC # / TYPE / VERS") {
115 _receiverNumber = line.mid( 0,20).trimmed();
116 _receiverType = line.mid(20,20).trimmed();
117 _receiverVersion = line.mid(40,20).trimmed();
118 }
[3716]119 else if (key == "INTERVAL") {
[3718]120 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
[3716]121 in >> _interval;
122 }
[4494]123 else if (key == "COMMENT") {
124 _comments << line.mid(0,60).trimmed();
125 }
[3716]126 else if (key == "WAVELENGTH FACT L1/2") {
[3718]127 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
[3716]128 int wlFactL1 = 0;
129 int wlFactL2 = 0;
130 int numSat = 0;
131 in >> wlFactL1 >> wlFactL2 >> numSat;
132 if (numSat == 0) {
[5742]133 for (unsigned iPrn = 1; iPrn <= t_prn::MAXPRN_GPS; iPrn++) {
[3716]134 _wlFactorsL1[iPrn] = wlFactL1;
135 _wlFactorsL2[iPrn] = wlFactL2;
136 }
137 }
138 else {
139 for (int ii = 0; ii < numSat; ii++) {
[3718]140 QString prn; in >> prn;
[3716]141 if (prn[0] == 'G') {
142 int iPrn;
143 readInt(prn, 1, 2, iPrn);
144 _wlFactorsL1[iPrn] = wlFactL1;
145 _wlFactorsL2[iPrn] = wlFactL2;
146 }
147 }
148 }
149 }
150 else if (key == "APPROX POSITION XYZ") {
[3718]151 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
[3716]152 in >> _xyz[0] >> _xyz[1] >> _xyz[2];
153 }
154 else if (key == "ANTENNA: DELTA H/E/N") {
[3718]155 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
[3716]156 in >> _antNEU[2] >> _antNEU[1] >> _antNEU[0];
157 }
158 else if (key == "ANTENNA: DELTA X/Y/Z") {
[3718]159 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
[3716]160 in >> _antXYZ[0] >> _antXYZ[1] >> _antXYZ[2];
161 }
162 else if (key == "ANTENNA: B.SIGHT XYZ") {
[3718]163 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
[3716]164 in >> _antBSG[0] >> _antBSG[1] >> _antBSG[2];
165 }
166 else if (key == "# / TYPES OF OBSERV") {
[6223]167 if (_version == 0.0) {
168 _version = t_rnxObsHeader::defaultRnxObsVersion2;
169 }
[3864]170 QTextStream* in = new QTextStream(value.toAscii(), QIODevice::ReadOnly);
[3716]171 int nTypes;
[3864]172 *in >> nTypes;
[6245]173 char sys0 = _usedSystems[0].toAscii();
[6125]174 _obsTypes[sys0].clear();
[3716]175 for (int ii = 0; ii < nTypes; ii++) {
[3864]176 if (ii > 0 && ii % 9 == 0) {
177 line = stream->readLine(); ++numLines;
178 delete in;
[4152]179 in = new QTextStream(line.left(60).toAscii(), QIODevice::ReadOnly);
[3864]180 }
[3718]181 QString hlp;
[3864]182 *in >> hlp;
[6125]183 _obsTypes[sys0].append(hlp);
[3716]184 }
[6245]185 for (int ii = 1; ii < _usedSystems.length(); ii++) {
186 char sysI = _usedSystems[ii].toAscii();
[6125]187 _obsTypes[sysI] = _obsTypes[sys0];
[6119]188 }
[3716]189 }
190 else if (key == "SYS / # / OBS TYPES") {
[6223]191 if (_version == 0.0) {
[6228]192 _version = t_rnxObsHeader::defaultRnxObsVersion3;
[6223]193 }
[3718]194 QTextStream* in = new QTextStream(value.toAscii(), QIODevice::ReadOnly);
[3716]195 char sys;
196 int nTypes;
197 *in >> sys >> nTypes;
[6119]198 _obsTypes[sys].clear();
[3716]199 for (int ii = 0; ii < nTypes; ii++) {
200 if (ii > 0 && ii % 13 == 0) {
[3718]201 line = stream->readLine(); ++numLines;
[3716]202 delete in;
[3718]203 in = new QTextStream(line.toAscii(), QIODevice::ReadOnly);
[3716]204 }
[3718]205 QString hlp;
[3716]206 *in >> hlp;
[6817]207 if (sys == 'C' && _version < 3.03) {
[6816]208 hlp.replace('1', '2');
209 }
[6119]210 _obsTypes[sys].push_back(hlp);
[3716]211 }
212 delete in;
213 }
[3837]214 else if (key == "TIME OF FIRST OBS") {
215 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
216 int year, month, day, hour, min;
217 double sec;
218 in >> year >> month >> day >> hour >> min >> sec;
219 _startTime.set(year, month, day, hour, min, sec);
220 }
[6719]221 else if (key == "SYS / PHASE SHIFT"){
[6815]222 QTextStream* in = new QTextStream(value.toAscii(), QIODevice::ReadOnly);
223 char sys;
224 QString obstype;
225 double shift;
226 int satnum = 0;
227 QStringList satList;
228 QString sat;
229 *in >> sys >> obstype >> shift >> satnum;
230 if (obstype.size()) {
231 for (int ii = 0; ii < satnum; ii++) {
232 if (ii > 0 && ii % 10 == 0) {
233 line = stream->readLine(); ++numLines;
234 delete in;
235 in = new QTextStream(line.left(60).toAscii(), QIODevice::ReadOnly);
236 }
237 *in >> sat;
238 satList.append(sat);
239 }
240 delete in;
241 }
[6871]242 _phaseShifts.insert(sys+obstype, QPair<double, QStringList>(shift, satList));
[6719]243 }
244 else if (key == "GLONASS COD/PHS/BIS"){
245 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
246 for (int ii = 0; ii < 4; ii++) {
247 QString type;
248 double value;
249 in >> type >> value;
250 if (type.size())
[6841]251 _gloBiases[type] = value;
[6719]252 }
253 }
254 else if (key == "GLONASS SLOT / FRQ #") {
255 QTextStream* in = new QTextStream(value.toAscii(), QIODevice::ReadOnly);
256 int nSlots = 0;
257 *in >> nSlots;
258 for (int ii = 0; ii < nSlots; ii++) {
259 if (ii > 0 && ii % 8 == 0) {
260 line = stream->readLine(); ++numLines;
261 delete in;
262 in = new QTextStream(line.left(60).toAscii(), QIODevice::ReadOnly);
263 }
264 QString sat;
265 int slot;
266 *in >> sat >> slot;
267 t_prn prn;
268 prn.set(sat.toStdString());
269 if(sat.size())
270 _gloSlots[prn] = slot;
271 }
272 delete in;
273 }
[3716]274 if (maxLines > 0 && numLines == maxLines) {
275 break;
276 }
277 }
278
[6719]279 // set default observation types if empty in input file
280 // ----------------------------------------------------
[6704]281 if (_obsTypes.empty()) {
[7665]282 if (!_writeRinexOnlyWithSklObsTypes) {
283 setDefault(_markerName, _version);
284 }
285 else {
286 return failure;
287 }
[6704]288 }
289
[6245]290 // Systems used
291 // ------------
292 _usedSystems.clear();
293 QMapIterator<char, QStringList> it(_obsTypes);
294 while (it.hasNext()) {
295 it.next();
296 _usedSystems += QChar(it.key());
297 }
298
[3716]299 return success;
300}
301
[6222]302// Set Default Header
303////////////////////////////////////////////////////////////////////////////
304void t_rnxObsHeader::setDefault(const QString& markerName, int version) {
305
306 _markerName = markerName;
307
308 if (version <= 2) {
309 _version = t_rnxObsHeader::defaultRnxObsVersion2;
310 }
311 else {
312 _version = t_rnxObsHeader::defaultRnxObsVersion3;
313 }
314
315 _comments << "Default set of observation types used";
316
317 _obsTypes.clear();
318 if (_version < 3.0) {
[7474]319 _obsTypes['G'] << "C1" << "P1" << "L1" << "S1"
[6222]320 << "C2" << "P2" << "L2" << "S2";
321 _obsTypes['R'] = _obsTypes['G'];
322 _obsTypes['E'] = _obsTypes['G'];
323 _obsTypes['J'] = _obsTypes['G'];
324 _obsTypes['S'] = _obsTypes['G'];
325 _obsTypes['C'] = _obsTypes['G'];
326 }
327 else {
[7474]328 _obsTypes['G'] << "C1C" << "L1C" << "S1C"
[6815]329 << "C1W" << "L1W" << "S1W"
330 << "C2X" << "L2X" << "S2X"
[7474]331 << "C2W" << "L2W" << "S2W"
[6815]332 << "C5X" << "L5X" << "S5X";
333
[6222]334 _obsTypes['J'] = _obsTypes['G'];
[7790]335 // C2P L2P D2P S2P
[7474]336
337 _obsTypes['R'] << "C1C" << "L1C" << "S1C"
[7790]338 << "C1P" << "L1P" << "S1P"
339 << "C2C" << "L2C" << "S2C"
[6222]340 << "C2P" << "L2P" << "S2P";
[7474]341
[6815]342 _obsTypes['E'] << "C1X" << "L1X" << "SX1"
343 << "C5X" << "L5X" << "SX5"
344 << "C7X" << "L7X" << "SX7"
345 << "C8X" << "L8X" << "SX8";
[7474]346
[6815]347 _obsTypes['S'] << "C1C" << "L1C" << "S1C"
348 << "C5I" << "L5I" << "S5I"
349 << "C5Q" << "L5Q" << "S5Q";
[7474]350
[6815]351 _obsTypes['C'] << "C2I" << "L2I" << "S2I"
352 << "C6I" << "L6I" << "S6I"
353 << "C7I" << "L7I" << "S7I";
[6222]354 }
355}
356
357// Copy header
358////////////////////////////////////////////////////////////////////////////
359void t_rnxObsHeader::set(const t_rnxObsHeader& header, int version,
[6841]360 const QStringList* useObsTypes,
361 const QStringList* phaseShifts,
362 const QStringList* gloBiases,
363 const QStringList* gloSlots) {
[6222]364
365 if (version <= 2) {
366 _version = t_rnxObsHeader::defaultRnxObsVersion2;
367 }
368 else {
369 _version = t_rnxObsHeader::defaultRnxObsVersion3;
370 }
[7474]371 _interval = header._interval;
372 _antennaNumber = header._antennaNumber;
373 _antennaName = header._antennaName;
374 _markerName = header._markerName;
375 _markerNumber = header._markerNumber;
[6943]376 _markerType = header._markerType;
[7474]377 _antNEU = header._antNEU;
378 _antXYZ = header._antXYZ;
379 _antBSG = header._antBSG;
380 _xyz = header._xyz;
381 _observer = header._observer;
382 _agency = header._agency;
383 _receiverNumber = header._receiverNumber;
384 _receiverType = header._receiverType;
[6222]385 _receiverVersion = header._receiverVersion;
[7474]386 _startTime = header._startTime;
[6224]387 _comments = header._comments;
[6245]388 _usedSystems = header._usedSystems;
[6841]389
[6222]390 for (unsigned iPrn = 1; iPrn <= t_prn::MAXPRN_GPS; iPrn++) {
[7474]391 _wlFactorsL1[iPrn] = header._wlFactorsL1[iPrn];
392 _wlFactorsL2[iPrn] = header._wlFactorsL2[iPrn];
[6222]393 }
394
395 // Set observation types
396 // ---------------------
397 _obsTypes.clear();
398 if (!useObsTypes || useObsTypes->size() == 0) {
399 if (int(_version) == int(header._version)) {
400 _obsTypes = header._obsTypes;
401 }
402 else {
[6250]403 if (_version >= 3.0) {
404 for (int iSys = 0; iSys < header.numSys(); iSys++) {
405 char sys = header.system(iSys);
406 for (int iType = 0; iType < header.nTypes(sys); iType++) {
407 QString type = header.obsType(sys, iType, _version);
408 if (!_obsTypes[sys].contains(type)) {
409 _obsTypes[sys].push_back(type);
410 }
[6249]411 }
[6250]412 }
413 }
414 else {
415 for (int iSys = 0; iSys < header.numSys(); iSys++) {
416 char sys = header.system(iSys);
417 for (int iType = 0; iType < header.nTypes(sys); iType++) {
418 QString type = header.obsType(sys, iType, _version);
[6249]419 for (int jSys = 0; jSys < _usedSystems.length(); jSys++) {
420 char thisSys = _usedSystems[jSys].toAscii();
421 if (!_obsTypes[thisSys].contains(type)) {
422 _obsTypes[thisSys].push_back(type);
423 }
424 }
425 }
[6222]426 }
427 }
428 }
429 }
430 else {
431 for (int iType = 0; iType < useObsTypes->size(); iType++) {
432 if (useObsTypes->at(iType).indexOf(":") != -1) {
433 QStringList hlp = useObsTypes->at(iType).split(":", QString::SkipEmptyParts);
434 if (hlp.size() == 2 && hlp[0].length() == 1) {
[6248]435 if (_version >= 3.0) {
436 char sys = hlp[0][0].toAscii();
437 QString type = t_rnxObsFile::type2to3(sys, hlp[1]);
438 if (!_obsTypes[sys].contains(type)) {
439 _obsTypes[sys].push_back(type);
440 }
441 }
442 else {
443 for (int iSys = 0; iSys < _usedSystems.length(); iSys++) {
444 char sys = _usedSystems[iSys].toAscii();
445 QString type = t_rnxObsFile::type3to2(sys, hlp[1]);
446 if (!_obsTypes[sys].contains(type)) {
447 _obsTypes[sys].push_back(type);
448 }
449 }
450 }
[6222]451 }
452 }
453 else {
[6245]454 for (int iSys = 0; iSys < _usedSystems.length(); iSys++) {
[6248]455 char sys = _usedSystems[iSys].toAscii();
[7474]456 QString type = _version >= 3.0 ? t_rnxObsFile::type2to3(sys, useObsTypes->at(iType)) :
[6248]457 t_rnxObsFile::type3to2(sys, useObsTypes->at(iType));
458 if (!_obsTypes[sys].contains(type)) {
459 _obsTypes[sys].push_back(type);
460 }
[6222]461 }
462 }
463 }
[6245]464 _usedSystems.clear();
[6244]465 QMapIterator<char, QStringList> it(_obsTypes);
466 while (it.hasNext()) {
467 it.next();
[6245]468 _usedSystems += QChar(it.key());
[6244]469 }
[6222]470 }
[6841]471
472 if (_version >= 3.0) {
473 // set phase shifts
474 if (!phaseShifts || phaseShifts->empty()) {
475 _phaseShifts = header._phaseShifts;
476 }
477 else {
478 foreach (const QString &str, *phaseShifts) {
479 QStringList hlp = str.split("_", QString::SkipEmptyParts);
480 QStringList hlp1 = hlp.last().split(":", QString::SkipEmptyParts);
481 QString type = hlp.first();
482 double shift = hlp1.first().toDouble();
483 hlp1.removeFirst();
484 QStringList &satList = hlp1;
485 QMap<QString, QPair<double, QStringList> >::iterator it = _phaseShifts.find(type);
486 if ( it != _phaseShifts.end()) {
487 it.value().second.append(satList);
488 it.value().second.removeDuplicates();
489 }
490 else {
491 _phaseShifts.insert(type, QPair<double, QStringList>(shift, satList));
492 }
493 }
494 }
495 // set GLONASS biases
496 if (!gloBiases || gloBiases->empty()) {
497 _gloBiases = header._gloBiases;
498 }
499 else {
500 foreach (const QString &str, *gloBiases) {
501 QStringList hlp = str.split(":", QString::SkipEmptyParts);
502 QString type = hlp.first();;
503 double value = hlp.last().toDouble();
504 if (type.size())
505 _gloBiases[type] = value;
506 }
507 }
508 // set GLONASS slots
509 if (!gloSlots || gloSlots->empty()) {
510 _gloSlots = header._gloSlots;
511 }
512 else {
513 foreach (const QString &str, *gloSlots) {
514 QStringList hlp = str.split(":", QString::SkipEmptyParts);
515 QString sat = hlp.first();
516 int slot = hlp.last().toInt();
517 t_prn prn;
518 prn.set(sat.toStdString());
519 if(sat.size())
520 _gloSlots[prn] = slot;
521 }
522 }
523 }
[6222]524}
525
[4481]526// Write Header
527////////////////////////////////////////////////////////////////////////////
528void t_rnxObsHeader::write(QTextStream* stream,
529 const QMap<QString, QString>* txtMap) const {
530
[4493]531 QStringList newComments;
[5068]532 QString runBy = BNC_CORE->userName();
[4481]533
534 if (txtMap) {
[7474]535 QMapIterator<QString, QString> it(*txtMap);
[4481]536 while (it.hasNext()) {
537 it.next();
538 if (it.key() == "RUN BY") {
539 runBy = it.value();
540 }
[7474]541 else if ((it.key().indexOf("COMMENT")) != -1) {
542 newComments += it.value().split("\\n", QString::SkipEmptyParts);
[4481]543 }
544 }
545 }
546
[6941]547 *stream << QString("%1 OBSERVATION DATA M")
[4481]548 .arg(_version, 9, 'f', 2)
549 .leftJustified(60)
550 << "RINEX VERSION / TYPE\n";
551
552 const QString fmtDate = (_version < 3.0) ? "dd-MMM-yy hh:mm"
553 : "yyyyMMdd hhmmss UTC";
554 *stream << QString("%1%2%3")
[5068]555 .arg(BNC_CORE->pgmName(), -20)
[4481]556 .arg(runBy.trimmed().left(20), -20)
557 .arg(QDateTime::currentDateTime().toUTC().toString(fmtDate), -20)
558 .leftJustified(60)
559 << "PGM / RUN BY / DATE\n";
560
[4493]561 QStringListIterator itCmnt(_comments + newComments);
[4481]562 while (itCmnt.hasNext()) {
563 *stream << itCmnt.next().trimmed().left(60).leftJustified(60) << "COMMENT\n";
564 }
565
566 *stream << QString("%1")
567 .arg(_markerName, -60)
568 .leftJustified(60)
569 << "MARKER NAME\n";
570
571 if (!_markerNumber.isEmpty()) {
572 *stream << QString("%1")
573 .arg(_markerNumber, -20)
574 .leftJustified(60)
575 << "MARKER NUMBER\n";
576 }
577
[6941]578 *stream << QString("%1")
579 .arg(_markerType, -60)
580 .leftJustified(60)
581 << "MARKER TYPE\n";
[7474]582
[4481]583 *stream << QString("%1%2")
[4529]584 .arg(_observer, -20)
585 .arg(_agency, -40)
[4481]586 .leftJustified(60)
587 << "OBSERVER / AGENCY\n";
588
589 *stream << QString("%1%2%3")
[4529]590 .arg(_receiverNumber, -20)
591 .arg(_receiverType, -20)
592 .arg(_receiverVersion, -20)
[4481]593 .leftJustified(60)
594 << "REC # / TYPE / VERS\n";
595
596 *stream << QString("%1%2")
[4529]597 .arg(_antennaNumber, -20)
598 .arg(_antennaName, -20)
[4481]599 .leftJustified(60)
600 << "ANT # / TYPE\n";
601
602 *stream << QString("%1%2%3")
603 .arg(_xyz(1), 14, 'f', 4)
604 .arg(_xyz(2), 14, 'f', 4)
605 .arg(_xyz(3), 14, 'f', 4)
606 .leftJustified(60)
607 << "APPROX POSITION XYZ\n";
608
609 *stream << QString("%1%2%3")
610 .arg(_antNEU(3), 14, 'f', 4)
611 .arg(_antNEU(2), 14, 'f', 4)
612 .arg(_antNEU(1), 14, 'f', 4)
613 .leftJustified(60)
614 << "ANTENNA: DELTA H/E/N\n";
615
616 if (_version < 3.0) {
617 int defaultWlFact1 = _wlFactorsL1[1];
618 int defaultWlFact2 = _wlFactorsL2[1]; // TODO check all prns
619 *stream << QString("%1%2")
620 .arg(defaultWlFact1, 6)
621 .arg(defaultWlFact2, 6)
622 .leftJustified(60)
623 << "WAVELENGTH FACT L1/2\n";
624 }
625
626 *stream << obsTypesStrings().join("");
627
[4484]628 if (_interval > 0) {
629 *stream << QString("%1")
630 .arg(_interval, 10, 'f', 3)
631 .leftJustified(60)
632 << "INTERVAL\n";
633 }
[4481]634
635 unsigned year, month, day, hour, min;
636 double sec;
637 _startTime.civil_date(year, month, day);
638 _startTime.civil_time(hour, min, sec);
639 *stream << QString("%1%2%3%4%5%6%7")
640 .arg(year, 6)
641 .arg(month, 6)
642 .arg(day, 6)
643 .arg(hour, 6)
644 .arg(min, 6)
645 .arg(sec, 13, 'f', 7)
646 .arg("GPS", 8)
647 .leftJustified(60)
648 << "TIME OF FIRST OBS\n";
649
[6719]650 if (_version >= 3.0) {
651 if (_phaseShifts.empty()) {
[6815]652 QMap<char, QStringList>::const_iterator it;
653 for (it = _obsTypes.begin(); it != _obsTypes.end(); ++it) {
654 char sys = it.key();
655 double shift = 0.0;
656 foreach (const QString &obstype, it.value()) {
657 if (obstype.left(1).contains('L')) {
[6866]658 *stream << QString("%1%2%3")
[6815]659 .arg(sys, 0)
[6866]660 .arg(obstype, 4)
[6815]661 .arg(shift, 9, 'f', 5)
662 .leftJustified(60)
663 << "SYS / PHASE SHIFT\n";
664 }
665 }
[6719]666 }
667 } else {
[6815]668 QMap<QString, QPair<double, QStringList> >::const_iterator it;
669 QString emptyFillStr;
670 for(it = _phaseShifts.begin(); it!= _phaseShifts.end(); ++it) {
671 QString sys = it.key().left(1);
672 QString obstype = it.key().mid(1);
673 double shift = it.value().first;
[6865]674 QStringList satList = it.value().second;
[6870]675 QString hlp;
676 if (obstype.isEmpty()) {
677 hlp = QString("%1")
678 .arg(sys.toStdString().c_str(), 0);
679 }
680 else {
681 hlp = QString("%1%2%3")
682 .arg(sys.toStdString().c_str(), 0)
683 .arg(obstype, 4)
684 .arg(shift, 9, 'f', 5);
685 }
[6815]686 if (!satList.empty()) {
[6865]687 hlp += QString("%1").arg(satList.size(), 4);
[6815]688 }
689 else {
690 *stream << QString("%1")
691 .arg(hlp, 0)
692 .leftJustified(60)
693 << "SYS / PHASE SHIFT\n";
694 hlp = "";
695 }
696 int ii = 0;
697 QStringList::const_iterator it_s;
698 for (it_s = satList.begin(); it_s != satList.end(); ++it_s) {
699 (hlp.contains(obstype)) ?
[6865]700 emptyFillStr = "": emptyFillStr = " ";
701 hlp += QString("%1").arg(*it_s, 4);
[6815]702 ii++;
703 if (ii % 10 == 0) {
704 *stream << QString("%1%2")
705 .arg(emptyFillStr, 0)
706 .arg(hlp, 0)
707 .leftJustified(60)
708 << "SYS / PHASE SHIFT\n";
709 hlp = "";
710 }
711 }
712 if (hlp.size()) {
[6865]713 (hlp.contains(obstype)) ?
714 emptyFillStr = "": emptyFillStr = " ";
[6815]715 *stream << QString("%1%2")
716 .arg(emptyFillStr, 0)
717 .arg(hlp, 0)
[6719]718 .leftJustified(60)
[6815]719 << "SYS / PHASE SHIFT\n";
720 }
[6719]721 }
722 }
723 }
724
725 if (_version >= 3.0) {
726 QString hlp = "";
[6841]727 QMap<QString, double>::const_iterator it = _gloBiases.begin();
728 while (it != _gloBiases.end()){
[6719]729 hlp += QString("%1%2").arg(it.key(), 4).arg(it.value(), 9, 'f', 3);
730 it++;
731 }
732 *stream << QString("%1")
733 .arg(hlp, 0)
734 .leftJustified(60)
735 << "GLONASS COD/PHS/BIS\n";
736 }
737
738 if (_version >= 3.0) {
739 QString number = QString::number(_gloSlots.size());
740 QString hlp = "";
741 int ii = 0;
742 QMap<t_prn, int>::const_iterator it = _gloSlots.begin();
743 while (it != _gloSlots.end()) {
744 QString prn(it.key().toString().c_str());
745 hlp += QString("%1%2").arg(prn, 4).arg(it.value(), 3);
746 it++;
747 ii++;
748 if (ii % 8 == 0) {
749 *stream << QString("%1%2")
750 .arg(number, 3)
751 .arg(hlp, 0)
752 .leftJustified(60)
753 << "GLONASS SLOT / FRQ #\n";
754 ii = 0;
755 hlp = number = "";
756 }
757 }
758 if (hlp.size() || !_gloSlots.size()) {
759 *stream << QString("%1%2")
760 .arg(number, 3)
761 .arg(hlp, 0)
762 .leftJustified(60)
763 << "GLONASS SLOT / FRQ #\n";
764 }
765 }
766
[4481]767 *stream << QString()
768 .leftJustified(60)
769 << "END OF HEADER\n";
770}
771
[6119]772// Number of Different Systems
773////////////////////////////////////////////////////////////////////////////
774int t_rnxObsHeader::numSys() const {
775 return _obsTypes.size();
776}
777
[7474]778//
[6130]779////////////////////////////////////////////////////////////////////////////
780char t_rnxObsHeader::system(int iSys) const {
781 int iSysLocal = -1;
[6230]782 QMapIterator<char, QStringList> it(_obsTypes);
[6130]783 while (it.hasNext()) {
784 ++iSysLocal;
785 it.next();
786 if (iSysLocal == iSys) {
787 return it.key();
788 }
789 }
790 return ' ';
791}
792
[7474]793//
794////////////////////////////////////////////////////////////////////////////
795QString t_rnxObsHeader::usedSystems(void) const {
796 return _usedSystems;
797}
798
799QStringList t_rnxObsHeader::obsTypes(char sys) const {
800 if (_obsTypes.contains(sys)) {
801 return _obsTypes[sys];
802 }
803 else {
804 return QStringList();
805 }
806}
807
[3716]808// Number of Observation Types (satellite-system specific)
809////////////////////////////////////////////////////////////////////////////
[4480]810int t_rnxObsHeader::nTypes(char sys) const {
[6119]811 if (_obsTypes.contains(sys)) {
812 return _obsTypes[sys].size();
[3716]813 }
814 else {
[6119]815 return 0;
[3716]816 }
817}
818
[6841]819// Number of GLONASS biases
820////////////////////////////////////////////////////////////////////////////
821int t_rnxObsHeader::numGloBiases() const {
822 return _gloBiases.size();
823}
824
[6842]825// Number of GLONASS slots
[6841]826////////////////////////////////////////////////////////////////////////////
827int t_rnxObsHeader::numGloSlots() const {
828 return _gloSlots.size();
829}
830
[3716]831// Observation Type (satellite-system specific)
832////////////////////////////////////////////////////////////////////////////
[6126]833QString t_rnxObsHeader::obsType(char sys, int index, double version) const {
834
835 if (version == 0.0) {
836 version = _version;
837 }
[6119]838 if (_obsTypes.contains(sys)) {
[6126]839 QString origType = _obsTypes[sys].at(index);
840 if (int(version) == int(_version)) {
841 return origType;
842 }
843 else if (int(version) == 2) {
[6192]844 return t_rnxObsFile::type3to2(sys, origType);
[6126]845 }
846 else if (int(version) == 3) {
[6192]847 return t_rnxObsFile::type2to3(sys, origType);
[6126]848 }
[3716]849 }
[6126]850 return "";
[3716]851}
852
[6841]853//
854////////////////////////////////////////////////////////////////////////////
855QStringList t_rnxObsHeader::phaseShifts() const {
856 QStringList strList;
857 QMap<QString, QPair<double, QStringList> >::const_iterator it = _phaseShifts.begin();
858 while (it != _phaseShifts.end()) {
859 strList.append(QString("%1_%2:%3").arg(it.key(), 3).arg(it.value().first, 9, 'f', 3).arg(it.value().second.join("")));
860 it++;
861 }
862 return strList;
863}
864
865//
866////////////////////////////////////////////////////////////////////////////
867QStringList t_rnxObsHeader::gloBiases() const {
868 QStringList strList;
869 QMap<QString, double>::const_iterator it = _gloBiases.begin();
870 while (it != _gloBiases.end()) {
871 strList.append(QString("%1:%2").arg(it.key(), 3).arg(it.value(), 9, 'f', 3));
872 it++;
873 }
874 return strList;
875}
876
877//
878////////////////////////////////////////////////////////////////////////////
879QStringList t_rnxObsHeader::gloSlots() const {
880 QStringList strList;
881 QMap<t_prn, int>::const_iterator it = _gloSlots.begin();
882 while (it != _gloSlots.end()){
883 QString prn(it.key().toString().c_str());
884 strList.append(QString("%1:%2").arg(prn, 3).arg(it.value()));
885 it++;
886 }
887 return strList;
888}
889
[4481]890// Write Observation Types
891////////////////////////////////////////////////////////////////////////////
892QStringList t_rnxObsHeader::obsTypesStrings() const {
893
894 QStringList strList;
895 if (_version < 3.0) {
[6245]896 char sys0 = _usedSystems[0].toAscii();
[4481]897 QString hlp;
[6125]898 QTextStream(&hlp) << QString("%1").arg(_obsTypes[sys0].size(), 6);
899 for (int ii = 0; ii < _obsTypes[sys0].size(); ii++) {
[7474]900 QTextStream(&hlp) << QString("%1").arg(_obsTypes[sys0][ii], 6);
[6125]901 if ((ii+1) % 9 == 0 || ii == _obsTypes[sys0].size()-1) {
[4481]902 strList.append(hlp.leftJustified(60) + "# / TYPES OF OBSERV\n");
903 hlp = QString().leftJustified(6);
904 }
905 }
906 }
907 else {
[6219]908 for (int iSys = 0; iSys < numSys(); iSys++) {
909 char sys = system(iSys);
[4481]910 QString hlp;
[6219]911 QTextStream(&hlp) << QString("%1 %2").arg(sys).arg(nTypes(sys), 3);
912 for (int iType = 0; iType < nTypes(sys); iType++) {
[6221]913 QString type = obsType(sys, iType);
[7474]914 QTextStream(&hlp) << QString(" %1").arg(type, -3);
[6219]915 if ((iType+1) % 13 == 0 || iType == nTypes(sys)-1) {
[4481]916 strList.append(hlp.leftJustified(60) + "SYS / # / OBS TYPES\n");
917 hlp = QString().leftJustified(6);
918 }
919 }
920 }
921 }
922
923 return strList;
924}
925
[3716]926// Constructor
927////////////////////////////////////////////////////////////////////////////
[3843]928t_rnxObsFile::t_rnxObsFile(const QString& fileName, e_inpOut inpOut) {
929 _inpOut = inpOut;
[3716]930 _stream = 0;
931 _flgPowerFail = false;
[3843]932 if (_inpOut == input) {
933 openRead(fileName);
934 }
935 else {
[3845]936 openWrite(fileName);
[3843]937 }
[3716]938}
939
[3845]940// Open for input
[3716]941////////////////////////////////////////////////////////////////////////////
[3843]942void t_rnxObsFile::openRead(const QString& fileName) {
[3718]943
944 _fileName = fileName; expandEnvVar(_fileName);
945 _file = new QFile(_fileName);
946 _file->open(QIODevice::ReadOnly | QIODevice::Text);
947 _stream = new QTextStream();
948 _stream->setDevice(_file);
949
[3716]950 _header.read(_stream);
951
952 // Guess Observation Interval
953 // --------------------------
954 if (_header._interval == 0.0) {
955 bncTime ttPrev;
956 for (int iEpo = 0; iEpo < 10; iEpo++) {
957 const t_rnxEpo* rnxEpo = nextEpoch();
958 if (!rnxEpo) {
[3718]959 throw QString("t_rnxObsFile: not enough epochs");
[3716]960 }
961 if (iEpo > 0) {
962 double dt = rnxEpo->tt - ttPrev;
963 if (_header._interval == 0.0 || dt < _header._interval) {
964 _header._interval = dt;
965 }
966 }
967 ttPrev = rnxEpo->tt;
968 }
[3719]969 _stream->seek(0);
[3716]970 _header.read(_stream);
971 }
[3837]972
973 // Time of first observation
974 // -------------------------
975 if (!_header._startTime.valid()) {
976 const t_rnxEpo* rnxEpo = nextEpoch();
977 if (!rnxEpo) {
978 throw QString("t_rnxObsFile: not enough epochs");
979 }
980 _header._startTime = rnxEpo->tt;
981 _stream->seek(0);
982 _header.read(_stream);
983 }
[3716]984}
985
[3845]986// Open for output
987////////////////////////////////////////////////////////////////////////////
988void t_rnxObsFile::openWrite(const QString& fileName) {
989
990 _fileName = fileName; expandEnvVar(_fileName);
991 _file = new QFile(_fileName);
992 _file->open(QIODevice::WriteOnly | QIODevice::Text);
993 _stream = new QTextStream();
994 _stream->setDevice(_file);
995}
996
[3716]997// Destructor
998////////////////////////////////////////////////////////////////////////////
999t_rnxObsFile::~t_rnxObsFile() {
1000 close();
1001}
1002
1003// Close
1004////////////////////////////////////////////////////////////////////////////
1005void t_rnxObsFile::close() {
1006 delete _stream; _stream = 0;
[3718]1007 delete _file; _file = 0;
[3716]1008}
1009
1010// Handle Special Epoch Flag
1011////////////////////////////////////////////////////////////////////////////
[7474]1012void t_rnxObsFile::handleEpochFlag(int flag, const QString& line,
[4540]1013 bool& headerReRead) {
[3716]1014
[4540]1015 headerReRead = false;
1016
[3716]1017 // Power Failure
1018 // -------------
1019 if (flag == 1) {
1020 _flgPowerFail = true;
1021 }
1022
1023 // Start moving antenna
1024 // --------------------
1025 else if (flag == 2) {
1026 // no action
1027 }
1028
1029 // Re-Read Header
[7474]1030 // --------------
[5468]1031 else if (flag == 3 || flag == 4 || flag == 5) {
[3716]1032 int numLines = 0;
1033 if (version() < 3.0) {
1034 readInt(line, 29, 3, numLines);
1035 }
1036 else {
1037 readInt(line, 32, 3, numLines);
1038 }
[5468]1039 if (flag == 3 || flag == 4) {
1040 _header.read(_stream, numLines);
1041 headerReRead = true;
1042 }
1043 else {
1044 for (int ii = 0; ii < numLines; ii++) {
1045 _stream->readLine();
1046 }
1047 }
[3716]1048 }
1049
1050 // Unhandled Flag
1051 // --------------
1052 else {
[3718]1053 throw QString("t_rnxObsFile: unhandled flag\n" + line);
[3716]1054 }
1055}
1056
1057// Retrieve single Epoch
1058////////////////////////////////////////////////////////////////////////////
[3994]1059t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpoch() {
[3716]1060 _currEpo.clear();
1061 if (version() < 3.0) {
1062 return nextEpochV2();
1063 }
1064 else {
1065 return nextEpochV3();
1066 }
1067}
1068
1069// Retrieve single Epoch (RINEX Version 3)
1070////////////////////////////////////////////////////////////////////////////
[3994]1071t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV3() {
[3716]1072
[3719]1073 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
[3716]1074
[3718]1075 QString line = _stream->readLine();
[3716]1076
[3718]1077 if (line.isEmpty()) {
[3716]1078 continue;
1079 }
1080
1081 int flag = 0;
1082 readInt(line, 31, 1, flag);
1083 if (flag > 0) {
[4540]1084 bool headerReRead = false;
1085 handleEpochFlag(flag, line, headerReRead);
1086 if (headerReRead) {
1087 continue;
1088 }
[3716]1089 }
1090
[3718]1091 QTextStream in(line.mid(1).toAscii(), QIODevice::ReadOnly);
[3716]1092
1093 // Epoch Time
1094 // ----------
1095 int year, month, day, hour, min;
1096 double sec;
1097 in >> year >> month >> day >> hour >> min >> sec;
[3720]1098 _currEpo.tt.set(year, month, day, hour, min, sec);
[3716]1099
1100 // Number of Satellites
1101 // --------------------
1102 int numSat;
1103 readInt(line, 32, 3, numSat);
[7474]1104
[3716]1105 _currEpo.rnxSat.resize(numSat);
1106
1107 // Observations
1108 // ------------
1109 for (int iSat = 0; iSat < numSat; iSat++) {
[3718]1110 line = _stream->readLine();
[6119]1111 t_prn prn; prn.set(line.left(3).toAscii().data());
1112 _currEpo.rnxSat[iSat].prn = prn;
1113 char sys = prn.system();
[3716]1114 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
1115 int pos = 3 + 16*iType;
1116 double obsValue = 0.0;
[7474]1117 int lli = 0;
[3716]1118 int snr = 0;
1119 readDbl(line, pos, 14, obsValue);
1120 readInt(line, pos + 14, 1, lli);
1121 readInt(line, pos + 15, 1, snr);
1122 if (_flgPowerFail) {
1123 lli |= 1;
1124 }
[6119]1125 QString type = obsType(sys, iType);
1126 _currEpo.rnxSat[iSat].obs[type].value = obsValue;
1127 _currEpo.rnxSat[iSat].obs[type].lli = lli;
1128 _currEpo.rnxSat[iSat].obs[type].snr = snr;
[3716]1129 }
1130 }
1131
1132 _flgPowerFail = false;
1133
1134 return &_currEpo;
1135 }
1136
1137 return 0;
1138}
1139
1140// Retrieve single Epoch (RINEX Version 2)
1141////////////////////////////////////////////////////////////////////////////
[3994]1142t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV2() {
[3716]1143
[3719]1144 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
[3716]1145
[3718]1146 QString line = _stream->readLine();
[3716]1147
[3718]1148 if (line.isEmpty()) {
[3716]1149 continue;
1150 }
1151
1152 int flag = 0;
1153 readInt(line, 28, 1, flag);
1154 if (flag > 0) {
[4540]1155 bool headerReRead = false;
1156 handleEpochFlag(flag, line, headerReRead);
1157 if (headerReRead) {
1158 continue;
1159 }
[3716]1160 }
1161
[3718]1162 QTextStream in(line.toAscii(), QIODevice::ReadOnly);
[3716]1163
1164 // Epoch Time
1165 // ----------
1166 int year, month, day, hour, min;
1167 double sec;
1168 in >> year >> month >> day >> hour >> min >> sec;
1169 if (year < 80) {
1170 year += 2000;
1171 }
1172 else if (year < 100) {
1173 year += 1900;
1174 }
[3720]1175 _currEpo.tt.set(year, month, day, hour, min, sec);
[3716]1176
1177 // Number of Satellites
1178 // --------------------
1179 int numSat;
1180 readInt(line, 29, 3, numSat);
[7474]1181
[3716]1182 _currEpo.rnxSat.resize(numSat);
1183
1184 // Read Satellite Numbers
1185 // ----------------------
1186 int pos = 32;
1187 for (int iSat = 0; iSat < numSat; iSat++) {
1188 if (iSat > 0 && iSat % 12 == 0) {
[3718]1189 line = _stream->readLine();
[3716]1190 pos = 32;
1191 }
1192
[6119]1193 char sys = line.toAscii()[pos];
[6258]1194 if (sys == ' ') {
1195 sys = 'G';
1196 }
[6119]1197 int satNum; readInt(line, pos + 1, 2, satNum);
1198 _currEpo.rnxSat[iSat].prn.set(sys, satNum);
[7474]1199
[3716]1200 pos += 3;
1201 }
1202
1203 // Read Observation Records
1204 // ------------------------
1205 for (int iSat = 0; iSat < numSat; iSat++) {
[6119]1206 char sys = _currEpo.rnxSat[iSat].prn.system();
[3718]1207 line = _stream->readLine();
[3716]1208 pos = 0;
[6119]1209 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
[3716]1210 if (iType > 0 && iType % 5 == 0) {
[3718]1211 line = _stream->readLine();
[3716]1212 pos = 0;
1213 }
1214 double obsValue = 0.0;
1215 int lli = 0;
1216 int snr = 0;
1217 readDbl(line, pos, 14, obsValue);
1218 readInt(line, pos + 14, 1, lli);
1219 readInt(line, pos + 15, 1, snr);
1220
1221 if (_flgPowerFail) {
1222 lli |= 1;
1223 }
1224
[6119]1225 QString type = obsType(sys, iType);
1226 _currEpo.rnxSat[iSat].obs[type].value = obsValue;
1227 _currEpo.rnxSat[iSat].obs[type].lli = lli;
1228 _currEpo.rnxSat[iSat].obs[type].snr = snr;
[3716]1229
1230 pos += 16;
1231 }
1232 }
[7474]1233
[3716]1234 _flgPowerFail = false;
1235
1236 return &_currEpo;
1237 }
[7474]1238
[3716]1239 return 0;
1240}
1241
[3845]1242// Write Data Epoch
1243////////////////////////////////////////////////////////////////////////////
1244void t_rnxObsFile::writeEpoch(const t_rnxEpo* epo) {
[6246]1245 if (epo == 0) {
1246 return;
1247 }
1248 t_rnxEpo epoLocal;
1249 epoLocal.tt = epo->tt;
1250 for (unsigned ii = 0; ii < epo->rnxSat.size(); ii++) {
1251 const t_rnxSat& rnxSat = epo->rnxSat[ii];
1252 if (_header._obsTypes[rnxSat.prn.system()].size() > 0) {
[7474]1253 epoLocal.rnxSat.push_back(rnxSat);
[6246]1254 }
1255 }
1256
[3866]1257 if (version() < 3.0) {
[6246]1258 return writeEpochV2(_stream, _header, &epoLocal);
[3866]1259 }
1260 else {
[6246]1261 return writeEpochV3(_stream, _header, &epoLocal);
[3866]1262 }
1263}
[3855]1264
[3866]1265// Write Data Epoch (RINEX Version 2)
1266////////////////////////////////////////////////////////////////////////////
[7474]1267void t_rnxObsFile::writeEpochV2(QTextStream* stream, const t_rnxObsHeader& header,
[6222]1268 const t_rnxEpo* epo) {
[3866]1269
[3855]1270 unsigned year, month, day, hour, min;
1271 double sec;
1272 epo->tt.civil_date(year, month, day);
1273 epo->tt.civil_time(hour, min, sec);
1274
1275 QString dateStr;
[3868]1276 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
[3856]1277 .arg(int(fmod(year, 100)), 2, 10, QChar('0'))
[3868]1278 .arg(month, 2, 10, QChar('0'))
1279 .arg(day, 2, 10, QChar('0'))
1280 .arg(hour, 2, 10, QChar('0'))
1281 .arg(min, 2, 10, QChar('0'))
1282 .arg(sec, 11, 'f', 7);
[3855]1283
[3857]1284 int flag = 0;
[6222]1285 *stream << dateStr << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
[3858]1286 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
[3869]1287 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
[3858]1288 if (iSat > 0 && iSat % 12 == 0) {
[6222]1289 *stream << endl << QString().leftJustified(32);
[3857]1290 }
[6222]1291 *stream << rnxSat.prn.toString().c_str();
[3857]1292 }
[6222]1293 *stream << endl;
[3858]1294 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
[3967]1295
[3858]1296 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
[6119]1297 char sys = rnxSat.prn.system();
[3966]1298
[6222]1299 for (int iTypeV2 = 0; iTypeV2 < header.nTypes(sys); iTypeV2++) {
[6216]1300 if (iTypeV2 > 0 && iTypeV2 % 5 == 0) {
[6222]1301 *stream << endl;
[3967]1302 }
[6222]1303 QString typeV2 = header.obsType(sys, iTypeV2);
[6216]1304 bool found = false;
[7474]1305
[6241]1306 QString preferredAttrib = signalPriorities(sys);
[6231]1307 for (int iPref = 0; iPref < preferredAttrib.length(); iPref++) {
1308 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
1309 while (itObs.hasNext()) {
1310 itObs.next();
1311 const QString& type = itObs.key();
1312 const t_rnxObs& rnxObs = itObs.value();
[6232]1313 if ( preferredAttrib[iPref] == '?' ||
[6241]1314 (type.length() == 2 && preferredAttrib[iPref] == '_' ) ||
[6232]1315 (type.length() == 3 && preferredAttrib[iPref] == type[2]) ) {
1316 if (typeV2 == type3to2(sys, type)) {
1317 found = true;
1318 if (rnxObs.value == 0.0) {
1319 *stream << QString().leftJustified(16);
[6231]1320 }
1321 else {
[6232]1322 *stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
1323 if (rnxObs.lli != 0.0) {
1324 *stream << QString("%1").arg(rnxObs.lli,1);
1325 }
1326 else {
1327 *stream << ' ';
1328 }
1329 if (rnxObs.snr != 0.0) {
1330 *stream << QString("%1").arg(rnxObs.snr,1);
1331 }
1332 else {
1333 *stream << ' ';
1334 }
[6231]1335 }
[6251]1336 goto end_loop_iPref;
[6216]1337 }
[6127]1338 }
[6231]1339 }
[6251]1340 } end_loop_iPref:
[6216]1341 if (!found) {
[6222]1342 *stream << QString().leftJustified(16);
[6216]1343 }
[3858]1344 }
[6222]1345 *stream << endl;
[3858]1346 }
[3845]1347}
[3866]1348
1349// Write Data Epoch (RINEX Version 3)
1350////////////////////////////////////////////////////////////////////////////
[7474]1351void t_rnxObsFile::writeEpochV3(QTextStream* stream, const t_rnxObsHeader& header,
[6222]1352 const t_rnxEpo* epo) {
[3866]1353
1354 unsigned year, month, day, hour, min;
1355 double sec;
1356 epo->tt.civil_date(year, month, day);
1357 epo->tt.civil_time(hour, min, sec);
1358
[3867]1359 QString dateStr;
[3868]1360 QTextStream(&dateStr) << QString("> %1 %2 %3 %4 %5%6")
[7478]1361 .arg(year, 4)
1362 .arg(month, 2, 10, QChar('0'))
1363 .arg(day, 2, 10, QChar('0'))
1364 .arg(hour, 2, 10, QChar('0'))
1365 .arg(min, 2, 10, QChar('0'))
1366 .arg(sec, 11, 'f', 7);
[3866]1367
[3867]1368 int flag = 0;
[6222]1369 *stream << dateStr << QString("%1%2\n").arg(flag, 3).arg(epo->rnxSat.size(), 3);
[3867]1370
[3869]1371 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
[6588]1372 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
[7478]1373 char sys = rnxSat.prn.system();
[3964]1374
[6585]1375 const t_rnxObs* hlp[header.nTypes(sys)];
[6222]1376 for (int iTypeV3 = 0; iTypeV3 < header.nTypes(sys); iTypeV3++) {
[6585]1377 hlp[iTypeV3] = 0;
[6222]1378 QString typeV3 = header.obsType(sys, iTypeV3);
[6220]1379 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
[6586]1380
1381 // Exact match
1382 // -----------
[6220]1383 while (itObs.hasNext()) {
1384 itObs.next();
[7478]1385 const QString& type = itObs.key();
[6220]1386 const t_rnxObs& rnxObs = itObs.value();
[6586]1387 if (typeV3 == type2to3(sys, type) && rnxObs.value != 0.0) {
[6585]1388 hlp[iTypeV3] = &itObs.value();
[3979]1389 }
[3869]1390 }
[6586]1391
1392 // Non-Exact match
1393 // ---------------
1394 itObs.toFront();
1395 while (itObs.hasNext()) {
1396 itObs.next();
[7478]1397 const QString& type = itObs.key();
[6586]1398 const t_rnxObs& rnxObs = itObs.value();
1399 if (hlp[iTypeV3] == 0 && typeV3 == type2to3(sys, type).left(2) && rnxObs.value != 0.0) {
1400 hlp[iTypeV3] = &itObs.value();
1401 }
1402 }
[6585]1403 }
1404
[7478]1405 if (header.nTypes(sys)) {
1406 *stream << rnxSat.prn.toString().c_str();
1407 for (int iTypeV3 = 0; iTypeV3 < header.nTypes(sys); iTypeV3++) {
1408 const t_rnxObs* rnxObs = hlp[iTypeV3];
1409 if (rnxObs == 0) {
1410 *stream << QString().leftJustified(16);
[6585]1411 }
1412 else {
[7478]1413 *stream << QString("%1").arg(rnxObs->value, 14, 'f', 3);
1414 if (rnxObs->lli != 0.0) {
1415 *stream << QString("%1").arg(rnxObs->lli, 1);
1416 }
1417 else {
1418 *stream << ' ';
1419 }
1420 if (rnxObs->snr != 0.0) {
1421 *stream << QString("%1").arg(rnxObs->snr, 1);
1422 }
1423 else {
1424 *stream << ' ';
1425 }
[6585]1426 }
1427 }
[7478]1428 *stream << endl;
[3869]1429 }
1430 }
[3866]1431}
[3956]1432
1433// Translate Observation Type v2 --> v3
1434////////////////////////////////////////////////////////////////////////////
[6193]1435QString t_rnxObsFile::type2to3(char sys, const QString& typeV2) {
[6147]1436 if (typeV2 == "P1") {
[6193]1437 return (sys == 'G') ? "C1W" : "C1P";
[3956]1438 }
[6147]1439 else if (typeV2 == "P2") {
[6193]1440 return (sys == 'G') ? "C2W" : "C2P";
[3956]1441 }
[6147]1442 return typeV2;
[3956]1443}
[3962]1444
1445// Translate Observation Type v3 --> v2
1446////////////////////////////////////////////////////////////////////////////
[6192]1447QString t_rnxObsFile::type3to2(char /* sys */, const QString& typeV3) {
[6193]1448 if (typeV3 == "C1P" || typeV3 == "C1W") {
[3962]1449 return "P1";
1450 }
[6193]1451 else if (typeV3 == "C2P" || typeV3 == "C2W") {
[3962]1452 return "P2";
1453 }
[6147]1454 return typeV3.left(2);
[3962]1455}
[4053]1456
[5883]1457// Set Observations from RINEX File
1458////////////////////////////////////////////////////////////////////////////
[7474]1459void t_rnxObsFile::setObsFromRnx(const t_rnxObsFile* rnxObsFile, const t_rnxObsFile::t_rnxEpo* epo,
[6137]1460 const t_rnxObsFile::t_rnxSat& rnxSat, t_satObs& obs) {
1461 obs._staID = rnxObsFile->markerName().toAscii().constData();
1462 obs._prn = rnxSat.prn;
1463 obs._time = epo->tt;
[5883]1464
[6137]1465 char sys = rnxSat.prn.system();
[5883]1466
[6259]1467 QChar addToL2;
[6137]1468 for (int iType = 0; iType < rnxObsFile->nTypes(sys); iType++) {
[6253]1469 QString type = rnxObsFile->obsType(sys, iType);
1470 QString typeV3 = rnxObsFile->obsType(sys, iType, 3.0); // may or may not differ from type
[6259]1471 if (rnxSat.obs.contains(type) && rnxSat.obs[type].value != 0.0) {
1472 if (type == "P2" && typeV3.length() > 2) {
1473 addToL2 = typeV3[2];
1474 break;
1475 }
1476 }
1477 }
1478
1479 for (int iType = 0; iType < rnxObsFile->nTypes(sys); iType++) {
1480 QString type = rnxObsFile->obsType(sys, iType);
1481 QString typeV3 = rnxObsFile->obsType(sys, iType, 3.0); // may or may not differ from type
1482 if (type == "L2") {
1483 typeV3 += addToL2;
1484 }
[6119]1485 if (rnxSat.obs.contains(type)) {
1486 const t_rnxObs& rnxObs = rnxSat.obs[type];
[6188]1487 if (rnxObs.value != 0.0) {
[6253]1488 string type2ch(typeV3.mid(1).toAscii().data());
[7474]1489
[6188]1490 t_frqObs* frqObs = 0;
1491 for (unsigned iFrq = 0; iFrq < obs._obs.size(); iFrq++) {
1492 if (obs._obs[iFrq]->_rnxType2ch == type2ch) {
1493 frqObs = obs._obs[iFrq];
1494 break;
1495 }
1496 }
1497 if (frqObs == 0) {
1498 frqObs = new t_frqObs;
1499 frqObs->_rnxType2ch = type2ch;
1500 obs._obs.push_back(frqObs);
1501 }
[7474]1502
[6253]1503 switch( typeV3.toAscii().data()[0] ) {
[6188]1504 case 'C':
1505 frqObs->_codeValid = true;
1506 frqObs->_code = rnxObs.value;
[6137]1507 break;
[6188]1508 case 'L':
1509 frqObs->_phaseValid = true;
1510 frqObs->_phase = rnxObs.value;
1511 frqObs->_slip = (rnxObs.lli & 1);
1512 break;
1513 case 'D':
1514 frqObs->_dopplerValid = true;
1515 frqObs->_doppler = rnxObs.value;
1516 break;
1517 case 'S':
1518 frqObs->_snrValid = true;
1519 frqObs->_snr = rnxObs.value;
1520 break;
[6137]1521 }
[6260]1522
1523 // Handle old-fashioned SNR values
1524 // -------------------------------
1525 if (rnxObs.snr != 0 && !frqObs->_snrValid) {
1526 frqObs->_snrValid = true;
[6263]1527 frqObs->_snr = rnxObs.snr * 6.0 + 2.5;
[6260]1528 }
[6119]1529 }
[5883]1530 }
[6119]1531 }
1532}
1533
[6241]1534// Tracking Mode Priorities
1535////////////////////////////////////////////////////////////////////////////
1536QString t_rnxObsFile::signalPriorities(char sys) {
[6242]1537
1538 bncSettings settings;
[6675]1539
1540 QStringList priorList;
1541 QString reqcAction = settings.value("reqcAction").toString();
1542
1543 // Priorities in Edit/Concatenate (post processing) mode
1544 // ---------------------------------------------------
1545 if (reqcAction == "Edit/Concatenate") {
1546 priorList = settings.value("reqcV2Priority").toString().split(" ", QString::SkipEmptyParts);
1547 }
1548
1549 // Priorities in real-time mode
1550 // ----------------------------
1551 else {
1552 priorList = settings.value("rnxV2Priority").toString().split(" ", QString::SkipEmptyParts);
1553 }
1554
[6243]1555 if (priorList.empty()) {
1556 priorList << "CWPX_?";
1557 }
[6242]1558
1559 QString result;
1560 for (int ii = 0; ii < priorList.size(); ii++) {
1561 if (priorList[ii].indexOf(":") != -1) {
1562 QStringList hlp = priorList[ii].split(":", QString::SkipEmptyParts);
1563 if (hlp.size() == 2 && hlp[0].length() == 1 && hlp[0][0] == sys) {
1564 result = hlp[1];
1565 break;
1566 }
1567 }
1568 else {
1569 result = priorList[ii];
1570 }
1571 }
1572
1573 return result;
[6241]1574}
Note: See TracBrowser for help on using the repository browser.