source: ntrip/trunk/BNC/src/RTCM/RTCM2Decoder.cpp@ 7071

Last change on this file since 7071 was 7055, checked in by stuerze, 10 years ago

IOD data type changed, to support IODs computed from CRC over broadcasted ephemris and clock parameters

File size: 11.8 KB
RevLine 
[297]1// Part of BNC, a utility for retrieving decoding and
[464]2// converting GNSS data streams from NTRIP broadcasters.
[242]3//
[464]4// Copyright (C) 2007
[297]5// German Federal Agency for Cartography and Geodesy (BKG)
6// http://www.bkg.bund.de
[464]7// Czech Technical University Prague, Department of Geodesy
[297]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.
[242]24
[464]25/* -------------------------------------------------------------------------
26 * BKG NTRIP Client
27 * -------------------------------------------------------------------------
28 *
29 * Class: RTCM2Decoder
30 *
31 * Purpose: RTCM2 Decoder
32 *
33 * Author: L. Mervart
34 *
35 * Created: 24-Aug-2006
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
[1044]41#include <math.h>
42#include <sstream>
43#include <iomanip>
[1218]44#include <set>
[1044]45
[242]46#include "../bncutils.h"
[1044]47#include "rtcm_utils.h"
[243]48#include "RTCM2Decoder.h"
[242]49
50using namespace std;
[1044]51using namespace rtcm2;
[242]52
53//
54// Constructor
55//
56
[6443]57RTCM2Decoder::RTCM2Decoder(const std::string& ID) : _ephUser(true) {
[1044]58 _ID = ID;
[242]59}
60
61//
62// Destructor
63//
64
65RTCM2Decoder::~RTCM2Decoder() {
66}
67
68//
[1044]69t_irc RTCM2Decoder::getStaCrd(double& xx, double& yy, double& zz) {
[6703]70 if (!_msg03.validMsg) {
[1044]71 return failure;
72 }
[6703]73
[1044]74 xx = _msg03.x + (_msg22.validMsg ? _msg22.dL1[0] : 0.0);
75 yy = _msg03.y + (_msg22.validMsg ? _msg22.dL1[1] : 0.0);
76 zz = _msg03.z + (_msg22.validMsg ? _msg22.dL1[2] : 0.0);
[242]77
[1044]78 return success;
79}
80
[1167]81//
[6703]82t_irc RTCM2Decoder::getStaCrd(double& xx, double& yy, double& zz, double& dx1,
83 double& dy1, double& dz1, double& dx2, double& dy2, double& dz2) {
[1167]84 xx = _msg03.x;
85 yy = _msg03.y;
86 zz = _msg03.z;
[1044]87
[1167]88 dx1 = (_msg22.validMsg ? _msg22.dL1[0] : 0.0);
89 dy1 = (_msg22.validMsg ? _msg22.dL1[1] : 0.0);
90 dz1 = (_msg22.validMsg ? _msg22.dL1[2] : 0.0);
91
92 dx2 = (_msg22.validMsg ? _msg22.dL2[0] : 0.0);
93 dy2 = (_msg22.validMsg ? _msg22.dL2[1] : 0.0);
94 dz2 = (_msg22.validMsg ? _msg22.dL2[2] : 0.0);
95
96 return success;
97}
98
[1044]99//
[1218]100t_irc RTCM2Decoder::Decode(char* buffer, int bufLen, vector<string>& errmsg) {
[242]101
[1218]102 errmsg.clear();
103
[242]104 _buffer.append(buffer, bufLen);
[6703]105 int refWeek;
[242]106 double refSecs;
107 currentGPSWeeks(refWeek, refSecs);
[702]108 bool decoded = false;
[242]109
[6703]110 while (true) {
[242]111 _PP.getPacket(_buffer);
112 if (!_PP.valid()) {
[702]113 if (decoded) {
114 return success;
115 } else {
116 return failure;
117 }
[242]118 }
[6703]119
[1268]120 // Store message number
121 _typeList.push_back(_PP.ID());
[242]122
[6703]123 if (_PP.ID() == 18 || _PP.ID() == 19) {
[242]124
125 _ObsBlock.extract(_PP);
126
127 if (_ObsBlock.valid()) {
[702]128 decoded = true;
[242]129
[6703]130 int epochWeek;
[242]131 double epochSecs;
132 _ObsBlock.resolveEpoch(refWeek, refSecs, epochWeek, epochSecs);
[6703]133
134 for (int iSat = 0; iSat < _ObsBlock.nSat; iSat++) {
[6137]135 t_satObs obs;
[341]136 if (_ObsBlock.PRN[iSat] > 100) {
[6137]137 obs._prn.set('R', _ObsBlock.PRN[iSat] % 100);
[6703]138 } else {
[6194]139 obs._prn.set('G', _ObsBlock.PRN[iSat]);
[6703]140 }
[6194]141 char sys = obs._prn.system();
[6137]142 obs._time.set(epochWeek, epochSecs);
[6703]143
[6137]144 t_frqObs* frqObs1C = new t_frqObs;
[6703]145 frqObs1C->_rnxType2ch = "1C";
146 frqObs1C->_codeValid = true;
147 frqObs1C->_code = _ObsBlock.rng_C1[iSat];
[6137]148 obs._obs.push_back(frqObs1C);
[2711]149
[6137]150 t_frqObs* frqObs1P = new t_frqObs;
[6703]151 frqObs1P->_rnxType2ch = (sys == 'G') ? "1W" : "1P";
152 frqObs1P->_codeValid = true;
153 frqObs1P->_code = _ObsBlock.rng_P1[iSat];
154 frqObs1P->_phaseValid = true;
155 frqObs1P->_phase = _ObsBlock.resolvedPhase_L1(iSat);
[6137]156 frqObs1P->_slipCounter = _ObsBlock.slip_L1[iSat];
157 obs._obs.push_back(frqObs1P);
158
159 t_frqObs* frqObs2P = new t_frqObs;
[6703]160 frqObs2P->_rnxType2ch = (sys == 'G') ? "2W" : "2P";
161 frqObs2P->_codeValid = true;
162 frqObs2P->_code = _ObsBlock.rng_P2[iSat];
163 frqObs2P->_phaseValid = true;
164 frqObs2P->_phase = _ObsBlock.resolvedPhase_L2(iSat);
[6137]165 frqObs2P->_slipCounter = _ObsBlock.slip_L2[iSat];
166 obs._obs.push_back(frqObs2P);
167
[2711]168 _obsList.push_back(obs);
[242]169 }
170 _ObsBlock.clear();
171 }
172 }
[1044]173
[6703]174 else if (_PP.ID() == 20 || _PP.ID() == 21) {
[1044]175 _msg2021.extract(_PP);
176
177 if (_msg2021.valid()) {
[1045]178 decoded = true;
[6703]179 translateCorr2Obs(errmsg);
180 }
[1044]181 }
182
[6703]183 else if (_PP.ID() == 3) {
[1044]184 _msg03.extract(_PP);
185 }
186
[6703]187 else if (_PP.ID() == 22) {
[1044]188 _msg22.extract(_PP);
189 }
[1268]190
[6703]191 else if (_PP.ID() == 23) {
[1269]192 _msg23.extract(_PP);
193 }
[1268]194
[6703]195 else if (_PP.ID() == 24) {
[1269]196 _msg24.extract(_PP);
197 }
[1268]198
[1269]199 // Output for RTCM scan
[6703]200 if (_PP.ID() == 3) {
201 if (_msg03.validMsg) {
202 _antList.push_back(t_antInfo());
203
204 this->getStaCrd(_antList.back().xx, _antList.back().yy,
205 _antList.back().zz);
206
207 _antList.back().type = t_antInfo::APC;
208 _antList.back().message = _PP.ID();
[1269]209 }
[6703]210 } else if (_PP.ID() == 23) {
211 if (_msg23.validMsg) {
212 _antType.push_back(_msg23.antType.c_str());
[1269]213 }
[6703]214 } else if (_PP.ID() == 24) {
215 if (_msg24.validMsg) {
216 _antList.push_back(t_antInfo());
[3594]217
[6703]218 _antList.back().xx = _msg24.x;
219 _antList.back().yy = _msg24.y;
220 _antList.back().zz = _msg24.z;
221
222 _antList.back().height_f = true;
223 _antList.back().height = _msg24.h;
224
225 _antList.back().type = t_antInfo::ARP;
226 _antList.back().message = _PP.ID();
[1269]227 }
228 }
[242]229 }
[649]230 return success;
[242]231}
232
[1218]233void RTCM2Decoder::translateCorr2Obs(vector<string>& errmsg) {
[1044]234
[3580]235 QMutexLocker locker(&_mutex);
236
[6703]237 if (!_msg03.validMsg || !_msg2021.valid()) {
[1044]238 return;
239 }
240
241 double stax = _msg03.x + (_msg22.validMsg ? _msg22.dL1[0] : 0.0);
242 double stay = _msg03.y + (_msg22.validMsg ? _msg22.dL1[1] : 0.0);
243 double staz = _msg03.z + (_msg22.validMsg ? _msg22.dL1[2] : 0.0);
244
[6703]245 int refWeek;
[1044]246 double refSecs;
247 currentGPSWeeks(refWeek, refSecs);
248
249 // Resolve receiver time of measurement (see RTCM 2.3, page 4-42, Message 18, Note 1)
250 // ----------------------------------------------------------------------------------
[6703]251 double hoursec_est = _msg2021.hoursec(); // estimated time of measurement
252 double hoursec_rcv = rint(hoursec_est * 1e2) / 1e2; // receiver clock reading at hoursec_est
[1044]253 double rcv_clk_bias = (hoursec_est - hoursec_rcv) * c_light;
254
[6703]255 int GPSWeek;
[1044]256 double GPSWeeks;
[6703]257 resolveEpoch(hoursec_est, refWeek, refSecs, GPSWeek, GPSWeeks);
[1044]258
[6703]259 int GPSWeek_rcv;
[1044]260 double GPSWeeks_rcv;
[6703]261 resolveEpoch(hoursec_rcv, refWeek, refSecs, GPSWeek_rcv, GPSWeeks_rcv);
[1044]262
263 // Loop over all satellites
264 // ------------------------
265 for (RTCM2_2021::data_iterator icorr = _msg2021.data.begin();
[6703]266 icorr != _msg2021.data.end(); icorr++) {
[1044]267 const RTCM2_2021::HiResCorr* corr = icorr->second;
268
[1218]269 // beg test
[6703]270 if (corr->PRN >= 200) {
[1218]271 continue;
272 }
273 // end test
274
[3562]275 QString prn;
[6703]276 char sys;
[3562]277 if (corr->PRN < 200) {
[6194]278 sys = 'G';
[7043]279 prn = sys + QString("%1_0").arg(corr->PRN, 2, 10, QChar('0'));
[6703]280 } else {
[6194]281 sys = 'R';
[7043]282 prn = sys + QString("%1_0").arg(corr->PRN - 200, 2, 10, QChar('0'));
[3562]283 }
[1218]284
[1044]285 double L1 = 0;
286 double L2 = 0;
287 double P1 = 0;
288 double P2 = 0;
289 string obsT = "";
290
291 // new observation
[6137]292 t_satObs* new_obs = 0;
[1044]293
[6137]294 t_frqObs* frqObs1C = new t_frqObs;
[6703]295 frqObs1C->_rnxType2ch = "1C";
[6137]296 new_obs->_obs.push_back(frqObs1C);
297
298 t_frqObs* frqObs1P = new t_frqObs;
[6703]299 frqObs1P->_rnxType2ch = (sys == 'G') ? "1W" : "1P";
[6137]300 new_obs->_obs.push_back(frqObs1P);
301
302 t_frqObs* frqObs2P = new t_frqObs;
[6703]303 frqObs2P->_rnxType2ch = (sys == 'G') ? "2W" : "2P";
[6137]304 new_obs->_obs.push_back(frqObs2P);
305
[1218]306 // missing IOD
307 vector<string> missingIOD;
[6703]308 vector<string> hasIOD;
[1044]309 for (unsigned ii = 0; ii < 4; ii++) {
[7055]310 unsigned long IODcorr = 0;
[6703]311 double corrVal = 0;
312 const t_eph* eph = 0;
313 double* obsVal = 0;
[1044]314
315 switch (ii) {
[6703]316 case 0: // --- L1 ---
317 IODcorr = corr->IODp1;
318 corrVal = corr->phase1 * LAMBDA_1;
319 obsVal = &L1;
320 obsT = "L1";
321 break;
322 case 1: // --- L2 ---
323 IODcorr = corr->IODp2;
324 corrVal = corr->phase2 * LAMBDA_2;
325 obsVal = &L2;
326 obsT = "L2";
327 break;
328 case 2: // --- P1 ---
329 IODcorr = corr->IODr1;
330 corrVal = corr->range1;
331 obsVal = &P1;
332 obsT = "P1";
333 break;
334 case 3: // --- P2 ---
335 IODcorr = corr->IODr2;
336 corrVal = corr->range2;
337 obsVal = &P2;
338 obsT = "P2";
339 break;
340 default:
341 continue;
[1044]342 }
343
[1299]344 // Select corresponding ephemerides
[6443]345 const t_eph* ephLast = _ephUser.ephLast(prn);
346 const t_eph* ephPrev = _ephUser.ephPrev(prn);
[6703]347 if (ephLast && ephLast->IOD() == IODcorr) {
[6443]348 eph = ephLast;
[6703]349 } else if (ephPrev && ephPrev->IOD() == IODcorr) {
[6443]350 eph = ephPrev;
[6442]351 }
[1218]352
[6703]353 if (eph) {
[1218]354 ostringstream msg;
355 msg << obsT << ':' << setw(3) << eph->IOD();
356 hasIOD.push_back(msg.str());
357
[6703]358 int GPSWeek_tot;
359 double GPSWeeks_tot;
360 double rho, xSat, ySat, zSat, clkSat;
361 cmpRho(eph, stax, stay, staz, GPSWeek, GPSWeeks, rho, GPSWeek_tot,
362 GPSWeeks_tot, xSat, ySat, zSat, clkSat);
[1218]363
[6703]364 *obsVal = rho - corrVal + rcv_clk_bias - clkSat;
[1044]365
[6703]366 if (*obsVal == 0)
367 *obsVal = ZEROVALUE;
[1044]368
[6703]369 // Allocate new memory
370 // -------------------
371 if (!new_obs) {
372 new_obs = new t_satObs();
[6137]373 if (corr->PRN < 200) {
374 new_obs->_prn.set('G', corr->PRN);
[6703]375 } else {
376 new_obs->_prn.set('R', corr->PRN - 200);
[6137]377 }
[6703]378 new_obs->_time.set(GPSWeek_rcv, GPSWeeks_rcv);
379 }
380
381 // Store estimated measurements
382 // ----------------------------
383 switch (ii) {
384 case 0: // --- L1 ---
385 frqObs1P->_phaseValid = true;
386 frqObs1P->_phase = *obsVal / LAMBDA_1;
387 frqObs1P->_slipCounter = corr->lock1;
388 break;
389 case 1: // --- L2 ---
390 frqObs2P->_phaseValid = true;
391 frqObs2P->_phase = *obsVal / LAMBDA_2;
392 frqObs2P->_slipCounter = corr->lock2;
393 break;
394 case 2: // --- C1 / P1 ---
395 if (corr->Pind1) {
396 frqObs1P->_codeValid = true;
397 frqObs1P->_code = *obsVal;
398 } else {
399 frqObs1C->_codeValid = true;
400 frqObs1C->_code = *obsVal;
401 }
402 break;
403 case 3: // --- C2 / P2 ---
404 if (corr->Pind2) {
405 frqObs2P->_codeValid = true;
406 frqObs2P->_code = *obsVal;
407 }
408 break;
409 default:
410 continue;
411 }
412 } else if (IODcorr != 0) {
[1218]413 ostringstream msg;
414 msg << obsT << ':' << setw(3) << IODcorr;
415 missingIOD.push_back(msg.str());
416 }
[1044]417 } // loop over frequencies
[6703]418
[1218]419 // Error report
[6703]420 if (missingIOD.size()) {
[1218]421 ostringstream missingIODstr;
422
[6703]423 copy(missingIOD.begin(), missingIOD.end(),
424 ostream_iterator<string>(missingIODstr, " "));
[1218]425
[6703]426 errmsg.push_back(
427 "missing eph for " + string(prn.toAscii().data()) + " , IODs "
428 + missingIODstr.str());
[1218]429 }
430
431 // Store new observation
[6703]432 if (new_obs) {
[2711]433 _obsList.push_back(*new_obs);
[2867]434 delete new_obs;
[1044]435 }
436 }
437}
Note: See TracBrowser for help on using the repository browser.