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

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

minor changes ragarding rinex obs file writing with incomplete skl file

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