source: ntrip/branches/BNC_2.12/src/rinex/rnxobsfile.cpp@ 8681

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

minor changes in RTCM3 Decoder with respect to MSM obs codes

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