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

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

fixes regarding SSR orbit correction: transformation of radial, along track, out-of-plane components into xyz has to be done for all systems. correction for velocity is added

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