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

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

IRNSS support is added in RINEX QC

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