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

Last change on this file since 9786 was 9786, checked in by stuerze, 3 months ago

some more changes to consider RINEX Version 4 in nav files: added CNAF, CNV2 for GPS, QZSS

File size: 60.7 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 _navType = undefined;
24 _orbCorr = 0;
25 _clkCorr = 0;
26}
27// Destructor
28////////////////////////////////////////////////////////////////////////////
29t_eph::~t_eph() {
30 if (_orbCorr)
31 delete _orbCorr;
32 if (_clkCorr)
33 delete _clkCorr;
34}
35
36//
37////////////////////////////////////////////////////////////////////////////
38void t_eph::setOrbCorr(const t_orbCorr* orbCorr) {
39 if (_orbCorr) {
40 delete _orbCorr;
41 _orbCorr = 0;
42 }
43 _orbCorr = new t_orbCorr(*orbCorr);
44}
45
46//
47////////////////////////////////////////////////////////////////////////////
48void t_eph::setClkCorr(const t_clkCorr* clkCorr) {
49 if (_clkCorr) {
50 delete _clkCorr;
51 _clkCorr = 0;
52 }
53 _clkCorr = new t_clkCorr(*clkCorr);
54}
55
56//
57////////////////////////////////////////////////////////////////////////////
58t_irc t_eph::getCrd(const bncTime& tt, ColumnVector& xc, ColumnVector& vv, bool useCorr) const {
59
60 if (_checkState == bad ||
61 _checkState == unhealthy ||
62 _checkState == outdated) {
63 return failure;
64 }
65
66 xc.ReSize(6);
67 vv.ReSize(3);
68 if (position(tt.gpsw(), tt.gpssec(), xc.data(), vv.data()) != success) {
69 return failure;
70 }
71 if (useCorr) {
72 if (_orbCorr && _clkCorr) {
73 double dtO = tt - _orbCorr->_time;
74 if (_orbCorr->_updateInt) {
75 dtO -= (0.5 * ssrUpdateInt[_orbCorr->_updateInt]);
76 }
77 ColumnVector dx(3);
78 dx[0] = _orbCorr->_xr[0] + _orbCorr->_dotXr[0] * dtO;
79 dx[1] = _orbCorr->_xr[1] + _orbCorr->_dotXr[1] * dtO;
80 dx[2] = _orbCorr->_xr[2] + _orbCorr->_dotXr[2] * dtO;
81
82 RSW_to_XYZ(xc.Rows(1,3), vv.Rows(1,3), dx, dx);
83
84 xc[0] -= dx[0];
85 xc[1] -= dx[1];
86 xc[2] -= dx[2];
87
88 ColumnVector dv(3);
89 RSW_to_XYZ(xc.Rows(1,3), vv.Rows(1,3), _orbCorr->_dotXr, dv);
90
91 vv[0] -= dv[0];
92 vv[1] -= dv[1];
93 vv[2] -= dv[2];
94
95 double dtC = tt - _clkCorr->_time;
96 if (_clkCorr->_updateInt) {
97 dtC -= (0.5 * ssrUpdateInt[_clkCorr->_updateInt]);
98 }
99 xc[3] += _clkCorr->_dClk + _clkCorr->_dotDClk * dtC + _clkCorr->_dotDotDClk * dtC * dtC;
100 }
101 else {
102 return failure;
103 }
104 }
105 return success;
106}
107
108
109//
110//////////////////////////////////////////////////////////////////////////////
111t_irc t_eph::setNavType(QString navTypeStr) {
112 if (navTypeStr == "LNAV") {_navType = t_eph::LNAV;}
113 else if (navTypeStr == "FDMA") {_navType = t_eph::FDMA;}
114 else if (navTypeStr == "FNAV") {_navType = t_eph::FNAV;}
115 else if (navTypeStr == "INAF") {_navType = t_eph::INAF;}
116 else if (navTypeStr == "D1") {_navType = t_eph::D1;}
117 else if (navTypeStr == "D2") {_navType = t_eph::D2;}
118 else if (navTypeStr == "SBAS") {_navType = t_eph::SBASL1;}
119 else if (navTypeStr == "CNAV") {_navType = t_eph::CNAV;}
120 else if (navTypeStr == "CNV1") {_navType = t_eph::CNV1;}
121 else if (navTypeStr == "CNV2") {_navType = t_eph::CNV2;}
122 else if (navTypeStr == "CNV3") {_navType = t_eph::CNV3;}
123 else {_navType = t_eph::undefined; return failure;}
124
125 return success;
126}
127
128//
129//////////////////////////////////////////////////////////////////////////////
130QString t_eph::navTypeString(e_navType navType, const t_prn& prn, double version) {
131 QString navTypeString = "";
132 QString epochStart;
133 QString eolStr;
134
135 if (version < 4.0) {
136 return navTypeString;
137 }
138
139 if (version == 99.0) {
140 epochStart = "";
141 eolStr = "";
142 }
143 else {
144 epochStart = "> ";
145 eolStr = "\n";
146 }
147
148 QString ephStr = QString("EPH %1 ").arg(prn.toString().c_str());
149 switch (navType) {
150 case undefined:
151 navTypeString = epochStart + ephStr + "unknown" + eolStr;
152 break;
153 case LNAV:
154 navTypeString = epochStart + ephStr + "LNAV" + eolStr;
155 break;
156 case FDMA:
157 navTypeString = epochStart + ephStr + "FDMA" + eolStr;
158 break;
159 case FNAV:
160 navTypeString = epochStart + ephStr + "FNAV" + eolStr;
161 break;
162 case INAF:
163 navTypeString = epochStart + ephStr + "INAV" + eolStr;
164 break;
165 case D1:
166 navTypeString = epochStart + ephStr + "D1 " + eolStr;
167 break;
168 case D2:
169 navTypeString = epochStart + ephStr + "D2 " + eolStr;
170 break;
171 case SBASL1:
172 navTypeString = epochStart + ephStr + "SBAS" + eolStr;
173 break;
174 case CNAV:
175 navTypeString = epochStart + ephStr + "CNAV" + eolStr;
176 break;
177 case CNV1:
178 navTypeString = epochStart + ephStr + "CNV1" + eolStr;
179 break;
180 case CNV2:
181 navTypeString = epochStart + ephStr + "CNV2" + eolStr;
182 break;
183 case CNV3:
184 navTypeString = epochStart + ephStr + "CNV3" + eolStr;
185 break;
186 }
187 return navTypeString;
188 }
189
190//
191//////////////////////////////////////////////////////////////////////////////
192QString t_eph::rinexDateStr(const bncTime& tt, const t_prn& prn, double version) {
193 QString prnStr(prn.toString().c_str());
194 return rinexDateStr(tt, prnStr, version);
195}
196
197//
198//////////////////////////////////////////////////////////////////////////////
199QString t_eph::rinexDateStr(const bncTime& tt, const QString& prnStr, double version) {
200
201 QString datStr;
202
203 unsigned year, month, day, hour, min;
204 double sec;
205 tt.civil_date(year, month, day);
206 tt.civil_time(hour, min, sec);
207
208 QTextStream out(&datStr);
209
210 if (version < 3.0) {
211 QString prnHlp = prnStr.mid(1,2); if (prnHlp[0] == '0') prnHlp[0] = ' ';
212 out << prnHlp << QString(" %1 %2 %3 %4 %5%6")
213 .arg(year % 100, 2, 10, QChar('0'))
214 .arg(month, 2)
215 .arg(day, 2)
216 .arg(hour, 2)
217 .arg(min, 2)
218 .arg(sec, 5, 'f',1);
219 }
220 else if (version == 99) {
221 out << QString(" %1 %2 %3 %4 %5 %6")
222 .arg(year, 4)
223 .arg(month, 2, 10, QChar('0'))
224 .arg(day, 2, 10, QChar('0'))
225 .arg(hour, 2, 10, QChar('0'))
226 .arg(min, 2, 10, QChar('0'))
227 .arg(int(sec), 2, 10, QChar('0'));
228 }
229 else {
230 out << prnStr << QString(" %1 %2 %3 %4 %5 %6")
231 .arg(year, 4)
232 .arg(month, 2, 10, QChar('0'))
233 .arg(day, 2, 10, QChar('0'))
234 .arg(hour, 2, 10, QChar('0'))
235 .arg(min, 2, 10, QChar('0'))
236 .arg(int(sec), 2, 10, QChar('0'));
237 }
238
239 return datStr;
240}
241
242// Constructor
243//////////////////////////////////////////////////////////////////////////////
244t_ephGPS::t_ephGPS(double rnxVersion, const QStringList& lines) {
245
246 int nLines = 8;
247
248 if (navType() == t_eph::CNAV) {
249 nLines += 1;
250 }
251 else if (navType() == t_eph::CNV2) {
252 nLines += 2;
253 }
254
255 if (lines.size() != nLines) {
256 _checkState = bad;
257 return;
258 }
259
260 // RINEX Format
261 // ------------
262 int fieldLen = 19;
263
264 int pos[4];
265 pos[0] = (rnxVersion <= 2.12) ? 3 : 4;
266 pos[1] = pos[0] + fieldLen;
267 pos[2] = pos[1] + fieldLen;
268 pos[3] = pos[2] + fieldLen;
269
270 // Read eight lines
271 // ----------------
272 for (int iLine = 0; iLine < nLines; iLine++) {
273 QString line = lines[iLine];
274
275 if ( iLine == 0 ) {
276 QTextStream in(line.left(pos[1]).toLatin1());
277 int year, month, day, hour, min;
278 double sec;
279
280 QString prnStr, n;
281 in >> prnStr;
282
283 if (prnStr.size() == 1 &&
284 (prnStr[0] == 'G' ||
285 prnStr[0] == 'J' ||
286 prnStr[0] == 'I')) {
287 in >> n;
288 prnStr.append(n);
289 }
290
291 in >> year >> month >> day >> hour >> min >> sec;
292 if (prnStr.at(0) == 'G') {
293 _prn.set('G', prnStr.mid(1).toInt());
294 }
295 else if (prnStr.at(0) == 'J') {
296 _prn.set('J', prnStr.mid(1).toInt());
297 }
298 else if (prnStr.at(0) == 'I') {
299 _prn.set('I', prnStr.mid(1).toInt());
300 }
301 else {
302 _prn.set('G', prnStr.toInt());
303 }
304
305 if (year < 80) {
306 year += 2000;
307 }
308 else if (year < 100) {
309 year += 1900;
310 }
311
312 _TOC.set(year, month, day, hour, min, sec);
313
314 if ( readDbl(line, pos[1], fieldLen, _clock_bias ) ||
315 readDbl(line, pos[2], fieldLen, _clock_drift ) ||
316 readDbl(line, pos[3], fieldLen, _clock_driftrate) ) {
317 _checkState = bad;
318 return;
319 }
320 }
321 // =====================
322 // BROADCAST ORBIT - 1
323 // =====================
324 else if ( iLine == 1) {
325
326 if (navType() == t_eph::CNAV ||
327 navType() == t_eph::CNV2) {
328 if ( readDbl(line, pos[0], fieldLen, _ADOT ) ||
329 readDbl(line, pos[1], fieldLen, _Crs ) ||
330 readDbl(line, pos[2], fieldLen, _Delta_n) ||
331 readDbl(line, pos[3], fieldLen, _M0 ) ) {
332 _checkState = bad;
333 return;
334 }
335 }
336 else { // LNAV, undefined
337 if ( readDbl(line, pos[0], fieldLen, _IODE ) ||
338 readDbl(line, pos[1], fieldLen, _Crs ) ||
339 readDbl(line, pos[2], fieldLen, _Delta_n) ||
340 readDbl(line, pos[3], fieldLen, _M0 ) ) {
341 _checkState = bad;
342 return;
343 }
344 }
345 }
346 // =====================
347 // BROADCAST ORBIT - 2
348 // =====================
349 else if ( iLine == 2 ) {
350 if ( readDbl(line, pos[0], fieldLen, _Cuc ) ||
351 readDbl(line, pos[1], fieldLen, _e ) ||
352 readDbl(line, pos[2], fieldLen, _Cus ) ||
353 readDbl(line, pos[3], fieldLen, _sqrt_A) ) {
354 _checkState = bad;
355 return;
356 }
357 }
358 // =====================
359 // BROADCAST ORBIT - 3
360 // =====================
361 else if ( iLine == 3 ) {
362
363 if (navType() == t_eph::CNAV ||
364 navType() == t_eph::CNV2) {
365 if ( readDbl(line, pos[0], fieldLen, _top) ||
366 readDbl(line, pos[1], fieldLen, _Cic ) ||
367 readDbl(line, pos[2], fieldLen, _OMEGA0) ||
368 readDbl(line, pos[3], fieldLen, _Cis ) ) {
369 _checkState = bad;
370 return;
371 }
372 }
373 else { // LNAV, undefined
374 if ( readDbl(line, pos[0], fieldLen, _TOEsec) ||
375 readDbl(line, pos[1], fieldLen, _Cic ) ||
376 readDbl(line, pos[2], fieldLen, _OMEGA0) ||
377 readDbl(line, pos[3], fieldLen, _Cis ) ) {
378 _checkState = bad;
379 return;
380 }
381 }
382 }
383 // =====================
384 // BROADCAST ORBIT - 4
385 // =====================
386 else if ( iLine == 4 ) {
387 if ( readDbl(line, pos[0], fieldLen, _i0 ) ||
388 readDbl(line, pos[1], fieldLen, _Crc ) ||
389 readDbl(line, pos[2], fieldLen, _omega ) ||
390 readDbl(line, pos[3], fieldLen, _OMEGADOT) ) {
391 _checkState = bad;
392 return;
393 }
394 }
395 // =====================
396 // BROADCAST ORBIT - 5
397 // =====================
398 else if ( iLine == 5 && type() != t_eph::IRNSS) {
399
400 if (navType() == t_eph::CNAV ||
401 navType() == t_eph::CNV2) {
402 if ( readDbl(line, pos[0], fieldLen, _IDOT ) ||
403 readDbl(line, pos[1], fieldLen, _DN0DOT ) ||
404 readDbl(line, pos[2], fieldLen, _URAI_NED0 ) ||
405 readDbl(line, pos[3], fieldLen, _URAI_NED1) ) {
406 _checkState = bad;
407 return;
408 }
409 }
410 else { // LNAV, undefined
411 if ( readDbl(line, pos[0], fieldLen, _IDOT ) ||
412 readDbl(line, pos[1], fieldLen, _L2Codes) ||
413 readDbl(line, pos[2], fieldLen, _TOEweek ) ||
414 readDbl(line, pos[3], fieldLen, _L2PFlag) ) {
415 _checkState = bad;
416 return;
417 }
418 }
419 }
420 else if ( iLine == 5 && type() == t_eph::IRNSS) {
421 if ( readDbl(line, pos[0], fieldLen, _IDOT ) ||
422 readDbl(line, pos[2], fieldLen, _TOEweek) ) {
423 _checkState = bad;
424 return;
425 }
426 }
427 // =====================
428 // BROADCAST ORBIT - 6
429 // =====================
430 else if ( iLine == 6 && type() != t_eph::IRNSS) {
431
432 if (navType() == t_eph::CNAV ||
433 navType() == t_eph::CNV2 ) {
434 if ( readDbl(line, pos[0], fieldLen, _URAI_ED) ||
435 readDbl(line, pos[1], fieldLen, _health ) ||
436 readDbl(line, pos[2], fieldLen, _TGD ) ||
437 readDbl(line, pos[3], fieldLen, _URAI_NED2) ) {
438 _checkState = bad;
439 return;
440 }
441 }
442 else { // LNAV, undefined
443 if ( readDbl(line, pos[0], fieldLen, _ura ) ||
444 readDbl(line, pos[1], fieldLen, _health) ||
445 readDbl(line, pos[2], fieldLen, _TGD ) ||
446 readDbl(line, pos[3], fieldLen, _IODC ) ) {
447 _checkState = bad;
448 return;
449 }
450 }
451 }
452 else if ( iLine == 6 && type() == t_eph::IRNSS) {
453 if ( readDbl(line, pos[0], fieldLen, _ura ) ||
454 readDbl(line, pos[1], fieldLen, _health) ||
455 readDbl(line, pos[2], fieldLen, _TGD ) ) {
456 _checkState = bad;
457 return;
458 }
459 }
460 // =====================
461 // BROADCAST ORBIT - 7
462 // =====================
463 else if ( iLine == 7 ) {
464 if (navType() == t_eph::LNAV ||
465 navType() == t_eph::undefined) {
466
467 if ( readDbl(line, pos[0], fieldLen, _TOT) ) {
468 _checkState = bad;
469 return;
470 }
471
472 if (type() != t_eph::IRNSS) {
473 double fitIntervalRnx;
474 if ( readDbl(line, pos[1], fieldLen, fitIntervalRnx) ) {
475 _checkState = bad;
476 return;
477 }
478 if (type() == t_eph::GPS) { // in RINEX specified always as time period for GPS
479 _fitInterval = fitIntervalRnx;
480 } else if (type() == t_eph::QZSS) { // specified as flag for QZSS
481 if (rnxVersion == 3.02) {
482 _fitInterval = fitIntervalRnx; // specified as time period
483 }
484 else {
485 _fitInterval = fitIntervalFromFlag(fitIntervalRnx, _IODC, t_eph::QZSS);
486 }
487 }
488 }
489 }
490
491 else if (navType() == t_eph::CNAV ||
492 navType() == t_eph::CNV2) {
493 if ( readDbl(line, pos[0], fieldLen, _ISC_L1CA) ||
494 readDbl(line, pos[1], fieldLen, _ISC_L2C ) ||
495 readDbl(line, pos[2], fieldLen, _ISC_L5I5) ||
496 readDbl(line, pos[3], fieldLen, _ISC_L5Q5) ) {
497 _checkState = bad;
498 return;
499 }
500
501 }
502
503 }
504 // =====================
505 // BROADCAST ORBIT - 8
506 // =====================
507 else if ( iLine == 8 ) {
508 if (navType() == t_eph::CNAV) {
509 if ( readDbl(line, pos[0], fieldLen, _TOT) ||
510 readDbl(line, pos[1], fieldLen, _wnop) ) {
511 _checkState = bad;
512 return;
513 }
514 }
515 else if (navType() == t_eph::CNV2) {
516 if ( readDbl(line, pos[0], fieldLen, _ISC_L1Cd) ||
517 readDbl(line, pos[1], fieldLen, _ISC_L1Cp)) {
518 _checkState = bad;
519 return;
520 }
521 }
522 }
523 // =====================
524 // BROADCAST ORBIT - 9
525 // =====================
526 else if ( iLine == 9 ) {
527 if (navType() == t_eph::CNV2) {
528 if ( readDbl(line, pos[0], fieldLen, _TOT) ||
529 readDbl(line, pos[1], fieldLen, _wnop) ) {
530 _checkState = bad;
531 return;
532 }
533 }
534 }
535 }
536}
537
538// Compute GPS Satellite Position (virtual)
539////////////////////////////////////////////////////////////////////////////
540t_irc t_ephGPS::position(int GPSweek, double GPSweeks, double* xc, double* vv) const {
541
542 static const double omegaEarth = 7292115.1467e-11;
543 static const double gmGRS = 398.6005e12;
544
545 memset(xc, 0, 6*sizeof(double));
546 memset(vv, 0, 3*sizeof(double));
547
548 double a0 = _sqrt_A * _sqrt_A;
549 if (a0 == 0) {
550 return failure;
551 }
552
553 double n0 = sqrt(gmGRS/(a0*a0*a0));
554
555 bncTime tt(GPSweek, GPSweeks);
556 double tk = tt - bncTime(int(_TOEweek), _TOEsec);
557
558 double n = n0 + _Delta_n;
559 double M = _M0 + n*tk;
560 double E = M;
561 double E_last;
562 int nLoop = 0;
563 do {
564 E_last = E;
565 E = M + _e*sin(E);
566
567 if (++nLoop == 100) {
568 return failure;
569 }
570 } while ( fabs(E-E_last)*a0 > 0.001);
571 double v = 2.0*atan( sqrt( (1.0 + _e)/(1.0 - _e) )*tan( E/2 ) );
572 double u0 = v + _omega;
573 double sin2u0 = sin(2*u0);
574 double cos2u0 = cos(2*u0);
575 double r = a0*(1 - _e*cos(E)) + _Crc*cos2u0 + _Crs*sin2u0;
576 double i = _i0 + _IDOT*tk + _Cic*cos2u0 + _Cis*sin2u0;
577 double u = u0 + _Cuc*cos2u0 + _Cus*sin2u0;
578 double xp = r*cos(u);
579 double yp = r*sin(u);
580 double OM = _OMEGA0 + (_OMEGADOT - omegaEarth)*tk -
581 omegaEarth*_TOEsec;
582
583 double sinom = sin(OM);
584 double cosom = cos(OM);
585 double sini = sin(i);
586 double cosi = cos(i);
587 xc[0] = xp*cosom - yp*cosi*sinom;
588 xc[1] = xp*sinom + yp*cosi*cosom;
589 xc[2] = yp*sini;
590
591 double tc = tt - _TOC;
592 xc[3] = _clock_bias + _clock_drift*tc + _clock_driftrate*tc*tc;
593
594 // Velocity
595 // --------
596 double tanv2 = tan(v/2);
597 double dEdM = 1 / (1 - _e*cos(E));
598 double dotv = sqrt((1.0 + _e)/(1.0 - _e)) / cos(E/2)/cos(E/2) / (1 + tanv2*tanv2)
599 * dEdM * n;
600 double dotu = dotv + (-_Cuc*sin2u0 + _Cus*cos2u0)*2*dotv;
601 double dotom = _OMEGADOT - omegaEarth;
602 double doti = _IDOT + (-_Cic*sin2u0 + _Cis*cos2u0)*2*dotv;
603 double dotr = a0 * _e*sin(E) * dEdM * n
604 + (-_Crc*sin2u0 + _Crs*cos2u0)*2*dotv;
605 double dotx = dotr*cos(u) - r*sin(u)*dotu;
606 double doty = dotr*sin(u) + r*cos(u)*dotu;
607
608 vv[0] = cosom *dotx - cosi*sinom *doty // dX / dr
609 - xp*sinom*dotom - yp*cosi*cosom*dotom // dX / dOMEGA
610 + yp*sini*sinom*doti; // dX / di
611
612 vv[1] = sinom *dotx + cosi*cosom *doty
613 + xp*cosom*dotom - yp*cosi*sinom*dotom
614 - yp*sini*cosom*doti;
615
616 vv[2] = sini *doty + yp*cosi *doti;
617
618 // Relativistic Correction
619 // -----------------------
620 xc[3] -= 4.442807633e-10 * _e * sqrt(a0) *sin(E);
621
622 xc[4] = _clock_drift + _clock_driftrate*tc;
623 xc[5] = _clock_driftrate;
624
625 return success;
626}
627
628// RINEX Format String
629//////////////////////////////////////////////////////////////////////////////
630QString t_ephGPS::toString(double version) const {
631
632 QString navStr = navTypeString(_navType, _prn, version);
633 QString rnxStr = navStr + rinexDateStr(_TOC, _prn, version);
634
635 QTextStream out(&rnxStr);
636
637 out << QString("%1%2%3\n")
638 .arg(_clock_bias, 19, 'e', 12)
639 .arg(_clock_drift, 19, 'e', 12)
640 .arg(_clock_driftrate, 19, 'e', 12);
641
642 QString fmt = version < 3.0 ? " %1%2%3%4\n" : " %1%2%3%4\n";
643
644
645 // =====================
646 // BROADCAST ORBIT - 1
647 // =====================
648 if (navType() == t_eph::CNAV ||
649 navType() == t_eph::CNV2) {
650 out << QString(fmt)
651 .arg(_ADOT, 19, 'e', 12)
652 .arg(_Crs, 19, 'e', 12)
653 .arg(_Delta_n, 19, 'e', 12)
654 .arg(_M0, 19, 'e', 12);
655 }
656 else { // LNAV, undefinded
657 out << QString(fmt)
658 .arg(_IODE, 19, 'e', 12)
659 .arg(_Crs, 19, 'e', 12)
660 .arg(_Delta_n, 19, 'e', 12)
661 .arg(_M0, 19, 'e', 12);
662 }
663 // =====================
664 // BROADCAST ORBIT - 2
665 // =====================
666 out << QString(fmt)
667 .arg(_Cuc, 19, 'e', 12)
668 .arg(_e, 19, 'e', 12)
669 .arg(_Cus, 19, 'e', 12)
670 .arg(_sqrt_A, 19, 'e', 12);
671 // =====================
672 // BROADCAST ORBIT - 3
673 // =====================
674 if (navType() == t_eph::CNAV ||
675 navType() == t_eph::CNV2) {
676 out << QString(fmt)
677 .arg(_top, 19, 'e', 12)
678 .arg(_Cic, 19, 'e', 12)
679 .arg(_OMEGA0, 19, 'e', 12)
680 .arg(_Cis, 19, 'e', 12);
681 }
682 else {
683 out << QString(fmt)
684 .arg(_TOEsec, 19, 'e', 12)
685 .arg(_Cic, 19, 'e', 12)
686 .arg(_OMEGA0, 19, 'e', 12)
687 .arg(_Cis, 19, 'e', 12);
688 }
689 // =====================
690 // BROADCAST ORBIT - 4
691 // =====================
692 out << QString(fmt)
693 .arg(_i0, 19, 'e', 12)
694 .arg(_Crc, 19, 'e', 12)
695 .arg(_omega, 19, 'e', 12)
696 .arg(_OMEGADOT, 19, 'e', 12);
697 // =====================
698 // BROADCAST ORBIT - 5
699 // =====================
700 if (type() == t_eph::IRNSS) {
701 out << QString(fmt)
702 .arg(_IDOT, 19, 'e', 12)
703 .arg(0.0, 19, 'e', 12)
704 .arg(_TOEweek, 19, 'e', 12)
705 .arg(0.0, 19, 'e', 12);
706 }
707 else {
708 if (navType() == t_eph::CNAV ||
709 navType() == t_eph::CNV2) {
710 out << QString(fmt)
711 .arg(_IDOT, 19, 'e', 12)
712 .arg(_DN0DOT, 19, 'e', 12)
713 .arg(_URAI_NED0, 19, 'e', 12)
714 .arg(_URAI_NED1, 19, 'e', 12);
715
716 }
717 else { // LNAV, undefined
718 out << QString(fmt)
719 .arg(_IDOT, 19, 'e', 12)
720 .arg(_L2Codes, 19, 'e', 12)
721 .arg(_TOEweek, 19, 'e', 12)
722 .arg(_L2PFlag, 19, 'e', 12);
723
724 }
725 }
726 // =====================
727 // BROADCAST ORBIT - 6
728 // =====================
729 if (type() == t_eph::IRNSS) {
730 out << QString(fmt)
731 .arg(_ura, 19, 'e', 12)
732 .arg(_health, 19, 'e', 12)
733 .arg(_TGD, 19, 'e', 12)
734 .arg(0.0, 19, 'e', 12);
735 }
736 else {
737 if (navType() == t_eph::CNAV ||
738 navType() == t_eph::CNV2) {
739 out << QString(fmt)
740 .arg(_URAI_ED, 19, 'e', 12)
741 .arg(_health, 19, 'e', 12)
742 .arg(_TGD, 19, 'e', 12)
743 .arg(_URAI_NED2,19, 'e', 12);
744
745 }
746 else { // LNAV, undefined
747 out << QString(fmt)
748 .arg(_ura, 19, 'e', 12)
749 .arg(_health, 19, 'e', 12)
750 .arg(_TGD, 19, 'e', 12)
751 .arg(_IODC, 19, 'e', 12);
752 }
753 }
754 // =====================
755 // BROADCAST ORBIT - 7
756 // =====================
757 if (navType() == t_eph::LNAV ||
758 navType() == t_eph::undefined) {
759
760 double tot = _TOT;
761 if (tot == 0.9999e9 && version < 3.0) {
762 tot = 0.0;
763 }
764 // fitInterval
765 if (type() == t_eph::IRNSS) {// not valid for IRNSS
766 out << QString(fmt)
767 .arg(tot, 19, 'e', 12)
768 .arg(0.0, 19, 'e', 12)
769 .arg("", 19, QChar(' '))
770 .arg("", 19, QChar(' '));
771 }
772 else {
773 // for GPS and QZSS in version 3.02 specified in hours
774 double fitIntervalRnx = _fitInterval;
775 // otherwise specified as flag
776 if (type() == t_eph::QZSS && version != 3.02) {
777 (_fitInterval == 2.0) ? fitIntervalRnx = 0.0 : fitIntervalRnx = 1.0;
778 }
779 out << QString(fmt)
780 .arg(tot, 19, 'e', 12)
781 .arg(fitIntervalRnx, 19, 'e', 12)
782 .arg("", 19, QChar(' '))
783 .arg("", 19, QChar(' '));
784 }
785 }
786 else if (navType() == t_eph::CNAV ||
787 navType() == t_eph::CNV2) {
788 out << QString(fmt)
789 .arg(_ISC_L1CA, 19, 'e', 12)
790 .arg(_ISC_L2C, 19, 'e', 12)
791 .arg(_ISC_L5I5, 19, 'e', 12)
792 .arg(_ISC_L5Q5, 19, 'e', 12);
793 }
794 // =====================
795 // BROADCAST ORBIT - 8
796 // =====================
797 if (navType() == t_eph::CNAV) {
798 out << QString(fmt)
799 .arg(_TOT, 19, 'e', 12)
800 .arg(_wnop, 19, 'e', 12)
801 .arg("", 19, QChar(' '))
802 .arg("", 19, QChar(' '));
803 }
804 else if (navType() == t_eph::CNV2) {
805 out << QString(fmt)
806 .arg(_ISC_L1Cd, 19, 'e', 12)
807 .arg(_ISC_L1Cp, 19, 'e', 12)
808 .arg("", 19, QChar(' '))
809 .arg("", 19, QChar(' '));
810 }
811
812 // =====================
813 // BROADCAST ORBIT - 9
814 // =====================
815 if (navType() == t_eph::CNV2) {
816 out << QString(fmt)
817 .arg(_TOT, 19, 'e', 12)
818 .arg(_wnop, 19, 'e', 12)
819 .arg("", 19, QChar(' '))
820 .arg("", 19, QChar(' '));
821 }
822
823 return rnxStr;
824}
825
826// Constructor
827//////////////////////////////////////////////////////////////////////////////
828t_ephGlo::t_ephGlo(double rnxVersion, const QStringList& lines) {
829
830 int nLines = 4;
831 if (rnxVersion >= 3.05) {
832 nLines += 1;
833 _flags_unknown = false;
834 }
835 else {
836 _M_delta_tau = 0.9999e9; // unknown
837 _M_FT = 1.5e1; // unknown
838 _flags_unknown = true;
839 }
840
841 if (lines.size() != nLines) {
842 _checkState = bad;
843 return;
844 }
845
846 // RINEX Format
847 // ------------
848 int fieldLen = 19;
849 double statusflags = 0.0;
850 double healthflags = 0.0;
851
852 int pos[4];
853 pos[0] = (rnxVersion <= 2.12) ? 3 : 4;
854 pos[1] = pos[0] + fieldLen;
855 pos[2] = pos[1] + fieldLen;
856 pos[3] = pos[2] + fieldLen;
857
858 // Read four lines
859 // ---------------
860 for (int iLine = 0; iLine < nLines; iLine++) {
861 QString line = lines[iLine];
862
863 if ( iLine == 0 ) {
864 QTextStream in(line.left(pos[1]).toLatin1());
865
866 int year, month, day, hour, min;
867 double sec;
868
869 QString prnStr, n;
870 in >> prnStr;
871 if (prnStr.size() == 1 && prnStr[0] == 'R') {
872 in >> n;
873 prnStr.append(n);
874 }
875 in >> year >> month >> day >> hour >> min >> sec;
876 if (prnStr.at(0) == 'R') {
877 _prn.set('R', prnStr.mid(1).toInt());
878 }
879 else {
880 _prn.set('R', prnStr.toInt());
881 }
882
883 if (year < 80) {
884 year += 2000;
885 }
886 else if (year < 100) {
887 year += 1900;
888 }
889
890 _gps_utc = gnumleap(year, month, day);
891
892 _TOC.set(year, month, day, hour, min, sec);
893 _TOC = _TOC + _gps_utc;
894 int nd = int((_TOC.gpssec())) / (24.0*60.0*60.0);
895 if ( readDbl(line, pos[1], fieldLen, _tau ) ||
896 readDbl(line, pos[2], fieldLen, _gamma) ||
897 readDbl(line, pos[3], fieldLen, _tki ) ) {
898 _checkState = bad;
899 return;
900 }
901 _tki -= nd * 86400.0;
902 _tau = -_tau;
903 }
904
905 else if ( iLine == 1 ) {
906 if ( readDbl(line, pos[0], fieldLen, _x_pos ) ||
907 readDbl(line, pos[1], fieldLen, _x_velocity ) ||
908 readDbl(line, pos[2], fieldLen, _x_acceleration) ||
909 readDbl(line, pos[3], fieldLen, _health ) ) {
910 _checkState = bad;
911 return;
912 }
913 }
914
915 else if ( iLine == 2 ) {
916 if ( readDbl(line, pos[0], fieldLen, _y_pos ) ||
917 readDbl(line, pos[1], fieldLen, _y_velocity ) ||
918 readDbl(line, pos[2], fieldLen, _y_acceleration ) ||
919 readDbl(line, pos[3], fieldLen, _frequency_number) ) {
920 _checkState = bad;
921 return;
922 }
923 }
924
925 else if ( iLine == 3 ) {
926 if ( readDbl(line, pos[0], fieldLen, _z_pos ) ||
927 readDbl(line, pos[1], fieldLen, _z_velocity ) ||
928 readDbl(line, pos[2], fieldLen, _z_acceleration) ||
929 readDbl(line, pos[3], fieldLen, _E ) ) {
930 _checkState = bad;
931 return;
932 }
933 }
934
935 else if ( iLine == 4 ) {
936 if ( readDbl(line, pos[0], fieldLen, statusflags ) ||
937 readDbl(line, pos[1], fieldLen, _M_delta_tau ) ||
938 readDbl(line, pos[2], fieldLen, _M_FT ) ||
939 readDbl(line, pos[3], fieldLen, healthflags ) ) {
940 _checkState = bad;
941 return;
942 }
943 else {
944 // status flags
945 // ============
946 // bit 0-1
947 _M_P = double(bitExtracted(statusflags, 2, 0));
948 // bit 2-3
949 _P1 = double(bitExtracted(statusflags, 2, 2));
950 // bit 4
951 _P2 = double(bitExtracted(statusflags, 1, 4));
952 // bit 5
953 _P3 = double(bitExtracted(statusflags, 1, 5));
954 // bit 6
955 _M_P4 = double(bitExtracted(statusflags, 1, 6));
956 // bit 7-8
957 _M_M = double(bitExtracted(statusflags, 2, 7));
958 /// GLO M/K exclusive flags/values only valid if flag M is set to '01'
959 if (!_M_M) {
960 _M_P4 = 0.0;
961 _M_P = 0.0;
962 }
963 // health flags
964 // ============
965 // bit 0 (is to be ignored, if bit 1 is zero)
966 _almanac_health = double(bitExtracted(healthflags, 1, 0));
967 // bit 1
968 _almanac_health_availablility_indicator = double(bitExtracted(healthflags, 1, 1));
969 // bit 2
970 _M_l3 = double(bitExtracted(healthflags, 1, 2));
971 }
972 }
973 }
974
975 // Initialize status vector
976 // ------------------------
977 _tt = _TOC;
978 _xv.ReSize(6); _xv = 0.0;
979 _xv(1) = _x_pos * 1.e3;
980 _xv(2) = _y_pos * 1.e3;
981 _xv(3) = _z_pos * 1.e3;
982 _xv(4) = _x_velocity * 1.e3;
983 _xv(5) = _y_velocity * 1.e3;
984 _xv(6) = _z_velocity * 1.e3;
985}
986
987// Compute Glonass Satellite Position (virtual)
988////////////////////////////////////////////////////////////////////////////
989t_irc t_ephGlo::position(int GPSweek, double GPSweeks, double* xc, double* vv) const {
990
991 static const double nominalStep = 10.0;
992
993 memset(xc, 0, 6*sizeof(double));
994 memset(vv, 0, 3*sizeof(double));
995
996 double dtPos = bncTime(GPSweek, GPSweeks) - _tt;
997
998 if (fabs(dtPos) > 24 * 3600.0) {
999 return failure;
1000 }
1001
1002 int nSteps = int(fabs(dtPos) / nominalStep) + 1;
1003 double step = dtPos / nSteps;
1004
1005 double acc[3];
1006 acc[0] = _x_acceleration * 1.e3;
1007 acc[1] = _y_acceleration * 1.e3;
1008 acc[2] = _z_acceleration * 1.e3;
1009
1010 for (int ii = 1; ii <= nSteps; ii++) {
1011 _xv = rungeKutta4(_tt.gpssec(), _xv, step, acc, glo_deriv);
1012 _tt = _tt + step;
1013 }
1014
1015 // Position and Velocity
1016 // ---------------------
1017 xc[0] = _xv(1);
1018 xc[1] = _xv(2);
1019 xc[2] = _xv(3);
1020
1021 vv[0] = _xv(4);
1022 vv[1] = _xv(5);
1023 vv[2] = _xv(6);
1024
1025 // Clock Correction
1026 // ----------------
1027 double dtClk = bncTime(GPSweek, GPSweeks) - _TOC;
1028 xc[3] = -_tau + _gamma * dtClk;
1029
1030 xc[4] = _gamma;
1031 xc[5] = 0.0;
1032
1033 return success;
1034}
1035
1036// RINEX Format String
1037//////////////////////////////////////////////////////////////////////////////
1038QString t_ephGlo::toString(double version) const {
1039
1040 QString navStr = navTypeString(_navType, _prn, version);
1041 QString rnxStr = navStr + rinexDateStr(_TOC -_gps_utc, _prn, version);
1042 int nd = int((_TOC - _gps_utc).gpssec()) / (24.0*60.0*60.0);
1043 QTextStream out(&rnxStr);
1044
1045 out << QString("%1%2%3\n")
1046 .arg(-_tau, 19, 'e', 12)
1047 .arg(_gamma, 19, 'e', 12)
1048 .arg(_tki+nd*86400.0, 19, 'e', 12);
1049
1050 QString fmt = version < 3.0 ? " %1%2%3%4\n" : " %1%2%3%4\n";
1051
1052 out << QString(fmt)
1053 .arg(_x_pos, 19, 'e', 12)
1054 .arg(_x_velocity, 19, 'e', 12)
1055 .arg(_x_acceleration, 19, 'e', 12)
1056 .arg(_health, 19, 'e', 12);
1057
1058 out << QString(fmt)
1059 .arg(_y_pos, 19, 'e', 12)
1060 .arg(_y_velocity, 19, 'e', 12)
1061 .arg(_y_acceleration, 19, 'e', 12)
1062 .arg(_frequency_number, 19, 'e', 12);
1063
1064 out << QString(fmt)
1065 .arg(_z_pos, 19, 'e', 12)
1066 .arg(_z_velocity, 19, 'e', 12)
1067 .arg(_z_acceleration, 19, 'e', 12)
1068 .arg(_E, 19, 'e', 12);
1069
1070 if (version >= 3.05) {
1071 // unknown (RINEX version < 3.05)
1072 if (_flags_unknown) {
1073 out << QString(fmt)
1074 .arg("", 19, QChar(' ')) // statusflags blank if unknown
1075 .arg(_M_delta_tau, 19, 'e', 12)
1076 .arg(_M_FT, 19, 'e', 12)
1077 .arg("", 19, QChar(' ')); // healthflags blank if unknown
1078 }
1079 else {
1080 int statusflags = 0;
1081 // bit 7-8
1082 if (_M_M == 2.0) {
1083 statusflags |= (1<<7);
1084 }
1085 // bit 6
1086 if (_M_P4) {
1087 statusflags |= (1<<6);
1088 }
1089 // bit 5
1090 if (_P3) {
1091 statusflags |= (1<<5);
1092 }
1093 // bit 4
1094 if (_P2) {
1095 statusflags |= (1<<4);
1096 }
1097 // bit 2-3
1098 if (_P1 == 2.0) {
1099 statusflags |= (1<<2);
1100 }
1101 else if (_P1 == 1.0) {
1102 statusflags |= (1<<3);
1103 }
1104 else if (_P1 == 3.0) {
1105 statusflags |= (1<<2);
1106 statusflags |= (1<<3);
1107 }
1108 // bit 0-1
1109 if (_M_P == 2.0) {
1110 statusflags |= (1<<0);
1111 }
1112 else if (_M_P == 1.0) {
1113 statusflags |= (1<<1);
1114 }
1115 else if (_M_P == 3.0) {
1116 statusflags |= (1<<0);
1117 statusflags |= (1<<1);
1118 }
1119 // health flags
1120 // ============
1121 int healthflags = 0;
1122 // bit 0 (is to be ignored, if bit 1 is zero)
1123 if (_almanac_health) {
1124 healthflags |= (1<<0);
1125 }
1126 // bit 1
1127 if (_almanac_health_availablility_indicator) {
1128 healthflags |= (1<<1);
1129 }
1130 // bit 2
1131 if (_M_l3) {
1132 healthflags |= (1<<2);
1133 }
1134 out << QString(fmt)
1135 .arg(double(statusflags), 19, 'e', 12)
1136 .arg(_M_delta_tau, 19, 'e', 12)
1137 .arg(_M_FT, 19, 'e', 12)
1138 .arg(double(healthflags), 19, 'e', 12);
1139 }
1140 }
1141
1142 return rnxStr;
1143}
1144
1145// Derivative of the state vector using a simple force model (static)
1146////////////////////////////////////////////////////////////////////////////
1147ColumnVector t_ephGlo::glo_deriv(double /* tt */, const ColumnVector& xv,
1148 double* acc) {
1149
1150 // State vector components
1151 // -----------------------
1152 ColumnVector rr = xv.rows(1,3);
1153 ColumnVector vv = xv.rows(4,6);
1154
1155 // Acceleration
1156 // ------------
1157 static const double gmWGS = 398.60044e12;
1158 static const double AE = 6378136.0;
1159 static const double OMEGA = 7292115.e-11;
1160 static const double C20 = -1082.6257e-6;
1161
1162 double rho = rr.NormFrobenius();
1163 double t1 = -gmWGS/(rho*rho*rho);
1164 double t2 = 3.0/2.0 * C20 * (gmWGS*AE*AE) / (rho*rho*rho*rho*rho);
1165 double t3 = OMEGA * OMEGA;
1166 double t4 = 2.0 * OMEGA;
1167 double z2 = rr(3) * rr(3);
1168
1169 // Vector of derivatives
1170 // ---------------------
1171 ColumnVector va(6);
1172 va(1) = vv(1);
1173 va(2) = vv(2);
1174 va(3) = vv(3);
1175 va(4) = (t1 + t2*(1.0-5.0*z2/(rho*rho)) + t3) * rr(1) + t4*vv(2) + acc[0];
1176 va(5) = (t1 + t2*(1.0-5.0*z2/(rho*rho)) + t3) * rr(2) - t4*vv(1) + acc[1];
1177 va(6) = (t1 + t2*(3.0-5.0*z2/(rho*rho)) ) * rr(3) + acc[2];
1178
1179 return va;
1180}
1181
1182// IOD of Glonass Ephemeris (virtual)
1183////////////////////////////////////////////////////////////////////////////
1184unsigned int t_ephGlo::IOD() const {
1185 bncTime tMoscow = _TOC - _gps_utc + 3 * 3600.0;
1186 return (unsigned long)tMoscow.daysec() / 900;
1187}
1188
1189// Health status of Glonass Ephemeris (virtual)
1190////////////////////////////////////////////////////////////////////////////
1191unsigned int t_ephGlo::isUnhealthy() const {
1192
1193 if (_almanac_health_availablility_indicator) {
1194 if ((_health == 0 && _almanac_health == 0) ||
1195 (_health == 1 && _almanac_health == 0) ||
1196 (_health == 1 && _almanac_health == 1)) {
1197 return 1;
1198 }
1199 }
1200 else if (!_almanac_health_availablility_indicator) {
1201 if (_health) {
1202 return 1;
1203 }
1204 }
1205 return 0; /* (_health == 0 && _almanac_health == 1) or (_health == 0) */
1206}
1207
1208// Constructor
1209//////////////////////////////////////////////////////////////////////////////
1210t_ephGal::t_ephGal(double rnxVersion, const QStringList& lines) {
1211 int year, month, day, hour, min;
1212 double sec;
1213 QString prnStr;
1214 const int nLines = 8;
1215 if (lines.size() != nLines) {
1216 _checkState = bad;
1217 return;
1218 }
1219
1220 // RINEX Format
1221 // ------------
1222 int fieldLen = 19;
1223 double SVhealth = 0.0;
1224 double datasource = 0.0;
1225
1226 int pos[4];
1227 pos[0] = (rnxVersion <= 2.12) ? 3 : 4;
1228 pos[1] = pos[0] + fieldLen;
1229 pos[2] = pos[1] + fieldLen;
1230 pos[3] = pos[2] + fieldLen;
1231
1232 // Read eight lines
1233 // ----------------
1234 for (int iLine = 0; iLine < nLines; iLine++) {
1235 QString line = lines[iLine];
1236
1237 if ( iLine == 0 ) {
1238 QTextStream in(line.left(pos[1]).toLatin1());
1239 QString n;
1240 in >> prnStr;
1241 if (prnStr.size() == 1 && prnStr[0] == 'E') {
1242 in >> n;
1243 prnStr.append(n);
1244 }
1245 in >> year >> month >> day >> hour >> min >> sec;
1246 if (year < 80) {
1247 year += 2000;
1248 }
1249 else if (year < 100) {
1250 year += 1900;
1251 }
1252
1253 _TOC.set(year, month, day, hour, min, sec);
1254
1255 if ( readDbl(line, pos[1], fieldLen, _clock_bias ) ||
1256 readDbl(line, pos[2], fieldLen, _clock_drift ) ||
1257 readDbl(line, pos[3], fieldLen, _clock_driftrate) ) {
1258 _checkState = bad;
1259 return;
1260 }
1261 }
1262
1263 else if ( iLine == 1 ) {
1264 if ( readDbl(line, pos[0], fieldLen, _IODnav ) ||
1265 readDbl(line, pos[1], fieldLen, _Crs ) ||
1266 readDbl(line, pos[2], fieldLen, _Delta_n) ||
1267 readDbl(line, pos[3], fieldLen, _M0 ) ) {
1268 _checkState = bad;
1269 return;
1270 }
1271 }
1272
1273 else if ( iLine == 2 ) {
1274 if ( readDbl(line, pos[0], fieldLen, _Cuc ) ||
1275 readDbl(line, pos[1], fieldLen, _e ) ||
1276 readDbl(line, pos[2], fieldLen, _Cus ) ||
1277 readDbl(line, pos[3], fieldLen, _sqrt_A) ) {
1278 _checkState = bad;
1279 return;
1280 }
1281 }
1282
1283 else if ( iLine == 3 ) {
1284 if ( readDbl(line, pos[0], fieldLen, _TOEsec) ||
1285 readDbl(line, pos[1], fieldLen, _Cic ) ||
1286 readDbl(line, pos[2], fieldLen, _OMEGA0) ||
1287 readDbl(line, pos[3], fieldLen, _Cis ) ) {
1288 _checkState = bad;
1289 return;
1290 }
1291 }
1292
1293 else if ( iLine == 4 ) {
1294 if ( readDbl(line, pos[0], fieldLen, _i0 ) ||
1295 readDbl(line, pos[1], fieldLen, _Crc ) ||
1296 readDbl(line, pos[2], fieldLen, _omega ) ||
1297 readDbl(line, pos[3], fieldLen, _OMEGADOT) ) {
1298 _checkState = bad;
1299 return;
1300 }
1301 }
1302
1303 else if ( iLine == 5 ) {
1304 if ( readDbl(line, pos[0], fieldLen, _IDOT ) ||
1305 readDbl(line, pos[1], fieldLen, datasource) ||
1306 readDbl(line, pos[2], fieldLen, _TOEweek ) ) {
1307 _checkState = bad;
1308 return;
1309 } else {
1310 if (int(datasource) & (1<<8)) {
1311 _fnav = true;
1312 _inav = false;
1313 } else if (int(datasource) & (1<<9)) {
1314 _fnav = false;
1315 _inav = true;
1316 }
1317 _TOEweek -= 1024.0;
1318 }
1319 }
1320
1321 else if ( iLine == 6 ) {
1322 if ( readDbl(line, pos[0], fieldLen, _SISA ) ||
1323 readDbl(line, pos[1], fieldLen, SVhealth) ||
1324 readDbl(line, pos[2], fieldLen, _BGD_1_5A) ||
1325 readDbl(line, pos[3], fieldLen, _BGD_1_5B) ) {
1326 _checkState = bad;
1327 return;
1328 } else {
1329 // Bit 0
1330 _e1DataInValid = (int(SVhealth) & (1<<0));
1331 // Bit 1-2
1332 _E1_bHS = double((int(SVhealth) >> 1) & 0x3);
1333 // Bit 3
1334 _e5aDataInValid = (int(SVhealth) & (1<<3));
1335 // Bit 4-5
1336 _E5aHS = double((int(SVhealth) >> 4) & 0x3);
1337 // Bit 6
1338 _e5bDataInValid = (int(SVhealth) & (1<<6));
1339 // Bit 7-8
1340 _E5bHS = double((int(SVhealth) >> 7) & 0x3);
1341
1342 if (prnStr.at(0) == 'E') {
1343 _prn.set('E', prnStr.mid(1).toInt(), _inav ? 1 : 0);
1344 }
1345 }
1346 }
1347
1348 else if ( iLine == 7 ) {
1349 if ( readDbl(line, pos[0], fieldLen, _TOT) ) {
1350 _checkState = bad;
1351 return;
1352 }
1353 }
1354 }
1355}
1356
1357// Compute Galileo Satellite Position (virtual)
1358////////////////////////////////////////////////////////////////////////////
1359t_irc t_ephGal::position(int GPSweek, double GPSweeks, double* xc, double* vv) const {
1360
1361 static const double omegaEarth = 7292115.1467e-11;
1362 static const double gmWGS = 398.6004418e12;
1363
1364 memset(xc, 0, 6*sizeof(double));
1365 memset(vv, 0, 3*sizeof(double));
1366
1367 double a0 = _sqrt_A * _sqrt_A;
1368 if (a0 == 0) {
1369 return failure;
1370 }
1371
1372 double n0 = sqrt(gmWGS/(a0*a0*a0));
1373
1374 bncTime tt(GPSweek, GPSweeks);
1375 double tk = tt - bncTime(_TOC.gpsw(), _TOEsec);
1376
1377 double n = n0 + _Delta_n;
1378 double M = _M0 + n*tk;
1379 double E = M;
1380 double E_last;
1381 int nLoop = 0;
1382 do {
1383 E_last = E;
1384 E = M + _e*sin(E);
1385
1386 if (++nLoop == 100) {
1387 return failure;
1388 }
1389 } while ( fabs(E-E_last)*a0 > 0.001 );
1390 double v = 2.0*atan( sqrt( (1.0 + _e)/(1.0 - _e) )*tan( E/2 ) );
1391 double u0 = v + _omega;
1392 double sin2u0 = sin(2*u0);
1393 double cos2u0 = cos(2*u0);
1394 double r = a0*(1 - _e*cos(E)) + _Crc*cos2u0 + _Crs*sin2u0;
1395 double i = _i0 + _IDOT*tk + _Cic*cos2u0 + _Cis*sin2u0;
1396 double u = u0 + _Cuc*cos2u0 + _Cus*sin2u0;
1397 double xp = r*cos(u);
1398 double yp = r*sin(u);
1399 double OM = _OMEGA0 + (_OMEGADOT - omegaEarth)*tk -
1400 omegaEarth*_TOEsec;
1401
1402 double sinom = sin(OM);
1403 double cosom = cos(OM);
1404 double sini = sin(i);
1405 double cosi = cos(i);
1406 xc[0] = xp*cosom - yp*cosi*sinom;
1407 xc[1] = xp*sinom + yp*cosi*cosom;
1408 xc[2] = yp*sini;
1409
1410 double tc = tt - _TOC;
1411 xc[3] = _clock_bias + _clock_drift*tc + _clock_driftrate*tc*tc;
1412
1413 // Velocity
1414 // --------
1415 double tanv2 = tan(v/2);
1416 double dEdM = 1 / (1 - _e*cos(E));
1417 double dotv = sqrt((1.0 + _e)/(1.0 - _e)) / cos(E/2)/cos(E/2) / (1 + tanv2*tanv2)
1418 * dEdM * n;
1419 double dotu = dotv + (-_Cuc*sin2u0 + _Cus*cos2u0)*2*dotv;
1420 double dotom = _OMEGADOT - omegaEarth;
1421 double doti = _IDOT + (-_Cic*sin2u0 + _Cis*cos2u0)*2*dotv;
1422 double dotr = a0 * _e*sin(E) * dEdM * n
1423 + (-_Crc*sin2u0 + _Crs*cos2u0)*2*dotv;
1424 double dotx = dotr*cos(u) - r*sin(u)*dotu;
1425 double doty = dotr*sin(u) + r*cos(u)*dotu;
1426
1427 vv[0] = cosom *dotx - cosi*sinom *doty // dX / dr
1428 - xp*sinom*dotom - yp*cosi*cosom*dotom // dX / dOMEGA
1429 + yp*sini*sinom*doti; // dX / di
1430
1431 vv[1] = sinom *dotx + cosi*cosom *doty
1432 + xp*cosom*dotom - yp*cosi*sinom*dotom
1433 - yp*sini*cosom*doti;
1434
1435 vv[2] = sini *doty + yp*cosi *doti;
1436
1437 // Relativistic Correction
1438 // -----------------------
1439 xc[3] -= 4.442807309e-10 * _e * sqrt(a0) *sin(E);
1440
1441 xc[4] = _clock_drift + _clock_driftrate*tc;
1442 xc[5] = _clock_driftrate;
1443
1444 return success;
1445}
1446
1447// Health status of Galileo Ephemeris (virtual)
1448////////////////////////////////////////////////////////////////////////////
1449unsigned int t_ephGal::isUnhealthy() const {
1450 if (_E5aHS && _E5bHS && _E1_bHS) {
1451 return 1;
1452 }
1453 return 0;
1454}
1455
1456// RINEX Format String
1457//////////////////////////////////////////////////////////////////////////////
1458QString t_ephGal::toString(double version) const {
1459
1460 QString navStr = navTypeString(_navType, _prn, version);
1461 QString rnxStr = navStr + rinexDateStr(_TOC, _prn, version);
1462
1463 QTextStream out(&rnxStr);
1464
1465 out << QString("%1%2%3\n")
1466 .arg(_clock_bias, 19, 'e', 12)
1467 .arg(_clock_drift, 19, 'e', 12)
1468 .arg(_clock_driftrate, 19, 'e', 12);
1469
1470 QString fmt = version < 3.0 ? " %1%2%3%4\n" : " %1%2%3%4\n";
1471
1472 out << QString(fmt)
1473 .arg(_IODnav, 19, 'e', 12)
1474 .arg(_Crs, 19, 'e', 12)
1475 .arg(_Delta_n, 19, 'e', 12)
1476 .arg(_M0, 19, 'e', 12);
1477
1478 out << QString(fmt)
1479 .arg(_Cuc, 19, 'e', 12)
1480 .arg(_e, 19, 'e', 12)
1481 .arg(_Cus, 19, 'e', 12)
1482 .arg(_sqrt_A, 19, 'e', 12);
1483
1484 out << QString(fmt)
1485 .arg(_TOEsec, 19, 'e', 12)
1486 .arg(_Cic, 19, 'e', 12)
1487 .arg(_OMEGA0, 19, 'e', 12)
1488 .arg(_Cis, 19, 'e', 12);
1489
1490 out << QString(fmt)
1491 .arg(_i0, 19, 'e', 12)
1492 .arg(_Crc, 19, 'e', 12)
1493 .arg(_omega, 19, 'e', 12)
1494 .arg(_OMEGADOT, 19, 'e', 12);
1495
1496 int dataSource = 0;
1497 int SVhealth = 0;
1498 double BGD_1_5A = _BGD_1_5A;
1499 double BGD_1_5B = _BGD_1_5B;
1500 if (_fnav) {
1501 dataSource |= (1<<1);
1502 dataSource |= (1<<8);
1503 BGD_1_5B = 0.0;
1504 // SVhealth
1505 // Bit 3 : E5a DVS
1506 if (_e5aDataInValid) {
1507 SVhealth |= (1<<3);
1508 }
1509 // Bit 4-5: E5a HS
1510 if (_E5aHS == 1.0) {
1511 SVhealth |= (1<<4);
1512 }
1513 else if (_E5aHS == 2.0) {
1514 SVhealth |= (1<<5);
1515 }
1516 else if (_E5aHS == 3.0) {
1517 SVhealth |= (1<<4);
1518 SVhealth |= (1<<5);
1519 }
1520 }
1521 else if(_inav) {
1522 // Bit 2 and 0 are set because from MT1046 the data source cannot be determined
1523 // and RNXv3.03 says both can be set if the navigation messages were merged
1524 dataSource |= (1<<0);
1525 dataSource |= (1<<2);
1526 dataSource |= (1<<9);
1527 // SVhealth
1528 // Bit 0 : E1-B DVS
1529 if (_e1DataInValid) {
1530 SVhealth |= (1<<0);
1531 }
1532 // Bit 1-2: E1-B HS
1533 if (_E1_bHS == 1.0) {
1534 SVhealth |= (1<<1);
1535 }
1536 else if (_E1_bHS == 2.0) {
1537 SVhealth |= (1<<2);
1538 }
1539 else if (_E1_bHS == 3.0) {
1540 SVhealth |= (1<<1);
1541 SVhealth |= (1<<2);
1542 }
1543 // Bit 3 : E5a DVS
1544 if (_e5aDataInValid) {
1545 SVhealth |= (1<<3);
1546 }
1547 // Bit 4-5: E5a HS
1548 if (_E5aHS == 1.0) {
1549 SVhealth |= (1<<4);
1550 }
1551 else if (_E5aHS == 2.0) {
1552 SVhealth |= (1<<5);
1553 }
1554 else if (_E5aHS == 3.0) {
1555 SVhealth |= (1<<4);
1556 SVhealth |= (1<<5);
1557 }
1558 // Bit 6 : E5b DVS
1559 if (_e5bDataInValid) {
1560 SVhealth |= (1<<6);
1561 }
1562 // Bit 7-8: E5b HS
1563 if (_E5bHS == 1.0) {
1564 SVhealth |= (1<<7);
1565 }
1566 else if (_E5bHS == 2.0) {
1567 SVhealth |= (1<<8);
1568 }
1569 else if (_E5bHS == 3.0) {
1570 SVhealth |= (1<<7);
1571 SVhealth |= (1<<8);
1572 }
1573 }
1574
1575 out << QString(fmt)
1576 .arg(_IDOT, 19, 'e', 12)
1577 .arg(double(dataSource), 19, 'e', 12)
1578 .arg(_TOEweek + 1024.0, 19, 'e', 12)
1579 .arg(0.0, 19, 'e', 12);
1580
1581 out << QString(fmt)
1582 .arg(_SISA, 19, 'e', 12)
1583 .arg(double(SVhealth), 19, 'e', 12)
1584 .arg(BGD_1_5A, 19, 'e', 12)
1585 .arg(BGD_1_5B, 19, 'e', 12);
1586
1587 double tot = _TOT;
1588 if (tot == 0.9999e9 && version < 3.0) {
1589 tot = 0.0;
1590 }
1591 out << QString(fmt)
1592 .arg(tot, 19, 'e', 12)
1593 .arg("", 19, QChar(' '))
1594 .arg("", 19, QChar(' '))
1595 .arg("", 19, QChar(' '));
1596
1597 return rnxStr;
1598}
1599
1600// Constructor
1601//////////////////////////////////////////////////////////////////////////////
1602t_ephSBAS::t_ephSBAS(double rnxVersion, const QStringList& lines) {
1603
1604 const int nLines = 4;
1605
1606 if (lines.size() != nLines) {
1607 _checkState = bad;
1608 return;
1609 }
1610
1611 // RINEX Format
1612 // ------------
1613 int fieldLen = 19;
1614
1615 int pos[4];
1616 pos[0] = (rnxVersion <= 2.12) ? 3 : 4;
1617 pos[1] = pos[0] + fieldLen;
1618 pos[2] = pos[1] + fieldLen;
1619 pos[3] = pos[2] + fieldLen;
1620
1621 // Read four lines
1622 // ---------------
1623 for (int iLine = 0; iLine < nLines; iLine++) {
1624 QString line = lines[iLine];
1625
1626 if ( iLine == 0 ) {
1627 QTextStream in(line.left(pos[1]).toLatin1());
1628
1629 int year, month, day, hour, min;
1630 double sec;
1631
1632 QString prnStr, n;
1633 in >> prnStr;
1634 if (prnStr.size() == 1 && prnStr[0] == 'S') {
1635 in >> n;
1636 prnStr.append(n);
1637 }
1638 in >> year >> month >> day >> hour >> min >> sec;
1639 if (prnStr.at(0) == 'S') {
1640 _prn.set('S', prnStr.mid(1).toInt());
1641 }
1642 else {
1643 _prn.set('S', prnStr.toInt());
1644 }
1645
1646 if (year < 80) {
1647 year += 2000;
1648 }
1649 else if (year < 100) {
1650 year += 1900;
1651 }
1652
1653 _TOC.set(year, month, day, hour, min, sec);
1654
1655 if ( readDbl(line, pos[1], fieldLen, _agf0 ) ||
1656 readDbl(line, pos[2], fieldLen, _agf1 ) ||
1657 readDbl(line, pos[3], fieldLen, _TOT ) ) {
1658 _checkState = bad;
1659 return;
1660 }
1661 }
1662
1663 else if ( iLine == 1 ) {
1664 if ( readDbl(line, pos[0], fieldLen, _x_pos ) ||
1665 readDbl(line, pos[1], fieldLen, _x_velocity ) ||
1666 readDbl(line, pos[2], fieldLen, _x_acceleration) ||
1667 readDbl(line, pos[3], fieldLen, _health ) ) {
1668 _checkState = bad;
1669 return;
1670 }
1671 }
1672
1673 else if ( iLine == 2 ) {
1674 if ( readDbl(line, pos[0], fieldLen, _y_pos ) ||
1675 readDbl(line, pos[1], fieldLen, _y_velocity ) ||
1676 readDbl(line, pos[2], fieldLen, _y_acceleration ) ||
1677 readDbl(line, pos[3], fieldLen, _ura ) ) {
1678 _checkState = bad;
1679 return;
1680 }
1681 }
1682
1683 else if ( iLine == 3 ) {
1684 double iodn;
1685 if ( readDbl(line, pos[0], fieldLen, _z_pos ) ||
1686 readDbl(line, pos[1], fieldLen, _z_velocity ) ||
1687 readDbl(line, pos[2], fieldLen, _z_acceleration) ||
1688 readDbl(line, pos[3], fieldLen, iodn ) ) {
1689 _checkState = bad;
1690 return;
1691 } else {
1692 _IODN = int(iodn);
1693 }
1694 }
1695 }
1696
1697 _x_pos *= 1.e3;
1698 _y_pos *= 1.e3;
1699 _z_pos *= 1.e3;
1700 _x_velocity *= 1.e3;
1701 _y_velocity *= 1.e3;
1702 _z_velocity *= 1.e3;
1703 _x_acceleration *= 1.e3;
1704 _y_acceleration *= 1.e3;
1705 _z_acceleration *= 1.e3;
1706}
1707
1708// IOD of SBAS Ephemeris (virtual)
1709////////////////////////////////////////////////////////////////////////////
1710
1711unsigned int t_ephSBAS::IOD() const {
1712 unsigned char buffer[80];
1713 int size = 0;
1714 int numbits = 0;
1715 long long bitbuffer = 0;
1716 unsigned char *startbuffer = buffer;
1717
1718 SBASADDBITSFLOAT(30, this->_x_pos, 0.08)
1719 SBASADDBITSFLOAT(30, this->_y_pos, 0.08)
1720 SBASADDBITSFLOAT(25, this->_z_pos, 0.4)
1721 SBASADDBITSFLOAT(17, this->_x_velocity, 0.000625)
1722 SBASADDBITSFLOAT(17, this->_y_velocity, 0.000625)
1723 SBASADDBITSFLOAT(18, this->_z_velocity, 0.004)
1724 SBASADDBITSFLOAT(10, this->_x_acceleration, 0.0000125)
1725 SBASADDBITSFLOAT(10, this->_y_acceleration, 0.0000125)
1726 SBASADDBITSFLOAT(10, this->_z_acceleration, 0.0000625)
1727 SBASADDBITSFLOAT(12, this->_agf0, 1.0/static_cast<double>(1<<30)/static_cast<double>(1<<1))
1728 SBASADDBITSFLOAT(8, this->_agf1, 1.0/static_cast<double>(1<<30)/static_cast<double>(1<<10))
1729 SBASADDBITS(5,0); // the last byte is filled by 0-bits to obtain a length of an integer multiple of 8
1730
1731 return CRC24(size, startbuffer);
1732}
1733
1734// Compute SBAS Satellite Position (virtual)
1735////////////////////////////////////////////////////////////////////////////
1736t_irc t_ephSBAS::position(int GPSweek, double GPSweeks, double* xc, double* vv) const {
1737
1738 bncTime tt(GPSweek, GPSweeks);
1739 double dt = tt - _TOC;
1740
1741 xc[0] = _x_pos + _x_velocity * dt + _x_acceleration * dt * dt / 2.0;
1742 xc[1] = _y_pos + _y_velocity * dt + _y_acceleration * dt * dt / 2.0;
1743 xc[2] = _z_pos + _z_velocity * dt + _z_acceleration * dt * dt / 2.0;
1744
1745 vv[0] = _x_velocity + _x_acceleration * dt;
1746 vv[1] = _y_velocity + _y_acceleration * dt;
1747 vv[2] = _z_velocity + _z_acceleration * dt;
1748
1749 xc[3] = _agf0 + _agf1 * dt;
1750
1751 xc[4] = _agf1;
1752 xc[5] = 0.0;
1753
1754 return success;
1755}
1756
1757// Health status of SBAS Ephemeris (virtual)
1758////////////////////////////////////////////////////////////////////////////
1759unsigned int t_ephSBAS::isUnhealthy() const {
1760
1761 // Bit 5
1762 bool URAindexIs15 = (int(_health) & (1<<5));
1763 if (URAindexIs15) {
1764 // in this case it is recommended
1765 // to set the bits 0,1,2,3 to 1 (MT17health = 15)
1766 return 1;
1767 }
1768
1769 // Bit 0-3
1770 int MT17health = (int(_health)) & (0x0f);
1771 if (MT17health) {
1772 return 1;
1773 }
1774
1775 // Bit 4
1776 // bool MT17HealthIsUnavailable = (int(_health) & (1<<4));
1777 // is not used because the MT17health bits can be independently set if URA index is 15
1778
1779 return 0;
1780}
1781
1782
1783// RINEX Format String
1784//////////////////////////////////////////////////////////////////////////////
1785QString t_ephSBAS::toString(double version) const {
1786
1787 QString navStr = navTypeString(_navType, _prn, version);
1788 QString rnxStr = navStr + rinexDateStr(_TOC, _prn, version);
1789
1790 QTextStream out(&rnxStr);
1791
1792 out << QString("%1%2%3\n")
1793 .arg(_agf0, 19, 'e', 12)
1794 .arg(_agf1, 19, 'e', 12)
1795 .arg(_TOT, 19, 'e', 12);
1796
1797 QString fmt = version < 3.0 ? " %1%2%3%4\n" : " %1%2%3%4\n";
1798
1799 out << QString(fmt)
1800 .arg(1.e-3*_x_pos, 19, 'e', 12)
1801 .arg(1.e-3*_x_velocity, 19, 'e', 12)
1802 .arg(1.e-3*_x_acceleration, 19, 'e', 12)
1803 .arg(_health, 19, 'e', 12);
1804
1805 out << QString(fmt)
1806 .arg(1.e-3*_y_pos, 19, 'e', 12)
1807 .arg(1.e-3*_y_velocity, 19, 'e', 12)
1808 .arg(1.e-3*_y_acceleration, 19, 'e', 12)
1809 .arg(_ura, 19, 'e', 12);
1810
1811 out << QString(fmt)
1812 .arg(1.e-3*_z_pos, 19, 'e', 12)
1813 .arg(1.e-3*_z_velocity, 19, 'e', 12)
1814 .arg(1.e-3*_z_acceleration, 19, 'e', 12)
1815 .arg(double(_IODN), 19, 'e', 12);
1816
1817 return rnxStr;
1818}
1819
1820// Constructor
1821//////////////////////////////////////////////////////////////////////////////
1822t_ephBDS::t_ephBDS(double rnxVersion, const QStringList& lines) {
1823
1824 const int nLines = 8;
1825
1826 if (lines.size() != nLines) {
1827 _checkState = bad;
1828 return;
1829 }
1830
1831 // RINEX Format
1832 // ------------
1833 int fieldLen = 19;
1834
1835 int pos[4];
1836 pos[0] = (rnxVersion <= 2.12) ? 3 : 4;
1837 pos[1] = pos[0] + fieldLen;
1838 pos[2] = pos[1] + fieldLen;
1839 pos[3] = pos[2] + fieldLen;
1840
1841 // Read eight lines
1842 // ----------------
1843 for (int iLine = 0; iLine < nLines; iLine++) {
1844 QString line = lines[iLine];
1845
1846 if ( iLine == 0 ) {
1847 QTextStream in(line.left(pos[1]).toLatin1());
1848
1849 int year, month, day, hour, min;
1850 double sec;
1851
1852 QString prnStr, n;
1853 in >> prnStr;
1854 if (prnStr.size() == 1 && prnStr[0] == 'C') {
1855 in >> n;
1856 prnStr.append(n);
1857 }
1858 in >> year >> month >> day >> hour >> min >> sec;
1859 if (prnStr.at(0) == 'C') {
1860 _prn.set('C', prnStr.mid(1).toInt());
1861 }
1862 else {
1863 _prn.set('C', prnStr.toInt());
1864 }
1865
1866 if (year < 80) {
1867 year += 2000;
1868 }
1869 else if (year < 100) {
1870 year += 1900;
1871 }
1872
1873 _TOC.setBDS(year, month, day, hour, min, sec);
1874
1875 if ( readDbl(line, pos[1], fieldLen, _clock_bias ) ||
1876 readDbl(line, pos[2], fieldLen, _clock_drift ) ||
1877 readDbl(line, pos[3], fieldLen, _clock_driftrate) ) {
1878 _checkState = bad;
1879 return;
1880 }
1881 }
1882
1883 else if ( iLine == 1 ) {
1884 double aode;
1885 if ( readDbl(line, pos[0], fieldLen, aode ) ||
1886 readDbl(line, pos[1], fieldLen, _Crs ) ||
1887 readDbl(line, pos[2], fieldLen, _Delta_n) ||
1888 readDbl(line, pos[3], fieldLen, _M0 ) ) {
1889 _checkState = bad;
1890 return;
1891 }
1892 _AODE = int(aode);
1893 }
1894
1895 else if ( iLine == 2 ) {
1896 if ( readDbl(line, pos[0], fieldLen, _Cuc ) ||
1897 readDbl(line, pos[1], fieldLen, _e ) ||
1898 readDbl(line, pos[2], fieldLen, _Cus ) ||
1899 readDbl(line, pos[3], fieldLen, _sqrt_A) ) {
1900 _checkState = bad;
1901 return;
1902 }
1903 }
1904
1905 else if ( iLine == 3 ) {
1906 if ( readDbl(line, pos[0], fieldLen, _TOEsec ) ||
1907 readDbl(line, pos[1], fieldLen, _Cic ) ||
1908 readDbl(line, pos[2], fieldLen, _OMEGA0) ||
1909 readDbl(line, pos[3], fieldLen, _Cis ) ) {
1910 _checkState = bad;
1911 return;
1912 }
1913 }
1914
1915 else if ( iLine == 4 ) {
1916 if ( readDbl(line, pos[0], fieldLen, _i0 ) ||
1917 readDbl(line, pos[1], fieldLen, _Crc ) ||
1918 readDbl(line, pos[2], fieldLen, _omega ) ||
1919 readDbl(line, pos[3], fieldLen, _OMEGADOT) ) {
1920 _checkState = bad;
1921 return;
1922 }
1923 }
1924
1925 else if ( iLine == 5 ) {
1926 if ( readDbl(line, pos[0], fieldLen, _IDOT ) ||
1927 readDbl(line, pos[2], fieldLen, _BDTweek)) {
1928 _checkState = bad;
1929 return;
1930 }
1931 }
1932
1933 else if ( iLine == 6 ) {
1934 double SatH1;
1935 if ( readDbl(line, pos[0], fieldLen, _URA ) ||
1936 readDbl(line, pos[1], fieldLen, SatH1) ||
1937 readDbl(line, pos[2], fieldLen, _TGD1) ||
1938 readDbl(line, pos[3], fieldLen, _TGD2) ) {
1939 _checkState = bad;
1940 return;
1941 }
1942 _SatH1 = int(SatH1);
1943 }
1944
1945 else if ( iLine == 7 ) {
1946 double aodc;
1947 if ( readDbl(line, pos[0], fieldLen, _TOT) ||
1948 readDbl(line, pos[1], fieldLen, aodc) ) {
1949 _checkState = bad;
1950 return;
1951 }
1952 if (_TOT == 0.9999e9) { // 0.9999e9 means not known (RINEX standard)
1953 _TOT = _TOEsec;
1954 }
1955 _AODC = int(aodc);
1956 }
1957 }
1958
1959 _TOE.setBDS(int(_BDTweek), _TOEsec);
1960
1961 // remark: actually should be computed from second_tot
1962 // but it seems to be unreliable in RINEX files
1963 //_TOT = _TOC.bdssec();
1964}
1965
1966// IOD of BDS Ephemeris (virtual)
1967////////////////////////////////////////////////////////////////////////////
1968unsigned int t_ephBDS::IOD() const {
1969 return (int(_TOEsec)/720) % 240;
1970}
1971
1972// Compute BDS Satellite Position (virtual)
1973//////////////////////////////////////////////////////////////////////////////
1974t_irc t_ephBDS::position(int GPSweek, double GPSweeks, double* xc, double* vv) const {
1975
1976 static const double gmBDS = 398.6004418e12;
1977 static const double omegaBDS = 7292115.0000e-11;
1978
1979 xc[0] = xc[1] = xc[2] = xc[3] = 0.0;
1980 vv[0] = vv[1] = vv[2] = 0.0;
1981
1982 bncTime tt(GPSweek, GPSweeks);
1983
1984 if (_sqrt_A == 0) {
1985 return failure;
1986 }
1987 double a0 = _sqrt_A * _sqrt_A;
1988
1989 double n0 = sqrt(gmBDS/(a0*a0*a0));
1990 double tk = tt - _TOE;
1991 double n = n0 + _Delta_n;
1992 double M = _M0 + n*tk;
1993 double E = M;
1994 double E_last;
1995 int nLoop = 0;
1996 do {
1997 E_last = E;
1998 E = M + _e*sin(E);
1999
2000 if (++nLoop == 100) {
2001 return failure;
2002 }
2003 } while ( fabs(E-E_last)*a0 > 0.001 );
2004
2005 double v = atan2(sqrt(1-_e*_e) * sin(E), cos(E) - _e);
2006 double u0 = v + _omega;
2007 double sin2u0 = sin(2*u0);
2008 double cos2u0 = cos(2*u0);
2009 double r = a0*(1 - _e*cos(E)) + _Crc*cos2u0 + _Crs*sin2u0;
2010 double i = _i0 + _IDOT*tk + _Cic*cos2u0 + _Cis*sin2u0;
2011 double u = u0 + _Cuc*cos2u0 + _Cus*sin2u0;
2012 double xp = r*cos(u);
2013 double yp = r*sin(u);
2014 double toesec = (_TOE.gpssec() - 14.0);
2015 double sinom = 0;
2016 double cosom = 0;
2017 double sini = 0;
2018 double cosi = 0;
2019
2020 // Velocity
2021 // --------
2022 double tanv2 = tan(v/2);
2023 double dEdM = 1 / (1 - _e*cos(E));
2024 double dotv = sqrt((1.0 + _e)/(1.0 - _e)) / cos(E/2)/cos(E/2)
2025 / (1 + tanv2*tanv2) * dEdM * n;
2026 double dotu = dotv + (-_Cuc*sin2u0 + _Cus*cos2u0)*2*dotv;
2027 double doti = _IDOT + (-_Cic*sin2u0 + _Cis*cos2u0)*2*dotv;
2028 double dotr = a0 * _e*sin(E) * dEdM * n
2029 + (-_Crc*sin2u0 + _Crs*cos2u0)*2*dotv;
2030
2031 double dotx = dotr*cos(u) - r*sin(u)*dotu;
2032 double doty = dotr*sin(u) + r*cos(u)*dotu;
2033
2034 const double iMaxGEO = 10.0 / 180.0 * M_PI;
2035
2036 // MEO/IGSO satellite
2037 // ------------------
2038 if (_i0 > iMaxGEO) {
2039 double OM = _OMEGA0 + (_OMEGADOT - omegaBDS)*tk - omegaBDS*toesec;
2040
2041 sinom = sin(OM);
2042 cosom = cos(OM);
2043 sini = sin(i);
2044 cosi = cos(i);
2045
2046 xc[0] = xp*cosom - yp*cosi*sinom;
2047 xc[1] = xp*sinom + yp*cosi*cosom;
2048 xc[2] = yp*sini;
2049
2050 // Velocity
2051 // --------
2052
2053 double dotom = _OMEGADOT - t_CST::omega;
2054
2055 vv[0] = cosom *dotx - cosi*sinom *doty // dX / dr
2056 - xp*sinom*dotom - yp*cosi*cosom*dotom // dX / dOMEGA
2057 + yp*sini*sinom*doti; // dX / di
2058
2059 vv[1] = sinom *dotx + cosi*cosom *doty
2060 + xp*cosom*dotom - yp*cosi*sinom*dotom
2061 - yp*sini*cosom*doti;
2062
2063 vv[2] = sini *doty + yp*cosi *doti;
2064
2065 }
2066
2067 // GEO satellite
2068 // -------------
2069 else {
2070 double OM = _OMEGA0 + _OMEGADOT*tk - omegaBDS*toesec;
2071 double ll = omegaBDS*tk;
2072
2073 sinom = sin(OM);
2074 cosom = cos(OM);
2075 sini = sin(i);
2076 cosi = cos(i);
2077
2078 double xx = xp*cosom - yp*cosi*sinom;
2079 double yy = xp*sinom + yp*cosi*cosom;
2080 double zz = yp*sini;
2081
2082 Matrix RX = BNC_PPP::t_astro::rotX(-5.0 / 180.0 * M_PI);
2083 Matrix RZ = BNC_PPP::t_astro::rotZ(ll);
2084
2085 ColumnVector X1(3); X1 << xx << yy << zz;
2086 ColumnVector X2 = RZ*RX*X1;
2087
2088 xc[0] = X2(1);
2089 xc[1] = X2(2);
2090 xc[2] = X2(3);
2091
2092 double dotom = _OMEGADOT;
2093
2094 double vx = cosom *dotx - cosi*sinom *doty
2095 - xp*sinom*dotom - yp*cosi*cosom*dotom
2096 + yp*sini*sinom*doti;
2097
2098 double vy = sinom *dotx + cosi*cosom *doty
2099 + xp*cosom*dotom - yp*cosi*sinom*dotom
2100 - yp*sini*cosom*doti;
2101
2102 double vz = sini *doty + yp*cosi *doti;
2103
2104 ColumnVector V(3); V << vx << vy << vz;
2105
2106 Matrix RdotZ(3,3);
2107 double C = cos(ll);
2108 double S = sin(ll);
2109 Matrix UU(3,3);
2110 UU[0][0] = -S; UU[0][1] = +C; UU[0][2] = 0.0;
2111 UU[1][0] = -C; UU[1][1] = -S; UU[1][2] = 0.0;
2112 UU[2][0] = 0.0; UU[2][1] = 0.0; UU[2][2] = 0.0;
2113 RdotZ = omegaBDS * UU;
2114
2115 ColumnVector VV(3);
2116 VV = RZ*RX*V + RdotZ*RX*X1;
2117
2118 vv[0] = VV(1);
2119 vv[1] = VV(2);
2120 vv[2] = VV(3);
2121 }
2122
2123 double tc = tt - _TOC;
2124 xc[3] = _clock_bias + _clock_drift*tc + _clock_driftrate*tc*tc;
2125
2126// dotC = _clock_drift + _clock_driftrate*tc
2127// - 4.442807309e-10*_e * sqrt(a0) * cos(E) * dEdM * n;
2128
2129 // Relativistic Correction
2130 // -----------------------
2131 xc[3] -= 4.442807309e-10 * _e * sqrt(a0) *sin(E);
2132
2133 xc[4] = _clock_drift + _clock_driftrate*tc;
2134 xc[5] = _clock_driftrate;
2135
2136 return success;
2137}
2138
2139// RINEX Format String
2140//////////////////////////////////////////////////////////////////////////////
2141QString t_ephBDS::toString(double version) const {
2142
2143 QString navStr = navTypeString(_navType, _prn, version);
2144 QString rnxStr = navStr + rinexDateStr(_TOC-14.0, _prn, version);
2145
2146 QTextStream out(&rnxStr);
2147
2148 out << QString("%1%2%3\n")
2149 .arg(_clock_bias, 19, 'e', 12)
2150 .arg(_clock_drift, 19, 'e', 12)
2151 .arg(_clock_driftrate, 19, 'e', 12);
2152
2153 QString fmt = version < 3.0 ? " %1%2%3%4\n" : " %1%2%3%4\n";
2154
2155 out << QString(fmt)
2156 .arg(double(_AODE), 19, 'e', 12)
2157 .arg(_Crs, 19, 'e', 12)
2158 .arg(_Delta_n, 19, 'e', 12)
2159 .arg(_M0, 19, 'e', 12);
2160
2161 out << QString(fmt)
2162 .arg(_Cuc, 19, 'e', 12)
2163 .arg(_e, 19, 'e', 12)
2164 .arg(_Cus, 19, 'e', 12)
2165 .arg(_sqrt_A, 19, 'e', 12);
2166
2167 out << QString(fmt)
2168 .arg(_TOEsec, 19, 'e', 12)
2169 .arg(_Cic, 19, 'e', 12)
2170 .arg(_OMEGA0, 19, 'e', 12)
2171 .arg(_Cis, 19, 'e', 12);
2172
2173 out << QString(fmt)
2174 .arg(_i0, 19, 'e', 12)
2175 .arg(_Crc, 19, 'e', 12)
2176 .arg(_omega, 19, 'e', 12)
2177 .arg(_OMEGADOT, 19, 'e', 12);
2178
2179 out << QString(fmt)
2180 .arg(_IDOT, 19, 'e', 12)
2181 .arg(0.0, 19, 'e', 12)
2182 .arg(_BDTweek, 19, 'e', 12)
2183 .arg(0.0, 19, 'e', 12);
2184
2185 out << QString(fmt)
2186 .arg(_URA, 19, 'e', 12)
2187 .arg(double(_SatH1), 19, 'e', 12)
2188 .arg(_TGD1, 19, 'e', 12)
2189 .arg(_TGD2, 19, 'e', 12);
2190
2191 double tots = 0.0;
2192 if (_receptDateTime.isValid()) {// RTCM stream input
2193 tots = _TOE.bdssec();
2194 }
2195 else { // RINEX input
2196 tots = _TOT;
2197 }
2198 out << QString(fmt)
2199 .arg(tots, 19, 'e', 12)
2200 .arg(double(_AODC), 19, 'e', 12)
2201 .arg("", 19, QChar(' '))
2202 .arg("", 19, QChar(' '));
2203 return rnxStr;
2204}
Note: See TracBrowser for help on using the repository browser.