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
RevLine 
[3901]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 *
[7474]37 * Changes:
[3901]38 *
39 * -----------------------------------------------------------------------*/
40
41#include <iostream>
42#include "reqcedit.h"
[5070]43#include "bnccore.h"
[3901]44#include "bncsettings.h"
[4516]45#include "bncutils.h"
[5378]46#include "rnxobsfile.h"
47#include "rnxnavfile.h"
[3901]48
49using namespace std;
50
51// Constructor
52////////////////////////////////////////////////////////////////////////////
53t_reqcEdit::t_reqcEdit(QObject* parent) : QThread(parent) {
54
55 bncSettings settings;
56
[4516]57 _logFileName = settings.value("reqcOutLogFile").toString(); expandEnvVar(_logFileName);
58 _logFile = 0;
[10630]59 _logStream = 0;
[10548]60 _obsFileNames = settings.value("reqcObsFile").toString().split(",", Qt::SkipEmptyParts);
[3901]61 _outObsFileName = settings.value("reqcOutObsFile").toString();
[10548]62 _navFileNames = settings.value("reqcNavFile").toString().split(",", Qt::SkipEmptyParts);
[3999]63 _outNavFileName = settings.value("reqcOutNavFile").toString();
[4010]64 int version = settings.value("reqcRnxVersion").toInt();
[9765]65 if (version == 2) {
[8127]66 _rnxVersion = defaultRnxObsVersion2;
[4010]67 }
[9770]68 else if (version == 3) {
[8127]69 _rnxVersion = defaultRnxObsVersion3;
[4010]70 }
[9770]71 else if (version == 4) {
[9765]72 _rnxVersion = defaultRnxObsVersion4;
73 }
[8397]74 _samplingRate = settings.value("reqcSampling").toString().split("sec").first().toDouble();
[10945]75 _minEle = settings.value("reqcMinEle").toDouble();
[8204]76 _begTime = bncTime(settings.value("reqcStartDateTime").toString().toLatin1().data());
77 _endTime = bncTime(settings.value("reqcEndDateTime").toString().toLatin1().data());
[6898]78
[10614]79 _checkEph = false;
80
[3901]81}
82
83// Destructor
84////////////////////////////////////////////////////////////////////////////
85t_reqcEdit::~t_reqcEdit() {
86 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
87 delete _rnxObsFiles[ii];
88 }
[4001]89 for (int ii = 0; ii < _ephs.size(); ii++) {
90 delete _ephs[ii];
91 }
[10630]92 delete _logStream; _logStream = 0;
[4516]93 delete _logFile; _logFile = 0;
[3901]94}
95
[7474]96//
[3901]97////////////////////////////////////////////////////////////////////////////
98void t_reqcEdit::run() {
[7474]99
[4516]100 // Open Log File
101 // -------------
[7280]102 if (!_logFileName.isEmpty()) {
103 _logFile = new QFile(_logFileName);
104 if (_logFile->open(QIODevice::WriteOnly | QIODevice::Text)) {
[10630]105 _logStream = new QTextStream();
106 _logStream->setDevice(_logFile);
[7280]107 }
[4518]108 }
[4516]109
[4518]110 // Log File Header
111 // ---------------
[10630]112 if (_logStream) {
113 *_logStream << QByteArray(78, '-') << Qt::endl;
114 *_logStream << "RINEX File Editing\n";
115 *_logStream << QByteArray(78, '-') << Qt::endl;
[4520]116
[10630]117 *_logStream << QByteArray("Program").leftJustified(15) << ": "
[10561]118 << BNC_CORE->pgmName() << Qt::endl;
[10630]119 *_logStream << QByteArray("Run by").leftJustified(15) << ": "
[10561]120 << BNC_CORE->userName() << Qt::endl;
[10630]121 *_logStream << QByteArray("Date").leftJustified(15) << ": "
[10561]122 << QDateTime::currentDateTime().toUTC().toString("yyyy-MM-dd hh:mm:ss") << Qt::endl;
[10630]123 *_logStream << QByteArray("RINEX Version").leftJustified(15) << ": "
[10561]124 << _rnxVersion << Qt::endl;
[10630]125 *_logStream << QByteArray("Sampling").leftJustified(15) << ": "
[10561]126 << _samplingRate << " sec" << Qt::endl;
[10630]127 *_logStream << QByteArray("Start time").leftJustified(15) << ": "
[7474]128 << _begTime.datestr().c_str() << ' '
[10561]129 << _begTime.timestr(0).c_str() << Qt::endl;
[10630]130 *_logStream << QByteArray("End time").leftJustified(15) << ": "
[7474]131 << _endTime.datestr().c_str() << ' '
[10561]132 << _endTime.timestr(0).c_str() << Qt::endl;
[10630]133 *_logStream << QByteArray("Input Obs Files").leftJustified(15) << ": "
[10561]134 << _obsFileNames.join(",") << Qt::endl;
[10630]135 *_logStream << QByteArray("Input Nav Files").leftJustified(15) << ": "
[10561]136 << _navFileNames.join(",") << Qt::endl;
[10630]137 *_logStream << QByteArray("Output Obs File").leftJustified(15) << ": "
[10561]138 << _outObsFileName << Qt::endl;
[10630]139 *_logStream << QByteArray("Output Nav File").leftJustified(15) << ": "
[10561]140 << _outNavFileName << Qt::endl;
[4520]141
[10630]142 *_logStream << QByteArray(78, '-') << Qt::endl;
143 _logStream->flush();
[4518]144 }
145
[4516]146 // Handle Observation Files
147 // ------------------------
[3998]148 editObservations();
[3901]149
[4516]150 // Handle Navigations Files
151 // ------------------------
[3998]152 editEphemerides();
153
[4516]154 // Exit (thread)
155 // -------------
[5072]156 if (BNC_CORE->mode() != t_bncCore::interactive) {
[9854]157 qApp->exit(9);
[7942]158 msleep(100); //sleep 0.1 sec
[3998]159 }
160 else {
161 emit finished();
162 deleteLater();
163 }
[7980]164
[3998]165}
166
[4254]167// Initialize input observation files, sort them according to start time
[3998]168////////////////////////////////////////////////////////////////////////////
[7474]169void t_reqcEdit::initRnxObsFiles(const QStringList& obsFileNames,
[4525]170 QVector<t_rnxObsFile*>& rnxObsFiles,
171 QTextStream* log) {
[3998]172
[4254]173 QStringListIterator it(obsFileNames);
[3901]174 while (it.hasNext()) {
175 QString fileName = it.next();
[10614]176 if (fileName.indexOf('*') != -1 ||
177 fileName.indexOf('?') != -1) {
[4080]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()) {
[7474]183 QString filePath = it.next().filePath();
[4364]184 t_rnxObsFile* rnxObsFile = 0;
[4363]185 try {
[4364]186 rnxObsFile = new t_rnxObsFile(filePath, t_rnxObsFile::input);
[4363]187 rnxObsFiles.append(rnxObsFile);
188 }
189 catch (...) {
[4364]190 delete rnxObsFile;
[4525]191 if (log) {
[10561]192 *log << "Error in rnxObsFile " << filePath.toLatin1().data() << Qt::endl;
[4525]193 }
[4363]194 }
[4080]195 }
196 }
197 else {
[4364]198 t_rnxObsFile* rnxObsFile = 0;
[4363]199 try {
[4364]200 rnxObsFile = new t_rnxObsFile(fileName, t_rnxObsFile::input);
[4363]201 rnxObsFiles.append(rnxObsFile);
202 }
203 catch (...) {
[4525]204 if (log) {
[10561]205 *log << "Error in rnxObsFile " << fileName.toLatin1().data() << Qt::endl;
[4525]206 }
[4363]207 }
[4080]208 }
[3901]209 }
[10525]210 std::stable_sort(rnxObsFiles.begin(), rnxObsFiles.end(),
[3901]211 t_rnxObsFile::earlierStartTime);
[4254]212}
[3901]213
[7474]214//
[4254]215////////////////////////////////////////////////////////////////////////////
216void t_reqcEdit::editObservations() {
217
218 // Easy Exit
219 // ---------
220 if (_obsFileNames.isEmpty() || _outObsFileName.isEmpty()) {
221 return;
222 }
223
[10630]224 t_reqcEdit::initRnxObsFiles(_obsFileNames, _rnxObsFiles, _logStream);
[4254]225
[10945]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
[3901]232 // Initialize output observation file
233 // ----------------------------------
234 t_rnxObsFile outObsFile(_outObsFileName, t_rnxObsFile::output);
[7474]235
[9945]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
[6118]251 // Select observation types
252 // ------------------------
253 bncSettings settings;
[10548]254 QStringList useObsTypes = settings.value("reqcUseObsTypes").toString().split(" ", Qt::SkipEmptyParts);
[6118]255
[6130]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 != ' ') {
[6131]264 for (int iType = 0; iType < obsFile->nTypes(sys); iType++) {
265 QString type = obsFile->obsType(sys, iType);
[6132]266 if (_rnxVersion < 3.0) {
267 useObsTypes << type;
268 }
269 else {
270 useObsTypes << QString(sys) + ":" + type;
271 }
[6131]272 }
[6130]273 }
274 }
275 }
[6132]276 useObsTypes.removeDuplicates();
[6130]277 }
278
[6841]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 }
[9639]287 phaseShifts.removeDuplicates();
[6841]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
[3901]323 // Loop over all input observation files
324 // -------------------------------------
325 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
326 t_rnxObsFile* obsFile = _rnxObsFiles[ii];
[10630]327 if (_logStream) {
328 *_logStream << "Input Obs File: " << obsFile->fileName() << " start: "
[7474]329 << obsFile->startTime().datestr().c_str() << ' '
[10561]330 << obsFile->startTime().timestr(0).c_str() << Qt::endl;
[4524]331 }
[3901]332 if (ii == 0) {
[6841]333 outObsFile.setHeader(obsFile->header(), int(_rnxVersion), &useObsTypes,
[9945]334 &phaseShifts, &gloBiases, &gloSlots, &runByDate);
[3992]335 if (_begTime.valid() && _begTime > outObsFile.startTime()) {
336 outObsFile.setStartTime(_begTime);
337 }
[4112]338 if (_samplingRate > outObsFile.interval()) {
339 outObsFile.setInterval(_samplingRate);
340 }
[3982]341 editRnxObsHeader(outObsFile);
[4117]342 bncSettings settings;
[4114]343 QMap<QString, QString> txtMap;
[4117]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 }
[7474]352 if (int(_rnxVersion) < int(obsFile->header().version())) {
353 addRnxConversionDetails(obsFile, txtMap);
354 }
[4514]355 outObsFile.header().write(outObsFile.stream(), &txtMap);
[3901]356 }
[3994]357 t_rnxObsFile::t_rnxEpo* epo = 0;
[4541]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 }
[7474]366
[8372]367 int sec = int(nint(epo->tt.gpssec()*10));
[8397]368 if (sec % (int(_samplingRate)*10) == 0) {
[4541]369 applyLLI(obsFile, epo);
[10945]370 if (_minEle > 0.0) {
371 applyElevationMask(obsFile, epo);
372 }
[4541]373 outObsFile.writeEpoch(epo);
374 }
375 else {
376 rememberLLI(obsFile, epo);
377 }
[3993]378 }
[4541]379 }
380 catch (QString str) {
[10630]381 if (_logStream) {
382 *_logStream << "Exception " << str << Qt::endl;
[3993]383 }
[3994]384 else {
[7474]385 qDebug() << str;
[3994]386 }
[4541]387 return;
[3901]388 }
[6130]389 catch (...) {
[10630]390 if (_logStream) {
391 *_logStream << "Exception unknown" << Qt::endl;
[6130]392 }
393 else {
394 qDebug() << "Exception unknown";
395 }
396 return;
397 }
[3901]398 }
399}
[3982]400
[7474]401// Change RINEX Header Content
[3982]402////////////////////////////////////////////////////////////////////////////
[3985]403void t_reqcEdit::editRnxObsHeader(t_rnxObsFile& obsFile) {
[3982]404
[3983]405 bncSettings settings;
406
407 QString oldMarkerName = settings.value("reqcOldMarkerName").toString();
408 QString newMarkerName = settings.value("reqcNewMarkerName").toString();
[4090]409 if (!newMarkerName.isEmpty()) {
[7474]410 if (oldMarkerName.isEmpty() ||
[4090]411 QRegExp(oldMarkerName).exactMatch(obsFile.markerName())) {
412 obsFile.setMarkerName(newMarkerName);
413 }
[3985]414 }
415
[3983]416 QString oldAntennaName = settings.value("reqcOldAntennaName").toString();
417 QString newAntennaName = settings.value("reqcNewAntennaName").toString();
[4090]418 if (!newAntennaName.isEmpty()) {
[7474]419 if (oldAntennaName.isEmpty() ||
[4090]420 QRegExp(oldAntennaName).exactMatch(obsFile.antennaName())) {
421 obsFile.setAntennaName(newAntennaName);
422 }
[3985]423 }
[3983]424
[6795]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
[3985]460 QString oldReceiverType = settings.value("reqcOldReceiverName").toString();
461 QString newReceiverType = settings.value("reqcNewReceiverName").toString();
[4090]462 if (!newReceiverType.isEmpty()) {
[7474]463 if (oldReceiverType.isEmpty() ||
[4090]464 QRegExp(oldReceiverType).exactMatch(obsFile.receiverType())) {
465 obsFile.setReceiverType(newReceiverType);
466 }
[3985]467 }
[6795]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 }
[3982]477}
[3994]478
[7474]479//
[3994]480////////////////////////////////////////////////////////////////////////////
[7474]481void t_reqcEdit::rememberLLI(const t_rnxObsFile* obsFile,
[3995]482 const t_rnxObsFile::t_rnxEpo* epo) {
[3994]483
[3995]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];
[6121]490 char sys = rnxSat.prn.system();
491 QString prn(rnxSat.prn.toString().c_str());
[3997]492
[3995]493 for (int iType = 0; iType < obsFile->nTypes(sys); iType++) {
[6121]494 QString type = obsFile->obsType(sys, iType);
[3997]495 if (!_lli[prn].contains(iType)) {
496 _lli[prn][iType] = 0;
[3996]497 }
[6121]498 if (rnxSat.obs.contains(type) && rnxSat.obs[type].lli & 1) {
[3997]499 _lli[prn][iType] |= 1;
[3996]500 }
[3995]501 }
502 }
[3994]503}
[7474]504
505//
[3994]506////////////////////////////////////////////////////////////////////////////
[7474]507void t_reqcEdit::applyLLI(const t_rnxObsFile* obsFile,
[3995]508 t_rnxObsFile::t_rnxEpo* epo) {
[7474]509
[3996]510 if (_samplingRate == 0) {
[3995]511 return;
512 }
[3996]513
514 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
515 t_rnxObsFile::t_rnxSat& rnxSat = epo->rnxSat[iSat];
[6121]516 char sys = rnxSat.prn.system();
517 QString prn(rnxSat.prn.toString().c_str());
[3997]518
[3996]519 for (int iType = 0; iType < obsFile->nTypes(sys); iType++) {
[6121]520 QString type = obsFile->obsType(sys, iType);
[3997]521 if (_lli[prn].contains(iType) && _lli[prn][iType] & 1) {
[6121]522 if (rnxSat.obs.contains(type)) {
523 rnxSat.obs[type].lli |= 1;
524 }
[3996]525 }
526 }
527 }
528
529 _lli.clear();
[3994]530}
[3998]531
[10945]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
[4256]569/// Read All Ephemerides
[3998]570////////////////////////////////////////////////////////////////////////////
[4256]571void t_reqcEdit::readEphemerides(const QStringList& navFileNames,
[10614]572 QVector<t_eph*>& ephs, QTextStream* log,
573 bool checkEph) {
[3998]574
[4256]575 QStringListIterator it(navFileNames);
[3999]576 while (it.hasNext()) {
577 QString fileName = it.next();
[10614]578 if (fileName.indexOf('*') != -1 ||
579 fileName.indexOf('?') != -1) {
[4081]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()) {
[7474]585 QString filePath = it.next().filePath();
[10614]586 appendEphemerides(filePath, ephs, log, checkEph);
[4000]587 }
588 }
[4081]589 else {
[10614]590 appendEphemerides(fileName, ephs, log, checkEph);
[4081]591 }
[3999]592 }
[9366]593 // TODO: enable user decision
[10525]594 std::stable_sort(ephs.begin(), ephs.end(), t_eph::earlierTime);
595 //std::stable_sort(ephs.begin(), ephs.end(), t_eph::prnSort);
[4256]596}
[3999]597
[7474]598//
[4256]599////////////////////////////////////////////////////////////////////////////
600void t_reqcEdit::editEphemerides() {
601
602 // Easy Exit
603 // ---------
604 if (_navFileNames.isEmpty() || _outNavFileName.isEmpty()) {
605 return;
606 }
[9945]607 // Concatenate all comments and all run by date lines
608 // --------------------------------------------------
[7999]609 QStringList comments;
[9945]610 QStringList runByDate;
[7999]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();
[10614]619
[7999]620 t_rnxNavFile rnxNavFile(fileName, t_rnxNavFile::input);
621 QStringListIterator itCmnt(rnxNavFile.comments());
622 while (itCmnt.hasNext()) {
623 comments.append(itCmnt.next());
624 }
[9945]625 QStringListIterator itRunByDt(rnxNavFile.runByDate());
626 while (itRunByDt.hasNext()) {
627 runByDate.append(itRunByDt.next());
628 }
[7999]629 }
630 comments.removeDuplicates();
[9945]631 runByDate.removeDuplicates();
[4256]632
[4257]633 // Read Ephemerides
634 // ----------------
[10630]635 t_reqcEdit::readEphemerides(_navFileNames, _ephs, _logStream, _checkEph);
[4256]636
[4229]637 // Check Satellite Systems
638 // -----------------------
639 bool haveGPS = false;
640 bool haveGlonass = false;
[10587]641 QMap<t_eph::e_system, bool> haveGnss;
[4229]642 for (int ii = 0; ii < _ephs.size(); ii++) {
643 const t_eph* eph = _ephs[ii];
[10587]644 switch (eph->system()) {
[8354]645 case t_eph::GPS:
646 haveGPS = true;
[8655]647 haveGnss[t_eph::GPS] = true;
[8354]648 break;
649 case t_eph::GLONASS:
650 haveGlonass = true;
[8655]651 haveGnss[t_eph::GLONASS] = true;
[8354]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;
[10619]662 case t_eph::NavIC:
663 haveGnss[t_eph::NavIC] = true;
[8354]664 break;
665 case t_eph::SBAS:
666 haveGnss[t_eph::SBAS] = true;
667 break;
668 default:
669 haveGnss[t_eph::unknown] = true;
[4229]670 }
671 }
672
[4007]673 // Initialize output navigation file
674 // ---------------------------------
[4004]675 t_rnxNavFile outNavFile(_outNavFileName, t_rnxNavFile::output);
[4229]676
677 outNavFile.setGlonass(haveGlonass);
678
[9765]679 if (_rnxVersion < 3.0) {
680 if (haveGPS && haveGlonass) {
681 outNavFile.setVersion(defaultRnxNavVersion3);
682 }
683 if (haveGPS && !haveGlonass) {
684 outNavFile.setVersion(defaultRnxNavVersion2);
685 }
[9945]686 if (!haveGPS && haveGlonass) {
687 outNavFile.setVersion(defaultRnxNavVersion2);
688 }
[9765]689 }
690
691 if (_rnxVersion >= 3.0 && _rnxVersion < 4.0) {
[8127]692 outNavFile.setVersion(defaultRnxNavVersion3);
[4229]693 }
[9765]694
695 if (_rnxVersion >= 4.0) {
696 outNavFile.setVersion(defaultRnxNavVersion4);
[4229]697 }
698
[8354]699 if (outNavFile.version() > 3.0) {
700 if (haveGnss.size() > 1) {
701 outNavFile.setGnssTypeV3(t_eph::unknown);
702 }
703 else if (haveGnss.size() == 1){
[8355]704 outNavFile.setGnssTypeV3(haveGnss.keys().first());
[8354]705 }
706 }
707
[4221]708 QMap<QString, QString> txtMap;
709 QString runBy = settings.value("reqcRunBy").toString();
710 if (!runBy.isEmpty()) {
711 txtMap["RUN BY"] = runBy;
712 }
[9945]713 if (!runByDate.empty()) {
714 txtMap["RUN BY DATE"] = runByDate.join("\\n");
715 }
[7999]716 if (!comments.isEmpty()) {
717 txtMap["COMMENT"] = comments.join("\\n");
[4221]718 }
[4229]719
[9765]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);
[4009]728
[4004]729 // Loop over all ephemerides
730 // -------------------------
731 for (int ii = 0; ii < _ephs.size(); ii++) {
732 const t_eph* eph = _ephs[ii];
[6954]733 bncTime begTime = _begTime;
734 bncTime endTime = _endTime;
[10587]735 if (eph->system() == t_eph::BDS) {
[6954]736 begTime += 14;
737 endTime += 14;
738 }
739 if (begTime.valid() && eph->TOC() < begTime) {
[6898]740 continue;
741 }
[6954]742 if (endTime.valid() && eph->TOC() > endTime) {
[6898]743 break;
744 }
[8437]745 if (eph->checkState() == t_eph::bad) {
[8368]746 continue;
747 }
[9945]748
749 if (outNavFile.version() < 3.0) {
[10587]750 if (outNavFile.glonass() && eph->system() != t_eph::GLONASS) {
[9945]751 continue;
752 }
[10587]753 if (!outNavFile.glonass() && eph->system() != t_eph::GPS) {
[9945]754 continue;
755 }
756 }
[4229]757 outNavFile.writeEph(eph);
[4004]758 }
[3998]759}
[4081]760
[7474]761//
[4081]762////////////////////////////////////////////////////////////////////////////
[4256]763void t_reqcEdit::appendEphemerides(const QString& fileName,
[10614]764 QVector<t_eph*>& ephs, QTextStream* log,
765 bool checkEph) {
[4081]766 t_rnxNavFile rnxNavFile(fileName, t_rnxNavFile::input);
[10614]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
[4081]780 for (unsigned ii = 0; ii < rnxNavFile.ephs().size(); ii++) {
781 t_eph* eph = rnxNavFile.ephs()[ii];
782 bool isNew = true;
[4256]783 for (int iOld = 0; iOld < ephs.size(); iOld++) {
784 const t_eph* ephOld = ephs[iOld];
[6804]785 if (ephOld->prn() == eph->prn() &&
[6809]786 ephOld->TOC() == eph->TOC()) {
[4081]787 isNew = false;
788 break;
789 }
790 }
[9893]791
[4081]792 if (isNew) {
[10614]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) {
[4256]811 ephs.append(new t_ephGPS(*dynamic_cast<t_ephGPS*>(eph)));
[4081]812 }
[10614]813 else if (eph->system() == t_eph::GLONASS) {
[4256]814 ephs.append(new t_ephGlo(*dynamic_cast<t_ephGlo*>(eph)));
[4081]815 }
[10614]816 else if (eph->system() == t_eph::Galileo) {
[4256]817 ephs.append(new t_ephGal(*dynamic_cast<t_ephGal*>(eph)));
[4081]818 }
[10614]819 else if (eph->system() == t_eph::QZSS) {
[6377]820 ephs.append(new t_ephGPS(*dynamic_cast<t_ephGPS*>(eph)));
821 }
[10614]822 else if (eph->system() == t_eph::SBAS) {
[6391]823 ephs.append(new t_ephSBAS(*dynamic_cast<t_ephSBAS*>(eph)));
824 }
[10614]825 else if (eph->system() == t_eph::BDS) {
[6600]826 ephs.append(new t_ephBDS(*dynamic_cast<t_ephBDS*>(eph)));
[6402]827 }
[10619]828 else if (eph->system() == t_eph::NavIC) {
[8168]829 ephs.append(new t_ephGPS(*dynamic_cast<t_ephGPS*>(eph)));
830 }
[4081]831 }
832 }
[10614]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 << " : "
[10630]845 << QString("WRONG %2:%3\n")
[10614]846 .arg(eph->typeStr(eph->type(), eph->prn(), 99.0))
847 .arg(eph->rinexDateStr(eph->TOC(), eph->prn(), 99.0)).toLatin1();
848 }
[10630]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 }*/
[10614]858 }
859 }
860 *log << Qt::endl;
861 }
[4081]862}
[7474]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();
[7980]869 QString comment = QString("Signal priorities for RINEX 3 => 2 conversion:");
[7474]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++) {
[8204]874 char sys = systems[ii].toLatin1();
[7474]875 txtMap.insert(commentKey, comment);
[7980]876 QMap <char, QString> signalPriorityMap;
877 QStringList preferredAttribListSys = obsFile->signalPriorities(sys);
[7474]878 QStringList types = obsFile->header().obsTypes(sys);
879 for (int jj = 0; jj < types.size(); jj++) {
880 QString inType = types[jj];
[8204]881 char band = inType[1].toLatin1();
[7980]882 for (int ii = 0; ii < preferredAttribListSys.size(); ii++) {
883 QString preferredAttrib;
884 if (preferredAttribListSys[ii].indexOf("&") != -1) {
[10548]885 QStringList hlp = preferredAttribListSys[ii].split("&", Qt::SkipEmptyParts);
[7980]886 if (hlp.size() == 2 && hlp[0].contains(band)) {
887 preferredAttrib = hlp[1];
888 }
[7474]889 }
[7980]890 else {
891 preferredAttrib = preferredAttribListSys[ii];
892 }
893 if (!signalPriorityMap.contains(band) && !preferredAttrib.isEmpty()){
894 signalPriorityMap[band] = preferredAttrib;
895 }
[7474]896 }
897 }
[7980]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 }
[7474]906 }
907}
Note: See TracBrowser for help on using the repository browser.