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

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

minor changes

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