source: ntrip/trunk/BNC/src/PPP/pppClient.cpp@ 10938

Last change on this file since 10938 was 10938, checked in by stuerze, 5 days ago

bugfix regarding ionospheric constraints

  • Property svn:keywords set to Author Date Id Rev URL;svn:eol-style=native
  • Property svn:mime-type set to text/plain
File size: 19.6 KB
Line 
1/* -------------------------------------------------------------------------
2 * BKG NTRIP Client
3 * -------------------------------------------------------------------------
4 *
5 * Class: t_pppClient
6 *
7 * Purpose: PPP Client processing starts here
8 *
9 * Author: L. Mervart
10 *
11 * Created: 29-Jul-2014
12 *
13 * Changes:
14 *
15 * -----------------------------------------------------------------------*/
16
17#include <QThreadStorage>
18
19#include <iostream>
20#include <iomanip>
21#include <cmath>
22#include <stdlib.h>
23#include <string.h>
24#include <stdexcept>
25
26#include "pppClient.h"
27#include "pppEphPool.h"
28#include "pppObsPool.h"
29#include "bncconst.h"
30#include "bncutils.h"
31#include "pppStation.h"
32#include "bncantex.h"
33#include "pppFilter.h"
34
35using namespace BNC_PPP;
36using namespace std;
37
38// Global variable holding thread-specific pointers
39//////////////////////////////////////////////////////////////////////////////
40QThreadStorage<t_pppClient*> CLIENTS;
41
42// Static function returning thread-specific pointer
43//////////////////////////////////////////////////////////////////////////////
44t_pppClient* t_pppClient::instance() {
45 return CLIENTS.localData();
46}
47
48// Constructor
49//////////////////////////////////////////////////////////////////////////////
50t_pppClient::t_pppClient(const t_pppOptions* opt) {
51 _running = true;
52 _output = 0;
53 _opt = new t_pppOptions(*opt);
54 _log = new ostringstream();
55 _ephPool = new t_pppEphPool();
56 _obsPool = new t_pppObsPool();
57 _staRover = new t_pppStation();
58 _filter = new t_pppFilter();
59 _tides = new t_tides();
60 _antex = 0;
61 if (!_opt->_antexFileName.empty()) {
62 _antex = new bncAntex(_opt->_antexFileName.c_str());
63 }
64 if (!_opt->_blqFileName.empty()) {
65 if (_tides->readBlqFile(_opt->_blqFileName.c_str()) == success) {
66 //_tides->printAllBlqSets();
67 }
68 }
69 CLIENTS.setLocalData(this); // CLIENTS takes ownership over "this"
70}
71
72// Destructor
73//////////////////////////////////////////////////////////////////////////////
74t_pppClient::~t_pppClient() {
75 _running = false;
76 delete _log;
77 delete _opt;
78 delete _ephPool;
79 delete _obsPool;
80 delete _staRover;
81 if (_antex) {
82 delete _antex;
83 }
84 delete _filter;
85 delete _tides;
86 clearObs();
87}
88
89//
90//////////////////////////////////////////////////////////////////////////////
91void t_pppClient::putEphemeris(const t_eph* eph) {
92 const t_ephGPS* ephGPS = dynamic_cast<const t_ephGPS*>(eph);
93 const t_ephGlo* ephGlo = dynamic_cast<const t_ephGlo*>(eph);
94 const t_ephGal* ephGal = dynamic_cast<const t_ephGal*>(eph);
95 const t_ephBDS* ephBDS = dynamic_cast<const t_ephBDS*>(eph);
96 if (ephGPS) {
97 _ephPool->putEphemeris(new t_ephGPS(*ephGPS));
98 }
99 else if (ephGlo) {
100 _ephPool->putEphemeris(new t_ephGlo(*ephGlo));
101 }
102 else if (ephGal) {
103 _ephPool->putEphemeris(new t_ephGal(*ephGal));
104 }
105 else if (ephBDS) {
106 _ephPool->putEphemeris(new t_ephBDS(*ephBDS));
107 }
108}
109
110//
111//////////////////////////////////////////////////////////////////////////////
112void t_pppClient::putTec(const t_vTec* vTec) {
113 _obsPool->putTec(new t_vTec(*vTec));
114}
115
116//
117//////////////////////////////////////////////////////////////////////////////
118void t_pppClient::putOrbCorrections(const vector<t_orbCorr*>& corr) {
119 if (OPT->_logMode == t_pppOptions::normal && corr.size() > 0) {
120 LOG << "orbCorrections " << string(corr[0]->_time) << ' ' << corr.size() << endl;
121 }
122 for (unsigned ii = 0; ii < corr.size(); ii++) {
123 _ephPool->putOrbCorrection(new t_orbCorr(*corr[ii]));
124 }
125}
126
127//
128//////////////////////////////////////////////////////////////////////////////
129void t_pppClient::putClkCorrections(const vector<t_clkCorr*>& corr) {
130 if (OPT->_logMode == t_pppOptions::normal && corr.size() > 0) {
131 LOG << "clkCorrections " << string(corr[0]->_time) << ' ' << corr.size() << endl;
132 }
133 for (unsigned ii = 0; ii < corr.size(); ii++) {
134 _ephPool->putClkCorrection(new t_clkCorr(*corr[ii]));
135 }
136}
137
138//
139//////////////////////////////////////////////////////////////////////////////
140void t_pppClient::putCodeBiases(const vector<t_satCodeBias*>& biases) {
141 if (OPT->_logMode == t_pppOptions::normal && biases.size() > 0) {
142 LOG << "codeBiases " << string(biases[0]->_time) << ' ' << biases.size() << endl;
143 }
144 set<char> systems;
145 for (unsigned ii = 0; ii < biases.size(); ii++) {
146 t_satCodeBias* newBias = new t_satCodeBias(*biases[ii]);
147 char sys = newBias->_prn.system();
148 if (systems.find(sys) == systems.end()) {
149 _obsPool->clearCodeBiases(sys);
150 systems.insert(sys);
151 }
152 _obsPool->putCodeBias(newBias);
153 }
154}
155
156//
157//////////////////////////////////////////////////////////////////////////////
158void t_pppClient::putPhaseBiases(const vector<t_satPhaseBias*>& biases) {
159 if (OPT->_logMode == t_pppOptions::normal && biases.size() > 0) {
160 LOG << "phaseBiases " << string(biases[0]->_time) << ' ' << biases.size() << endl;
161 }
162 set<char> systems;
163 for (unsigned ii = 0; ii < biases.size(); ii++) {
164 t_satPhaseBias* newBias = new t_satPhaseBias(*biases[ii]);
165 char sys = newBias->_prn.system();
166 if (systems.find(sys) == systems.end()) {
167 _obsPool->clearPhaseBiases(sys);
168 systems.insert(sys);
169 }
170 _obsPool->putPhaseBias(newBias);
171 }
172}
173
174//
175//////////////////////////////////////////////////////////////////////////////
176t_irc t_pppClient::prepareObs(const vector<t_satObs*>& satObs,
177 vector<t_pppSatObs*>& obsVector, bncTime& epoTime) {
178
179 // Default
180 // -------
181 epoTime.reset();
182 clearObs();
183
184 // Create vector of valid observations
185 // -----------------------------------
186 for (unsigned ii = 0; ii < satObs.size(); ii++) {
187 char sys = satObs[ii]->_prn.system();
188 if (_opt->useSystem(sys)) {
189 t_pppSatObs* pppSatObs = new t_pppSatObs(*satObs[ii]);
190 if (pppSatObs->isValid()) {
191 obsVector.push_back(pppSatObs);
192 }
193 else {
194 delete pppSatObs;
195 }
196 }
197 }
198
199 // Check whether data are synchronized, compute epoTime
200 // ----------------------------------------------------
201 const double MAXSYNC = 0.05; // synchronization limit
202 double meanDt = 0.0;
203 for (unsigned ii = 0; ii < obsVector.size(); ii++) {
204 const t_pppSatObs* satObs = obsVector.at(ii);
205 if (epoTime.undef()) {
206 epoTime = satObs->time();
207 }
208 else {
209 double dt = satObs->time() - epoTime;
210 if (fabs(dt) > MAXSYNC) {
211 LOG << "t_pppClient::prepareObs asynchronous observations" << endl;
212 return failure;
213 }
214 meanDt += dt;
215 }
216 }
217
218 if (obsVector.size() > 0) {
219 epoTime += meanDt / obsVector.size();
220 }
221
222 return success;
223}
224
225//
226//////////////////////////////////////////////////////////////////////////////
227bool t_pppClient::preparePseudoObs(std::vector<t_pppSatObs*>& obsVector) {
228
229 bool pseudoObsIono = false;
230
231 if (_opt->_pseudoObsIono) {
232
233 // Select reference satellite per system: keep the current one if still
234 // visible; only switch to highest elevation when the current one disappears
235 // -------------------------------------------------------------------------
236 map<char, t_pppSatObs*> refSatMap;
237 map<char, t_pppSatObs*> bestEleMap;
238 for (t_pppSatObs* satObs : obsVector) {
239 satObs->resetReference();
240 double stec = satObs->getIonoCodeDelay(t_frequency::G1);
241 if (stec == 0.0) continue;
242 char sys = satObs->prn().system();
243 if (!bestEleMap.count(sys) || satObs->eleSat() > bestEleMap[sys]->eleSat()) {
244 bestEleMap[sys] = satObs;
245 }
246 if (_refPrnMap.count(sys) && satObs->prn() == _refPrnMap[sys]) {
247 refSatMap[sys] = satObs;
248 }
249 }
250 for (auto& kv : bestEleMap) {
251 if (!refSatMap.count(kv.first)) {
252 refSatMap[kv.first] = kv.second;
253 }
254 }
255 for (auto& kv : refSatMap) {
256 _refPrnMap[kv.first] = kv.second->prn();
257 kv.second->setAsReference();
258 }
259
260 if (bestEleMap.empty()) {
261 LOG << "GIM pseudo-obs unavailable: no valid STEC (vTec data missing?)" << endl;
262 }
263
264 // Set STEC pseudo-observations (single-differenced vs reference satellite)
265 // -------------------------------------------------------------------------
266 int nGIM = 0;
267 for (t_pppSatObs* satObs : obsVector) {
268 char sys = satObs->prn().system();
269 double stecRefSat = refSatMap.count(sys)
270 ? refSatMap[sys]->getIonoCodeDelay(t_frequency::G1)
271 : 0.0;
272 if (satObs->setPseudoObsIono(t_frequency::G1, stecRefSat)) {
273 pseudoObsIono = true;
274 nGIM++;
275 }
276 }
277 if (nGIM > 0) {
278 LOG << "GIM pseudo-obs: " << nGIM << " satellites, ref:";
279 for (auto& kv : refSatMap) {
280 LOG << ' ' << kv.second->prn().toString();
281 }
282 LOG << endl;
283 }
284 }
285
286 if (OPT->_logMode == t_pppOptions::all) {
287 vector<t_pppSatObs*>::iterator it = obsVector.begin();
288 while (it != obsVector.end()) {
289 t_pppSatObs* satObs = *it;
290 satObs->printObsMinusComputed();
291 it++;
292 }
293 }
294 return pseudoObsIono;
295}
296
297// Compute the Bancroft position, check for blunders
298//////////////////////////////////////////////////////////////////////////////
299t_irc t_pppClient::cmpBancroft(const bncTime& epoTime,
300 vector<t_pppSatObs*>& obsVector,
301 ColumnVector& xyzc, bool print) {
302
303 int numBancroft = obsVector.size();
304
305 while (_running) {
306 Matrix BB(numBancroft, 4);
307 int iObs = -1;
308 for (unsigned ii = 0; ii < obsVector.size(); ii++) {
309 const t_pppSatObs* satObs = obsVector.at(ii);
310 t_lc LC = satObs->rangeLC();
311 if ( satObs->isValid(LC) &&
312 (!satObs->modelSet() || satObs->eleSat() >= _opt->_minEle) ) {
313 ++iObs;
314 BB[iObs][0] = satObs->xc()[0];
315 BB[iObs][1] = satObs->xc()[1];
316 BB[iObs][2] = satObs->xc()[2];
317 BB[iObs][3] = satObs->obsValue(LC) - satObs->cmpValueForBanc(LC);
318 }
319 }
320 if (iObs + 1 < _opt->_minObs) {
321 LOG << "t_pppClient::cmpBancroft not enough observations: " << iObs + 1 << endl;
322 return failure;
323 }
324 BB = BB.Rows(1,iObs+1);
325 if (bancroft(BB, xyzc) != success) {
326 return failure;
327 }
328
329 xyzc[3] /= t_CST::c;
330
331 // Check Blunders
332 // --------------
333 const double BLUNDER = 1500.0;
334 double maxRes = 0.0;
335 unsigned maxResIndex = 0;
336 for (unsigned ii = 0; ii < obsVector.size(); ii++) {
337 const t_pppSatObs* satObs = obsVector.at(ii);
338 t_lc LC = satObs->rangeLC();
339 if (satObs->isValid(LC) &&
340 (!satObs->modelSet() || satObs->eleSat() >= _opt->_minEle) ) {
341 ColumnVector rr = satObs->xc().Rows(1,3) - xyzc.Rows(1,3);
342 double res = rr.NormFrobenius() - satObs->obsValue(LC)
343 - (satObs->xc()[3] - xyzc[3]) * t_CST::c;
344 if (fabs(res) > maxRes) {
345 maxRes = fabs(res);
346 maxResIndex = ii;
347 }
348 }
349 }
350 if (maxRes < BLUNDER) {
351 if (print) {
352 LOG.setf(ios::fixed);
353 LOG << "\nPPP of Epoch ";
354 if (!_epoTimeRover.undef()) LOG << string(_epoTimeRover);
355 LOG << " using " << _opt->_corrMount;
356 LOG << "\n---------------------------------------------------------------\n";
357 LOG << string(epoTime) << " BANCROFT: "
358 << setw(14) << setprecision(3) << xyzc[0] << ' '
359 << setw(14) << setprecision(3) << xyzc[1] << ' '
360 << setw(14) << setprecision(3) << xyzc[2] << ' '
361 << setw(14) << setprecision(3) << xyzc[3] * t_CST::c << endl << endl;
362 }
363 break;
364 }
365 else {
366 t_pppSatObs* satObs = obsVector.at(maxResIndex);
367 LOG << "t_pppClient::cmpBancroft Outlier " << satObs->prn().toString()
368 << " " << maxRes << endl;
369 delete satObs;
370 obsVector.erase(obsVector.begin() + maxResIndex);
371 }
372 }
373
374 return success;
375}
376
377//
378//////////////////////////////////////////////////////////////////////////////
379void t_pppClient::initOutput(t_output* output) {
380 _output = output;
381 _output->_numSat = 0;
382 _output->_hDop = 0.0;
383 _output->_error = false;
384}
385
386//
387//////////////////////////////////////////////////////////////////////////////
388void t_pppClient::clearObs() {
389 for (unsigned ii = 0; ii < _obsRover.size(); ii++) {
390 delete _obsRover.at(ii);
391 }
392 _obsRover.clear();
393}
394
395//
396//////////////////////////////////////////////////////////////////////////////
397void t_pppClient::finish(t_irc irc, int /*ind*/) {
398#ifdef BNC_DEBUG_PPP
399 LOG << "t_pppClient::finish(" << ind << "): " << irc << endl;
400#endif
401
402 clearObs();
403
404 _output->_epoTime = _epoTimeRover;
405
406 if (irc == success) {
407 _output->_xyzRover[0] = _staRover->xyzApr()[0] + _filter->x()[0];
408 _output->_xyzRover[1] = _staRover->xyzApr()[1] + _filter->x()[1];
409 _output->_xyzRover[2] = _staRover->xyzApr()[2] + _filter->x()[2];
410
411 xyz2neu(_staRover->ellApr().data(), _filter->x().data(), _output->_neu);
412
413 copy(&_filter->Q().data()[0], &_filter->Q().data()[6], _output->_covMatrix);
414
415 _output->_trp0 = t_tropo::delay_saast(_staRover->xyzApr(), M_PI/2.0);
416 _output->_trp = _filter->trp();
417 _output->_trpStdev = _filter->trpStdev();
418
419 _output->_fixRatio = _filter->fixRatio();
420
421 _output->_numSat = _filter->numSat();
422 _output->_hDop = _filter->HDOP();
423 _output->_error = false;
424 }
425 else {
426 _output->_error = true;
427 }
428
429 _output->_log = _log->str();
430 delete _log; _log = new ostringstream();
431
432 return;
433}
434
435//
436//////////////////////////////////////////////////////////////////////////////
437t_irc t_pppClient::cmpModel(t_pppStation* station, const ColumnVector& xyzc,
438 vector<t_pppSatObs*>& obsVector) {
439 bncTime time;
440 time = _epoTimeRover;
441 station->setName(_opt->_roverName);
442 station->setAntName(_opt->_antNameRover);
443 station->setEpochTime(time);
444
445 if (_opt->xyzAprRoverSet()) {
446 station->setXyzApr(_opt->_xyzAprRover);
447 }
448 else {
449 station->setXyzApr(xyzc.Rows(1,3));
450 }
451 station->setNeuEcc(_opt->_neuEccRover);
452
453 // Receiver Clock
454 // --------------
455 station->setDClk(xyzc[3]);
456
457 // Tides
458 // -----
459 station->setTideDsplEarth(_tides->earth(time, station->xyzApr()));
460 station->setTideDsplOcean(_tides->ocean(time, station->xyzApr(), station->name()));
461
462 // Observation model
463 // -----------------
464 vector<t_pppSatObs*>::iterator it = obsVector.begin();
465 while (it != obsVector.end()) {
466 t_pppSatObs* satObs = *it;
467 t_irc modelSetup;
468 if (satObs->isValid()) {
469 modelSetup = satObs->cmpModel(station);
470 }
471 if (satObs->isValid() &&
472 satObs->eleSat() >= _opt->_minEle &&
473 modelSetup == success) {
474 ++it;
475 }
476 else {
477 delete satObs;
478 it = obsVector.erase(it);
479 }
480 }
481
482 return success;
483}
484
485//
486//////////////////////////////////////////////////////////////////////////////
487void t_pppClient::processEpoch(const vector<t_satObs*>& satObs, t_output* output) {
488
489 try {
490 initOutput(output);
491
492 // Prepare Observations of the Rover
493 // ---------------------------------
494 if (prepareObs(satObs, _obsRover, _epoTimeRover) != success) {
495 return finish(failure, 1);
496 }
497
498 for (int iter = 1; iter <= 2; iter++) {
499 ColumnVector xyzc(4); xyzc = 0.0;
500 bool print = (iter == 2);
501 if (cmpBancroft(_epoTimeRover, _obsRover, xyzc, print) != success) {
502 return finish(failure, 2);
503 }
504 if (cmpModel(_staRover, xyzc, _obsRover) != success) {
505 return finish(failure, 3);
506 }
507 }
508
509 // Use observations only if satellite code biases are available
510 // ------------------------------------------------------------
511 if (_opt->ambRes()) {
512 useObsWithBiasesOnly(_obsRover);
513 }
514
515 if (int(_obsRover.size()) < _opt->_minObs) {
516 LOG << "t_pppClient::processEpoch not enough observations" << endl;
517 return finish(failure, 4);
518 }
519
520 // Prepare Pseudo Observations of the Rover
521 // ----------------------------------------
522 _pseudoObsIono = preparePseudoObs(_obsRover);
523
524 // Store last epoch of data
525 // ------------------------
526 _obsPool->putEpoch(_epoTimeRover, _obsRover, _pseudoObsIono);
527
528 // Process Epoch in Filter
529 // -----------------------
530 if (_filter->processEpoch(_obsPool) != success) {
531 LOG << "t_pppFilter::processEpoch() != success" << endl;
532 return finish(failure, 5);
533 }
534 }
535 catch (Exception& exc) {
536 LOG << exc.what() << endl;
537 return finish(failure, 6);
538 }
539 catch (t_except msg) {
540 LOG << msg.what() << endl;
541 return finish(failure, 7);
542 }
543 catch (const char* msg) {
544 LOG << msg << endl;
545 return finish(failure, 8);
546 }
547 catch (...) {
548 LOG << "unknown exception" << endl;
549 return finish(failure, 9);
550 }
551 return finish(success, 0);
552}
553
554//
555////////////////////////////////////////////////////////////////////////////
556double lorentz(const ColumnVector& aa, const ColumnVector& bb) {
557 return aa[0]*bb[0] + aa[1]*bb[1] + aa[2]*bb[2] - aa[3]*bb[3];
558}
559
560//
561////////////////////////////////////////////////////////////////////////////
562t_irc t_pppClient::bancroft(const Matrix& BBpass, ColumnVector& pos) {
563
564 if (pos.Nrows() != 4) {
565 pos.ReSize(4);
566 }
567 pos = 0.0;
568
569 for (int iter = 1; iter <= 2; iter++) {
570 Matrix BB = BBpass;
571 int mm = BB.Nrows();
572 for (int ii = 1; ii <= mm; ii++) {
573 double xx = BB(ii,1);
574 double yy = BB(ii,2);
575 double traveltime = 0.072;
576 if (iter > 1) {
577 double zz = BB(ii,3);
578 double rho = sqrt( (xx-pos(1)) * (xx-pos(1)) +
579 (yy-pos(2)) * (yy-pos(2)) +
580 (zz-pos(3)) * (zz-pos(3)) );
581 traveltime = rho / t_CST::c;
582 }
583 double angle = traveltime * t_CST::omega;
584 double cosa = cos(angle);
585 double sina = sin(angle);
586 BB(ii,1) = cosa * xx + sina * yy;
587 BB(ii,2) = -sina * xx + cosa * yy;
588 }
589
590 Matrix BBB;
591 if (mm > 4) {
592 SymmetricMatrix hlp; hlp << BB.t() * BB;
593 BBB = hlp.i() * BB.t();
594 }
595 else {
596 BBB = BB.i();
597 }
598 ColumnVector ee(mm); ee = 1.0;
599 ColumnVector alpha(mm); alpha = 0.0;
600 for (int ii = 1; ii <= mm; ii++) {
601 alpha(ii) = lorentz(BB.Row(ii).t(),BB.Row(ii).t())/2.0;
602 }
603 ColumnVector BBBe = BBB * ee;
604 ColumnVector BBBalpha = BBB * alpha;
605 double aa = lorentz(BBBe, BBBe);
606 double bb = lorentz(BBBe, BBBalpha)-1;
607 double cc = lorentz(BBBalpha, BBBalpha);
608 double root = sqrt(bb*bb-aa*cc);
609
610 Matrix hlpPos(4,2);
611 hlpPos.Column(1) = (-bb-root)/aa * BBBe + BBBalpha;
612 hlpPos.Column(2) = (-bb+root)/aa * BBBe + BBBalpha;
613
614 ColumnVector omc(2);
615 for (int pp = 1; pp <= 2; pp++) {
616 hlpPos(4,pp) = -hlpPos(4,pp);
617 omc(pp) = BB(1,4) -
618 sqrt( (BB(1,1)-hlpPos(1,pp)) * (BB(1,1)-hlpPos(1,pp)) +
619 (BB(1,2)-hlpPos(2,pp)) * (BB(1,2)-hlpPos(2,pp)) +
620 (BB(1,3)-hlpPos(3,pp)) * (BB(1,3)-hlpPos(3,pp)) ) -
621 hlpPos(4,pp);
622 }
623 if ( fabs(omc(1)) > fabs(omc(2)) ) {
624 pos = hlpPos.Column(2);
625 }
626 else {
627 pos = hlpPos.Column(1);
628 }
629 }
630 if (pos.size() != 4 ||
631 std::isnan(pos(1)) ||
632 std::isnan(pos(2)) ||
633 std::isnan(pos(3)) ||
634 std::isnan(pos(4))) {
635 return failure;
636 }
637
638 return success;
639}
640
641//
642//////////////////////////////////////////////////////////////////////////////
643void t_pppClient::reset() {
644
645 LOG << "pppClient: reset" << endl;
646 _refPrnMap.clear();
647 // to delete old orbit and clock corrections
648 delete _ephPool;
649 _ephPool = new t_pppEphPool();
650
651 // to delete old biases
652 delete _obsPool;
653 _obsPool = new t_pppObsPool();
654
655 // to delete all parameters
656 delete _filter;
657 _filter = new t_pppFilter();
658
659}
660
661//
662//////////////////////////////////////////////////////////////////////////////
663void t_pppClient::useObsWithBiasesOnly(vector<t_pppSatObs*>& obsVector) const {
664 vector<t_pppSatObs*>::iterator it = obsVector.begin();
665 while (it != obsVector.end()) {
666 t_pppSatObs* pppSatObs = *it;
667 if (pppSatObs->hasBiases()) {
668 ++it;
669 }
670 else {
671 it = obsVector.erase(it);
672 delete pppSatObs;
673 }
674 }
675}
Note: See TracBrowser for help on using the repository browser.