source: ntrip/trunk/BNC/src/RTCM3/RTCM3coDecoder.cpp@ 11004

Last change on this file since 11004 was 11004, checked in by stuerze, 3 weeks ago

updates regarding RTCM-SSR

File size: 32.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: RTCM3coDecoder
30 *
31 * Purpose: RTCM3 Clock Orbit Decoder
32 *
33 * Author: L. Mervart
34 *
35 * Created: 05-May-2008
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <stdio.h>
42#include <math.h>
43
44#include "RTCM3coDecoder.h"
45#include "bncutils.h"
46#include "bncrinex.h"
47#include "bnccore.h"
48#include "bncsettings.h"
49#include "bnctime.h"
50
51using namespace std;
52
53// Constructor
54////////////////////////////////////////////////////////////////////////////
55RTCM3coDecoder::RTCM3coDecoder(const QString& staID) {
56
57 _staID = staID;
58
59 // File Output
60 // -----------
61 bncSettings settings;
62 QString path = settings.value("corrPath").toString();
63 if (!path.isEmpty()) {
64 expandEnvVar(path);
65 if ( path.length() > 0 && path[path.length()-1] != QDir::separator() ) {
66 path += QDir::separator();
67 }
68 _fileNameSkl = path + staID;
69 }
70 _out = 0;
71
72 connect(this, SIGNAL(newOrbCorrections(QList<t_orbCorr>)),
73 BNC_CORE, SLOT(slotNewOrbCorrections(QList<t_orbCorr>)));
74
75 connect(this, SIGNAL(newClkCorrections(QList<t_clkCorr>)),
76 BNC_CORE, SLOT(slotNewClkCorrections(QList<t_clkCorr>)));
77
78 connect(this, SIGNAL(newCodeBiases(QList<t_satCodeBias>)),
79 BNC_CORE, SLOT(slotNewCodeBiases(QList<t_satCodeBias>)));
80
81 connect(this, SIGNAL(newPhaseBiases(QList<t_satPhaseBias>)),
82 BNC_CORE, SLOT(slotNewPhaseBiases(QList<t_satPhaseBias>)));
83
84 connect(this, SIGNAL(newTec(t_vTec)),
85 BNC_CORE, SLOT(slotNewTec(t_vTec)));
86
87 connect(this, SIGNAL(providerIDChanged(QString)),
88 BNC_CORE, SIGNAL(providerIDChanged(QString)));
89
90 connect(this, SIGNAL(newMessage(QByteArray,bool)),
91 BNC_CORE, SLOT(slotMessage(const QByteArray,bool)));
92
93 reset();
94
95 _providerID[0] = -1;
96 _providerID[1] = -1;
97 _providerID[2] = -1;
98
99 _ssrCorr = 0;
100
101}
102
103// Destructor
104////////////////////////////////////////////////////////////////////////////
105RTCM3coDecoder::~RTCM3coDecoder() {
106 delete _out;
107 delete _ssrCorr;
108 _IODs.clear();
109 _orbCorrections.clear();
110 _clkCorrections.clear();
111 _lastClkCorrections.clear();
112 _codeBiases.clear();
113 _phaseBiases.clear();
114 _vTecMap.clear();
115}
116
117//
118////////////////////////////////////////////////////////////////////////////
119void RTCM3coDecoder::reset(bool resetPhaseBias) {
120 memset(&_clkOrb, 0, sizeof(_clkOrb));
121 memset(&_codeBias, 0, sizeof(_codeBias));
122 if (resetPhaseBias) {
123 memset(&_phaseBias, 0, sizeof(_phaseBias));
124 }
125 memset(&_vTEC, 0, sizeof(_vTEC));
126}
127
128// Reopen Output File
129////////////////////////////////////////////////////////////////////////
130void RTCM3coDecoder::reopen() {
131
132 if (!_fileNameSkl.isEmpty()) {
133
134 bncSettings settings;
135
136 QDateTime datTim = currentDateAndTimeGPS();
137
138 QString hlpStr = bncRinex::nextEpochStr(datTim,
139 settings.value("corrIntr").toString(), 3);
140
141 QString cntStr = (_fileNameSkl.contains("ION")) ? "_ION.ssr" : "_MC.ssr";
142
143 QString fileNameHlp = _fileNameSkl +
144 "_S_" + // stream
145 QString("%1").arg(datTim.date().year()) +
146 QString("%1").arg(datTim.date().dayOfYear(), 3, 10, QChar('0')) +
147 hlpStr + // HM_period
148 cntStr; // mixed ION or CLK
149
150 if (_fileName == fileNameHlp) {
151 return;
152 }
153 else {
154 _fileName = fileNameHlp;
155 }
156
157 delete _out;
158 if ( Qt::CheckState(settings.value("rnxAppend").toInt()) == Qt::Checked) {
159 _out = new ofstream( _fileName.toLatin1().data(), ios_base::out | ios_base::app );
160 }
161 else {
162 _out = new ofstream( _fileName.toLatin1().data() );
163 }
164 }
165}
166
167//
168////////////////////////////////////////////////////////////////////////////
169t_irc RTCM3coDecoder::Decode(char* buffer, int bufLen, vector<string>& errmsg) {
170
171 errmsg.clear();
172
173 _buffer.append(QByteArray(buffer,bufLen));
174
175 t_irc retCode = failure;
176
177 while(_buffer.size()) {
178
179 struct SsrCorr::ClockOrbit clkOrbSav;
180 struct SsrCorr::CodeBias codeBiasSav;
181 struct SsrCorr::PhaseBias phaseBiasSav;
182 struct SsrCorr::VTEC vTECSav;
183 struct SsrCorr::MetaData metaDataSav;
184 // save state
185 memcpy(&clkOrbSav, &_clkOrb, sizeof(clkOrbSav));
186 memcpy(&codeBiasSav, &_codeBias, sizeof(codeBiasSav));
187 memcpy(&phaseBiasSav, &_phaseBias, sizeof(phaseBiasSav));
188 memcpy(&vTECSav, &_vTEC, sizeof(vTECSav));
189 memcpy(&metaDataSav, &_metaData, sizeof(metaDataSav));
190
191 int bytesused = 0;
192
193 GCOB_RETURN irc = _ssrCorr->GetSSR(&_clkOrb, &_codeBias, &_vTEC, &_phaseBias, &_metaData,
194 _buffer.data(), _buffer.size(), &bytesused);
195
196 if (irc <= -30) { // not enough data - restore state and exit loop
197 memcpy(&_clkOrb, &clkOrbSav, sizeof(clkOrbSav));
198 memcpy(&_codeBias, &codeBiasSav, sizeof(codeBiasSav));
199 memcpy(&_phaseBias, &phaseBiasSav, sizeof(phaseBiasSav));
200 memcpy(&_vTEC, &vTECSav, sizeof(vTECSav));
201 memcpy(&metaDataSav, &_metaData, sizeof(metaDataSav));
202 break;
203 }
204
205 else if (irc < 0) { // error - skip this message (or 1 byte if the
206 // frame itself couldn't be recognized) and retry
207 if (irc != GCOBR_UNKNOWNTYPE) {
208 // A recognized-but-unimplemented message (e.g. Tropospheric or
209 // Regional Ionospheric Correction) leaves _clkOrb/_codeBias/
210 // _phaseBias/_vTEC untouched, and bytesused is already reliably set
211 // from its CRC-validated frame length, so there is nothing to
212 // discard. Every other error code may have left inconsistent
213 // partial state (e.g. mid-satellite-loop) or an unreliable frame
214 // boundary, so reset defensively there. Without this, streams with
215 // frequent unimplemented messages (e.g. dense grid-based Regional
216 // Ionospheric traffic) would wipe unrelated, still-valid orbit/
217 // clock/bias/phase-bias state every time one is skipped.
218 reset();
219 }
220 _buffer = _buffer.mid(bytesused ? bytesused : 1);
221 }
222
223 else { // OK or MESSAGEFOLLOWS
224 _buffer = _buffer.mid(bytesused);
225
226 if (irc == GCOBR_OK || irc == GCOBR_MESSAGEFOLLOWS ) {
227 setEpochTime(); // sets _lastTime
228
229 if (_lastTime.valid()) {
230 reopen();
231 checkProviderID();
232 sendResults();
233 retCode = success;
234 }
235 else {
236 emit newMessage("RTCM3coDecoder: _lastTime invalid: " + _staID.toLatin1(), true);
237 retCode = failure;
238 }
239 // Keep _phaseBias intact: an Extended Phase Bias message (COBOFS_PBEXT)
240 // arriving later needs to correlate against the satellite/signal list
241 // just published by this Phase Bias message. clock_orbit_rtcm_new.cpp's
242 // COBOFS_PBIAS handling resets pb->NumberOfSat[s] itself before decoding
243 // a fresh message, so this doesn't cause stale data to accumulate.
244 reset(false);
245 }
246 }
247 }
248
249 return retCode;
250}
251
252//
253////////////////////////////////////////////////////////////////////////////
254void RTCM3coDecoder::sendResults() {
255
256 // Orbit and clock corrections of all satellites
257 // ---------------------------------------------
258 for (unsigned ii = 0; ii < CLOCKORBIT_NUMGPS
259 + CLOCKORBIT_NUMGLONASS
260 + CLOCKORBIT_NUMGALILEO
261 + CLOCKORBIT_NUMQZSS
262 + CLOCKORBIT_NUMSBAS
263 + _clkOrb.NumberOfSat[CLOCKORBIT_SATBDS];
264 ii++) {
265 if (corrIsOutOfRange(_clkOrb.Sat[ii])) {
266 continue;
267 }
268 char sys = ' ';
269 int num = _clkOrb.Sat[ii].ID;
270 int flag = 0; // to force NAV type usage according SSR standard
271 if (ii < _clkOrb.NumberOfSat[CLOCKORBIT_SATGPS]) {
272 sys = 'G';
273 flag = t_eph::LNAV;
274 }
275 else if (ii >= CLOCKORBIT_OFFSETGLONASS &&
276 ii < CLOCKORBIT_OFFSETGLONASS + _clkOrb.NumberOfSat[CLOCKORBIT_SATGLONASS]) {
277 sys = 'R';
278 flag = t_eph::FDMA_M;
279 }
280 else if (ii >= CLOCKORBIT_OFFSETGALILEO &&
281 ii < CLOCKORBIT_OFFSETGALILEO + _clkOrb.NumberOfSat[CLOCKORBIT_SATGALILEO]) {
282 sys = 'E';
283 flag = t_eph::INAV;
284 }
285 else if (ii >= CLOCKORBIT_OFFSETQZSS &&
286 ii < CLOCKORBIT_OFFSETQZSS + _clkOrb.NumberOfSat[CLOCKORBIT_SATQZSS]) {
287 sys = 'J';
288 flag = t_eph::LNAV;
289 }
290 else if (ii >= CLOCKORBIT_OFFSETSBAS &&
291 ii < CLOCKORBIT_OFFSETSBAS + _clkOrb.NumberOfSat[CLOCKORBIT_SATSBAS]) {
292 sys = 'S';
293 flag = t_eph::SBASL1;
294 }
295 else if (ii >= CLOCKORBIT_OFFSETBDS &&
296 ii < CLOCKORBIT_OFFSETBDS + _clkOrb.NumberOfSat[CLOCKORBIT_SATBDS]) {
297 sys = 'C';
298 if (num < 6) {// GEO
299 flag = t_eph::D2;
300 }
301 else if (num > 58 && num < 63) { // GEO
302 flag = t_eph::D2;
303 }
304 else {
305 flag = t_eph::D1;
306 }
307 }
308 else {
309 continue;
310 }
311
312 // Orbit correction
313 // ----------------
314 if ( _clkOrb.messageType == _ssrCorr->COTYPE_GPSCOMBINED ||
315 _clkOrb.messageType == _ssrCorr->COTYPE_GLONASSCOMBINED ||
316 _clkOrb.messageType == _ssrCorr->COTYPE_GALILEOCOMBINED ||
317 _clkOrb.messageType == _ssrCorr->COTYPE_QZSSCOMBINED ||
318 _clkOrb.messageType == _ssrCorr->COTYPE_SBASCOMBINED ||
319 _clkOrb.messageType == _ssrCorr->COTYPE_BDSCOMBINED ||
320 _clkOrb.messageType == _ssrCorr->COTYPE_GPSORBIT ||
321 _clkOrb.messageType == _ssrCorr->COTYPE_GLONASSORBIT ||
322 _clkOrb.messageType == _ssrCorr->COTYPE_GALILEOORBIT ||
323 _clkOrb.messageType == _ssrCorr->COTYPE_QZSSORBIT ||
324 _clkOrb.messageType == _ssrCorr->COTYPE_SBASORBIT ||
325 _clkOrb.messageType == _ssrCorr->COTYPE_BDSORBIT ) {
326
327 t_orbCorr orbCorr;
328 orbCorr._prn.set(sys, num, flag);
329 orbCorr._staID = _staID.toStdString();
330 orbCorr._iod = _clkOrb.Sat[ii].IOD;
331 orbCorr._time = _lastTime;
332 orbCorr._updateInt = _clkOrb.UpdateInterval;
333 orbCorr._system = sys;
334 orbCorr._xr[0] = _clkOrb.Sat[ii].Orbit.DeltaRadial;
335 orbCorr._xr[1] = _clkOrb.Sat[ii].Orbit.DeltaAlongTrack;
336 orbCorr._xr[2] = _clkOrb.Sat[ii].Orbit.DeltaCrossTrack;
337 orbCorr._dotXr[0] = _clkOrb.Sat[ii].Orbit.DotDeltaRadial;
338 orbCorr._dotXr[1] = _clkOrb.Sat[ii].Orbit.DotDeltaAlongTrack;
339 orbCorr._dotXr[2] = _clkOrb.Sat[ii].Orbit.DotDeltaCrossTrack;
340 orbCorr._ssrFormat = (_type == RTCMssr) ? ssrRtcmOld :
341 (_type == RTCMnewssr) ? ssrRtcmNew : ssrUnknown;
342
343 _orbCorrections[_lastTime].append(orbCorr);
344
345 _IODs[orbCorr._prn] = _clkOrb.Sat[ii].IOD;
346 }
347
348 // Clock Corrections
349 // -----------------
350 if ( _clkOrb.messageType == _ssrCorr->COTYPE_GPSCOMBINED ||
351 _clkOrb.messageType == _ssrCorr->COTYPE_GLONASSCOMBINED ||
352 _clkOrb.messageType == _ssrCorr->COTYPE_GALILEOCOMBINED ||
353 _clkOrb.messageType == _ssrCorr->COTYPE_QZSSCOMBINED ||
354 _clkOrb.messageType == _ssrCorr->COTYPE_SBASCOMBINED ||
355 _clkOrb.messageType == _ssrCorr->COTYPE_BDSCOMBINED ||
356 _clkOrb.messageType == _ssrCorr->COTYPE_GPSCLOCK ||
357 _clkOrb.messageType == _ssrCorr->COTYPE_GLONASSCLOCK ||
358 _clkOrb.messageType == _ssrCorr->COTYPE_GALILEOCLOCK ||
359 _clkOrb.messageType == _ssrCorr->COTYPE_QZSSCLOCK ||
360 _clkOrb.messageType == _ssrCorr->COTYPE_SBASCLOCK ||
361 _clkOrb.messageType == _ssrCorr->COTYPE_BDSCLOCK) {
362
363 t_clkCorr clkCorr;
364 clkCorr._prn.set(sys, _clkOrb.Sat[ii].ID, flag);
365 clkCorr._staID = _staID.toStdString();
366 clkCorr._time = _lastTime;
367 clkCorr._updateInt = _clkOrb.UpdateInterval;
368 clkCorr._dClk = _clkOrb.Sat[ii].Clock.DeltaA0 / t_CST::c;
369 clkCorr._dotDClk = _clkOrb.Sat[ii].Clock.DeltaA1 / t_CST::c;
370 clkCorr._dotDotDClk = _clkOrb.Sat[ii].Clock.DeltaA2 / t_CST::c;
371
372 _lastClkCorrections[clkCorr._prn] = clkCorr;
373
374 if (_IODs.contains(clkCorr._prn)) {
375 clkCorr._iod = _IODs[clkCorr._prn];
376 _clkCorrections[_lastTime].append(clkCorr);
377 }
378 }
379
380 // High-Resolution Clocks
381 // ----------------------
382 if ( _clkOrb.messageType == _ssrCorr->COTYPE_GPSHR ||
383 _clkOrb.messageType == _ssrCorr->COTYPE_GLONASSHR ||
384 _clkOrb.messageType == _ssrCorr->COTYPE_GALILEOHR ||
385 _clkOrb.messageType == _ssrCorr->COTYPE_QZSSHR ||
386 _clkOrb.messageType == _ssrCorr->COTYPE_SBASHR ||
387 _clkOrb.messageType == _ssrCorr->COTYPE_BDSHR) {
388 t_prn prn(sys, _clkOrb.Sat[ii].ID, flag);
389 if (_lastClkCorrections.contains(prn)) {
390 t_clkCorr clkCorr;
391 clkCorr = _lastClkCorrections[prn];
392 clkCorr._time = _lastTime;
393 clkCorr._updateInt = _clkOrb.UpdateInterval;
394 clkCorr._dClk += _clkOrb.Sat[ii].hrclock / t_CST::c;
395 if (_IODs.contains(clkCorr._prn)) {
396 clkCorr._iod = _IODs[clkCorr._prn];
397 _clkCorrections[_lastTime].append(clkCorr);
398 }
399 }
400 }
401 }
402
403 // Code Biases
404 // -----------
405 for (unsigned ii = 0; ii < CLOCKORBIT_NUMGPS
406 + CLOCKORBIT_NUMGLONASS
407 + CLOCKORBIT_NUMGALILEO
408 + CLOCKORBIT_NUMQZSS
409 + CLOCKORBIT_NUMSBAS
410 + _codeBias.NumberOfSat[CLOCKORBIT_SATBDS];
411 ii++) {
412 char sys = ' ';
413 int num = _codeBias.Sat[ii].ID;
414 int flag = 0;
415 if (ii < _codeBias.NumberOfSat[CLOCKORBIT_SATGPS]) {
416 sys = 'G';
417 flag = t_eph::LNAV;
418 }
419 else if (ii >= CLOCKORBIT_OFFSETGLONASS &&
420 ii < CLOCKORBIT_OFFSETGLONASS + _codeBias.NumberOfSat[CLOCKORBIT_SATGLONASS]) {
421 sys = 'R';
422 flag = t_eph::FDMA_M;
423 }
424 else if (ii >= CLOCKORBIT_OFFSETGALILEO &&
425 ii < CLOCKORBIT_OFFSETGALILEO + _codeBias.NumberOfSat[CLOCKORBIT_SATGALILEO]) {
426 sys = 'E';
427 flag = t_eph::INAV;
428 }
429 else if (ii >= CLOCKORBIT_OFFSETQZSS &&
430 ii < CLOCKORBIT_OFFSETQZSS + _codeBias.NumberOfSat[CLOCKORBIT_SATQZSS]) {
431 sys = 'J';
432 flag = t_eph::LNAV;
433 }
434 else if (ii >= CLOCKORBIT_OFFSETSBAS &&
435 ii < CLOCKORBIT_OFFSETSBAS + _codeBias.NumberOfSat[CLOCKORBIT_SATSBAS]) {
436 sys = 'S';
437 flag = t_eph::SBASL1;
438 }
439 else if (ii >= CLOCKORBIT_OFFSETBDS &&
440 ii < CLOCKORBIT_OFFSETBDS + _codeBias.NumberOfSat[CLOCKORBIT_SATBDS]) {
441 sys = 'C';
442 if (num < 6) {// GEO
443 flag = t_eph::D2;
444 }
445 else if (num > 58 && num < 63) { // GEO
446 flag = t_eph::D2;
447 }
448 else {
449 flag = t_eph::D1;
450 }
451 }
452 else {
453 continue;
454 }
455 t_satCodeBias satCodeBias;
456 satCodeBias._prn.set(sys, num, flag);
457 satCodeBias._staID = _staID.toStdString();
458 satCodeBias._time = _lastTime;
459 satCodeBias._updateInt = _codeBias.UpdateInterval;
460 for (unsigned jj = 0; jj < _codeBias.Sat[ii].NumberOfCodeBiases; jj++) {
461 const SsrCorr::CodeBias::BiasSat::CodeBiasEntry& biasEntry = _codeBias.Sat[ii].Biases[jj];
462 t_frqCodeBias frqCodeBias;
463 frqCodeBias._rnxType2ch.assign(_ssrCorr->codeTypeToRnxType(sys, biasEntry.Type));
464 frqCodeBias._value = biasEntry.Bias;
465 if (!frqCodeBias._rnxType2ch.empty()) {
466 satCodeBias._bias.push_back(frqCodeBias);
467 }
468 }
469 _codeBiases[_lastTime].append(satCodeBias);
470 }
471
472 // Phase Biases
473 // -----------
474 for (unsigned ii = 0; ii < CLOCKORBIT_NUMGPS
475 + CLOCKORBIT_NUMGLONASS
476 + CLOCKORBIT_NUMGALILEO
477 + CLOCKORBIT_NUMQZSS
478 + CLOCKORBIT_NUMSBAS
479 + _phaseBias.NumberOfSat[CLOCKORBIT_SATBDS];
480 ii++) {
481 char sys = ' ';
482 int num = _phaseBias.Sat[ii].ID;
483 int flag = 0;
484 if (ii < _phaseBias.NumberOfSat[CLOCKORBIT_SATGPS]) {
485 sys = 'G';
486 flag = t_eph::LNAV;
487 }
488 else if (ii >= CLOCKORBIT_OFFSETGLONASS &&
489 ii < CLOCKORBIT_OFFSETGLONASS + _phaseBias.NumberOfSat[CLOCKORBIT_SATGLONASS]) {
490 sys = 'R';
491 flag = t_eph::FDMA_M;
492 }
493 else if (ii >= CLOCKORBIT_OFFSETGALILEO &&
494 ii < CLOCKORBIT_OFFSETGALILEO + _phaseBias.NumberOfSat[CLOCKORBIT_SATGALILEO]) {
495 sys = 'E';
496 flag = t_eph::INAV;
497 }
498 else if (ii >= CLOCKORBIT_OFFSETQZSS &&
499 ii < CLOCKORBIT_OFFSETQZSS + _phaseBias.NumberOfSat[CLOCKORBIT_SATQZSS]) {
500 sys = 'J';
501 flag = t_eph::LNAV;
502 }
503 else if (ii >= CLOCKORBIT_OFFSETSBAS &&
504 ii < CLOCKORBIT_OFFSETSBAS + _phaseBias.NumberOfSat[CLOCKORBIT_SATSBAS]) {
505 sys = 'S';
506 flag = t_eph::SBASL1;
507 }
508 else if (ii >= CLOCKORBIT_OFFSETBDS &&
509 ii < CLOCKORBIT_OFFSETBDS + _phaseBias.NumberOfSat[CLOCKORBIT_SATBDS]) {
510 sys = 'C';
511 if (num < 6) {// GEO
512 flag = t_eph::D2;
513 }
514 else if (num > 58 && num < 63) { // GEO
515 flag = t_eph::D2;
516 }
517 else {
518 flag = t_eph::D1;
519 }
520 }
521 else {
522 continue;
523 }
524 t_satPhaseBias satPhaseBias;
525 satPhaseBias._prn.set(sys, num, flag);
526 satPhaseBias._staID = _staID.toStdString();
527 satPhaseBias._time = _lastTime;
528 satPhaseBias._updateInt = _phaseBias.UpdateInterval;
529 satPhaseBias._ssrFormat = (_type == RTCMssr) ? ssrRtcmOld :
530 (_type == RTCMnewssr) ? ssrRtcmNew : ssrUnknown;
531 if (satPhaseBias._ssrFormat == e_ssrFormat::ssrRtcmNew) {
532 satPhaseBias._satYawInfoInd = _phaseBias.SatelliteYawInformationIndicator;
533 satPhaseBias._extPBPhaseInd = _phaseBias.ExtendedPhaseBiasPropertyID;
534 }
535 else {
536 satPhaseBias._dispBiasConsistInd = _phaseBias.DispersiveBiasConsistencyIndicator;
537 satPhaseBias._MelbWuebConsistInd = _phaseBias.MWConsistencyIndicator;
538 }
539 satPhaseBias._yaw = _phaseBias.Sat[ii].YawAngle;
540 satPhaseBias._yawRate = _phaseBias.Sat[ii].YawRate;
541 for (unsigned jj = 0; jj < _phaseBias.Sat[ii].NumberOfPhaseBiases; jj++) {
542 const SsrCorr::PhaseBias::PhaseBiasSat::PhaseBiasEntry& biasEntry = _phaseBias.Sat[ii].Biases[jj];
543 t_frqPhaseBias frqPhaseBias;
544 frqPhaseBias._rnxType2ch.assign(_ssrCorr->codeTypeToRnxType(sys, biasEntry.Type));
545 frqPhaseBias._value = biasEntry.Bias;
546 frqPhaseBias._fixIndicator = biasEntry.IntegerIndicator;
547 if (satPhaseBias._ssrFormat == e_ssrFormat::ssrRtcmNew) {
548 if (satPhaseBias._extPBPhaseInd) {
549 frqPhaseBias._fixWideLaneIndicator = biasEntry.WidelaneGroupIndicator;
550 }
551 }
552 else {
553 frqPhaseBias._fixWideLaneIndicator = biasEntry.WidelaneGroupIndicator;
554 }
555 frqPhaseBias._jumpCounter = biasEntry.DiscontinuityCounter;
556 if (!frqPhaseBias._rnxType2ch.empty()) {
557 satPhaseBias._bias.push_back(frqPhaseBias);
558 }
559 }
560 _phaseBiases[_lastTime].append(satPhaseBias);
561 }
562
563 // Ionospheric Model
564 // -----------------
565 if (_vTEC.NumLayers > 0) {
566 _vTecMap[_lastTime]._time = _lastTime;
567 _vTecMap[_lastTime]._updateInt = _vTEC.UpdateInterval;
568 _vTecMap[_lastTime]._staID = _staID.toStdString();
569 for (unsigned ii = 0; ii < _vTEC.NumLayers; ii++) {
570 const SsrCorr::VTEC::IonoLayers& ionoLayer = _vTEC.Layers[ii];
571 t_vTecLayer layer;
572 layer._height = ionoLayer.Height;
573 layer._C.ReSize(ionoLayer.Degree+1, ionoLayer.Order+1);
574 layer._S.ReSize(ionoLayer.Degree+1, ionoLayer.Order+1);
575 for (unsigned iDeg = 0; iDeg <= ionoLayer.Degree; iDeg++) {
576 for (unsigned iOrd = 0; iOrd <= ionoLayer.Order; iOrd++) {
577 layer._C[iDeg][iOrd] = ionoLayer.Cosinus[iDeg][iOrd];
578 layer._S[iDeg][iOrd] = ionoLayer.Sinus[iDeg][iOrd];
579 }
580 }
581 _vTecMap[_lastTime]._layers.push_back(layer);
582 }
583 }
584
585 // Dump all older epochs
586 // ---------------------
587 QMutableMapIterator<bncTime, QList<t_orbCorr> > itOrb(_orbCorrections);
588 while (itOrb.hasNext()) {
589 itOrb.next();
590 if (itOrb.key() < _lastTime) {
591 emit newOrbCorrections(itOrb.value());
592 t_orbCorr::writeEpoch(_out, itOrb.value());
593 itOrb.remove();
594 }
595 }
596 QMutableMapIterator<bncTime, QList<t_clkCorr> > itClk(_clkCorrections);
597 while (itClk.hasNext()) {
598 itClk.next();
599 if (itClk.key() < _lastTime) {
600 emit newClkCorrections(itClk.value());
601 t_clkCorr::writeEpoch(_out, itClk.value());
602 itClk.remove();
603 }
604 }
605 QMutableMapIterator<bncTime, QList<t_satCodeBias> > itCB(_codeBiases);
606 while (itCB.hasNext()) {
607 itCB.next();
608 if (itCB.key() < _lastTime) {
609 emit newCodeBiases(itCB.value());
610 t_satCodeBias::writeEpoch(_out, itCB.value());
611 itCB.remove();
612 }
613 }
614 QMutableMapIterator<bncTime, QList<t_satPhaseBias> > itPB(_phaseBiases);
615 while (itPB.hasNext()) {
616 itPB.next();
617 if (itPB.key() < _lastTime) {
618 emit newPhaseBiases(itPB.value());
619 t_satPhaseBias::writeEpoch(_out, itPB.value());
620 itPB.remove();
621 }
622 }
623 QMutableMapIterator<bncTime, t_vTec> itTec(_vTecMap);
624 while (itTec.hasNext()) {
625 itTec.next();
626 if (itTec.key() < _lastTime) {
627 emit newTec(itTec.value());
628 t_vTec::write(_out, itTec.value());
629 itTec.remove();
630 }
631 }
632}
633
634//
635////////////////////////////////////////////////////////////////////////////
636void RTCM3coDecoder::checkProviderID() {
637
638 if (_clkOrb.SSRProviderID == 0 && _clkOrb.SSRSolutionID == 0 && _clkOrb.SSRIOD == 0) {
639 return;
640 }
641
642 int newProviderID[3];
643 newProviderID[0] = _clkOrb.SSRProviderID;
644 newProviderID[1] = _clkOrb.SSRSolutionID;
645 newProviderID[2] = _clkOrb.SSRIOD;
646 QString newProviderIDStr = QString(" [SSR Provider ID: %1 SSR Solution ID: %2 SSR IOD: %3]: ")
647 .arg(newProviderID[0]).arg(newProviderID[1]).arg(newProviderID[2]);
648
649 bool alreadySet = false;
650 bool different = false;
651
652 for (unsigned ii = 0; ii < 3; ii++) {
653 if (_providerID[ii] != -1) {
654 alreadySet = true;
655 }
656 if (_providerID[ii] != newProviderID[ii]) {
657 different = true;
658 }
659 _providerID[ii] = newProviderID[ii];
660 }
661
662 if (alreadySet && different) {
663 emit newMessage("RTCM3coDecoder: SSR Provider or Service changed " + newProviderIDStr.toLatin1() + _staID.toLatin1(), true);
664 emit providerIDChanged(_staID);
665 }
666}
667
668// Check corrections
669////////////////////////////////////////////////////////////////////////////
670bool RTCM3coDecoder::corrIsOutOfRange(const SsrCorr::ClockOrbit::SatData& coSat) {
671
672 QString ssrParStr;
673 QString ssrParValue;
674 bool corrIsOutOfRange = false;
675
676 switch (_type) {
677 // ======== //
678 // IGS SSR //
679 // ======== //
680 case IGSssr:
681 if (coSat.Clock.DeltaA0 < -209.7151 ||
682 coSat.Clock.DeltaA0 > +209.7151) {
683 ssrParStr = "Clock::DeltaA0";
684 ssrParValue = QString::number(coSat.Clock.DeltaA0, 'f', 4);
685 corrIsOutOfRange = true;
686 }
687 if (coSat.Clock.DeltaA1 < -1.048575 ||
688 coSat.Clock.DeltaA1 > +1.048575) {
689 ssrParStr = "Clock::DeltaA1";
690 ssrParValue = QString::number(coSat.Clock.DeltaA1, 'f', 6);
691 corrIsOutOfRange = true;
692 }
693 if (coSat.Clock.DeltaA2 < -1.3421772 ||
694 coSat.Clock.DeltaA2 > +1.3421772) {
695 ssrParStr = "Clock::DeltaA2";
696 ssrParValue = QString::number(coSat.Clock.DeltaA2, 'f', 7);
697 corrIsOutOfRange = true;
698 }
699
700 if (coSat.Orbit.DeltaRadial < -209.7151 ||
701 coSat.Orbit.DeltaRadial > +209.7151) {
702 ssrParStr = "Orbit::DeltaRadial";
703 ssrParValue = QString::number(coSat.Orbit.DeltaRadial, 'f', 4);
704 corrIsOutOfRange = true;
705 }
706
707 if (coSat.Orbit.DeltaAlongTrack < -209.7148 ||
708 coSat.Orbit.DeltaAlongTrack > +209.7148) {
709 ssrParStr = "Orbit::DeltaAlongTrack";
710 ssrParValue = QString::number(coSat.Orbit.DeltaAlongTrack, 'f', 4);
711 corrIsOutOfRange = true;
712 }
713 if (coSat.Orbit.DeltaCrossTrack < -209.7148 ||
714 coSat.Orbit.DeltaCrossTrack > +209.7148) {
715 ssrParStr = "Orbit::DeltaCrossTrack";
716 ssrParValue = QString::number(coSat.Orbit.DeltaCrossTrack, 'f', 4);
717 corrIsOutOfRange = true;
718 }
719
720 if (coSat.Orbit.DotDeltaRadial < -1.048575 ||
721 coSat.Orbit.DotDeltaRadial > +1.048575) {
722 ssrParStr = "Orbit::DotDeltaRadial";
723 ssrParValue = QString::number(coSat.Orbit.DotDeltaRadial, 'f', 6);
724 corrIsOutOfRange = true;
725 }
726 if (coSat.Orbit.DotDeltaAlongTrack < -1.048572 ||
727 coSat.Orbit.DotDeltaAlongTrack > +1.048572) {
728 ssrParStr = "Orbit::DotDeltaAlongTrack";
729 ssrParValue = QString::number(coSat.Orbit.DotDeltaAlongTrack, 'f', 6);
730 corrIsOutOfRange = true;
731 }
732 if (coSat.Orbit.DotDeltaCrossTrack < -1.048572 ||
733 coSat.Orbit.DotDeltaCrossTrack > +1.048572) {
734 ssrParStr = "Orbit::DotDeltaCrossTrack";
735 ssrParValue = QString::number(coSat.Orbit.DotDeltaCrossTrack, 'f', 6);
736 corrIsOutOfRange = true;
737 }
738 break;
739 //==========//
740 // RTCM SSR //
741 // =========//
742 case RTCMssr:
743 case RTCMnewssr:
744 if (coSat.Clock.DeltaA0 < -209.7151 ||
745 coSat.Clock.DeltaA0 > +209.7151) {
746 ssrParStr = "Clock::DeltaA0";
747 ssrParValue = QString::number(coSat.Clock.DeltaA0, 'f', 4);
748 corrIsOutOfRange = true;
749 }
750 if (coSat.Clock.DeltaA1 < -1.048575 ||
751 coSat.Clock.DeltaA1 > +1.048575) {
752 ssrParStr = "Clock::DeltaA1";
753 ssrParValue = QString::number(coSat.Clock.DeltaA1, 'f', 6);
754 corrIsOutOfRange = true;
755 }
756 if (coSat.Clock.DeltaA2 < -1.34217726 ||
757 coSat.Clock.DeltaA2 > +1.34217726) {
758 ssrParStr = "Clock::DeltaA2";
759 ssrParValue = QString::number(coSat.Clock.DeltaA2, 'f', 8);
760 corrIsOutOfRange = true;
761 }
762
763 if (coSat.Orbit.DeltaRadial < -209.7151 ||
764 coSat.Orbit.DeltaRadial > +209.7151) {
765 ssrParStr = "Orbit::DeltaRadial";
766 ssrParValue = QString::number(coSat.Orbit.DeltaRadial, 'f', 4);
767 corrIsOutOfRange = true;
768 }
769
770 if (coSat.Orbit.DeltaAlongTrack < -209.7148 ||
771 coSat.Orbit.DeltaAlongTrack > +209.7148) {
772 ssrParStr = "Orbit::DeltaAlongTrack";
773 ssrParValue = QString::number(coSat.Orbit.DeltaAlongTrack, 'f', 4);
774 corrIsOutOfRange = true;
775 }
776 if (coSat.Orbit.DeltaCrossTrack < -209.7148 ||
777 coSat.Orbit.DeltaCrossTrack > +209.7148) {
778 ssrParStr = "Orbit::DeltaCrossTrack";
779 ssrParValue = QString::number(coSat.Orbit.DeltaCrossTrack, 'f', 4);
780 corrIsOutOfRange = true;
781 }
782
783 if (coSat.Orbit.DotDeltaRadial < -1.048575 ||
784 coSat.Orbit.DotDeltaRadial > +1.048575) {
785 ssrParStr = "Orbit::DotDeltaRadial";
786 ssrParValue = QString::number(coSat.Orbit.DotDeltaRadial, 'f', 6);
787 corrIsOutOfRange = true;
788 }
789 if (coSat.Orbit.DotDeltaAlongTrack < -1.048572 ||
790 coSat.Orbit.DotDeltaAlongTrack > +1.048572) {
791 ssrParStr = "Orbit::DotDeltaAlongTrack";
792 ssrParValue = QString::number(coSat.Orbit.DotDeltaAlongTrack, 'f', 6);
793 corrIsOutOfRange = true;
794 }
795 if (coSat.Orbit.DotDeltaCrossTrack < -1.048572 ||
796 coSat.Orbit.DotDeltaCrossTrack > +1.048572) {
797 ssrParStr = "Orbit::DotDeltaCrossTrack";
798 ssrParValue = QString::number(coSat.Orbit.DotDeltaCrossTrack, 'f', 6);
799 corrIsOutOfRange = true;
800 }
801 break;
802 }
803
804 if (corrIsOutOfRange) {
805 emit newMessage("RTCM3coDecoder: Correction " + ssrParStr.toLatin1()
806 + " (" + ssrParValue.toLatin1() + ") "
807 + "is out of range " + _staID.toLatin1(), true);
808 }
809
810 return corrIsOutOfRange;
811}
812
813//
814////////////////////////////////////////////////////////////////////////////
815void RTCM3coDecoder::setEpochTime() {
816
817 _lastTime.reset();
818
819 double epoSecGPS = -1.0;
820 double epoSecGlo = -1.0;
821 double epoSecGal = -1.0;
822 double epoSecQzss = -1.0;
823 double epoSecSbas = -1.0;
824 double epoSecBds = -1.0;
825 if (_clkOrb.NumberOfSat[CLOCKORBIT_SATGPS] > 0) {
826 epoSecGPS = _clkOrb.EpochTime[CLOCKORBIT_SATGPS]; // 0 .. 604799 s
827 }
828 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATGPS] > 0) {
829 epoSecGPS = _codeBias.EpochTime[CLOCKORBIT_SATGPS]; // 0 .. 604799 s
830 }
831 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATGPS] > 0) {
832 epoSecGPS = _phaseBias.EpochTime[CLOCKORBIT_SATGPS]; // 0 .. 604799 s
833 }
834 else if (_vTEC.NumLayers > 0) {
835 epoSecGPS = _vTEC.EpochTime; // 0 .. 604799 s
836 }
837 else if (_clkOrb.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) {
838 epoSecGlo = _clkOrb.EpochTime[CLOCKORBIT_SATGLONASS]; // 0 .. 86399 s
839 }
840 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) {
841 epoSecGlo = _codeBias.EpochTime[CLOCKORBIT_SATGLONASS]; // 0 .. 86399 s
842 }
843 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATGLONASS] > 0) {
844 epoSecGlo = _phaseBias.EpochTime[CLOCKORBIT_SATGLONASS]; // 0 .. 86399 s
845 }
846 else if (_clkOrb.NumberOfSat[CLOCKORBIT_SATGALILEO] > 0) {
847 epoSecGal = _clkOrb.EpochTime[CLOCKORBIT_SATGALILEO];
848 }
849 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATGALILEO] > 0) {
850 epoSecGal = _codeBias.EpochTime[CLOCKORBIT_SATGALILEO];
851 }
852 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATGALILEO] > 0) {
853 epoSecGal = _phaseBias.EpochTime[CLOCKORBIT_SATGALILEO];
854 }
855 else if (_clkOrb.NumberOfSat[CLOCKORBIT_SATQZSS] > 0) {
856 epoSecQzss = _clkOrb.EpochTime[CLOCKORBIT_SATQZSS];
857 }
858 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATQZSS] > 0) {
859 epoSecQzss = _codeBias.EpochTime[CLOCKORBIT_SATQZSS];
860 }
861 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATQZSS] > 0) {
862 epoSecQzss = _phaseBias.EpochTime[CLOCKORBIT_SATQZSS];
863 }
864 else if (_clkOrb.NumberOfSat[CLOCKORBIT_SATSBAS] > 0) {
865 epoSecSbas = _clkOrb.EpochTime[CLOCKORBIT_SATSBAS];
866 }
867 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATSBAS] > 0) {
868 epoSecSbas = _codeBias.EpochTime[CLOCKORBIT_SATSBAS];
869 }
870 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATSBAS] > 0) {
871 epoSecSbas = _phaseBias.EpochTime[CLOCKORBIT_SATSBAS];
872 }
873 else if (_clkOrb.NumberOfSat[CLOCKORBIT_SATBDS] > 0) {
874 epoSecBds = _clkOrb.EpochTime[CLOCKORBIT_SATBDS];
875 }
876 else if (_codeBias.NumberOfSat[CLOCKORBIT_SATBDS] > 0) {
877 epoSecBds = _codeBias.EpochTime[CLOCKORBIT_SATBDS];
878 }
879 else if (_phaseBias.NumberOfSat[CLOCKORBIT_SATBDS] > 0) {
880 epoSecBds = _phaseBias.EpochTime[CLOCKORBIT_SATBDS];
881 }
882
883 // Retrieve current time
884 // ---------------------
885 int currentWeek = 0;
886 double currentSec = 0.0;
887 currentGPSWeeks(currentWeek, currentSec);
888 bncTime currentTime(currentWeek, currentSec);
889
890 // Set _lastTime close to currentTime
891 // ----------------------------------
892 if (epoSecGPS != -1) {
893 _lastTime.set(currentWeek, epoSecGPS);
894 }
895 else if (epoSecGlo != -1) {
896 QDate date = dateAndTimeFromGPSweek(currentTime.gpsw(), currentTime.gpssec()).date();
897 if (_type == IGSssr) {
898 epoSecGlo = epoSecGlo + gnumleap(date.year(), date.month(), date.day());
899 }
900 if (_type == RTCMssr) {
901 epoSecGlo = epoSecGlo - 3 * 3600 + gnumleap(date.year(), date.month(), date.day());
902 }
903 _lastTime.set(currentWeek, epoSecGlo);
904 }
905 else if (epoSecGal != -1) {
906 _lastTime.set(currentWeek, epoSecGal);
907 }
908 else if (epoSecQzss != -1) {
909 _lastTime.set(currentWeek, epoSecQzss);
910 }
911 else if (epoSecSbas != -1) {
912 _lastTime.set(currentWeek, epoSecSbas);
913 }
914 else if (epoSecBds != -1) {
915 epoSecBds += 14.0;
916 if (epoSecBds > 604800.0) {
917 epoSecBds -= 7.0*24.0*60.0*60.0;
918 }
919 _lastTime.set(currentWeek, epoSecBds);
920 }
921
922 if (_lastTime.valid()) {
923 double maxDiff = 12 * 3600.0;
924 while (_lastTime < currentTime - maxDiff) {
925 _lastTime = _lastTime + maxDiff;
926 }
927 while (_lastTime > currentTime + maxDiff) {
928 _lastTime = _lastTime - maxDiff;
929 }
930 }
931}
Note: See TracBrowser for help on using the repository browser.