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

Last change on this file since 7922 was 7922, checked in by stuerze, 8 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.