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

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

minor simplification of the last changes

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