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

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