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

Last change on this file since 10555 was 10533, checked in by stuerze, 10 months ago

Service and RTCM CRS encoding and decoding as well as Helmert parameter decoding added + some re-organisation

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