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

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

some updates to support RINEX Version 3.04

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