source: ntrip/trunk/BNC/src/PPP/pppSatObs.cpp@ 6035

Last change on this file since 6035 was 6035, checked in by mervart, 10 years ago
File size: 16.0 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_pppSatObs
30 *
31 * Purpose: Satellite observations
32 *
33 * Author: L. Mervart
34 *
35 * Created: 29-Jul-2014
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41
42#include <iostream>
43#include <cmath>
44#include <newmatio.h>
45
46#include "pppSatObs.h"
47#include "bncconst.h"
48#include "pppEphPool.h"
49#include "pppStation.h"
50#include "bncutils.h"
51#include "bncantex.h"
52#include "pppObsPool.h"
53#include "pppClient.h"
54
55using namespace BNC_PPP;
56using namespace std;
57
58// Constructor
59////////////////////////////////////////////////////////////////////////////
60t_pppSatObs::t_pppSatObs(const t_satObs& pppSatObs) {
61 _prn = pppSatObs._prn;
62 _time = pppSatObs._time;
63 _outlier = false;
64 _valid = true;
65 for (unsigned ii = 0; ii < t_frequency::max; ii++) {
66 _obs[ii] = 0;
67 }
68 prepareObs(pppSatObs);
69}
70
71// Destructor
72////////////////////////////////////////////////////////////////////////////
73t_pppSatObs::~t_pppSatObs() {
74 for (unsigned iFreq = 1; iFreq < t_frequency::max; iFreq++) {
75 delete _obs[iFreq];
76 }
77}
78
79//
80////////////////////////////////////////////////////////////////////////////
81void t_pppSatObs::prepareObs(const t_satObs& pppSatObs) {
82
83 _model.reset();
84
85 // Select pseudoranges and phase observations
86 // ------------------------------------------
87 const string preferredAttrib = "CWPX_";
88
89 for (unsigned iFreq = 1; iFreq < t_frequency::max; iFreq++) {
90 string frqNum = t_frequency::toString(t_frequency::type(iFreq)).substr(1);
91 for (unsigned iPref = 0; iPref < preferredAttrib.length(); iPref++) {
92 string obsType = (preferredAttrib[iPref] == '_') ? frqNum : frqNum + preferredAttrib[iPref];
93 if (_obs[iFreq] == 0) {
94 for (unsigned ii = 0; ii < pppSatObs._obs.size(); ii++) {
95 const t_frqObs* obs = pppSatObs._obs[ii];
96 if (obs->_rnxType2ch == obsType && obs->_codeValid && obs->_phaseValid) {
97 _obs[iFreq] = new t_frqObs(*obs);
98 }
99 }
100 }
101 }
102 }
103
104 // Used frequency types
105 // --------------------
106 _fType1 = t_lc::toFreq(_prn.system(),t_lc::l1);
107 if (_prn.system() == 'E') {
108 _fType2 = t_frequency::E5;
109 }
110 else {
111 _fType2 = t_lc::toFreq(_prn.system(),t_lc::l2);
112 }
113
114 // Check whether all required frequencies available
115 // ------------------------------------------------
116 for (unsigned ii = 0; ii < OPT->LCs(_prn.system()).size(); ii++) {
117 t_lc::type tLC = OPT->LCs(_prn.system())[ii];
118 if (!isValid(tLC)) {
119 _valid = false;
120 return;
121 }
122 }
123
124 // Find Glonass Channel Number
125 // ---------------------------
126 if (_prn.system() == 'R') {
127 _channel = PPP_CLIENT->ephPool()->getChannel(_prn);
128 }
129 else {
130 _channel = 0;
131 }
132
133 // Compute Satellite Coordinates at Time of Transmission
134 // -----------------------------------------------------
135 _xcSat.ReSize(4); _xcSat = 0.0;
136 _vvSat.ReSize(4); _vvSat = 0.0;
137 bool totOK = false;
138 ColumnVector satPosOld(4); satPosOld = 0.0;
139 t_lc::type tLC = isValid(t_lc::cIF) ? t_lc::cIF : t_lc::c1;
140 double prange = obsValue(tLC);
141 for (int ii = 1; ii <= 10; ii++) {
142 bncTime ToT = _time - prange / t_CST::c - _xcSat[3];
143 if (PPP_CLIENT->ephPool()->getCrd(_prn, ToT, _xcSat, _vvSat) != success) {
144 _valid = false;
145 return;
146 }
147 ColumnVector dx = _xcSat - satPosOld;
148 dx[3] *= t_CST::c;
149 if (dx.norm_Frobenius() < 1.e-4) {
150 totOK = true;
151 break;
152 }
153 satPosOld = _xcSat;
154 }
155 if (totOK) {
156 _model._satClkM = _xcSat[3] * t_CST::c;
157 }
158 else {
159 _valid = false;
160 }
161}
162
163//
164////////////////////////////////////////////////////////////////////////////
165void t_pppSatObs::lcCoeff(t_lc::type tLC,
166 map<t_frequency::type, double>& codeCoeff,
167 map<t_frequency::type, double>& phaseCoeff) const {
168
169 codeCoeff.clear();
170 phaseCoeff.clear();
171
172 double f1 = t_CST::freq(_fType1, _channel);
173 double f2 = t_CST::freq(_fType2, _channel);
174
175 switch (tLC) {
176 case t_lc::l1:
177 phaseCoeff[_fType1] = 1.0;
178 return;
179 case t_lc::l2:
180 phaseCoeff[_fType2] = 1.0;
181 return;
182 case t_lc::lIF:
183 phaseCoeff[_fType1] = f1 * f1 / (f1 * f1 - f2 * f2);
184 phaseCoeff[_fType2] = -f2 * f2 / (f1 * f1 - f2 * f2);
185 return;
186 case t_lc::MW:
187 phaseCoeff[_fType1] = f1 / (f1 - f2);
188 phaseCoeff[_fType2] = -f2 / (f1 - f2);
189 codeCoeff[_fType1] = -f1 / (f1 + f2);
190 codeCoeff[_fType2] = -f2 / (f1 + f2);
191 return;
192 case t_lc::CL:
193 phaseCoeff[_fType1] = 0.5;
194 codeCoeff[_fType1] = 0.5;
195 return;
196 case t_lc::c1:
197 codeCoeff[_fType1] = 1.0;
198 return;
199 case t_lc::c2:
200 codeCoeff[_fType2] = 1.0;
201 return;
202 case t_lc::cIF:
203 codeCoeff[_fType1] = f1 * f1 / (f1 * f1 - f2 * f2);
204 codeCoeff[_fType2] = -f2 * f2 / (f1 * f1 - f2 * f2);
205 return;
206 case t_lc::dummy:
207 case t_lc::maxLc:
208 return;
209 }
210}
211
212//
213////////////////////////////////////////////////////////////////////////////
214bool t_pppSatObs::isValid(t_lc::type tLC) const {
215 bool valid = true;
216 obsValue(tLC, &valid);
217 return valid;
218}
219//
220////////////////////////////////////////////////////////////////////////////
221double t_pppSatObs::obsValue(t_lc::type tLC, bool* valid) const {
222
223 map<t_frequency::type, double> codeCoeff;
224 map<t_frequency::type, double> phaseCoeff;
225 lcCoeff(tLC, codeCoeff, phaseCoeff);
226
227 double retVal = 0.0;
228 if (valid) *valid = true;
229
230 map<t_frequency::type, double>::const_iterator it;
231 for (it = codeCoeff.begin(); it != codeCoeff.end(); it++) {
232 t_frequency::type tFreq = it->first;
233 if (_obs[tFreq] == 0) {
234 if (valid) *valid = false;
235 return 0.0;
236 }
237 else {
238 retVal += it->second * _obs[tFreq]->_code;
239 }
240 }
241 for (it = phaseCoeff.begin(); it != phaseCoeff.end(); it++) {
242 t_frequency::type tFreq = it->first;
243 if (_obs[tFreq] == 0) {
244 if (valid) *valid = false;
245 return 0.0;
246 }
247 else {
248 retVal += it->second * _obs[tFreq]->_phase * t_CST::lambda(tFreq, _channel);
249 }
250 }
251
252 return retVal;
253}
254
255//
256////////////////////////////////////////////////////////////////////////////
257double t_pppSatObs::lambda(t_lc::type tLC) const {
258
259 double f1 = t_CST::freq(_fType1, _channel);
260 double f2 = t_CST::freq(_fType2, _channel);
261
262 if (tLC == t_lc::l1) {
263 return t_CST::c / f1;
264 }
265 else if (tLC == t_lc::l2) {
266 return t_CST::c / f2;
267 }
268 else if (tLC == t_lc::lIF) {
269 return t_CST::c / (f1 + f2);
270 }
271 else if (tLC == t_lc::MW) {
272 return t_CST::c / (f1 - f2);
273 }
274 else if (tLC == t_lc::CL) {
275 return t_CST::c / f1 / 2.0;
276 }
277
278 return 0.0;
279}
280
281//
282////////////////////////////////////////////////////////////////////////////
283double t_pppSatObs::sigma(t_lc::type tLC) const {
284
285 map<t_frequency::type, double> codeCoeff;
286 map<t_frequency::type, double> phaseCoeff;
287 lcCoeff(tLC, codeCoeff, phaseCoeff);
288
289 double retVal = 0.0;
290
291 map<t_frequency::type, double>::const_iterator it;
292 for (it = codeCoeff.begin(); it != codeCoeff.end(); it++) {
293 retVal += it->second * it->second * OPT->_sigmaC1 * OPT->_sigmaC1;
294 }
295 for (it = phaseCoeff.begin(); it != phaseCoeff.end(); it++) {
296 retVal += it->second * it->second * OPT->_sigmaL1 * OPT->_sigmaL1;
297 }
298
299 retVal = sqrt(retVal);
300
301 // Elevation-Dependent Weighting
302 // -----------------------------
303 double cEle = 1.0;
304 if ( (OPT->_eleWgtCode && t_lc::includesCode(tLC)) ||
305 (OPT->_eleWgtPhase && t_lc::includesPhase(tLC)) ) {
306 double eleD = eleSat()*180.0/M_PI;
307 double hlp = fabs(90.0 - eleD);
308 cEle = (1.0 + hlp*hlp*hlp*0.000004);
309 }
310
311 return cEle * retVal;
312}
313
314//
315////////////////////////////////////////////////////////////////////////////
316double t_pppSatObs::maxRes(t_lc::type tLC) const {
317
318 map<t_frequency::type, double> codeCoeff;
319 map<t_frequency::type, double> phaseCoeff;
320 lcCoeff(tLC, codeCoeff, phaseCoeff);
321
322 double retVal = 0.0;
323
324 map<t_frequency::type, double>::const_iterator it;
325 for (it = codeCoeff.begin(); it != codeCoeff.end(); it++) {
326 retVal += it->second * it->second * OPT->_maxResC1 * OPT->_maxResC1;
327 }
328 for (it = phaseCoeff.begin(); it != phaseCoeff.end(); it++) {
329 retVal += it->second * it->second * OPT->_maxResL1 * OPT->_maxResL1;
330 }
331
332 return sqrt(retVal);
333}
334
335
336//
337////////////////////////////////////////////////////////////////////////////
338t_irc t_pppSatObs::cmpModel(const t_pppStation* station) {
339
340 // Reset all model values
341 // ----------------------
342 _model.reset();
343
344 // Topocentric Satellite Position
345 // ------------------------------
346 ColumnVector rSat = _xcSat.Rows(1,3);
347 ColumnVector rhoV = rSat - station->xyzApr();
348 _model._rho = rhoV.norm_Frobenius();
349
350 ColumnVector neu(3);
351 xyz2neu(station->ellApr().data(), rhoV.data(), neu.data());
352
353 _model._eleSat = acos( sqrt(neu[0]*neu[0] + neu[1]*neu[1]) / _model._rho );
354 if (neu[2] < 0) {
355 _model._eleSat *= -1.0;
356 }
357 _model._azSat = atan2(neu[1], neu[0]);
358
359 // Satellite Clocks
360 // ----------------
361 _model._satClkM = _xcSat[3] * t_CST::c;
362
363 // Receiver Clocks
364 // ---------------
365 _model._recClkM = station->dClk() * t_CST::c;
366
367 // Sagnac Effect (correction due to Earth rotation)
368 // ------------------------------------------------
369 ColumnVector Omega(3);
370 Omega[0] = 0.0;
371 Omega[1] = 0.0;
372 Omega[2] = t_CST::omega / t_CST::c;
373 _model._sagnac = DotProduct(Omega, crossproduct(rSat, station->xyzApr()));
374
375 // Antenna Eccentricity
376 // --------------------
377 _model._antEcc = -DotProduct(station->xyzEcc(), rhoV) / _model._rho;
378
379 // Antenna Phase Center Offsets and Variations
380 // -------------------------------------------
381 if (PPP_CLIENT->antex()) {
382 bool found;
383 double pco = PPP_CLIENT->antex()->rcvCorr(station->antName(), _model._eleSat, found);
384 for (unsigned ii = 0; ii < t_frequency::max; ii++) {
385 _model._antPCO[ii] = pco;
386 }
387 }
388
389 // Tropospheric Delay
390 // ------------------
391 _model._tropo = t_tropo::delay_saast(station->xyzApr(), _model._eleSat);
392
393 // Phase Wind-Up
394 // -------------
395 _model._windUp = station->windUp(_time, _prn, rSat);
396
397 // Code and Phase Biases
398 // ---------------------
399 const t_satBias* satBias = PPP_CLIENT->obsPool()->satBias(_prn);
400 if (satBias) {
401 for (unsigned ii = 0; ii < satBias->_bias.size(); ii++) {
402 const t_frqBias& bias = satBias->_bias[ii];
403 for (unsigned iFreq = 1; iFreq < t_frequency::max; iFreq++) {
404 const t_frqObs* obs = _obs[iFreq];
405 if (obs && obs->_rnxType2ch == bias._rnxType2ch) {
406 _model._codeBias[iFreq] = bias._code;
407 _model._phaseBias[iFreq] = bias._phase;
408 }
409 }
410 }
411 }
412
413 // Tidal Correction
414 // ----------------
415 _model._tide = -DotProduct(station->tideDspl(), rhoV) / _model._rho;
416
417 // Ionospheric Delay
418 // -----------------
419 // TODO
420
421 // Ocean Loading
422 // -------------
423 // TODO
424
425 // Set Model Set Flag
426 // ------------------
427 _model._set = true;
428
429 return success;
430}
431
432//
433////////////////////////////////////////////////////////////////////////////
434void t_pppSatObs::printModel() const {
435 LOG.setf(ios::fixed);
436 LOG << "MODEL for Satellite " << _prn.toString() << endl
437 << "RHO: " << setw(12) << setprecision(3) << _model._rho << endl
438 << "ELE: " << setw(12) << setprecision(3) << _model._eleSat * 180.0 / M_PI << endl
439 << "AZI: " << setw(12) << setprecision(3) << _model._azSat * 180.0 / M_PI << endl
440 << "SATCLK: " << setw(12) << setprecision(3) << _model._satClkM << endl
441 << "RECCLK: " << setw(12) << setprecision(3) << _model._recClkM << endl
442 << "SAGNAC: " << setw(12) << setprecision(3) << _model._sagnac << endl
443 << "ANTECC: " << setw(12) << setprecision(3) << _model._antEcc << endl
444 << "TROPO: " << setw(12) << setprecision(3) << _model._tropo << endl
445 << "WINDUP: " << setw(12) << setprecision(3) << _model._windUp << endl
446 << "TIDES: " << setw(12) << setprecision(3) << _model._tide << endl;
447 for (unsigned iFreq = 1; iFreq < t_frequency::max; iFreq++) {
448 if (_obs[iFreq]) {
449 LOG << "PCO: " << t_frequency::toString(t_frequency::type(iFreq)) << setw(12) << setprecision(3) << _model._antPCO[iFreq] << endl
450 << "BIAS CODE: " << t_frequency::toString(t_frequency::type(iFreq)) << setw(12) << setprecision(3) << _model._codeBias[iFreq] << endl
451 << "BIAS PHASE: " << t_frequency::toString(t_frequency::type(iFreq)) << setw(12) << setprecision(3) << _model._phaseBias[iFreq] << endl;
452 }
453 }
454 LOG << "OBS-CMP P3: " << _prn.toString() << " "
455 << setw(12) << setprecision(3) << obsValue(t_lc::cIF) << " "
456 << setw(12) << setprecision(3) << cmpValue(t_lc::cIF) << " "
457 << setw(12) << setprecision(3) << obsValue(t_lc::cIF) - cmpValue(t_lc::cIF) << endl;
458
459 LOG << "OBS-CMP L3: " << _prn.toString() << " "
460 << setw(12) << setprecision(3) << obsValue(t_lc::lIF) << " "
461 << setw(12) << setprecision(3) << cmpValue(t_lc::lIF) << " "
462 << setw(12) << setprecision(3) << obsValue(t_lc::lIF) - cmpValue(t_lc::lIF) << endl;
463
464 LOG << "OBS-CMP MW: " << _prn.toString() << " "
465 << setw(12) << setprecision(3) << obsValue(t_lc::MW) << " "
466 << setw(12) << setprecision(3) << cmpValue(t_lc::MW) << " "
467 << setw(12) << setprecision(3) << obsValue(t_lc::MW) - cmpValue(t_lc::MW) << endl;
468}
469
470//
471////////////////////////////////////////////////////////////////////////////
472double t_pppSatObs::cmpValueForBanc(t_lc::type tLC) const {
473 return cmpValue(tLC) - _model._rho - _model._sagnac - _model._recClkM;
474}
475
476//
477////////////////////////////////////////////////////////////////////////////
478double t_pppSatObs::cmpValue(t_lc::type tLC) const {
479
480 if (!isValid(tLC)) {
481 return 0.0;
482 }
483
484 // Non-Dispersive Part
485 // -------------------
486 double nonDisp = _model._rho + _model._recClkM - _model._satClkM
487 + _model._sagnac + _model._antEcc + _model._tropo
488 + _model._tide;
489
490 // Add Dispersive Part
491 // -------------------
492 map<t_frequency::type, double> codeCoeff;
493 map<t_frequency::type, double> phaseCoeff;
494 lcCoeff(tLC, codeCoeff, phaseCoeff);
495
496 double dispPart = 0.0;
497
498 map<t_frequency::type, double>::const_iterator it;
499 for (it = codeCoeff.begin(); it != codeCoeff.end(); it++) {
500 t_frequency::type tFreq = it->first;
501 dispPart += it->second * (_model._antPCO[tFreq] + _model._codeBias[tFreq]);
502 }
503 for (it = phaseCoeff.begin(); it != phaseCoeff.end(); it++) {
504 t_frequency::type tFreq = it->first;
505 dispPart += it->second * (_model._antPCO[tFreq] + _model._phaseBias[tFreq] +
506 _model._windUp * t_CST::lambda(tFreq, _channel));
507 }
508
509 return nonDisp + dispPart;
510}
511
512//
513////////////////////////////////////////////////////////////////////////////
514void t_pppSatObs::setRes(t_lc::type tLC, double res) {
515 _res[tLC] = res;
516}
517
518//
519////////////////////////////////////////////////////////////////////////////
520double t_pppSatObs::getRes(t_lc::type tLC) const {
521 map<t_lc::type, double>::const_iterator it = _res.find(tLC);
522 if (it != _res.end()) {
523 return it->second;
524 }
525 else {
526 return 0.0;
527 }
528}
Note: See TracBrowser for help on using the repository browser.