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

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

minor additions regarding default GLONASS obs types

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