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

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

bug fixed in RINEX v2.11 header

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