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

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

minor changes

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