source: ntrip/trunk/BNC/latencychecker.cpp@ 1558

Last change on this file since 1558 was 1558, checked in by mervart, 15 years ago

* empty log message *

File size: 10.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: latencyChecker
30 *
31 * Purpose: Check incoming GNSS data for latencies, gaps etc.
32 *
33 * Author: G. Weber
34 *
35 * Created: 02-Feb-2009
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include "latencychecker.h"
42#include "bncapp.h"
43#include "bncutils.h"
44#include "bncsettings.h"
45
46// Constructor
47//////////////////////////////////////////////////////////////////////////////
48latencyChecker::latencyChecker(QByteArray staID) {
49
50 _staID = staID;
51
52 bncApp* app = (bncApp*) qApp;
53 connect(this, SIGNAL(newMessage(QByteArray,bool)),
54 app, SLOT(slotMessage(const QByteArray,bool)));
55
56 bncSettings settings;
57
58 // Notice threshold
59 // ----------------
60 QString obsRate = settings.value("obsRate").toString();
61 _inspSegm = 0;
62 if ( obsRate.isEmpty() ) {
63 _inspSegm = 0;
64 }
65 else if ( obsRate.indexOf("5 Hz") != -1 ) {
66 _inspSegm = 20;
67 }
68 else if ( obsRate.indexOf("1 Hz") != -1 ) {
69 _inspSegm = 10;
70 }
71 else if ( obsRate.indexOf("0.5 Hz") != -1 ) {
72 _inspSegm = 20;
73 }
74 else if ( obsRate.indexOf("0.2 Hz") != -1 ) {
75 _inspSegm = 40;
76 }
77 else if ( obsRate.indexOf("0.1 Hz") != -1 ) {
78 _inspSegm = 50;
79 }
80 _adviseFail = settings.value("adviseFail").toInt();
81 _adviseReco = settings.value("adviseReco").toInt();
82 if ( Qt::CheckState(settings.value("makePause").toInt()) == Qt::Checked) {
83 _makePause = true;
84 }
85 else {
86 _makePause = false;
87 }
88 _adviseScript = settings.value("adviseScript").toString();
89 expandEnvVar(_adviseScript);
90
91 // Latency interval/average
92 // ------------------------
93 _perfIntr = 0;
94 QString perfIntr = settings.value("perfIntr").toString();
95 if ( perfIntr.isEmpty() ) {
96 _perfIntr = 0;
97 }
98 else if ( perfIntr.indexOf("2 sec") != -1 ) {
99 _perfIntr = 2;
100 }
101 else if ( perfIntr.indexOf("10 sec") != -1 ) {
102 _perfIntr = 10;
103 }
104 else if ( perfIntr.indexOf("1 min") != -1 ) {
105 _perfIntr = 60;
106 }
107 else if ( perfIntr.indexOf("5 min") != -1 ) {
108 _perfIntr = 300;
109 }
110 else if ( perfIntr.indexOf("15 min") != -1 ) {
111 _perfIntr = 900;
112 }
113 else if ( perfIntr.indexOf("1 hour") != -1 ) {
114 _perfIntr = 3600;
115 }
116 else if ( perfIntr.indexOf("6 hours") != -1 ) {
117 _perfIntr = 21600;
118 }
119 else if ( perfIntr.indexOf("1 day") != -1 ) {
120 _perfIntr = 86400;
121 }
122
123 // RTCM message types
124 // ------------------
125 _checkMountPoint = settings.value("miscMount").toString();
126
127 // Initialize private members
128 // --------------------------
129 _maxDt = 600.0; // Check observation epoch
130 _wrongEpoch = false;
131 _decode = true;
132 _numSucc = 0;
133 _secSucc = 0;
134 _secFail = 0;
135 _initPause = 30; // Initial pause for corrupted streams
136 _currPause = 0;
137 _begCorrupt = false;
138 _endCorrupt = false;
139 _followSec = false;
140 _oldSecGPS = 0;
141 _newSecGPS = 0;
142 _numGaps = 0;
143 _diffSecGPS = 0;
144 _numLat = 0;
145 _sumLat = 0.0;
146 _sumLatQ = 0.0;
147 _meanDiff = 0.0;
148 _minLat = _maxDt;
149 _maxLat = -_maxDt;
150 _curLat = 0.0;
151
152 _decodeTime = QDateTime::currentDateTime();
153 _decodeSucc = QDateTime::currentDateTime();
154}
155
156// Destructor
157//////////////////////////////////////////////////////////////////////////////
158latencyChecker::~latencyChecker() {
159
160}
161
162// Perform latency checks
163//////////////////////////////////////////////////////////////////////////////
164void latencyChecker::check(GPSDecoder* decoder) {
165
166 // Check - once per inspect segment
167 // --------------------------------
168 if (decoder->_obsList.size() > 0) {
169
170 _decodeTime = QDateTime::currentDateTime();
171
172 if (_numSucc > 0) {
173 _secSucc += _inspSegm;
174 _decodeSucc = QDateTime::currentDateTime();
175 if (_secSucc > _adviseReco * 60) {
176 _secSucc = _adviseReco * 60 + 1;
177 }
178 _numSucc = 0;
179 _currPause = _initPause;
180 _decodePause.setDate(QDate());
181 _decodePause.setTime(QTime());
182 }
183 else {
184 _secFail += _inspSegm;
185 _secSucc = 0;
186 if (_secFail > _adviseFail * 60) {
187 _secFail = _adviseFail * 60 + 1;
188 }
189 if (!_decodePause.isValid() || !_makePause) {
190 _decodePause = QDateTime::currentDateTime();
191 }
192 else {
193 _decodePause.setDate(QDate());
194 _decodePause.setTime(QTime());
195 _secFail = _secFail + _currPause - _inspSegm;
196 _currPause = _currPause * 2;
197 if (_currPause > 960) {
198 _currPause = 960;
199 }
200 }
201 }
202
203 // End corrupt threshold
204 // ---------------------
205 if ( _begCorrupt && !_endCorrupt && _secSucc > _adviseReco * 60 ) {
206 _endDateCor = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().date().toString("yy-MM-dd");
207 _endTimeCor = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().time().toString("hh:mm:ss");
208 emit(newMessage((_staID + ": Recovery threshold exceeded, corruption ended "
209 + _endDateCor + " " + _endTimeCor).toAscii(), true));
210 callScript(("End_Corrupted " + _endDateCor + " " + _endTimeCor + " Begin was " + _begDateCor + " " + _begTimeCor).toAscii());
211 _endCorrupt = true;
212 _begCorrupt = false;
213 _secFail = 0;
214 }
215 else {
216
217 // Begin corrupt threshold
218 // -----------------------
219 if ( !_begCorrupt && _secFail > _adviseFail * 60 ) {
220 _begDateCor = _decodeSucc.toUTC().date().toString("yy-MM-dd");
221 _begTimeCor = _decodeSucc.toUTC().time().toString("hh:mm:ss");
222 emit(newMessage((_staID + ": Failure threshold exceeded, corrupted since "
223 + _begDateCor + " " + _begTimeCor).toAscii(), true));
224 callScript(("Begin_Corrupted " + _begDateCor + " " + _begTimeCor).toAscii());
225 _begCorrupt = true;
226 _endCorrupt = false;
227 _secSucc = 0;
228 _numSucc = 0;
229 }
230 }
231 }
232
233 // End outage threshold
234 // --------------------
235 if ( _decodeStart.isValid() && _decodeStart.secsTo(QDateTime::currentDateTime()) > _adviseReco * 60 ) {
236 _decodeStart.setDate(QDate());
237 _decodeStart.setTime(QTime());
238 if (_inspSegm > 0) {
239 _endDateOut = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().date().toString("yy-MM-dd");
240 _endTimeOut = QDateTime::currentDateTime().addSecs(- _adviseReco * 60).toUTC().time().toString("hh:mm:ss");
241 emit(newMessage((_staID + ": Recovery threshold exceeded, outage ended "
242 + _endDateOut + " " + _endTimeOut).toAscii(), true));
243 callScript(("End_Outage " + _endDateOut + " " + _endTimeOut + " Begin was " + _begDateOut + " " + _begTimeOut).toAscii());
244 }
245 }
246
247 // Latency and completeness
248 // ------------------------
249 if ( _checkMountPoint == _staID || _checkMountPoint == "ALL" ) {
250 if (_perfIntr > 0 ) {
251
252 QListIterator<p_obs> it(decoder->_obsList);
253 while (it.hasNext()) {
254 p_obs obs = it.next();
255
256 _newSecGPS = static_cast<int>(obs->_o.GPSWeeks);
257 if (_newSecGPS != _oldSecGPS) {
258 if (_newSecGPS % _perfIntr < _oldSecGPS % _perfIntr) {
259 if (_numLat > 0) {
260 if (_meanDiff > 0.0) {
261 emit( newMessage(QString("%1: Mean latency %2 sec, min %3, max %4, rms %5, %6 epochs, %7 gaps")
262 .arg(_staID.data())
263 .arg(int(_sumLat/_numLat*100)/100.)
264 .arg(int(_minLat*100)/100.)
265 .arg(int(_maxLat*100)/100.)
266 .arg(int((sqrt((_sumLatQ - _sumLat * _sumLat / _numLat)/_numLat))*100)/100.)
267 .arg(_numLat)
268 .arg(_numGaps)
269 .toAscii(), true) );
270 } else {
271 emit( newMessage(QString("%1: Mean latency %2 sec, min %3, max %4, rms %5, %6 epochs")
272 .arg(_staID.data())
273 .arg(int(_sumLat/_numLat*100)/100.)
274 .arg(int(_minLat*100)/100.)
275 .arg(int(_maxLat*100)/100.)
276 .arg(int((sqrt((_sumLatQ - _sumLat * _sumLat / _numLat)/_numLat))*100)/100.)
277 .arg(_numLat)
278 .toAscii(), true) );
279 }
280 }
281 _meanDiff = _diffSecGPS / _numLat;
282 _diffSecGPS = 0;
283 _numGaps = 0;
284 _sumLat = 0.0;
285 _sumLatQ = 0.0;
286 _numLat = 0;
287 _minLat = _maxDt;
288 _maxLat = -_maxDt;
289 }
290 if (_followSec) {
291 _diffSecGPS += _newSecGPS - _oldSecGPS;
292 if (_meanDiff>0.) {
293 if (_newSecGPS - _oldSecGPS > 1.5 * _meanDiff) {
294 _numGaps += 1;
295 }
296 }
297 }
298
299 // Compute the observations latency
300 // --------------------------------
301 int week;
302 double sec;
303 currentGPSWeeks(week, sec);
304 const double secPerWeek = 7.0 * 24.0 * 3600.0;
305 if (week < obs->_o.GPSWeek) {
306 week += 1;
307 sec -= secPerWeek;
308 }
309 if (week > obs->_o.GPSWeek) {
310 week -= 1;
311 sec += secPerWeek;
312 }
313
314 _curLat = sec - obs->_o.GPSWeeks;
315 _sumLat += _curLat;
316 _sumLatQ += _curLat * _curLat;
317 if (_curLat < _minLat) {
318 _minLat = _curLat;
319 }
320 if (_curLat >= _maxLat) {
321 _maxLat = _curLat;
322 }
323 _numLat += 1;
324 _oldSecGPS = _newSecGPS;
325 _followSec = true;
326 }
327 }
328 }
329 }
330}
331
332// Call advisory notice script
333////////////////////////////////////////////////////////////////////////////
334void latencyChecker::callScript(const char* comment) {
335 if (!_adviseScript.isEmpty()) {
336 sleep(1);
337#ifdef WIN32
338 QProcess::startDetached(_adviseScript, QStringList() << _staID << comment) ;
339#else
340 QProcess::startDetached("nohup", QStringList() << _adviseScript << _staID << comment) ;
341#endif
342 }
343}
Note: See TracBrowser for help on using the repository browser.