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

Last change on this file since 10371 was 10330, checked in by stuerze, 10 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
Line 
1// Part of BNC, a utility for retrieving decoding and
2// converting GNSS data streams from NTRIP broadcasters.
3//
4// Copyright (C) 2007
5// German Federal Agency for Cartography and Geodesy (BKG)
6// http://www.bkg.bund.de
7// Czech Technical University Prague, Department of Geodesy
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.
24
25/* -------------------------------------------------------------------------
26 * BKG NTRIP Client
27 * -------------------------------------------------------------------------
28 *
29 * Class: bncutils
30 *
31 * Purpose: Auxiliary Functions
32 *
33 * Author: L. Mervart
34 *
35 * Created: 30-Aug-2006
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <iostream>
42#include <ctime>
43#include <math.h>
44
45#include <QRegExp>
46#include <QStringList>
47#include <QDateTime>
48
49#include <newmatap.h>
50
51#include "bncutils.h"
52#include "bnccore.h"
53
54using namespace std;
55
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},
91{31, 12, 2016,37},
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
148 // new version
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
161//
162////////////////////////////////////////////////////////////////////////////
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.toLatin1()));
173 }
174 }
175}
176
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
190//
191////////////////////////////////////////////////////////////////////////////
192QDateTime dateAndTimeFromGPSweek(int GPSWeek, double GPSWeeks) {
193
194 static const QDate zeroEpoch(1980, 1, 6);
195
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}
205
206//
207////////////////////////////////////////////////////////////////////////////
208void currentGPSWeeks(int& week, double& sec) {
209
210 QDateTime currDateTimeGPS;
211
212 if ( BNC_CORE->dateAndTimeGPSSet() ) {
213 currDateTimeGPS = BNC_CORE->dateAndTimeGPS();
214 }
215 else {
216 currDateTimeGPS = QDateTime::currentDateTime().toUTC();
217 QDate hlp = currDateTimeGPS.date();
218 currDateTimeGPS = currDateTimeGPS.addSecs(gnumleap(hlp.year(),
219 hlp.month(), hlp.day()));
220 }
221
222 QDate currDateGPS = currDateTimeGPS.date();
223 QTime currTimeGPS = currDateTimeGPS.time();
224
225 week = int( (double(currDateGPS.toJulianDay()) - 2444244.5) / 7 );
226
227 sec = (currDateGPS.dayOfWeek() % 7) * 24.0 * 3600.0 +
228 currTimeGPS.hour() * 3600.0 +
229 currTimeGPS.minute() * 60.0 +
230 currTimeGPS.second() +
231 currTimeGPS.msec() / 1000.0;
232}
233
234//
235////////////////////////////////////////////////////////////////////////////
236QDateTime currentDateAndTimeGPS() {
237 if ( BNC_CORE->dateAndTimeGPSSet() ) {
238 return BNC_CORE->dateAndTimeGPS();
239 }
240 else {
241 int GPSWeek;
242 double GPSWeeks;
243 currentGPSWeeks(GPSWeek, GPSWeeks);
244 return dateAndTimeFromGPSweek(GPSWeek, GPSWeeks);
245 }
246}
247
248//
249////////////////////////////////////////////////////////////////////////////
250bool checkForWrongObsEpoch(bncTime obsEpoch) {
251 const double maxDt = 600.0;
252 bncTime obsTime = obsEpoch;
253 int week;
254 double sec;
255 currentGPSWeeks(week, sec);
256 bncTime currTime(week, sec);
257
258 if (((currTime - obsTime) < 0.0) ||
259 (fabs(currTime - obsTime) > maxDt)) {
260 return true;
261 }
262 return false;
263}
264
265//
266////////////////////////////////////////////////////////////////////////////
267bool outDatedBcep(const t_eph *eph, bncTime tt) {
268 bncTime toc = eph->TOC();
269 double dt = tt -toc;
270
271 // update interval: 2h, data sets are valid for 4 hours
272 if (eph->type() == t_eph::GPS && (dt > 14400.0 || dt < -7200.0)) {
273 return true;
274 }
275 // update interval: 3h, data sets are valid for 4 hours
276 else if (eph->type() == t_eph::Galileo && (dt > 14400.0 || dt < 0.0)) {
277 return true;
278 }
279 // updated every 30 minutes + 5 min
280 else if (eph->type() == t_eph::GLONASS && (dt > 2100.0 || dt < -2100.0)) {
281 return true;
282 }
283 // orbit parameters are valid for 7200 seconds (minimum)
284 else if (eph->type() == t_eph::QZSS && (dt > 7200.0 || dt < -3600.0)) {
285 return true;
286 }
287 // maximum update interval: 300 sec
288 else if (eph->type() == t_eph::SBAS && (dt > 600.0 || dt < -600.0)) {
289 return true;
290 }
291 // updates 1h + 5 min
292 else if (eph->type() == t_eph::BDS && (dt > 3900.0 || dt < 0.0) ) {
293 return true;
294 }
295 // update interval: up to 24 hours
296 else if (eph->type() == t_eph::IRNSS && (fabs(dt > 86400.0))) {
297 return true;
298 }
299
300 return false;
301}
302
303//
304////////////////////////////////////////////////////////////////////////////
305QByteArray ggaString(const QByteArray& latitude,
306 const QByteArray& longitude,
307 const QByteArray& height,
308 const QString& ggaType) {
309
310 double lat = strtod(latitude,NULL);
311 double lon = strtod(longitude,NULL);
312 double hei = strtod(height,NULL);
313 QString sentences = "GPGGA,";
314 if (ggaType.contains("GNGGA")) {
315 sentences = "GNGGA,";
316 }
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());
325 int lat_deg = (int)lat;
326 double lat_min=(lat-lat_deg)*60.;
327 int lon_deg = (int)lon;
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;
335 gga += sentences;
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'));
340 gga += flagE + QString(",1,05,1.00");
341 gga += QString(",%1,").arg(hei, 2, 'f', 1);
342 gga += QString("M,10.000,M,,");
343
344 unsigned char XOR = 0;
345 for (int ii = 0; ii < gga.length(); ii++) {
346 XOR ^= (unsigned char) gga[ii].toLatin1();
347 }
348 gga = "$" + gga + QString("*%1").arg(XOR, 2, 16, QLatin1Char('0')) + "\r\n";
349
350 return gga.toLatin1();
351}
352
353//
354////////////////////////////////////////////////////////////////////////////
355void RSW_to_XYZ(const ColumnVector& rr, const ColumnVector& vv,
356 const ColumnVector& rsw, ColumnVector& xyz) {
357
358 ColumnVector along = vv / vv.NormFrobenius();
359 ColumnVector cross = crossproduct(rr, vv); cross /= cross.NormFrobenius();
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}
369
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
375 ColumnVector along = vv / vv.NormFrobenius();
376 ColumnVector cross = crossproduct(rr, vv); cross /= cross.NormFrobenius();
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
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) ;
392
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
402 Ell[0] = atan( (XYZ[2] + e2c * bell * sin3) / (ss - e2 * t_CST::aell * cos3) );
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}
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}
442
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
464// Rectangular Coordinates -> Geocentric Coordinates
465////////////////////////////////////////////////////////////////////////////
466t_irc xyz2geoc(const double* XYZ, double* Geoc) {
467
468 const double bell = t_CST::aell*(1.0-1.0/t_CST::fInv) ;
469 const double e2 = (t_CST::aell*t_CST::aell-bell*bell)/(t_CST::aell*t_CST::aell) ;
470 double Ell[3];
471 if (xyz2ell(XYZ, Ell) != success) {
472 return failure;
473 }
474 double rho = sqrt(XYZ[0]*XYZ[0]+XYZ[1]*XYZ[1]+XYZ[2]*XYZ[2]);
475 double Rn = t_CST::aell/sqrt(1-e2*pow(sin(Ell[0]),2));
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;
480
481 return success;
482}
483
484//
485////////////////////////////////////////////////////////////////////////////
486double Frac (double x) {
487 return x-floor(x);
488}
489
490//
491////////////////////////////////////////////////////////////////////////////
492double Modulo (double x, double y) {
493 return y*Frac(x/y);
494}
495
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
502//
503////////////////////////////////////////////////////////////////////////////
504double factorial(int n) {
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++) {
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));
522 }
523 double fac = pow(2.0,(double) -n) * pow((1 - t*t), (double)m/2);
524 return sum *= fac;
525}
526
527
528// Jacobian XYZ --> NEU
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;
542
543 jacobi(2,1) = - sinLam;
544 jacobi(2,2) = cosLam;
545 jacobi(2,3) = 0.0;
546
547 jacobi(3,1) = cosPhi * cosLam;
548 jacobi(3,2) = cosPhi * sinLam;
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;
579}
580
581// Covariance Matrix in NEU
582////////////////////////////////////////////////////////////////////////////
583void covariXYZ_NEU(const SymmetricMatrix& QQxyz, const double* Ell,
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////////////////////////////////////////////////////////////////////////////
595void covariNEU_XYZ(const SymmetricMatrix& QQneu, const double* Ell,
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
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
611 double* acc, // additional acceleration
612 ColumnVector (*der)(double x, const ColumnVector& y, double* acc)
613 // A pointer to a function that computes the
614 // derivative of a function at a point (x,y)
615 ) {
616
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;
621
622 ColumnVector yf = yi + k1/6.0 + k2/3.0 + k3/3.0 + k4/6.0;
623
624 return yf;
625}
626//
627////////////////////////////////////////////////////////////////////////////
628double djul(long jj, long mm, double tt) {
629 long ii, kk;
630 double djul ;
631 if( mm <= 2 ) {
632 jj = jj - 1;
633 mm = mm + 12;
634 }
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;
640}
641
642//
643////////////////////////////////////////////////////////////////////////////
644double gpjd(double second, int nweek) {
645 double deltat;
646 deltat = nweek*7.0 + second/86400.0 ;
647 return( 44244.0 + deltat) ;
648}
649
650//
651////////////////////////////////////////////////////////////////////////////
652void jdgp(double tjul, double & second, long & nweek) {
653 double deltat;
654 deltat = tjul - 44244.0 ;
655 nweek = (long) floor(deltat/7.0);
656 second = (deltat - (nweek)*7.0)*86400.0;
657}
658
659//
660////////////////////////////////////////////////////////////////////////////
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;
677}
678
679//
680////////////////////////////////////////////////////////////////////////////
681void GPSweekFromDateAndTime(const QDateTime& dateTime,
682 int& GPSWeek, double& GPSWeeks) {
683
684 static const QDateTime zeroEpoch(QDate(1980, 1, 6),QTime(),Qt::UTC);
685
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
692 - dateTime.time().msecsTo(QTime()) / 1e3;
693}
694
695//
696////////////////////////////////////////////////////////////////////////////
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
702 long GPSWeek_long;
703 jdgp(mjd, GPSWeeks, GPSWeek_long);
704 GPSWeek = GPSWeek_long;
705 GPSWeeks += hour * 3600.0 + min * 60.0 + sec;
706}
707
708//
709////////////////////////////////////////////////////////////////////////////
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() +
718 (dateTime.time().second() +
719 dateTime.time().msec() / 1000.0) / 60.0) / 60.0) / 24.0;
720}
721
722//
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
734//
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
742//
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}
755
756// Topocentrical Distance and Elevation
757////////////////////////////////////////////////////////////////////////////
758void topos(double xRec, double yRec, double zRec,
759 double xSat, double ySat, double zSat,
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
767 rho = sqrt( dx[0]*dx[0] + dx[1]*dx[1] + dx[2]*dx[2] );
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 );
780 if (neu[2] < 0.0) {
781 eleSat *= -1.0;
782 }
783
784 azSat = atan2(neu[1], neu[0]);
785}
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);
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;
794}
795
796//
797////////////////////////////////////////////////////////////////////////////
798QString fortranFormat(double value, int width, int prec) {
799 int expo = value == 0.0 ? 0 : int(log10(fabs(value)));
800 double mant = value == 0.0 ? 0 : value / pow(10.0, double(expo));
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}
812
813//
814//////////////////////////////////////////////////////////////////////////////
815void kalman(const Matrix& AA, const ColumnVector& ll, const DiagonalMatrix& PP,
816 SymmetricMatrix& QQ, ColumnVector& xx) {
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;
832
833 UpperTriangularMatrix UU;
834 QRZ(SRF, UU);
835
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);
839
840 UpperTriangularMatrix SHi = SH_rt.i();
841
842 Matrix KT = SHi * YY;
843 SymmetricMatrix Hi; Hi << SHi * SHi.t();
844
845 xx += KT.t() * (ll - AA * xx);
846 QQ << (SS.t() * SS);
847}
848
849//
850////////////////////////////////////////////////////////////////////////////
851double accuracyFromIndex(int index, t_eph::e_type type) {
852double accuracy = -1.0;
853
854 if (type == t_eph::GPS ||
855 type == t_eph::BDS ||
856 type == t_eph::SBAS||
857 type == t_eph::QZSS) {
858 if ((index >= 0) && (index <= 6)) {
859 if (index == 3) {
860 accuracy = ceil(10.0 * pow(2.0, (double(index) / 2.0) + 1.0)) / 10.0;
861 }
862 else {
863 accuracy = floor(10.0 * pow(2.0, (double(index) / 2.0) + 1.0)) / 10.0;
864 }
865 }
866 else if ((index > 6) && (index <= 15)) {
867 accuracy = (10.0 * pow(2.0, (double(index) - 2.0))) / 10.0;
868 }
869 else {
870 accuracy = 8192.0;
871 }
872 }
873 else if (type == t_eph::Galileo) {
874 if ((index >= 0) && (index <= 49)) {
875 accuracy = (double(index) / 100.0);
876 }
877 else if ((index > 49) && (index <= 74)) {
878 accuracy = (50.0 + (double(index) - 50.0) * 2.0) / 100.0;
879 }
880 else if ((index > 74) && (index <= 99)) {
881 accuracy = 1.0 + (double(index) - 75.0) * 0.04;
882 }
883 else if ((index > 99) && (index <= 125)) {
884 accuracy = 2.0 + (double(index) - 100.0) * 0.16;
885 }
886 else {
887 accuracy = -1.0;
888 }
889 }
890 else if (type == t_eph::IRNSS) {
891 if ((index >= 0) && (index <= 6)) {
892 if (index == 1) {
893 accuracy = 2.8;
894 }
895 else if (index == 3) {
896 accuracy = 5.7;
897 }
898 else if (index == 5) {
899 accuracy = 11.3;
900 }
901 else {
902 accuracy = pow(2, 1 + index / 2);
903 }
904 }
905 else if ((index > 6) && (index <= 15)) {
906 accuracy = pow(2, index - 2);
907 }
908 }
909 return accuracy;
910}
911
912//
913////////////////////////////////////////////////////////////////////////////
914int indexFromAccuracy(double accuracy, t_eph::e_type type) {
915
916 if (type == t_eph::GPS ||
917 type == t_eph::BDS ||
918 type == t_eph::SBAS ||
919 type == t_eph::QZSS) {
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) {
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 }
988 }
989
990 return (type == t_eph::Galileo) ? 255 : 15;
991}
992
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
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
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
1052// Convert RTCM3 lock-time indicator to minimum lock time in seconds
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;
1066 else return -1.0;
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;
1087 default : return -1.0;
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;
1114 else return ( -1.0 );
1115 }
1116 else {
1117 return -1.0;
1118 };
1119};
Note: See TracBrowser for help on using the repository browser.