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

Last change on this file since 6840 was 6812, checked in by stoecker, 10 years ago

integrate RTCM3 parsing into BNC and directly fill target structures, add doxygen documentation

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