source: ntrip/trunk/BNC/src/bncutils.cpp@ 10358

Last change on this file since 10358 was 10330, checked in by stuerze, 11 months ago

another test is added in PPP and combination mode to check if stored ephemerides were outdated and/or not updated in between

File size: 32.3 KB
RevLine 
[280]1// Part of BNC, a utility for retrieving decoding and
[464]2// converting GNSS data streams from NTRIP broadcasters.
[280]3//
[464]4// Copyright (C) 2007
[280]5// German Federal Agency for Cartography and Geodesy (BKG)
6// http://www.bkg.bund.de
[464]7// Czech Technical University Prague, Department of Geodesy
[280]8// http://www.fsv.cvut.cz
9//
10// Email: euref-ip@bkg.bund.de
11//
12// This program is free software; you can redistribute it and/or
13// modify it under the terms of the GNU General Public License
14// as published by the Free Software Foundation, version 2.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
[83]24
25/* -------------------------------------------------------------------------
[93]26 * BKG NTRIP Client
[83]27 * -------------------------------------------------------------------------
28 *
29 * Class: bncutils
30 *
31 * Purpose: Auxiliary Functions
32 *
33 * Author: L. Mervart
34 *
35 * Created: 30-Aug-2006
36 *
[7527]37 * Changes:
[83]38 *
39 * -----------------------------------------------------------------------*/
40
[124]41#include <iostream>
[218]42#include <ctime>
[221]43#include <math.h>
[124]44
[83]45#include <QRegExp>
46#include <QStringList>
[271]47#include <QDateTime>
[83]48
[5807]49#include <newmatap.h>
50
[83]51#include "bncutils.h"
[5070]52#include "bnccore.h"
[83]53
[124]54using namespace std;
55
[6812]56struct leapseconds { /* specify the day of leap second */
57 int day; /* this is the day, where 23:59:59 exists 2 times */
58 int month; /* not the next day! */
59 int year;
60 int taicount;
61};
62static const int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
63static const struct leapseconds leap[] = {
64/*{31, 12, 1971, 10},*/
65/*{30, 06, 1972, 11},*/
66/*{31, 12, 1972, 12},*/
67/*{31, 12, 1973, 13},*/
68/*{31, 12, 1974, 14},*/
69/*{31, 12, 1975, 15},*/
70/*{31, 12, 1976, 16},*/
71/*{31, 12, 1977, 17},*/
72/*{31, 12, 1978, 18},*/
73/*{31, 12, 1979, 19},*/
74{30, 06, 1981,20},
75{30, 06, 1982,21},
76{30, 06, 1983,22},
77{30, 06, 1985,23},
78{31, 12, 1987,24},
79{31, 12, 1989,25},
80{31, 12, 1990,26},
81{30, 06, 1992,27},
82{30, 06, 1993,28},
83{30, 06, 1994,29},
84{31, 12, 1995,30},
85{30, 06, 1997,31},
86{31, 12, 1998,32},
87{31, 12, 2005,33},
88{31, 12, 2008,34},
89{30, 06, 2012,35},
90{30, 06, 2015,36},
[9503]91{31, 12, 2016,37},
[6812]92{0,0,0,0} /* end marker */
93};
94
95#define GPSLEAPSTART 19 /* 19 leap seconds existed at 6.1.1980 */
96
97static int longyear(int year, int month)
98{
99 if(!(year % 4) && (!(year % 400) || (year % 100)))
100 {
101 if(!month || month == 2)
102 return 1;
103 }
104 return 0;
105}
106
107int gnumleap(int year, int month, int day)
108{
109 int ls = 0;
110 const struct leapseconds *l;
111
112 for(l = leap; l->taicount && year >= l->year; ++l)
113 {
114 if(year > l->year || month > l->month || (month == l->month && day > l->day))
115 ls = l->taicount - GPSLEAPSTART;
116 }
117 return ls;
118}
119
120/* Convert Moscow time into UTC (fixnumleap == 1) or GPS (fixnumleap == 0) */
121void updatetime(int *week, int *secOfWeek, int mSecOfWeek, bool fixnumleap)
122{
123 int y,m,d,k,l, nul;
124 unsigned int j = *week*(7*24*60*60) + *secOfWeek + 5*24*60*60+3*60*60;
125 int glo_daynumber = 0, glo_timeofday;
126 for(y = 1980; j >= (unsigned int)(k = (l = (365+longyear(y,0)))*24*60*60)
127 + gnumleap(y+1,1,1); ++y)
128 {
129 j -= k; glo_daynumber += l;
130 }
131 for(m = 1; j >= (unsigned int)(k = (l = months[m]+longyear(y, m))*24*60*60)
132 + gnumleap(y, m+1, 1); ++m)
133 {
134 j -= k; glo_daynumber += l;
135 }
136 for(d = 1; j >= 24UL*60UL*60UL + gnumleap(y, m, d+1); ++d)
137 j -= 24*60*60;
138 glo_daynumber -= 16*365+4-d;
139 nul = gnumleap(y, m, d);
140 glo_timeofday = j-nul;
141
142 // original version
143 // if(mSecOfWeek < 5*60*1000 && glo_timeofday > 23*60*60)
144 // *secOfWeek += 24*60*60;
145 // else if(glo_timeofday < 5*60 && mSecOfWeek > 23*60*60*1000)
146 // *secOfWeek -= 24*60*60;
147
[7527]148 // new version
[6812]149 if(mSecOfWeek < 4*60*60*1000 && glo_timeofday > 20*60*60)
150 *secOfWeek += 24*60*60;
151 else if(glo_timeofday < 4*60*60 && mSecOfWeek > 20*60*60*1000)
152 *secOfWeek -= 24*60*60;
153
154 *secOfWeek += mSecOfWeek/1000-glo_timeofday;
155 if(fixnumleap)
156 *secOfWeek -= nul;
157 if(*secOfWeek < 0) {*secOfWeek += 24*60*60*7; --*week; }
158 if(*secOfWeek >= 24*60*60*7) {*secOfWeek -= 24*60*60*7; ++*week; }
159}
160
[7527]161//
[1381]162////////////////////////////////////////////////////////////////////////////
[83]163void expandEnvVar(QString& str) {
164
165 QRegExp rx("(\\$\\{.+\\})");
166
167 if (rx.indexIn(str) != -1) {
168 QStringListIterator it(rx.capturedTexts());
169 if (it.hasNext()) {
170 QString rxStr = it.next();
171 QString envVar = rxStr.mid(2,rxStr.length()-3);
[8203]172 str.replace(rxStr, qgetenv(envVar.toLatin1()));
[83]173 }
174 }
175}
[124]176
[5910]177// Strip White Space
178////////////////////////////////////////////////////////////////////////////
179void stripWhiteSpace(string& str) {
180 if (!str.empty()) {
181 string::size_type beg = str.find_first_not_of(" \t\f\n\r\v");
182 string::size_type end = str.find_last_not_of(" \t\f\n\r\v");
183 if (beg > str.max_size())
184 str.erase();
185 else
186 str = str.substr(beg, end-beg+1);
187 }
188}
189
[7527]190//
[1381]191////////////////////////////////////////////////////////////////////////////
[124]192QDateTime dateAndTimeFromGPSweek(int GPSWeek, double GPSWeeks) {
193
194 static const QDate zeroEpoch(1980, 1, 6);
[7527]195
[124]196 QDate date(zeroEpoch);
197 QTime time(0,0,0,0);
198
199 int weekDays = int(GPSWeeks) / 86400;
200 date = date.addDays( GPSWeek * 7 + weekDays );
201 time = time.addMSecs( int( (GPSWeeks - 86400 * weekDays) * 1e3 ) );
202
203 return QDateTime(date,time);
204}
[210]205
[7527]206//
[1381]207////////////////////////////////////////////////////////////////////////////
[218]208void currentGPSWeeks(int& week, double& sec) {
[210]209
[1942]210 QDateTime currDateTimeGPS;
[1155]211
[5846]212 if ( BNC_CORE->dateAndTimeGPSSet() ) {
213 currDateTimeGPS = BNC_CORE->dateAndTimeGPS();
[1155]214 }
215 else {
[1942]216 currDateTimeGPS = QDateTime::currentDateTime().toUTC();
217 QDate hlp = currDateTimeGPS.date();
[7527]218 currDateTimeGPS = currDateTimeGPS.addSecs(gnumleap(hlp.year(),
[1942]219 hlp.month(), hlp.day()));
[1155]220 }
221
[1942]222 QDate currDateGPS = currDateTimeGPS.date();
223 QTime currTimeGPS = currDateTimeGPS.time();
[210]224
[1942]225 week = int( (double(currDateGPS.toJulianDay()) - 2444244.5) / 7 );
[1036]226
[7527]227 sec = (currDateGPS.dayOfWeek() % 7) * 24.0 * 3600.0 +
228 currTimeGPS.hour() * 3600.0 +
229 currTimeGPS.minute() * 60.0 +
[1942]230 currTimeGPS.second() +
231 currTimeGPS.msec() / 1000.0;
[1036]232}
[1154]233
[7527]234//
[1381]235////////////////////////////////////////////////////////////////////////////
[1154]236QDateTime currentDateAndTimeGPS() {
[5846]237 if ( BNC_CORE->dateAndTimeGPSSet() ) {
238 return BNC_CORE->dateAndTimeGPS();
[2530]239 }
240 else {
241 int GPSWeek;
242 double GPSWeeks;
243 currentGPSWeeks(GPSWeek, GPSWeeks);
244 return dateAndTimeFromGPSweek(GPSWeek, GPSWeeks);
245 }
[1154]246}
247
[7527]248//
[1381]249////////////////////////////////////////////////////////////////////////////
[8011]250bool checkForWrongObsEpoch(bncTime obsEpoch) {
251 const double maxDt = 600.0;
[8417]252 bncTime obsTime = obsEpoch;
[8011]253 int week;
254 double sec;
255 currentGPSWeeks(week, sec);
[8417]256 bncTime currTime(week, sec);
[8011]257
[8673]258 if (((currTime - obsTime) < 0.0) ||
259 (fabs(currTime - obsTime) > maxDt)) {
[8011]260 return true;
261 }
262 return false;
263}
[9245]264
[8011]265//
266////////////////////////////////////////////////////////////////////////////
[10330]267bool outDatedBcep(const t_eph *eph, bncTime tt) {
[9245]268 bncTime toc = eph->TOC();
[10330]269 double dt = tt -toc;
[9245]270
[9376]271 // update interval: 2h, data sets are valid for 4 hours
[9409]272 if (eph->type() == t_eph::GPS && (dt > 14400.0 || dt < -7200.0)) {
[9245]273 return true;
274 }
[9376]275 // update interval: 3h, data sets are valid for 4 hours
[9409]276 else if (eph->type() == t_eph::Galileo && (dt > 14400.0 || dt < 0.0)) {
[9245]277 return true;
278 }
[9362]279 // updated every 30 minutes + 5 min
[10330]280 else if (eph->type() == t_eph::GLONASS && (dt > 2100.0 || dt < -2100.0)) {
[9245]281 return true;
[9362]282 }
[9376]283 // orbit parameters are valid for 7200 seconds (minimum)
[9409]284 else if (eph->type() == t_eph::QZSS && (dt > 7200.0 || dt < -3600.0)) {
[9245]285 return true;
286 }
[9376]287 // maximum update interval: 300 sec
[9409]288 else if (eph->type() == t_eph::SBAS && (dt > 600.0 || dt < -600.0)) {
[9245]289 return true;
290 }
[9362]291 // updates 1h + 5 min
[9409]292 else if (eph->type() == t_eph::BDS && (dt > 3900.0 || dt < 0.0) ) {
[9245]293 return true;
294 }
[9376]295 // update interval: up to 24 hours
[9409]296 else if (eph->type() == t_eph::IRNSS && (fabs(dt > 86400.0))) {
[9245]297 return true;
298 }
[9409]299
[9245]300 return false;
301}
302
303//
304////////////////////////////////////////////////////////////////////////////
[1595]305QByteArray ggaString(const QByteArray& latitude,
306 const QByteArray& longitude,
[6786]307 const QByteArray& height,
308 const QString& ggaType) {
[1381]309
310 double lat = strtod(latitude,NULL);
311 double lon = strtod(longitude,NULL);
[1595]312 double hei = strtod(height,NULL);
[6786]313 QString sentences = "GPGGA,";
314 if (ggaType.contains("GNGGA")) {
315 sentences = "GNGGA,";
316 }
[1381]317
318 const char* flagN="N";
319 const char* flagE="E";
320 if (lon >180.) {lon=(lon-360.)*(-1.); flagE="W";}
321 if ((lon < 0.) && (lon >= -180.)) {lon=lon*(-1.); flagE="W";}
322 if (lon < -180.) {lon=(lon+360.); flagE="E";}
323 if (lat < 0.) {lat=lat*(-1.); flagN="S";}
324 QTime ttime(QDateTime::currentDateTime().toUTC().time());
[7527]325 int lat_deg = (int)lat;
[1381]326 double lat_min=(lat-lat_deg)*60.;
[7527]327 int lon_deg = (int)lon;
[1381]328 double lon_min=(lon-lon_deg)*60.;
329 int hh = 0 , mm = 0;
330 double ss = 0.0;
331 hh=ttime.hour();
332 mm=ttime.minute();
333 ss=(double)ttime.second()+0.001*ttime.msec();
334 QString gga;
[6786]335 gga += sentences;
[1381]336 gga += QString("%1%2%3,").arg((int)hh, 2, 10, QLatin1Char('0')).arg((int)mm, 2, 10, QLatin1Char('0')).arg((int)ss, 2, 10, QLatin1Char('0'));
337 gga += QString("%1%2,").arg((int)lat_deg,2, 10, QLatin1Char('0')).arg(lat_min, 7, 'f', 4, QLatin1Char('0'));
338 gga += flagN;
339 gga += QString(",%1%2,").arg((int)lon_deg,3, 10, QLatin1Char('0')).arg(lon_min, 7, 'f', 4, QLatin1Char('0'));
[1595]340 gga += flagE + QString(",1,05,1.00");
[1599]341 gga += QString(",%1,").arg(hei, 2, 'f', 1);
[1595]342 gga += QString("M,10.000,M,,");
[7527]343
[8646]344 unsigned char XOR = 0;
345 for (int ii = 0; ii < gga.length(); ii++) {
346 XOR ^= (unsigned char) gga[ii].toLatin1();
[1381]347 }
[9787]348 gga = "$" + gga + QString("*%1").arg(XOR, 2, 16, QLatin1Char('0')) + "\r\n";
[1381]349
[8203]350 return gga.toLatin1();
[1381]351}
[2043]352
[7527]353//
[2043]354////////////////////////////////////////////////////////////////////////////
355void RSW_to_XYZ(const ColumnVector& rr, const ColumnVector& vv,
356 const ColumnVector& rsw, ColumnVector& xyz) {
357
[8903]358 ColumnVector along = vv / vv.NormFrobenius();
359 ColumnVector cross = crossproduct(rr, vv); cross /= cross.NormFrobenius();
[2043]360 ColumnVector radial = crossproduct(along, cross);
361
362 Matrix RR(3,3);
363 RR.Column(1) = radial;
364 RR.Column(2) = along;
365 RR.Column(3) = cross;
366
367 xyz = RR * rsw;
368}
[2063]369
[2988]370// Transformation xyz --> radial, along track, out-of-plane
371////////////////////////////////////////////////////////////////////////////
372void XYZ_to_RSW(const ColumnVector& rr, const ColumnVector& vv,
373 const ColumnVector& xyz, ColumnVector& rsw) {
374
[8903]375 ColumnVector along = vv / vv.NormFrobenius();
376 ColumnVector cross = crossproduct(rr, vv); cross /= cross.NormFrobenius();
[2988]377 ColumnVector radial = crossproduct(along, cross);
378
379 rsw.ReSize(3);
380 rsw(1) = DotProduct(xyz, radial);
381 rsw(2) = DotProduct(xyz, along);
382 rsw(3) = DotProduct(xyz, cross);
383}
384
[2063]385// Rectangular Coordinates -> Ellipsoidal Coordinates
386////////////////////////////////////////////////////////////////////////////
387t_irc xyz2ell(const double* XYZ, double* Ell) {
388
389 const double bell = t_CST::aell*(1.0-1.0/t_CST::fInv) ;
390 const double e2 = (t_CST::aell*t_CST::aell-bell*bell)/(t_CST::aell*t_CST::aell) ;
391 const double e2c = (t_CST::aell*t_CST::aell-bell*bell)/(bell*bell) ;
[7527]392
[2063]393 double nn, ss, zps, hOld, phiOld, theta, sin3, cos3;
394
395 ss = sqrt(XYZ[0]*XYZ[0]+XYZ[1]*XYZ[1]) ;
396 zps = XYZ[2]/ss ;
397 theta = atan( (XYZ[2]*t_CST::aell) / (ss*bell) );
398 sin3 = sin(theta) * sin(theta) * sin(theta);
399 cos3 = cos(theta) * cos(theta) * cos(theta);
400
401 // Closed formula
[7527]402 Ell[0] = atan( (XYZ[2] + e2c * bell * sin3) / (ss - e2 * t_CST::aell * cos3) );
[2063]403 Ell[1] = atan2(XYZ[1],XYZ[0]) ;
404 nn = t_CST::aell/sqrt(1.0-e2*sin(Ell[0])*sin(Ell[0])) ;
405 Ell[2] = ss / cos(Ell[0]) - nn;
406
407 const int MAXITER = 100;
408 for (int ii = 1; ii <= MAXITER; ii++) {
409 nn = t_CST::aell/sqrt(1.0-e2*sin(Ell[0])*sin(Ell[0])) ;
410 hOld = Ell[2] ;
411 phiOld = Ell[0] ;
412 Ell[2] = ss/cos(Ell[0])-nn ;
413 Ell[0] = atan(zps/(1.0-e2*nn/(nn+Ell[2]))) ;
414 if ( fabs(phiOld-Ell[0]) <= 1.0e-11 && fabs(hOld-Ell[2]) <= 1.0e-5 ) {
415 return success;
416 }
417 }
418
419 return failure;
420}
[2065]421
422// Rectangular Coordinates -> North, East, Up Components
423////////////////////////////////////////////////////////////////////////////
424void xyz2neu(const double* Ell, const double* xyz, double* neu) {
425
426 double sinPhi = sin(Ell[0]);
427 double cosPhi = cos(Ell[0]);
428 double sinLam = sin(Ell[1]);
429 double cosLam = cos(Ell[1]);
430
431 neu[0] = - sinPhi*cosLam * xyz[0]
432 - sinPhi*sinLam * xyz[1]
433 + cosPhi * xyz[2];
434
435 neu[1] = - sinLam * xyz[0]
436 + cosLam * xyz[1];
437
438 neu[2] = + cosPhi*cosLam * xyz[0]
439 + cosPhi*sinLam * xyz[1]
440 + sinPhi * xyz[2];
441}
[2221]442
[2582]443// North, East, Up Components -> Rectangular Coordinates
444////////////////////////////////////////////////////////////////////////////
445void neu2xyz(const double* Ell, const double* neu, double* xyz) {
446
447 double sinPhi = sin(Ell[0]);
448 double cosPhi = cos(Ell[0]);
449 double sinLam = sin(Ell[1]);
450 double cosLam = cos(Ell[1]);
451
452 xyz[0] = - sinPhi*cosLam * neu[0]
453 - sinLam * neu[1]
454 + cosPhi*cosLam * neu[2];
455
456 xyz[1] = - sinPhi*sinLam * neu[0]
457 + cosLam * neu[1]
458 + cosPhi*sinLam * neu[2];
459
460 xyz[2] = + cosPhi * neu[0]
461 + sinPhi * neu[2];
462}
463
[7244]464// Rectangular Coordinates -> Geocentric Coordinates
465////////////////////////////////////////////////////////////////////////////
[7251]466t_irc xyz2geoc(const double* XYZ, double* Geoc) {
[7244]467
468 const double bell = t_CST::aell*(1.0-1.0/t_CST::fInv) ;
[7260]469 const double e2 = (t_CST::aell*t_CST::aell-bell*bell)/(t_CST::aell*t_CST::aell) ;
[7244]470 double Ell[3];
[7251]471 if (xyz2ell(XYZ, Ell) != success) {
472 return failure;
473 }
[7244]474 double rho = sqrt(XYZ[0]*XYZ[0]+XYZ[1]*XYZ[1]+XYZ[2]*XYZ[2]);
[7260]475 double Rn = t_CST::aell/sqrt(1-e2*pow(sin(Ell[0]),2));
[7244]476
477 Geoc[0] = atan((1-e2 * Rn/(Rn + Ell[2])) * tan(Ell[0]));
478 Geoc[1] = Ell[1];
479 Geoc[2] = rho-t_CST::rgeoc;
[7251]480
481 return success;
[7244]482}
483
[7527]484//
[5807]485////////////////////////////////////////////////////////////////////////////
486double Frac (double x) {
[7527]487 return x-floor(x);
[5807]488}
489
[7183]490//
[5807]491////////////////////////////////////////////////////////////////////////////
[7527]492double Modulo (double x, double y) {
493 return y*Frac(x/y);
[5807]494}
495
[5753]496// Round to nearest integer
497////////////////////////////////////////////////////////////////////////////
498double nint(double val) {
499 return ((val < 0.0) ? -floor(fabs(val)+0.5) : floor(val+0.5));
500}
501
[7183]502//
503////////////////////////////////////////////////////////////////////////////
[8774]504double factorial(int n) {
[7183]505 if (n == 0) {
506 return 1;
507 }
508 else {
509 return (n * factorial(n - 1));
510 }
511}
512
513//
514////////////////////////////////////////////////////////////////////////////
515double associatedLegendreFunction(int n, int m, double t) {
516 double sum = 0.0;
517 int r = (int) floor((n - m) / 2);
518 for (int k = 0; k <= r; k++) {
[7228]519 sum += (pow(-1.0, (double)k) * factorial(2*n - 2*k)
520 / (factorial(k) * factorial(n-k) * factorial(n-m-2*k))
521 * pow(t, (double)n-m-2*k));
[7183]522 }
523 double fac = pow(2.0,(double) -n) * pow((1 - t*t), (double)m/2);
524 return sum *= fac;
525}
526
527
[7527]528// Jacobian XYZ --> NEU
[5752]529////////////////////////////////////////////////////////////////////////////
530void jacobiXYZ_NEU(const double* Ell, Matrix& jacobi) {
531
532 Tracer tracer("jacobiXYZ_NEU");
533
534 double sinPhi = sin(Ell[0]);
535 double cosPhi = cos(Ell[0]);
536 double sinLam = sin(Ell[1]);
537 double cosLam = cos(Ell[1]);
538
539 jacobi(1,1) = - sinPhi * cosLam;
540 jacobi(1,2) = - sinPhi * sinLam;
541 jacobi(1,3) = cosPhi;
[7527]542
543 jacobi(2,1) = - sinLam;
[5752]544 jacobi(2,2) = cosLam;
[7527]545 jacobi(2,3) = 0.0;
546
547 jacobi(3,1) = cosPhi * cosLam;
548 jacobi(3,2) = cosPhi * sinLam;
[5752]549 jacobi(3,3) = sinPhi;
550}
551
552// Jacobian Ell --> XYZ
553////////////////////////////////////////////////////////////////////////////
554void jacobiEll_XYZ(const double* Ell, Matrix& jacobi) {
555
556 Tracer tracer("jacobiEll_XYZ");
557
558 double sinPhi = sin(Ell[0]);
559 double cosPhi = cos(Ell[0]);
560 double sinLam = sin(Ell[1]);
561 double cosLam = cos(Ell[1]);
562 double hh = Ell[2];
563
564 double bell = t_CST::aell*(1.0-1.0/t_CST::fInv);
565 double e2 = (t_CST::aell*t_CST::aell-bell*bell)/(t_CST::aell*t_CST::aell) ;
566 double nn = t_CST::aell/sqrt(1.0-e2*sinPhi*sinPhi) ;
567
568 jacobi(1,1) = -(nn+hh) * sinPhi * cosLam;
569 jacobi(1,2) = -(nn+hh) * cosPhi * sinLam;
570 jacobi(1,3) = cosPhi * cosLam;
571
572 jacobi(2,1) = -(nn+hh) * sinPhi * sinLam;
573 jacobi(2,2) = (nn+hh) * cosPhi * cosLam;
574 jacobi(2,3) = cosPhi * sinLam;
575
576 jacobi(3,1) = (nn*(1.0-e2)+hh) * cosPhi;
577 jacobi(3,2) = 0.0;
578 jacobi(3,3) = sinPhi;
[7527]579}
[5752]580
581// Covariance Matrix in NEU
582////////////////////////////////////////////////////////////////////////////
[7527]583void covariXYZ_NEU(const SymmetricMatrix& QQxyz, const double* Ell,
[5752]584 SymmetricMatrix& Qneu) {
585
586 Tracer tracer("covariXYZ_NEU");
587
588 Matrix CC(3,3);
589 jacobiXYZ_NEU(Ell, CC);
590 Qneu << CC * QQxyz * CC.t();
591}
592
593// Covariance Matrix in XYZ
594////////////////////////////////////////////////////////////////////////////
[7527]595void covariNEU_XYZ(const SymmetricMatrix& QQneu, const double* Ell,
[5752]596 SymmetricMatrix& Qxyz) {
597
598 Tracer tracer("covariNEU_XYZ");
599
600 Matrix CC(3,3);
601 jacobiXYZ_NEU(Ell, CC);
602 Qxyz << CC.t() * QQneu * CC;
603}
604
[2221]605// Fourth order Runge-Kutta numerical integrator for ODEs
606////////////////////////////////////////////////////////////////////////////
607ColumnVector rungeKutta4(
608 double xi, // the initial x-value
609 const ColumnVector& yi, // vector of the initial y-values
610 double dx, // the step size for the integration
[8417]611 double* acc, // additional acceleration
[2556]612 ColumnVector (*der)(double x, const ColumnVector& y, double* acc)
[7527]613 // A pointer to a function that computes the
[2221]614 // derivative of a function at a point (x,y)
615 ) {
616
[2556]617 ColumnVector k1 = der(xi , yi , acc) * dx;
618 ColumnVector k2 = der(xi+dx/2.0, yi+k1/2.0, acc) * dx;
619 ColumnVector k3 = der(xi+dx/2.0, yi+k2/2.0, acc) * dx;
620 ColumnVector k4 = der(xi+dx , yi+k3 , acc) * dx;
[2221]621
622 ColumnVector yf = yi + k1/6.0 + k2/3.0 + k3/3.0 + k4/6.0;
[7527]623
[2221]624 return yf;
625}
[7527]626//
[3044]627////////////////////////////////////////////////////////////////////////////
[5886]628double djul(long jj, long mm, double tt) {
629 long ii, kk;
[3171]630 double djul ;
631 if( mm <= 2 ) {
632 jj = jj - 1;
633 mm = mm + 12;
[7527]634 }
[3171]635 ii = jj/100;
636 kk = 2 - ii + ii/4;
637 djul = (365.25*jj - fmod( 365.25*jj, 1.0 )) - 679006.0;
638 djul = djul + floor( 30.6001*(mm + 1) ) + tt + kk;
639 return djul;
[7527]640}
[3171]641
[7527]642//
[3171]643////////////////////////////////////////////////////////////////////////////
[5886]644double gpjd(double second, int nweek) {
645 double deltat;
646 deltat = nweek*7.0 + second/86400.0 ;
647 return( 44244.0 + deltat) ;
[7527]648}
[5886]649
[7527]650//
[5886]651////////////////////////////////////////////////////////////////////////////
652void jdgp(double tjul, double & second, long & nweek) {
[3171]653 double deltat;
654 deltat = tjul - 44244.0 ;
[5886]655 nweek = (long) floor(deltat/7.0);
[3171]656 second = (deltat - (nweek)*7.0)*86400.0;
657}
658
[7527]659//
[3171]660////////////////////////////////////////////////////////////////////////////
[5886]661void jmt(double djul, long& jj, long& mm, double& dd) {
662 long ih, ih1, ih2 ;
663 double t1, t2, t3, t4;
664 t1 = 1.0 + djul - fmod( djul, 1.0 ) + 2400000.0;
665 t4 = fmod( djul, 1.0 );
666 ih = long( (t1 - 1867216.25)/36524.25 );
667 t2 = t1 + 1 + ih - ih/4;
668 t3 = t2 - 1720995.0;
669 ih1 = long( (t3 - 122.1)/365.25 );
670 t1 = 365.25*ih1 - fmod( 365.25*ih1, 1.0 );
671 ih2 = long( (t3 - t1)/30.6001 );
672 dd = t3 - t1 - (int)( 30.6001*ih2 ) + t4;
673 mm = ih2 - 1;
674 if ( ih2 > 13 ) mm = ih2 - 13;
675 jj = ih1;
676 if ( mm <= 2 ) jj = jj + 1;
[7527]677}
[5886]678
[7527]679//
[5886]680////////////////////////////////////////////////////////////////////////////
[7527]681void GPSweekFromDateAndTime(const QDateTime& dateTime,
[3044]682 int& GPSWeek, double& GPSWeeks) {
683
684 static const QDateTime zeroEpoch(QDate(1980, 1, 6),QTime(),Qt::UTC);
[7527]685
[3044]686 GPSWeek = zeroEpoch.daysTo(dateTime) / 7;
687
688 int weekDay = dateTime.date().dayOfWeek() + 1; // Qt: Monday = 1
689 if (weekDay > 7) weekDay = 1;
690
691 GPSWeeks = (weekDay - 1) * 86400.0
[7527]692 - dateTime.time().msecsTo(QTime()) / 1e3;
[3044]693}
694
[7527]695//
[3044]696////////////////////////////////////////////////////////////////////////////
[3171]697void GPSweekFromYMDhms(int year, int month, int day, int hour, int min,
698 double sec, int& GPSWeek, double& GPSWeeks) {
699
700 double mjd = djul(year, month, day);
701
[5888]702 long GPSWeek_long;
703 jdgp(mjd, GPSWeeks, GPSWeek_long);
704 GPSWeek = GPSWeek_long;
[7527]705 GPSWeeks += hour * 3600.0 + min * 60.0 + sec;
[3171]706}
707
[7527]708//
[3171]709////////////////////////////////////////////////////////////////////////////
[3044]710void mjdFromDateAndTime(const QDateTime& dateTime, int& mjd, double& dayfrac) {
711
712 static const QDate zeroDate(1858, 11, 17);
713
714 mjd = zeroDate.daysTo(dateTime.date());
715
716 dayfrac = (dateTime.time().hour() +
717 (dateTime.time().minute() +
[7527]718 (dateTime.time().second() +
[3044]719 dateTime.time().msec() / 1000.0) / 60.0) / 60.0) / 24.0;
720}
[3408]721
[7527]722//
[3408]723////////////////////////////////////////////////////////////////////////////
724bool findInVector(const vector<QString>& vv, const QString& str) {
725 std::vector<QString>::const_iterator it;
726 for (it = vv.begin(); it != vv.end(); ++it) {
727 if ( (*it) == str) {
728 return true;
729 }
730 }
731 return false;
732}
733
[7527]734//
[3664]735////////////////////////////////////////////////////////////////////////////
736int readInt(const QString& str, int pos, int len, int& value) {
737 bool ok;
738 value = str.mid(pos, len).toInt(&ok);
739 return ok ? 0 : 1;
740}
741
[7527]742//
[3664]743////////////////////////////////////////////////////////////////////////////
744int readDbl(const QString& str, int pos, int len, double& value) {
745 QString hlp = str.mid(pos, len);
746 for (int ii = 0; ii < hlp.length(); ii++) {
747 if (hlp[ii]=='D' || hlp[ii]=='d' || hlp[ii] == 'E') {
748 hlp[ii]='e';
749 }
750 }
751 bool ok;
752 value = hlp.toDouble(&ok);
753 return ok ? 0 : 1;
754}
[4338]755
756// Topocentrical Distance and Elevation
757////////////////////////////////////////////////////////////////////////////
[7527]758void topos(double xRec, double yRec, double zRec,
759 double xSat, double ySat, double zSat,
[4338]760 double& rho, double& eleSat, double& azSat) {
761
762 double dx[3];
763 dx[0] = xSat-xRec;
764 dx[1] = ySat-yRec;
765 dx[2] = zSat-zRec;
766
[7527]767 rho = sqrt( dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2] );
[4338]768
769 double xyzRec[3];
770 xyzRec[0] = xRec;
771 xyzRec[1] = yRec;
772 xyzRec[2] = zRec;
773
774 double Ell[3];
775 double neu[3];
776 xyz2ell(xyzRec, Ell);
777 xyz2neu(Ell, dx, neu);
778
779 eleSat = acos( sqrt(neu[0]*neu[0] + neu[1]*neu[1]) / rho );
[9797]780 if (neu[2] < 0.0) {
[4338]781 eleSat *= -1.0;
782 }
783
784 azSat = atan2(neu[1], neu[0]);
785}
[5230]786
787// Degrees -> degrees, minutes, seconds
788////////////////////////////////////////////////////////////////////////////
789void deg2DMS(double decDeg, int& deg, int& min, double& sec) {
790 int sgn = (decDeg < 0.0 ? -1 : 1);
[7787]791 deg = static_cast<int>(decDeg);
792 min = sgn * static_cast<int>((decDeg - deg)*60);
793 sec = (sgn* (decDeg - deg) - min/60.0) * 3600.0;
[5230]794}
[5310]795
[7527]796//
[5310]797////////////////////////////////////////////////////////////////////////////
798QString fortranFormat(double value, int width, int prec) {
[6537]799 int expo = value == 0.0 ? 0 : int(log10(fabs(value)));
[7656]800 double mant = value == 0.0 ? 0 : value / pow(10.0, double(expo));
[5310]801 if (fabs(mant) >= 1.0) {
802 mant /= 10.0;
803 expo += 1;
804 }
805 if (expo >= 0) {
806 return QString("%1e+%2").arg(mant, width-4, 'f', prec).arg(expo, 2, 10, QChar('0'));
807 }
808 else {
809 return QString("%1e-%2").arg(mant, width-4, 'f', prec).arg(-expo, 2, 10, QChar('0'));
810 }
811}
[5807]812
813//
814//////////////////////////////////////////////////////////////////////////////
[7527]815void kalman(const Matrix& AA, const ColumnVector& ll, const DiagonalMatrix& PP,
[6168]816 SymmetricMatrix& QQ, ColumnVector& xx) {
[5807]817
818 Tracer tracer("kalman");
819
820 int nPar = AA.Ncols();
821 int nObs = AA.Nrows();
822 UpperTriangularMatrix SS = Cholesky(QQ).t();
823
824 Matrix SA = SS*AA.t();
825 Matrix SRF(nObs+nPar, nObs+nPar); SRF = 0;
826 for (int ii = 1; ii <= nObs; ++ii) {
827 SRF(ii,ii) = 1.0 / sqrt(PP(ii,ii));
828 }
829
830 SRF.SubMatrix (nObs+1, nObs+nPar, 1, nObs) = SA;
831 SRF.SymSubMatrix(nObs+1, nObs+nPar) = SS;
[7527]832
[5807]833 UpperTriangularMatrix UU;
834 QRZ(SRF, UU);
[7527]835
[5807]836 SS = UU.SymSubMatrix(nObs+1, nObs+nPar);
837 UpperTriangularMatrix SH_rt = UU.SymSubMatrix(1, nObs);
838 Matrix YY = UU.SubMatrix(1, nObs, nObs+1, nObs+nPar);
[7527]839
[5807]840 UpperTriangularMatrix SHi = SH_rt.i();
[7527]841
842 Matrix KT = SHi * YY;
[5807]843 SymmetricMatrix Hi; Hi << SHi * SHi.t();
844
[6168]845 xx += KT.t() * (ll - AA * xx);
[5807]846 QQ << (SS.t() * SS);
847}
848
[8903]849//
850////////////////////////////////////////////////////////////////////////////
[6799]851double accuracyFromIndex(int index, t_eph::e_type type) {
[8801]852double accuracy = -1.0;
[6799]853
[8782]854 if (type == t_eph::GPS ||
855 type == t_eph::BDS ||
856 type == t_eph::SBAS||
857 type == t_eph::QZSS) {
[6799]858 if ((index >= 0) && (index <= 6)) {
859 if (index == 3) {
[8801]860 accuracy = ceil(10.0 * pow(2.0, (double(index) / 2.0) + 1.0)) / 10.0;
[6799]861 }
862 else {
[8801]863 accuracy = floor(10.0 * pow(2.0, (double(index) / 2.0) + 1.0)) / 10.0;
[6799]864 }
865 }
866 else if ((index > 6) && (index <= 15)) {
[8801]867 accuracy = (10.0 * pow(2.0, (double(index) - 2.0))) / 10.0;
[6799]868 }
869 else {
[8801]870 accuracy = 8192.0;
[6799]871 }
872 }
[8790]873 else if (type == t_eph::Galileo) {
[6799]874 if ((index >= 0) && (index <= 49)) {
[8801]875 accuracy = (double(index) / 100.0);
[6799]876 }
877 else if ((index > 49) && (index <= 74)) {
[8801]878 accuracy = (50.0 + (double(index) - 50.0) * 2.0) / 100.0;
[6799]879 }
880 else if ((index > 74) && (index <= 99)) {
[8801]881 accuracy = 1.0 + (double(index) - 75.0) * 0.04;
[6799]882 }
883 else if ((index > 99) && (index <= 125)) {
[8801]884 accuracy = 2.0 + (double(index) - 100.0) * 0.16;
[6799]885 }
886 else {
[8801]887 accuracy = -1.0;
[6799]888 }
889 }
[8790]890 else if (type == t_eph::IRNSS) {
891 if ((index >= 0) && (index <= 6)) {
892 if (index == 1) {
[8801]893 accuracy = 2.8;
[8790]894 }
895 else if (index == 3) {
[8801]896 accuracy = 5.7;
[8790]897 }
898 else if (index == 5) {
[8801]899 accuracy = 11.3;
[8790]900 }
901 else {
[8801]902 accuracy = pow(2, 1 + index / 2);
[8790]903 }
904 }
905 else if ((index > 6) && (index <= 15)) {
[8801]906 accuracy = pow(2, index - 2);
[8790]907 }
908 }
[8801]909 return accuracy;
[6799]910}
911
[8903]912//
913////////////////////////////////////////////////////////////////////////////
[6799]914int indexFromAccuracy(double accuracy, t_eph::e_type type) {
915
[10091]916 if (type == t_eph::GPS ||
917 type == t_eph::BDS ||
918 type == t_eph::SBAS ||
919 type == t_eph::QZSS) {
[6799]920
921 if (accuracy <= 2.40) {
922 return 0;
923 }
924 else if (accuracy <= 3.40) {
925 return 1;
926 }
927 else if (accuracy <= 4.85) {
928 return 2;
929 }
930 else if (accuracy <= 6.85) {
931 return 3;
932 }
933 else if (accuracy <= 9.65) {
934 return 4;
935 }
936 else if (accuracy <= 13.65) {
937 return 5;
938 }
939 else if (accuracy <= 24.00) {
940 return 6;
941 }
942 else if (accuracy <= 48.00) {
943 return 7;
944 }
945 else if (accuracy <= 96.00) {
946 return 8;
947 }
948 else if (accuracy <= 192.00) {
949 return 9;
950 }
951 else if (accuracy <= 384.00) {
952 return 10;
953 }
954 else if (accuracy <= 768.00) {
955 return 11;
956 }
957 else if (accuracy <= 1536.00) {
958 return 12;
959 }
960 else if (accuracy <= 3072.00) {
961 return 13;
962 }
963 else if (accuracy <= 6144.00) {
964 return 14;
965 }
966 else {
967 return 15;
968 }
969 }
970
971 if (type == t_eph::Galileo) {
[6800]972
973 if (accuracy <= 0.49) {
974 return int(ceil(accuracy * 100.0));
975 }
976 else if (accuracy <= 0.98) {
977 return int(50.0 + (((accuracy * 100.0) - 50) / 2.0));
978 }
979 else if (accuracy <= 2.0) {
980 return int(75.0 + ((accuracy - 1.0) / 0.04));
981 }
982 else if (accuracy <= 6.0) {
983 return int(100.0 + ((accuracy - 2.0) / 0.16));
984 }
985 else {
986 return 255;
987 }
[6799]988 }
989
990 return (type == t_eph::Galileo) ? 255 : 15;
991}
[7053]992
[8903]993// Returns fit interval in hours from flag
994////////////////////////////////////////////////////////////////////////////
995double fitIntervalFromFlag(int flag, double iodc, t_eph::e_type type) {
996 double fitInterval = 0.0;
997
998 switch (flag) {
999 case 0:
1000 if (type == t_eph::GPS) {
1001 fitInterval = 4.0;
1002 }
1003 else if (type == t_eph::QZSS) {
1004 fitInterval = 2.0;
1005 }
1006 break;
1007 case 1:
1008 if (type == t_eph::GPS) {
1009 if (iodc >= 240 && iodc <= 247) {
1010 fitInterval = 8.0;
1011 }
1012 else if ((iodc >= 248 && iodc <= 255) ||
1013 (iodc == 496) ) {
1014 fitInterval = 14.0;
1015 }
1016 else if ((iodc >= 497 && iodc <= 503) ||
1017 (iodc >= 2021 && iodc <= 1023) ) {
1018 fitInterval = 26.0;
1019 }
1020 else {
1021 fitInterval = 6.0;
1022 }
1023 }
1024 break;
1025 }
1026 return fitInterval;
1027}
1028
[7053]1029// Returns CRC24
1030////////////////////////////////////////////////////////////////////////////
1031unsigned long CRC24(long size, const unsigned char *buf) {
1032 unsigned long crc = 0;
1033 int ii;
1034 while (size--) {
1035 crc ^= (*buf++) << (16);
1036 for(ii = 0; ii < 8; ii++) {
1037 crc <<= 1;
1038 if (crc & 0x1000000) {
1039 crc ^= 0x01864cfb;
1040 }
1041 }
1042 }
1043 return crc;
1044}
1045
[9368]1046// Extracts k bits from position p and returns the extracted value as integer
1047////////////////////////////////////////////////////////////////////////////
1048int bitExtracted(int number, int k, int p) {
1049 return (((1 << k) - 1) & (number >> (p - 1)));
1050}
1051
[9088]1052// Convert RTCM3 lock-time indicator to minimum lock time in seconds
[8617]1053////////////////////////////////////////////////////////////////////////////
1054double lti2sec(int type, int lti) {
1055
1056 if ( (type>=1001 && type<=1004) ||
1057 (type>=1009 && type<=1012) ) { // RTCM3 msg 100[1...4] and 10[09...12]
1058 if (lti< 0) return -1;
1059 else if (lti< 24) return 1*lti; // [ 0 1 23]
1060 else if (lti< 48) return 2*lti-24; // [ 24 2 70]
1061 else if (lti< 72) return 4*lti-120; // [ 72 4 164]
1062 else if (lti< 96) return 8*lti-408; // [168 8 352]
1063 else if (lti< 120) return 16*lti-1176; // [360 16 728]
1064 else if (lti< 127) return 32*lti-3096; // [744 32 905]
1065 else if (lti==127) return 937;
[9088]1066 else return -1.0;
[8617]1067 }
1068 else if (type%10==2 || type%10==3 ||
1069 type%10==4 || type%10==5) { // RTCM3 MSM-2/-3/-4/-5
1070 switch(lti) {
1071 case( 0) : return 0;
1072 case( 1) : return 32e-3;
1073 case( 2) : return 64e-3;
1074 case( 3) : return 128e-3;
1075 case( 4) : return 256e-3;
1076 case( 5) : return 512e-3;
1077 case( 6) : return 1024e-3;
1078 case( 7) : return 2048e-3;
1079 case( 8) : return 4096e-3;
1080 case( 9) : return 8192e-3;
1081 case(10) : return 16384e-3;
1082 case(11) : return 32768e-3;
1083 case(12) : return 65536e-3;
1084 case(13) : return 131072e-3;
1085 case(14) : return 262144e-3;
1086 case(15) : return 524288e-3;
[9088]1087 default : return -1.0;
[8617]1088 };
1089 }
1090 else if (type%10==6 || type%10==7) { // RTCM3 MSM-6 and MSM-7
1091 if (lti< 0) return ( -1 );
1092 else if (lti< 64) return ( 1*lti )*1e-3;
1093 else if (lti< 96) return ( 2*lti-64 )*1e-3;
1094 else if (lti< 128) return ( 4*lti-256 )*1e-3;
1095 else if (lti< 160) return ( 8*lti-768 )*1e-3;
1096 else if (lti< 192) return ( 16*lti-2048 )*1e-3;
1097 else if (lti< 224) return ( 32*lti-5120 )*1e-3;
1098 else if (lti< 256) return ( 64*lti-12288 )*1e-3;
1099 else if (lti< 288) return ( 128*lti-28672 )*1e-3;
1100 else if (lti< 320) return ( 256*lti-65536 )*1e-3;
1101 else if (lti< 352) return ( 512*lti-147456 )*1e-3;
1102 else if (lti< 384) return ( 1024*lti-327680 )*1e-3;
1103 else if (lti< 416) return ( 2048*lti-720896 )*1e-3;
1104 else if (lti< 448) return ( 4096*lti-1572864 )*1e-3;
1105 else if (lti< 480) return ( 8192*lti-3407872 )*1e-3;
1106 else if (lti< 512) return ( 16384*lti-7340032 )*1e-3;
1107 else if (lti< 544) return ( 32768*lti-15728640 )*1e-3;
1108 else if (lti< 576) return ( 65536*lti-33554432 )*1e-3;
1109 else if (lti< 608) return ( 131072*lti-71303168 )*1e-3;
1110 else if (lti< 640) return ( 262144*lti-150994944 )*1e-3;
1111 else if (lti< 672) return ( 524288*lti-318767104 )*1e-3;
1112 else if (lti< 704) return (1048576*lti-671088640 )*1e-3;
1113 else if (lti==704) return (2097152*lti-1409286144)*1e-3;
[9088]1114 else return ( -1.0 );
[8617]1115 }
1116 else {
[9088]1117 return -1.0;
[8617]1118 };
1119};
Note: See TracBrowser for help on using the repository browser.