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

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

some updates to support RINEX Version 3.04

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