source: ntrip/trunk/BNC/bncmodel.cpp@ 2108

Last change on this file since 2108 was 2108, checked in by mervart, 14 years ago

* empty log message *

File size: 14.6 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: bncParam, bncModel
30 *
31 * Purpose: Model for PPP
32 *
33 * Author: L. Mervart
34 *
35 * Created: 01-Dec-2009
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <iomanip>
42#include <cmath>
43#include <newmatio.h>
44
45#include "bncmodel.h"
46#include "bncpppclient.h"
47#include "bancroft.h"
48#include "bncutils.h"
49#include "bncsettings.h"
50
51using namespace std;
52
53const unsigned MINOBS = 4;
54const double MINELE = 10.0 * M_PI / 180.0;
55const double sig_crd_0 = 100.0;
56const double sig_crd_p = 100.0;
57const double sig_clk_0 = 1000.0;
58const double sig_trp_0 = 0.01;
59const double sig_trp_p = 1e-6;
60const double sig_amb_0 = 100.0;
61const double sig_P3 = 1.0;
62const double sig_L3 = 0.01;
63
64// Constructor
65////////////////////////////////////////////////////////////////////////////
66bncParam::bncParam(bncParam::parType typeIn, int indexIn,
67 const QString& prnIn) {
68 type = typeIn;
69 index = indexIn;
70 prn = prnIn;
71 index_old = 0;
72 x0 = 0.0;
73 xx = 0.0;
74}
75
76// Destructor
77////////////////////////////////////////////////////////////////////////////
78bncParam::~bncParam() {
79}
80
81// Partial
82////////////////////////////////////////////////////////////////////////////
83double bncParam::partial(t_satData* satData, const QString& prnIn) {
84 if (type == CRD_X) {
85 return (x0 - satData->xx(1)) / satData->rho;
86 }
87 else if (type == CRD_Y) {
88 return (x0 - satData->xx(2)) / satData->rho;
89 }
90 else if (type == CRD_Z) {
91 return (x0 - satData->xx(3)) / satData->rho;
92 }
93 else if (type == RECCLK) {
94 return 1.0;
95 }
96 else if (type == TROPO) {
97 return 1.0 / sin(satData->eleSat);
98 }
99 else if (type == AMB_L3) {
100 if (prnIn == prn) {
101 return 1.0;
102 }
103 else {
104 return 0.0;
105 }
106 }
107 return 0.0;
108}
109
110// Constructor
111////////////////////////////////////////////////////////////////////////////
112bncModel::bncModel() {
113
114 bncSettings settings;
115
116 _static = false;
117 if ( Qt::CheckState(settings.value("pppStatic").toInt()) == Qt::Checked) {
118 _static = true;
119 }
120
121 _usePhase = false;
122 if ( Qt::CheckState(settings.value("pppUsePhase").toInt()) == Qt::Checked) {
123 _usePhase = true;
124 }
125
126 _estTropo = false;
127 if ( Qt::CheckState(settings.value("pppEstTropo").toInt()) == Qt::Checked) {
128 _estTropo = true;
129 }
130
131 _xcBanc.ReSize(4); _xcBanc = 0.0;
132 _ellBanc.ReSize(3); _ellBanc = 0.0;
133
134 _params.push_back(new bncParam(bncParam::CRD_X, 1, ""));
135 _params.push_back(new bncParam(bncParam::CRD_Y, 2, ""));
136 _params.push_back(new bncParam(bncParam::CRD_Z, 3, ""));
137 _params.push_back(new bncParam(bncParam::RECCLK, 4, ""));
138 if (_estTropo) {
139 _params.push_back(new bncParam(bncParam::TROPO, 5, ""));
140 }
141
142 unsigned nPar = _params.size();
143
144 _QQ.ReSize(nPar);
145 _QQ = 0.0;
146
147 _QQ(1,1) = sig_crd_0 * sig_crd_0;
148 _QQ(2,2) = sig_crd_0 * sig_crd_0;
149 _QQ(3,3) = sig_crd_0 * sig_crd_0;
150 _QQ(4,4) = sig_clk_0 * sig_clk_0;
151 if (_estTropo) {
152 _QQ(5,5) = sig_trp_0 * sig_trp_0;
153 }
154}
155
156// Destructor
157////////////////////////////////////////////////////////////////////////////
158bncModel::~bncModel() {
159}
160
161// Bancroft Solution
162////////////////////////////////////////////////////////////////////////////
163t_irc bncModel::cmpBancroft(t_epoData* epoData) {
164
165 if (epoData->size() < MINOBS) {
166 return failure;
167 }
168
169 Matrix BB(epoData->size(), 4);
170
171 QMapIterator<QString, t_satData*> it(epoData->satData);
172 int iObs = 0;
173 while (it.hasNext()) {
174 ++iObs;
175 it.next();
176 QString prn = it.key();
177 t_satData* satData = it.value();
178 BB(iObs, 1) = satData->xx(1);
179 BB(iObs, 2) = satData->xx(2);
180 BB(iObs, 3) = satData->xx(3);
181 BB(iObs, 4) = satData->P3 + satData->clk;
182 }
183
184 bancroft(BB, _xcBanc);
185
186 // Ellipsoidal Coordinates
187 // ------------------------
188 xyz2ell(_xcBanc.data(), _ellBanc.data());
189
190 // Compute Satellite Elevations
191 // ----------------------------
192 QMutableMapIterator<QString, t_satData*> it2(epoData->satData);
193 while (it2.hasNext()) {
194 it2.next();
195 QString prn = it2.key();
196 t_satData* satData = it2.value();
197
198 ColumnVector dx = satData->xx - _xcBanc.Rows(1,3);
199 double rho = dx.norm_Frobenius();
200
201 double neu[3];
202 xyz2neu(_ellBanc.data(), dx.data(), neu);
203
204 satData->eleSat = acos( sqrt(neu[0]*neu[0] + neu[1]*neu[1]) / rho );
205 if (neu[2] < 0) {
206 satData->eleSat *= -1.0;
207 }
208 satData->azSat = atan2(neu[1], neu[0]);
209
210 if (satData->eleSat < MINELE) {
211 delete satData;
212 it2.remove();
213 }
214 }
215
216 return success;
217}
218
219// Computed Value
220////////////////////////////////////////////////////////////////////////////
221double bncModel::cmpValue(t_satData* satData) {
222
223 ColumnVector xRec(3);
224 xRec(1) = x();
225 xRec(2) = y();
226 xRec(3) = z();
227
228 double rho0 = (satData->xx - xRec).norm_Frobenius();
229 double dPhi = t_CST::omega * rho0 / t_CST::c;
230
231 xRec(1) = x() * cos(dPhi) - y() * sin(dPhi);
232 xRec(2) = y() * cos(dPhi) + x() * sin(dPhi);
233 xRec(3) = z();
234
235 satData->rho = (satData->xx - xRec).norm_Frobenius();
236
237 double tropDelay = delay_saast(satData->eleSat) +
238 trp() / sin(satData->eleSat);
239
240 return satData->rho + clk() - satData->clk + tropDelay;
241}
242
243// Tropospheric Model (Saastamoinen)
244////////////////////////////////////////////////////////////////////////////
245double bncModel::delay_saast(double Ele) {
246
247 double height = _ellBanc(3);
248
249 double pp = 1013.25 * pow(1.0 - 2.26e-5 * height, 5.225);
250 double TT = 18.0 - height * 0.0065 + 273.15;
251 double hh = 50.0 * exp(-6.396e-4 * height);
252 double ee = hh / 100.0 * exp(-37.2465 + 0.213166*TT - 0.000256908*TT*TT);
253
254 double h_km = height / 1000.0;
255
256 if (h_km < 0.0) h_km = 0.0;
257 if (h_km > 5.0) h_km = 5.0;
258 int ii = int(h_km + 1);
259 double href = ii - 1;
260
261 double bCor[6];
262 bCor[0] = 1.156;
263 bCor[1] = 1.006;
264 bCor[2] = 0.874;
265 bCor[3] = 0.757;
266 bCor[4] = 0.654;
267 bCor[5] = 0.563;
268
269 double BB = bCor[ii-1] + (bCor[ii]-bCor[ii-1]) * (h_km - href);
270
271 double zen = M_PI/2.0 - Ele;
272
273 return (0.002277/cos(zen)) * (pp + ((1255.0/TT)+0.05)*ee - BB*(tan(zen)*tan(zen)));
274}
275
276// Prediction Step of the Filter
277////////////////////////////////////////////////////////////////////////////
278void bncModel::predict(t_epoData* epoData) {
279
280 if (_usePhase) {
281
282 // Make a copy of QQ and xx, set parameter indices
283 // -----------------------------------------------
284 SymmetricMatrix QQ_old = _QQ;
285
286 for (int iPar = 1; iPar <= _params.size(); iPar++) {
287 _params[iPar-1]->index_old = _params[iPar-1]->index;
288 _params[iPar-1]->index = 0;
289 }
290
291 // Remove Ambiguity Parameters without observations
292 // ------------------------------------------------
293 int iPar = 0;
294 QMutableVectorIterator<bncParam*> it(_params);
295 while (it.hasNext()) {
296 bncParam* par = it.next();
297 bool removed = false;
298 if (par->type == bncParam::AMB_L3) {
299 if (epoData->satData.find(par->prn) == epoData->satData.end()) {
300 removed = true;
301 delete par;
302 it.remove();
303 }
304 }
305 if (! removed) {
306 ++iPar;
307 par->index = iPar;
308 }
309 }
310
311 // Add new ambiguity parameters
312 // ----------------------------
313 QMapIterator<QString, t_satData*> itObs(epoData->satData);
314 while (itObs.hasNext()) {
315 itObs.next();
316 QString prn = itObs.key();
317 bool found = false;
318 for (int iPar = 1; iPar <= _params.size(); iPar++) {
319 if (_params[iPar-1]->type == bncParam::AMB_L3 &&
320 _params[iPar-1]->prn == prn) {
321 found = true;
322 break;
323 }
324 }
325 if (!found) {
326 bncParam* par = new bncParam(bncParam::AMB_L3, _params.size()+1, prn);
327 _params.push_back(par);
328 }
329 }
330
331 int nPar = _params.size();
332 _QQ.ReSize(nPar); _QQ = 0.0;
333 for (int i1 = 1; i1 <= nPar; i1++) {
334 bncParam* p1 = _params[i1-1];
335 if (p1->index_old != 0) {
336 _QQ(p1->index, p1->index) = QQ_old(p1->index_old, p1->index_old);
337 for (int i2 = 1; i2 <= nPar; i2++) {
338 bncParam* p2 = _params[i2-1];
339 if (p2->index_old != 0) {
340 _QQ(p1->index, p2->index) = QQ_old(p1->index_old, p2->index_old);
341 }
342 }
343 }
344 }
345
346 for (int ii = 1; ii <= nPar; ii++) {
347 bncParam* par = _params[ii-1];
348 if (par->index_old == 0) {
349 _QQ(par->index, par->index) = sig_amb_0 * sig_amb_0;
350 }
351 par->index_old = par->index;
352 }
353 }
354
355 // Coordinates
356 // -----------
357 if (_static) {
358 if (x() == 0.0 && y() == 0.0 && z() == 0.0) {
359 _params[0]->x0 = _xcBanc(1);
360 _params[1]->x0 = _xcBanc(2);
361 _params[2]->x0 = _xcBanc(3);
362 }
363 else {
364 _params[0]->x0 += _params[0]->xx;
365 _params[1]->x0 += _params[1]->xx;
366 _params[2]->x0 += _params[2]->xx;
367 }
368 }
369 else {
370 _params[0]->x0 = _xcBanc(1);
371 _params[1]->x0 = _xcBanc(2);
372 _params[2]->x0 = _xcBanc(3);
373
374 _QQ(1,1) += sig_crd_p * sig_crd_p;
375 _QQ(2,2) += sig_crd_p * sig_crd_p;
376 _QQ(3,3) += sig_crd_p * sig_crd_p;
377 }
378
379 // Receiver Clocks
380 // ---------------
381 _params[3]->x0 = _xcBanc(4);
382 for (int iPar = 1; iPar <= _params.size(); iPar++) {
383 _QQ(iPar, 4) = 0.0;
384 }
385 _QQ(4,4) = sig_clk_0 * sig_clk_0;
386
387 // Tropospheric Delay
388 // ------------------
389 if (_estTropo) {
390 _params[4]->x0 += _params[4]->xx;
391 _QQ(5,5) += sig_trp_p * sig_trp_p;
392 }
393
394 // Ambiguities
395 // -----------
396 for (int iPar = 1; iPar <= _params.size(); iPar++) {
397 if (_params[iPar-1]->type == bncParam::AMB_L3) {
398 _params[iPar-1]->x0 += _params[iPar-1]->xx;
399 }
400 }
401
402 // Nullify the Solution Vector
403 // ---------------------------
404 for (int iPar = 1; iPar <= _params.size(); iPar++) {
405 _params[iPar-1]->xx = 0.0;
406 }
407}
408
409// Update Step of the Filter (currently just a single-epoch solution)
410////////////////////////////////////////////////////////////////////////////
411t_irc bncModel::update(t_epoData* epoData) {
412
413 const static double MAXRES_CODE = 10.0;
414 const static double MAXRES_PHASE = 0.10;
415
416 ColumnVector xx;
417
418 bool outlier = false;
419
420 do {
421
422 outlier = false;
423
424 if (epoData->size() < MINOBS) {
425 return failure;
426 }
427
428 // Bancroft Solution
429 // -----------------
430 if (cmpBancroft(epoData) != success) {
431 return failure;
432 }
433
434 // Status Prediction
435 // -----------------
436 predict(epoData);
437
438 SymmetricMatrix QQsav = _QQ;
439
440 unsigned nPar = _params.size();
441 unsigned nObs = _usePhase ? 2 * epoData->size() : epoData->size();
442
443 // Set Solution Vector
444 // -------------------
445 xx.ReSize(nPar);
446 QVectorIterator<bncParam*> itPar(_params);
447 while (itPar.hasNext()) {
448 bncParam* par = itPar.next();
449 xx(par->index) = par->xx;
450 }
451
452 // Create First-Design Matrix
453 // --------------------------
454 Matrix AA(nObs, nPar); // first design matrix
455 ColumnVector ll(nObs); // tems observed-computed
456 SymmetricMatrix PP(nObs); PP = 0.0;
457
458 unsigned iObs = 0;
459 QMapIterator<QString, t_satData*> itObs(epoData->satData);
460 while (itObs.hasNext()) {
461 ++iObs;
462 itObs.next();
463 QString prn = itObs.key();
464 t_satData* satData = itObs.value();
465
466 double rhoCmp = cmpValue(satData);
467
468 ll(iObs) = satData->P3 - rhoCmp;
469 PP(iObs,iObs) = 1.0 / (sig_P3 * sig_P3);
470 for (int iPar = 1; iPar <= _params.size(); iPar++) {
471 AA(iObs, iPar) = _params[iPar-1]->partial(satData, "");
472 }
473
474 if (_usePhase) {
475 ++iObs;
476 ll(iObs) = satData->L3 - rhoCmp;
477 PP(iObs,iObs) = 1.0 / (sig_L3 * sig_L3);
478 for (int iPar = 1; iPar <= _params.size(); iPar++) {
479 if (_params[iPar-1]->type == bncParam::AMB_L3 &&
480 _params[iPar-1]->prn == prn) {
481 ll(iObs) -= _params[iPar-1]->x0;
482 }
483 AA(iObs, iPar) = _params[iPar-1]->partial(satData, prn);
484 }
485 }
486 }
487
488 // Compute Kalman Update
489 // ---------------------
490 if (false) {
491 SymmetricMatrix HH; HH << PP + AA * _QQ * AA.t();
492 SymmetricMatrix Hi = HH.i();
493 Matrix KK = _QQ * AA.t() * Hi;
494 ColumnVector v1 = ll - AA * xx;
495 xx = xx + KK * v1;
496 IdentityMatrix Id(nPar);
497 _QQ << (Id - KK * AA) * _QQ;
498 }
499 else {
500 Matrix ATP = AA.t() * PP;
501 SymmetricMatrix NN = _QQ.i();
502 ColumnVector bb = NN * xx + ATP * ll;
503 NN << NN + ATP * AA;
504 _QQ = NN.i();
505 xx = _QQ * bb;
506 }
507
508 // Outlier Detection
509 // -----------------
510 ColumnVector vv = ll - AA * xx;
511
512 iObs = 0;
513 QMutableMapIterator<QString, t_satData*> it2Obs(epoData->satData);
514 while (it2Obs.hasNext()) {
515 ++iObs;
516 it2Obs.next();
517 QString prn = it2Obs.key();
518 t_satData* satData = it2Obs.value();
519 if (fabs(vv(iObs)) > MAXRES_CODE) {
520 delete satData;
521 it2Obs.remove();
522 _QQ = QQsav;
523 outlier = true;
524 cout << "Code " << prn.toAscii().data() << " " << vv(iObs) << endl;
525 break;
526 }
527 if (_usePhase) {
528 ++iObs;
529 if (fabs(vv(iObs)) > MAXRES_PHASE) {
530 delete satData;
531 it2Obs.remove();
532 _QQ = QQsav;
533 outlier = true;
534 cout << "Phase " << prn.toAscii().data() << " " << vv(iObs) << endl;
535 break;
536 }
537 }
538 }
539
540 } while (outlier);
541
542 // Set Solution Vector back
543 // ------------------------
544 QVectorIterator<bncParam*> itPar(_params);
545 while (itPar.hasNext()) {
546 bncParam* par = itPar.next();
547 par->xx = xx(par->index);
548 }
549
550 return success;
551}
Note: See TracBrowser for help on using the repository browser.