source: ntrip/branches/BNC_2.12/src/rinex/rnxobsfile.cpp@ 8286

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

minor changes

File size: 48.6 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() {
[8167]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") {
[3718]94 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
[3716]95 in >> _version;
96 }
97 else if (key == "MARKER NAME") {
98 _markerName = value;
99 }
[6941]100 else if (key == "MARKER TYPE") {
101 _markerType = value;
102 }
[3930]103 else if (key == "MARKER NUMBER") {
104 _markerNumber = line.mid(0,20).trimmed();
105 }
[3716]106 else if (key == "ANT # / TYPE") {
[3930]107 _antennaNumber = line.mid( 0,20).trimmed();
108 _antennaName = line.mid(20,20).trimmed();
[3716]109 }
[3930]110 else if (key == "OBSERVER / AGENCY") {
111 _observer = line.mid( 0,20).trimmed();
112 _agency = line.mid(20,40).trimmed();
113 }
114 else if (key == "REC # / TYPE / VERS") {
115 _receiverNumber = line.mid( 0,20).trimmed();
116 _receiverType = line.mid(20,20).trimmed();
117 _receiverVersion = line.mid(40,20).trimmed();
118 }
[3716]119 else if (key == "INTERVAL") {
[3718]120 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
[3716]121 in >> _interval;
122 }
[4494]123 else if (key == "COMMENT") {
124 _comments << line.mid(0,60).trimmed();
125 }
[3716]126 else if (key == "WAVELENGTH FACT L1/2") {
[3718]127 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
[3716]128 int wlFactL1 = 0;
129 int wlFactL2 = 0;
130 int numSat = 0;
131 in >> wlFactL1 >> wlFactL2 >> numSat;
132 if (numSat == 0) {
[5742]133 for (unsigned iPrn = 1; iPrn <= t_prn::MAXPRN_GPS; iPrn++) {
[3716]134 _wlFactorsL1[iPrn] = wlFactL1;
135 _wlFactorsL2[iPrn] = wlFactL2;
136 }
137 }
138 else {
139 for (int ii = 0; ii < numSat; ii++) {
[3718]140 QString prn; in >> prn;
[3716]141 if (prn[0] == 'G') {
142 int iPrn;
143 readInt(prn, 1, 2, iPrn);
144 _wlFactorsL1[iPrn] = wlFactL1;
145 _wlFactorsL2[iPrn] = wlFactL2;
146 }
147 }
148 }
149 }
150 else if (key == "APPROX POSITION XYZ") {
[3718]151 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
[3716]152 in >> _xyz[0] >> _xyz[1] >> _xyz[2];
153 }
154 else if (key == "ANTENNA: DELTA H/E/N") {
[3718]155 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
[3716]156 in >> _antNEU[2] >> _antNEU[1] >> _antNEU[0];
157 }
158 else if (key == "ANTENNA: DELTA X/Y/Z") {
[3718]159 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
[3716]160 in >> _antXYZ[0] >> _antXYZ[1] >> _antXYZ[2];
161 }
162 else if (key == "ANTENNA: B.SIGHT XYZ") {
[3718]163 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
[3716]164 in >> _antBSG[0] >> _antBSG[1] >> _antBSG[2];
165 }
166 else if (key == "# / TYPES OF OBSERV") {
[6223]167 if (_version == 0.0) {
[8286]168 _version = defaultRnxObsVersion2;
[6223]169 }
[3864]170 QTextStream* in = new QTextStream(value.toAscii(), QIODevice::ReadOnly);
[3716]171 int nTypes;
[3864]172 *in >> nTypes;
[6245]173 char sys0 = _usedSystems[0].toAscii();
[6125]174 _obsTypes[sys0].clear();
[3716]175 for (int ii = 0; ii < nTypes; ii++) {
[3864]176 if (ii > 0 && ii % 9 == 0) {
177 line = stream->readLine(); ++numLines;
178 delete in;
[4152]179 in = new QTextStream(line.left(60).toAscii(), QIODevice::ReadOnly);
[3864]180 }
[3718]181 QString hlp;
[3864]182 *in >> hlp;
[6125]183 _obsTypes[sys0].append(hlp);
[3716]184 }
[6245]185 for (int ii = 1; ii < _usedSystems.length(); ii++) {
186 char sysI = _usedSystems[ii].toAscii();
[6125]187 _obsTypes[sysI] = _obsTypes[sys0];
[6119]188 }
[3716]189 }
190 else if (key == "SYS / # / OBS TYPES") {
[6223]191 if (_version == 0.0) {
[8286]192 _version = defaultRnxObsVersion3;
[6223]193 }
[3718]194 QTextStream* in = new QTextStream(value.toAscii(), QIODevice::ReadOnly);
[3716]195 char sys;
196 int nTypes;
197 *in >> sys >> nTypes;
[6119]198 _obsTypes[sys].clear();
[3716]199 for (int ii = 0; ii < nTypes; ii++) {
200 if (ii > 0 && ii % 13 == 0) {
[3718]201 line = stream->readLine(); ++numLines;
[3716]202 delete in;
[3718]203 in = new QTextStream(line.toAscii(), QIODevice::ReadOnly);
[3716]204 }
[3718]205 QString hlp;
[3716]206 *in >> hlp;
[6817]207 if (sys == 'C' && _version < 3.03) {
[6816]208 hlp.replace('1', '2');
209 }
[6119]210 _obsTypes[sys].push_back(hlp);
[3716]211 }
212 delete in;
213 }
[3837]214 else if (key == "TIME OF FIRST OBS") {
215 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
216 int year, month, day, hour, min;
217 double sec;
218 in >> year >> month >> day >> hour >> min >> sec;
219 _startTime.set(year, month, day, hour, min, sec);
220 }
[6719]221 else if (key == "SYS / PHASE SHIFT"){
[6815]222 QTextStream* in = new QTextStream(value.toAscii(), QIODevice::ReadOnly);
223 char sys;
224 QString obstype;
225 double shift;
226 int satnum = 0;
227 QStringList satList;
228 QString sat;
229 *in >> sys >> obstype >> shift >> satnum;
230 if (obstype.size()) {
231 for (int ii = 0; ii < satnum; ii++) {
232 if (ii > 0 && ii % 10 == 0) {
233 line = stream->readLine(); ++numLines;
234 delete in;
235 in = new QTextStream(line.left(60).toAscii(), QIODevice::ReadOnly);
236 }
237 *in >> sat;
238 satList.append(sat);
239 }
240 delete in;
241 }
[6871]242 _phaseShifts.insert(sys+obstype, QPair<double, QStringList>(shift, satList));
[6719]243 }
244 else if (key == "GLONASS COD/PHS/BIS"){
245 QTextStream in(value.toAscii(), QIODevice::ReadOnly);
246 for (int ii = 0; ii < 4; ii++) {
247 QString type;
248 double value;
249 in >> type >> value;
250 if (type.size())
[6841]251 _gloBiases[type] = value;
[6719]252 }
253 }
254 else if (key == "GLONASS SLOT / FRQ #") {
255 QTextStream* in = new QTextStream(value.toAscii(), QIODevice::ReadOnly);
256 int nSlots = 0;
257 *in >> nSlots;
258 for (int ii = 0; ii < nSlots; ii++) {
259 if (ii > 0 && ii % 8 == 0) {
260 line = stream->readLine(); ++numLines;
261 delete in;
262 in = new QTextStream(line.left(60).toAscii(), QIODevice::ReadOnly);
263 }
264 QString sat;
265 int slot;
266 *in >> sat >> slot;
267 t_prn prn;
268 prn.set(sat.toStdString());
269 if(sat.size())
270 _gloSlots[prn] = slot;
271 }
272 delete in;
273 }
[3716]274 if (maxLines > 0 && numLines == maxLines) {
275 break;
276 }
277 }
278
[6719]279 // set default observation types if empty in input file
280 // ----------------------------------------------------
[6704]281 if (_obsTypes.empty()) {
[7665]282 if (!_writeRinexOnlyWithSklObsTypes) {
283 setDefault(_markerName, _version);
284 }
285 else {
286 return failure;
287 }
[6704]288 }
289
[6245]290 // Systems used
291 // ------------
292 _usedSystems.clear();
293 QMapIterator<char, QStringList> it(_obsTypes);
294 while (it.hasNext()) {
295 it.next();
296 _usedSystems += QChar(it.key());
297 }
298
[3716]299 return success;
300}
301
[6222]302// Set Default Header
303////////////////////////////////////////////////////////////////////////////
304void t_rnxObsHeader::setDefault(const QString& markerName, int version) {
305
306 _markerName = markerName;
307
308 if (version <= 2) {
[8286]309 _version = defaultRnxObsVersion2;
[6222]310 }
311 else {
[8286]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"
[6222]347 << "C2P" << "L2P" << "S2P";
[7474]348
[8036]349 _obsTypes['E'] << "C1X" << "L1X" << "S1X"
350 << "C5X" << "L5X" << "S5X"
351 << "C7X" << "L7X" << "S7X"
352 << "C8X" << "L8X" << "S8X";
[7474]353
[6815]354 _obsTypes['S'] << "C1C" << "L1C" << "S1C"
355 << "C5I" << "L5I" << "S5I"
356 << "C5Q" << "L5Q" << "S5Q";
[7474]357
[6815]358 _obsTypes['C'] << "C2I" << "L2I" << "S2I"
359 << "C6I" << "L6I" << "S6I"
360 << "C7I" << "L7I" << "S7I";
[8286]361
[8149]362 _obsTypes['I'] << "C5A" << "L5A" << "S5A"
363 << "C9A" << "L9A" << "S9A";
[6222]364 }
365}
366
367// Copy header
368////////////////////////////////////////////////////////////////////////////
369void t_rnxObsHeader::set(const t_rnxObsHeader& header, int version,
[6841]370 const QStringList* useObsTypes,
371 const QStringList* phaseShifts,
372 const QStringList* gloBiases,
373 const QStringList* gloSlots) {
[6222]374
375 if (version <= 2) {
[8286]376 _version = defaultRnxObsVersion2;
[6222]377 }
378 else {
[8286]379 _version = defaultRnxObsVersion3;
[6222]380 }
[7474]381 _interval = header._interval;
382 _antennaNumber = header._antennaNumber;
383 _antennaName = header._antennaName;
384 _markerName = header._markerName;
385 _markerNumber = header._markerNumber;
[6943]386 _markerType = header._markerType;
[7474]387 _antNEU = header._antNEU;
388 _antXYZ = header._antXYZ;
389 _antBSG = header._antBSG;
390 _xyz = header._xyz;
391 _observer = header._observer;
392 _agency = header._agency;
393 _receiverNumber = header._receiverNumber;
394 _receiverType = header._receiverType;
[6222]395 _receiverVersion = header._receiverVersion;
[7474]396 _startTime = header._startTime;
[7803]397 _usedSystems = header._usedSystems;
[6224]398 _comments = header._comments;
[7808]399 _comments.removeDuplicates();
[6841]400
[6222]401 for (unsigned iPrn = 1; iPrn <= t_prn::MAXPRN_GPS; iPrn++) {
[7474]402 _wlFactorsL1[iPrn] = header._wlFactorsL1[iPrn];
403 _wlFactorsL2[iPrn] = header._wlFactorsL2[iPrn];
[6222]404 }
405
406 // Set observation types
407 // ---------------------
408 _obsTypes.clear();
409 if (!useObsTypes || useObsTypes->size() == 0) {
410 if (int(_version) == int(header._version)) {
411 _obsTypes = header._obsTypes;
412 }
413 else {
[6250]414 if (_version >= 3.0) {
[8113]415 _comments << "Default set of observation types used";
416 _comments.removeDuplicates();
417 _obsTypes['G'] << "C1C" << "L1C" << "S1C"
418 << "C1W" << "L1W" << "S1W"
419 << "C2X" << "L2X" << "S2X"
420 << "C2W" << "L2W" << "S2W"
421 << "C5X" << "L5X" << "S5X";
422
423 _obsTypes['J'] << "C1C" << "L1C" << "S1C"
424 << "C1S" << "L1S" << "S1S"
425 << "C1L" << "L1L" << "S1L"
426 << "C1X" << "L1X" << "S1X"
427 << "C2S" << "L2S" << "S2S"
428 << "C2L" << "L2L" << "S2L"
429 << "C2X" << "L2X" << "S2X"
430 << "C5X" << "L5X" << "S5X";
431
432 _obsTypes['R'] << "C1C" << "L1C" << "S1C"
433 << "C1P" << "L1P" << "S1P"
434 << "C2C" << "L2C" << "S2C"
435 << "C2P" << "L2P" << "S2P";
436
437 _obsTypes['E'] << "C1X" << "L1X" << "S1X"
438 << "C5X" << "L5X" << "S5X"
439 << "C7X" << "L7X" << "S7X"
440 << "C8X" << "L8X" << "S8X";
441
442 _obsTypes['S'] << "C1C" << "L1C" << "S1C"
443 << "C5I" << "L5I" << "S5I"
444 << "C5Q" << "L5Q" << "S5Q";
445
446 _obsTypes['C'] << "C2I" << "L2I" << "S2I"
447 << "C6I" << "L6I" << "S6I"
448 << "C7I" << "L7I" << "S7I";
[8286]449
[8167]450 _obsTypes['I'] << "C5A" << "L5A" << "S5A"
451 << "C9A" << "L9A" << "S9A";
[6250]452 }
[8113]453
[6250]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++) {
460 char thisSys = _usedSystems[jSys].toAscii();
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) {
476 char sys = hlp[0][0].toAscii();
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++) {
484 char sys = _usedSystems[iSys].toAscii();
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++) {
[6248]495 char sys = _usedSystems[iSys].toAscii();
[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
[7895]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) {
[6245]939 char sys0 = _usedSystems[0].toAscii();
[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
[3718]1134 QTextStream in(line.mid(1).toAscii(), 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();
[6119]1154 t_prn prn; prn.set(line.left(3).toAscii().data());
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
[3718]1205 QTextStream in(line.toAscii(), 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
[6119]1236 char sys = line.toAscii()[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}
1307// Write Data Epoch (RINEX Version 2)
1308////////////////////////////////////////////////////////////////////////////
[7474]1309void t_rnxObsFile::writeEpochV2(QTextStream* stream, const t_rnxObsHeader& header,
[6222]1310 const t_rnxEpo* epo) {
[3866]1311
[3855]1312 unsigned year, month, day, hour, min;
1313 double sec;
1314 epo->tt.civil_date(year, month, day);
1315 epo->tt.civil_time(hour, min, sec);
1316
1317 QString dateStr;
[3868]1318 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
[3856]1319 .arg(int(fmod(year, 100)), 2, 10, QChar('0'))
[3868]1320 .arg(month, 2, 10, QChar('0'))
1321 .arg(day, 2, 10, QChar('0'))
1322 .arg(hour, 2, 10, QChar('0'))
1323 .arg(min, 2, 10, QChar('0'))
1324 .arg(sec, 11, 'f', 7);
[3855]1325
[3857]1326 int flag = 0;
[6222]1327 *stream << dateStr << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
[3858]1328 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
[3869]1329 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
[3858]1330 if (iSat > 0 && iSat % 12 == 0) {
[6222]1331 *stream << endl << QString().leftJustified(32);
[3857]1332 }
[6222]1333 *stream << rnxSat.prn.toString().c_str();
[3857]1334 }
[6222]1335 *stream << endl;
[7985]1336
[3858]1337 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
1338 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
[6119]1339 char sys = rnxSat.prn.system();
[6222]1340 for (int iTypeV2 = 0; iTypeV2 < header.nTypes(sys); iTypeV2++) {
[6216]1341 if (iTypeV2 > 0 && iTypeV2 % 5 == 0) {
[6222]1342 *stream << endl;
[3967]1343 }
[6222]1344 QString typeV2 = header.obsType(sys, iTypeV2);
[6216]1345 bool found = false;
[7983]1346 QStringList preferredAttribList = signalPriorities(sys);
1347 QString preferredAttrib;
1348 for (int ii = 0; ii < preferredAttribList.size(); ii++) {
1349 if (preferredAttribList[ii].indexOf("&") != -1) {
1350 QStringList hlp = preferredAttribList[ii].split("&", QString::SkipEmptyParts);
1351 if (hlp.size() == 2 && hlp[0].contains(typeV2[1])) {
1352 preferredAttrib = hlp[1];
1353 }
1354 }
1355 else {
1356 preferredAttrib = preferredAttribList[ii];
1357 }
1358 }
[7474]1359
[7985]1360 for (int iPref = 0; iPref < preferredAttrib.size(); iPref++) {
[6231]1361 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
1362 while (itObs.hasNext()) {
1363 itObs.next();
1364 const QString& type = itObs.key();
1365 const t_rnxObs& rnxObs = itObs.value();
[6232]1366 if ( preferredAttrib[iPref] == '?' ||
[6241]1367 (type.length() == 2 && preferredAttrib[iPref] == '_' ) ||
[6232]1368 (type.length() == 3 && preferredAttrib[iPref] == type[2]) ) {
1369 if (typeV2 == type3to2(sys, type)) {
1370 found = true;
1371 if (rnxObs.value == 0.0) {
1372 *stream << QString().leftJustified(16);
[6231]1373 }
1374 else {
[6232]1375 *stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
1376 if (rnxObs.lli != 0.0) {
1377 *stream << QString("%1").arg(rnxObs.lli,1);
1378 }
1379 else {
1380 *stream << ' ';
1381 }
1382 if (rnxObs.snr != 0.0) {
1383 *stream << QString("%1").arg(rnxObs.snr,1);
1384 }
1385 else {
1386 *stream << ' ';
1387 }
[6231]1388 }
[6251]1389 goto end_loop_iPref;
[6216]1390 }
[6127]1391 }
[6231]1392 }
[6251]1393 } end_loop_iPref:
[6216]1394 if (!found) {
[6222]1395 *stream << QString().leftJustified(16);
[6216]1396 }
[3858]1397 }
[6222]1398 *stream << endl;
[3858]1399 }
[3845]1400}
[3866]1401
[7983]1402
[3866]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) {
1515 obs._staID = rnxObsFile->markerName().toAscii().constData();
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) {
[6253]1542 string type2ch(typeV3.mid(1).toAscii().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
[6253]1557 switch( typeV3.toAscii().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////////////////////////////////////////////////////////////////////////////
[7983]1590QStringList t_rnxObsFile::signalPriorities(char sys) {
[6242]1591
1592 bncSettings settings;
[7985]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") {
[7983]1600 priorList = settings.value("reqcV2Priority").toString().split(" ", QString::SkipEmptyParts);
[6675]1601 }
1602
1603 // Priorities in real-time mode
1604 // ----------------------------
1605 else {
[7983]1606 priorList = settings.value("rnxV2Priority").toString().split(" ", QString::SkipEmptyParts);
[6675]1607 }
1608
[7983]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) {
[7983]1614 result.append(hlp[1]);
[6242]1615 }
1616 }
1617 else {
[7983]1618 result.append(priorList[ii]);
[6242]1619 }
1620 }
1621
[7983]1622 if (result.empty()) {
1623 switch (sys) {
1624 case 'G':
[7987]1625 result.append("12&PWCSLXYN");
1626 result.append("5&IQX");
[7983]1627 break;
1628 case 'R':
[7987]1629 result.append("12&PC");
1630 result.append("3&IQX");
[7983]1631 break;
1632 case 'E':
[7987]1633 result.append("16&BCX");
1634 result.append("578&IQX");
[7983]1635 break;
1636 case 'J':
[7987]1637 result.append("1&SLXCZ");
1638 result.append("26&SLX");
1639 result.append("5&IQX");
[7983]1640 break;
1641 case 'C':
[7987]1642 result.append("IQX");
[7983]1643 break;
1644 case 'I':
[7987]1645 result.append("ABCX");
[7983]1646 break;
1647 case 'S':
[7987]1648 result.append("1&C");
1649 result.append("5&IQX");
[7983]1650 break;
1651 }
1652 }
[6242]1653 return result;
[6241]1654}
Note: See TracBrowser for help on using the repository browser.