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

Last change on this file since 8558 was 8407, checked in by stuerze, 6 years ago

updated RINEX obs codes

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