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

Last change on this file since 6812 was 6812, checked in by stoecker, 9 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.