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

Last change on this file since 8642 was 8642, checked in by stuerze, 5 years ago

minor changes

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