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

Last change on this file since 8113 was 8113, checked in by stuerze, 7 years ago

set default rinex version 3 obs types if skl file obs types are of version 2 and rinex output file shall be in version 3 in order to get 3char obs types as required in rinex version 3.03

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