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

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

minor changes regarding obs types

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