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

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