source: ntrip/trunk/BNC/src/ephemeris.cpp@ 7298

Last change on this file since 7298 was 7278, checked in by stuerze, 9 years ago

some memory leaks fixed

File size: 44.8 KB
RevLine 
[1025]1#include <sstream>
[2234]2#include <iostream>
[1025]3#include <iomanip>
[1239]4#include <cstring>
[1025]5
[2234]6#include <newmatio.h>
7
[1025]8#include "ephemeris.h"
[2221]9#include "bncutils.h"
[2285]10#include "bnctime.h"
[5070]11#include "bnccore.h"
[5839]12#include "bncutils.h"
[6141]13#include "satObs.h"
[6044]14#include "pppInclude.h"
[6400]15#include "pppModel.h"
[1025]16
17using namespace std;
18
[5749]19// Constructor
20////////////////////////////////////////////////////////////////////////////
21t_eph::t_eph() {
[6518]22 _checkState = unchecked;
23 _orbCorr = 0;
24 _clkCorr = 0;
[5749]25}
[7278]26// Destructor
27////////////////////////////////////////////////////////////////////////////
28t_eph::~t_eph() {
29 if (_orbCorr)
30 delete _orbCorr;
31 if (_clkCorr)
32 delete _clkCorr;
33}
[5749]34
35//
36////////////////////////////////////////////////////////////////////////////
[6141]37void t_eph::setOrbCorr(const t_orbCorr* orbCorr) {
[5749]38 delete _orbCorr;
[6141]39 _orbCorr = new t_orbCorr(*orbCorr);
[5749]40}
41
42//
43////////////////////////////////////////////////////////////////////////////
[6141]44void t_eph::setClkCorr(const t_clkCorr* clkCorr) {
[5749]45 delete _clkCorr;
[6141]46 _clkCorr = new t_clkCorr(*clkCorr);
[5749]47}
48
49//
50////////////////////////////////////////////////////////////////////////////
[6109]51t_irc t_eph::getCrd(const bncTime& tt, ColumnVector& xc, ColumnVector& vv, bool useCorr) const {
[6518]52
53 if (_checkState == bad) {
54 return failure;
55 }
[6556]56 const QVector<int> updateInt = QVector<int>() << 1 << 2 << 5 << 10 << 15 << 30
57 << 60 << 120 << 240 << 300 << 600
58 << 900 << 1800 << 3600 << 7200
59 << 10800;
[5749]60 xc.ReSize(4);
61 vv.ReSize(3);
[6213]62 if (position(tt.gpsw(), tt.gpssec(), xc.data(), vv.data()) != success) {
63 return failure;
64 }
[5789]65 if (useCorr) {
[5839]66 if (_orbCorr && _clkCorr) {
[5849]67 double dtO = tt - _orbCorr->_time;
[6556]68 if (_orbCorr->_updateInt) {
69 dtO -= (0.5 * updateInt[_orbCorr->_updateInt]);
70 }
[5839]71 ColumnVector dx(3);
[5849]72 dx[0] = _orbCorr->_xr[0] + _orbCorr->_dotXr[0] * dtO;
73 dx[1] = _orbCorr->_xr[1] + _orbCorr->_dotXr[1] * dtO;
74 dx[2] = _orbCorr->_xr[2] + _orbCorr->_dotXr[2] * dtO;
75
[7133]76 RSW_to_XYZ(xc.Rows(1,3), vv.Rows(1,3), dx, dx);
[5849]77
[5839]78 xc[0] -= dx[0];
79 xc[1] -= dx[1];
80 xc[2] -= dx[2];
[5849]81
[7133]82 ColumnVector dv(3);
83 RSW_to_XYZ(xc.Rows(1,3), vv.Rows(1,3), _orbCorr->_dotXr, dv);
84
85 vv[0] -= dv[0];
86 vv[1] -= dv[1];
87 vv[2] -= dv[2];
88
[5849]89 double dtC = tt - _clkCorr->_time;
[6556]90 if (_clkCorr->_updateInt) {
91 dtC -= (0.5 * updateInt[_clkCorr->_updateInt]);
92 }
[7014]93 xc[3] += _clkCorr->_dClk + _clkCorr->_dotDClk * dtC + _clkCorr->_dotDotDClk * dtC * dtC;
[5839]94 }
95 else {
96 return failure;
97 }
[5749]98 }
99 return success;
100}
101
[6801]102//
103//////////////////////////////////////////////////////////////////////////////
104QString t_eph::rinexDateStr(const bncTime& tt, const t_prn& prn, double version) {
105 QString prnStr(prn.toString().c_str());
106 return rinexDateStr(tt, prnStr, version);
107}
108
109//
110//////////////////////////////////////////////////////////////////////////////
111QString t_eph::rinexDateStr(const bncTime& tt, const QString& prnStr, double version) {
112
113 QString datStr;
114
115 unsigned year, month, day, hour, min;
116 double sec;
117 tt.civil_date(year, month, day);
118 tt.civil_time(hour, min, sec);
119
120 QTextStream out(&datStr);
121
122 if (version < 3.0) {
123 QString prnHlp = prnStr.mid(1,2); if (prnHlp[0] == '0') prnHlp[0] = ' ';
124 out << prnHlp << QString(" %1 %2 %3 %4 %5%6")
125 .arg(year % 100, 2, 10, QChar('0'))
126 .arg(month, 2)
127 .arg(day, 2)
128 .arg(hour, 2)
129 .arg(min, 2)
130 .arg(sec, 5, 'f',1);
131 }
132 else {
133 out << prnStr << QString(" %1 %2 %3 %4 %5 %6")
134 .arg(year, 4)
135 .arg(month, 2, 10, QChar('0'))
136 .arg(day, 2, 10, QChar('0'))
137 .arg(hour, 2, 10, QChar('0'))
138 .arg(min, 2, 10, QChar('0'))
139 .arg(int(sec), 2, 10, QChar('0'));
140 }
141
142 return datStr;
143}
144
145// Constructor
146//////////////////////////////////////////////////////////////////////////////
147t_ephGPS::t_ephGPS(float rnxVersion, const QStringList& lines) {
148
149 const int nLines = 8;
150
151 if (lines.size() != nLines) {
152 _checkState = bad;
153 return;
154 }
155
156 // RINEX Format
157 // ------------
158 int fieldLen = 19;
159
160 int pos[4];
161 pos[0] = (rnxVersion <= 2.12) ? 3 : 4;
162 pos[1] = pos[0] + fieldLen;
163 pos[2] = pos[1] + fieldLen;
164 pos[3] = pos[2] + fieldLen;
165
166 // Read eight lines
167 // ----------------
168 for (int iLine = 0; iLine < nLines; iLine++) {
169 QString line = lines[iLine];
170
171 if ( iLine == 0 ) {
172 QTextStream in(line.left(pos[1]).toAscii());
173 int year, month, day, hour, min;
174 double sec;
175
[7139]176 QString prnStr, n;
[6880]177 in >> prnStr;
178 if (prnStr.size() == 1) {
[7139]179 in >> n;
180 prnStr.append(n);
[6880]181 }
182 in >> year >> month >> day >> hour >> min >> sec;
[6801]183 if (prnStr.at(0) == 'G') {
184 _prn.set('G', prnStr.mid(1).toInt());
185 }
186 else if (prnStr.at(0) == 'J') {
187 _prn.set('J', prnStr.mid(1).toInt());
188 }
189 else {
190 _prn.set('G', prnStr.toInt());
191 }
192
193 if (year < 80) {
194 year += 2000;
195 }
196 else if (year < 100) {
197 year += 1900;
198 }
199
200 _TOC.set(year, month, day, hour, min, sec);
201
202 if ( readDbl(line, pos[1], fieldLen, _clock_bias ) ||
203 readDbl(line, pos[2], fieldLen, _clock_drift ) ||
204 readDbl(line, pos[3], fieldLen, _clock_driftrate) ) {
205 _checkState = bad;
206 return;
207 }
208 }
209
210 else if ( iLine == 1 ) {
211 if ( readDbl(line, pos[0], fieldLen, _IODE ) ||
212 readDbl(line, pos[1], fieldLen, _Crs ) ||
213 readDbl(line, pos[2], fieldLen, _Delta_n) ||
214 readDbl(line, pos[3], fieldLen, _M0 ) ) {
215 _checkState = bad;
216 return;
217 }
218 }
219
220 else if ( iLine == 2 ) {
221 if ( readDbl(line, pos[0], fieldLen, _Cuc ) ||
222 readDbl(line, pos[1], fieldLen, _e ) ||
223 readDbl(line, pos[2], fieldLen, _Cus ) ||
224 readDbl(line, pos[3], fieldLen, _sqrt_A) ) {
225 _checkState = bad;
226 return;
227 }
228 }
229
230 else if ( iLine == 3 ) {
231 if ( readDbl(line, pos[0], fieldLen, _TOEsec) ||
232 readDbl(line, pos[1], fieldLen, _Cic ) ||
233 readDbl(line, pos[2], fieldLen, _OMEGA0) ||
234 readDbl(line, pos[3], fieldLen, _Cis ) ) {
235 _checkState = bad;
236 return;
237 }
238 }
239
240 else if ( iLine == 4 ) {
241 if ( readDbl(line, pos[0], fieldLen, _i0 ) ||
242 readDbl(line, pos[1], fieldLen, _Crc ) ||
243 readDbl(line, pos[2], fieldLen, _omega ) ||
244 readDbl(line, pos[3], fieldLen, _OMEGADOT) ) {
245 _checkState = bad;
246 return;
247 }
248 }
249
250 else if ( iLine == 5 ) {
251 if ( readDbl(line, pos[0], fieldLen, _IDOT ) ||
252 readDbl(line, pos[1], fieldLen, _L2Codes) ||
253 readDbl(line, pos[2], fieldLen, _TOEweek ) ||
254 readDbl(line, pos[3], fieldLen, _L2PFlag) ) {
255 _checkState = bad;
256 return;
257 }
258 }
259
260 else if ( iLine == 6 ) {
261 if ( readDbl(line, pos[0], fieldLen, _ura ) ||
262 readDbl(line, pos[1], fieldLen, _health) ||
263 readDbl(line, pos[2], fieldLen, _TGD ) ||
264 readDbl(line, pos[3], fieldLen, _IODC ) ) {
265 _checkState = bad;
266 return;
267 }
268 }
269
270 else if ( iLine == 7 ) {
271 if ( readDbl(line, pos[0], fieldLen, _TOT) ) {
272 _checkState = bad;
273 return;
274 }
275 readDbl(line, pos[1], fieldLen, _fitInterval); // _fitInterval optional
276 }
277 }
278}
279
[2222]280// Compute GPS Satellite Position (virtual)
[1025]281////////////////////////////////////////////////////////////////////////////
[6213]282t_irc t_ephGPS::position(int GPSweek, double GPSweeks, double* xc, double* vv) const {
[1025]283
[6518]284 if (_checkState == bad) {
285 return failure;
286 }
287
[1098]288 static const double omegaEarth = 7292115.1467e-11;
[5277]289 static const double gmGRS = 398.6005e12;
[1025]290
291 memset(xc, 0, 4*sizeof(double));
292 memset(vv, 0, 3*sizeof(double));
293
294 double a0 = _sqrt_A * _sqrt_A;
295 if (a0 == 0) {
[6213]296 return failure;
[1025]297 }
298
[5277]299 double n0 = sqrt(gmGRS/(a0*a0*a0));
[4018]300
301 bncTime tt(GPSweek, GPSweeks);
[4543]302 double tk = tt - bncTime(int(_TOEweek), _TOEsec);
[4018]303
[1025]304 double n = n0 + _Delta_n;
305 double M = _M0 + n*tk;
306 double E = M;
307 double E_last;
308 do {
309 E_last = E;
310 E = M + _e*sin(E);
311 } while ( fabs(E-E_last)*a0 > 0.001 );
312 double v = 2.0*atan( sqrt( (1.0 + _e)/(1.0 - _e) )*tan( E/2 ) );
313 double u0 = v + _omega;
314 double sin2u0 = sin(2*u0);
315 double cos2u0 = cos(2*u0);
316 double r = a0*(1 - _e*cos(E)) + _Crc*cos2u0 + _Crs*sin2u0;
317 double i = _i0 + _IDOT*tk + _Cic*cos2u0 + _Cis*sin2u0;
318 double u = u0 + _Cuc*cos2u0 + _Cus*sin2u0;
319 double xp = r*cos(u);
320 double yp = r*sin(u);
321 double OM = _OMEGA0 + (_OMEGADOT - omegaEarth)*tk -
[4018]322 omegaEarth*_TOEsec;
[7278]323
[1025]324 double sinom = sin(OM);
325 double cosom = cos(OM);
326 double sini = sin(i);
327 double cosi = cos(i);
328 xc[0] = xp*cosom - yp*cosi*sinom;
329 xc[1] = xp*sinom + yp*cosi*cosom;
[7278]330 xc[2] = yp*sini;
[1025]331
[4018]332 double tc = tt - _TOC;
[2429]333 xc[3] = _clock_bias + _clock_drift*tc + _clock_driftrate*tc*tc;
[1025]334
335 // Velocity
336 // --------
337 double tanv2 = tan(v/2);
338 double dEdM = 1 / (1 - _e*cos(E));
[7278]339 double dotv = sqrt((1.0 + _e)/(1.0 - _e)) / cos(E/2)/cos(E/2) / (1 + tanv2*tanv2)
[1025]340 * dEdM * n;
341 double dotu = dotv + (-_Cuc*sin2u0 + _Cus*cos2u0)*2*dotv;
342 double dotom = _OMEGADOT - omegaEarth;
343 double doti = _IDOT + (-_Cic*sin2u0 + _Cis*cos2u0)*2*dotv;
[7278]344 double dotr = a0 * _e*sin(E) * dEdM * n
[1025]345 + (-_Crc*sin2u0 + _Crs*cos2u0)*2*dotv;
346 double dotx = dotr*cos(u) - r*sin(u)*dotu;
347 double doty = dotr*sin(u) + r*cos(u)*dotu;
348
349 vv[0] = cosom *dotx - cosi*sinom *doty // dX / dr
350 - xp*sinom*dotom - yp*cosi*cosom*dotom // dX / dOMEGA
351 + yp*sini*sinom*doti; // dX / di
352
353 vv[1] = sinom *dotx + cosi*cosom *doty
354 + xp*cosom*dotom - yp*cosi*sinom*dotom
355 - yp*sini*cosom*doti;
356
357 vv[2] = sini *doty + yp*cosi *doti;
[2429]358
359 // Relativistic Correction
360 // -----------------------
361 xc[3] -= 2.0 * (xc[0]*vv[0] + xc[1]*vv[1] + xc[2]*vv[2]) / t_CST::c / t_CST::c;
[6213]362
363 return success;
[1025]364}
365
[6801]366// RINEX Format String
367//////////////////////////////////////////////////////////////////////////////
368QString t_ephGPS::toString(double version) const {
[2221]369
[6801]370 QString rnxStr = rinexDateStr(_TOC, _prn, version);
[2221]371
[6801]372 QTextStream out(&rnxStr);
[2221]373
[6801]374 out << QString("%1%2%3\n")
375 .arg(_clock_bias, 19, 'e', 12)
376 .arg(_clock_drift, 19, 'e', 12)
377 .arg(_clock_driftrate, 19, 'e', 12);
[2221]378
[6801]379 QString fmt = version < 3.0 ? " %1%2%3%4\n" : " %1%2%3%4\n";
[2221]380
[6801]381 out << QString(fmt)
382 .arg(_IODE, 19, 'e', 12)
383 .arg(_Crs, 19, 'e', 12)
384 .arg(_Delta_n, 19, 'e', 12)
385 .arg(_M0, 19, 'e', 12);
386
387 out << QString(fmt)
388 .arg(_Cuc, 19, 'e', 12)
389 .arg(_e, 19, 'e', 12)
390 .arg(_Cus, 19, 'e', 12)
391 .arg(_sqrt_A, 19, 'e', 12);
392
393 out << QString(fmt)
394 .arg(_TOEsec, 19, 'e', 12)
395 .arg(_Cic, 19, 'e', 12)
396 .arg(_OMEGA0, 19, 'e', 12)
397 .arg(_Cis, 19, 'e', 12);
398
399 out << QString(fmt)
400 .arg(_i0, 19, 'e', 12)
401 .arg(_Crc, 19, 'e', 12)
402 .arg(_omega, 19, 'e', 12)
403 .arg(_OMEGADOT, 19, 'e', 12);
404
405 out << QString(fmt)
406 .arg(_IDOT, 19, 'e', 12)
407 .arg(_L2Codes, 19, 'e', 12)
408 .arg(_TOEweek, 19, 'e', 12)
409 .arg(_L2PFlag, 19, 'e', 12);
410
411 out << QString(fmt)
412 .arg(_ura, 19, 'e', 12)
413 .arg(_health, 19, 'e', 12)
414 .arg(_TGD, 19, 'e', 12)
415 .arg(_IODC, 19, 'e', 12);
416
417 out << QString(fmt)
418 .arg(_TOT, 19, 'e', 12)
419 .arg(_fitInterval, 19, 'e', 12)
420 .arg("", 19, QChar(' '))
421 .arg("", 19, QChar(' '));
422
423 return rnxStr;
[2221]424}
425
[6801]426// Constructor
427//////////////////////////////////////////////////////////////////////////////
428t_ephGlo::t_ephGlo(float rnxVersion, const QStringList& lines) {
[2221]429
[6801]430 const int nLines = 4;
431
432 if (lines.size() != nLines) {
433 _checkState = bad;
434 return;
[6518]435 }
436
[6801]437 // RINEX Format
438 // ------------
439 int fieldLen = 19;
[2221]440
[6801]441 int pos[4];
442 pos[0] = (rnxVersion <= 2.12) ? 3 : 4;
443 pos[1] = pos[0] + fieldLen;
444 pos[2] = pos[1] + fieldLen;
445 pos[3] = pos[2] + fieldLen;
[2221]446
[6801]447 // Read four lines
448 // ---------------
449 for (int iLine = 0; iLine < nLines; iLine++) {
450 QString line = lines[iLine];
[2221]451
[6801]452 if ( iLine == 0 ) {
453 QTextStream in(line.left(pos[1]).toAscii());
[6213]454
[6801]455 int year, month, day, hour, min;
456 double sec;
[2221]457
[7139]458 QString prnStr, n;
[6880]459 in >> prnStr;
460 if (prnStr.size() == 1) {
[7139]461 in >> n;
462 prnStr.append(n);
[6880]463 }
464 in >> year >> month >> day >> hour >> min >> sec;
[6801]465 if (prnStr.at(0) == 'R') {
466 _prn.set('R', prnStr.mid(1).toInt());
467 }
468 else {
469 _prn.set('R', prnStr.toInt());
470 }
[2221]471
[6801]472 if (year < 80) {
473 year += 2000;
474 }
475 else if (year < 100) {
476 year += 1900;
477 }
[2221]478
[6801]479 _gps_utc = gnumleap(year, month, day);
[2221]480
[6801]481 _TOC.set(year, month, day, hour, min, sec);
482 _TOC = _TOC + _gps_utc;
[6213]483
[6801]484 if ( readDbl(line, pos[1], fieldLen, _tau ) ||
485 readDbl(line, pos[2], fieldLen, _gamma) ||
486 readDbl(line, pos[3], fieldLen, _tki ) ) {
487 _checkState = bad;
488 return;
489 }
[2221]490
[6801]491 _tau = -_tau;
492 }
493
494 else if ( iLine == 1 ) {
495 if ( readDbl(line, pos[0], fieldLen, _x_pos ) ||
496 readDbl(line, pos[1], fieldLen, _x_velocity ) ||
497 readDbl(line, pos[2], fieldLen, _x_acceleration) ||
498 readDbl(line, pos[3], fieldLen, _health ) ) {
499 _checkState = bad;
500 return;
501 }
502 }
503
504 else if ( iLine == 2 ) {
505 if ( readDbl(line, pos[0], fieldLen, _y_pos ) ||
506 readDbl(line, pos[1], fieldLen, _y_velocity ) ||
507 readDbl(line, pos[2], fieldLen, _y_acceleration ) ||
508 readDbl(line, pos[3], fieldLen, _frequency_number) ) {
509 _checkState = bad;
510 return;
511 }
512 }
513
514 else if ( iLine == 3 ) {
515 if ( readDbl(line, pos[0], fieldLen, _z_pos ) ||
516 readDbl(line, pos[1], fieldLen, _z_velocity ) ||
517 readDbl(line, pos[2], fieldLen, _z_acceleration) ||
518 readDbl(line, pos[3], fieldLen, _E ) ) {
519 _checkState = bad;
520 return;
521 }
522 }
523 }
524
525 // Initialize status vector
526 // ------------------------
527 _tt = _TOC;
528 _xv.ReSize(6);
529 _xv(1) = _x_pos * 1.e3;
530 _xv(2) = _y_pos * 1.e3;
531 _xv(3) = _z_pos * 1.e3;
532 _xv(4) = _x_velocity * 1.e3;
533 _xv(5) = _y_velocity * 1.e3;
534 _xv(6) = _z_velocity * 1.e3;
[2221]535}
536
[6801]537// Compute Glonass Satellite Position (virtual)
[2771]538////////////////////////////////////////////////////////////////////////////
[6801]539t_irc t_ephGlo::position(int GPSweek, double GPSweeks, double* xc, double* vv) const {
[2771]540
[6518]541 if (_checkState == bad) {
542 return failure;
543 }
544
[6801]545 static const double nominalStep = 10.0;
[2771]546
547 memset(xc, 0, 4*sizeof(double));
548 memset(vv, 0, 3*sizeof(double));
549
[6801]550 double dtPos = bncTime(GPSweek, GPSweeks) - _tt;
551
552 if (fabs(dtPos) > 24*3600.0) {
[6213]553 return failure;
[2771]554 }
555
[6801]556 int nSteps = int(fabs(dtPos) / nominalStep) + 1;
557 double step = dtPos / nSteps;
[4018]558
[6801]559 double acc[3];
560 acc[0] = _x_acceleration * 1.e3;
561 acc[1] = _y_acceleration * 1.e3;
562 acc[2] = _z_acceleration * 1.e3;
563 for (int ii = 1; ii <= nSteps; ii++) {
564 _xv = rungeKutta4(_tt.gpssec(), _xv, step, acc, glo_deriv);
565 _tt = _tt + step;
566 }
[4018]567
[6801]568 // Position and Velocity
569 // ---------------------
570 xc[0] = _xv(1);
571 xc[1] = _xv(2);
572 xc[2] = _xv(3);
[2771]573
[6801]574 vv[0] = _xv(4);
575 vv[1] = _xv(5);
576 vv[2] = _xv(6);
[2771]577
[6801]578 // Clock Correction
579 // ----------------
580 double dtClk = bncTime(GPSweek, GPSweeks) - _TOC;
581 xc[3] = -_tau + _gamma * dtClk;
[2771]582
[6213]583 return success;
[2771]584}
585
[6801]586// RINEX Format String
[3659]587//////////////////////////////////////////////////////////////////////////////
[6801]588QString t_ephGlo::toString(double version) const {
[3664]589
[6801]590 QString rnxStr = rinexDateStr(_TOC-_gps_utc, _prn, version);
[3699]591
[6801]592 QTextStream out(&rnxStr);
[3664]593
[6801]594 out << QString("%1%2%3\n")
595 .arg(-_tau, 19, 'e', 12)
596 .arg(_gamma, 19, 'e', 12)
597 .arg(_tki, 19, 'e', 12);
[3668]598
[6801]599 QString fmt = version < 3.0 ? " %1%2%3%4\n" : " %1%2%3%4\n";
[3664]600
[6801]601 out << QString(fmt)
602 .arg(_x_pos, 19, 'e', 12)
603 .arg(_x_velocity, 19, 'e', 12)
604 .arg(_x_acceleration, 19, 'e', 12)
605 .arg(_health, 19, 'e', 12);
[3664]606
[6801]607 out << QString(fmt)
608 .arg(_y_pos, 19, 'e', 12)
609 .arg(_y_velocity, 19, 'e', 12)
610 .arg(_y_acceleration, 19, 'e', 12)
611 .arg(_frequency_number, 19, 'e', 12);
[3666]612
[6801]613 out << QString(fmt)
614 .arg(_z_pos, 19, 'e', 12)
615 .arg(_z_velocity, 19, 'e', 12)
616 .arg(_z_acceleration, 19, 'e', 12)
617 .arg(_E, 19, 'e', 12);
[3666]618
[6801]619 return rnxStr;
[3659]620}
621
[6801]622// Derivative of the state vector using a simple force model (static)
623////////////////////////////////////////////////////////////////////////////
624ColumnVector t_ephGlo::glo_deriv(double /* tt */, const ColumnVector& xv,
625 double* acc) {
[3659]626
[6801]627 // State vector components
628 // -----------------------
629 ColumnVector rr = xv.rows(1,3);
630 ColumnVector vv = xv.rows(4,6);
[3699]631
[6801]632 // Acceleration
[3699]633 // ------------
[6801]634 static const double gmWGS = 398.60044e12;
635 static const double AE = 6378136.0;
636 static const double OMEGA = 7292115.e-11;
637 static const double C20 = -1082.6257e-6;
[3699]638
[6801]639 double rho = rr.norm_Frobenius();
640 double t1 = -gmWGS/(rho*rho*rho);
641 double t2 = 3.0/2.0 * C20 * (gmWGS*AE*AE) / (rho*rho*rho*rho*rho);
642 double t3 = OMEGA * OMEGA;
643 double t4 = 2.0 * OMEGA;
644 double z2 = rr(3) * rr(3);
[3699]645
[6801]646 // Vector of derivatives
647 // ---------------------
648 ColumnVector va(6);
649 va(1) = vv(1);
650 va(2) = vv(2);
651 va(3) = vv(3);
652 va(4) = (t1 + t2*(1.0-5.0*z2/(rho*rho)) + t3) * rr(1) + t4*vv(2) + acc[0];
653 va(5) = (t1 + t2*(1.0-5.0*z2/(rho*rho)) + t3) * rr(2) - t4*vv(1) + acc[1];
654 va(6) = (t1 + t2*(3.0-5.0*z2/(rho*rho)) ) * rr(3) + acc[2];
[3699]655
[6801]656 return va;
657}
[3699]658
[6801]659// IOD of Glonass Ephemeris (virtual)
660////////////////////////////////////////////////////////////////////////////
[7169]661unsigned int t_ephGlo::IOD() const {
[6801]662 bncTime tMoscow = _TOC - _gps_utc + 3 * 3600.0;
[7054]663 return (unsigned long)tMoscow.daysec() / 900;
[3659]664}
665
666// Constructor
667//////////////////////////////////////////////////////////////////////////////
[4891]668t_ephGal::t_ephGal(float rnxVersion, const QStringList& lines) {
[6809]669 int year, month, day, hour, min;
670 double sec;
671 QString prnStr;
[4891]672 const int nLines = 8;
673 if (lines.size() != nLines) {
[6518]674 _checkState = bad;
[4891]675 return;
676 }
677
678 // RINEX Format
679 // ------------
680 int fieldLen = 19;
[6792]681 double SVhealth = 0.0;
682 double datasource = 0.0;
[6798]683
[4891]684 int pos[4];
685 pos[0] = (rnxVersion <= 2.12) ? 3 : 4;
686 pos[1] = pos[0] + fieldLen;
687 pos[2] = pos[1] + fieldLen;
688 pos[3] = pos[2] + fieldLen;
689
690 // Read eight lines
691 // ----------------
692 for (int iLine = 0; iLine < nLines; iLine++) {
693 QString line = lines[iLine];
694
695 if ( iLine == 0 ) {
696 QTextStream in(line.left(pos[1]).toAscii());
[7140]697 QString n;
[6880]698 in >> prnStr;
699 if (prnStr.size() == 1) {
[7139]700 in >> n;
701 prnStr.append(n);
[6880]702 }
703 in >> year >> month >> day >> hour >> min >> sec;
[4891]704 if (year < 80) {
705 year += 2000;
706 }
707 else if (year < 100) {
708 year += 1900;
709 }
710
711 _TOC.set(year, month, day, hour, min, sec);
712
713 if ( readDbl(line, pos[1], fieldLen, _clock_bias ) ||
714 readDbl(line, pos[2], fieldLen, _clock_drift ) ||
715 readDbl(line, pos[3], fieldLen, _clock_driftrate) ) {
[6518]716 _checkState = bad;
[4891]717 return;
718 }
719 }
720
721 else if ( iLine == 1 ) {
722 if ( readDbl(line, pos[0], fieldLen, _IODnav ) ||
723 readDbl(line, pos[1], fieldLen, _Crs ) ||
724 readDbl(line, pos[2], fieldLen, _Delta_n) ||
725 readDbl(line, pos[3], fieldLen, _M0 ) ) {
[6518]726 _checkState = bad;
[4891]727 return;
728 }
729 }
730
731 else if ( iLine == 2 ) {
732 if ( readDbl(line, pos[0], fieldLen, _Cuc ) ||
733 readDbl(line, pos[1], fieldLen, _e ) ||
734 readDbl(line, pos[2], fieldLen, _Cus ) ||
735 readDbl(line, pos[3], fieldLen, _sqrt_A) ) {
[6518]736 _checkState = bad;
[4891]737 return;
738 }
739 }
740
741 else if ( iLine == 3 ) {
742 if ( readDbl(line, pos[0], fieldLen, _TOEsec) ||
743 readDbl(line, pos[1], fieldLen, _Cic ) ||
744 readDbl(line, pos[2], fieldLen, _OMEGA0) ||
745 readDbl(line, pos[3], fieldLen, _Cis ) ) {
[6518]746 _checkState = bad;
[4891]747 return;
748 }
749 }
750
751 else if ( iLine == 4 ) {
752 if ( readDbl(line, pos[0], fieldLen, _i0 ) ||
753 readDbl(line, pos[1], fieldLen, _Crc ) ||
754 readDbl(line, pos[2], fieldLen, _omega ) ||
755 readDbl(line, pos[3], fieldLen, _OMEGADOT) ) {
[6518]756 _checkState = bad;
[4891]757 return;
758 }
759 }
760
761 else if ( iLine == 5 ) {
[6792]762 if ( readDbl(line, pos[0], fieldLen, _IDOT ) ||
763 readDbl(line, pos[1], fieldLen, datasource) ||
764 readDbl(line, pos[2], fieldLen, _TOEweek ) ) {
[6518]765 _checkState = bad;
[4891]766 return;
[6792]767 } else {
768 if (int(datasource) & (1<<8)) {
[6812]769 _fnav = true;
770 _inav = false;
[6792]771 } else if (int(datasource) & (1<<9)) {
[6812]772 _fnav = false;
773 _inav = true;
[6792]774 }
[6892]775 _TOEweek -= 1024.0;
[4891]776 }
777 }
778
779 else if ( iLine == 6 ) {
780 if ( readDbl(line, pos[0], fieldLen, _SISA ) ||
[6792]781 readDbl(line, pos[1], fieldLen, SVhealth) ||
[4891]782 readDbl(line, pos[2], fieldLen, _BGD_1_5A) ||
783 readDbl(line, pos[3], fieldLen, _BGD_1_5B) ) {
[6518]784 _checkState = bad;
[4891]785 return;
[6792]786 } else {
787 // Bit 0
[6812]788 _e1DataInValid = (int(SVhealth) & (1<<0));
[6792]789 // Bit 1-2
[6802]790 _E1_bHS = double((int(SVhealth) >> 1) & 0x3);
[6792]791 // Bit 3
[6812]792 _e5aDataInValid = (int(SVhealth) & (1<<3));
[6792]793 // Bit 4-5
[6802]794 _E5aHS = double((int(SVhealth) >> 4) & 0x3);
[6792]795 // Bit 6
[6812]796 _e5bDataInValid = (int(SVhealth) & (1<<6));
[6792]797 // Bit 7-8
[6802]798 _E5bHS = double((int(SVhealth) >> 7) & 0x3);
[6809]799
800 if (prnStr.at(0) == 'E') {
[7140]801 _prn.set('E', prnStr.mid(1).toInt(), _inav ? 1 : 0);
[6809]802 }
[4891]803 }
804 }
805
806 else if ( iLine == 7 ) {
807 if ( readDbl(line, pos[0], fieldLen, _TOT) ) {
[6518]808 _checkState = bad;
[4891]809 return;
810 }
811 }
812 }
[3659]813}
[4013]814
[6801]815// Compute Galileo Satellite Position (virtual)
816////////////////////////////////////////////////////////////////////////////
817t_irc t_ephGal::position(int GPSweek, double GPSweeks, double* xc, double* vv) const {
[4013]818
[6801]819 if (_checkState == bad) {
820 return failure;
821 }
[4013]822
[6801]823 static const double omegaEarth = 7292115.1467e-11;
824 static const double gmWGS = 398.60044e12;
[4023]825
[6801]826 memset(xc, 0, 4*sizeof(double));
827 memset(vv, 0, 3*sizeof(double));
[4023]828
[6801]829 double a0 = _sqrt_A * _sqrt_A;
830 if (a0 == 0) {
831 return failure;
832 }
[4023]833
[6801]834 double n0 = sqrt(gmWGS/(a0*a0*a0));
[4023]835
[6801]836 bncTime tt(GPSweek, GPSweeks);
837 double tk = tt - bncTime(_TOC.gpsw(), _TOEsec);
[4023]838
[6801]839 double n = n0 + _Delta_n;
840 double M = _M0 + n*tk;
841 double E = M;
842 double E_last;
843 do {
844 E_last = E;
845 E = M + _e*sin(E);
846 } while ( fabs(E-E_last)*a0 > 0.001 );
847 double v = 2.0*atan( sqrt( (1.0 + _e)/(1.0 - _e) )*tan( E/2 ) );
848 double u0 = v + _omega;
849 double sin2u0 = sin(2*u0);
850 double cos2u0 = cos(2*u0);
851 double r = a0*(1 - _e*cos(E)) + _Crc*cos2u0 + _Crs*sin2u0;
852 double i = _i0 + _IDOT*tk + _Cic*cos2u0 + _Cis*sin2u0;
853 double u = u0 + _Cuc*cos2u0 + _Cus*sin2u0;
854 double xp = r*cos(u);
855 double yp = r*sin(u);
856 double OM = _OMEGA0 + (_OMEGADOT - omegaEarth)*tk -
857 omegaEarth*_TOEsec;
[4023]858
[6801]859 double sinom = sin(OM);
860 double cosom = cos(OM);
861 double sini = sin(i);
862 double cosi = cos(i);
863 xc[0] = xp*cosom - yp*cosi*sinom;
864 xc[1] = xp*sinom + yp*cosi*cosom;
865 xc[2] = yp*sini;
[4023]866
[6801]867 double tc = tt - _TOC;
868 xc[3] = _clock_bias + _clock_drift*tc + _clock_driftrate*tc*tc;
[4023]869
[6801]870 // Velocity
871 // --------
872 double tanv2 = tan(v/2);
873 double dEdM = 1 / (1 - _e*cos(E));
874 double dotv = sqrt((1.0 + _e)/(1.0 - _e)) / cos(E/2)/cos(E/2) / (1 + tanv2*tanv2)
875 * dEdM * n;
876 double dotu = dotv + (-_Cuc*sin2u0 + _Cus*cos2u0)*2*dotv;
877 double dotom = _OMEGADOT - omegaEarth;
878 double doti = _IDOT + (-_Cic*sin2u0 + _Cis*cos2u0)*2*dotv;
879 double dotr = a0 * _e*sin(E) * dEdM * n
880 + (-_Crc*sin2u0 + _Crs*cos2u0)*2*dotv;
881 double dotx = dotr*cos(u) - r*sin(u)*dotu;
882 double doty = dotr*sin(u) + r*cos(u)*dotu;
[4023]883
[6801]884 vv[0] = cosom *dotx - cosi*sinom *doty // dX / dr
885 - xp*sinom*dotom - yp*cosi*cosom*dotom // dX / dOMEGA
886 + yp*sini*sinom*doti; // dX / di
887
888 vv[1] = sinom *dotx + cosi*cosom *doty
889 + xp*cosom*dotom - yp*cosi*sinom*dotom
890 - yp*sini*cosom*doti;
891
892 vv[2] = sini *doty + yp*cosi *doti;
893
894 // Relativistic Correction
895 // -----------------------
896 // xc(4) -= 4.442807633e-10 * _e * sqrt(a0) *sin(E);
897 xc[3] -= 2.0 * (xc[0]*vv[0] + xc[1]*vv[1] + xc[2]*vv[2]) / t_CST::c / t_CST::c;
898
899 return success;
[4023]900}
901
902// RINEX Format String
903//////////////////////////////////////////////////////////////////////////////
904QString t_ephGal::toString(double version) const {
905
[4029]906 QString rnxStr = rinexDateStr(_TOC, _prn, version);
[4023]907
908 QTextStream out(&rnxStr);
909
910 out << QString("%1%2%3\n")
911 .arg(_clock_bias, 19, 'e', 12)
912 .arg(_clock_drift, 19, 'e', 12)
913 .arg(_clock_driftrate, 19, 'e', 12);
914
915 QString fmt = version < 3.0 ? " %1%2%3%4\n" : " %1%2%3%4\n";
916
917 out << QString(fmt)
918 .arg(_IODnav, 19, 'e', 12)
919 .arg(_Crs, 19, 'e', 12)
920 .arg(_Delta_n, 19, 'e', 12)
921 .arg(_M0, 19, 'e', 12);
922
923 out << QString(fmt)
924 .arg(_Cuc, 19, 'e', 12)
925 .arg(_e, 19, 'e', 12)
926 .arg(_Cus, 19, 'e', 12)
927 .arg(_sqrt_A, 19, 'e', 12);
928
929 out << QString(fmt)
930 .arg(_TOEsec, 19, 'e', 12)
931 .arg(_Cic, 19, 'e', 12)
932 .arg(_OMEGA0, 19, 'e', 12)
933 .arg(_Cis, 19, 'e', 12);
934
935 out << QString(fmt)
936 .arg(_i0, 19, 'e', 12)
937 .arg(_Crc, 19, 'e', 12)
938 .arg(_omega, 19, 'e', 12)
939 .arg(_OMEGADOT, 19, 'e', 12);
940
[6792]941 int dataSource = 0;
942 int SVhealth = 0;
943 double BGD_1_5A = _BGD_1_5A;
944 double BGD_1_5B = _BGD_1_5B;
[6812]945 if (_fnav) {
[6792]946 dataSource |= (1<<1);
947 dataSource |= (1<<8);
948 BGD_1_5B = 0.0;
949 // SVhealth
950 // Bit 3 : E5a DVS
[6812]951 if (_e5aDataInValid) {
[6792]952 SVhealth |= (1<<3);
953 }
954 // Bit 4-5: E5a HS
955 if (_E5aHS == 1.0) {
956 SVhealth |= (1<<4);
957 }
958 else if (_E5aHS == 2.0) {
959 SVhealth |= (1<<5);
960 }
961 else if (_E5aHS == 3.0) {
962 SVhealth |= (1<<4);
963 SVhealth |= (1<<5);
964 }
965 }
[6812]966 else if(_inav) {
[6803]967 // Bit 2 and 0 are set because from MT1046 the data source cannot be determined
968 // and RNXv3.03 says both can be set if the navigation messages were merged
[5539]969 dataSource |= (1<<0);
[6792]970 dataSource |= (1<<2);
[5540]971 dataSource |= (1<<9);
[6792]972 // SVhealth
973 // Bit 0 : E1-B DVS
[6812]974 if (_e1DataInValid) {
[6792]975 SVhealth |= (1<<0);
976 }
977 // Bit 1-2: E1-B HS
978 if (_E1_bHS == 1.0) {
979 SVhealth |= (1<<1);
980 }
981 else if (_E1_bHS == 2.0) {
982 SVhealth |= (1<<2);
983 }
[6803]984 else if (_E1_bHS == 3.0) {
[6792]985 SVhealth |= (1<<1);
986 SVhealth |= (1<<2);
987 }
[6802]988 // Bit 3 : E5a DVS
[6812]989 if (_e5aDataInValid) {
[6802]990 SVhealth |= (1<<3);
991 }
992 // Bit 4-5: E5a HS
993 if (_E5aHS == 1.0) {
994 SVhealth |= (1<<4);
995 }
996 else if (_E5aHS == 2.0) {
997 SVhealth |= (1<<5);
998 }
[6803]999 else if (_E5aHS == 3.0) {
[6802]1000 SVhealth |= (1<<4);
1001 SVhealth |= (1<<5);
1002 }
[6792]1003 // Bit 6 : E5b DVS
[6812]1004 if (_e5bDataInValid) {
[6792]1005 SVhealth |= (1<<6);
1006 }
1007 // Bit 7-8: E5b HS
1008 if (_E5bHS == 1.0) {
1009 SVhealth |= (1<<7);
1010 }
1011 else if (_E5bHS == 2.0) {
1012 SVhealth |= (1<<8);
1013 }
[6803]1014 else if (_E5bHS == 3.0) {
[6792]1015 SVhealth |= (1<<7);
1016 SVhealth |= (1<<8);
1017 }
[5539]1018 }
[6792]1019
[4023]1020 out << QString(fmt)
[5532]1021 .arg(_IDOT, 19, 'e', 12)
1022 .arg(double(dataSource), 19, 'e', 12)
[6892]1023 .arg(_TOEweek + 1024.0, 19, 'e', 12)
[5532]1024 .arg(0.0, 19, 'e', 12);
[4023]1025
1026 out << QString(fmt)
[6798]1027 .arg(_SISA, 19, 'e', 12)
[6792]1028 .arg(double(SVhealth), 19, 'e', 12)
1029 .arg(BGD_1_5A, 19, 'e', 12)
1030 .arg(BGD_1_5B, 19, 'e', 12);
[4023]1031
1032 out << QString(fmt)
1033 .arg(_TOT, 19, 'e', 12)
[4024]1034 .arg("", 19, QChar(' '))
1035 .arg("", 19, QChar(' '))
1036 .arg("", 19, QChar(' '));
[4023]1037
1038 return rnxStr;
1039}
1040
[6385]1041// Constructor
1042//////////////////////////////////////////////////////////////////////////////
[6390]1043t_ephSBAS::t_ephSBAS(float rnxVersion, const QStringList& lines) {
1044
1045 const int nLines = 4;
1046
1047 if (lines.size() != nLines) {
[6518]1048 _checkState = bad;
[6390]1049 return;
1050 }
1051
1052 // RINEX Format
1053 // ------------
1054 int fieldLen = 19;
1055
1056 int pos[4];
1057 pos[0] = (rnxVersion <= 2.12) ? 3 : 4;
1058 pos[1] = pos[0] + fieldLen;
1059 pos[2] = pos[1] + fieldLen;
1060 pos[3] = pos[2] + fieldLen;
1061
1062 // Read four lines
1063 // ---------------
1064 for (int iLine = 0; iLine < nLines; iLine++) {
1065 QString line = lines[iLine];
1066
1067 if ( iLine == 0 ) {
1068 QTextStream in(line.left(pos[1]).toAscii());
1069
1070 int year, month, day, hour, min;
1071 double sec;
[6880]1072
[7139]1073 QString prnStr, n;
[6880]1074 in >> prnStr;
1075 if (prnStr.size() == 1) {
[7139]1076 in >> n;
1077 prnStr.append(n);
[6880]1078 }
1079 in >> year >> month >> day >> hour >> min >> sec;
[6390]1080 if (prnStr.at(0) == 'S') {
1081 _prn.set('S', prnStr.mid(1).toInt());
1082 }
1083 else {
1084 _prn.set('S', prnStr.toInt());
1085 }
1086
1087 if (year < 80) {
1088 year += 2000;
1089 }
1090 else if (year < 100) {
1091 year += 1900;
1092 }
1093
1094 _TOC.set(year, month, day, hour, min, sec);
1095
1096 if ( readDbl(line, pos[1], fieldLen, _agf0 ) ||
1097 readDbl(line, pos[2], fieldLen, _agf1 ) ||
1098 readDbl(line, pos[3], fieldLen, _TOW ) ) {
[6518]1099 _checkState = bad;
[6390]1100 return;
1101 }
1102 }
1103
1104 else if ( iLine == 1 ) {
1105 if ( readDbl(line, pos[0], fieldLen, _x_pos ) ||
1106 readDbl(line, pos[1], fieldLen, _x_velocity ) ||
1107 readDbl(line, pos[2], fieldLen, _x_acceleration) ||
1108 readDbl(line, pos[3], fieldLen, _health ) ) {
[6518]1109 _checkState = bad;
[6390]1110 return;
1111 }
1112 }
1113
1114 else if ( iLine == 2 ) {
1115 if ( readDbl(line, pos[0], fieldLen, _y_pos ) ||
1116 readDbl(line, pos[1], fieldLen, _y_velocity ) ||
1117 readDbl(line, pos[2], fieldLen, _y_acceleration ) ||
1118 readDbl(line, pos[3], fieldLen, _ura ) ) {
[6518]1119 _checkState = bad;
[6390]1120 return;
1121 }
1122 }
1123
1124 else if ( iLine == 3 ) {
[6536]1125 double iodn;
[6390]1126 if ( readDbl(line, pos[0], fieldLen, _z_pos ) ||
1127 readDbl(line, pos[1], fieldLen, _z_velocity ) ||
1128 readDbl(line, pos[2], fieldLen, _z_acceleration) ||
[6536]1129 readDbl(line, pos[3], fieldLen, iodn ) ) {
[6518]1130 _checkState = bad;
[6390]1131 return;
[6891]1132 } else {
[6536]1133 _IODN = int(iodn);
[6390]1134 }
1135 }
1136 }
1137
[7278]1138 _x_pos *= 1.e3;
1139 _y_pos *= 1.e3;
1140 _z_pos *= 1.e3;
1141 _x_velocity *= 1.e3;
1142 _y_velocity *= 1.e3;
1143 _z_velocity *= 1.e3;
1144 _x_acceleration *= 1.e3;
1145 _y_acceleration *= 1.e3;
1146 _z_acceleration *= 1.e3;
[6385]1147}
1148
[7054]1149// IOD of SBAS Ephemeris (virtual)
1150////////////////////////////////////////////////////////////////////////////
1151
[7169]1152unsigned int t_ephSBAS::IOD() const {
[7054]1153 unsigned char buffer[80];
1154 int size = 0;
1155 int numbits = 0;
1156 long long bitbuffer = 0;
1157 unsigned char *startbuffer = buffer;
1158
1159 SBASADDBITSFLOAT(30, this->_x_pos, 0.08)
1160 SBASADDBITSFLOAT(30, this->_y_pos, 0.08)
1161 SBASADDBITSFLOAT(25, this->_z_pos, 0.4)
1162 SBASADDBITSFLOAT(17, this->_x_velocity, 0.000625)
1163 SBASADDBITSFLOAT(17, this->_y_velocity, 0.000625)
1164 SBASADDBITSFLOAT(18, this->_z_velocity, 0.004)
1165 SBASADDBITSFLOAT(10, this->_x_acceleration, 0.0000125)
1166 SBASADDBITSFLOAT(10, this->_y_acceleration, 0.0000125)
1167 SBASADDBITSFLOAT(10, this->_z_acceleration, 0.0000625)
1168 SBASADDBITSFLOAT(12, this->_agf0, 1.0/static_cast<double>(1<<30)/static_cast<double>(1<<1))
1169 SBASADDBITSFLOAT(8, this->_agf1, 1.0/static_cast<double>(1<<30)/static_cast<double>(1<<10))
1170 SBASADDBITS(5,0); // the last byte is filled by 0-bits to obtain a length of an integer multiple of 8
1171
1172 return CRC24(size, startbuffer);
1173}
1174
[6385]1175// Compute SBAS Satellite Position (virtual)
1176////////////////////////////////////////////////////////////////////////////
1177t_irc t_ephSBAS::position(int GPSweek, double GPSweeks, double* xc, double* vv) const {
[6386]1178
[6518]1179 if (_checkState == bad) {
1180 return failure;
1181 }
1182
[6386]1183 bncTime tt(GPSweek, GPSweeks);
1184 double dt = tt - _TOC;
1185
[7278]1186 xc[0] = _x_pos + _x_velocity * dt + _x_acceleration * dt * dt / 2.0;
1187 xc[1] = _y_pos + _y_velocity * dt + _y_acceleration * dt * dt / 2.0;
1188 xc[2] = _z_pos + _z_velocity * dt + _z_acceleration * dt * dt / 2.0;
[6386]1189
1190 vv[0] = _x_velocity + _x_acceleration * dt;
1191 vv[1] = _y_velocity + _y_acceleration * dt;
1192 vv[2] = _z_velocity + _z_acceleration * dt;
1193
1194 xc[3] = _agf0 + _agf1 * dt;
1195
1196 return success;
[6385]1197}
1198
1199// RINEX Format String
1200//////////////////////////////////////////////////////////////////////////////
[6388]1201QString t_ephSBAS::toString(double version) const {
1202
1203 QString rnxStr = rinexDateStr(_TOC, _prn, version);
1204
1205 QTextStream out(&rnxStr);
1206
1207 out << QString("%1%2%3\n")
[6390]1208 .arg(_agf0, 19, 'e', 12)
1209 .arg(_agf1, 19, 'e', 12)
1210 .arg(_TOW, 19, 'e', 12);
[6388]1211
1212 QString fmt = version < 3.0 ? " %1%2%3%4\n" : " %1%2%3%4\n";
1213
1214 out << QString(fmt)
1215 .arg(1.e-3*_x_pos, 19, 'e', 12)
1216 .arg(1.e-3*_x_velocity, 19, 'e', 12)
1217 .arg(1.e-3*_x_acceleration, 19, 'e', 12)
[6390]1218 .arg(_health, 19, 'e', 12);
[6388]1219
1220 out << QString(fmt)
1221 .arg(1.e-3*_y_pos, 19, 'e', 12)
1222 .arg(1.e-3*_y_velocity, 19, 'e', 12)
1223 .arg(1.e-3*_y_acceleration, 19, 'e', 12)
[6390]1224 .arg(_ura, 19, 'e', 12);
[6388]1225
1226 out << QString(fmt)
1227 .arg(1.e-3*_z_pos, 19, 'e', 12)
1228 .arg(1.e-3*_z_velocity, 19, 'e', 12)
1229 .arg(1.e-3*_z_acceleration, 19, 'e', 12)
[6536]1230 .arg(double(_IODN), 19, 'e', 12);
[6388]1231
1232 return rnxStr;
[6385]1233}
[6400]1234
1235// Constructor
1236//////////////////////////////////////////////////////////////////////////////
[6600]1237t_ephBDS::t_ephBDS(float rnxVersion, const QStringList& lines) {
[6400]1238
1239 const int nLines = 8;
1240
1241 if (lines.size() != nLines) {
[6518]1242 _checkState = bad;
[6400]1243 return;
1244 }
1245
1246 // RINEX Format
1247 // ------------
1248 int fieldLen = 19;
1249
1250 int pos[4];
1251 pos[0] = (rnxVersion <= 2.12) ? 3 : 4;
1252 pos[1] = pos[0] + fieldLen;
1253 pos[2] = pos[1] + fieldLen;
1254 pos[3] = pos[2] + fieldLen;
1255
1256 // Read eight lines
1257 // ----------------
1258 for (int iLine = 0; iLine < nLines; iLine++) {
1259 QString line = lines[iLine];
1260
1261 if ( iLine == 0 ) {
1262 QTextStream in(line.left(pos[1]).toAscii());
1263
1264 int year, month, day, hour, min;
1265 double sec;
[6880]1266
[7139]1267 QString prnStr, n;
[6880]1268 in >> prnStr;
1269 if (prnStr.size() == 1) {
[7139]1270 in >> n;
1271 prnStr.append(n);
[6880]1272 }
1273 in >> year >> month >> day >> hour >> min >> sec;
[6400]1274 if (prnStr.at(0) == 'C') {
1275 _prn.set('C', prnStr.mid(1).toInt());
1276 }
1277 else {
1278 _prn.set('C', prnStr.toInt());
1279 }
1280
1281 if (year < 80) {
1282 year += 2000;
1283 }
1284 else if (year < 100) {
1285 year += 1900;
1286 }
1287
[6812]1288 _TOC.setBDS(year, month, day, hour, min, sec);
[6400]1289
1290 if ( readDbl(line, pos[1], fieldLen, _clock_bias ) ||
1291 readDbl(line, pos[2], fieldLen, _clock_drift ) ||
1292 readDbl(line, pos[3], fieldLen, _clock_driftrate) ) {
[6518]1293 _checkState = bad;
[6400]1294 return;
1295 }
1296 }
1297
1298 else if ( iLine == 1 ) {
1299 double aode;
1300 if ( readDbl(line, pos[0], fieldLen, aode ) ||
1301 readDbl(line, pos[1], fieldLen, _Crs ) ||
1302 readDbl(line, pos[2], fieldLen, _Delta_n) ||
1303 readDbl(line, pos[3], fieldLen, _M0 ) ) {
[6518]1304 _checkState = bad;
[6400]1305 return;
1306 }
1307 _AODE = int(aode);
1308 }
1309
1310 else if ( iLine == 2 ) {
1311 if ( readDbl(line, pos[0], fieldLen, _Cuc ) ||
1312 readDbl(line, pos[1], fieldLen, _e ) ||
1313 readDbl(line, pos[2], fieldLen, _Cus ) ||
1314 readDbl(line, pos[3], fieldLen, _sqrt_A) ) {
[6518]1315 _checkState = bad;
[6400]1316 return;
1317 }
1318 }
1319
1320 else if ( iLine == 3 ) {
[6812]1321 if ( readDbl(line, pos[0], fieldLen, _TOEsec ) ||
[6400]1322 readDbl(line, pos[1], fieldLen, _Cic ) ||
1323 readDbl(line, pos[2], fieldLen, _OMEGA0) ||
1324 readDbl(line, pos[3], fieldLen, _Cis ) ) {
[6518]1325 _checkState = bad;
[6400]1326 return;
1327 }
1328 }
1329
1330 else if ( iLine == 4 ) {
1331 if ( readDbl(line, pos[0], fieldLen, _i0 ) ||
1332 readDbl(line, pos[1], fieldLen, _Crc ) ||
1333 readDbl(line, pos[2], fieldLen, _omega ) ||
1334 readDbl(line, pos[3], fieldLen, _OMEGADOT) ) {
[6518]1335 _checkState = bad;
[6400]1336 return;
1337 }
1338 }
1339
1340 else if ( iLine == 5 ) {
1341 if ( readDbl(line, pos[0], fieldLen, _IDOT ) ||
[6812]1342 readDbl(line, pos[2], fieldLen, _TOEweek)) {
[6518]1343 _checkState = bad;
[6400]1344 return;
1345 }
1346 }
1347
1348 else if ( iLine == 6 ) {
1349 double SatH1;
[6755]1350 if ( readDbl(line, pos[0], fieldLen, _URA ) ||
1351 readDbl(line, pos[1], fieldLen, SatH1) ||
[6400]1352 readDbl(line, pos[2], fieldLen, _TGD1) ||
1353 readDbl(line, pos[3], fieldLen, _TGD2) ) {
[6518]1354 _checkState = bad;
[6400]1355 return;
1356 }
1357 _SatH1 = int(SatH1);
1358 }
1359
1360 else if ( iLine == 7 ) {
1361 double aodc;
[6812]1362 if ( readDbl(line, pos[0], fieldLen, _TOT) ||
[6400]1363 readDbl(line, pos[1], fieldLen, aodc) ) {
[6518]1364 _checkState = bad;
[6400]1365 return;
1366 }
[6812]1367 if (_TOT == 0.9999e9) { // 0.9999e9 means not known (RINEX standard)
1368 _TOT = _TOEsec;
[6400]1369 }
1370 _AODC = int(aodc);
1371 }
1372 }
1373
[7138]1374 _TOE.setBDS(int(_TOEweek), _TOEsec);
1375
[6400]1376 // remark: actually should be computed from second_tot
1377 // but it seems to be unreliable in RINEX files
[6843]1378 //_TOT = _TOC.bdssec();
[6400]1379}
1380
[7054]1381// IOD of BDS Ephemeris (virtual)
1382////////////////////////////////////////////////////////////////////////////
[7169]1383unsigned int t_ephBDS::IOD() const {
[7054]1384 unsigned char buffer[80];
1385 int size = 0;
1386 int numbits = 0;
1387 long long bitbuffer = 0;
1388 unsigned char *startbuffer = buffer;
1389
1390 BDSADDBITSFLOAT(14, this->_IDOT, M_PI/static_cast<double>(1<<30)/static_cast<double>(1<<13))
1391 BDSADDBITSFLOAT(11, this->_clock_driftrate, 1.0/static_cast<double>(1<<30)
1392 /static_cast<double>(1<<30)/static_cast<double>(1<<6))
1393 BDSADDBITSFLOAT(22, this->_clock_drift, 1.0/static_cast<double>(1<<30)/static_cast<double>(1<<20))
1394 BDSADDBITSFLOAT(24, this->_clock_bias, 1.0/static_cast<double>(1<<30)/static_cast<double>(1<<3))
1395 BDSADDBITSFLOAT(18, this->_Crs, 1.0/static_cast<double>(1<<6))
1396 BDSADDBITSFLOAT(16, this->_Delta_n, M_PI/static_cast<double>(1<<30)/static_cast<double>(1<<13))
1397 BDSADDBITSFLOAT(32, this->_M0, M_PI/static_cast<double>(1<<30)/static_cast<double>(1<<1))
1398 BDSADDBITSFLOAT(18, this->_Cuc, 1.0/static_cast<double>(1<<30)/static_cast<double>(1<<1))
1399 BDSADDBITSFLOAT(32, this->_e, 1.0/static_cast<double>(1<<30)/static_cast<double>(1<<3))
1400 BDSADDBITSFLOAT(18, this->_Cus, 1.0/static_cast<double>(1<<30)/static_cast<double>(1<<1))
1401 BDSADDBITSFLOAT(32, this->_sqrt_A, 1.0/static_cast<double>(1<<19))
1402 BDSADDBITSFLOAT(18, this->_Cic, 1.0/static_cast<double>(1<<30)/static_cast<double>(1<<1))
1403 BDSADDBITSFLOAT(32, this->_OMEGA0, M_PI/static_cast<double>(1<<30)/static_cast<double>(1<<1))
1404 BDSADDBITSFLOAT(18, this->_Cis, 1.0/static_cast<double>(1<<30)/static_cast<double>(1<<1))
1405 BDSADDBITSFLOAT(32, this->_i0, M_PI/static_cast<double>(1<<30)/static_cast<double>(1<<1))
1406 BDSADDBITSFLOAT(18, this->_Crc, 1.0/static_cast<double>(1<<6))
1407 BDSADDBITSFLOAT(32, this->_omega, M_PI/static_cast<double>(1<<30)/static_cast<double>(1<<1))
1408 BDSADDBITSFLOAT(24, this->_OMEGADOT, M_PI/static_cast<double>(1<<30)/static_cast<double>(1<<13))
1409 BDSADDBITS(5, 0) // the last byte is filled by 0-bits to obtain a length of an integer multiple of 8
1410
1411 return CRC24(size, startbuffer);
1412}
1413
[6601]1414// Compute BDS Satellite Position (virtual)
[6400]1415//////////////////////////////////////////////////////////////////////////////
[6600]1416t_irc t_ephBDS::position(int GPSweek, double GPSweeks, double* xc, double* vv) const {
[6400]1417
[6518]1418 if (_checkState == bad) {
1419 return failure;
1420 }
1421
[6602]1422 static const double gmBDS = 398.6004418e12;
1423 static const double omegaBDS = 7292115.0000e-11;
[6400]1424
1425 xc[0] = xc[1] = xc[2] = xc[3] = 0.0;
1426 vv[0] = vv[1] = vv[2] = 0.0;
1427
1428 bncTime tt(GPSweek, GPSweeks);
1429
1430 if (_sqrt_A == 0) {
1431 return failure;
1432 }
1433 double a0 = _sqrt_A * _sqrt_A;
1434
[6602]1435 double n0 = sqrt(gmBDS/(a0*a0*a0));
[6400]1436 double tk = tt - _TOE;
1437 double n = n0 + _Delta_n;
1438 double M = _M0 + n*tk;
1439 double E = M;
1440 double E_last;
1441 int nLoop = 0;
1442 do {
1443 E_last = E;
1444 E = M + _e*sin(E);
1445
1446 if (++nLoop == 100) {
1447 return failure;
1448 }
1449 } while ( fabs(E-E_last)*a0 > 0.001 );
1450
1451 double v = atan2(sqrt(1-_e*_e) * sin(E), cos(E) - _e);
1452 double u0 = v + _omega;
1453 double sin2u0 = sin(2*u0);
1454 double cos2u0 = cos(2*u0);
1455 double r = a0*(1 - _e*cos(E)) + _Crc*cos2u0 + _Crs*sin2u0;
1456 double i = _i0 + _IDOT*tk + _Cic*cos2u0 + _Cis*sin2u0;
1457 double u = u0 + _Cuc*cos2u0 + _Cus*sin2u0;
1458 double xp = r*cos(u);
1459 double yp = r*sin(u);
1460 double toesec = (_TOE.gpssec() - 14.0);
1461 double sinom = 0;
1462 double cosom = 0;
1463 double sini = 0;
1464 double cosi = 0;
[7278]1465
[6400]1466 const double iMaxGEO = 10.0 / 180.0 * M_PI;
1467
1468 // MEO/IGSO satellite
1469 // ------------------
1470 if (_i0 > iMaxGEO) {
[6602]1471 double OM = _OMEGA0 + (_OMEGADOT - omegaBDS)*tk - omegaBDS*toesec;
[6400]1472
1473 sinom = sin(OM);
1474 cosom = cos(OM);
1475 sini = sin(i);
1476 cosi = cos(i);
1477
1478 xc[0] = xp*cosom - yp*cosi*sinom;
1479 xc[1] = xp*sinom + yp*cosi*cosom;
[7278]1480 xc[2] = yp*sini;
[6400]1481 }
1482
1483 // GEO satellite
1484 // -------------
1485 else {
[6602]1486 double OM = _OMEGA0 + _OMEGADOT*tk - omegaBDS*toesec;
1487 double ll = omegaBDS*tk;
[6400]1488
1489 sinom = sin(OM);
1490 cosom = cos(OM);
1491 sini = sin(i);
1492 cosi = cos(i);
1493
1494 double xx = xp*cosom - yp*cosi*sinom;
1495 double yy = xp*sinom + yp*cosi*cosom;
[7278]1496 double zz = yp*sini;
[6400]1497
1498 Matrix R1 = BNC_PPP::t_astro::rotX(-5.0 / 180.0 * M_PI);
1499 Matrix R2 = BNC_PPP::t_astro::rotZ(ll);
1500
1501 ColumnVector X1(3); X1 << xx << yy << zz;
1502 ColumnVector X2 = R2*R1*X1;
1503
1504 xc[0] = X2(1);
1505 xc[1] = X2(2);
1506 xc[2] = X2(3);
1507 }
[7278]1508
[6400]1509 double tc = tt - _TOC;
[7278]1510 xc[3] = _clock_bias + _clock_drift*tc + _clock_driftrate*tc*tc
[6400]1511 - 4.442807633e-10 * _e * sqrt(a0) *sin(E);
1512
1513 // Velocity
1514 // --------
1515 double tanv2 = tan(v/2);
1516 double dEdM = 1 / (1 - _e*cos(E));
[7278]1517 double dotv = sqrt((1.0 + _e)/(1.0 - _e)) / cos(E/2)/cos(E/2)
[6400]1518 / (1 + tanv2*tanv2) * dEdM * n;
1519 double dotu = dotv + (-_Cuc*sin2u0 + _Cus*cos2u0)*2*dotv;
1520 double dotom = _OMEGADOT - t_CST::omega;
1521 double doti = _IDOT + (-_Cic*sin2u0 + _Cis*cos2u0)*2*dotv;
[7278]1522 double dotr = a0 * _e*sin(E) * dEdM * n
[6400]1523 + (-_Crc*sin2u0 + _Crs*cos2u0)*2*dotv;
1524 double dotx = dotr*cos(u) - r*sin(u)*dotu;
1525 double doty = dotr*sin(u) + r*cos(u)*dotu;
1526
1527 vv[0] = cosom *dotx - cosi*sinom *doty // dX / dr
1528 - xp*sinom*dotom - yp*cosi*cosom*dotom // dX / dOMEGA
1529 + yp*sini*sinom*doti; // dX / di
[7278]1530
[6400]1531 vv[1] = sinom *dotx + cosi*cosom *doty
1532 + xp*cosom*dotom - yp*cosi*sinom*dotom
1533 - yp*sini*cosom*doti;
1534
1535 vv[2] = sini *doty + yp*cosi *doti;
1536
[7278]1537 // dotC = _clock_drift + _clock_driftrate*tc
[6400]1538 // - 4.442807633e-10*_e*sqrt(a0)*cos(E) * dEdM * n;
1539
1540 return success;
1541}
1542
1543// RINEX Format String
1544//////////////////////////////////////////////////////////////////////////////
[6600]1545QString t_ephBDS::toString(double version) const {
[6400]1546
[6812]1547 QString rnxStr = rinexDateStr(_TOC-14.0, _prn, version);
[6400]1548
1549 QTextStream out(&rnxStr);
1550
1551 out << QString("%1%2%3\n")
1552 .arg(_clock_bias, 19, 'e', 12)
1553 .arg(_clock_drift, 19, 'e', 12)
1554 .arg(_clock_driftrate, 19, 'e', 12);
1555
1556 QString fmt = version < 3.0 ? " %1%2%3%4\n" : " %1%2%3%4\n";
1557
1558 out << QString(fmt)
1559 .arg(double(_AODE), 19, 'e', 12)
1560 .arg(_Crs, 19, 'e', 12)
1561 .arg(_Delta_n, 19, 'e', 12)
1562 .arg(_M0, 19, 'e', 12);
1563
1564 out << QString(fmt)
1565 .arg(_Cuc, 19, 'e', 12)
1566 .arg(_e, 19, 'e', 12)
1567 .arg(_Cus, 19, 'e', 12)
1568 .arg(_sqrt_A, 19, 'e', 12);
1569
[6843]1570 double toes = 0.0;
1571 if (_TOEweek > -1.0) {// RINEX input
1572 toes = _TOEsec;
1573 }
1574 else {// RTCM stream input
[6812]1575 toes = _TOE.bdssec();
[6755]1576 }
[6400]1577 out << QString(fmt)
[6843]1578 .arg(toes, 19, 'e', 12)
[6755]1579 .arg(_Cic, 19, 'e', 12)
1580 .arg(_OMEGA0, 19, 'e', 12)
1581 .arg(_Cis, 19, 'e', 12);
[6400]1582
1583 out << QString(fmt)
1584 .arg(_i0, 19, 'e', 12)
1585 .arg(_Crc, 19, 'e', 12)
1586 .arg(_omega, 19, 'e', 12)
1587 .arg(_OMEGADOT, 19, 'e', 12);
1588
[6843]1589 double toew = 0.0;
1590 if (_TOEweek > -1.0) {// RINEX input
1591 toew = _TOEweek;
1592 }
1593 else {// RTCM stream input
1594 toew = double(_TOE.bdsw());
1595 }
[6400]1596 out << QString(fmt)
[6843]1597 .arg(_IDOT, 19, 'e', 12)
1598 .arg(0.0, 19, 'e', 12)
1599 .arg(toew, 19, 'e', 12)
1600 .arg(0.0, 19, 'e', 12);
[6400]1601
1602 out << QString(fmt)
[6798]1603 .arg(_URA, 19, 'e', 12)
[6400]1604 .arg(double(_SatH1), 19, 'e', 12)
1605 .arg(_TGD1, 19, 'e', 12)
1606 .arg(_TGD2, 19, 'e', 12);
1607
[6843]1608 double tots = 0.0;
1609 if (_TOEweek > -1.0) {// RINEX input
1610 tots = _TOT;
1611 }
1612 else {// RTCM stream input
[6812]1613 tots = _TOE.bdssec();
[6755]1614 }
[6400]1615 out << QString(fmt)
[6792]1616 .arg(tots, 19, 'e', 12)
[6755]1617 .arg(double(_AODC), 19, 'e', 12)
1618 .arg("", 19, QChar(' '))
1619 .arg("", 19, QChar(' '));
[6400]1620 return rnxStr;
1621}
Note: See TracBrowser for help on using the repository browser.