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

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

minor changes

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