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

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

now empty phase shift lines are considered as well during RNX concatenation and editing

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