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

Last change on this file since 9870 was 9870, checked in by stuerze, 18 months ago

minor changes

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