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

Last change on this file since 8718 was 8718, checked in by stuerze, 5 years ago

minor changes

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