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

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