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

Last change on this file since 7337 was 7280, checked in by weber, 10 years ago

Avoid error message through opening log file only if file name is specified

File size: 19.9 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 _log = 0;
60 _obsFileNames = settings.value("reqcObsFile").toString().split(",", QString::SkipEmptyParts);
61 _outObsFileName = settings.value("reqcOutObsFile").toString();
62 _navFileNames = settings.value("reqcNavFile").toString().split(",", QString::SkipEmptyParts);
63 _outNavFileName = settings.value("reqcOutNavFile").toString();
64 int version = settings.value("reqcRnxVersion").toInt();
65 if (version < 3) {
66 _rnxVersion = t_rnxObsHeader::defaultRnxObsVersion2;
67 }
68 else {
69 _rnxVersion = t_rnxObsHeader::defaultRnxObsVersion3;
70 }
71 _samplingRate = settings.value("reqcSampling").toInt();
72 _begTime = bncTime(settings.value("reqcStartDateTime").toString().toAscii().data());
73 _endTime = bncTime(settings.value("reqcEndDateTime").toString().toAscii().data());
74
75}
76
77// Destructor
78////////////////////////////////////////////////////////////////////////////
79t_reqcEdit::~t_reqcEdit() {
80 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
81 delete _rnxObsFiles[ii];
82 }
83 for (int ii = 0; ii < _ephs.size(); ii++) {
84 delete _ephs[ii];
85 }
86 delete _log; _log = 0;
87 delete _logFile; _logFile = 0;
88}
89
90//
91////////////////////////////////////////////////////////////////////////////
92void t_reqcEdit::run() {
93
94 // Open Log File
95 // -------------
96 if (!_logFileName.isEmpty()) {
97 _logFile = new QFile(_logFileName);
98 if (_logFile->open(QIODevice::WriteOnly | QIODevice::Text)) {
99 _log = new QTextStream();
100 _log->setDevice(_logFile);
101 }
102 }
103
104 // Log File Header
105 // ---------------
106 if (_log) {
107 *_log << QByteArray(78, '-') << endl;
108 *_log << "Concatenation of RINEX Observation and/or Navigation Files\n";
109 *_log << QByteArray(78, '-') << endl;
110
111 *_log << QByteArray("Program").leftJustified(15) << ": "
112 << BNC_CORE->pgmName() << endl;
113 *_log << QByteArray("Run by").leftJustified(15) << ": "
114 << BNC_CORE->userName() << endl;
115 *_log << QByteArray("Date").leftJustified(15) << ": "
116 << QDateTime::currentDateTime().toUTC().toString("yyyy-MM-dd hh:mm:ss") << endl;
117 *_log << QByteArray("RINEX Version").leftJustified(15) << ": "
118 << _rnxVersion << endl;
119 *_log << QByteArray("Sampling").leftJustified(15) << ": "
120 << _samplingRate << endl;
121 *_log << QByteArray("Start time").leftJustified(15) << ": "
122 << _begTime.datestr().c_str() << ' '
123 << _begTime.timestr(0).c_str() << endl;
124 *_log << QByteArray("End time").leftJustified(15) << ": "
125 << _endTime.datestr().c_str() << ' '
126 << _endTime.timestr(0).c_str() << endl;
127 *_log << QByteArray("Input Obs Files").leftJustified(15) << ": "
128 << _obsFileNames.join(",") << endl;
129 *_log << QByteArray("Input Nav Files").leftJustified(15) << ": "
130 << _navFileNames.join(",") << endl;
131 *_log << QByteArray("Output Obs File").leftJustified(15) << ": "
132 << _outObsFileName << endl;
133 *_log << QByteArray("Output Nav File").leftJustified(15) << ": "
134 << _outNavFileName << endl;
135
136 *_log << QByteArray(78, '-') << endl;
137 _log->flush();
138 }
139
140 // Handle Observation Files
141 // ------------------------
142 editObservations();
143
144 // Handle Navigations Files
145 // ------------------------
146 editEphemerides();
147
148 // Exit (thread)
149 // -------------
150 if (BNC_CORE->mode() != t_bncCore::interactive) {
151 qApp->exit(0);
152 }
153 else {
154 emit finished();
155 deleteLater();
156 }
157}
158
159// Initialize input observation files, sort them according to start time
160////////////////////////////////////////////////////////////////////////////
161void t_reqcEdit::initRnxObsFiles(const QStringList& obsFileNames,
162 QVector<t_rnxObsFile*>& rnxObsFiles,
163 QTextStream* log) {
164
165 QStringListIterator it(obsFileNames);
166 while (it.hasNext()) {
167 QString fileName = it.next();
168 if (fileName.indexOf('*') != -1 || fileName.indexOf('?') != -1) {
169 QFileInfo fileInfo(fileName);
170 QDir dir = fileInfo.dir();
171 QStringList filters; filters << fileInfo.fileName();
172 QListIterator<QFileInfo> it(dir.entryInfoList(filters));
173 while (it.hasNext()) {
174 QString filePath = it.next().filePath();
175 t_rnxObsFile* rnxObsFile = 0;
176 try {
177 rnxObsFile = new t_rnxObsFile(filePath, t_rnxObsFile::input);
178 rnxObsFiles.append(rnxObsFile);
179 }
180 catch (...) {
181 delete rnxObsFile;
182 if (log) {
183 *log << "Error in rnxObsFile " << filePath.toAscii().data() << endl;
184 }
185 }
186 }
187 }
188 else {
189 t_rnxObsFile* rnxObsFile = 0;
190 try {
191 rnxObsFile = new t_rnxObsFile(fileName, t_rnxObsFile::input);
192 rnxObsFiles.append(rnxObsFile);
193 }
194 catch (...) {
195 if (log) {
196 *log << "Error in rnxObsFile " << fileName.toAscii().data() << endl;
197 }
198 }
199 }
200 }
201 qStableSort(rnxObsFiles.begin(), rnxObsFiles.end(),
202 t_rnxObsFile::earlierStartTime);
203}
204
205//
206////////////////////////////////////////////////////////////////////////////
207void t_reqcEdit::editObservations() {
208
209 // Easy Exit
210 // ---------
211 if (_obsFileNames.isEmpty() || _outObsFileName.isEmpty()) {
212 return;
213 }
214
215 t_reqcEdit::initRnxObsFiles(_obsFileNames, _rnxObsFiles, _log);
216
217 // Initialize output observation file
218 // ----------------------------------
219 t_rnxObsFile outObsFile(_outObsFileName, t_rnxObsFile::output);
220
221 // Select observation types
222 // ------------------------
223 bncSettings settings;
224 QStringList useObsTypes = settings.value("reqcUseObsTypes").toString().split(" ", QString::SkipEmptyParts);
225
226 // Put together all observation types
227 // ----------------------------------
228 if (_rnxObsFiles.size() > 1 && useObsTypes.size() == 0) {
229 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
230 t_rnxObsFile* obsFile = _rnxObsFiles[ii];
231 for (int iSys = 0; iSys < obsFile->numSys(); iSys++) {
232 char sys = obsFile->system(iSys);
233 if (sys != ' ') {
234 for (int iType = 0; iType < obsFile->nTypes(sys); iType++) {
235 QString type = obsFile->obsType(sys, iType);
236 if (_rnxVersion < 3.0) {
237 useObsTypes << type;
238 }
239 else {
240 useObsTypes << QString(sys) + ":" + type;
241 }
242 }
243 }
244 }
245 }
246 useObsTypes.removeDuplicates();
247 }
248
249 // Put together all phase shifts
250 // -----------------------------
251 QStringList phaseShifts;
252 if (_rnxVersion >= 3.0 && _rnxObsFiles.size() > 1) {
253 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
254 t_rnxObsFile* obsFile = _rnxObsFiles[ii];
255 phaseShifts << obsFile->phaseShifts();
256 }
257 phaseShifts.removeDuplicates();
258 }
259
260 // Put together all GLONASS biases
261 // -------------------------------
262 QStringList gloBiases;
263 if (_rnxVersion >= 3.0 && _rnxObsFiles.size() > 1) {
264 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
265 t_rnxObsFile* obsFile = _rnxObsFiles[ii];
266 if (ii == 0 && obsFile->numGloBiases() == 4) {
267 break;
268 }
269 else {
270 gloBiases << obsFile->gloBiases();
271 }
272 }
273 gloBiases.removeDuplicates();
274 }
275
276 // Put together all GLONASS slots
277 // -----------------------------
278 QStringList gloSlots;
279 if (_rnxVersion >= 3.0 && _rnxObsFiles.size() > 1) {
280 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
281 t_rnxObsFile* obsFile = _rnxObsFiles[ii];
282 if (ii == 0 &&
283 obsFile->numGloSlots() == signed(t_prn::MAXPRN_GLONASS)) {
284 break;
285 }
286 else {
287 gloSlots << obsFile->gloSlots();
288 }
289 }
290 gloSlots.removeDuplicates();
291 }
292
293 // Loop over all input observation files
294 // -------------------------------------
295 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
296 t_rnxObsFile* obsFile = _rnxObsFiles[ii];
297 if (_log) {
298 *_log << "Processing File: " << obsFile->fileName() << " start: "
299 << obsFile->startTime().datestr().c_str() << ' '
300 << obsFile->startTime().timestr(0).c_str() << endl;
301 }
302 if (ii == 0) {
303 outObsFile.setHeader(obsFile->header(), int(_rnxVersion), &useObsTypes,
304 &phaseShifts, &gloBiases, &gloSlots);
305 if (_begTime.valid() && _begTime > outObsFile.startTime()) {
306 outObsFile.setStartTime(_begTime);
307 }
308 if (_samplingRate > outObsFile.interval()) {
309 outObsFile.setInterval(_samplingRate);
310 }
311 editRnxObsHeader(outObsFile);
312 bncSettings settings;
313 QMap<QString, QString> txtMap;
314 QString runBy = settings.value("reqcRunBy").toString();
315 if (!runBy.isEmpty()) {
316 txtMap["RUN BY"] = runBy;
317 }
318 QString comment = settings.value("reqcComment").toString();
319 if (!comment.isEmpty()) {
320 txtMap["COMMENT"] = comment;
321 }
322 outObsFile.header().write(outObsFile.stream(), &txtMap);
323 }
324 t_rnxObsFile::t_rnxEpo* epo = 0;
325 try {
326 while ( (epo = obsFile->nextEpoch()) != 0) {
327 if (_begTime.valid() && epo->tt < _begTime) {
328 continue;
329 }
330 if (_endTime.valid() && epo->tt > _endTime) {
331 break;
332 }
333
334 if (_samplingRate == 0 ||
335 fmod(round(epo->tt.gpssec()), _samplingRate) == 0) {
336 applyLLI(obsFile, epo);
337 outObsFile.writeEpoch(epo);
338 }
339 else {
340 rememberLLI(obsFile, epo);
341 }
342 }
343 }
344 catch (QString str) {
345 if (_log) {
346 *_log << "Exception " << str << endl;
347 }
348 else {
349 qDebug() << str;
350 }
351 return;
352 }
353 catch (...) {
354 if (_log) {
355 *_log << "Exception unknown" << endl;
356 }
357 else {
358 qDebug() << "Exception unknown";
359 }
360 return;
361 }
362 }
363}
364
365// Change RINEX Header Content
366////////////////////////////////////////////////////////////////////////////
367void t_reqcEdit::editRnxObsHeader(t_rnxObsFile& obsFile) {
368
369 bncSettings settings;
370
371 QString oldMarkerName = settings.value("reqcOldMarkerName").toString();
372 QString newMarkerName = settings.value("reqcNewMarkerName").toString();
373 if (!newMarkerName.isEmpty()) {
374 if (oldMarkerName.isEmpty() ||
375 QRegExp(oldMarkerName).exactMatch(obsFile.markerName())) {
376 obsFile.setMarkerName(newMarkerName);
377 }
378 }
379
380 QString oldAntennaName = settings.value("reqcOldAntennaName").toString();
381 QString newAntennaName = settings.value("reqcNewAntennaName").toString();
382 if (!newAntennaName.isEmpty()) {
383 if (oldAntennaName.isEmpty() ||
384 QRegExp(oldAntennaName).exactMatch(obsFile.antennaName())) {
385 obsFile.setAntennaName(newAntennaName);
386 }
387 }
388
389 QString oldAntennaNumber = settings.value("reqcOldAntennaNumber").toString();
390 QString newAntennaNumber = settings.value("reqcNewAntennaNumber").toString();
391 if (!newAntennaNumber.isEmpty()) {
392 if (oldAntennaNumber.isEmpty() ||
393 QRegExp(oldAntennaNumber).exactMatch(obsFile.antennaNumber())) {
394 obsFile.setAntennaNumber(newAntennaNumber);
395 }
396 }
397
398
399 const ColumnVector& obsFileAntNEU = obsFile.antNEU();
400 QString oldAntennadN = settings.value("reqcOldAntennadN").toString();
401 QString newAntennadN = settings.value("reqcNewAntennadN").toString();
402 if(!newAntennadN.isEmpty()) {
403 if (oldAntennadN.isEmpty() ||
404 oldAntennadN.toDouble() == obsFileAntNEU(1)) {
405 obsFile.setAntennaN(newAntennadN.toDouble());
406 }
407 }
408 QString oldAntennadE = settings.value("reqcOldAntennadE").toString();
409 QString newAntennadE = settings.value("reqcNewAntennadE").toString();
410 if(!newAntennadE.isEmpty()) {
411 if (oldAntennadE.isEmpty() ||
412 oldAntennadE.toDouble() == obsFileAntNEU(2)) {
413 obsFile.setAntennaE(newAntennadE.toDouble());
414 }
415 }
416 QString oldAntennadU = settings.value("reqcOldAntennadU").toString();
417 QString newAntennadU = settings.value("reqcNewAntennadU").toString();
418 if(!newAntennadU.isEmpty()) {
419 if (oldAntennadU.isEmpty() ||
420 oldAntennadU.toDouble() == obsFileAntNEU(3)) {
421 obsFile.setAntennaU(newAntennadU.toDouble());
422 }
423 }
424
425 QString oldReceiverType = settings.value("reqcOldReceiverName").toString();
426 QString newReceiverType = settings.value("reqcNewReceiverName").toString();
427 if (!newReceiverType.isEmpty()) {
428 if (oldReceiverType.isEmpty() ||
429 QRegExp(oldReceiverType).exactMatch(obsFile.receiverType())) {
430 obsFile.setReceiverType(newReceiverType);
431 }
432 }
433
434 QString oldReceiverNumber = settings.value("reqcOldReceiverNumber").toString();
435 QString newReceiverNumber = settings.value("reqcNewReceiverNumber").toString();
436 if (!newReceiverNumber.isEmpty()) {
437 if (oldReceiverNumber.isEmpty() ||
438 QRegExp(oldReceiverNumber).exactMatch(obsFile.receiverNumber())) {
439 obsFile.setReceiverNumber(newReceiverNumber);
440 }
441 }
442}
443
444//
445////////////////////////////////////////////////////////////////////////////
446void t_reqcEdit::rememberLLI(const t_rnxObsFile* obsFile,
447 const t_rnxObsFile::t_rnxEpo* epo) {
448
449 if (_samplingRate == 0) {
450 return;
451 }
452
453 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
454 const t_rnxObsFile::t_rnxSat& rnxSat = epo->rnxSat[iSat];
455 char sys = rnxSat.prn.system();
456 QString prn(rnxSat.prn.toString().c_str());
457
458 for (int iType = 0; iType < obsFile->nTypes(sys); iType++) {
459 QString type = obsFile->obsType(sys, iType);
460 if (!_lli[prn].contains(iType)) {
461 _lli[prn][iType] = 0;
462 }
463 if (rnxSat.obs.contains(type) && rnxSat.obs[type].lli & 1) {
464 _lli[prn][iType] |= 1;
465 }
466 }
467 }
468}
469
470//
471////////////////////////////////////////////////////////////////////////////
472void t_reqcEdit::applyLLI(const t_rnxObsFile* obsFile,
473 t_rnxObsFile::t_rnxEpo* epo) {
474
475 if (_samplingRate == 0) {
476 return;
477 }
478
479 for (unsigned iSat = 0; iSat < epo->rnxSat.size(); iSat++) {
480 t_rnxObsFile::t_rnxSat& rnxSat = epo->rnxSat[iSat];
481 char sys = rnxSat.prn.system();
482 QString prn(rnxSat.prn.toString().c_str());
483
484 for (int iType = 0; iType < obsFile->nTypes(sys); iType++) {
485 QString type = obsFile->obsType(sys, iType);
486 if (_lli[prn].contains(iType) && _lli[prn][iType] & 1) {
487 if (rnxSat.obs.contains(type)) {
488 rnxSat.obs[type].lli |= 1;
489 }
490 }
491 }
492 }
493
494 _lli.clear();
495}
496
497/// Read All Ephemerides
498////////////////////////////////////////////////////////////////////////////
499void t_reqcEdit::readEphemerides(const QStringList& navFileNames,
500 QVector<t_eph*>& ephs) {
501
502 QStringListIterator it(navFileNames);
503 while (it.hasNext()) {
504 QString fileName = it.next();
505 if (fileName.indexOf('*') != -1 || fileName.indexOf('?') != -1) {
506 QFileInfo fileInfo(fileName);
507 QDir dir = fileInfo.dir();
508 QStringList filters; filters << fileInfo.fileName();
509 QListIterator<QFileInfo> it(dir.entryInfoList(filters));
510 while (it.hasNext()) {
511 QString filePath = it.next().filePath();
512 appendEphemerides(filePath, ephs);
513 }
514 }
515 else {
516 appendEphemerides(fileName, ephs);
517 }
518 }
519 qStableSort(ephs.begin(), ephs.end(), t_eph::earlierTime);
520}
521
522//
523////////////////////////////////////////////////////////////////////////////
524void t_reqcEdit::editEphemerides() {
525
526 // Easy Exit
527 // ---------
528 if (_navFileNames.isEmpty() || _outNavFileName.isEmpty()) {
529 return;
530 }
531
532 // Read Ephemerides
533 // ----------------
534 t_reqcEdit::readEphemerides(_navFileNames, _ephs);
535
536 // Check Satellite Systems
537 // -----------------------
538 bool haveGPS = false;
539 bool haveGlonass = false;
540 for (int ii = 0; ii < _ephs.size(); ii++) {
541 const t_eph* eph = _ephs[ii];
542 if (eph->type() == t_eph::GPS) {
543 haveGPS = true;
544 }
545 else if (eph->type() == t_eph::GLONASS) {
546 haveGlonass = true;
547 }
548 }
549
550 // Initialize output navigation file
551 // ---------------------------------
552 t_rnxNavFile outNavFile(_outNavFileName, t_rnxNavFile::output);
553
554 outNavFile.setGlonass(haveGlonass);
555
556 if ( (haveGPS && haveGlonass) || _rnxVersion >= 3.0) {
557 outNavFile.setVersion(t_rnxNavFile::defaultRnxNavVersion3);
558 }
559 else {
560 outNavFile.setVersion(t_rnxNavFile::defaultRnxNavVersion2);
561 }
562
563 bncSettings settings;
564 QMap<QString, QString> txtMap;
565 QString runBy = settings.value("reqcRunBy").toString();
566 if (!runBy.isEmpty()) {
567 txtMap["RUN BY"] = runBy;
568 }
569 QString comment = settings.value("reqcComment").toString();
570 if (!comment.isEmpty()) {
571 txtMap["COMMENT"] = comment;
572 }
573
574 outNavFile.writeHeader(&txtMap);
575
576 // Loop over all ephemerides
577 // -------------------------
578 for (int ii = 0; ii < _ephs.size(); ii++) {
579 const t_eph* eph = _ephs[ii];
580 bncTime begTime = _begTime;
581 bncTime endTime = _endTime;
582 if (eph->type() == t_eph::BDS) {
583 begTime += 14;
584 endTime += 14;
585 }
586 if (begTime.valid() && eph->TOC() < begTime) {
587 continue;
588 }
589 if (endTime.valid() && eph->TOC() > endTime) {
590 break;
591 }
592 outNavFile.writeEph(eph);
593 }
594}
595
596//
597////////////////////////////////////////////////////////////////////////////
598void t_reqcEdit::appendEphemerides(const QString& fileName,
599 QVector<t_eph*>& ephs) {
600
601 t_rnxNavFile rnxNavFile(fileName, t_rnxNavFile::input);
602 for (unsigned ii = 0; ii < rnxNavFile.ephs().size(); ii++) {
603 t_eph* eph = rnxNavFile.ephs()[ii];
604 bool isNew = true;
605 for (int iOld = 0; iOld < ephs.size(); iOld++) {
606 const t_eph* ephOld = ephs[iOld];
607 if (ephOld->prn() == eph->prn() &&
608 ephOld->TOC() == eph->TOC()) {
609 isNew = false;
610 break;
611 }
612 }
613 if (isNew) {
614 if (eph->type() == t_eph::GPS) {
615 ephs.append(new t_ephGPS(*dynamic_cast<t_ephGPS*>(eph)));
616 }
617 else if (eph->type() == t_eph::GLONASS) {
618 ephs.append(new t_ephGlo(*dynamic_cast<t_ephGlo*>(eph)));
619 }
620 else if (eph->type() == t_eph::Galileo) {
621 ephs.append(new t_ephGal(*dynamic_cast<t_ephGal*>(eph)));
622 }
623 else if (eph->type() == t_eph::QZSS) {
624 ephs.append(new t_ephGPS(*dynamic_cast<t_ephGPS*>(eph)));
625 }
626 else if (eph->type() == t_eph::SBAS) {
627 ephs.append(new t_ephSBAS(*dynamic_cast<t_ephSBAS*>(eph)));
628 }
629 else if (eph->type() == t_eph::BDS) {
630 ephs.append(new t_ephBDS(*dynamic_cast<t_ephBDS*>(eph)));
631 }
632 }
633 }
634}
Note: See TracBrowser for help on using the repository browser.