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

Last change on this file since 8035 was 8035, checked in by stuerze, 8 years ago

minor changes in default observation types

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