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

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

minor changes

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