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

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

minor format changes are added to write phase shifts

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