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

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

INRSS support regarding RINEX observation files is added

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