source: ntrip/branches/BNC_2.12/src/bncephuser.cpp@ 9322

Last change on this file since 9322 was 9322, checked in by stuerze, 19 months ago

some lines are added to consider corrected GPS BRDC data sets which come 16 seconds before nominal TOC

File size: 10.8 KB
Line 
1// converting GNSS data streams from NTRIP broadcasters.
2//
3// Copyright (C) 2007
4// German Federal Agency for Cartography and Geodesy (BKG)
5// http://www.bkg.bund.de
6// Czech Technical University Prague, Department of Geodesy
7// http://www.fsv.cvut.cz
8//
9// Email: euref-ip@bkg.bund.de
10//
11// This program is free software; you can redistribute it and/or
12// modify it under the terms of the GNU General Public License
13// as published by the Free Software Foundation, version 2.
14//
15// This program is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with this program; if not, write to the Free Software
22// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24/* -------------------------------------------------------------------------
25 * BKG NTRIP Client
26 * -------------------------------------------------------------------------
27 *
28 * Class: bncEphUser
29 *
30 * Purpose: Base for Classes that use Ephemerides
31 *
32 * Author: L. Mervart
33 *
34 * Created: 27-Jan-2011
35 *
36 * Changes:
37 *
38 * -----------------------------------------------------------------------*/
39
40#include <cmath>
41#include <iostream>
42
43#include "bncephuser.h"
44#include "bnccore.h"
45
46using namespace std;
47
48// Constructor
49////////////////////////////////////////////////////////////////////////////
50bncEphUser::bncEphUser(bool connectSlots) {
51 if (connectSlots) {
52 connect(BNC_CORE, SIGNAL(newGPSEph(t_ephGPS)),
53 this, SLOT(slotNewGPSEph(t_ephGPS)), Qt::DirectConnection);
54
55 connect(BNC_CORE, SIGNAL(newGlonassEph(t_ephGlo)),
56 this, SLOT(slotNewGlonassEph(t_ephGlo)), Qt::DirectConnection);
57
58 connect(BNC_CORE, SIGNAL(newGalileoEph(t_ephGal)),
59 this, SLOT(slotNewGalileoEph(t_ephGal)), Qt::DirectConnection);
60
61 connect(BNC_CORE, SIGNAL(newSBASEph(t_ephSBAS)),
62 this, SLOT(slotNewSBASEph(t_ephSBAS)), Qt::DirectConnection);
63
64 connect(BNC_CORE, SIGNAL(newBDSEph(t_ephBDS)),
65 this, SLOT(slotNewBDSEph(t_ephBDS)), Qt::DirectConnection);
66 }
67}
68
69// Destructor
70////////////////////////////////////////////////////////////////////////////
71bncEphUser::~bncEphUser() {
72 QMapIterator<QString, deque<t_eph*> > it(_eph);
73 while (it.hasNext()) {
74 it.next();
75 const deque<t_eph*>& qq = it.value();
76 for (unsigned ii = 0; ii < qq.size(); ii++) {
77 delete qq[ii];
78 }
79 }
80}
81
82// New GPS Ephemeris
83////////////////////////////////////////////////////////////////////////////
84void bncEphUser::slotNewGPSEph(t_ephGPS eph) {
85 putNewEph(&eph, true);
86}
87
88// New Glonass Ephemeris
89////////////////////////////////////////////////////////////////////////////
90void bncEphUser::slotNewGlonassEph(t_ephGlo eph) {
91 putNewEph(&eph, true);
92}
93
94// New Galileo Ephemeris
95////////////////////////////////////////////////////////////////////////////
96void bncEphUser::slotNewGalileoEph(t_ephGal eph) {
97 putNewEph(&eph, true);
98}
99
100// New SBAS Ephemeris
101////////////////////////////////////////////////////////////////////////////
102void bncEphUser::slotNewSBASEph(t_ephSBAS eph) {
103 putNewEph(&eph, true);
104}
105
106// New BDS Ephemeris
107////////////////////////////////////////////////////////////////////////////
108void bncEphUser::slotNewBDSEph(t_ephBDS eph) {
109 putNewEph(&eph, true);
110}
111
112//
113////////////////////////////////////////////////////////////////////////////
114t_irc bncEphUser::putNewEph(t_eph* eph, bool realTime) {
115
116 QMutexLocker locker(&_mutex);
117
118 if (eph == 0) {
119 return failure;
120 }
121
122 const t_ephGPS* ephGPS = dynamic_cast<const t_ephGPS*>(eph);
123 const t_ephGlo* ephGlo = dynamic_cast<const t_ephGlo*>(eph);
124 const t_ephGal* ephGal = dynamic_cast<const t_ephGal*>(eph);
125 const t_ephSBAS* ephSBAS = dynamic_cast<const t_ephSBAS*>(eph);
126 const t_ephBDS* ephBDS = dynamic_cast<const t_ephBDS*>(eph);
127
128 t_eph* newEph = 0;
129
130 if (ephGPS) {
131 newEph = new t_ephGPS(*ephGPS);
132 }
133 else if (ephGlo) {
134 newEph = new t_ephGlo(*ephGlo);
135 }
136 else if (ephGal) {
137 newEph = new t_ephGal(*ephGal);
138 }
139 else if (ephSBAS) {
140 newEph = new t_ephSBAS(*ephSBAS);
141 }
142 else if (ephBDS) {
143 newEph = new t_ephBDS(*ephBDS);
144 }
145 else {
146 return failure;
147 }
148
149 QString prn(newEph->prn().toInternalString().c_str());
150
151 const t_eph* ephOld = ephLast(prn);
152
153 if (ephOld &&
154 (ephOld->checkState() == t_eph::bad ||
155 ephOld->checkState() == t_eph::outdated ||
156 ephOld->checkState() == t_eph::unhealthy)) {
157 ephOld = 0;
158 }
159
160 if ( (ephOld == 0) ||
161 newEph->isNewerThan(ephOld) ||
162 newCorrectedGpsEphSet(newEph) ) {
163 checkEphemeris(newEph, realTime);
164 eph->setCheckState(newEph->checkState());
165 }
166 else {
167 delete newEph;
168 return failure;
169 }
170
171 if (newEph->checkState() != t_eph::bad &&
172 newEph->checkState() != t_eph::outdated) {
173 deque<t_eph*>& qq = _eph[prn];
174 qq.push_back(newEph);
175 if (qq.size() > _maxQueueSize) {
176 delete qq.front();
177 qq.pop_front();
178 }
179 ephBufferChanged();
180 return success;
181 }
182 else {
183 delete newEph;
184 return failure;
185 }
186}
187
188//
189////////////////////////////////////////////////////////////////////////////
190void bncEphUser::checkEphemeris(t_eph* eph, bool realTime) {
191
192 if (!eph) {
193 return;
194 }
195
196 // Check health status
197 // -------------------
198 if (eph->isUnhealthy()) {
199 eph->setCheckState(t_eph::unhealthy);
200 return;
201 }
202
203 // Simple Check - check satellite radial distance
204 // ----------------------------------------------
205 ColumnVector xc(6);
206 ColumnVector vv(3);
207 if (eph->getCrd(eph->TOC(), xc, vv, false) != success) {
208 eph->setCheckState(t_eph::bad);
209 return;
210 }
211 double rr = xc.Rows(1,3).norm_Frobenius();
212
213 const double MINDIST = 2.e7;
214 const double MAXDIST = 6.e7;
215 if (rr < MINDIST || rr > MAXDIST || std::isnan(rr)) {
216 eph->setCheckState(t_eph::bad);
217 return;
218 }
219
220 // Check whether the epoch is too far away the current time
221 // --------------------------------------------------------
222 if (realTime) {
223 bncTime toc = eph->TOC();
224 QDateTime now = currentDateAndTimeGPS();
225 bncTime currentTime(now.toString(Qt::ISODate).toStdString());
226 double dt = currentTime - toc;
227
228 // update interval: 2h, data sets are valid for 4 hours
229 if (eph->type() == t_eph::GPS && (dt > 4*3600.0 || dt < -2*3600.0)) {
230 eph->setCheckState(t_eph::outdated);
231 return;
232 }
233 // update interval: 3h, data sets are valid for 4 hours
234 else if (eph->type() == t_eph::Galileo && (dt > 4*3600.0 || dt < 0.0)) {
235 eph->setCheckState(t_eph::outdated);
236 return;
237 }
238 // updated every 30 minutes
239 else if (eph->type() == t_eph::GLONASS && (dt > 1*3600.0 || dt < -1800.0)) {
240 eph->setCheckState(t_eph::outdated);
241 return;
242 }
243 // orbit parameters are valid for 7200 seconds (minimum)
244 else if (eph->type() == t_eph::QZSS && (dt > 2*3600.0 || dt < -1*3600.0)) {
245 eph->setCheckState(t_eph::outdated);
246 return;
247 }
248 // maximum update interval: 300 sec
249 else if (eph->type() == t_eph::SBAS && (dt > 600 || dt < -300.0)) {
250 eph->setCheckState(t_eph::outdated);
251 return;
252 }
253 // updates 1h (GEO) up to 6 hours non-GEO
254 else if (eph->type() == t_eph::BDS && (dt > 6*3600 || dt < 0.0)) {
255 eph->setCheckState(t_eph::outdated);
256 return;
257 }
258 // update interval: up to 24 hours
259 else if (eph->type() == t_eph::IRNSS && fabs(dt > 24*3600.0)) {
260 eph->setCheckState(t_eph::outdated);
261 return;
262 }
263 }
264
265 // Check consistency with older ephemeris
266 // --------------------------------------
267 const double MAXDIFF = 10.0;
268 const double MINDIFF = 0.005;
269 QString prn = QString(eph->prn().toInternalString().c_str());
270 t_eph* ephL = ephLast(prn);
271
272 if (ephL) {
273 ColumnVector xcL(6);
274 ColumnVector vvL(3);
275 ephL->getCrd(eph->TOC(), xcL, vvL, false);
276
277 double diff = (xc.Rows(1,3) - xcL.Rows(1,3)).norm_Frobenius();
278 double diffC = fabs(xc(4) - xcL(4)) * t_CST::c;
279
280 if (diff < MAXDIFF && diffC < MAXDIFF) {
281 if (diff < MINDIFF && diffC < MINDIFF &&
282 ephL->checkState() == t_eph::ok) {
283 // to prevent the same data sets with different TOC values
284 eph->setCheckState(t_eph::bad);
285 }
286 else {
287 eph->setCheckState(t_eph::ok);
288 ephL->setCheckState(t_eph::ok);
289 }
290 }
291 else {
292 if (ephL->checkState() == t_eph::ok) {
293 eph->setCheckState(t_eph::bad);
294 }
295 }
296
297 double dt = eph->TOC() - ephL->TOC();
298 // some lines to allow update of ephemeris data sets after an outage
299 // -----------------------------------------------------------------
300 // update interval: 2h,
301 // sometimes corrected BRDC sets are sent with TOC values 16 seconds
302 // before the nominal TOC (integer time)
303 if (eph->type() == t_eph::GPS && dt > (2*3600.0 + 60.0)) {
304 ephL->setCheckState(t_eph::outdated);
305 return;
306 }
307 // update interval: 3h,
308 else if (eph->type() == t_eph::Galileo && dt > (3*3600.0 + 60.0)) {
309 ephL->setCheckState(t_eph::outdated);
310 return;
311 }
312 // updated every 30 minutes
313 else if (eph->type() == t_eph::GLONASS && dt > ( 1800.0 + 60.0)) {
314 ephL->setCheckState(t_eph::outdated);
315 return;
316 }
317 // updated every ?
318 else if (eph->type() == t_eph::QZSS && dt > (2*3600.0 + 60.0)) {
319 ephL->setCheckState(t_eph::outdated);
320 return;
321 }
322 // maximum update interval: 300 sec
323 else if (eph->type() == t_eph::SBAS && dt > ( 300.0)) {
324 ephL->setCheckState(t_eph::outdated);
325 return;
326 }
327 // updates 1h (GEO) up to 6 hours non-GEO
328 else if (eph->type() == t_eph::BDS && dt > 6*3600.0) {
329 ephL->setCheckState(t_eph::outdated);
330 return;
331 }
332 // update interval: up to 24 hours
333 else if (eph->type() == t_eph::IRNSS && dt > 24*3600.0) {
334 ephL->setCheckState(t_eph::outdated);
335 return;
336 }
337 }
338}
339
340//
341////////////////////////////////////////////////////////////////////////////
342bool bncEphUser::newCorrectedGpsEphSet(const t_eph* eph) {
343
344 bool correctedGpsEphSet = false;
345 bool newCorrectedGpsEphSet = false;
346
347 if (eph->prn().system() != 'G') {
348 return newCorrectedGpsEphSet;
349 }
350
351 if ((fmod(eph->TOC().daysec()+16.0, 7200) == 0.0)) {
352 // sometimes corrected BRDC sets are sent with TOC values 16 seconds
353 // before the nominal TOC (integer time)
354 correctedGpsEphSet = true;
355 }
356
357 QString prn = QString(eph->prn().toInternalString().c_str());
358 t_eph* ephL = ephLast(prn);
359 if (!ephL) { // first set for GPS Sat
360 return correctedGpsEphSet;
361 }
362
363
364 double dt = eph->TOC() - ephL->TOC();
365 if (correctedGpsEphSet){
366 if (dt == 0.0) {
367 newCorrectedGpsEphSet = false;
368 }
369 else {
370 newCorrectedGpsEphSet = true;
371 }
372 }
373 return newCorrectedGpsEphSet;
374}
Note: See TracBrowser for help on using the repository browser.