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

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

updated default observation types for Galileo

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