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

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