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

Last change on this file since 6887 was 6880, checked in by stuerze, 10 years ago

minor changes to read rinex nav files with blank space between satellite system and number

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