source: ntrip/trunk/BNC/src/PPP/pppFilter.cpp

Last change on this file was 10411, checked in by stuerze, 5 weeks ago

minor changes

  • Property svn:keywords set to Author Date Id Rev URL;svn:eol-style=native
  • Property svn:mime-type set to text/plain
File size: 16.5 KB
RevLine 
[7237]1/* -------------------------------------------------------------------------
2 * BKG NTRIP Client
3 * -------------------------------------------------------------------------
4 *
5 * Class: t_pppFilter
6 *
7 * Purpose: Filter Adjustment
8 *
9 * Author: L. Mervart
10 *
11 * Created: 29-Jul-2014
12 *
[7267]13 * Changes:
[7237]14 *
15 * -----------------------------------------------------------------------*/
16
17#include <iostream>
18#include <iomanip>
19#include <cmath>
20#include <newmat.h>
21#include <newmatio.h>
22#include <newmatap.h>
23
24#include "pppFilter.h"
25#include "bncutils.h"
26#include "pppParlist.h"
27#include "pppObsPool.h"
28#include "pppStation.h"
[10034]29#include "pppClient.h"
[7237]30
31using namespace BNC_PPP;
32using namespace std;
33
34// Constructor
35////////////////////////////////////////////////////////////////////////////
[10034]36t_pppFilter::t_pppFilter() {
37 _parlist = 0;
[7237]38}
39
40// Destructor
41////////////////////////////////////////////////////////////////////////////
42t_pppFilter::~t_pppFilter() {
[10034]43 delete _parlist;
[7237]44}
45
46// Process Single Epoch
47////////////////////////////////////////////////////////////////////////////
[10034]48t_irc t_pppFilter::processEpoch(t_pppObsPool* obsPool) {
49
[9642]50 _numSat = 0;
[7302]51 const double maxSolGap = 60.0;
[10028]52 bool setNeuNoiseToZero = false;
[7237]53
[10034]54 if (!_parlist) {
55 _parlist = new t_pppParlist();
[10028]56 }
57
[7237]58 // Vector of all Observations
59 // --------------------------
[10034]60 t_pppObsPool::t_epoch *epoch = obsPool->lastEpoch();
[7237]61 if (!epoch) {
62 return failure;
63 }
[9642]64 vector<t_pppSatObs*> &allObs = epoch->obsVector();
[7237]65
66 // Time of the Epoch
67 // -----------------
68 _epoTime = epoch->epoTime();
69
[10015]70 if (!_firstEpoTime.valid() ||
71 !_lastEpoTimeOK.valid()||
72 (maxSolGap > 0.0 && _epoTime - _lastEpoTimeOK > maxSolGap)) {
[7237]73 _firstEpoTime = _epoTime;
74 }
75
[7267]76 string epoTimeStr = string(_epoTime);
77
[7237]78 // Set Parameters
[10034]79 // --------------
80 if (_parlist->set(_epoTime, allObs) != success) {
[9419]81 return failure;
82 }
[10028]83
[7237]84 // Status Vector, Variance-Covariance Matrix
85 // -----------------------------------------
[10256]86 ColumnVector xFltOld = _xFlt;
87 SymmetricMatrix QFltOld = _QFlt;
88 setStateVectorAndVarCovMatrix(xFltOld, QFltOld, setNeuNoiseToZero);
[8956]89
[7237]90 // Process Satellite Systems separately
91 // ------------------------------------
[10384]92 for (unsigned iSys = 0; iSys < OPT->systems().size(); iSys++) {
93 char sys = OPT->systems()[iSys];
94 int num = 0;
[7237]95 vector<t_pppSatObs*> obsVector;
96 for (unsigned jj = 0; jj < allObs.size(); jj++) {
[9419]97 if (allObs[jj]->prn().system() == sys) {
[7237]98 obsVector.push_back(allObs[jj]);
[10034]99 num++;
[7237]100 }
101 }
[10386]102 LOG << epoTimeStr << " SATNUM " << sys << ' ' << right << setw(2) << num << endl;
[10034]103 if (processSystem(OPT->LCs(sys), obsVector, epoch->pseudoObsIono()) != success) {
[10220]104 LOG << "t_pppFilter::processSystem() != success: " << sys << endl;
[7237]105 return failure;
106 }
107 }
[8912]108
109 // close epoch processing
110 // ----------------------
[10034]111 cmpDOP(allObs);
112 _parlist->printResult(_epoTime, _QFlt, _xFlt);
[9642]113 _lastEpoTimeOK = _epoTime; // remember time of last successful epoch processing
[7237]114 return success;
115}
116
117// Process Selected LCs
118////////////////////////////////////////////////////////////////////////////
[9642]119t_irc t_pppFilter::processSystem(const vector<t_lc::type> &LCs,
[10034]120 const vector<t_pppSatObs*> &obsVector,
121 bool pseudoObsIonoAvailable) {
[7237]122 LOG.setf(ios::fixed);
123
124 // Detect Cycle Slips
125 // ------------------
[10034]126 if (detectCycleSlips(LCs, obsVector) != success) {
[7237]127 return failure;
128 }
129
[10034]130 ColumnVector xSav = _xFlt;
[9642]131 SymmetricMatrix QSav = _QFlt;
[10034]132 string epoTimeStr = string(_epoTime);
133 const vector<t_pppParam*> &params = _parlist->params();
134 unsigned nPar = _parlist->nPar();
[8965]135
[9642]136 unsigned usedLCs = LCs.size();
[8965]137 if (OPT->_pseudoObsIono && !pseudoObsIonoAvailable) {
[9642]138 usedLCs -= 1; // GIM not used
[8961]139 }
140 // max Obs
[9538]141 unsigned maxObs = obsVector.size() * usedLCs;
142
[7237]143 // Outlier Detection Loop
144 // ----------------------
145 for (unsigned iOutlier = 0; iOutlier < maxObs; iOutlier++) {
146
147 if (iOutlier > 0) {
148 _xFlt = xSav;
149 _QFlt = QSav;
150 }
151
152 // First-Design Matrix, Terms Observed-Computed, Weight Matrix
153 // -----------------------------------------------------------
[9642]154 Matrix AA(maxObs, nPar);
[10034]155 ColumnVector ll(maxObs); ll = 0.0;
156 DiagonalMatrix PP(maxObs); PP = 0.0;
[8912]157
[7237]158 int iObs = -1;
159 vector<t_pppSatObs*> usedObs;
[9642]160 vector<t_lc::type> usedTypes;
[9386]161
162 // Real Observations
163 // =================
[10184]164 int nSat = 0;
[7237]165 for (unsigned ii = 0; ii < obsVector.size(); ii++) {
[9642]166 t_pppSatObs *obs = obsVector[ii];
[10034]167 if (iOutlier == 0) {
[9419]168 obs->resetOutlier();
169 }
[7237]170 if (!obs->outlier()) {
[9583]171 nSat++;
[8905]172 for (unsigned jj = 0; jj < usedLCs; jj++) {
[7237]173 const t_lc::type tLC = LCs[jj];
[9642]174 if (tLC == t_lc::GIM) {
175 continue;
176 }
[7237]177 ++iObs;
178 usedObs.push_back(obs);
179 usedTypes.push_back(tLC);
[9524]180 for (unsigned iPar = 0; iPar < nPar; iPar++) {
[9642]181 const t_pppParam *par = params[iPar];
[10034]182 AA[iObs][iPar] = par->partial(_epoTime, obs, tLC);
[7237]183 }
[10384]184
185 ll[iObs] = obs->obsValue(tLC) - obs->cmpValue(tLC) - DotProduct(_x0, AA.Row(iObs + 1));
[7237]186 PP[iObs] = 1.0 / (obs->sigma(tLC) * obs->sigma(tLC));
187 }
188 }
189 }
190
[9556]191 // Check number of observations
192 // ----------------------------
[10257]193 if (!nSat) {
[9701]194 return failure;
[9699]195 }
[9625]196
[9386]197 // Pseudo Obs Iono
198 // ================
199 if (OPT->_pseudoObsIono && pseudoObsIonoAvailable) {
200 for (unsigned ii = 0; ii < obsVector.size(); ii++) {
[9642]201 t_pppSatObs *obs = obsVector[ii];
[9386]202 if (!obs->outlier()) {
203 for (unsigned jj = 0; jj < usedLCs; jj++) {
204 const t_lc::type tLC = LCs[jj];
[10034]205 if (tLC == t_lc::GIM) {
[9386]206 ++iObs;
[9642]207 } else {
208 continue;
209 }
[9386]210 usedObs.push_back(obs);
211 usedTypes.push_back(tLC);
[9524]212 for (unsigned iPar = 0; iPar < nPar; iPar++) {
[9642]213 const t_pppParam *par = params[iPar];
[10034]214 AA[iObs][iPar] = par->partial(_epoTime, obs, tLC);
[9386]215 }
[10384]216 ll[iObs] = obs->obsValue(tLC) - obs->cmpValue(tLC) - DotProduct(_x0, AA.Row(iObs + 1));
[9386]217 PP[iObs] = 1.0 / (obs->sigma(tLC) * obs->sigma(tLC));
218 }
219 }
[8956]220 }
[8915]221 }
222
[9556]223 // Truncate matrices
224 // -----------------
[9642]225 AA = AA.Rows(1, iObs + 1);
226 ll = ll.Rows(1, iObs + 1);
227 PP = PP.SymSubMatrix(1, iObs + 1);
[7237]228
229 // Kalman update step
230 // ------------------
231 kalman(AA, ll, PP, _QFlt, _xFlt);
232
233 // Check Residuals
234 // ---------------
235 ColumnVector vv = AA * _xFlt - ll;
[9642]236 double maxOutlier = 0.0;
237 int maxOutlierIndex = -1;
238 t_lc::type maxOutlierLC = t_lc::dummy;
[7237]239 for (unsigned ii = 0; ii < usedObs.size(); ii++) {
240 const t_lc::type tLC = usedTypes[ii];
241 double res = fabs(vv[ii]);
242 if (res > usedObs[ii]->maxRes(tLC)) {
243 if (res > fabs(maxOutlier)) {
[9642]244 maxOutlier = vv[ii];
[7237]245 maxOutlierIndex = ii;
[9642]246 maxOutlierLC = tLC;
[7237]247 }
248 }
249 }
250
251 // Mark outlier or break outlier detection loop
252 // --------------------------------------------
253 if (maxOutlierIndex > -1) {
[9642]254 t_pppSatObs *obs = usedObs[maxOutlierIndex];
255 t_pppParam *par = 0;
[10034]256 LOG << epoTimeStr << " Outlier " << t_lc::toString(maxOutlierLC) << ' '
257 << obs->prn().toString() << ' ' << setw(8) << setprecision(4)
258 << maxOutlier << endl;
[9524]259 for (unsigned iPar = 0; iPar < nPar; iPar++) {
[9642]260 t_pppParam *hlp = params[iPar];
[10008]261 if (hlp->type() == t_pppParam::amb &&
[10034]262 hlp->prn() == obs->prn() &&
263 hlp->tLC() == usedTypes[maxOutlierIndex]) {
[7237]264 par = hlp;
265 }
266 }
[10034]267 if (par) {
[10319]268 resetAmb(obs->prn(), obsVector, maxOutlierLC, &QSav, &xSav);
[10021]269 }
[10034]270 else {
271 obs->setOutlier();
[7237]272 }
273 }
274 // Print Residuals
275 // ---------------
276 else {
[8905]277 for (unsigned jj = 0; jj < LCs.size(); jj++) {
278 for (unsigned ii = 0; ii < usedObs.size(); ii++) {
279 const t_lc::type tLC = usedTypes[ii];
[9642]280 t_pppSatObs *obs = usedObs[ii];
[8905]281 if (tLC == LCs[jj]) {
282 obs->setRes(tLC, vv[ii]);
[9642]283 LOG << epoTimeStr << " RES " << left << setw(3)
[9699]284 << t_lc::toString(tLC) << right << ' '
[10034]285 << obs->prn().toString() << ' '
286 << setw(8) << setprecision(4) << vv[ii] << endl;
[7237]287 }
288 }
289 }
290 break;
291 }
292 }
293 return success;
294}
295
296// Cycle-Slip Detection
297////////////////////////////////////////////////////////////////////////////
[9642]298t_irc t_pppFilter::detectCycleSlips(const vector<t_lc::type> &LCs,
[10034]299 const vector<t_pppSatObs*> &obsVector) {
300
[10327]301 double SLIP = 20.0;
302 double fac = 1.0;
303 if (_lastEpoTimeOK.valid()) {
304 fac = _epoTime - _lastEpoTimeOK;
305 if (fac > 60.0 || fac < 1.0) {
306 fac = 1.0;
307 }
308 }
309 SLIP *= fac;
[9386]310 string epoTimeStr = string(_epoTime);
[10034]311 const vector<t_pppParam*> &params = _parlist->params();
[7237]312
313 for (unsigned ii = 0; ii < LCs.size(); ii++) {
[9642]314 const t_lc::type &tLC = LCs[ii];
[7237]315 if (t_lc::includesPhase(tLC)) {
316 for (unsigned iObs = 0; iObs < obsVector.size(); iObs++) {
[9642]317 const t_pppSatObs *obs = obsVector[iObs];
[7237]318
[7267]319 // Check set Slips and Jump Counters
[7237]320 // ---------------------------------
321 bool slip = false;
[9386]322
[7237]323 if (obs->slip()) {
[10319]324 LOG << epoTimeStr << " Cycle slip set (obs) " << obs->prn().toString() << endl;
[7237]325 slip = true;
326 }
327
[10034]328 if (_slips[obs->prn()]._obsSlipCounter != -1 &&
329 _slips[obs->prn()]._obsSlipCounter != obs->slipCounter()) {
[10319]330 LOG << epoTimeStr << " Cycle slip set (obsSlipCounter) " << obs->prn().toString() << endl;
[7237]331 slip = true;
332 }
[10034]333 _slips[obs->prn()]._obsSlipCounter = obs->slipCounter();
334
335 if (_slips[obs->prn()]._biasJumpCounter != -1 &&
336 _slips[obs->prn()]._biasJumpCounter != obs->biasJumpCounter()) {
[10319]337 LOG << epoTimeStr << " Cycle slip set (biasJumpCounter) " << obs->prn().toString() << endl;
[7237]338 slip = true;
339 }
[10034]340 _slips[obs->prn()]._biasJumpCounter = obs->biasJumpCounter();
341
[7237]342 // Slip Set
[7267]343 // --------
[7237]344 if (slip) {
[10034]345 resetAmb(obs->prn(), obsVector, tLC);
[7237]346 }
[10034]347
[10259]348 // Check Pre-Fit Residuals
[10388]349 // -----------------------
[7237]350 else {
[10034]351 ColumnVector AA(params.size());
352 for (unsigned iPar = 0; iPar < params.size(); iPar++) {
353 const t_pppParam* par = params[iPar];
354 AA[iPar] = par->partial(_epoTime, obs, tLC);
[7237]355 }
[10384]356 double ll = obs->obsValue(tLC) - obs->cmpValue(tLC) - DotProduct(_x0, AA);
[10034]357 double vv = DotProduct(AA, _xFlt) - ll;
358
359 if (fabs(vv) > SLIP) {
360 LOG << epoTimeStr << " cycle slip detected " << t_lc::toString(tLC) << ' '
361 << obs->prn().toString() << ' ' << setw(8) << setprecision(4) << vv << endl;
362 }
[10388]363 }
[7237]364 }
365 }
366 }
367 return success;
368}
369
370// Reset Ambiguity Parameter (cycle slip)
371////////////////////////////////////////////////////////////////////////////
[10248]372t_irc t_pppFilter::resetAmb(const t_prn prn, const vector<t_pppSatObs*> &obsVector, t_lc::type lc,
373 SymmetricMatrix *QSav, ColumnVector *xSav) {
[8965]374
[7237]375 t_irc irc = failure;
[10034]376 vector<t_pppParam*>& params = _parlist->params();
[7237]377 for (unsigned iPar = 0; iPar < params.size(); iPar++) {
[9642]378 t_pppParam *par = params[iPar];
[7237]379 if (par->type() == t_pppParam::amb && par->prn() == prn) {
[10249]380 int ind = par->indexNew();
381 double eleSat = par->ambEleSat();
[10156]382 bncTime firstObsTime;
383 bncTime lastObsTime = par->lastObsTime();
[10249]384 (par->firstObsTime().undef()) ?
385 firstObsTime = lastObsTime : firstObsTime = par->firstObsTime();
[7237]386 t_lc::type tLC = par->tLC();
[10184]387 if (tLC != lc) {continue;}
[7237]388 LOG << string(_epoTime) << " RESET " << par->toString() << endl;
[10034]389 delete par; par = new t_pppParam(t_pppParam::amb, prn, tLC, &obsVector);
[7237]390 par->setIndex(ind);
[10156]391 par->setFirstObsTime(firstObsTime);
392 par->setLastObsTime(lastObsTime);
[10248]393 par->setAmbEleSat(eleSat);
[7237]394 params[iPar] = par;
395 for (unsigned ii = 1; ii <= params.size(); ii++) {
[9642]396 _QFlt(ii, ind + 1) = 0.0;
[7237]397 if (QSav) {
[10250]398 (*QSav)(ii, ind + 1) = 0.0;
[7237]399 }
400 }
[9642]401 _QFlt(ind + 1, ind + 1) = par->sigma0() * par->sigma0();
[7237]402 if (QSav) {
[9642]403 (*QSav)(ind + 1, ind + 1) = _QFlt(ind + 1, ind + 1);
[7237]404 }
405 _xFlt[ind] = 0.0;
406 if (xSav) {
407 (*xSav)[ind] = _xFlt[ind];
408 }
409 _x0[ind] = par->x0();
[10256]410 irc = success;
[7237]411 }
412 }
413
414 return irc;
415}
416
417// Compute various DOP Values
418////////////////////////////////////////////////////////////////////////////
[10034]419void t_pppFilter::cmpDOP(const vector<t_pppSatObs*> &obsVector) {
[7237]420
421 _dop.reset();
422
423 try {
424 const unsigned numPar = 4;
425 Matrix AA(obsVector.size(), numPar);
[10328]426 t_pppParam* parX = 0;
427 t_pppParam* parY = 0;
428 t_pppParam* parZ = 0;
[7237]429 _numSat = 0;
430 for (unsigned ii = 0; ii < obsVector.size(); ii++) {
[9642]431 t_pppSatObs *obs = obsVector[ii];
[7237]432 if (obs->isValid() && !obs->outlier()) {
433 ++_numSat;
434 for (unsigned iPar = 0; iPar < numPar; iPar++) {
[10328]435 t_pppParam* par = _parlist->params()[iPar];
[10034]436 AA[_numSat - 1][iPar] = par->partial(_epoTime, obs, t_lc::c1);
[10328]437 if (par->type() == t_pppParam::crdX) {
438 parX = par;
439 }
440 else if (par->type() == t_pppParam::crdY) {
441 parY = par;
442 }
443 else if (par->type() == t_pppParam::crdZ) {
444 parZ = par;
445 }
[7237]446 }
447 }
448 }
449 if (_numSat < 4) {
450 return;
451 }
452 AA = AA.Rows(1, _numSat);
[10034]453 SymmetricMatrix NN; NN << AA.t() * AA;
[7237]454 SymmetricMatrix QQ = NN.i();
[10328]455 SymmetricMatrix QQxyz = QQ.SymSubMatrix(1,3);
[7267]456
[10328]457 ColumnVector xyz(3), neu(3);
458 SymmetricMatrix QQneu(3);
459 const t_pppStation *sta = PPP_CLIENT->staRover();
460 xyz[0] = _xFlt[parX->indexNew()];
461 xyz[1] = _xFlt[parY->indexNew()];
462 xyz[2] = _xFlt[parZ->indexNew()];
463 xyz2neu(sta->ellApr().data(), xyz.data(), neu.data());
464 covariXYZ_NEU(QQxyz, sta->ellApr().data(), QQneu);
465
466 _dop.H = sqrt(QQneu(1, 1) + QQneu(2, 2));
467 _dop.V = sqrt(QQneu(3, 3));
[9642]468 _dop.P = sqrt(QQ(1, 1) + QQ(2, 2) + QQ(3, 3));
469 _dop.T = sqrt(QQ(4, 4));
470 _dop.G = sqrt(QQ(1, 1) + QQ(2, 2) + QQ(3, 3) + QQ(4, 4));
[7237]471 }
[10034]472 catch (...) {
473 }
[7237]474}
475
[9526]476//
[7237]477////////////////////////////////////////////////////////////////////////////
[10256]478void t_pppFilter::predictCovCrdPart(const SymmetricMatrix &QFltOld, bool setNeuNoiseToZero) {
[7237]479
[10034]480 const vector<t_pppParam*>& params = _parlist->params();
481
[7237]482 if (params.size() < 3) {
483 return;
484 }
485
486 bool first = (params[0]->indexOld() < 0);
487
[10034]488 SymmetricMatrix Qneu(3); Qneu = 0.0;
[7237]489 for (unsigned ii = 0; ii < 3; ii++) {
[9642]490 const t_pppParam *par = params[ii];
[7237]491 if (first) {
492 Qneu[ii][ii] = par->sigma0() * par->sigma0();
[10034]493 }
494 else {
[7237]495 Qneu[ii][ii] = par->noise() * par->noise();
496 }
497 }
498
[9642]499 const t_pppStation *sta = PPP_CLIENT->staRover();
[7237]500 SymmetricMatrix Qxyz(3);
501 covariNEU_XYZ(Qneu, sta->ellApr().data(), Qxyz);
502
503 if (first) {
[9642]504 _QFlt.SymSubMatrix(1, 3) = Qxyz;
[10034]505 }
506 else {
[7237]507 double dt = _epoTime - _firstEpoTime;
[10010]508 if (dt < OPT->_seedingTime || setNeuNoiseToZero) {
[10256]509 _QFlt.SymSubMatrix(1, 3) = QFltOld.SymSubMatrix(1, 3);
[10034]510 }
511 else {
[10256]512 _QFlt.SymSubMatrix(1, 3) = QFltOld.SymSubMatrix(1, 3) + Qxyz;
[7237]513 }
514 }
515}
[8912]516
[9526]517//
518////////////////////////////////////////////////////////////////////////////
[10256]519void t_pppFilter::setStateVectorAndVarCovMatrix(const ColumnVector &xFltOld,
520 const SymmetricMatrix &QFltOld,
521 bool setNeuNoiseToZero) {
[9526]522
[10034]523 const vector<t_pppParam*>& params = _parlist->params();
[9526]524 unsigned nPar = params.size();
525
[10034]526 _QFlt.ReSize(nPar); _QFlt = 0.0;
527 _xFlt.ReSize(nPar); _xFlt = 0.0;
528 _x0.ReSize(nPar); _x0 = 0.0;
[9526]529
530 for (unsigned ii = 0; ii < nPar; ii++) {
[9642]531 t_pppParam *par1 = params[ii];
[10256]532 if (QFltOld.size() == 0) {
[9526]533 par1->resetIndex();
534 }
535 _x0[ii] = par1->x0();
536 int iOld = par1->indexOld();
537 if (iOld < 0) {
538 _QFlt[ii][ii] = par1->sigma0() * par1->sigma0(); // new parameter
[9642]539 } else {
[10256]540 _QFlt[ii][ii] = QFltOld[iOld][iOld] + par1->noise() * par1->noise();
541 _xFlt[ii] = xFltOld[iOld];
[9526]542 for (unsigned jj = 0; jj < ii; jj++) {
[9642]543 t_pppParam *par2 = params[jj];
544 int jOld = par2->indexOld();
[9526]545 if (jOld >= 0) {
[10256]546 _QFlt[ii][jj] = QFltOld(iOld + 1, jOld + 1);
[9526]547 }
548 }
549 }
550 }
[10256]551 predictCovCrdPart(QFltOld, setNeuNoiseToZero);
[9526]552}
Note: See TracBrowser for help on using the repository browser.