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

Last change on this file since 9640 was 9640, checked in by stuerze, 2 years ago

bug fixed in phase bias merging

File size: 50.1 KB
Line 
1// Part of BNC, a utility for retrieving decoding and
2// converting GNSS data streams from NTRIP broadcasters.
3//
4// Copyright (C) 2007
5// German Federal Agency for Cartography and Geodesy (BKG)
6// http://www.bkg.bund.de
7// Czech Technical University Prague, Department of Geodesy
8// http://www.fsv.cvut.cz
9//
10// Email: euref-ip@bkg.bund.de
11//
12// This program is free software; you can redistribute it and/or
13// modify it under the terms of the GNU General Public License
14// as published by the Free Software Foundation, version 2.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25/* -------------------------------------------------------------------------
26 * BKG NTRIP Client
27 * -------------------------------------------------------------------------
28 *
29 * Class: t_rnxObsFile
30 *
31 * Purpose: Reads RINEX Observation File
32 *
33 * Author: L. Mervart
34 *
35 * Created: 24-Jan-2012
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <iostream>
42#include <iomanip>
43#include <sstream>
44#include "rnxobsfile.h"
45#include "bncutils.h"
46#include "bnccore.h"
47#include "bncsettings.h"
48
49using namespace std;
50
51// Constructor
52////////////////////////////////////////////////////////////////////////////
53t_rnxObsHeader::t_rnxObsHeader() {
54 _usedSystems = "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 if (satStr.size()) {
541 hlp1 = satStr.split(" ");
542 }
543 QStringList &satList = hlp1;
544 QMap<QString, QPair<double, QStringList> >::iterator it = _phaseShifts.find(type);
545 if ( it != _phaseShifts.end()) {
546 it.value().second.append(satList);
547 it.value().second.removeDuplicates();
548 }
549 else {
550 _phaseShifts.insert(type, QPair<double, QStringList>(shift, satList));
551 }
552 }
553 }
554 // set GLONASS biases
555 if (!gloBiases || gloBiases->empty()) {
556 _gloBiases = header._gloBiases;
557 }
558 else {
559 foreach (const QString &str, *gloBiases) {
560 QStringList hlp = str.split(":", QString::SkipEmptyParts);
561 QString type = hlp.first();;
562 double value = hlp.last().toDouble();
563 if (type.size())
564 _gloBiases[type] = value;
565 }
566 }
567 // set GLONASS slots
568 if (!gloSlots || gloSlots->empty()) {
569 _gloSlots = header._gloSlots;
570 }
571 else {
572 foreach (const QString &str, *gloSlots) {
573 QStringList hlp = str.split(":", QString::SkipEmptyParts);
574 QString sat = hlp.first();
575 int slot = hlp.last().toInt();
576 t_prn prn;
577 prn.set(sat.toStdString());
578 if(sat.size())
579 _gloSlots[prn] = slot;
580 }
581 }
582 }
583}
584
585// Write Header
586////////////////////////////////////////////////////////////////////////////
587void t_rnxObsHeader::write(QTextStream* stream,
588 const QMap<QString, QString>* txtMap) const {
589
590 QStringList newComments;
591 QString runBy = BNC_CORE->userName();
592
593 if (txtMap) {
594 QMapIterator<QString, QString> it(*txtMap);
595 while (it.hasNext()) {
596 it.next();
597 if (it.key() == "RUN BY") {
598 runBy = it.value();
599 }
600 else if ((it.key().indexOf("COMMENT")) != -1) {
601 newComments += it.value().split("\\n", QString::SkipEmptyParts);
602 }
603 }
604 newComments.removeDuplicates();
605 }
606
607 *stream << QString("%1 OBSERVATION DATA M")
608 .arg(_version, 9, 'f', 2)
609 .leftJustified(60)
610 << "RINEX VERSION / TYPE\n";
611
612 const QString fmtDate = (_version < 3.0) ? "dd-MMM-yy hh:mm"
613 : "yyyyMMdd hhmmss UTC";
614 *stream << QString("%1%2%3")
615 .arg(BNC_CORE->pgmName(), -20)
616 .arg(runBy.trimmed().left(20), -20)
617 .arg(QDateTime::currentDateTime().toUTC().toString(fmtDate), -20)
618 .leftJustified(60)
619 << "PGM / RUN BY / DATE\n";
620
621 QStringListIterator itCmnt(_comments + newComments);
622 while (itCmnt.hasNext()) {
623 *stream << itCmnt.next().trimmed().left(60).leftJustified(60) << "COMMENT\n";
624 }
625 QString markerName = _markerName.left(9);
626 if (_version < 3.0) {
627 markerName = _markerName.left(4);
628 }
629 *stream << QString("%1")
630 .arg(markerName, -60)
631 .leftJustified(60)
632 << "MARKER NAME\n";
633
634
635 if (!_markerNumber.isEmpty()) {
636 *stream << QString("%1")
637 .arg(_markerNumber, -20)
638 .leftJustified(60)
639 << "MARKER NUMBER\n";
640 }
641
642 if (_version >= 3.0) {
643 *stream << QString("%1")
644 .arg(_markerType, -60)
645 .leftJustified(60)
646 << "MARKER TYPE\n";
647 }
648
649 *stream << QString("%1%2")
650 .arg(_observer, -20)
651 .arg(_agency, -40)
652 .leftJustified(60)
653 << "OBSERVER / AGENCY\n";
654
655 *stream << QString("%1%2%3")
656 .arg(_receiverNumber, -20)
657 .arg(_receiverType, -20)
658 .arg(_receiverVersion, -20)
659 .leftJustified(60)
660 << "REC # / TYPE / VERS\n";
661
662 *stream << QString("%1%2")
663 .arg(_antennaNumber, -20)
664 .arg(_antennaName, -20)
665 .leftJustified(60)
666 << "ANT # / TYPE\n";
667
668 *stream << QString("%1%2%3")
669 .arg(_xyz(1), 14, 'f', 4)
670 .arg(_xyz(2), 14, 'f', 4)
671 .arg(_xyz(3), 14, 'f', 4)
672 .leftJustified(60)
673 << "APPROX POSITION XYZ\n";
674
675 *stream << QString("%1%2%3")
676 .arg(_antNEU(3), 14, 'f', 4)
677 .arg(_antNEU(2), 14, 'f', 4)
678 .arg(_antNEU(1), 14, 'f', 4)
679 .leftJustified(60)
680 << "ANTENNA: DELTA H/E/N\n";
681
682 if (_version < 3.0) {
683 int defaultWlFact1 = _wlFactorsL1[1];
684 int defaultWlFact2 = _wlFactorsL2[1]; // TODO check all prns
685 *stream << QString("%1%2")
686 .arg(defaultWlFact1, 6)
687 .arg(defaultWlFact2, 6)
688 .leftJustified(60)
689 << "WAVELENGTH FACT L1/2\n";
690 }
691
692 *stream << obsTypesStrings().join("");
693
694 if (_interval > 0) {
695 *stream << QString("%1")
696 .arg(_interval, 10, 'f', 3)
697 .leftJustified(60)
698 << "INTERVAL\n";
699 }
700
701 unsigned year, month, day, hour, min;
702 double sec;
703 _startTime.civil_date(year, month, day);
704 _startTime.civil_time(hour, min, sec);
705 *stream << QString("%1%2%3%4%5%6%7")
706 .arg(year, 6)
707 .arg(month, 6)
708 .arg(day, 6)
709 .arg(hour, 6)
710 .arg(min, 6)
711 .arg(sec, 13, 'f', 7)
712 .arg("GPS", 8)
713 .leftJustified(60)
714 << "TIME OF FIRST OBS\n";
715
716 if (_version >= 3.0) {
717 if (_phaseShifts.empty()) {
718 QMap<char, QStringList>::const_iterator it;
719 for (it = _obsTypes.begin(); it != _obsTypes.end(); ++it) {
720 char sys = it.key();
721 double shift = 0.0;
722 foreach (const QString &obstype, it.value()) {
723 if (obstype.left(1).contains('L')) {
724 *stream << QString("%1%2%3")
725 .arg(sys, 0)
726 .arg(obstype, 4)
727 .arg(shift, 9, 'f', 5)
728 .leftJustified(60)
729 << "SYS / PHASE SHIFT\n";
730 }
731 }
732 }
733 } else {
734 QMap<QString, QPair<double, QStringList> >::const_iterator it;
735 QString emptyFillStr;
736 for(it = _phaseShifts.begin(); it!= _phaseShifts.end(); ++it) {
737 QString sys = it.key().left(1);
738 QString obstype = it.key().mid(1);
739 double shift = it.value().first;
740 QStringList satList = it.value().second;
741 satList.sort();
742 QString hlp;
743 if (obstype.isEmpty()) {
744 hlp = QString("%1")
745 .arg(sys.toStdString().c_str(), 0);
746 }
747 else {
748 hlp = QString("%1%2")
749 .arg(sys.toStdString().c_str(), 0)
750 .arg(obstype, 4);
751 }
752 if (shift) {
753 hlp += QString("%1")
754 .arg(shift, 9, 'f', 5);
755 }
756 if (!satList.empty()) {
757 hlp += QString("%1").arg(satList.size(), 4);
758 }
759 else {
760 *stream << QString("%1")
761 .arg(hlp, 0)
762 .leftJustified(60)
763 << "SYS / PHASE SHIFT\n";
764 hlp = "";
765 }
766 int ii = 0;
767 QStringList::const_iterator it_s;
768 for (it_s = satList.begin(); it_s != satList.end(); ++it_s) {
769 (hlp.contains(obstype)) ?
770 emptyFillStr = "": emptyFillStr = " ";
771 hlp += QString("%1").arg(*it_s, 4);
772 ii++;
773 if (ii % 10 == 0) {
774 *stream << QString("%1%2")
775 .arg(emptyFillStr, 0)
776 .arg(hlp, 0)
777 .leftJustified(60)
778 << "SYS / PHASE SHIFT\n";
779 hlp = "";
780 }
781 }
782 if (hlp.size()) {
783 (hlp.contains(obstype)) ?
784 emptyFillStr = "": emptyFillStr = " ";
785 *stream << QString("%1%2")
786 .arg(emptyFillStr, 0)
787 .arg(hlp, 0)
788 .leftJustified(60)
789 << "SYS / PHASE SHIFT\n";
790 }
791 }
792 }
793 }
794
795 if (_version >= 3.0) {
796 QString hlp = "";
797 QMap<QString, double>::const_iterator it = _gloBiases.begin();
798 while (it != _gloBiases.end()){
799 hlp += QString("%1%2").arg(it.key(), 4).arg(it.value(), 9, 'f', 3);
800 it++;
801 }
802 *stream << QString("%1")
803 .arg(hlp, 0)
804 .leftJustified(60)
805 << "GLONASS COD/PHS/BIS\n";
806 }
807
808 if (_version >= 3.0) {
809 QString number = QString::number(_gloSlots.size());
810 QString hlp = "";
811 int ii = 0;
812 QMap<t_prn, int>::const_iterator it = _gloSlots.begin();
813 while (it != _gloSlots.end()) {
814 QString prn(it.key().toString().c_str());
815 hlp += QString("%1%2").arg(prn, 4).arg(it.value(), 3);
816 it++;
817 ii++;
818 if (ii % 8 == 0) {
819 *stream << QString("%1%2")
820 .arg(number, 3)
821 .arg(hlp, 0)
822 .leftJustified(60)
823 << "GLONASS SLOT / FRQ #\n";
824 ii = 0;
825 hlp = number = "";
826 }
827 }
828 if (hlp.size() || !_gloSlots.size()) {
829 *stream << QString("%1%2")
830 .arg(number, 3)
831 .arg(hlp, 0)
832 .leftJustified(60)
833 << "GLONASS SLOT / FRQ #\n";
834 }
835 }
836
837 *stream << QString()
838 .leftJustified(60)
839 << "END OF HEADER\n";
840}
841
842// Number of Different Systems
843////////////////////////////////////////////////////////////////////////////
844int t_rnxObsHeader::numSys() const {
845 return _obsTypes.size();
846}
847
848//
849////////////////////////////////////////////////////////////////////////////
850char t_rnxObsHeader::system(int iSys) const {
851 int iSysLocal = -1;
852 QMapIterator<char, QStringList> it(_obsTypes);
853 while (it.hasNext()) {
854 ++iSysLocal;
855 it.next();
856 if (iSysLocal == iSys) {
857 return it.key();
858 }
859 }
860 return ' ';
861}
862
863//
864////////////////////////////////////////////////////////////////////////////
865QString t_rnxObsHeader::usedSystems(void) const {
866 return _usedSystems;
867}
868
869QStringList t_rnxObsHeader::obsTypes(char sys) const {
870 if (_obsTypes.contains(sys)) {
871 return _obsTypes[sys];
872 }
873 else {
874 return QStringList();
875 }
876}
877
878// Number of Observation Types (satellite-system specific)
879////////////////////////////////////////////////////////////////////////////
880int t_rnxObsHeader::nTypes(char sys) const {
881 if (_obsTypes.contains(sys)) {
882 return _obsTypes[sys].size();
883 }
884 else {
885 return 0;
886 }
887}
888
889// Number of GLONASS biases
890////////////////////////////////////////////////////////////////////////////
891int t_rnxObsHeader::numGloBiases() const {
892 return _gloBiases.size();
893}
894
895// Number of GLONASS slots
896////////////////////////////////////////////////////////////////////////////
897int t_rnxObsHeader::numGloSlots() const {
898 return _gloSlots.size();
899}
900
901// Observation Type (satellite-system specific)
902////////////////////////////////////////////////////////////////////////////
903QString t_rnxObsHeader::obsType(char sys, int index, double version) const {
904
905 if (version == 0.0) {
906 version = _version;
907 }
908 if (_obsTypes.contains(sys)) {
909 QString origType = _obsTypes[sys].at(index);
910 if (int(version) == int(_version)) {
911 return origType;
912 }
913 else if (int(version) == 2) {
914 return t_rnxObsFile::type3to2(sys, origType);
915 }
916 else if (int(version) == 3) {
917 return t_rnxObsFile::type2to3(sys, origType);
918 }
919 }
920 return "";
921}
922
923//
924////////////////////////////////////////////////////////////////////////////
925QStringList t_rnxObsHeader::phaseShifts() const {
926 QStringList strList;
927 QMap<QString, QPair<double, QStringList> >::const_iterator it = _phaseShifts.begin();
928 while (it != _phaseShifts.end()) {
929 strList.append(QString("%1_%2:%3").arg(it.key(), 3).arg(it.value().first, 9, 'f', 3).arg(it.value().second.join(" ")));
930 it++;
931 }
932 return strList;
933}
934
935//
936////////////////////////////////////////////////////////////////////////////
937QStringList t_rnxObsHeader::gloBiases() const {
938 QStringList strList;
939 QMap<QString, double>::const_iterator it = _gloBiases.begin();
940 while (it != _gloBiases.end()) {
941 strList.append(QString("%1:%2").arg(it.key(), 3).arg(it.value(), 9, 'f', 3));
942 it++;
943 }
944 return strList;
945}
946
947//
948////////////////////////////////////////////////////////////////////////////
949QStringList t_rnxObsHeader::gloSlots() const {
950 QStringList strList;
951 QMap<t_prn, int>::const_iterator it = _gloSlots.begin();
952 while (it != _gloSlots.end()){
953 QString prn(it.key().toString().c_str());
954 strList.append(QString("%1:%2").arg(prn, 3).arg(it.value()));
955 it++;
956 }
957 return strList;
958}
959
960// Write Observation Types
961////////////////////////////////////////////////////////////////////////////
962QStringList t_rnxObsHeader::obsTypesStrings() const {
963
964 QStringList strList;
965 if (_version < 3.0) {
966 char sys0 = _usedSystems[0].toLatin1();
967 QString hlp;
968 QTextStream(&hlp) << QString("%1").arg(_obsTypes[sys0].size(), 6);
969 for (int ii = 0; ii < _obsTypes[sys0].size(); ii++) {
970 QTextStream(&hlp) << QString("%1").arg(_obsTypes[sys0][ii], 6);
971 if ((ii+1) % 9 == 0 || ii == _obsTypes[sys0].size()-1) {
972 strList.append(hlp.leftJustified(60) + "# / TYPES OF OBSERV\n");
973 hlp = QString().leftJustified(6);
974 }
975 }
976 }
977 else {
978 for (int iSys = 0; iSys < numSys(); iSys++) {
979 char sys = system(iSys);
980 QString hlp;
981 QTextStream(&hlp) << QString("%1 %2").arg(sys).arg(nTypes(sys), 3);
982 for (int iType = 0; iType < nTypes(sys); iType++) {
983 QString type = obsType(sys, iType);
984 QTextStream(&hlp) << QString(" %1").arg(type, -3);
985 if ((iType+1) % 13 == 0 || iType == nTypes(sys)-1) {
986 strList.append(hlp.leftJustified(60) + "SYS / # / OBS TYPES\n");
987 hlp = QString().leftJustified(6);
988 }
989 }
990 }
991 }
992
993 return strList;
994}
995
996// Constructor
997////////////////////////////////////////////////////////////////////////////
998t_rnxObsFile::t_rnxObsFile(const QString& fileName, e_inpOut inpOut) {
999 _inpOut = inpOut;
1000 _stream = 0;
1001 _flgPowerFail = false;
1002 if (_inpOut == input) {
1003 openRead(fileName);
1004 }
1005 else {
1006 openWrite(fileName);
1007 }
1008}
1009
1010// Open for input
1011////////////////////////////////////////////////////////////////////////////
1012void t_rnxObsFile::openRead(const QString& fileName) {
1013
1014 _fileName = fileName; expandEnvVar(_fileName);
1015 _file = new QFile(_fileName);
1016 _file->open(QIODevice::ReadOnly | QIODevice::Text);
1017 _stream = new QTextStream();
1018 _stream->setDevice(_file);
1019
1020 _header.read(_stream);
1021
1022 // Guess Observation Interval
1023 // --------------------------
1024 if (_header._interval == 0.0) {
1025 bncTime ttPrev;
1026 for (int iEpo = 0; iEpo < 10; iEpo++) {
1027 const t_rnxEpo* rnxEpo = nextEpoch();
1028 if (!rnxEpo) {
1029 throw QString("t_rnxObsFile: not enough epochs");
1030 }
1031 if (iEpo > 0) {
1032 double dt = rnxEpo->tt - ttPrev;
1033 if (_header._interval == 0.0 || dt < _header._interval) {
1034 _header._interval = dt;
1035 }
1036 }
1037 ttPrev = rnxEpo->tt;
1038 }
1039 _stream->seek(0);
1040 _header.read(_stream);
1041 }
1042
1043 // Time of first observation
1044 // -------------------------
1045 if (!_header._startTime.valid()) {
1046 const t_rnxEpo* rnxEpo = nextEpoch();
1047 if (!rnxEpo) {
1048 throw QString("t_rnxObsFile: not enough epochs");
1049 }
1050 _header._startTime = rnxEpo->tt;
1051 _stream->seek(0);
1052 _header.read(_stream);
1053 }
1054}
1055
1056// Open for output
1057////////////////////////////////////////////////////////////////////////////
1058void t_rnxObsFile::openWrite(const QString& fileName) {
1059
1060 _fileName = fileName; expandEnvVar(_fileName);
1061 _file = new QFile(_fileName);
1062 _file->open(QIODevice::WriteOnly | QIODevice::Text);
1063 _stream = new QTextStream();
1064 _stream->setDevice(_file);
1065}
1066
1067// Destructor
1068////////////////////////////////////////////////////////////////////////////
1069t_rnxObsFile::~t_rnxObsFile() {
1070 close();
1071}
1072
1073// Close
1074////////////////////////////////////////////////////////////////////////////
1075void t_rnxObsFile::close() {
1076 delete _stream; _stream = 0;
1077 delete _file; _file = 0;
1078}
1079
1080// Handle Special Epoch Flag
1081////////////////////////////////////////////////////////////////////////////
1082void t_rnxObsFile::handleEpochFlag(int flag, const QString& line,
1083 bool& headerReRead) {
1084
1085 headerReRead = false;
1086
1087 // Power Failure
1088 // -------------
1089 if (flag == 1) {
1090 _flgPowerFail = true;
1091 }
1092
1093 // Start moving antenna
1094 // --------------------
1095 else if (flag == 2) {
1096 // no action
1097 }
1098
1099 // Re-Read Header
1100 // --------------
1101 else if (flag == 3 || flag == 4 || flag == 5) {
1102 int numLines = 0;
1103 if (version() < 3.0) {
1104 readInt(line, 29, 3, numLines);
1105 }
1106 else {
1107 readInt(line, 32, 3, numLines);
1108 }
1109 if (flag == 3 || flag == 4) {
1110 _header.read(_stream, numLines);
1111 headerReRead = true;
1112 }
1113 else {
1114 for (int ii = 0; ii < numLines; ii++) {
1115 _stream->readLine();
1116 }
1117 }
1118 }
1119
1120 // Unhandled Flag
1121 // --------------
1122 else {
1123 throw QString("t_rnxObsFile: unhandled flag\n" + line);
1124 }
1125}
1126
1127// Retrieve single Epoch
1128////////////////////////////////////////////////////////////////////////////
1129t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpoch() {
1130 _currEpo.clear();
1131 if (version() < 3.0) {
1132 return nextEpochV2();
1133 }
1134 else {
1135 return nextEpochV3();
1136 }
1137}
1138
1139// Retrieve single Epoch (RINEX Version 3)
1140////////////////////////////////////////////////////////////////////////////
1141t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV3() {
1142
1143 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
1144
1145 QString line = _stream->readLine();
1146
1147 if (line.isEmpty()) {
1148 continue;
1149 }
1150
1151 int flag = 0;
1152 readInt(line, 31, 1, flag);
1153 if (flag > 0) {
1154 bool headerReRead = false;
1155 handleEpochFlag(flag, line, headerReRead);
1156 if (headerReRead) {
1157 continue;
1158 }
1159 }
1160
1161 QTextStream in(line.mid(1).toLatin1(), QIODevice::ReadOnly);
1162
1163 // Epoch Time
1164 // ----------
1165 int year, month, day, hour, min;
1166 double sec;
1167 in >> year >> month >> day >> hour >> min >> sec;
1168 _currEpo.tt.set(year, month, day, hour, min, sec);
1169
1170 // Number of Satellites
1171 // --------------------
1172 int numSat;
1173 readInt(line, 32, 3, numSat);
1174
1175 _currEpo.rnxSat.resize(numSat);
1176
1177 // Observations
1178 // ------------
1179 for (int iSat = 0; iSat < numSat; iSat++) {
1180 line = _stream->readLine();
1181 t_prn prn; prn.set(line.left(3).toLatin1().data());
1182 _currEpo.rnxSat[iSat].prn = prn;
1183 char sys = prn.system();
1184 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
1185 int pos = 3 + 16*iType;
1186 double obsValue = 0.0;
1187 int lli = 0;
1188 int snr = 0;
1189 readDbl(line, pos, 14, obsValue);
1190 readInt(line, pos + 14, 1, lli);
1191 readInt(line, pos + 15, 1, snr);
1192 if (_flgPowerFail) {
1193 lli |= 1;
1194 }
1195 QString type = obsType(sys, iType);
1196 _currEpo.rnxSat[iSat].obs[type].value = obsValue;
1197 _currEpo.rnxSat[iSat].obs[type].lli = lli;
1198 _currEpo.rnxSat[iSat].obs[type].snr = snr;
1199 }
1200 }
1201
1202 _flgPowerFail = false;
1203
1204 return &_currEpo;
1205 }
1206
1207 return 0;
1208}
1209
1210// Retrieve single Epoch (RINEX Version 2)
1211////////////////////////////////////////////////////////////////////////////
1212t_rnxObsFile::t_rnxEpo* t_rnxObsFile::nextEpochV2() {
1213
1214 while ( _stream->status() == QTextStream::Ok && !_stream->atEnd() ) {
1215
1216 QString line = _stream->readLine();
1217
1218 if (line.isEmpty()) {
1219 continue;
1220 }
1221
1222 int flag = 0;
1223 readInt(line, 28, 1, flag);
1224 if (flag > 0) {
1225 bool headerReRead = false;
1226 handleEpochFlag(flag, line, headerReRead);
1227 if (headerReRead) {
1228 continue;
1229 }
1230 }
1231
1232 QTextStream in(line.toLatin1(), QIODevice::ReadOnly);
1233
1234 // Epoch Time
1235 // ----------
1236 int year, month, day, hour, min;
1237 double sec;
1238 in >> year >> month >> day >> hour >> min >> sec;
1239 if (year < 80) {
1240 year += 2000;
1241 }
1242 else if (year < 100) {
1243 year += 1900;
1244 }
1245 _currEpo.tt.set(year, month, day, hour, min, sec);
1246
1247 // Number of Satellites
1248 // --------------------
1249 int numSat;
1250 readInt(line, 29, 3, numSat);
1251
1252 _currEpo.rnxSat.resize(numSat);
1253
1254 // Read Satellite Numbers
1255 // ----------------------
1256 int pos = 32;
1257 for (int iSat = 0; iSat < numSat; iSat++) {
1258 if (iSat > 0 && iSat % 12 == 0) {
1259 line = _stream->readLine();
1260 pos = 32;
1261 }
1262
1263 char sys = line.toLatin1()[pos];
1264 if (sys == ' ') {
1265 sys = 'G';
1266 }
1267 int satNum; readInt(line, pos + 1, 2, satNum);
1268 _currEpo.rnxSat[iSat].prn.set(sys, satNum);
1269
1270 pos += 3;
1271 }
1272
1273 // Read Observation Records
1274 // ------------------------
1275 for (int iSat = 0; iSat < numSat; iSat++) {
1276 char sys = _currEpo.rnxSat[iSat].prn.system();
1277 line = _stream->readLine();
1278 pos = 0;
1279 for (int iType = 0; iType < _header.nTypes(sys); iType++) {
1280 if (iType > 0 && iType % 5 == 0) {
1281 line = _stream->readLine();
1282 pos = 0;
1283 }
1284 double obsValue = 0.0;
1285 int lli = 0;
1286 int snr = 0;
1287 readDbl(line, pos, 14, obsValue);
1288 readInt(line, pos + 14, 1, lli);
1289 readInt(line, pos + 15, 1, snr);
1290
1291 if (_flgPowerFail) {
1292 lli |= 1;
1293 }
1294
1295 QString type = obsType(sys, iType);
1296 _currEpo.rnxSat[iSat].obs[type].value = obsValue;
1297 _currEpo.rnxSat[iSat].obs[type].lli = lli;
1298 _currEpo.rnxSat[iSat].obs[type].snr = snr;
1299
1300 pos += 16;
1301 }
1302 }
1303
1304 _flgPowerFail = false;
1305
1306 return &_currEpo;
1307 }
1308
1309 return 0;
1310}
1311
1312// Write Data Epoch
1313////////////////////////////////////////////////////////////////////////////
1314void t_rnxObsFile::writeEpoch(const t_rnxEpo* epo) {
1315 if (epo == 0) {
1316 return;
1317 }
1318 t_rnxEpo epoLocal;
1319 epoLocal.tt = epo->tt;
1320 for (unsigned ii = 0; ii < epo->rnxSat.size(); ii++) {
1321 const t_rnxSat& rnxSat = epo->rnxSat[ii];
1322 if (_header._obsTypes[rnxSat.prn.system()].size() > 0) {
1323 if (_header.version() < 3.0) { // exclude new GNSS such as BDS, QZSS, IRNSS, etc.
1324 if (rnxSat.prn.system() != 'G' && rnxSat.prn.system() != 'R' &&
1325 rnxSat.prn.system() != 'E' && rnxSat.prn.system() != 'S' &&
1326 rnxSat.prn.system() != 'I') {
1327 continue;
1328 }
1329 }
1330 epoLocal.rnxSat.push_back(rnxSat);
1331 }
1332 }
1333 std::stable_sort(epoLocal.rnxSat.begin(), epoLocal.rnxSat.end(), t_rnxSat::prnSort);
1334
1335 if (version() < 3.0) {
1336 return writeEpochV2(_stream, _header, &epoLocal);
1337 }
1338 else {
1339 return writeEpochV3(_stream, _header, &epoLocal);
1340 }
1341}
1342
1343// Write Data Epoch (RINEX Version 2)
1344////////////////////////////////////////////////////////////////////////////
1345void t_rnxObsFile::writeEpochV2(QTextStream* stream, const t_rnxObsHeader& header,
1346 const t_rnxEpo* epo) {
1347
1348 unsigned year, month, day, hour, min;
1349 double sec;
1350 epo->tt.civil_date(year, month, day);
1351 epo->tt.civil_time(hour, min, sec);
1352
1353 QString dateStr;
1354 QTextStream(&dateStr) << QString(" %1 %2 %3 %4 %5%6")
1355 .arg(int(fmod(double(year), 100.0)), 2, 10, QChar('0'))
1356 .arg(month, 2, 10, QChar('0'))
1357 .arg(day, 2, 10, QChar('0'))
1358 .arg(hour, 2, 10, QChar('0'))
1359 .arg(min, 2, 10, QChar('0'))
1360 .arg(sec, 11, 'f', 7);
1361
1362 int flag = 0;
1363 *stream << dateStr << QString("%1%2").arg(flag, 3).arg(epo->rnxSat.size(), 3);
1364 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
1365 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
1366 if (iSat > 0 && iSat % 12 == 0) {
1367 *stream << endl << QString().leftJustified(32);
1368 }
1369 *stream << rnxSat.prn.toString().c_str();
1370 }
1371 *stream << endl;
1372
1373 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
1374 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
1375 char sys = rnxSat.prn.system();
1376 for (int iTypeV2 = 0; iTypeV2 < header.nTypes(sys); iTypeV2++) {
1377 if (iTypeV2 > 0 && iTypeV2 % 5 == 0) {
1378 *stream << endl;
1379 }
1380 QString typeV2 = header.obsType(sys, iTypeV2);
1381 bool found = false;
1382 QStringList preferredAttribList = signalPriorities(sys);
1383 QString preferredAttrib;
1384 for (int ii = 0; ii < preferredAttribList.size(); ii++) {
1385 if (preferredAttribList[ii].indexOf("&") != -1) {
1386 QStringList hlp = preferredAttribList[ii].split("&", QString::SkipEmptyParts);
1387 if (hlp.size() == 2 && hlp[0].contains(typeV2[1])) {
1388 preferredAttrib = hlp[1];
1389 }
1390 }
1391 else {
1392 preferredAttrib = preferredAttribList[ii];
1393 }
1394 }
1395
1396 for (int iPref = 0; iPref < preferredAttrib.size(); iPref++) {
1397 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
1398 while (itObs.hasNext()) {
1399 itObs.next();
1400 const QString& type = itObs.key();
1401 const t_rnxObs& rnxObs = itObs.value();
1402 if ( preferredAttrib[iPref] == '?' ||
1403 (type.length() == 2 && preferredAttrib[iPref] == '_' ) ||
1404 (type.length() == 3 && preferredAttrib[iPref] == type[2]) ) {
1405 if (typeV2 == type3to2(sys, type)) {
1406 found = true;
1407 if (rnxObs.value == 0.0) {
1408 *stream << QString().leftJustified(16);
1409 }
1410 else {
1411 *stream << QString("%1").arg(rnxObs.value, 14, 'f', 3);
1412 if (rnxObs.lli != 0.0) {
1413 *stream << QString("%1").arg(rnxObs.lli,1);
1414 }
1415 else {
1416 *stream << ' ';
1417 }
1418 if (rnxObs.snr != 0.0) {
1419 *stream << QString("%1").arg(rnxObs.snr,1);
1420 }
1421 else {
1422 *stream << ' ';
1423 }
1424 }
1425 goto end_loop_iPref;
1426 }
1427 }
1428 }
1429 } end_loop_iPref:
1430 if (!found) {
1431 *stream << QString().leftJustified(16);
1432 }
1433 }
1434 *stream << endl;
1435 }
1436}
1437
1438// Write Data Epoch (RINEX Version 3)
1439////////////////////////////////////////////////////////////////////////////
1440void t_rnxObsFile::writeEpochV3(QTextStream* stream, const t_rnxObsHeader& header,
1441 const t_rnxEpo* epo) {
1442
1443 unsigned year, month, day, hour, min;
1444 double sec;
1445 epo->tt.civil_date(year, month, day);
1446 epo->tt.civil_time(hour, min, sec);
1447
1448 QString dateStr;
1449 QTextStream(&dateStr) << QString("> %1 %2 %3 %4 %5%6")
1450 .arg(year, 4)
1451 .arg(month, 2, 10, QChar('0'))
1452 .arg(day, 2, 10, QChar('0'))
1453 .arg(hour, 2, 10, QChar('0'))
1454 .arg(min, 2, 10, QChar('0'))
1455 .arg(sec, 11, 'f', 7);
1456
1457 int flag = 0;
1458 *stream << dateStr << QString("%1%2\n").arg(flag, 3).arg(epo->rnxSat.size(), 3);
1459
1460 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
1461 const t_rnxSat& rnxSat = epo->rnxSat[iSat];
1462 char sys = rnxSat.prn.system();
1463
1464 const t_rnxObs* hlp[header.nTypes(sys)];
1465 for (int iTypeV3 = 0; iTypeV3 < header.nTypes(sys); iTypeV3++) {
1466 hlp[iTypeV3] = 0;
1467 QString typeV3 = header.obsType(sys, iTypeV3);
1468 QMapIterator<QString, t_rnxObs> itObs(rnxSat.obs);
1469
1470 // Exact match
1471 // -----------
1472 while (itObs.hasNext()) {
1473 itObs.next();
1474 const QString& type = itObs.key();
1475 const t_rnxObs& rnxObs = itObs.value();
1476 if (typeV3 == type2to3(sys, type) && rnxObs.value != 0.0) {
1477 hlp[iTypeV3] = &itObs.value();
1478 }
1479 }
1480
1481 // Non-Exact match
1482 // ---------------
1483 itObs.toFront();
1484 while (itObs.hasNext()) {
1485 itObs.next();
1486 const QString& type = itObs.key();
1487 const t_rnxObs& rnxObs = itObs.value();
1488 if (hlp[iTypeV3] == 0 && typeV3 == type2to3(sys, type).left(2) && rnxObs.value != 0.0) {
1489 hlp[iTypeV3] = &itObs.value();
1490 }
1491 }
1492 }
1493
1494 if (header.nTypes(sys)) {
1495 *stream << rnxSat.prn.toString().c_str();
1496 for (int iTypeV3 = 0; iTypeV3 < header.nTypes(sys); iTypeV3++) {
1497 const t_rnxObs* rnxObs = hlp[iTypeV3];
1498 if (rnxObs == 0) {
1499 *stream << QString().leftJustified(16);
1500 }
1501 else {
1502 *stream << QString("%1").arg(rnxObs->value, 14, 'f', 3);
1503 if (rnxObs->lli != 0.0) {
1504 *stream << QString("%1").arg(rnxObs->lli, 1);
1505 }
1506 else {
1507 *stream << ' ';
1508 }
1509 if (rnxObs->snr != 0.0) {
1510 *stream << QString("%1").arg(rnxObs->snr, 1);
1511 }
1512 else {
1513 *stream << ' ';
1514 }
1515 }
1516 }
1517 *stream << endl;
1518 }
1519 }
1520}
1521
1522// Translate Observation Type v2 --> v3
1523////////////////////////////////////////////////////////////////////////////
1524QString t_rnxObsFile::type2to3(char sys, const QString& typeV2) {
1525 if (typeV2 == "P1") {
1526 return (sys == 'G') ? "C1W" : "C1P";
1527 }
1528 else if (typeV2 == "P2") {
1529 return (sys == 'G') ? "C2W" : "C2P";
1530 }
1531 return typeV2;
1532}
1533
1534// Translate Observation Type v3 --> v2
1535////////////////////////////////////////////////////////////////////////////
1536QString t_rnxObsFile::type3to2(char /* sys */, const QString& typeV3) {
1537 if (typeV3 == "C1P" || typeV3 == "C1W") {
1538 return "P1";
1539 }
1540 else if (typeV3 == "C2P" || typeV3 == "C2W") {
1541 return "P2";
1542 }
1543 return typeV3.left(2);
1544}
1545
1546// Set Observations from RINEX File
1547////////////////////////////////////////////////////////////////////////////
1548void t_rnxObsFile::setObsFromRnx(const t_rnxObsFile* rnxObsFile, const t_rnxObsFile::t_rnxEpo* epo,
1549 const t_rnxObsFile::t_rnxSat& rnxSat, t_satObs& obs) {
1550 obs._staID = rnxObsFile->markerName().toLatin1().constData();
1551 obs._prn = rnxSat.prn;
1552 obs._time = epo->tt;
1553
1554 char sys = rnxSat.prn.system();
1555
1556 QChar addToL2;
1557 for (int iType = 0; iType < rnxObsFile->nTypes(sys); iType++) {
1558 QString type = rnxObsFile->obsType(sys, iType);
1559 QString typeV3 = rnxObsFile->obsType(sys, iType, 3.0); // may or may not differ from type
1560 if (rnxSat.obs.contains(type) && rnxSat.obs[type].value != 0.0) {
1561 if (type == "P2" && typeV3.length() > 2) {
1562 addToL2 = typeV3[2];
1563 break;
1564 }
1565 }
1566 }
1567
1568 for (int iType = 0; iType < rnxObsFile->nTypes(sys); iType++) {
1569 QString type = rnxObsFile->obsType(sys, iType);
1570 QString typeV3 = rnxObsFile->obsType(sys, iType, 3.0); // may or may not differ from type
1571 if (type == "L2") {
1572 typeV3 += addToL2;
1573 }
1574 if (rnxSat.obs.contains(type)) {
1575 const t_rnxObs& rnxObs = rnxSat.obs[type];
1576 if (rnxObs.value != 0.0) {
1577 string type2ch(typeV3.mid(1).toLatin1().data());
1578
1579 t_frqObs* frqObs = 0;
1580 for (unsigned iFrq = 0; iFrq < obs._obs.size(); iFrq++) {
1581 if (obs._obs[iFrq]->_rnxType2ch == type2ch) {
1582 frqObs = obs._obs[iFrq];
1583 break;
1584 }
1585 }
1586 if (frqObs == 0) {
1587 frqObs = new t_frqObs;
1588 frqObs->_rnxType2ch = type2ch;
1589 obs._obs.push_back(frqObs);
1590 }
1591
1592 switch( typeV3.toLatin1().data()[0] ) {
1593 case 'C':
1594 frqObs->_codeValid = true;
1595 frqObs->_code = rnxObs.value;
1596 break;
1597 case 'L':
1598 frqObs->_phaseValid = true;
1599 frqObs->_phase = rnxObs.value;
1600 frqObs->_slip = (rnxObs.lli & 1);
1601 break;
1602 case 'D':
1603 frqObs->_dopplerValid = true;
1604 frqObs->_doppler = rnxObs.value;
1605 break;
1606 case 'S':
1607 frqObs->_snrValid = true;
1608 frqObs->_snr = rnxObs.value;
1609 break;
1610 }
1611
1612 // Handle old-fashioned SNR values
1613 // -------------------------------
1614 if (rnxObs.snr != 0 && !frqObs->_snrValid) {
1615 frqObs->_snrValid = true;
1616 frqObs->_snr = rnxObs.snr * 6.0 + 2.5;
1617 }
1618 }
1619 }
1620 }
1621}
1622
1623// Tracking Mode Priorities
1624////////////////////////////////////////////////////////////////////////////
1625QStringList t_rnxObsFile::signalPriorities(char sys) {
1626
1627 bncSettings settings;
1628
1629 QStringList priorList;
1630 QString reqcAction = settings.value("reqcAction").toString();
1631
1632 // Priorities in Edit/Concatenate (post processing) mode
1633 // ---------------------------------------------------
1634 if (reqcAction == "Edit/Concatenate") {
1635 priorList = settings.value("reqcV2Priority").toString().split(" ", QString::SkipEmptyParts);
1636 }
1637
1638 // Priorities in real-time mode
1639 // ----------------------------
1640 else {
1641 priorList = settings.value("rnxV2Priority").toString().split(" ", QString::SkipEmptyParts);
1642 }
1643
1644 QStringList result;
1645 for (int ii = 0; ii < priorList.size(); ii++) {
1646 if (priorList[ii].indexOf(":") != -1) {
1647 QStringList hlp = priorList[ii].split(":", QString::SkipEmptyParts);
1648 if (hlp.size() == 2 && hlp[0].length() == 1 && hlp[0][0] == sys) {
1649 result.append(hlp[1]);
1650 }
1651 }
1652 else {
1653 result.append(priorList[ii]);
1654 }
1655 }
1656
1657 if (result.empty()) {
1658 switch (sys) {
1659 case 'G':
1660 result.append("12&PWCSLXYN");
1661 result.append("5&IQX");
1662 break;
1663 case 'R':
1664 result.append("12&PC");
1665 result.append("3&IQX");
1666 break;
1667 case 'E':
1668 result.append("16&BCX");
1669 result.append("578&IQX");
1670 break;
1671 case 'J':
1672 result.append("1&SLXCZ");
1673 result.append("26&SLX");
1674 result.append("5&IQX");
1675 break;
1676 case 'C':
1677 result.append("IQX");
1678 break;
1679 case 'I':
1680 result.append("ABCX");
1681 break;
1682 case 'S':
1683 result.append("1&C");
1684 result.append("5&IQX");
1685 break;
1686 }
1687 }
1688 return result;
1689}
Note: See TracBrowser for help on using the repository browser.