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

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

consideration of obs header etries for phase shifts, GLONASS slots and GLONASS biases during merging of RINEX files

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