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

Last change on this file since 7474 was 7474, checked in by stuerze, 9 years ago

in case of RINEX3 to RINEX 2 conversion now some comment lines are written into the RINEX header

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