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

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

minor changes to remove duplicates in rinex header comments

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