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

Last change on this file since 6800 was 6795, checked in by stuerze, 11 years ago

Receiver Number, Antenna Number and Antenna Eccentricity are now additional editable RINEX header fields

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