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

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

INRSS support regarding RINEX observation files is added

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