source: ntrip/trunk/BNC/bncpppclient.cpp@ 3635

Last change on this file since 3635 was 3635, checked in by mervart, 12 years ago
File size: 13.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: bncPPPclient
30 *
31 * Purpose: Precise Point Positioning
32 *
33 * Author: L. Mervart
34 *
35 * Created: 21-Nov-2009
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <newmatio.h>
42#include <iomanip>
43#include <sstream>
44
45#include "bncpppclient.h"
46#include "bncapp.h"
47#include "bncutils.h"
48#include "bncconst.h"
49#include "bncmodel.h"
50#include "pppopt.h"
51
52using namespace std;
53
54// Constructor
55////////////////////////////////////////////////////////////////////////////
56bncPPPclient::bncPPPclient(QByteArray staID, t_pppOpt* opt) {
57
58 if (opt) {
59 _opt = opt;
60 _optOwner = false;
61 }
62 else {
63 _opt = new t_pppOpt();
64 _optOwner = true;
65 }
66
67 _staID = staID;
68 _model = new bncModel(staID);
69
70 connect(this, SIGNAL(newMessage(QByteArray,bool)),
71 ((bncApp*)qApp), SLOT(slotMessage(const QByteArray,bool)));
72
73 connect(((bncApp*)qApp), SIGNAL(newCorrections(QList<QString>)),
74 this, SLOT(slotNewCorrections(QList<QString>)));
75
76 connect(_model, SIGNAL(newNMEAstr(QByteArray)),
77 this, SIGNAL(newNMEAstr(QByteArray)));
78}
79
80// Destructor
81////////////////////////////////////////////////////////////////////////////
82bncPPPclient::~bncPPPclient() {
83 delete _model;
84 while (!_epoData.empty()) {
85 delete _epoData.front();
86 _epoData.pop();
87 }
88 QMapIterator<QString, t_corr*> ic(_corr);
89 while (ic.hasNext()) {
90 ic.next();
91 delete ic.value();
92 }
93 QMapIterator<QString, t_bias*> ib(_bias);
94 while (ib.hasNext()) {
95 ib.next();
96 delete ib.value();
97 }
98 if (_optOwner) {
99 delete _opt;
100 }
101}
102
103//
104////////////////////////////////////////////////////////////////////////////
105void bncPPPclient::putNewObs(const t_obs& obs) {
106 QMutexLocker locker(&_mutex);
107
108 if (obs.satSys == 'R') {
109 if (!_opt->useGlonass) return;
110 }
111 else if (obs.satSys == 'E') {
112 if (!_opt->useGalileo) return;
113 }
114 else if (obs.satSys != 'G') {
115 return;
116 }
117
118 t_satData* satData = new t_satData();
119 satData->tt = bncTime(obs.GPSWeek, obs.GPSWeeks);
120
121 // Satellite Number
122 // ----------------
123 satData->prn = QString("%1%2").arg(obs.satSys).arg(obs.satNum,2,10,QChar('0'));
124
125 // Check Slips
126 // -----------
127 slipInfo& sInfo = _slips[satData->prn];
128 if ( sInfo.slipCntL1 == obs.slip_cnt_L1 &&
129 sInfo.slipCntL2 == obs.slip_cnt_L2 &&
130 sInfo.slipCntL5 == obs.slip_cnt_L5 ) {
131 satData->slipFlag = false;
132 }
133 else {
134 satData->slipFlag = true;
135 }
136 sInfo.slipCntL1 = obs.slip_cnt_L1;
137 sInfo.slipCntL2 = obs.slip_cnt_L2;
138
139 // Handle Code Biases
140 // ------------------
141 t_bias* bb = 0;
142 if (_bias.contains(satData->prn)) {
143 bb = _bias.value(satData->prn);
144 }
145
146 // Add new epoch, process the older ones
147 // -------------------------------------
148 if (_epoData.size() == 0) {
149 _epoData.push(new t_epoData());
150 _epoData.back()->tt = satData->tt;
151 }
152 else if (satData->tt != _epoData.back()->tt) {
153 processEpochs();
154 _epoData.push(new t_epoData());
155 _epoData.back()->tt = satData->tt;
156 }
157
158 // Set Observations GPS
159 // --------------------
160 if (obs.satSys == 'G') {
161 if ( (obs.P1 || obs.C1) && (obs.P2 || obs.C2) && obs.L1() && obs.L2() ) {
162 double f1 = t_CST::freq1;
163 double f2 = t_CST::freq2;
164 double c1 = f1 * f1 / (f1 * f1 - f2 * f2);
165 double c2 = - f2 * f2 / (f1 * f1 - f2 * f2);
166 if (obs.P1) {
167 satData->P1 = obs.P1 + (bb ? bb->p1 : 0.0);
168 }
169 else {
170 satData->P1 = obs.C1 + (bb ? bb->c1 : 0.0);
171 }
172 if (obs.P2) {
173 satData->P2 = obs.P2 + (bb ? bb->p2 : 0.0);
174 }
175 else {
176 satData->P2 = obs.C2;
177 }
178 satData->L1 = obs.L1() * t_CST::c / f1;
179 satData->L2 = obs.L2() * t_CST::c / f2;
180 satData->P3 = c1 * satData->P1 + c2 * satData->P2;
181 satData->L3 = c1 * satData->L1 + c2 * satData->L2;
182 satData->lambda3 = c1 * t_CST::c / f1 + c2 * t_CST::c / f2;
183
184 _epoData.back()->satData[satData->prn] = satData;
185 }
186 else {
187 delete satData;
188 }
189 }
190
191 // Set Observations GLONASS
192 // ------------------------
193 else if (obs.satSys == 'R') {
194 if ( (obs.P1 || obs.C1) && (obs.P2 || obs.C2) && obs.L1() && obs.L2() ) {
195 double f1 = 1602000000.0 + 562500.0 * obs.slotNum;
196 double f2 = 1246000000.0 + 437500.0 * obs.slotNum;
197 double c1 = f1 * f1 / (f1 * f1 - f2 * f2);
198 double c2 = - f2 * f2 / (f1 * f1 - f2 * f2);
199 if (obs.P1) {
200 satData->P1 = obs.P1 + (bb ? bb->p1 : 0.0);
201 }
202 else {
203 satData->P1 = obs.C1 + (bb ? bb->c1 : 0.0);
204 }
205 if (obs.P2) {
206 satData->P2 = obs.P2 + (bb ? bb->p2 : 0.0);
207 }
208 else {
209 satData->P2 = obs.C2;
210 }
211 satData->L1 = obs.L1() * t_CST::c / f1;
212 satData->L2 = obs.L2() * t_CST::c / f2;
213 satData->P3 = c1 * satData->P1 + c2 * satData->P2;
214 satData->L3 = c1 * satData->L1 + c2 * satData->L2;
215 satData->lambda3 = c1 * t_CST::c / f1 + c2 * t_CST::c / f2;
216
217 _epoData.back()->satData[satData->prn] = satData;
218 }
219 else {
220 delete satData;
221 }
222 }
223
224 // Set Observations Galileo
225 // ------------------------
226 else if (obs.satSys == 'E') {
227 if ( obs.C1 && obs.C5 && obs.L1() && obs.L5) {
228 double f1 = t_CST::freq1;
229 double f5 = t_CST::freq5;
230 double c1 = f1 * f1 / (f1 * f1 - f5 * f5);
231 double c5 = - f5 * f5 / (f1 * f1 - f5 * f5);
232
233 satData->P1 = obs.C1;
234 satData->P5 = obs.C5;
235 satData->L1 = obs.L1() * t_CST::c / f1;
236 satData->L5 = obs.L5 * t_CST::c / f5;
237 satData->P3 = c1 * satData->P1 + c5 * satData->P5;
238 satData->L3 = c1 * satData->L1 + c5 * satData->L5;
239 satData->lambda3 = c1 * t_CST::c / f1 + c5 * t_CST::c / f5;
240 _epoData.back()->satData[satData->prn] = satData;
241 }
242 else {
243 delete satData;
244 }
245 }
246}
247
248//
249////////////////////////////////////////////////////////////////////////////
250void bncPPPclient::slotNewCorrections(QList<QString> corrList) {
251 QMutexLocker locker(&_mutex);
252
253 // Check the Mountpoint (source of corrections)
254 // --------------------------------------------
255 if (!_opt->pppCorrMount.isEmpty()) {
256 QMutableListIterator<QString> itm(corrList);
257 while (itm.hasNext()) {
258 QStringList hlp = itm.next().split(" ");
259 if (hlp.size() > 0) {
260 QString mountpoint = hlp[hlp.size()-1];
261 if (mountpoint != _opt->pppCorrMount) {
262 itm.remove();
263 }
264 }
265 }
266 }
267
268 if (corrList.size() == 0) {
269 return;
270 }
271
272 // Remove All Corrections
273 // ----------------------
274 // QMapIterator<QString, t_corr*> ic(_corr);
275 // while (ic.hasNext()) {
276 // ic.next();
277 // delete ic.value();
278 // }
279 // _corr.clear();
280
281 QListIterator<QString> it(corrList);
282 while (it.hasNext()) {
283 QString line = it.next();
284
285 QTextStream in(&line);
286 int messageType;
287 int updateInterval;
288 int GPSweek;
289 double GPSweeks;
290 QString prn;
291 in >> messageType >> updateInterval >> GPSweek >> GPSweeks >> prn;
292
293 if ( t_corr::relevantMessageType(messageType) ) {
294 t_corr* cc = 0;
295 if (_corr.contains(prn)) {
296 cc = _corr.value(prn);
297 }
298 else {
299 cc = new t_corr();
300 _corr[prn] = cc;
301 }
302
303 cc->readLine(line);
304 _corr_tt = cc->tt;
305 }
306 else if ( messageType == BTYPE_GPS ) {
307
308 t_bias* bb = 0;
309 if (_bias.contains(prn)) {
310 bb = _bias.value(prn);
311 }
312 else {
313 bb = new t_bias();
314 _bias[prn] = bb;
315 }
316
317 bb->tt.set(GPSweek, GPSweeks);
318
319 int numBiases;
320 in >> numBiases;
321 for (int ii = 0; ii < numBiases; ++ii) {
322 int bType;
323 double bValue;
324 in >> bType >> bValue;
325 if (bType == CODETYPEGPS_L1_Z) {
326 bb->p1 = bValue;
327 }
328 else if (bType == CODETYPEGPS_L1_CA) {
329 bb->c1 = bValue;
330 }
331 else if (bType == CODETYPEGPS_L2_Z) {
332 bb->p2 = bValue;
333 }
334 }
335 }
336 }
337
338 QMutableMapIterator<QString, t_corr*> im(_corr);
339 while (im.hasNext()) {
340 im.next();
341 t_corr* cc = im.value();
342 if (!cc->ready()) {
343 delete cc;
344 im.remove();
345 }
346 }
347}
348
349// Satellite Position
350////////////////////////////////////////////////////////////////////////////
351t_irc bncPPPclient::getSatPos(const bncTime& tt, const QString& prn,
352 ColumnVector& xc, ColumnVector& vv) {
353
354 const double MAXAGE = 120.0;
355
356 if (_eph.contains(prn)) {
357
358 if (_opt->pppMode) {
359 if (_corr.contains(prn)) {
360 t_corr* cc = _corr.value(prn);
361 if (tt - cc->tt < MAXAGE) {
362 t_eph* eLast = _eph.value(prn)->last;
363 t_eph* ePrev = _eph.value(prn)->prev;
364 if (eLast && eLast->IOD() == cc->iod) {
365 eLast->position(tt.gpsw(), tt.gpssec(), xc.data(), vv.data());
366 return applyCorr(tt, cc, xc, vv);
367 }
368 else if (ePrev && ePrev->IOD() == cc->iod) {
369 ePrev->position(tt.gpsw(), tt.gpssec(), xc.data(), vv.data());
370 return applyCorr(tt, cc, xc, vv);
371 }
372 }
373 }
374 }
375
376 else {
377 t_eph* ee = _eph.value(prn)->last;
378 ee->position(tt.gpsw(), tt.gpssec(), xc.data(), vv.data());
379 return success;
380 }
381 }
382
383 return failure;
384}
385
386//
387////////////////////////////////////////////////////////////////////////////
388t_irc bncPPPclient::applyCorr(const bncTime& tt, const t_corr* cc,
389 ColumnVector& xc, ColumnVector& vv) {
390
391 double dt = tt - cc->tt;
392 ColumnVector raoHlp = cc->rao + cc->dotRao * dt + cc->dotDotRao * dt * dt;
393
394 if (raoHlp.norm_Frobenius() > 20.0) {
395 return failure;
396 }
397
398 ColumnVector dx(3);
399 RSW_to_XYZ(xc.Rows(1,3), vv, raoHlp, dx);
400 xc[0] -= dx[0];
401 xc[1] -= dx[1];
402 xc[2] -= dx[2];
403 xc[3] += cc->dClk + cc->dotDClk * dt + cc->dotDotDClk * dt * dt
404 + cc->hrClk;
405
406 return success;
407}
408
409// Correct Time of Transmission
410////////////////////////////////////////////////////////////////////////////
411t_irc bncPPPclient::cmpToT(t_satData* satData) {
412
413 double prange = satData->P3;
414 if (prange == 0.0) {
415 return failure;
416 }
417
418 double clkSat = 0.0;
419 for (int ii = 1; ii <= 10; ii++) {
420
421 bncTime ToT = satData->tt - prange / t_CST::c - clkSat;
422
423 ColumnVector xc(4);
424 ColumnVector vv(3);
425 if (getSatPos(ToT, satData->prn, xc, vv) != success) {
426 return failure;
427 }
428
429 double clkSatOld = clkSat;
430 clkSat = xc(4);
431
432 if ( fabs(clkSat-clkSatOld) * t_CST::c < 1.e-4 ) {
433 satData->xx = xc.Rows(1,3);
434 satData->vv = vv;
435 satData->clk = clkSat * t_CST::c;
436 return success;
437 }
438 }
439
440 return failure;
441}
442
443//
444////////////////////////////////////////////////////////////////////////////
445void bncPPPclient::processFrontEpoch() {
446
447 // Data Pre-Processing
448 // -------------------
449 QMutableMapIterator<QString, t_satData*> it(_epoData.front()->satData);
450 while (it.hasNext()) {
451 it.next();
452 QString prn = it.key();
453 t_satData* satData = it.value();
454
455 if (cmpToT(satData) != success) {
456 delete satData;
457 it.remove();
458 continue;
459 }
460 }
461
462 // Filter Solution
463 // ---------------
464 if (_model->update(_epoData.front()) == success) {
465 emit newPosition(_model->time(), _model->x(), _model->y(), _model->z());
466 }
467}
468
469//
470////////////////////////////////////////////////////////////////////////////
471void bncPPPclient::processEpochs() {
472
473 // Make sure the buffer does not grow beyond any limit
474 // ---------------------------------------------------
475 const unsigned MAX_EPODATA_SIZE = 120;
476 if (_epoData.size() > MAX_EPODATA_SIZE) {
477 delete _epoData.front();
478 _epoData.pop();
479 }
480
481 // Loop over all unprocessed epochs
482 // --------------------------------
483 while (!_epoData.empty()) {
484
485 t_epoData* frontEpoData = _epoData.front();
486
487 // No corrections yet, skip the epoch
488 // ----------------------------------
489 if (_opt->corrSync != 0.0 && !_corr_tt.valid()) {
490 return;
491 }
492
493 // Process the front epoch
494 // -----------------------
495 if (_opt->corrSync == 0 || frontEpoData->tt - _corr_tt < _opt->corrSync) {
496 processFrontEpoch();
497 delete _epoData.front();
498 _epoData.pop();
499 }
500 else {
501 return;
502 }
503 }
504}
Note: See TracBrowser for help on using the repository browser.