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

Last change on this file since 10945 was 10945, checked in by stuerze, 8 weeks ago

Added a Minimum Elevation parameter to BNC's RINEX Editing & QC feature

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