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

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

minor changes

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