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

Last change on this file since 8036 was 8011, checked in by stuerze, 10 years ago

check regarding wrong observation epochs is done in latencychecker as well to prevent erroneous latencies

File size: 26.5 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},
[7978]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);
172 str.replace(rxStr, qgetenv(envVar.toAscii()));
173 }
174 }
175
176}
[124]177
[5910]178// Strip White Space
179////////////////////////////////////////////////////////////////////////////
180void stripWhiteSpace(string& str) {
181 if (!str.empty()) {
182 string::size_type beg = str.find_first_not_of(" \t\f\n\r\v");
183 string::size_type end = str.find_last_not_of(" \t\f\n\r\v");
184 if (beg > str.max_size())
185 str.erase();
186 else
187 str = str.substr(beg, end-beg+1);
188 }
189}
190
[7527]191//
[1381]192////////////////////////////////////////////////////////////////////////////
[124]193QDateTime dateAndTimeFromGPSweek(int GPSWeek, double GPSWeeks) {
194
195 static const QDate zeroEpoch(1980, 1, 6);
[7527]196
[124]197 QDate date(zeroEpoch);
198 QTime time(0,0,0,0);
199
200 int weekDays = int(GPSWeeks) / 86400;
201 date = date.addDays( GPSWeek * 7 + weekDays );
202 time = time.addMSecs( int( (GPSWeeks - 86400 * weekDays) * 1e3 ) );
203
204 return QDateTime(date,time);
205}
[210]206
[7527]207//
[1381]208////////////////////////////////////////////////////////////////////////////
[218]209void currentGPSWeeks(int& week, double& sec) {
[210]210
[1942]211 QDateTime currDateTimeGPS;
[1155]212
[5846]213 if ( BNC_CORE->dateAndTimeGPSSet() ) {
214 currDateTimeGPS = BNC_CORE->dateAndTimeGPS();
[1155]215 }
216 else {
[1942]217 currDateTimeGPS = QDateTime::currentDateTime().toUTC();
218 QDate hlp = currDateTimeGPS.date();
[7527]219 currDateTimeGPS = currDateTimeGPS.addSecs(gnumleap(hlp.year(),
[1942]220 hlp.month(), hlp.day()));
[1155]221 }
222
[1942]223 QDate currDateGPS = currDateTimeGPS.date();
224 QTime currTimeGPS = currDateTimeGPS.time();
[210]225
[1942]226 week = int( (double(currDateGPS.toJulianDay()) - 2444244.5) / 7 );
[1036]227
[7527]228 sec = (currDateGPS.dayOfWeek() % 7) * 24.0 * 3600.0 +
229 currTimeGPS.hour() * 3600.0 +
230 currTimeGPS.minute() * 60.0 +
[1942]231 currTimeGPS.second() +
232 currTimeGPS.msec() / 1000.0;
[1036]233}
[1154]234
[7527]235//
[1381]236////////////////////////////////////////////////////////////////////////////
[1154]237QDateTime currentDateAndTimeGPS() {
[5846]238 if ( BNC_CORE->dateAndTimeGPSSet() ) {
239 return BNC_CORE->dateAndTimeGPS();
[2530]240 }
241 else {
242 int GPSWeek;
243 double GPSWeeks;
244 currentGPSWeeks(GPSWeek, GPSWeeks);
245 return dateAndTimeFromGPSweek(GPSWeek, GPSWeeks);
246 }
[1154]247}
248
[7527]249//
[1381]250////////////////////////////////////////////////////////////////////////////
[8011]251bool checkForWrongObsEpoch(bncTime obsEpoch) {
252 const double maxDt = 600.0;
253 long iSec = long(floor(obsEpoch.gpssec()+0.5));
254 long obsTime = obsEpoch.gpsw()*7*24*3600 + iSec;
255 int week;
256 double sec;
257 currentGPSWeeks(week, sec);
258 long currTime = week * 7*24*3600 + long(sec);
259
260 if (fabs(currTime - obsTime) > maxDt) {
261 return true;
262 }
263 return false;
264}
265//
266////////////////////////////////////////////////////////////////////////////
[1595]267QByteArray ggaString(const QByteArray& latitude,
268 const QByteArray& longitude,
[6786]269 const QByteArray& height,
270 const QString& ggaType) {
[1381]271
272 double lat = strtod(latitude,NULL);
273 double lon = strtod(longitude,NULL);
[1595]274 double hei = strtod(height,NULL);
[6786]275 QString sentences = "GPGGA,";
276 if (ggaType.contains("GNGGA")) {
277 sentences = "GNGGA,";
278 }
[1381]279
280 const char* flagN="N";
281 const char* flagE="E";
282 if (lon >180.) {lon=(lon-360.)*(-1.); flagE="W";}
283 if ((lon < 0.) && (lon >= -180.)) {lon=lon*(-1.); flagE="W";}
284 if (lon < -180.) {lon=(lon+360.); flagE="E";}
285 if (lat < 0.) {lat=lat*(-1.); flagN="S";}
286 QTime ttime(QDateTime::currentDateTime().toUTC().time());
[7527]287 int lat_deg = (int)lat;
[1381]288 double lat_min=(lat-lat_deg)*60.;
[7527]289 int lon_deg = (int)lon;
[1381]290 double lon_min=(lon-lon_deg)*60.;
291 int hh = 0 , mm = 0;
292 double ss = 0.0;
293 hh=ttime.hour();
294 mm=ttime.minute();
295 ss=(double)ttime.second()+0.001*ttime.msec();
296 QString gga;
[6786]297 gga += sentences;
[1381]298 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'));
299 gga += QString("%1%2,").arg((int)lat_deg,2, 10, QLatin1Char('0')).arg(lat_min, 7, 'f', 4, QLatin1Char('0'));
300 gga += flagN;
301 gga += QString(",%1%2,").arg((int)lon_deg,3, 10, QLatin1Char('0')).arg(lon_min, 7, 'f', 4, QLatin1Char('0'));
[1595]302 gga += flagE + QString(",1,05,1.00");
[1599]303 gga += QString(",%1,").arg(hei, 2, 'f', 1);
[1595]304 gga += QString("M,10.000,M,,");
[1381]305 int xori;
[7527]306
[1381]307 char XOR = 0;
[7527]308 char Buff[gga.size()];
309 strncpy(Buff, gga.toAscii().data(), gga.size());
[1381]310 int iLen = strlen(Buff);
311 for (xori = 0; xori < iLen; xori++) {
312 XOR ^= (char)Buff[xori];
313 }
[1506]314 gga = "$" + gga + QString("*%1").arg(XOR, 2, 16, QLatin1Char('0'));
[1381]315
[1387]316 return gga.toAscii();
[1381]317}
[2043]318
[7527]319//
[2043]320////////////////////////////////////////////////////////////////////////////
321void RSW_to_XYZ(const ColumnVector& rr, const ColumnVector& vv,
322 const ColumnVector& rsw, ColumnVector& xyz) {
323
324 ColumnVector along = vv / vv.norm_Frobenius();
325 ColumnVector cross = crossproduct(rr, vv); cross /= cross.norm_Frobenius();
326 ColumnVector radial = crossproduct(along, cross);
327
328 Matrix RR(3,3);
329 RR.Column(1) = radial;
330 RR.Column(2) = along;
331 RR.Column(3) = cross;
332
333 xyz = RR * rsw;
334}
[2063]335
[2988]336// Transformation xyz --> radial, along track, out-of-plane
337////////////////////////////////////////////////////////////////////////////
338void XYZ_to_RSW(const ColumnVector& rr, const ColumnVector& vv,
339 const ColumnVector& xyz, ColumnVector& rsw) {
340
341 ColumnVector along = vv / vv.norm_Frobenius();
342 ColumnVector cross = crossproduct(rr, vv); cross /= cross.norm_Frobenius();
343 ColumnVector radial = crossproduct(along, cross);
344
345 rsw.ReSize(3);
346 rsw(1) = DotProduct(xyz, radial);
347 rsw(2) = DotProduct(xyz, along);
348 rsw(3) = DotProduct(xyz, cross);
349}
350
[2063]351// Rectangular Coordinates -> Ellipsoidal Coordinates
352////////////////////////////////////////////////////////////////////////////
353t_irc xyz2ell(const double* XYZ, double* Ell) {
354
355 const double bell = t_CST::aell*(1.0-1.0/t_CST::fInv) ;
356 const double e2 = (t_CST::aell*t_CST::aell-bell*bell)/(t_CST::aell*t_CST::aell) ;
357 const double e2c = (t_CST::aell*t_CST::aell-bell*bell)/(bell*bell) ;
[7527]358
[2063]359 double nn, ss, zps, hOld, phiOld, theta, sin3, cos3;
360
361 ss = sqrt(XYZ[0]*XYZ[0]+XYZ[1]*XYZ[1]) ;
362 zps = XYZ[2]/ss ;
363 theta = atan( (XYZ[2]*t_CST::aell) / (ss*bell) );
364 sin3 = sin(theta) * sin(theta) * sin(theta);
365 cos3 = cos(theta) * cos(theta) * cos(theta);
366
367 // Closed formula
[7527]368 Ell[0] = atan( (XYZ[2] + e2c * bell * sin3) / (ss - e2 * t_CST::aell * cos3) );
[2063]369 Ell[1] = atan2(XYZ[1],XYZ[0]) ;
370 nn = t_CST::aell/sqrt(1.0-e2*sin(Ell[0])*sin(Ell[0])) ;
371 Ell[2] = ss / cos(Ell[0]) - nn;
372
373 const int MAXITER = 100;
374 for (int ii = 1; ii <= MAXITER; ii++) {
375 nn = t_CST::aell/sqrt(1.0-e2*sin(Ell[0])*sin(Ell[0])) ;
376 hOld = Ell[2] ;
377 phiOld = Ell[0] ;
378 Ell[2] = ss/cos(Ell[0])-nn ;
379 Ell[0] = atan(zps/(1.0-e2*nn/(nn+Ell[2]))) ;
380 if ( fabs(phiOld-Ell[0]) <= 1.0e-11 && fabs(hOld-Ell[2]) <= 1.0e-5 ) {
381 return success;
382 }
383 }
384
385 return failure;
386}
[2065]387
388// Rectangular Coordinates -> North, East, Up Components
389////////////////////////////////////////////////////////////////////////////
390void xyz2neu(const double* Ell, const double* xyz, double* neu) {
391
392 double sinPhi = sin(Ell[0]);
393 double cosPhi = cos(Ell[0]);
394 double sinLam = sin(Ell[1]);
395 double cosLam = cos(Ell[1]);
396
397 neu[0] = - sinPhi*cosLam * xyz[0]
398 - sinPhi*sinLam * xyz[1]
399 + cosPhi * xyz[2];
400
401 neu[1] = - sinLam * xyz[0]
402 + cosLam * xyz[1];
403
404 neu[2] = + cosPhi*cosLam * xyz[0]
405 + cosPhi*sinLam * xyz[1]
406 + sinPhi * xyz[2];
407}
[2221]408
[2582]409// North, East, Up Components -> Rectangular Coordinates
410////////////////////////////////////////////////////////////////////////////
411void neu2xyz(const double* Ell, const double* neu, double* xyz) {
412
413 double sinPhi = sin(Ell[0]);
414 double cosPhi = cos(Ell[0]);
415 double sinLam = sin(Ell[1]);
416 double cosLam = cos(Ell[1]);
417
418 xyz[0] = - sinPhi*cosLam * neu[0]
419 - sinLam * neu[1]
420 + cosPhi*cosLam * neu[2];
421
422 xyz[1] = - sinPhi*sinLam * neu[0]
423 + cosLam * neu[1]
424 + cosPhi*sinLam * neu[2];
425
426 xyz[2] = + cosPhi * neu[0]
427 + sinPhi * neu[2];
428}
429
[7244]430// Rectangular Coordinates -> Geocentric Coordinates
431////////////////////////////////////////////////////////////////////////////
[7251]432t_irc xyz2geoc(const double* XYZ, double* Geoc) {
[7244]433
434 const double bell = t_CST::aell*(1.0-1.0/t_CST::fInv) ;
[7260]435 const double e2 = (t_CST::aell*t_CST::aell-bell*bell)/(t_CST::aell*t_CST::aell) ;
[7244]436 double Ell[3];
[7251]437 if (xyz2ell(XYZ, Ell) != success) {
438 return failure;
439 }
[7244]440 double rho = sqrt(XYZ[0]*XYZ[0]+XYZ[1]*XYZ[1]+XYZ[2]*XYZ[2]);
[7260]441 double Rn = t_CST::aell/sqrt(1-e2*pow(sin(Ell[0]),2));
[7244]442
443 Geoc[0] = atan((1-e2 * Rn/(Rn + Ell[2])) * tan(Ell[0]));
444 Geoc[1] = Ell[1];
445 Geoc[2] = rho-t_CST::rgeoc;
[7251]446
447 return success;
[7244]448}
449
[7527]450//
[5807]451////////////////////////////////////////////////////////////////////////////
452double Frac (double x) {
[7527]453 return x-floor(x);
[5807]454}
455
[7183]456//
[5807]457////////////////////////////////////////////////////////////////////////////
[7527]458double Modulo (double x, double y) {
459 return y*Frac(x/y);
[5807]460}
461
[5753]462// Round to nearest integer
463////////////////////////////////////////////////////////////////////////////
464double nint(double val) {
465 return ((val < 0.0) ? -floor(fabs(val)+0.5) : floor(val+0.5));
466}
467
[7183]468//
469////////////////////////////////////////////////////////////////////////////
470int factorial(int n) {
471 if (n == 0) {
472 return 1;
473 }
474 else {
475 return (n * factorial(n - 1));
476 }
477}
478
479//
480////////////////////////////////////////////////////////////////////////////
481double associatedLegendreFunction(int n, int m, double t) {
482 double sum = 0.0;
483 int r = (int) floor((n - m) / 2);
484 for (int k = 0; k <= r; k++) {
[7228]485 sum += (pow(-1.0, (double)k) * factorial(2*n - 2*k)
486 / (factorial(k) * factorial(n-k) * factorial(n-m-2*k))
487 * pow(t, (double)n-m-2*k));
[7183]488 }
489 double fac = pow(2.0,(double) -n) * pow((1 - t*t), (double)m/2);
490 return sum *= fac;
491}
492
493
[7527]494// Jacobian XYZ --> NEU
[5752]495////////////////////////////////////////////////////////////////////////////
496void jacobiXYZ_NEU(const double* Ell, Matrix& jacobi) {
497
498 Tracer tracer("jacobiXYZ_NEU");
499
500 double sinPhi = sin(Ell[0]);
501 double cosPhi = cos(Ell[0]);
502 double sinLam = sin(Ell[1]);
503 double cosLam = cos(Ell[1]);
504
505 jacobi(1,1) = - sinPhi * cosLam;
506 jacobi(1,2) = - sinPhi * sinLam;
507 jacobi(1,3) = cosPhi;
[7527]508
509 jacobi(2,1) = - sinLam;
[5752]510 jacobi(2,2) = cosLam;
[7527]511 jacobi(2,3) = 0.0;
512
513 jacobi(3,1) = cosPhi * cosLam;
514 jacobi(3,2) = cosPhi * sinLam;
[5752]515 jacobi(3,3) = sinPhi;
516}
517
518// Jacobian Ell --> XYZ
519////////////////////////////////////////////////////////////////////////////
520void jacobiEll_XYZ(const double* Ell, Matrix& jacobi) {
521
522 Tracer tracer("jacobiEll_XYZ");
523
524 double sinPhi = sin(Ell[0]);
525 double cosPhi = cos(Ell[0]);
526 double sinLam = sin(Ell[1]);
527 double cosLam = cos(Ell[1]);
528 double hh = Ell[2];
529
530 double bell = t_CST::aell*(1.0-1.0/t_CST::fInv);
531 double e2 = (t_CST::aell*t_CST::aell-bell*bell)/(t_CST::aell*t_CST::aell) ;
532 double nn = t_CST::aell/sqrt(1.0-e2*sinPhi*sinPhi) ;
533
534 jacobi(1,1) = -(nn+hh) * sinPhi * cosLam;
535 jacobi(1,2) = -(nn+hh) * cosPhi * sinLam;
536 jacobi(1,3) = cosPhi * cosLam;
537
538 jacobi(2,1) = -(nn+hh) * sinPhi * sinLam;
539 jacobi(2,2) = (nn+hh) * cosPhi * cosLam;
540 jacobi(2,3) = cosPhi * sinLam;
541
542 jacobi(3,1) = (nn*(1.0-e2)+hh) * cosPhi;
543 jacobi(3,2) = 0.0;
544 jacobi(3,3) = sinPhi;
[7527]545}
[5752]546
547// Covariance Matrix in NEU
548////////////////////////////////////////////////////////////////////////////
[7527]549void covariXYZ_NEU(const SymmetricMatrix& QQxyz, const double* Ell,
[5752]550 SymmetricMatrix& Qneu) {
551
552 Tracer tracer("covariXYZ_NEU");
553
554 Matrix CC(3,3);
555 jacobiXYZ_NEU(Ell, CC);
556 Qneu << CC * QQxyz * CC.t();
557}
558
559// Covariance Matrix in XYZ
560////////////////////////////////////////////////////////////////////////////
[7527]561void covariNEU_XYZ(const SymmetricMatrix& QQneu, const double* Ell,
[5752]562 SymmetricMatrix& Qxyz) {
563
564 Tracer tracer("covariNEU_XYZ");
565
566 Matrix CC(3,3);
567 jacobiXYZ_NEU(Ell, CC);
568 Qxyz << CC.t() * QQneu * CC;
569}
570
[2221]571// Fourth order Runge-Kutta numerical integrator for ODEs
572////////////////////////////////////////////////////////////////////////////
573ColumnVector rungeKutta4(
574 double xi, // the initial x-value
575 const ColumnVector& yi, // vector of the initial y-values
576 double dx, // the step size for the integration
[2556]577 double* acc, // aditional acceleration
578 ColumnVector (*der)(double x, const ColumnVector& y, double* acc)
[7527]579 // A pointer to a function that computes the
[2221]580 // derivative of a function at a point (x,y)
581 ) {
582
[2556]583 ColumnVector k1 = der(xi , yi , acc) * dx;
584 ColumnVector k2 = der(xi+dx/2.0, yi+k1/2.0, acc) * dx;
585 ColumnVector k3 = der(xi+dx/2.0, yi+k2/2.0, acc) * dx;
586 ColumnVector k4 = der(xi+dx , yi+k3 , acc) * dx;
[2221]587
588 ColumnVector yf = yi + k1/6.0 + k2/3.0 + k3/3.0 + k4/6.0;
[7527]589
[2221]590 return yf;
591}
[7527]592//
[3044]593////////////////////////////////////////////////////////////////////////////
[5886]594double djul(long jj, long mm, double tt) {
595 long ii, kk;
[3171]596 double djul ;
597 if( mm <= 2 ) {
598 jj = jj - 1;
599 mm = mm + 12;
[7527]600 }
[3171]601 ii = jj/100;
602 kk = 2 - ii + ii/4;
603 djul = (365.25*jj - fmod( 365.25*jj, 1.0 )) - 679006.0;
604 djul = djul + floor( 30.6001*(mm + 1) ) + tt + kk;
605 return djul;
[7527]606}
[3171]607
[7527]608//
[3171]609////////////////////////////////////////////////////////////////////////////
[5886]610double gpjd(double second, int nweek) {
611 double deltat;
612 deltat = nweek*7.0 + second/86400.0 ;
613 return( 44244.0 + deltat) ;
[7527]614}
[5886]615
[7527]616//
[5886]617////////////////////////////////////////////////////////////////////////////
618void jdgp(double tjul, double & second, long & nweek) {
[3171]619 double deltat;
620 deltat = tjul - 44244.0 ;
[5886]621 nweek = (long) floor(deltat/7.0);
[3171]622 second = (deltat - (nweek)*7.0)*86400.0;
623}
624
[7527]625//
[3171]626////////////////////////////////////////////////////////////////////////////
[5886]627void jmt(double djul, long& jj, long& mm, double& dd) {
628 long ih, ih1, ih2 ;
629 double t1, t2, t3, t4;
630 t1 = 1.0 + djul - fmod( djul, 1.0 ) + 2400000.0;
631 t4 = fmod( djul, 1.0 );
632 ih = long( (t1 - 1867216.25)/36524.25 );
633 t2 = t1 + 1 + ih - ih/4;
634 t3 = t2 - 1720995.0;
635 ih1 = long( (t3 - 122.1)/365.25 );
636 t1 = 365.25*ih1 - fmod( 365.25*ih1, 1.0 );
637 ih2 = long( (t3 - t1)/30.6001 );
638 dd = t3 - t1 - (int)( 30.6001*ih2 ) + t4;
639 mm = ih2 - 1;
640 if ( ih2 > 13 ) mm = ih2 - 13;
641 jj = ih1;
642 if ( mm <= 2 ) jj = jj + 1;
[7527]643}
[5886]644
[7527]645//
[5886]646////////////////////////////////////////////////////////////////////////////
[7527]647void GPSweekFromDateAndTime(const QDateTime& dateTime,
[3044]648 int& GPSWeek, double& GPSWeeks) {
649
650 static const QDateTime zeroEpoch(QDate(1980, 1, 6),QTime(),Qt::UTC);
[7527]651
[3044]652 GPSWeek = zeroEpoch.daysTo(dateTime) / 7;
653
654 int weekDay = dateTime.date().dayOfWeek() + 1; // Qt: Monday = 1
655 if (weekDay > 7) weekDay = 1;
656
657 GPSWeeks = (weekDay - 1) * 86400.0
[7527]658 - dateTime.time().msecsTo(QTime()) / 1e3;
[3044]659}
660
[7527]661//
[3044]662////////////////////////////////////////////////////////////////////////////
[3171]663void GPSweekFromYMDhms(int year, int month, int day, int hour, int min,
664 double sec, int& GPSWeek, double& GPSWeeks) {
665
666 double mjd = djul(year, month, day);
667
[5888]668 long GPSWeek_long;
669 jdgp(mjd, GPSWeeks, GPSWeek_long);
670 GPSWeek = GPSWeek_long;
[7527]671 GPSWeeks += hour * 3600.0 + min * 60.0 + sec;
[3171]672}
673
[7527]674//
[3171]675////////////////////////////////////////////////////////////////////////////
[3044]676void mjdFromDateAndTime(const QDateTime& dateTime, int& mjd, double& dayfrac) {
677
678 static const QDate zeroDate(1858, 11, 17);
679
680 mjd = zeroDate.daysTo(dateTime.date());
681
682 dayfrac = (dateTime.time().hour() +
683 (dateTime.time().minute() +
[7527]684 (dateTime.time().second() +
[3044]685 dateTime.time().msec() / 1000.0) / 60.0) / 60.0) / 24.0;
686}
[3408]687
[7527]688//
[3408]689////////////////////////////////////////////////////////////////////////////
690bool findInVector(const vector<QString>& vv, const QString& str) {
691 std::vector<QString>::const_iterator it;
692 for (it = vv.begin(); it != vv.end(); ++it) {
693 if ( (*it) == str) {
694 return true;
695 }
696 }
697 return false;
698}
699
[7527]700//
[3664]701////////////////////////////////////////////////////////////////////////////
702int readInt(const QString& str, int pos, int len, int& value) {
703 bool ok;
704 value = str.mid(pos, len).toInt(&ok);
705 return ok ? 0 : 1;
706}
707
[7527]708//
[3664]709////////////////////////////////////////////////////////////////////////////
710int readDbl(const QString& str, int pos, int len, double& value) {
711 QString hlp = str.mid(pos, len);
712 for (int ii = 0; ii < hlp.length(); ii++) {
713 if (hlp[ii]=='D' || hlp[ii]=='d' || hlp[ii] == 'E') {
714 hlp[ii]='e';
715 }
716 }
717 bool ok;
718 value = hlp.toDouble(&ok);
719 return ok ? 0 : 1;
720}
[4338]721
722// Topocentrical Distance and Elevation
723////////////////////////////////////////////////////////////////////////////
[7527]724void topos(double xRec, double yRec, double zRec,
725 double xSat, double ySat, double zSat,
[4338]726 double& rho, double& eleSat, double& azSat) {
727
728 double dx[3];
729 dx[0] = xSat-xRec;
730 dx[1] = ySat-yRec;
731 dx[2] = zSat-zRec;
732
[7527]733 rho = sqrt( dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2] );
[4338]734
735 double xyzRec[3];
736 xyzRec[0] = xRec;
737 xyzRec[1] = yRec;
738 xyzRec[2] = zRec;
739
740 double Ell[3];
741 double neu[3];
742 xyz2ell(xyzRec, Ell);
743 xyz2neu(Ell, dx, neu);
744
745 eleSat = acos( sqrt(neu[0]*neu[0] + neu[1]*neu[1]) / rho );
746 if (neu[2] < 0) {
747 eleSat *= -1.0;
748 }
749
750 azSat = atan2(neu[1], neu[0]);
751}
[5230]752
753// Degrees -> degrees, minutes, seconds
754////////////////////////////////////////////////////////////////////////////
755void deg2DMS(double decDeg, int& deg, int& min, double& sec) {
756 int sgn = (decDeg < 0.0 ? -1 : 1);
[7787]757 deg = static_cast<int>(decDeg);
758 min = sgn * static_cast<int>((decDeg - deg)*60);
759 sec = (sgn* (decDeg - deg) - min/60.0) * 3600.0;
[5230]760}
[5310]761
[7527]762//
[5310]763////////////////////////////////////////////////////////////////////////////
764QString fortranFormat(double value, int width, int prec) {
[6537]765 int expo = value == 0.0 ? 0 : int(log10(fabs(value)));
[7656]766 double mant = value == 0.0 ? 0 : value / pow(10.0, double(expo));
[5310]767 if (fabs(mant) >= 1.0) {
768 mant /= 10.0;
769 expo += 1;
770 }
771 if (expo >= 0) {
772 return QString("%1e+%2").arg(mant, width-4, 'f', prec).arg(expo, 2, 10, QChar('0'));
773 }
774 else {
775 return QString("%1e-%2").arg(mant, width-4, 'f', prec).arg(-expo, 2, 10, QChar('0'));
776 }
777}
[5807]778
779//
780//////////////////////////////////////////////////////////////////////////////
[7527]781void kalman(const Matrix& AA, const ColumnVector& ll, const DiagonalMatrix& PP,
[6168]782 SymmetricMatrix& QQ, ColumnVector& xx) {
[5807]783
784 Tracer tracer("kalman");
785
786 int nPar = AA.Ncols();
787 int nObs = AA.Nrows();
788 UpperTriangularMatrix SS = Cholesky(QQ).t();
789
790 Matrix SA = SS*AA.t();
791 Matrix SRF(nObs+nPar, nObs+nPar); SRF = 0;
792 for (int ii = 1; ii <= nObs; ++ii) {
793 SRF(ii,ii) = 1.0 / sqrt(PP(ii,ii));
794 }
795
796 SRF.SubMatrix (nObs+1, nObs+nPar, 1, nObs) = SA;
797 SRF.SymSubMatrix(nObs+1, nObs+nPar) = SS;
[7527]798
[5807]799 UpperTriangularMatrix UU;
800 QRZ(SRF, UU);
[7527]801
[5807]802 SS = UU.SymSubMatrix(nObs+1, nObs+nPar);
803 UpperTriangularMatrix SH_rt = UU.SymSubMatrix(1, nObs);
804 Matrix YY = UU.SubMatrix(1, nObs, nObs+1, nObs+nPar);
[7527]805
[5807]806 UpperTriangularMatrix SHi = SH_rt.i();
[7527]807
808 Matrix KT = SHi * YY;
[5807]809 SymmetricMatrix Hi; Hi << SHi * SHi.t();
810
[6168]811 xx += KT.t() * (ll - AA * xx);
[5807]812 QQ << (SS.t() * SS);
813}
814
[6799]815double accuracyFromIndex(int index, t_eph::e_type type) {
816
817 if (type == t_eph::GPS || type == t_eph::BDS || type == t_eph::SBAS
818 || type == t_eph::QZSS) {
819
820 if ((index >= 0) && (index <= 6)) {
821 if (index == 3) {
822 return ceil(10.0 * pow(2.0, (double(index) / 2.0) + 1.0)) / 10.0;
823 }
824 else {
825 return floor(10.0 * pow(2.0, (double(index) / 2.0) + 1.0)) / 10.0;
826 }
827 }
828 else if ((index > 6) && (index <= 15)) {
829 return (10.0 * pow(2.0, (double(index) - 2.0))) / 10.0;
830 }
831 else {
832 return 8192.0;
833 }
834 }
835
836 if (type == t_eph::Galileo) {
837
838 if ((index >= 0) && (index <= 49)) {
839 return (double(index) / 100.0);
840 }
841 else if ((index > 49) && (index <= 74)) {
842 return (50.0 + (double(index) - 50.0) * 2.0) / 100.0;
843 }
844 else if ((index > 74) && (index <= 99)) {
845 return 1.0 + (double(index) - 75.0) * 0.04;
846 }
847 else if ((index > 99) && (index <= 125)) {
848 return 2.0 + (double(index) - 100.0) * 0.16;
849 }
850 else {
851 return -1.0;
852 }
853 }
854
855 return double(index);
856}
857
858int indexFromAccuracy(double accuracy, t_eph::e_type type) {
859
860 if (type == t_eph::GPS || type == t_eph::BDS || type == t_eph::SBAS
861 || type == t_eph::QZSS) {
862
863 if (accuracy <= 2.40) {
864 return 0;
865 }
866 else if (accuracy <= 3.40) {
867 return 1;
868 }
869 else if (accuracy <= 4.85) {
870 return 2;
871 }
872 else if (accuracy <= 6.85) {
873 return 3;
874 }
875 else if (accuracy <= 9.65) {
876 return 4;
877 }
878 else if (accuracy <= 13.65) {
879 return 5;
880 }
881 else if (accuracy <= 24.00) {
882 return 6;
883 }
884 else if (accuracy <= 48.00) {
885 return 7;
886 }
887 else if (accuracy <= 96.00) {
888 return 8;
889 }
890 else if (accuracy <= 192.00) {
891 return 9;
892 }
893 else if (accuracy <= 384.00) {
894 return 10;
895 }
896 else if (accuracy <= 768.00) {
897 return 11;
898 }
899 else if (accuracy <= 1536.00) {
900 return 12;
901 }
902 else if (accuracy <= 3072.00) {
903 return 13;
904 }
905 else if (accuracy <= 6144.00) {
906 return 14;
907 }
908 else {
909 return 15;
910 }
911 }
912
913 if (type == t_eph::Galileo) {
[6800]914
915 if (accuracy <= 0.49) {
916 return int(ceil(accuracy * 100.0));
917 }
918 else if (accuracy <= 0.98) {
919 return int(50.0 + (((accuracy * 100.0) - 50) / 2.0));
920 }
921 else if (accuracy <= 2.0) {
922 return int(75.0 + ((accuracy - 1.0) / 0.04));
923 }
924 else if (accuracy <= 6.0) {
925 return int(100.0 + ((accuracy - 2.0) / 0.16));
926 }
927 else {
928 return 255;
929 }
[6799]930 }
931
932 return (type == t_eph::Galileo) ? 255 : 15;
933}
[7053]934
935// Returns CRC24
936////////////////////////////////////////////////////////////////////////////
937unsigned long CRC24(long size, const unsigned char *buf) {
938 unsigned long crc = 0;
939 int ii;
940 while (size--) {
941 crc ^= (*buf++) << (16);
942 for(ii = 0; ii < 8; ii++) {
943 crc <<= 1;
944 if (crc & 0x1000000) {
945 crc ^= 0x01864cfb;
946 }
947 }
948 }
949 return crc;
950}
951
Note: See TracBrowser for help on using the repository browser.