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

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