source: ntrip/trunk/BNC/src/PPP_free/bncpppclient.cpp@ 6072

Last change on this file since 6072 was 6072, checked in by mervart, 10 years ago
File size: 11.8 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 "bnccore.h"
47#include "bncutils.h"
48#include "bncconst.h"
49#include "bncmodel.h"
50#include "pppOptions.h"
51
52using namespace BNC_PPP;
53using namespace std;
54
55// Constructor
56////////////////////////////////////////////////////////////////////////////
57bncPPPclient::bncPPPclient(QByteArray staID, const t_pppOptions* opt) : bncEphUser(false) {
58
59 _opt = opt;
60 _staID = staID;
61 _model = new bncModel(this);
62}
63
64// Destructor
65////////////////////////////////////////////////////////////////////////////
66bncPPPclient::~bncPPPclient() {
67 while (!_epoData.empty()) {
68 delete _epoData.front();
69 _epoData.pop();
70 }
71 QMapIterator<QString, t_corr*> ic(_corr);
72 while (ic.hasNext()) {
73 ic.next();
74 delete ic.value();
75 }
76 QMapIterator<QString, t_bias*> ib(_bias);
77 while (ib.hasNext()) {
78 ib.next();
79 delete ib.value();
80 }
81 delete _model;
82}
83
84//
85////////////////////////////////////////////////////////////////////////////
86void bncPPPclient::putNewObs(t_satData* satData, t_output* output) {
87 QMutexLocker locker(&_mutex);
88
89 // Add new epoch, process the older ones
90 // -------------------------------------
91 if (_epoData.size() == 0) {
92 _epoData.push(new t_epoData());
93 _epoData.back()->tt = satData->tt;
94 }
95 else if (satData->tt != _epoData.back()->tt) {
96 processEpochs(output);
97 _epoData.push(new t_epoData());
98 _epoData.back()->tt = satData->tt;
99 }
100
101 // Set Observations GPS and Glonass
102 // --------------------------------
103 if (satData->system() == 'G' || satData->system() == 'R') {
104 if (satData->P1 != 0.0 && satData->P2 != 0.0 &&
105 satData->L1 != 0.0 && satData->L2 != 0.0 ) {
106
107 int channel = 0;
108 if (satData->system() == 'R') {
109 cerr << "not yet implemented" << endl;
110 exit(0);
111 }
112
113 t_frequency::type fType1 = t_lc::toFreq(satData->system(), t_lc::l1);
114 t_frequency::type fType2 = t_lc::toFreq(satData->system(), t_lc::l2);
115 double f1 = t_CST::freq(fType1, channel);
116 double f2 = t_CST::freq(fType2, channel);
117 double a1 = f1 * f1 / (f1 * f1 - f2 * f2);
118 double a2 = - f2 * f2 / (f1 * f1 - f2 * f2);
119 satData->P3 = a1 * satData->P1 + a2 * satData->P2;
120 satData->L3 = a1 * satData->L1 + a2 * satData->L2;
121 satData->lambda3 = a1 * t_CST::c / f1 + a2 * t_CST::c / f2;
122 _epoData.back()->satData[satData->prn] = satData;
123 }
124 else {
125 delete satData;
126 }
127 }
128
129 // Set Observations Galileo
130 // ------------------------
131 else if (satData->system() == 'E') {
132 if (satData->P1 != 0.0 && satData->P5 != 0.0 &&
133 satData->L1 != 0.0 && satData->L5 != 0.0 ) {
134 double f1 = t_CST::freq(t_frequency::E1, 0);
135 double f5 = t_CST::freq(t_frequency::E5, 0);
136 double a1 = f1 * f1 / (f1 * f1 - f5 * f5);
137 double a5 = - f5 * f5 / (f1 * f1 - f5 * f5);
138 satData->P3 = a1 * satData->P1 + a5 * satData->P5;
139 satData->L3 = a1 * satData->L1 + a5 * satData->L5;
140 satData->lambda3 = a1 * t_CST::c / f1 + a5 * t_CST::c / f5;
141 _epoData.back()->satData[satData->prn] = satData;
142 }
143 else {
144 delete satData;
145 }
146 }
147}
148
149//
150////////////////////////////////////////////////////////////////////////////
151void bncPPPclient::putNewCorrections(QList<QString> corrList) {
152 QMutexLocker locker(&_mutex);
153
154 // Check the Mountpoint (source of corrections)
155 // --------------------------------------------
156 if (!_opt->_corrMount.empty()) {
157 QMutableListIterator<QString> itm(corrList);
158 while (itm.hasNext()) {
159 QStringList hlp = itm.next().split(" ");
160 if (hlp.size() > 0) {
161 QString mountpoint = hlp[hlp.size()-1];
162 if (mountpoint != QString(_opt->_corrMount.c_str())) {
163 itm.remove();
164 }
165 }
166 }
167 }
168
169 if (corrList.size() == 0) {
170 return;
171 }
172
173 QListIterator<QString> it(corrList);
174 while (it.hasNext()) {
175 QString line = it.next();
176
177 QTextStream in(&line);
178 int messageType;
179 int updateInterval;
180 int GPSweek;
181 double GPSweeks;
182 QString prn;
183 in >> messageType >> updateInterval >> GPSweek >> GPSweeks >> prn;
184
185 if ( t_corr::relevantMessageType(messageType) ) {
186 t_corr* cc = 0;
187 if (_corr.contains(prn)) {
188 cc = _corr.value(prn);
189 }
190 else {
191 cc = new t_corr();
192 _corr[prn] = cc;
193 }
194 cc->readLine(line);
195 _corr_tt = cc->tClk;
196 }
197 else if ( messageType == BTYPE_GPS || messageType == BTYPE_GLONASS ) {
198 t_bias* bb = 0;
199 if (_bias.contains(prn)) {
200 bb = _bias.value(prn);
201 }
202 else {
203 bb = new t_bias();
204 _bias[prn] = bb;
205 }
206 bb->readLine(line);
207 }
208 }
209}
210
211// Satellite Position
212////////////////////////////////////////////////////////////////////////////
213t_irc bncPPPclient::getSatPos(const bncTime& tt, const QString& prn,
214 ColumnVector& xc, ColumnVector& vv) {
215
216 const double MAXAGE = 120.0;
217
218 if (_eph.contains(prn)) {
219
220 if (_opt->useOrbClkCorr() && prn[0] != 'E') {
221 if (_corr.contains(prn)) {
222 t_corr* cc = _corr.value(prn);
223 if (cc->ready() && tt - cc->tClk < MAXAGE) {
224 t_eph* eLast = _eph.value(prn)->last;
225 t_eph* ePrev = _eph.value(prn)->prev;
226 if (eLast && eLast->IOD() == cc->iod) {
227 eLast->position(tt.gpsw(), tt.gpssec(), xc.data(), vv.data());
228 return applyCorr(tt, cc, xc, vv);
229 }
230 else if (ePrev && ePrev->IOD() == cc->iod) {
231 ePrev->position(tt.gpsw(), tt.gpssec(), xc.data(), vv.data());
232 return applyCorr(tt, cc, xc, vv);
233 }
234 }
235 }
236 }
237
238 else {
239 t_eph* ee = _eph.value(prn)->last;
240 ee->position(tt.gpsw(), tt.gpssec(), xc.data(), vv.data());
241 return success;
242 }
243 }
244
245 return failure;
246}
247
248//
249////////////////////////////////////////////////////////////////////////////
250t_irc bncPPPclient::applyCorr(const bncTime& tt, const t_corr* cc,
251 ColumnVector& xc, ColumnVector& vv) {
252
253 double dtRao = tt - cc->tRao;
254
255 // Position
256 // --------
257 ColumnVector raoHlp = cc->rao + cc->dotRao * dtRao;
258
259 if (raoHlp.norm_Frobenius() > 20.0) {
260 return failure;
261 }
262
263 ColumnVector dx(3);
264 RSW_to_XYZ(xc.Rows(1,3), vv, raoHlp, dx);
265 xc[0] -= dx[0];
266 xc[1] -= dx[1];
267 xc[2] -= dx[2];
268
269 // Velocity
270 // --------
271 ColumnVector dotRaoHlp = cc->dotRao;
272
273 ColumnVector dv(3);
274 RSW_to_XYZ(xc.Rows(1,3), vv, dotRaoHlp, dv);
275 vv[0] -= dv[0];
276 vv[1] -= dv[1];
277 vv[2] -= dv[2];
278
279 // Clocks
280 // ------
281 double dtClk = tt - cc->tClk;
282
283 xc[3] += cc->dClk + cc->dotDClk * dtClk + cc->dotDotDClk * dtClk * dtClk
284 + cc->hrClk;
285
286 return success;
287}
288
289// Correct Time of Transmission
290////////////////////////////////////////////////////////////////////////////
291t_irc bncPPPclient::cmpToT(t_satData* satData) {
292
293 double prange = satData->P3;
294 if (prange == 0.0) {
295 return failure;
296 }
297
298 double clkSat = 0.0;
299 for (int ii = 1; ii <= 10; ii++) {
300
301 bncTime ToT = satData->tt - prange / t_CST::c - clkSat;
302
303 ColumnVector xc(4);
304 ColumnVector vv(3);
305 if (getSatPos(ToT, satData->prn, xc, vv) != success) {
306 return failure;
307 }
308
309 double clkSatOld = clkSat;
310 clkSat = xc(4);
311
312 if ( fabs(clkSat-clkSatOld) * t_CST::c < 1.e-4 ) {
313 satData->xx = xc.Rows(1,3);
314 satData->vv = vv;
315 satData->clk = clkSat * t_CST::c;
316 return success;
317 }
318 }
319
320 return failure;
321}
322
323//
324////////////////////////////////////////////////////////////////////////////
325void bncPPPclient::processFrontEpoch(t_output* output) {
326
327#ifdef BNC_DEBUG
328 QString msg = "List of Corrections\n";
329 QMapIterator<QString, t_corr*> itC(_corr);
330 while (itC.hasNext()) {
331 itC.next();
332 QString src = itC.key();
333 const t_corr* corr = itC.value();
334 msg += QString("%1 %2 %3 %4\n")
335 .arg(corr->prn)
336 .arg(corr->iod)
337 .arg(QString(corr->tClk.datestr().c_str()) + "_" + QString(corr->tClk.timestr().c_str()))
338 .arg(QString(corr->tRao.datestr().c_str()) + "_" + QString(corr->tRao.timestr().c_str()));
339 }
340
341 msg += "List of Ephemeris\n";
342 QMapIterator<QString, t_ephPair*> itE(_eph);
343 while (itE.hasNext()) {
344 itE.next();
345 QString prn = itE.key();
346 const t_ephPair* ephPair = itE.value();
347 if (ephPair->prev) {
348 msg += QString("%1 %2 %3 %4 %5\n")
349 .arg(prn)
350 .arg(ephPair->last->IOD())
351 .arg(QString(ephPair->last->TOC().datestr().c_str()) + "_" +
352 QString(ephPair->last->TOC().timestr().c_str()))
353 .arg(ephPair->prev->IOD())
354 .arg(QString(ephPair->prev->TOC().datestr().c_str()) + "_" +
355 QString(ephPair->prev->TOC().timestr().c_str()));
356 }
357 else {
358 msg += QString("%1 %2 %3\n")
359 .arg(prn)
360 .arg(ephPair->last->IOD())
361 .arg(QString(ephPair->last->TOC().datestr().c_str()) + "_" +
362 QString(ephPair->last->TOC().timestr().c_str()));
363 }
364 }
365
366 LOG << msg.toAscii() << endl;
367#endif // BNC_DEBUG
368
369 // Data Pre-Processing
370 // -------------------
371 QMutableMapIterator<QString, t_satData*> it(_epoData.front()->satData);
372 while (it.hasNext()) {
373 it.next();
374 QString prn = it.key();
375 t_satData* satData = it.value();
376
377 if (cmpToT(satData) != success) {
378 delete satData;
379 it.remove();
380 continue;
381 }
382 }
383
384 // Filter Solution
385 // ---------------
386 if (_model->update(_epoData.front()) == success) {
387 /// emit newPosition(_model->time(), _model->x(), _model->y(), _model->z());
388 }
389}
390
391//
392////////////////////////////////////////////////////////////////////////////
393void bncPPPclient::processEpochs(t_output* output) {
394
395 // Make sure the buffer does not grow beyond any limit
396 // ---------------------------------------------------
397 const unsigned MAX_EPODATA_SIZE = 120;
398 if (_epoData.size() > MAX_EPODATA_SIZE) {
399 delete _epoData.front();
400 _epoData.pop();
401 }
402
403 // Loop over all unprocessed epochs
404 // --------------------------------
405 while (!_epoData.empty()) {
406
407 t_epoData* frontEpoData = _epoData.front();
408
409 // No corrections yet, skip the epoch
410 // ----------------------------------
411 if (_opt->useOrbClkCorr() && !_corr_tt.valid()) {
412 return;
413 }
414
415 // Process the front epoch
416 // -----------------------
417 if (_opt->_corrWaitTime == 0.0 || frontEpoData->tt - _corr_tt >= _opt->_corrWaitTime) {
418 processFrontEpoch(output);
419 delete _epoData.front();
420 _epoData.pop();
421 }
422 else {
423 return;
424 }
425 }
426}
Note: See TracBrowser for help on using the repository browser.