source: ntrip/trunk/BNC/src/rinex/reqcanalyze.cpp@ 6283

Last change on this file since 6283 was 6283, checked in by mervart, 9 years ago
File size: 20.3 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_reqcAnalyze
30 *
31 * Purpose: Analyze RINEX Files
32 *
33 * Author: L. Mervart
34 *
35 * Created: 11-Apr-2012
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <iostream>
42#include <iomanip>
43#include <qwt_plot_renderer.h>
44
45#include "reqcanalyze.h"
46#include "bnccore.h"
47#include "bncsettings.h"
48#include "reqcedit.h"
49#include "bncutils.h"
50#include "graphwin.h"
51#include "polarplot.h"
52#include "availplot.h"
53#include "eleplot.h"
54#include "dopplot.h"
55
56using namespace std;
57
58// Constructor
59////////////////////////////////////////////////////////////////////////////
60t_reqcAnalyze::t_reqcAnalyze(QObject* parent) : QThread(parent) {
61
62 bncSettings settings;
63
64 _logFileName = settings.value("reqcOutLogFile").toString(); expandEnvVar(_logFileName);
65 _logFile = 0;
66 _log = 0;
67 _currEpo = 0;
68 _obsFileNames = settings.value("reqcObsFile").toString().split(",", QString::SkipEmptyParts);
69 _navFileNames = settings.value("reqcNavFile").toString().split(",", QString::SkipEmptyParts);
70
71 connect(this, SIGNAL(dspSkyPlot(const QString&, const QByteArray&, QVector<t_polarPoint*>*,
72 const QByteArray&, QVector<t_polarPoint*>*,
73 const QByteArray&, double)),
74 this, SLOT(slotDspSkyPlot(const QString&, const QByteArray&, QVector<t_polarPoint*>*,
75 const QByteArray&, QVector<t_polarPoint*>*,
76 const QByteArray&, double)));
77
78 connect(this, SIGNAL(dspAvailPlot(const QString&, const QByteArray&)),
79 this, SLOT(slotDspAvailPlot(const QString&, const QByteArray&)));
80}
81
82// Destructor
83////////////////////////////////////////////////////////////////////////////
84t_reqcAnalyze::~t_reqcAnalyze() {
85 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
86 delete _rnxObsFiles[ii];
87 }
88 for (int ii = 0; ii < _ephs.size(); ii++) {
89 delete _ephs[ii];
90 }
91 delete _log; _log = 0;
92 delete _logFile; _logFile = 0;
93 if (BNC_CORE->mode() != t_bncCore::interactive) {
94 qApp->exit(0);
95 }
96}
97
98//
99////////////////////////////////////////////////////////////////////////////
100void t_reqcAnalyze::run() {
101
102 // Open Log File
103 // -------------
104 _logFile = new QFile(_logFileName);
105 if (_logFile->open(QIODevice::WriteOnly | QIODevice::Text)) {
106 _log = new QTextStream();
107 _log->setDevice(_logFile);
108 }
109
110 // Initialize RINEX Observation Files
111 // ----------------------------------
112 t_reqcEdit::initRnxObsFiles(_obsFileNames, _rnxObsFiles, _log);
113
114 // Read Ephemerides
115 // ----------------
116 t_reqcEdit::readEphemerides(_navFileNames, _ephs);
117
118 // Loop over all RINEX Files
119 // -------------------------
120 for (int ii = 0; ii < _rnxObsFiles.size(); ii++) {
121 analyzeFile(_rnxObsFiles[ii]);
122 }
123
124 // Exit
125 // ----
126 emit finished();
127 deleteLater();
128}
129
130//
131////////////////////////////////////////////////////////////////////////////
132void t_reqcAnalyze::analyzeFile(t_rnxObsFile* obsFile) {
133
134 if (_log) {
135 *_log << "\nAnalyze File\n"
136 << "------------\n"
137 << "File: " << obsFile->fileName().toAscii().data() << endl;
138 }
139
140 _qcFile.clear();
141
142 // A priori Coordinates
143 // --------------------
144 ColumnVector xyzSta = obsFile->xyz();
145
146 // Loop over all Epochs
147 // --------------------
148 try {
149 bool firstEpo = true;
150 while ( (_currEpo = obsFile->nextEpoch()) != 0) {
151 if (firstEpo) {
152 firstEpo = false;
153 _qcFile._startTime = _currEpo->tt;
154 _qcFile._antennaName = obsFile->antennaName();
155 _qcFile._markerName = obsFile->markerName();
156 _qcFile._receiverType = obsFile->receiverType();
157 _qcFile._interval = obsFile->interval();
158 }
159 _qcFile._endTime = _currEpo->tt;
160
161 t_qcEpo qcEpo;
162 qcEpo._epoTime = _currEpo->tt;
163 qcEpo._PDOP = cmpDOP(xyzSta);
164
165 // Loop over all satellites
166 // ------------------------
167 for (unsigned iObs = 0; iObs < _currEpo->rnxSat.size(); iObs++) {
168 const t_rnxObsFile::t_rnxSat& rnxSat = _currEpo->rnxSat[iObs];
169 t_satObs satObs;
170 t_rnxObsFile::setObsFromRnx(obsFile, _currEpo, rnxSat, satObs);
171 t_qcObs& qcObs = qcEpo._qcObs[satObs._prn];
172 setQcObs(qcEpo._epoTime, xyzSta, satObs, qcObs);
173 updateQcSat(qcObs, _qcFile._qcSat[satObs._prn]);
174 }
175 _qcFile._qcEpo.push_back(qcEpo);
176 }
177
178 analyzeMultipath();
179
180 preparePlotData(obsFile);
181
182 printReport();
183 }
184 catch (QString str) {
185 if (_log) {
186 *_log << "Exception " << str << endl;
187 }
188 else {
189 qDebug() << str;
190 }
191 }
192}
193
194// Compute Dilution of Precision
195////////////////////////////////////////////////////////////////////////////
196double t_reqcAnalyze::cmpDOP(const ColumnVector& xyzSta) const {
197
198 if (xyzSta.size() != 3) {
199 return 0.0;
200 }
201
202 unsigned nSat = _currEpo->rnxSat.size();
203
204 if (nSat < 4) {
205 return 0.0;
206 }
207
208 Matrix AA(nSat, 4);
209
210 unsigned nSatUsed = 0;
211 for (unsigned iSat = 0; iSat < nSat; iSat++) {
212
213 const t_rnxObsFile::t_rnxSat& rnxSat = _currEpo->rnxSat[iSat];
214 const t_prn& prn = rnxSat.prn;
215
216 t_eph* eph = 0;
217 for (int ie = 0; ie < _ephs.size(); ie++) {
218 if (_ephs[ie]->prn() == prn) {
219 eph = _ephs[ie];
220 break;
221 }
222 }
223 if (eph) {
224 ColumnVector xSat(4);
225 ColumnVector vv(3);
226 if (eph->getCrd(_currEpo->tt, xSat, vv, false) == success) {
227 ++nSatUsed;
228 ColumnVector dx = xSat.Rows(1,3) - xyzSta;
229 double rho = dx.norm_Frobenius();
230 AA(nSatUsed,1) = dx(1) / rho;
231 AA(nSatUsed,2) = dx(2) / rho;
232 AA(nSatUsed,3) = dx(3) / rho;
233 AA(nSatUsed,4) = 1.0;
234 }
235 }
236 }
237
238 if (nSatUsed < 4) {
239 return 0.0;
240 }
241
242 AA = AA.Rows(1, nSatUsed);
243
244 SymmetricMatrix QQ;
245 QQ << AA.t() * AA;
246 QQ = QQ.i();
247
248 return sqrt(QQ.trace());
249}
250
251//
252////////////////////////////////////////////////////////////////////////////
253void t_reqcAnalyze::updateQcSat(const t_qcObs& qcObs, t_qcSat& qcSat) {
254 if (qcObs._hasL1 && qcObs._hasL2) {
255 qcSat._numObs += 1;
256 }
257 if (qcObs._slipL1 && qcObs._slipL2) {
258 qcSat._numSlipsFlagged += 1;
259 }
260}
261
262//
263////////////////////////////////////////////////////////////////////////////
264void t_reqcAnalyze::setQcObs(const bncTime& epoTime, const ColumnVector& xyzSta,
265 const t_satObs& satObs, t_qcObs& qcObs) {
266
267 t_eph* eph = 0;
268 for (int ie = 0; ie < _ephs.size(); ie++) {
269 if (_ephs[ie]->prn() == satObs._prn) {
270 eph = _ephs[ie];
271 break;
272 }
273 }
274 if (eph) {
275 ColumnVector xc(4);
276 ColumnVector vv(3);
277 if (xyzSta.size() && eph->getCrd(epoTime, xc, vv, false) == success) {
278 double rho, eleSat, azSat;
279 topos(xyzSta(1), xyzSta(2), xyzSta(3), xc(1), xc(2), xc(3), rho, eleSat, azSat);
280 qcObs._eleSet = true;
281 qcObs._azDeg = azSat * 180.0/M_PI;
282 qcObs._eleDeg = eleSat * 180.0/M_PI;
283 }
284 if (satObs._prn.system() == 'R') {
285 qcObs._slotSet = true;
286 qcObs._slotNum = eph->slotNum();
287 }
288 }
289
290 // Check Gaps
291 // ----------
292 if (qcObs._lastObsTime.valid()) {
293 double dt = epoTime - qcObs._lastObsTime;
294 if (dt > 1.5 * _qcFile._interval) {
295 qcObs._gapL1 = true;
296 qcObs._gapL2 = true;
297 }
298 }
299 qcObs._lastObsTime = epoTime;
300
301 // Availability and Slip Flags
302 // ---------------------------
303 double L1 = 0.0;
304 double L2 = 0.0;
305 double P1 = 0.0;
306 double P2 = 0.0;
307 for (unsigned iFrq = 0; iFrq < satObs._obs.size(); iFrq++) {
308 const t_frqObs* frqObs = satObs._obs[iFrq];
309 if (frqObs->_rnxType2ch[0] == '1') {
310 if (frqObs->_phaseValid) {
311 L1 = frqObs->_phase;
312 qcObs._hasL1 = true;
313 qcObs._slipL1 = frqObs->_slip;
314 }
315 if (frqObs->_codeValid) {
316 P1 = frqObs->_code;
317 }
318 if (frqObs->_snrValid) {
319 qcObs._SNR1 = frqObs->_snr;
320 }
321 }
322 else if ( (satObs._prn.system() != 'E' && frqObs->_rnxType2ch[0] == '2') ||
323 (satObs._prn.system() == 'E' && frqObs->_rnxType2ch[0] == '5') ) {
324 if (frqObs->_phaseValid) {
325 L2 = frqObs->_phase;
326 qcObs._hasL2 = true;
327 qcObs._slipL2 = frqObs->_slip;
328 }
329 if (frqObs->_codeValid) {
330 P2 = frqObs->_code;
331 }
332 if (frqObs->_snrValid) {
333 qcObs._SNR2 = frqObs->_snr;
334 }
335 }
336 }
337
338 // Compute the Multipath Linear Combination
339 // ----------------------------------------
340 if (L1 != 0.0 && L2 != 0.0 && P1 != 0.0 && P2 != 0.0) {
341 double f1 = 0.0;
342 double f2 = 0.0;
343 if (satObs._prn.system() == 'G') {
344 f1 = t_CST::freq(t_frequency::G1, 0);
345 f2 = t_CST::freq(t_frequency::G2, 0);
346 }
347 else if (satObs._prn.system() == 'R') {
348 f1 = t_CST::freq(t_frequency::R1, qcObs._slotNum);
349 f2 = t_CST::freq(t_frequency::R2, qcObs._slotNum);
350 }
351 else if (satObs._prn.system() == 'E') {
352 f1 = t_CST::freq(t_frequency::E1, 0);
353 f2 = t_CST::freq(t_frequency::E5, 0);
354 }
355
356 L1 = L1 * t_CST::c / f1;
357 L2 = L2 * t_CST::c / f2;
358
359 qcObs._rawMP1 = P1 - L1 - 2.0*f2*f2/(f1*f1-f2*f2) * (L1 - L2);
360 qcObs._rawMP2 = P2 - L2 - 2.0*f1*f1/(f1*f1-f2*f2) * (L1 - L2);
361 qcObs._mpSet = true;
362 }
363}
364
365//
366////////////////////////////////////////////////////////////////////////////
367void t_reqcAnalyze::analyzeMultipath() {
368
369 const double SLIPTRESH = 10.0; // cycle-slip threshold (meters)
370 const double chunkStep = 600.0; // 10 minutes
371
372 // Loop over all satellites available
373 // ----------------------------------
374 QMutableMapIterator<t_prn, t_qcSat> it(_qcFile._qcSat);
375 while (it.hasNext()) {
376 it.next();
377 const t_prn& prn = it.key();
378 t_qcSat& qcSat = it.value();
379
380 // Loop over all Chunks of Data
381 // ----------------------------
382 for (bncTime chunkStart = _qcFile._startTime;
383 chunkStart < _qcFile._endTime; chunkStart += chunkStep) {
384
385 bncTime chunkEnd = chunkStart + chunkStep;
386
387 QVector<t_qcObs*> obsVec;
388 QVector<double> MP1;
389 QVector<double> MP2;
390
391 // Loop over all Epochs within one Chunk of Data
392 // ---------------------------------------------
393 for (int iEpo = 0; iEpo < _qcFile._qcEpo.size(); iEpo++) {
394 t_qcEpo& qcEpo = _qcFile._qcEpo[iEpo];
395 if (chunkStart <= qcEpo._epoTime && qcEpo._epoTime < chunkEnd) {
396 if (qcEpo._qcObs.contains(prn)) {
397 t_qcObs& qcObs = qcEpo._qcObs[prn];
398 obsVec << &qcObs;
399 if (qcObs._mpSet) {
400 MP1 << qcObs._rawMP1;
401 MP2 << qcObs._rawMP2;
402 }
403 }
404 }
405 }
406
407 // Compute the multipath mean and standard deviation
408 // -------------------------------------------------
409 if (MP1.size() > 1) {
410 double meanMP1 = 0.0;
411 double meanMP2 = 0.0;
412 for (int ii = 0; ii < MP1.size(); ii++) {
413 meanMP1 += MP1[ii];
414 meanMP2 += MP2[ii];
415 }
416 meanMP1 /= MP1.size();
417 meanMP2 /= MP2.size();
418
419 bool slipMP = false;
420
421 double stdMP1 = 0.0;
422 double stdMP2 = 0.0;
423 for (int ii = 0; ii < MP1.size(); ii++) {
424 double diff1 = MP1[ii] - meanMP1;
425 double diff2 = MP2[ii] - meanMP2;
426 if (fabs(diff1) > SLIPTRESH || fabs(diff2) > SLIPTRESH) {
427 slipMP = true;
428 break;
429 }
430 stdMP1 += diff1 * diff1;
431 stdMP2 += diff2 * diff2;
432 }
433
434 if (slipMP) {
435 stdMP1 = 0.0;
436 stdMP2 = 0.0;
437 qcSat._numSlipsFound += 1;
438 }
439 else {
440 stdMP1 = sqrt(stdMP1 / (MP1.size()-1));
441 stdMP2 = sqrt(stdMP2 / (MP2.size()-1));
442 }
443
444 for (int ii = 0; ii < obsVec.size(); ii++) {
445 t_qcObs* qcObs = obsVec[ii];
446 if (slipMP) {
447 qcObs->_slipL1 = true;
448 qcObs->_slipL2 = true;
449 }
450 else {
451 qcObs->_stdMP1 = stdMP1;
452 qcObs->_stdMP2 = stdMP2;
453 }
454 }
455 }
456 }
457 }
458}
459
460//
461////////////////////////////////////////////////////////////////////////////
462void t_reqcAnalyze::preparePlotData(const t_rnxObsFile* obsFile) {
463
464 QVector<t_polarPoint*>* dataMP1 = new QVector<t_polarPoint*>;
465 QVector<t_polarPoint*>* dataMP2 = new QVector<t_polarPoint*>;
466 QVector<t_polarPoint*>* dataSNR1 = new QVector<t_polarPoint*>;
467 QVector<t_polarPoint*>* dataSNR2 = new QVector<t_polarPoint*>;
468
469 bncSettings settings;
470 QString reqSkyPlotSystems = settings.value("reqcSkyPlotSystems").toString();
471 bool plotGPS = false;
472 bool plotGlo = false;
473 bool plotGal = false;
474 if (reqSkyPlotSystems == "GPS") {
475 plotGPS = true;
476 }
477 else if (reqSkyPlotSystems == "GLONASS") {
478 plotGlo = true;
479 }
480 else if (reqSkyPlotSystems == "Galileo") {
481 plotGal = true;
482 }
483 else {
484 plotGPS = true;
485 plotGlo = true;
486 plotGal = true;
487 }
488
489 // Loop over all observations
490 // --------------------------
491 for (int iEpo = 0; iEpo < _qcFile._qcEpo.size(); iEpo++) {
492 t_qcEpo& qcEpo = _qcFile._qcEpo[iEpo];
493 QMapIterator<t_prn, t_qcObs> it(qcEpo._qcObs);
494 while (it.hasNext()) {
495 it.next();
496 const t_prn& prn = it.key();
497 const t_qcObs& qcObs = it.value();
498 if ( (prn.system() == 'G' && plotGPS) ||
499 (prn.system() == 'R' && plotGlo) ||
500 (prn.system() == 'E' && plotGal) ) {
501
502 (*dataSNR1) << (new t_polarPoint(qcObs._azDeg, 90.0 - qcObs._eleDeg, qcObs._SNR1));
503 (*dataSNR2) << (new t_polarPoint(qcObs._azDeg, 90.0 - qcObs._eleDeg, qcObs._SNR2));
504
505 (*dataMP1) << (new t_polarPoint(qcObs._azDeg, 90.0 - qcObs._eleDeg, qcObs._stdMP1));
506 (*dataMP2) << (new t_polarPoint(qcObs._azDeg, 90.0 - qcObs._eleDeg, qcObs._stdMP2));
507 }
508 }
509 }
510
511 // Show the plots
512 // --------------
513 if (BNC_CORE->GUIenabled()) {
514 QFileInfo fileInfo(obsFile->fileName());
515 QByteArray title = fileInfo.fileName().toAscii();
516 emit dspSkyPlot(obsFile->fileName(), "MP1", dataMP1, "MP2", dataMP2, "Meters", 2.0);
517 emit dspSkyPlot(obsFile->fileName(), "SNR1", dataSNR1, "SNR2", dataSNR2, "dbHz", 54.0);
518 emit dspAvailPlot(obsFile->fileName(), title);
519 }
520 else {
521 for (int ii = 0; ii < dataMP1->size(); ii++) {
522 delete dataMP1->at(ii);
523 }
524 delete dataMP1;
525 for (int ii = 0; ii < dataMP2->size(); ii++) {
526 delete dataMP2->at(ii);
527 }
528 delete dataMP2;
529 for (int ii = 0; ii < dataSNR1->size(); ii++) {
530 delete dataSNR1->at(ii);
531 }
532 delete dataSNR1;
533 for (int ii = 0; ii < dataSNR2->size(); ii++) {
534 delete dataSNR2->at(ii);
535 }
536 delete dataSNR2;
537 }
538}
539
540//
541////////////////////////////////////////////////////////////////////////////
542void t_reqcAnalyze::slotDspSkyPlot(const QString& fileName, const QByteArray& title1,
543 QVector<t_polarPoint*>* data1, const QByteArray& title2,
544 QVector<t_polarPoint*>* data2, const QByteArray& scaleTitle,
545 double maxValue) {
546
547 if (BNC_CORE->GUIenabled()) {
548
549 if (maxValue == 0.0) {
550 if (data1) {
551 for (int ii = 0; ii < data1->size(); ii++) {
552 double val = data1->at(ii)->_value;
553 if (maxValue < val) {
554 maxValue = val;
555 }
556 }
557 }
558 if (data2) {
559 for (int ii = 0; ii < data2->size(); ii++) {
560 double val = data2->at(ii)->_value;
561 if (maxValue < val) {
562 maxValue = val;
563 }
564 }
565 }
566 }
567
568 QwtInterval scaleInterval(0.0, maxValue);
569
570 QVector<QWidget*> plots;
571 if (data1) {
572 t_polarPlot* plot1 = new t_polarPlot(QwtText(title1), scaleInterval,
573 BNC_CORE->mainWindow());
574 plot1->addCurve(data1);
575 plots << plot1;
576 }
577 if (data2) {
578 t_polarPlot* plot2 = new t_polarPlot(QwtText(title2), scaleInterval,
579 BNC_CORE->mainWindow());
580 plot2->addCurve(data2);
581 plots << plot2;
582 }
583
584 t_graphWin* graphWin = new t_graphWin(0, fileName, plots,
585 &scaleTitle, &scaleInterval);
586
587 graphWin->show();
588
589 bncSettings settings;
590 QString dirName = settings.value("reqcPlotDir").toString();
591 if (!dirName.isEmpty()) {
592 QByteArray ext = (scaleTitle == "Meters") ? "_M.png" : "_S.png";
593 graphWin->savePNG(dirName, ext);
594 }
595 }
596}
597
598//
599////////////////////////////////////////////////////////////////////////////
600void t_reqcAnalyze::slotDspAvailPlot(const QString& fileName, const QByteArray& title) {
601
602 t_plotData plotData;
603 QMap<t_prn, t_plotData> plotDataMap;
604
605 for (int ii = 0; ii < _qcFile._qcEpo.size(); ii++) {
606 const t_qcEpo& qcEpo = _qcFile._qcEpo[ii];
607 double mjdX24 = qcEpo._epoTime.mjddec() * 24.0;
608
609 plotData._mjdX24 << mjdX24;
610 plotData._PDOP << qcEpo._PDOP;
611 plotData._numSat << qcEpo._qcObs.size();
612
613 QMapIterator<t_prn, t_qcObs> it(qcEpo._qcObs);
614 while (it.hasNext()) {
615 it.next();
616 const t_prn& prn = it.key();
617 const t_qcObs& qcObs = it.value();
618 t_plotData& data = plotDataMap[prn];
619 data._mjdX24 << mjdX24;
620 data._eleDeg << qcObs._eleDeg;
621 if (qcObs._hasL1) data._L1ok << mjdX24;
622 if (qcObs._hasL2) data._L2ok << mjdX24;
623 if (qcObs._slipL1) data._L1slip << mjdX24;
624 if (qcObs._slipL2) data._L2slip << mjdX24;
625 if (qcObs._gapL1) data._L1gap << mjdX24;
626 if (qcObs._gapL2) data._L2gap << mjdX24;
627 }
628 }
629
630
631 if (BNC_CORE->GUIenabled()) {
632 t_availPlot* plotA = new t_availPlot(0, plotDataMap);
633 plotA->setTitle(title);
634
635 t_elePlot* plotZ = new t_elePlot(0, plotDataMap);
636
637 t_dopPlot* plotD = new t_dopPlot(0, plotData);
638
639 QVector<QWidget*> plots;
640 plots << plotA << plotZ << plotD;
641 t_graphWin* graphWin = new t_graphWin(0, fileName, plots, 0, 0);
642
643 int ww = QFontMetrics(graphWin->font()).width('w');
644 graphWin->setMinimumSize(120*ww, 40*ww);
645
646 graphWin->show();
647
648 bncSettings settings;
649 QString dirName = settings.value("reqcPlotDir").toString();
650 if (!dirName.isEmpty()) {
651 QByteArray ext = "_A.png";
652 graphWin->savePNG(dirName, ext);
653 }
654 }
655}
656
657// Finish the report
658////////////////////////////////////////////////////////////////////////////
659void t_reqcAnalyze::printReport() {
660
661 if (!_log) {
662 return;
663 }
664
665 *_log << "Marker name: " << _qcFile._markerName << endl
666 << "Receiver: " << _qcFile._receiverType << endl
667 << "Antenna: " << _qcFile._antennaName << endl
668 << "Start time: " << _qcFile._startTime.datestr().c_str() << ' '
669 << _qcFile._startTime.timestr().c_str() << endl
670 << "End time: " << _qcFile._endTime.datestr().c_str() << ' '
671 << _qcFile._endTime.timestr().c_str() << endl
672 << "Interval: " << _qcFile._interval << endl
673 << "# Sat.: " << _qcFile._qcSat.size() << endl;
674
675 int numObs = 0;
676 int numSlipsFlagged = 0;
677 int numSlipsFound = 0;
678 QMapIterator<t_prn, t_qcSat> it(_qcFile._qcSat);
679 while (it.hasNext()) {
680 it.next();
681 const t_qcSat& qcSat = it.value();
682 numObs += qcSat._numObs;
683 numSlipsFlagged += qcSat._numSlipsFlagged;
684 numSlipsFound += qcSat._numSlipsFound;
685 }
686 *_log << "# Obs.: " << numObs << endl
687 << "# Slips (file): " << numSlipsFlagged << endl
688 << "# Slips (found): " << numSlipsFound << endl;
689
690 _log->flush();
691}
Note: See TracBrowser for help on using the repository browser.