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

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

minor changes regarding rinexV3 writing

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