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

Last change on this file since 7012 was 7010, checked in by stuerze, 9 years ago

ssr clock correction has to be converted into seconds in order to be consistent with broadcast value

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