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

Last change on this file since 8132 was 7922, checked in by stuerze, 10 years ago

minor changes in RINEX 2.11 epemeris output in case of an unknown transmission time

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