source: ntrip/trunk/BNC/src/PPP_free/pppFilter.cpp@ 6561

Last change on this file since 6561 was 6407, checked in by mervart, 9 years ago
File size: 35.4 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: t_pppParam, t_pppFilter
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 <sstream>
44#include <newmatio.h>
45#include <newmatap.h>
46
47#include "pppFilter.h"
48#include "pppClient.h"
49#include "bncutils.h"
50#include "bncantex.h"
51#include "pppOptions.h"
52#include "pppModel.h"
53
54using namespace BNC_PPP;
55using namespace std;
56
57const double MAXRES_CODE = 2.98 * 3.0;
58const double MAXRES_PHASE_GPS = 2.98 * 0.03;
59const double MAXRES_PHASE_GLONASS = 2.98 * 0.03;
60const double GLONASS_WEIGHT_FACTOR = 1.0;
61
62#define LOG (_pppClient->log())
63#define OPT (_pppClient->opt())
64
65// Constructor
66////////////////////////////////////////////////////////////////////////////
67t_pppParam::t_pppParam(t_pppParam::parType typeIn, int indexIn,
68 const QString& prnIn) {
69 type = typeIn;
70 index = indexIn;
71 prn = prnIn;
72 index_old = 0;
73 xx = 0.0;
74 numEpo = 0;
75}
76
77// Destructor
78////////////////////////////////////////////////////////////////////////////
79t_pppParam::~t_pppParam() {
80}
81
82// Partial
83////////////////////////////////////////////////////////////////////////////
84double t_pppParam::partial(t_satData* satData, bool phase) {
85
86 Tracer tracer("t_pppParam::partial");
87
88 // Coordinates
89 // -----------
90 if (type == CRD_X) {
91 return (xx - satData->xx(1)) / satData->rho;
92 }
93 else if (type == CRD_Y) {
94 return (xx - satData->xx(2)) / satData->rho;
95 }
96 else if (type == CRD_Z) {
97 return (xx - satData->xx(3)) / satData->rho;
98 }
99
100 // Receiver Clocks
101 // ---------------
102 else if (type == RECCLK) {
103 return 1.0;
104 }
105
106 // Troposphere
107 // -----------
108 else if (type == TROPO) {
109 return 1.0 / sin(satData->eleSat);
110 }
111
112 // Glonass Offset
113 // --------------
114 else if (type == GLONASS_OFFSET) {
115 if (satData->prn[0] == 'R') {
116 return 1.0;
117 }
118 else {
119 return 0.0;
120 }
121 }
122
123 // Galileo Offset
124 // --------------
125 else if (type == GALILEO_OFFSET) {
126 if (satData->prn[0] == 'E') {
127 return 1.0;
128 }
129 else {
130 return 0.0;
131 }
132 }
133
134 // Ambiguities
135 // -----------
136 else if (type == AMB_L3) {
137 if (phase && satData->prn == prn) {
138 return 1.0;
139 }
140 else {
141 return 0.0;
142 }
143 }
144
145 // Default return
146 // --------------
147 return 0.0;
148}
149
150// Constructor
151////////////////////////////////////////////////////////////////////////////
152t_pppFilter::t_pppFilter(t_pppClient* pppClient) {
153
154 _pppClient = pppClient;
155 _tides = new t_tides();
156
157 // Antenna Name, ANTEX File
158 // ------------------------
159 _antex = 0;
160 if (!OPT->_antexFileName.empty()) {
161 _antex = new bncAntex(OPT->_antexFileName.c_str());
162 }
163
164 // Bancroft Coordinates
165 // --------------------
166 _xcBanc.ReSize(4); _xcBanc = 0.0;
167 _ellBanc.ReSize(3); _ellBanc = 0.0;
168
169 // Save copy of data (used in outlier detection)
170 // ---------------------------------------------
171 _epoData_sav = new t_epoData();
172
173 // Some statistics
174 // ---------------
175 _neu.ReSize(3); _neu = 0.0;
176 _numSat = 0;
177 _pDop = 0.0;
178}
179
180// Destructor
181////////////////////////////////////////////////////////////////////////////
182t_pppFilter::~t_pppFilter() {
183 delete _tides;
184 delete _antex;
185 for (int iPar = 1; iPar <= _params.size(); iPar++) {
186 delete _params[iPar-1];
187 }
188 for (int iPar = 1; iPar <= _params_sav.size(); iPar++) {
189 delete _params_sav[iPar-1];
190 }
191 delete _epoData_sav;
192}
193
194// Reset Parameters and Variance-Covariance Matrix
195////////////////////////////////////////////////////////////////////////////
196void t_pppFilter::reset() {
197
198 Tracer tracer("t_pppFilter::reset");
199
200 double lastTrp = 0.0;
201 for (int ii = 0; ii < _params.size(); ii++) {
202 t_pppParam* pp = _params[ii];
203 if (pp->type == t_pppParam::TROPO) {
204 lastTrp = pp->xx;
205 }
206 delete pp;
207 }
208 _params.clear();
209
210 int nextPar = 0;
211 _params.push_back(new t_pppParam(t_pppParam::CRD_X, ++nextPar, ""));
212 _params.push_back(new t_pppParam(t_pppParam::CRD_Y, ++nextPar, ""));
213 _params.push_back(new t_pppParam(t_pppParam::CRD_Z, ++nextPar, ""));
214 _params.push_back(new t_pppParam(t_pppParam::RECCLK, ++nextPar, ""));
215 if (OPT->estTrp()) {
216 _params.push_back(new t_pppParam(t_pppParam::TROPO, ++nextPar, ""));
217 }
218 if (OPT->useSystem('R')) {
219 _params.push_back(new t_pppParam(t_pppParam::GLONASS_OFFSET, ++nextPar, ""));
220 }
221 if (OPT->useSystem('E')) {
222 _params.push_back(new t_pppParam(t_pppParam::GALILEO_OFFSET, ++nextPar, ""));
223 }
224
225 _QQ.ReSize(_params.size());
226 _QQ = 0.0;
227 for (int iPar = 1; iPar <= _params.size(); iPar++) {
228 t_pppParam* pp = _params[iPar-1];
229 pp->xx = 0.0;
230 if (pp->isCrd()) {
231 _QQ(iPar,iPar) = OPT->_aprSigCrd(1) * OPT->_aprSigCrd(1);
232 }
233 else if (pp->type == t_pppParam::RECCLK) {
234 _QQ(iPar,iPar) = OPT->_noiseClk * OPT->_noiseClk;
235 }
236 else if (pp->type == t_pppParam::TROPO) {
237 _QQ(iPar,iPar) = OPT->_aprSigTrp * OPT->_aprSigTrp;
238 pp->xx = lastTrp;
239 }
240 else if (pp->type == t_pppParam::GLONASS_OFFSET) {
241 _QQ(iPar,iPar) = 1000.0 * 1000.0;
242 }
243 else if (pp->type == t_pppParam::GALILEO_OFFSET) {
244 _QQ(iPar,iPar) = 1000.0 * 1000.0;
245 }
246 }
247}
248
249// Bancroft Solution
250////////////////////////////////////////////////////////////////////////////
251t_irc t_pppFilter::cmpBancroft(t_epoData* epoData) {
252
253 Tracer tracer("t_pppFilter::cmpBancroft");
254
255 if (int(epoData->sizeSys('G')) < OPT->_minObs) {
256 LOG << "t_pppFilter::cmpBancroft: not enough data\n";
257 return failure;
258 }
259
260 Matrix BB(epoData->sizeSys('G'), 4);
261
262 QMapIterator<QString, t_satData*> it(epoData->satData);
263 int iObsBanc = 0;
264 while (it.hasNext()) {
265 it.next();
266 t_satData* satData = it.value();
267 if (satData->system() == 'G') {
268 ++iObsBanc;
269 QString prn = it.key();
270 BB(iObsBanc, 1) = satData->xx(1);
271 BB(iObsBanc, 2) = satData->xx(2);
272 BB(iObsBanc, 3) = satData->xx(3);
273 BB(iObsBanc, 4) = satData->P3 + satData->clk;
274 }
275 }
276
277 bancroft(BB, _xcBanc);
278
279 // Ellipsoidal Coordinates
280 // ------------------------
281 xyz2ell(_xcBanc.data(), _ellBanc.data());
282
283 // Compute Satellite Elevations
284 // ----------------------------
285 QMutableMapIterator<QString, t_satData*> im(epoData->satData);
286 while (im.hasNext()) {
287 im.next();
288 t_satData* satData = im.value();
289 cmpEle(satData);
290 if (satData->eleSat < OPT->_minEle) {
291 delete satData;
292 im.remove();
293 }
294 }
295
296 return success;
297}
298
299// Computed Value
300////////////////////////////////////////////////////////////////////////////
301double t_pppFilter::cmpValue(t_satData* satData, bool phase) {
302
303 Tracer tracer("t_pppFilter::cmpValue");
304
305 ColumnVector xRec(3);
306 xRec(1) = x();
307 xRec(2) = y();
308 xRec(3) = z();
309
310 double rho0 = (satData->xx - xRec).norm_Frobenius();
311 double dPhi = t_CST::omega * rho0 / t_CST::c;
312
313 xRec(1) = x() * cos(dPhi) - y() * sin(dPhi);
314 xRec(2) = y() * cos(dPhi) + x() * sin(dPhi);
315 xRec(3) = z();
316
317 xRec += _tides->displacement(_time, xRec);
318
319 satData->rho = (satData->xx - xRec).norm_Frobenius();
320
321 double tropDelay = delay_saast(satData->eleSat) +
322 trp() / sin(satData->eleSat);
323
324 double wind = 0.0;
325 if (phase) {
326 wind = windUp(satData->prn, satData->xx, xRec) * satData->lambda3;
327 }
328
329 double offset = 0.0;
330 if (satData->prn[0] == 'R') {
331 offset = Glonass_offset();
332 }
333 else if (satData->prn[0] == 'E') {
334 offset = Galileo_offset();
335 }
336
337 double phaseCenter = 0.0;
338 if (_antex) {
339 bool found;
340 phaseCenter = _antex->rcvCorr(OPT->_antNameRover, t_frequency::G1,
341 satData->eleSat, satData->azSat, found);
342 if (!found) {
343 LOG << "ANTEX: antenna >" << OPT->_antNameRover << "< not found\n";
344 }
345 }
346
347 double antennaOffset = 0.0;
348 double cosa = cos(satData->azSat);
349 double sina = sin(satData->azSat);
350 double cose = cos(satData->eleSat);
351 double sine = sin(satData->eleSat);
352 antennaOffset = -OPT->_neuEccRover(1) * cosa*cose
353 -OPT->_neuEccRover(2) * sina*cose
354 -OPT->_neuEccRover(3) * sine;
355
356 return satData->rho + phaseCenter + antennaOffset + clk()
357 + offset - satData->clk + tropDelay + wind;
358}
359
360// Tropospheric Model (Saastamoinen)
361////////////////////////////////////////////////////////////////////////////
362double t_pppFilter::delay_saast(double Ele) {
363
364 Tracer tracer("t_pppFilter::delay_saast");
365
366 double xyz[3];
367 xyz[0] = x();
368 xyz[1] = y();
369 xyz[2] = z();
370 double ell[3];
371 xyz2ell(xyz, ell);
372 double height = ell[2];
373
374 double pp = 1013.25 * pow(1.0 - 2.26e-5 * height, 5.225);
375 double TT = 18.0 - height * 0.0065 + 273.15;
376 double hh = 50.0 * exp(-6.396e-4 * height);
377 double ee = hh / 100.0 * exp(-37.2465 + 0.213166*TT - 0.000256908*TT*TT);
378
379 double h_km = height / 1000.0;
380
381 if (h_km < 0.0) h_km = 0.0;
382 if (h_km > 5.0) h_km = 5.0;
383 int ii = int(h_km + 1);
384 double href = ii - 1;
385
386 double bCor[6];
387 bCor[0] = 1.156;
388 bCor[1] = 1.006;
389 bCor[2] = 0.874;
390 bCor[3] = 0.757;
391 bCor[4] = 0.654;
392 bCor[5] = 0.563;
393
394 double BB = bCor[ii-1] + (bCor[ii]-bCor[ii-1]) * (h_km - href);
395
396 double zen = M_PI/2.0 - Ele;
397
398 return (0.002277/cos(zen)) * (pp + ((1255.0/TT)+0.05)*ee - BB*(tan(zen)*tan(zen)));
399}
400
401// Prediction Step of the Filter
402////////////////////////////////////////////////////////////////////////////
403void t_pppFilter::predict(int iPhase, t_epoData* epoData) {
404
405 Tracer tracer("t_pppFilter::predict");
406
407 if (iPhase == 0) {
408
409 const double maxSolGap = 0.0;
410
411 bool firstCrd = false;
412 if (!_lastTimeOK.valid() || (maxSolGap > 0.0 && _time - _lastTimeOK > maxSolGap)) {
413 firstCrd = true;
414 _startTime = epoData->tt;
415 reset();
416 }
417
418 // Use different white noise for Quick-Start mode
419 // ----------------------------------------------
420 double sigCrdP_used = OPT->_noiseCrd(1);
421 if ( OPT->_seedingTime > 0.0 && OPT->_seedingTime > (epoData->tt - _startTime) ) {
422 sigCrdP_used = 0.0;
423 }
424
425 // Predict Parameter values, add white noise
426 // -----------------------------------------
427 for (int iPar = 1; iPar <= _params.size(); iPar++) {
428 t_pppParam* pp = _params[iPar-1];
429
430 // Coordinates
431 // -----------
432 if (pp->type == t_pppParam::CRD_X) {
433 if (firstCrd) {
434 if (OPT->xyzAprRoverSet()) {
435 pp->xx = OPT->_xyzAprRover[0];
436 }
437 else {
438 pp->xx = _xcBanc(1);
439 }
440 }
441 _QQ(iPar,iPar) += sigCrdP_used * sigCrdP_used;
442 }
443 else if (pp->type == t_pppParam::CRD_Y) {
444 if (firstCrd) {
445 if (OPT->xyzAprRoverSet()) {
446 pp->xx = OPT->_xyzAprRover[1];
447 }
448 else {
449 pp->xx = _xcBanc(2);
450 }
451 }
452 _QQ(iPar,iPar) += sigCrdP_used * sigCrdP_used;
453 }
454 else if (pp->type == t_pppParam::CRD_Z) {
455 if (firstCrd) {
456 if (OPT->xyzAprRoverSet()) {
457 pp->xx = OPT->_xyzAprRover[2];
458 }
459 else {
460 pp->xx = _xcBanc(3);
461 }
462 }
463 _QQ(iPar,iPar) += sigCrdP_used * sigCrdP_used;
464 }
465
466 // Receiver Clocks
467 // ---------------
468 else if (pp->type == t_pppParam::RECCLK) {
469 pp->xx = _xcBanc(4);
470 for (int jj = 1; jj <= _params.size(); jj++) {
471 _QQ(iPar, jj) = 0.0;
472 }
473 _QQ(iPar,iPar) = OPT->_noiseClk * OPT->_noiseClk;
474 }
475
476 // Tropospheric Delay
477 // ------------------
478 else if (pp->type == t_pppParam::TROPO) {
479 _QQ(iPar,iPar) += OPT->_noiseTrp * OPT->_noiseTrp;
480 }
481
482 // Glonass Offset
483 // --------------
484 else if (pp->type == t_pppParam::GLONASS_OFFSET) {
485 pp->xx = 0.0;
486 for (int jj = 1; jj <= _params.size(); jj++) {
487 _QQ(iPar, jj) = 0.0;
488 }
489 _QQ(iPar,iPar) = 1000.0 * 1000.0;
490 }
491
492 // Galileo Offset
493 // --------------
494 else if (pp->type == t_pppParam::GALILEO_OFFSET) {
495 _QQ(iPar,iPar) += 0.1 * 0.1;
496 }
497 }
498 }
499
500 // Add New Ambiguities if necessary
501 // --------------------------------
502 if (OPT->ambLCs('G').size() || OPT->ambLCs('R').size() || OPT->ambLCs('E').size()) {
503
504 // Make a copy of QQ and xx, set parameter indices
505 // -----------------------------------------------
506 SymmetricMatrix QQ_old = _QQ;
507
508 for (int iPar = 1; iPar <= _params.size(); iPar++) {
509 _params[iPar-1]->index_old = _params[iPar-1]->index;
510 _params[iPar-1]->index = 0;
511 }
512
513 // Remove Ambiguity Parameters without observations
514 // ------------------------------------------------
515 int iPar = 0;
516 QMutableVectorIterator<t_pppParam*> im(_params);
517 while (im.hasNext()) {
518 t_pppParam* par = im.next();
519 bool removed = false;
520 if (par->type == t_pppParam::AMB_L3) {
521 if (epoData->satData.find(par->prn) == epoData->satData.end()) {
522 removed = true;
523 delete par;
524 im.remove();
525 }
526 }
527 if (! removed) {
528 ++iPar;
529 par->index = iPar;
530 }
531 }
532
533 // Add new ambiguity parameters
534 // ----------------------------
535 QMapIterator<QString, t_satData*> it(epoData->satData);
536 while (it.hasNext()) {
537 it.next();
538 t_satData* satData = it.value();
539 addAmb(satData);
540 }
541
542 int nPar = _params.size();
543 _QQ.ReSize(nPar); _QQ = 0.0;
544 for (int i1 = 1; i1 <= nPar; i1++) {
545 t_pppParam* p1 = _params[i1-1];
546 if (p1->index_old != 0) {
547 _QQ(p1->index, p1->index) = QQ_old(p1->index_old, p1->index_old);
548 for (int i2 = 1; i2 <= nPar; i2++) {
549 t_pppParam* p2 = _params[i2-1];
550 if (p2->index_old != 0) {
551 _QQ(p1->index, p2->index) = QQ_old(p1->index_old, p2->index_old);
552 }
553 }
554 }
555 }
556
557 for (int ii = 1; ii <= nPar; ii++) {
558 t_pppParam* par = _params[ii-1];
559 if (par->index_old == 0) {
560 _QQ(par->index, par->index) = OPT->_aprSigAmb * OPT->_aprSigAmb;
561 }
562 par->index_old = par->index;
563 }
564 }
565}
566
567// Update Step of the Filter (currently just a single-epoch solution)
568////////////////////////////////////////////////////////////////////////////
569t_irc t_pppFilter::update(t_epoData* epoData) {
570
571 Tracer tracer("t_pppFilter::update");
572
573 _time = epoData->tt; // current epoch time
574
575 if (OPT->useOrbClkCorr()) {
576 LOG << "Precise Point Positioning of Epoch " << _time.timestr(1)
577 << "\n---------------------------------------------------------------\n";
578 }
579 else {
580 LOG << "Single Point Positioning of Epoch " << _time.timestr(1)
581 << "\n--------------------------------------------------------------\n";
582 }
583
584 // Outlier Detection Loop
585 // ----------------------
586 if (update_p(epoData) != success) {
587 return failure;
588 }
589
590 // Set Solution Vector
591 // -------------------
592 LOG.setf(ios::fixed);
593 QVectorIterator<t_pppParam*> itPar(_params);
594 while (itPar.hasNext()) {
595 t_pppParam* par = itPar.next();
596 if (par->type == t_pppParam::RECCLK) {
597 LOG << "\n clk = " << setw(10) << setprecision(3) << par->xx
598 << " +- " << setw(6) << setprecision(3)
599 << sqrt(_QQ(par->index,par->index));
600 }
601 else if (par->type == t_pppParam::AMB_L3) {
602 ++par->numEpo;
603 LOG << "\n amb " << par->prn.toAscii().data() << " = "
604 << setw(10) << setprecision(3) << par->xx
605 << " +- " << setw(6) << setprecision(3)
606 << sqrt(_QQ(par->index,par->index))
607 << " nEpo = " << par->numEpo;
608 }
609 else if (par->type == t_pppParam::TROPO) {
610 double aprTrp = delay_saast(M_PI/2.0);
611 LOG << "\n trp = " << par->prn.toAscii().data()
612 << setw(7) << setprecision(3) << aprTrp << " "
613 << setw(6) << setprecision(3) << showpos << par->xx << noshowpos
614 << " +- " << setw(6) << setprecision(3)
615 << sqrt(_QQ(par->index,par->index));
616 }
617 else if (par->type == t_pppParam::GLONASS_OFFSET) {
618 LOG << "\n offGlo = " << setw(10) << setprecision(3) << par->xx
619 << " +- " << setw(6) << setprecision(3)
620 << sqrt(_QQ(par->index,par->index));
621 }
622 else if (par->type == t_pppParam::GALILEO_OFFSET) {
623 LOG << "\n offGal = " << setw(10) << setprecision(3) << par->xx
624 << " +- " << setw(6) << setprecision(3)
625 << sqrt(_QQ(par->index,par->index));
626 }
627 }
628
629 LOG << endl << endl;
630
631 // Compute dilution of precision
632 // -----------------------------
633 cmpDOP(epoData);
634
635 // Final Message (both log file and screen)
636 // ----------------------------------------
637 LOG << OPT->_roverName << " PPP "
638 << epoData->tt.timestr(1) << " " << epoData->sizeAll() << " "
639 << setw(14) << setprecision(3) << x() << " +- "
640 << setw(6) << setprecision(3) << sqrt(_QQ(1,1)) << " "
641 << setw(14) << setprecision(3) << y() << " +- "
642 << setw(6) << setprecision(3) << sqrt(_QQ(2,2)) << " "
643 << setw(14) << setprecision(3) << z() << " +- "
644 << setw(6) << setprecision(3) << sqrt(_QQ(3,3));
645
646 // NEU Output
647 // ----------
648 if (OPT->xyzAprRoverSet()) {
649 double xyz[3];
650 xyz[0] = x() - OPT->_xyzAprRover[0];
651 xyz[1] = y() - OPT->_xyzAprRover[1];
652 xyz[2] = z() - OPT->_xyzAprRover[2];
653
654 double ellRef[3];
655 xyz2ell(OPT->_xyzAprRover.data(), ellRef);
656 xyz2neu(ellRef, xyz, _neu.data());
657
658 LOG << " NEU "
659 << setw(8) << setprecision(3) << _neu[0] << " "
660 << setw(8) << setprecision(3) << _neu[1] << " "
661 << setw(8) << setprecision(3) << _neu[2] << endl << endl;
662 }
663 else {
664 LOG << endl << endl;
665 }
666
667 _lastTimeOK = _time; // remember time of last successful update
668 return success;
669}
670
671// Outlier Detection
672////////////////////////////////////////////////////////////////////////////
673QString t_pppFilter::outlierDetection(int iPhase, const ColumnVector& vv,
674 QMap<QString, t_satData*>& satData) {
675
676 Tracer tracer("t_pppFilter::outlierDetection");
677
678 QString prnGPS;
679 QString prnGlo;
680 double maxResGPS = 0.0;
681 double maxResGlo = 0.0;
682 findMaxRes(vv, satData, prnGPS, prnGlo, maxResGPS, maxResGlo);
683
684 if (iPhase == 1) {
685 if (maxResGlo > 2.98 * OPT->_maxResL1) {
686 LOG << "Outlier Phase " << prnGlo.toAscii().data() << ' ' << maxResGlo << endl;
687 return prnGlo;
688 }
689 else if (maxResGPS > 2.98 * OPT->_maxResL1) {
690 LOG << "Outlier Phase " << prnGPS.toAscii().data() << ' ' << maxResGPS << endl;
691 return prnGPS;
692 }
693 }
694 else if (iPhase == 0 && maxResGPS > 2.98 * OPT->_maxResC1) {
695 LOG << "Outlier Code " << prnGPS.toAscii().data() << ' ' << maxResGPS << endl;
696 return prnGPS;
697 }
698
699 return QString();
700}
701
702// Phase Wind-Up Correction
703///////////////////////////////////////////////////////////////////////////
704double t_pppFilter::windUp(const QString& prn, const ColumnVector& rSat,
705 const ColumnVector& rRec) {
706
707 Tracer tracer("t_pppFilter::windUp");
708
709 double Mjd = _time.mjd() + _time.daysec() / 86400.0;
710
711 // First time - initialize to zero
712 // -------------------------------
713 if (!_windUpTime.contains(prn)) {
714 _windUpSum[prn] = 0.0;
715 }
716
717 // Compute the correction for new time
718 // -----------------------------------
719 if (!_windUpTime.contains(prn) || _windUpTime[prn] != Mjd) {
720 _windUpTime[prn] = Mjd;
721
722 // Unit Vector GPS Satellite --> Receiver
723 // --------------------------------------
724 ColumnVector rho = rRec - rSat;
725 rho /= rho.norm_Frobenius();
726
727 // GPS Satellite unit Vectors sz, sy, sx
728 // -------------------------------------
729 ColumnVector sz = -rSat / rSat.norm_Frobenius();
730
731 ColumnVector xSun = t_astro::Sun(Mjd);
732 xSun /= xSun.norm_Frobenius();
733
734 ColumnVector sy = crossproduct(sz, xSun);
735 ColumnVector sx = crossproduct(sy, sz);
736
737 // Effective Dipole of the GPS Satellite Antenna
738 // ---------------------------------------------
739 ColumnVector dipSat = sx - rho * DotProduct(rho,sx)
740 - crossproduct(rho, sy);
741
742 // Receiver unit Vectors rx, ry
743 // ----------------------------
744 ColumnVector rx(3);
745 ColumnVector ry(3);
746
747 double recEll[3]; xyz2ell(rRec.data(), recEll) ;
748 double neu[3];
749
750 neu[0] = 1.0;
751 neu[1] = 0.0;
752 neu[2] = 0.0;
753 neu2xyz(recEll, neu, rx.data());
754
755 neu[0] = 0.0;
756 neu[1] = -1.0;
757 neu[2] = 0.0;
758 neu2xyz(recEll, neu, ry.data());
759
760 // Effective Dipole of the Receiver Antenna
761 // ----------------------------------------
762 ColumnVector dipRec = rx - rho * DotProduct(rho,rx)
763 + crossproduct(rho, ry);
764
765 // Resulting Effect
766 // ----------------
767 double alpha = DotProduct(dipSat,dipRec) /
768 (dipSat.norm_Frobenius() * dipRec.norm_Frobenius());
769
770 if (alpha > 1.0) alpha = 1.0;
771 if (alpha < -1.0) alpha = -1.0;
772
773 double dphi = acos(alpha) / 2.0 / M_PI; // in cycles
774
775 if ( DotProduct(rho, crossproduct(dipSat, dipRec)) < 0.0 ) {
776 dphi = -dphi;
777 }
778
779 _windUpSum[prn] = floor(_windUpSum[prn] - dphi + 0.5) + dphi;
780 }
781
782 return _windUpSum[prn];
783}
784
785//
786///////////////////////////////////////////////////////////////////////////
787void t_pppFilter::cmpEle(t_satData* satData) {
788 Tracer tracer("t_pppFilter::cmpEle");
789 ColumnVector rr = satData->xx - _xcBanc.Rows(1,3);
790 double rho = rr.norm_Frobenius();
791
792 double neu[3];
793 xyz2neu(_ellBanc.data(), rr.data(), neu);
794
795 satData->eleSat = acos( sqrt(neu[0]*neu[0] + neu[1]*neu[1]) / rho );
796 if (neu[2] < 0) {
797 satData->eleSat *= -1.0;
798 }
799 satData->azSat = atan2(neu[1], neu[0]);
800}
801
802//
803///////////////////////////////////////////////////////////////////////////
804void t_pppFilter::addAmb(t_satData* satData) {
805 Tracer tracer("t_pppFilter::addAmb");
806 bool found = false;
807 for (int iPar = 1; iPar <= _params.size(); iPar++) {
808 if (_params[iPar-1]->type == t_pppParam::AMB_L3 &&
809 _params[iPar-1]->prn == satData->prn) {
810 found = true;
811 break;
812 }
813 }
814 if (!found) {
815 t_pppParam* par = new t_pppParam(t_pppParam::AMB_L3,
816 _params.size()+1, satData->prn);
817 _params.push_back(par);
818 par->xx = satData->L3 - cmpValue(satData, true);
819 }
820}
821
822//
823///////////////////////////////////////////////////////////////////////////
824void t_pppFilter::addObs(int iPhase, unsigned& iObs, t_satData* satData,
825 Matrix& AA, ColumnVector& ll, DiagonalMatrix& PP) {
826
827 Tracer tracer("t_pppFilter::addObs");
828
829 const double ELEWGHT = 20.0;
830 double ellWgtCoef = 1.0;
831 double eleD = satData->eleSat * 180.0 / M_PI;
832 if (eleD < ELEWGHT) {
833 ellWgtCoef = 1.5 - 0.5 / (ELEWGHT - 10.0) * (eleD - 10.0);
834 }
835
836 // Remember Observation Index
837 // --------------------------
838 ++iObs;
839 satData->obsIndex = iObs;
840
841 // Phase Observations
842 // ------------------
843 if (iPhase == 1) {
844 ll(iObs) = satData->L3 - cmpValue(satData, true);
845 double sigL3 = 2.98 * OPT->_sigmaL1;
846 if (satData->system() == 'R') {
847 sigL3 *= GLONASS_WEIGHT_FACTOR;
848 }
849 PP(iObs,iObs) = 1.0 / (sigL3 * sigL3) / (ellWgtCoef * ellWgtCoef);
850 for (int iPar = 1; iPar <= _params.size(); iPar++) {
851 if (_params[iPar-1]->type == t_pppParam::AMB_L3 &&
852 _params[iPar-1]->prn == satData->prn) {
853 ll(iObs) -= _params[iPar-1]->xx;
854 }
855 AA(iObs, iPar) = _params[iPar-1]->partial(satData, true);
856 }
857 }
858
859 // Code Observations
860 // -----------------
861 else {
862 double sigP3 = 2.98 * OPT->_sigmaC1;
863 ll(iObs) = satData->P3 - cmpValue(satData, false);
864 PP(iObs,iObs) = 1.0 / (sigP3 * sigP3) / (ellWgtCoef * ellWgtCoef);
865 for (int iPar = 1; iPar <= _params.size(); iPar++) {
866 AA(iObs, iPar) = _params[iPar-1]->partial(satData, false);
867 }
868 }
869}
870
871//
872///////////////////////////////////////////////////////////////////////////
873QByteArray t_pppFilter::printRes(int iPhase, const ColumnVector& vv,
874 const QMap<QString, t_satData*>& satDataMap) {
875
876 Tracer tracer("t_pppFilter::printRes");
877
878 ostringstream str;
879 str.setf(ios::fixed);
880
881 QMapIterator<QString, t_satData*> it(satDataMap);
882 while (it.hasNext()) {
883 it.next();
884 t_satData* satData = it.value();
885 if (satData->obsIndex != 0) {
886 str << _time.timestr(1)
887 << " RES " << satData->prn.toAscii().data()
888 << (iPhase ? " L3 " : " P3 ")
889 << setw(9) << setprecision(4) << vv(satData->obsIndex) << endl;
890 }
891 }
892
893 return QByteArray(str.str().c_str());
894}
895
896//
897///////////////////////////////////////////////////////////////////////////
898void t_pppFilter::findMaxRes(const ColumnVector& vv,
899 const QMap<QString, t_satData*>& satData,
900 QString& prnGPS, QString& prnGlo,
901 double& maxResGPS, double& maxResGlo) {
902
903 Tracer tracer("t_pppFilter::findMaxRes");
904
905 maxResGPS = 0.0;
906 maxResGlo = 0.0;
907
908 QMapIterator<QString, t_satData*> it(satData);
909 while (it.hasNext()) {
910 it.next();
911 t_satData* satData = it.value();
912 if (satData->obsIndex != 0) {
913 QString prn = satData->prn;
914 if (prn[0] == 'R') {
915 if (fabs(vv(satData->obsIndex)) > maxResGlo) {
916 maxResGlo = fabs(vv(satData->obsIndex));
917 prnGlo = prn;
918 }
919 }
920 else {
921 if (fabs(vv(satData->obsIndex)) > maxResGPS) {
922 maxResGPS = fabs(vv(satData->obsIndex));
923 prnGPS = prn;
924 }
925 }
926 }
927 }
928}
929
930// Update Step (private - loop over outliers)
931////////////////////////////////////////////////////////////////////////////
932t_irc t_pppFilter::update_p(t_epoData* epoData) {
933
934 Tracer tracer("t_pppFilter::update_p");
935
936 // Save Variance-Covariance Matrix, and Status Vector
937 // --------------------------------------------------
938 rememberState(epoData);
939
940 QString lastOutlierPrn;
941
942 // Try with all satellites, then with all minus one, etc.
943 // ------------------------------------------------------
944 while (selectSatellites(lastOutlierPrn, epoData->satData) == success) {
945
946 QByteArray strResCode;
947 QByteArray strResPhase;
948
949 // Bancroft Solution
950 // -----------------
951 if (cmpBancroft(epoData) != success) {
952 break;
953 }
954
955 // First update using code observations, then phase observations
956 // -------------------------------------------------------------
957 bool usePhase = OPT->ambLCs('G').size() || OPT->ambLCs('R').size() ||
958 OPT->ambLCs('E').size();
959
960 for (int iPhase = 0; iPhase <= (usePhase ? 1 : 0); iPhase++) {
961
962 // Status Prediction
963 // -----------------
964 predict(iPhase, epoData);
965
966 // Create First-Design Matrix
967 // --------------------------
968 unsigned nPar = _params.size();
969 unsigned nObs = 0;
970 if (iPhase == 0) {
971 nObs = epoData->sizeAll() - epoData->sizeSys('R'); // Glonass code not used
972 }
973 else {
974 nObs = epoData->sizeAll();
975 }
976
977 // Prepare first-design Matrix, vector observed-computed
978 // -----------------------------------------------------
979 Matrix AA(nObs, nPar); // first design matrix
980 ColumnVector ll(nObs); // tems observed-computed
981 DiagonalMatrix PP(nObs); PP = 0.0;
982
983 unsigned iObs = 0;
984 QMapIterator<QString, t_satData*> it(epoData->satData);
985 while (it.hasNext()) {
986 it.next();
987 t_satData* satData = it.value();
988 if (iPhase == 1 || satData->system() != 'R') {
989 QString prn = satData->prn;
990 addObs(iPhase, iObs, satData, AA, ll, PP);
991 }
992 }
993
994 // Compute Filter Update
995 // ---------------------
996 ColumnVector dx(nPar); dx = 0.0;
997 kalman(AA, ll, PP, _QQ, dx);
998 ColumnVector vv = ll - AA * dx;
999
1000 // Print Residuals
1001 // ---------------
1002 if (iPhase == 0) {
1003 strResCode = printRes(iPhase, vv, epoData->satData);
1004 }
1005 else {
1006 strResPhase = printRes(iPhase, vv, epoData->satData);
1007 }
1008
1009 // Check the residuals
1010 // -------------------
1011 lastOutlierPrn = outlierDetection(iPhase, vv, epoData->satData);
1012
1013 // No Outlier Detected
1014 // -------------------
1015 if (lastOutlierPrn.isEmpty()) {
1016
1017 QVectorIterator<t_pppParam*> itPar(_params);
1018 while (itPar.hasNext()) {
1019 t_pppParam* par = itPar.next();
1020 par->xx += dx(par->index);
1021 }
1022
1023 if (!usePhase || iPhase == 1) {
1024 if (_outlierGPS.size() > 0 || _outlierGlo.size() > 0) {
1025 LOG << "Neglected PRNs: ";
1026 if (!_outlierGPS.isEmpty()) {
1027 LOG << _outlierGPS.last().toAscii().data() << ' ';
1028 }
1029 QStringListIterator itGlo(_outlierGlo);
1030 while (itGlo.hasNext()) {
1031 QString prn = itGlo.next();
1032 LOG << prn.toAscii().data() << ' ';
1033 }
1034 }
1035 LOG << strResCode.data() << strResPhase.data();
1036
1037 return success;
1038 }
1039 }
1040
1041 // Outlier Found
1042 // -------------
1043 else {
1044 restoreState(epoData);
1045 break;
1046 }
1047
1048 } // for iPhase
1049
1050 } // while selectSatellites
1051
1052 restoreState(epoData);
1053 return failure;
1054}
1055
1056// Remeber Original State Vector and Variance-Covariance Matrix
1057////////////////////////////////////////////////////////////////////////////
1058void t_pppFilter::rememberState(t_epoData* epoData) {
1059
1060 _QQ_sav = _QQ;
1061
1062 QVectorIterator<t_pppParam*> itSav(_params_sav);
1063 while (itSav.hasNext()) {
1064 t_pppParam* par = itSav.next();
1065 delete par;
1066 }
1067 _params_sav.clear();
1068
1069 QVectorIterator<t_pppParam*> it(_params);
1070 while (it.hasNext()) {
1071 t_pppParam* par = it.next();
1072 _params_sav.push_back(new t_pppParam(*par));
1073 }
1074
1075 _epoData_sav->deepCopy(epoData);
1076}
1077
1078// Restore Original State Vector and Variance-Covariance Matrix
1079////////////////////////////////////////////////////////////////////////////
1080void t_pppFilter::restoreState(t_epoData* epoData) {
1081
1082 _QQ = _QQ_sav;
1083
1084 QVectorIterator<t_pppParam*> it(_params);
1085 while (it.hasNext()) {
1086 t_pppParam* par = it.next();
1087 delete par;
1088 }
1089 _params.clear();
1090
1091 QVectorIterator<t_pppParam*> itSav(_params_sav);
1092 while (itSav.hasNext()) {
1093 t_pppParam* par = itSav.next();
1094 _params.push_back(new t_pppParam(*par));
1095 }
1096
1097 epoData->deepCopy(_epoData_sav);
1098}
1099
1100//
1101////////////////////////////////////////////////////////////////////////////
1102t_irc t_pppFilter::selectSatellites(const QString& lastOutlierPrn,
1103 QMap<QString, t_satData*>& satData) {
1104
1105 // First Call
1106 // ----------
1107 if (lastOutlierPrn.isEmpty()) {
1108 _outlierGPS.clear();
1109 _outlierGlo.clear();
1110 return success;
1111 }
1112
1113 // Second and next trials
1114 // ----------------------
1115 else {
1116
1117 if (lastOutlierPrn[0] == 'R') {
1118 _outlierGlo << lastOutlierPrn;
1119 }
1120
1121 // Remove all Glonass Outliers
1122 // ---------------------------
1123 QStringListIterator it(_outlierGlo);
1124 while (it.hasNext()) {
1125 QString prn = it.next();
1126 if (satData.contains(prn)) {
1127 delete satData.take(prn);
1128 }
1129 }
1130
1131 if (lastOutlierPrn[0] == 'R') {
1132 _outlierGPS.clear();
1133 return success;
1134 }
1135
1136 // GPS Outlier appeared for the first time - try to delete it
1137 // ----------------------------------------------------------
1138 if (_outlierGPS.indexOf(lastOutlierPrn) == -1) {
1139 _outlierGPS << lastOutlierPrn;
1140 if (satData.contains(lastOutlierPrn)) {
1141 delete satData.take(lastOutlierPrn);
1142 }
1143 return success;
1144 }
1145
1146 }
1147
1148 return failure;
1149}
1150
1151//
1152////////////////////////////////////////////////////////////////////////////
1153double lorentz(const ColumnVector& aa, const ColumnVector& bb) {
1154 return aa(1)*bb(1) + aa(2)*bb(2) + aa(3)*bb(3) - aa(4)*bb(4);
1155}
1156
1157//
1158////////////////////////////////////////////////////////////////////////////
1159void t_pppFilter::bancroft(const Matrix& BBpass, ColumnVector& pos) {
1160
1161 if (pos.Nrows() != 4) {
1162 pos.ReSize(4);
1163 }
1164 pos = 0.0;
1165
1166 for (int iter = 1; iter <= 2; iter++) {
1167 Matrix BB = BBpass;
1168 int mm = BB.Nrows();
1169 for (int ii = 1; ii <= mm; ii++) {
1170 double xx = BB(ii,1);
1171 double yy = BB(ii,2);
1172 double traveltime = 0.072;
1173 if (iter > 1) {
1174 double zz = BB(ii,3);
1175 double rho = sqrt( (xx-pos(1)) * (xx-pos(1)) +
1176 (yy-pos(2)) * (yy-pos(2)) +
1177 (zz-pos(3)) * (zz-pos(3)) );
1178 traveltime = rho / t_CST::c;
1179 }
1180 double angle = traveltime * t_CST::omega;
1181 double cosa = cos(angle);
1182 double sina = sin(angle);
1183 BB(ii,1) = cosa * xx + sina * yy;
1184 BB(ii,2) = -sina * xx + cosa * yy;
1185 }
1186
1187 Matrix BBB;
1188 if (mm > 4) {
1189 SymmetricMatrix hlp; hlp << BB.t() * BB;
1190 BBB = hlp.i() * BB.t();
1191 }
1192 else {
1193 BBB = BB.i();
1194 }
1195 ColumnVector ee(mm); ee = 1.0;
1196 ColumnVector alpha(mm); alpha = 0.0;
1197 for (int ii = 1; ii <= mm; ii++) {
1198 alpha(ii) = lorentz(BB.Row(ii).t(),BB.Row(ii).t())/2.0;
1199 }
1200 ColumnVector BBBe = BBB * ee;
1201 ColumnVector BBBalpha = BBB * alpha;
1202 double aa = lorentz(BBBe, BBBe);
1203 double bb = lorentz(BBBe, BBBalpha)-1;
1204 double cc = lorentz(BBBalpha, BBBalpha);
1205 double root = sqrt(bb*bb-aa*cc);
1206
1207 Matrix hlpPos(4,2);
1208 hlpPos.Column(1) = (-bb-root)/aa * BBBe + BBBalpha;
1209 hlpPos.Column(2) = (-bb+root)/aa * BBBe + BBBalpha;
1210
1211 ColumnVector omc(2);
1212 for (int pp = 1; pp <= 2; pp++) {
1213 hlpPos(4,pp) = -hlpPos(4,pp);
1214 omc(pp) = BB(1,4) -
1215 sqrt( (BB(1,1)-hlpPos(1,pp)) * (BB(1,1)-hlpPos(1,pp)) +
1216 (BB(1,2)-hlpPos(2,pp)) * (BB(1,2)-hlpPos(2,pp)) +
1217 (BB(1,3)-hlpPos(3,pp)) * (BB(1,3)-hlpPos(3,pp)) ) -
1218 hlpPos(4,pp);
1219 }
1220 if ( fabs(omc(1)) > fabs(omc(2)) ) {
1221 pos = hlpPos.Column(2);
1222 }
1223 else {
1224 pos = hlpPos.Column(1);
1225 }
1226 }
1227}
1228
1229//
1230////////////////////////////////////////////////////////////////////////////
1231void t_pppFilter::cmpDOP(t_epoData* epoData) {
1232
1233 Tracer tracer("t_pppFilter::cmpDOP");
1234
1235 _numSat = 0;
1236 _pDop = 0.0;
1237
1238 if (_params.size() < 4) {
1239 return;
1240 }
1241
1242 const unsigned numPar = 4;
1243 Matrix AA(epoData->sizeAll(), numPar);
1244 QMapIterator<QString, t_satData*> it(epoData->satData);
1245 while (it.hasNext()) {
1246 it.next();
1247 t_satData* satData = it.value();
1248 _numSat += 1;
1249 for (unsigned iPar = 0; iPar < numPar; iPar++) {
1250 AA[_numSat-1][iPar] = _params[iPar]->partial(satData, false);
1251 }
1252 }
1253 if (_numSat < 4) {
1254 return;
1255 }
1256 AA = AA.Rows(1, _numSat);
1257 SymmetricMatrix NN; NN << AA.t() * AA;
1258 SymmetricMatrix QQ = NN.i();
1259
1260 _pDop = sqrt(QQ(1,1) + QQ(2,2) + QQ(3,3));
1261}
Note: See TracBrowser for help on using the repository browser.