source: ntrip/trunk/BNC/src/rinex/reqcedit.cpp@ 10969

Last change on this file since 10969 was 10969, checked in by stuerze, 3 weeks ago

minor changes

File size: 28.8 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_reqcEdit
30 *
31 * Purpose: Edit/Concatenate RINEX Files
32 *
33 * Author: L. Mervart
34 *
35 * Created: 11-Apr-2012
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <iostream>
42#include "reqcedit.h"
43#include "bnccore.h"
44#include "bncsettings.h"
45#include "bncutils.h"
46#include "rnxobsfile.h"
47#include "rnxnavfile.h"
48
49using namespace std;
50
51// Constructor
52////////////////////////////////////////////////////////////////////////////
53t_reqcEdit::t_reqcEdit(QObject* parent) : QThread(parent) {
54
55 bncSettings settings;
56
57 _logFileName = settings.value("reqcOutLogFile").toString(); expandEnvVar(_logFileName);
58 _logFile = 0;
59 _logStream = 0;
60 _obsFileNames = settings.value("reqcObsFile").toString().split(",", Qt::SkipEmptyParts);
61 _outObsFileName = settings.value("reqcOutObsFile").toString();
62 _navFileNames = settings.value("reqcNavFile").toString().split(",", Qt::SkipEmptyParts);
63 _outNavFileName = settings.value("reqcOutNavFile").toString();
64 int version = settings.value("reqcRnxVersion").toInt();
65 if (version == 2) {
66 _rnxVersion = defaultRnxObsVersion2;
67 }
68 else if (version == 3) {
69 _rnxVersion = defaultRnxObsVersion3;
70 }
71 else if (version == 4) {
72 _rnxVersion = defaultRnxObsVersion4;
73 }
74 _samplingRate = settings.value("reqcSampling").toString().split("sec").first().toDouble();
75 _minEle = settings.value("reqcMinEle").toDouble();
76 _begTime = bncTime(settings.value("reqcStartDateTime").toString().toLatin1().data());
77 _endTime = bncTime(settings.value("reqcEndDateTime").toString().toLatin1().data());
78
79 _checkEph = false;
80
81}
82
83// Destructor
84////////////////////////////////////////////////////////////////////////////
85t_reqcEdit::~t_reqcEdit() {
86 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
87 delete _rnxObsFiles[ii];
88 }
89 for (int ii = 0; ii < _ephs.size(); ii++) {
90 delete _ephs[ii];
91 }
92 delete _logStream; _logStream = 0;
93 delete _logFile; _logFile = 0;
94}
95
96//
97////////////////////////////////////////////////////////////////////////////
98void t_reqcEdit::run() {
99
100 // Open Log File
101 // -------------
102 if (!_logFileName.isEmpty()) {
103 _logFile = new QFile(_logFileName);
104 if (_logFile->open(QIODevice::WriteOnly | QIODevice::Text)) {
105 _logStream = new QTextStream();
106 _logStream->setDevice(_logFile);
107 }
108 }
109
110 // Log File Header
111 // ---------------
112 if (_logStream) {
113 *_logStream << QByteArray(78, '-') << Qt::endl;
114 *_logStream << "RINEX File Editing\n";
115 *_logStream << QByteArray(78, '-') << Qt::endl;
116
117 *_logStream << QByteArray("Program").leftJustified(18) << ": "
118 << BNC_CORE->pgmName() << Qt::endl;
119 *_logStream << QByteArray("Run by").leftJustified(18) << ": "
120 << BNC_CORE->userName() << Qt::endl;
121 *_logStream << QByteArray("Date").leftJustified(18) << ": "
122 << QDateTime::currentDateTime().toUTC().toString("yyyy-MM-dd hh:mm:ss") << Qt::endl;
123 *_logStream << QByteArray("RINEX Version").leftJustified(18) << ": "
124 << _rnxVersion << Qt::endl;
125 *_logStream << QByteArray("Sampling").leftJustified(18) << ": "
126 << _samplingRate << " sec" << Qt::endl;
127 *_logStream << QByteArray("Minimum Elevation").leftJustified(18) << ": "
128 << _minEle << " deg" << Qt::endl;
129 *_logStream << QByteArray("Start time").leftJustified(18) << ": "
130 << _begTime.datestr().c_str() << ' '
131 << _begTime.timestr(0).c_str() << Qt::endl;
132 *_logStream << QByteArray("End time").leftJustified(18) << ": "
133 << _endTime.datestr().c_str() << ' '
134 << _endTime.timestr(0).c_str() << Qt::endl;
135 *_logStream << QByteArray("Input Obs Files").leftJustified(18) << ": "
136 << _obsFileNames.join(",") << Qt::endl;
137 *_logStream << QByteArray("Input Nav Files").leftJustified(18) << ": "
138 << _navFileNames.join(",") << Qt::endl;
139 *_logStream << QByteArray("Output Obs File").leftJustified(18) << ": "
140 << _outObsFileName << Qt::endl;
141 *_logStream << QByteArray("Output Nav File").leftJustified(18) << ": "
142 << _outNavFileName << Qt::endl;
143
144 *_logStream << QByteArray(78, '-') << Qt::endl;
145 _logStream->flush();
146 }
147
148 // Handle Observation Files
149 // ------------------------
150 editObservations();
151
152 // Handle Navigations Files
153 // ------------------------
154 editEphemerides();
155
156 // Exit (thread)
157 // -------------
158 if (BNC_CORE->mode() != t_bncCore::interactive) {
159 qApp->exit(9);
160 msleep(100); //sleep 0.1 sec
161 }
162 else {
163 emit finished();
164 deleteLater();
165 }
166
167}
168
169// Initialize input observation files, sort them according to start time
170////////////////////////////////////////////////////////////////////////////
171void t_reqcEdit::initRnxObsFiles(const QStringList& obsFileNames,
172 QVector<t_rnxObsFile*>& rnxObsFiles,
173 QTextStream* log) {
174
175 QStringListIterator it(obsFileNames);
176 while (it.hasNext()) {
177 QString fileName = it.next();
178 if (fileName.indexOf('*') != -1 ||
179 fileName.indexOf('?') != -1) {
180 QFileInfo fileInfo(fileName);
181 QDir dir = fileInfo.dir();
182 QStringList filters; filters << fileInfo.fileName();
183 QListIterator<QFileInfo> it(dir.entryInfoList(filters));
184 while (it.hasNext()) {
185 QString filePath = it.next().filePath();
186 t_rnxObsFile* rnxObsFile = 0;
187 try {
188 rnxObsFile = new t_rnxObsFile(filePath, t_rnxObsFile::input);
189 rnxObsFiles.append(rnxObsFile);
190 }
191 catch (...) {
192 delete rnxObsFile;
193 if (log) {
194 *log << "Error in rnxObsFile " << filePath.toLatin1().data() << Qt::endl;
195 }
196 }
197 }
198 }
199 else {
200 t_rnxObsFile* rnxObsFile = 0;
201 try {
202 rnxObsFile = new t_rnxObsFile(fileName, t_rnxObsFile::input);
203 rnxObsFiles.append(rnxObsFile);
204 }
205 catch (...) {
206 if (log) {
207 *log << "Error in rnxObsFile " << fileName.toLatin1().data() << Qt::endl;
208 }
209 }
210 }
211 }
212 std::stable_sort(rnxObsFiles.begin(), rnxObsFiles.end(),
213 t_rnxObsFile::earlierStartTime);
214}
215
216//
217////////////////////////////////////////////////////////////////////////////
218void t_reqcEdit::editObservations() {
219
220 // Easy Exit
221 // ---------
222 if (_obsFileNames.isEmpty() || _outObsFileName.isEmpty()) {
223 return;
224 }
225
226 t_reqcEdit::initRnxObsFiles(_obsFileNames, _rnxObsFiles, _logStream);
227
228 // Read Ephemerides (needed to apply the elevation mask)
229 // ------------------------------------------------------
230 if (_minEle > 0.0 && _ephs.isEmpty()) {
231 t_reqcEdit::readEphemerides(_navFileNames, _ephs, _logStream, _checkEph);
232 }
233
234 // Initialize output observation file
235 // ----------------------------------
236 t_rnxObsFile outObsFile(_outObsFileName, t_rnxObsFile::output);
237
238
239 // Put together all run by date entries
240 // ------------------------------------
241 QStringList runByDate;
242 if (_rnxVersion >= 4.0 && _rnxObsFiles.size() > 1) {
243 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
244 t_rnxObsFile* rnxObsFile = _rnxObsFiles[ii];
245 QStringListIterator itRunByDt(rnxObsFile->runByDate());
246 while (itRunByDt.hasNext()) {
247 runByDate.append(itRunByDt.next());
248 }
249 }
250 runByDate.removeDuplicates();
251 }
252
253 // Select observation types
254 // ------------------------
255 bncSettings settings;
256 QStringList useObsTypes = settings.value("reqcUseObsTypes").toString().split(" ", Qt::SkipEmptyParts);
257
258 // Put together all observation types
259 // ----------------------------------
260 if (_rnxObsFiles.size() > 1 && useObsTypes.size() == 0) {
261 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
262 t_rnxObsFile* obsFile = _rnxObsFiles[ii];
263 for (int iSys = 0; iSys < obsFile->numSys(); iSys++) {
264 char sys = obsFile->system(iSys);
265 if (sys != ' ') {
266 for (int iType = 0; iType < obsFile->nTypes(sys); iType++) {
267 QString type = obsFile->obsType(sys, iType);
268 if (_rnxVersion < 3.0) {
269 useObsTypes << type;
270 }
271 else {
272 useObsTypes << QString(sys) + ":" + type;
273 }
274 }
275 }
276 }
277 }
278 useObsTypes.removeDuplicates();
279 }
280
281 // Put together all phase shifts
282 // -----------------------------
283 QStringList phaseShifts;
284 if (_rnxVersion >= 3.0 && _rnxObsFiles.size() > 1) {
285 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
286 t_rnxObsFile* obsFile = _rnxObsFiles[ii];
287 phaseShifts << obsFile->phaseShifts();
288 }
289 phaseShifts.removeDuplicates();
290 }
291
292 // Put together all GLONASS biases
293 // -------------------------------
294 QStringList gloBiases;
295 if (_rnxVersion >= 3.0 && _rnxObsFiles.size() > 1) {
296 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
297 t_rnxObsFile* obsFile = _rnxObsFiles[ii];
298 if (ii == 0 && obsFile->numGloBiases() == 4) {
299 break;
300 }
301 else {
302 gloBiases << obsFile->gloBiases();
303 }
304 }
305 gloBiases.removeDuplicates();
306 }
307
308 // Put together all GLONASS slots
309 // -----------------------------
310 QStringList gloSlots;
311 if (_rnxVersion >= 3.0 && _rnxObsFiles.size() > 1) {
312 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
313 t_rnxObsFile* obsFile = _rnxObsFiles[ii];
314 if (ii == 0 &&
315 obsFile->numGloSlots() == signed(t_prn::MAXPRN_GLONASS)) {
316 break;
317 }
318 else {
319 gloSlots << obsFile->gloSlots();
320 }
321 }
322 gloSlots.removeDuplicates();
323 }
324
325 // Loop over all input observation files
326 // -------------------------------------
327 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
328 t_rnxObsFile* obsFile = _rnxObsFiles[ii];
329 if (_logStream) {
330 *_logStream << "Input Obs File: " << obsFile->fileName() << " start: "
331 << obsFile->startTime().datestr().c_str() << ' '
332 << obsFile->startTime().timestr(0).c_str() << Qt::endl;
333 }
334 if (ii == 0) {
335 outObsFile.setHeader(obsFile->header(), int(_rnxVersion), &useObsTypes,
336 &phaseShifts, &gloBiases, &gloSlots, &runByDate);
337 if (_begTime.valid() && _begTime > outObsFile.startTime()) {
338 outObsFile.setStartTime(_begTime);
339 }
340 if (_samplingRate > outObsFile.interval()) {
341 outObsFile.setInterval(_samplingRate);
342 }
343 editRnxObsHeader(outObsFile);
344 bncSettings settings;
345 QMap<QString, QString> txtMap;
346 QString runBy = settings.value("reqcRunBy").toString();
347 if (!runBy.isEmpty()) {
348 txtMap["RUN BY"] = runBy;
349 }
350 QString comment = settings.value("reqcComment").toString();
351 if (!comment.isEmpty()) {
352 txtMap["COMMENT"] = comment;
353 }
354 if (int(_rnxVersion) < int(obsFile->header().version())) {
355 addRnxConversionDetails(obsFile, txtMap);
356 }
357 outObsFile.header().write(outObsFile.stream(), &txtMap);
358 }
359 t_rnxObsFile::t_rnxEpo* epo = 0;
360 try {
361 while ( (epo = obsFile->nextEpoch()) != 0) {
362 if (_begTime.valid() && epo->tt < _begTime) {
363 continue;
364 }
365 if (_endTime.valid() && epo->tt > _endTime) {
366 break;
367 }
368
369 int sec = int(nint(epo->tt.gpssec()*10));
370 if (sec % (int(_samplingRate)*10) == 0) {
371 applyLLI(obsFile, epo);
372 if (_minEle > 0.0) {
373 applyElevationMask(obsFile, epo);
374 }
375 outObsFile.writeEpoch(epo);
376 }
377 else {
378 rememberLLI(obsFile, epo);
379 }
380 }
381 }
382 catch (QString str) {
383 if (_logStream) {
384 *_logStream << "Exception " << str << Qt::endl;
385 }
386 else {
387 qDebug() << str;
388 }
389 return;
390 }
391 catch (...) {
392 if (_logStream) {
393 *_logStream << "Exception unknown" << Qt::endl;
394 }
395 else {
396 qDebug() << "Exception unknown";
397 }
398 return;
399 }
400 }
401}
402
403// Change RINEX Header Content
404////////////////////////////////////////////////////////////////////////////
405void t_reqcEdit::editRnxObsHeader(t_rnxObsFile& obsFile) {
406
407 bncSettings settings;
408
409 QString oldMarkerName = settings.value("reqcOldMarkerName").toString();
410 QString newMarkerName = settings.value("reqcNewMarkerName").toString();
411 if (!newMarkerName.isEmpty()) {
412 if (oldMarkerName.isEmpty() ||
413 QRegExp(oldMarkerName).exactMatch(obsFile.markerName())) {
414 obsFile.setMarkerName(newMarkerName);
415 }
416 }
417
418 QString oldAntennaName = settings.value("reqcOldAntennaName").toString();
419 QString newAntennaName = settings.value("reqcNewAntennaName").toString();
420 if (!newAntennaName.isEmpty()) {
421 if (oldAntennaName.isEmpty() ||
422 QRegExp(oldAntennaName).exactMatch(obsFile.antennaName())) {
423 obsFile.setAntennaName(newAntennaName);
424 }
425 }
426
427 QString oldAntennaNumber = settings.value("reqcOldAntennaNumber").toString();
428 QString newAntennaNumber = settings.value("reqcNewAntennaNumber").toString();
429 if (!newAntennaNumber.isEmpty()) {
430 if (oldAntennaNumber.isEmpty() ||
431 QRegExp(oldAntennaNumber).exactMatch(obsFile.antennaNumber())) {
432 obsFile.setAntennaNumber(newAntennaNumber);
433 }
434 }
435
436 const ColumnVector& obsFileAntNEU = obsFile.antNEU();
437 QString oldAntennadN = settings.value("reqcOldAntennadN").toString();
438 QString newAntennadN = settings.value("reqcNewAntennadN").toString();
439 if(!newAntennadN.isEmpty()) {
440 if (oldAntennadN.isEmpty() ||
441 oldAntennadN.toDouble() == obsFileAntNEU(1)) {
442 obsFile.setAntennaN(newAntennadN.toDouble());
443 }
444 }
445 QString oldAntennadE = settings.value("reqcOldAntennadE").toString();
446 QString newAntennadE = settings.value("reqcNewAntennadE").toString();
447 if(!newAntennadE.isEmpty()) {
448 if (oldAntennadE.isEmpty() ||
449 oldAntennadE.toDouble() == obsFileAntNEU(2)) {
450 obsFile.setAntennaE(newAntennadE.toDouble());
451 }
452 }
453 QString oldAntennadU = settings.value("reqcOldAntennadU").toString();
454 QString newAntennadU = settings.value("reqcNewAntennadU").toString();
455 if(!newAntennadU.isEmpty()) {
456 if (oldAntennadU.isEmpty() ||
457 oldAntennadU.toDouble() == obsFileAntNEU(3)) {
458 obsFile.setAntennaU(newAntennadU.toDouble());
459 }
460 }
461
462 QString oldReceiverType = settings.value("reqcOldReceiverName").toString();
463 QString newReceiverType = settings.value("reqcNewReceiverName").toString();
464 if (!newReceiverType.isEmpty()) {
465 if (oldReceiverType.isEmpty() ||
466 QRegExp(oldReceiverType).exactMatch(obsFile.receiverType())) {
467 obsFile.setReceiverType(newReceiverType);
468 }
469 }
470
471 QString oldReceiverNumber = settings.value("reqcOldReceiverNumber").toString();
472 QString newReceiverNumber = settings.value("reqcNewReceiverNumber").toString();
473 if (!newReceiverNumber.isEmpty()) {
474 if (oldReceiverNumber.isEmpty() ||
475 QRegExp(oldReceiverNumber).exactMatch(obsFile.receiverNumber())) {
476 obsFile.setReceiverNumber(newReceiverNumber);
477 }
478 }
479}
480
481//
482////////////////////////////////////////////////////////////////////////////
483void t_reqcEdit::rememberLLI(const t_rnxObsFile* obsFile,
484 const t_rnxObsFile::t_rnxEpo* epo) {
485
486 if (_samplingRate == 0) {
487 return;
488 }
489
490 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
491 const t_rnxObsFile::t_rnxSat& rnxSat = epo->rnxSat[iSat];
492 char sys = rnxSat.prn.system();
493 QString prn(rnxSat.prn.toString().c_str());
494
495 for (int iType = 0; iType < obsFile->nTypes(sys); iType++) {
496 QString type = obsFile->obsType(sys, iType);
497 if (!_lli[prn].contains(iType)) {
498 _lli[prn][iType] = 0;
499 }
500 if (rnxSat.obs.contains(type) && rnxSat.obs[type].lli & 1) {
501 _lli[prn][iType] |= 1;
502 }
503 }
504 }
505}
506
507//
508////////////////////////////////////////////////////////////////////////////
509void t_reqcEdit::applyLLI(const t_rnxObsFile* obsFile,
510 t_rnxObsFile::t_rnxEpo* epo) {
511
512 if (_samplingRate == 0) {
513 return;
514 }
515
516 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
517 t_rnxObsFile::t_rnxSat& rnxSat = epo->rnxSat[iSat];
518 char sys = rnxSat.prn.system();
519 QString prn(rnxSat.prn.toString().c_str());
520
521 for (int iType = 0; iType < obsFile->nTypes(sys); iType++) {
522 QString type = obsFile->obsType(sys, iType);
523 if (_lli[prn].contains(iType) && _lli[prn][iType] & 1) {
524 if (rnxSat.obs.contains(type)) {
525 rnxSat.obs[type].lli |= 1;
526 }
527 }
528 }
529 }
530
531 _lli.clear();
532}
533
534// Remove satellites below the minimum elevation angle
535////////////////////////////////////////////////////////////////////////////
536void t_reqcEdit::applyElevationMask(const t_rnxObsFile* obsFile,
537 t_rnxObsFile::t_rnxEpo* epo) {
538
539 const ColumnVector& xyzSta = obsFile->xyz();
540 if (xyzSta.size() != 3 || (xyzSta(1) == 0.0 && xyzSta(2) == 0.0 && xyzSta(3) == 0.0)) {
541 return;
542 }
543
544 std::vector<t_rnxObsFile::t_rnxSat> keptSats;
545 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
546 const t_rnxObsFile::t_rnxSat& rnxSat = epo->rnxSat[iSat];
547
548 t_eph* eph = 0;
549 for (int ie = 0; ie < _ephs.size(); ie++) {
550 if (_ephs[ie]->prn() == rnxSat.prn) {
551 eph = _ephs[ie];
552 break;
553 }
554 }
555 if (eph) {
556 ColumnVector xc(6);
557 ColumnVector vv(3);
558 if (eph->getCrd(epo->tt, xc, vv, false) == success) {
559 double rho, eleSat, azSat;
560 topos(xyzSta(1), xyzSta(2), xyzSta(3), xc(1), xc(2), xc(3), rho, eleSat, azSat);
561 if (eleSat * 180.0/M_PI < _minEle) {
562 continue;
563 }
564 }
565 }
566 keptSats.push_back(rnxSat);
567 }
568 epo->rnxSat = keptSats;
569}
570
571/// Read All Ephemerides
572////////////////////////////////////////////////////////////////////////////
573void t_reqcEdit::readEphemerides(const QStringList& navFileNames,
574 QVector<t_eph*>& ephs, QTextStream* log,
575 bool checkEph) {
576
577 QStringListIterator it(navFileNames);
578 while (it.hasNext()) {
579 QString fileName = it.next();
580 if (fileName.indexOf('*') != -1 ||
581 fileName.indexOf('?') != -1) {
582 QFileInfo fileInfo(fileName);
583 QDir dir = fileInfo.dir();
584 QStringList filters; filters << fileInfo.fileName();
585 QListIterator<QFileInfo> it(dir.entryInfoList(filters));
586 while (it.hasNext()) {
587 QString filePath = it.next().filePath();
588 appendEphemerides(filePath, ephs, log, checkEph);
589 }
590 }
591 else {
592 appendEphemerides(fileName, ephs, log, checkEph);
593 }
594 }
595 // TODO: enable user decision
596 std::stable_sort(ephs.begin(), ephs.end(), t_eph::earlierTime);
597 //std::stable_sort(ephs.begin(), ephs.end(), t_eph::prnSort);
598}
599
600//
601////////////////////////////////////////////////////////////////////////////
602void t_reqcEdit::editEphemerides() {
603
604 // Easy Exit
605 // ---------
606 if (_navFileNames.isEmpty() || _outNavFileName.isEmpty()) {
607 return;
608 }
609 // Concatenate all comments and all run by date lines
610 // --------------------------------------------------
611 QStringList comments;
612 QStringList runByDate;
613 bncSettings settings;
614 QString comment = settings.value("reqcComment").toString();
615 if (!comment.isEmpty()) {
616 comments.append(comment);
617 }
618 QStringListIterator it(_navFileNames);
619 while (it.hasNext()) {
620 QString fileName = it.next();
621
622 t_rnxNavFile rnxNavFile(fileName, t_rnxNavFile::input);
623 QStringListIterator itCmnt(rnxNavFile.comments());
624 while (itCmnt.hasNext()) {
625 comments.append(itCmnt.next());
626 }
627 QStringListIterator itRunByDt(rnxNavFile.runByDate());
628 while (itRunByDt.hasNext()) {
629 runByDate.append(itRunByDt.next());
630 }
631 }
632 comments.removeDuplicates();
633 runByDate.removeDuplicates();
634
635 // Read Ephemerides
636 // ----------------
637 t_reqcEdit::readEphemerides(_navFileNames, _ephs, _logStream, _checkEph);
638
639 // Check Satellite Systems
640 // -----------------------
641 bool haveGPS = false;
642 bool haveGlonass = false;
643 QMap<t_eph::e_system, bool> haveGnss;
644 for (int ii = 0; ii < _ephs.size(); ii++) {
645 const t_eph* eph = _ephs[ii];
646 switch (eph->system()) {
647 case t_eph::GPS:
648 haveGPS = true;
649 haveGnss[t_eph::GPS] = true;
650 break;
651 case t_eph::GLONASS:
652 haveGlonass = true;
653 haveGnss[t_eph::GLONASS] = true;
654 break;
655 case t_eph::Galileo:
656 haveGnss[t_eph::Galileo] = true;
657 break;
658 case t_eph::BDS:
659 haveGnss[t_eph::BDS] = true;
660 break;
661 case t_eph::QZSS:
662 haveGnss[t_eph::QZSS] = true;
663 break;
664 case t_eph::NavIC:
665 haveGnss[t_eph::NavIC] = true;
666 break;
667 case t_eph::SBAS:
668 haveGnss[t_eph::SBAS] = true;
669 break;
670 default:
671 haveGnss[t_eph::unknown] = true;
672 }
673 }
674
675 // Initialize output navigation file
676 // ---------------------------------
677 t_rnxNavFile outNavFile(_outNavFileName, t_rnxNavFile::output);
678
679 outNavFile.setGlonass(haveGlonass);
680
681 if (_rnxVersion < 3.0) {
682 if (haveGPS && haveGlonass) {
683 outNavFile.setVersion(defaultRnxNavVersion3);
684 }
685 if (haveGPS && !haveGlonass) {
686 outNavFile.setVersion(defaultRnxNavVersion2);
687 }
688 if (!haveGPS && haveGlonass) {
689 outNavFile.setVersion(defaultRnxNavVersion2);
690 }
691 }
692
693 if (_rnxVersion >= 3.0 && _rnxVersion < 4.0) {
694 outNavFile.setVersion(defaultRnxNavVersion3);
695 }
696
697 if (_rnxVersion >= 4.0) {
698 outNavFile.setVersion(defaultRnxNavVersion4);
699 }
700
701 if (outNavFile.version() > 3.0) {
702 if (haveGnss.size() > 1) {
703 outNavFile.setGnssTypeV3(t_eph::unknown);
704 }
705 else if (haveGnss.size() == 1){
706 outNavFile.setGnssTypeV3(haveGnss.keys().first());
707 }
708 }
709
710 QMap<QString, QString> txtMap;
711 QString runBy = settings.value("reqcRunBy").toString();
712 if (!runBy.isEmpty()) {
713 txtMap["RUN BY"] = runBy;
714 }
715 if (!runByDate.empty()) {
716 txtMap["RUN BY DATE"] = runByDate.join("\\n");
717 }
718 if (!comments.isEmpty()) {
719 txtMap["COMMENT"] = comments.join("\\n");
720 }
721
722 int mergedNavFiles = _navFileNames.size();
723 unsigned year, month, day;
724 int gps_utc = 0;
725 if (_ephs.size()) {
726 _ephs.at(0)->TOC().civil_date(year, month, day);
727 gps_utc = gnumleap(year, month, day);
728 }
729 outNavFile.writeHeader(&txtMap, mergedNavFiles, gps_utc);
730
731 // Loop over all ephemerides
732 // -------------------------
733 for (int ii = 0; ii < _ephs.size(); ii++) {
734 const t_eph* eph = _ephs[ii];
735 bncTime begTime = _begTime;
736 bncTime endTime = _endTime;
737 if (eph->system() == t_eph::BDS) {
738 begTime += 14;
739 endTime += 14;
740 }
741 if (begTime.valid() && eph->TOC() < begTime) {
742 continue;
743 }
744 if (endTime.valid() && eph->TOC() > endTime) {
745 break;
746 }
747 if (eph->checkState() == t_eph::bad) {
748 continue;
749 }
750
751 if (outNavFile.version() < 3.0) {
752 if (outNavFile.glonass() && eph->system() != t_eph::GLONASS) {
753 continue;
754 }
755 if (!outNavFile.glonass() && eph->system() != t_eph::GPS) {
756 continue;
757 }
758 }
759 outNavFile.writeEph(eph);
760 }
761}
762
763//
764////////////////////////////////////////////////////////////////////////////
765void t_reqcEdit::appendEphemerides(const QString& fileName,
766 QVector<t_eph*>& ephs, QTextStream* log,
767 bool checkEph) {
768 t_rnxNavFile rnxNavFile(fileName, t_rnxNavFile::input);
769 unsigned numOK = 0;
770 unsigned numBad = 0;
771 unsigned numUnhealthy = 0;
772 bncEphUser ephUser(false);
773
774 if (log) {
775 QFileInfo navFi(rnxNavFile.fileName());
776 *log << "Input Nav File : " << navFi.fileName() << Qt::endl;
777 if (checkEph) {
778 *log << "RINEX Version : " << rnxNavFile.version() << Qt::endl;
779 }
780 }
781
782 for (unsigned ii = 0; ii < rnxNavFile.ephs().size(); ii++) {
783 t_eph* eph = rnxNavFile.ephs()[ii];
784 bool isNew = true;
785 for (int iOld = 0; iOld < ephs.size(); iOld++) {
786 const t_eph* ephOld = ephs[iOld];
787 if (ephOld->prn() == eph->prn() &&
788 ephOld->TOC() == eph->TOC()) {
789 isNew = false;
790 break;
791 }
792 }
793
794 if (isNew) {
795
796 if (checkEph) {
797 ephUser.putNewEph(eph, false);
798 if (eph->checkState() == t_eph::bad) {
799 ++numBad;
800 }
801 else if (eph->checkState() == t_eph::unhealthy) {
802 ++numUnhealthy;
803 }
804 else {
805 ++numOK;
806 }
807 if (eph->checkState() == t_eph::bad) {
808 continue;
809 }
810 }
811
812 if (eph->system() == t_eph::GPS) {
813 ephs.append(new t_ephGPS(*dynamic_cast<t_ephGPS*>(eph)));
814 }
815 else if (eph->system() == t_eph::GLONASS) {
816 ephs.append(new t_ephGlo(*dynamic_cast<t_ephGlo*>(eph)));
817 }
818 else if (eph->system() == t_eph::Galileo) {
819 ephs.append(new t_ephGal(*dynamic_cast<t_ephGal*>(eph)));
820 }
821 else if (eph->system() == t_eph::QZSS) {
822 ephs.append(new t_ephGPS(*dynamic_cast<t_ephGPS*>(eph)));
823 }
824 else if (eph->system() == t_eph::SBAS) {
825 ephs.append(new t_ephSBAS(*dynamic_cast<t_ephSBAS*>(eph)));
826 }
827 else if (eph->system() == t_eph::BDS) {
828 ephs.append(new t_ephBDS(*dynamic_cast<t_ephBDS*>(eph)));
829 }
830 else if (eph->system() == t_eph::NavIC) {
831 ephs.append(new t_ephGPS(*dynamic_cast<t_ephGPS*>(eph)));
832 }
833 }
834 }
835
836 if (log && checkEph) {
837 *log << "Ephemeris Check : " << numOK << " OK "
838 << numUnhealthy << " UNHEALTHY "
839 << numBad << " WRONG\n";
840 if (numBad > 0) {
841 for (unsigned ii = 0; ii < rnxNavFile.ephs().size(); ii++) {
842 t_eph* eph = rnxNavFile.ephs()[ii];
843 QFileInfo navFi(fileName);
844 if (eph->checkState() == t_eph::bad) {
845 if (log) {
846 *log << " : "
847 << QString("WRONG %2:%3\n")
848 .arg(eph->typeStr(eph->type(), eph->prn(), 99.0))
849 .arg(eph->rinexDateStr(eph->TOC(), eph->prn(), 99.0)).toLatin1();
850 }
851 }/* switched off because of to many SBAS satellites are set to unhealthy
852 if (eph->checkState() == t_eph::unhealthy) {
853 if (log) {
854 *log << " : "
855 << QString("UNHEALTHY %2:%3\n")
856 .arg(eph->typeStr(eph->type(), eph->prn(), 99.0))
857 .arg(eph->rinexDateStr(eph->TOC(), eph->prn(), 99.0)).toLatin1();
858 }
859 }*/
860 }
861 }
862 *log << Qt::endl;
863 }
864}
865
866void t_reqcEdit::addRnxConversionDetails(const t_rnxObsFile* obsFile,
867 QMap<QString, QString>& txtMap) {
868
869 int key = 0;
870 QString systems = obsFile->header().usedSystems();
871 QString comment = QString("Signal priorities for RINEX 3 => 2 conversion:");
872 QString commentKey = QString("COMMENT %1").arg(key, 3, 10, QChar('0'));
873 txtMap.insert(commentKey, comment);
874
875 for(int ii = 0; ii < obsFile->numSys(); ii++) {
876 char sys = systems[ii].toLatin1();
877 txtMap.insert(commentKey, comment);
878 QMap <char, QString> signalPriorityMap;
879 QStringList preferredAttribListSys = obsFile->signalPriorities(sys);
880 QStringList types = obsFile->header().obsTypes(sys);
881 for (int jj = 0; jj < types.size(); jj++) {
882 QString inType = types[jj];
883 char band = inType[1].toLatin1();
884 for (int ii = 0; ii < preferredAttribListSys.size(); ii++) {
885 QString preferredAttrib;
886 if (preferredAttribListSys[ii].indexOf("&") != -1) {
887 QStringList hlp = preferredAttribListSys[ii].split("&", Qt::SkipEmptyParts);
888 if (hlp.size() == 2 && hlp[0].contains(band)) {
889 preferredAttrib = hlp[1];
890 }
891 }
892 else {
893 preferredAttrib = preferredAttribListSys[ii];
894 }
895 if (!signalPriorityMap.contains(band) && !preferredAttrib.isEmpty()){
896 signalPriorityMap[band] = preferredAttrib;
897 }
898 }
899 }
900 QMapIterator<char, QString> it(signalPriorityMap);
901 while (it.hasNext()) {
902 it.next();
903 key++;
904 comment = QString("%1 band %2: %3").arg(sys).arg(it.key()).arg(it.value());
905 commentKey = QString("COMMENT %1").arg(key, 3, 10, QChar('0'));
906 txtMap.insert(commentKey, comment);
907 }
908 }
909}
Note: See TracBrowser for help on using the repository browser.