30static const double CLIGHT = 299792458.0;
31static const double D2R = 3.1415926535897932 / 180.0;
32static const double R2D = 180.0 / 3.1415926535897932;
33static const double OMGE = 7.2921151467E-5;
35static const double FREQ1 = 1.57542E9;
36static const double FREQ2 = 1.22760E9;
37static const double FREQ5 = 1.17645E9;
38static const double FREQ7 = 1.20714E9;
39static const double FREQ9 = 2.492028E9;
62const double chisqr[100] = {10.8, 13.8, 16.3, 18.5, 20.5, 22.5, 24.3, 26.1, 27.9, 29.6, 31.3, 32.9, 34.5, 36.1, 37.7,
63 39.3, 40.8, 42.3, 43.8, 45.3, 46.8, 48.3, 49.7, 51.2, 52.6, 54.1, 55.5, 56.9, 58.3, 59.7,
64 61.1, 62.5, 63.9, 65.2, 66.6, 68.0, 69.3, 70.7, 72.1, 73.4, 74.7, 76.0, 77.3, 78.6, 80.0,
65 81.3, 82.6, 84.0, 85.4, 86.7, 88.0, 89.3, 90.6, 91.9, 93.3, 94.7, 96.0, 97.4, 98.7, 100,
66 101, 102, 103, 104, 105, 107, 108, 109, 110, 112, 113, 114, 115, 116, 118,
67 119, 120, 122, 123, 125, 126, 127, 128, 129, 131, 132, 133, 134, 135, 137,
68 138, 139, 140, 142, 143, 144, 145, 147, 148, 149};
72#define SQR(x) ((x) * (x))
79#define MIN_EL (5.0 * D2R)
92 varr =
SQR(fact) * varr;
98 if (opt->
err[6] > 0.0 && snr > 0.0) {
99 double e = fact * opt->
err[6];
100 double d = opt->
err[5] - snr;
101 varr +=
SQR(e) * pow(10.0, 0.1 * (d > 0.0 ? d : 0.0));
107 int i, sys =
satsys(sat, NULL);
110 for (i = 0; i < nav->
ng; i++) {
117 for (i = 0; i < nav->
n; i++) {
118 if (nav->
eph[i].
sat == sat) {
140 for (j = 2; j < NFREQ; j++) {
141 if (obs->
P[j] != 0.0 && (!nav ||
sat2freq(obs->
sat, obs->
code[j], nav) != 0.0)) {
163 double P1, P2, gamma, b1, b2, freq1, freq2;
164 int sat, sys, i2 = 1;
182 gamma =
SQR(freq1 / freq2);
187 P1 += nav->
cbias[sat - 1][1];
190 P2 += nav->
cbias[sat - 1][2];
195 if (P1 == 0.0 || P2 == 0.0) {
200 return (P2 - gamma * P1) / (1.0 - gamma);
202 return (P2 - gamma * P1) / (1.0 - gamma);
207 return (P2 - gamma * P1) / (1.0 - gamma);
217 return ((P2 - gamma * P1) - (b2 - gamma * b1)) / (1.0 - gamma);
219 return (P2 - gamma * P1) / (1.0 - gamma);
229 return P1 - b1 / (gamma - 1.0);
248 return P1 - gamma * b1;
256static int rescode(
int iter,
const obsd_t* obs,
int n,
const double* rs,
const double* dts,
const double* vare,
257 const int* svh,
const nav_t* nav,
const double* x,
const prcopt_t* opt,
double* v,
double* H,
258 double* var,
double* azel,
int* vsat,
double* resp,
int* ns,
const int* outp) {
260 double r, freq, dion = 0.0, dtrp = 0.0, vmeas, vion = 0.0, vtrp = 0.0, rr[3], pos[3], dtr;
261 double e[3], P, fact_ion;
262 int i, j, nv = 0, sat, sys, mask[
NX - 3] = {0};
264 trace(NULL, 3,
"resprng : n=%d\n", n);
266 for (i = 0; i < 3; i++) {
273 for (i = *ns = 0; i < n && i <
MAXOBS; i++) {
275 azel[i * 2] = azel[1 + i * 2] = resp[i] = 0.0;
283 if (i < n - 1 && i <
MAXOBS - 1 && sat == obs[i + 1].sat) {
284 trace(NULL, 2,
"duplicated obs data %s sat=%d\n",
time_str(time, 3), sat);
289 if (sat >= 1 && sat <=
MAXSAT && outp && outp[sat - 1]) {
297 if ((r =
geodist(rs + i * 6, rr, e)) <= 0.0) {
308 if (!
snrmask(obs + i, azel + i * 2, opt)) {
313 if (!
ionocorr(time, nav, sat, pos, azel + i * 2, opt->
ionoopt, &dion, &vion)) {
316 if ((freq =
sat2freq(sat, obs[i].code[0], nav)) == 0.0) {
321 vion *=
SQR(fact_ion);
324 if (!
tropcorr(time, nav, pos, azel + i * 2, opt->
tropopt, &dtrp, &vtrp)) {
329 if ((P =
prange(obs + i, nav, opt, &vmeas)) == 0.0) {
334 v[nv] = P - (r + dtr -
CLIGHT * dts[i * 2] + dion + dtrp);
337 for (j = 0; j <
NX; j++) {
338 H[j + nv *
NX] = j < 3 ? -e[j] : (j == 3 ? 1.0 : 0.0);
343 H[4 + nv *
NX] = 1.0;
347 H[5 + nv *
NX] = 1.0;
351 H[6 + nv *
NX] = 1.0;
356 H[7 + nv *
NX] = 1.0;
360 H[8 + nv *
NX] = 1.0;
364 H[9 + nv *
NX] = 1.0;
376 var[nv++] =
varerr(opt, azel[1 + i * 2], obs[i].SNR[0] *
SNR_UNIT, sys) + vare[i] + vmeas + vion + vtrp;
378 trace(NULL, 4,
"sat=%2d azel=%5.1f %4.1f res=%7.3f sig=%5.3f\n", obs[i].sat, azel[i * 2] *
R2D,
379 azel[1 + i * 2] *
R2D, resp[i], sqrt(var[nv - 1]));
382 for (i = 0; i <
NT; i++) {
387 for (j = 0; j <
NX; j++) {
388 H[j + nv *
NX] = j == i + 3 ? 1.0 : 0.0;
395static int valsol(
const double* azel,
const int* vsat,
int n,
const prcopt_t* opt,
const double* v,
int nv,
int nx,
397 double azels[
MAXOBS * 2], dop[4], vv;
400 trace(NULL, 3,
"valsol : n=%d nv=%d\n", n, nv);
404 if (nv > nx && vv >
chisqr[nv - nx - 1]) {
405 sprintf(msg,
"chi-square error nv=%d vv=%.1f cs=%.1f", nv, vv,
chisqr[nv - nx - 1]);
409 trace(NULL, 2,
"ignore %s\n", msg);
412 for (i = ns = 0; i < n; i++) {
416 azels[ns * 2] = azel[i * 2];
417 azels[1 + ns * 2] = azel[1 + i * 2];
421 trace(NULL, 4,
"valsol : n=%d nv=%d vv=%.1f cs=%.1f maxgdop=%.1f gdop=%.1f pdop=%.1f hdop=%.1f vdop=%.1f\n", n, nv,
422 vv, nv > nx ?
chisqr[nv - nx - 1] : 0.0, opt->
maxgdop, dop[0], dop[1], dop[2], dop[3]);
423 if (dop[0] <= 0.0 || dop[0] > opt->
maxgdop) {
424 sprintf(msg,
"gdop error nv=%d gdop=%.1f", nv, dop[0]);
434 for (i = j = 0; i < n && i <
MAXOBS; i++) {
438 v2 += resp[i] * resp[i];
441 if (j == 0 || v2 / j > thres) {
444 for (i = 0; i < n && i <
MAXOBS; i++) {
445 int sat = obs[i].
sat;
446 if (!vsat[i] || sat < 1 || sat >
MAXSAT || resp[i] * resp[i] <= thres) {
450 trace(NULL, 2,
"pntpos : excluded obs due to large residuals :sat=%2d res=%.2f rms=%.2f\n", sat, resp[i],
458 double a = fabs(rt), t;
463 t = (k1 - a) / (k1 - k0);
464 return (k0 / a) * t * t;
469static int cmp_dbl(
const void* a,
const void* b) {
470 double d = *(
const double*)a - *(
const double*)b;
471 return (d < 0.0) ? -1 : (d > 0.0 ? 1 : 0);
474static double median_abs(
const double* x,
int n,
double* work) {
479 for (i = 0; i < n; i++) {
480 work[i] = fabs(x[i]);
482 qsort(work, n,
sizeof(
double),
cmp_dbl);
483 return (n % 2) ? work[n / 2] : 0.5 * (work[n / 2 - 1] + work[n / 2]);
486static int estpos(
const obsd_t* obs,
int n,
const double* rs,
const double* dts,
const double* vare,
const int* svh,
487 const nav_t* nav,
const prcopt_t* opt,
sol_t* sol,
double* azel,
int* vsat,
double* resp,
char* msg) {
488 double x[
NX] = {0}, dx[
NX], Q[
NX *
NX], *v, *H, *var, *vpre, sig;
489 int i, j, k, info, stat = 1, nv = 0, ns;
492 trace(NULL, 3,
"estpos : n=%d\n", n);
496 var =
mat(n +
NT, 1);
497 vpre =
mat(n +
NT, 1);
499 for (i = 0; i < 3; i++) {
503 for (i = 0; i <
MAXITR; i++) {
505 exclsat(obs, resp, opt, n, vsat, outp);
508 nv =
rescode(i, obs, n, rs, dts, vare, svh, nav, x, opt, v, H, var, azel, vsat, resp, &ns, outp);
511 sprintf(msg,
"lack of valid sats ns=%d", nv);
515 for (j = 0; j < nv; j++) {
518 for (k = 0; k <
NX; k++) {
519 H[k + j *
NX] /= sig;
528 int gated = (opt->
robust == 1 && i >= 1 && ns >= 5);
539 for (j = 0; j < nv; j++) {
546 for (j = 0; j < ns; j++) {
549 for (k = 0; k <
NX; k++) {
555 if ((info =
lsq(H, v,
NX, nv, dx, Q))) {
556 sprintf(msg,
"lsq error info=%d", info);
559 for (j = 0; j <
NX; j++) {
562 if (
norm(dx,
NX) < 1E-4) {
572 for (j = 0; j < 6; j++) {
573 sol->
rr[j] = j < 3 ? x[j] : 0.0;
575 for (j = 0; j < 3; j++) {
576 sol->
qr[j] = (float)Q[j + j *
NX];
578 sol->
qr[3] = (float)Q[1];
579 sol->
qr[4] = (float)Q[2 +
NX];
580 sol->
qr[5] = (float)Q[2];
581 sol->
ns = (uint8_t)ns;
587 if (!opt->
posopt[4] || (stat =
valsol(azel, vsat, n, opt, gated ? vpre : v, nv,
NX, msg))) {
598 sprintf(msg,
"iteration divergent i=%d", i);
608static int raim_fde(
const obsd_t* obs,
int n,
const double* rs,
const double* dts,
const double* vare,
const int* svh,
609 const nav_t* nav,
const prcopt_t* opt,
sol_t* sol,
double* azel,
int* vsat,
double* resp,
613 char tstr[32], name[16], msg_e[128];
614 double *rs_e, *dts_e, *vare_e, *azel_e, *resp_e, rms_e, rms = 100.0;
615 int i, j, k, nvsat, stat = 0, *svh_e, *vsat_e, sat = 0;
617 trace(NULL, 3,
"raim_fde: %s n=%2d\n",
time_str(obs[0].time, 0), n);
625 azel_e =
zeros(2, n);
630 for (i = 0; i < n; i++) {
632 for (j = k = 0; j < n; j++) {
637 matcpy(rs_e + 6 * k, rs + 6 * j, 6, 1);
638 matcpy(dts_e + 2 * k, dts + 2 * j, 2, 1);
643 if (!
estpos(obs_e, n - 1, rs_e, dts_e, vare_e, svh_e, nav, opt, &sol_e, azel_e, vsat_e, resp_e, msg_e)) {
644 trace(NULL, 3,
"raim_fde: exsat=%2d (%s)\n", obs[i].sat, msg);
647 for (j = nvsat = 0, rms_e = 0.0; j < n - 1; j++) {
651 rms_e +=
SQR(resp_e[j]);
655 trace(NULL, 3,
"raim_fde: exsat=%2d lack of satellites nvsat=%2d\n", obs[i].sat, nvsat);
658 rms_e = sqrt(rms_e / nvsat);
660 trace(NULL, 3,
"raim_fde: exsat=%2d rms=%8.3f\n", obs[i].sat, rms_e);
667 for (j = k = 0; j < n; j++) {
671 matcpy(azel + 2 * j, azel_e + 2 * k, 2, 1);
673 resp[j] = resp_e[k++];
685 trace(NULL, 2,
"%s: %s excluded by raim\n", tstr + 11, name);
707 double dph, dpt, tt, mean = 0.0, dif[
MAXOBS] = {0};
708 int i, sat, ndop = 0, valid[
MAXOBS] = {0};
710 for (i = 0; i < n && i <
MAXOBS; i++) {
711 slip[i] = (obs[i].
LLI[0] & 1) ? 1 : 0;
713 if (thresdop <= 0.0 || obs[i].L[0] == 0.0 || obs[i].D[0] == 0.0 || ssat[sat - 1].sph[0] == 0.0) {
716 tt =
timediff(obs[i].time, ssat[sat - 1].spt[0]);
717 if (fabs(tt) <
DTTOL || fabs(tt) > 3.0) {
720 dph = (obs[i].
L[0] - ssat[sat - 1].
sph[0]) / tt;
724 if (fabs(dif[i]) < 3.0 * thresdop) {
733 for (i = 0; i < n && i <
MAXOBS; i++) {
734 if (valid[i] && fabs(dif[i] - mean) > thresdop) {
743static int resdop(
const obsd_t* obs,
int n,
const double* rs,
const double* dts,
const nav_t* nav,
const double* rr,
744 const double* x,
const double* azel,
const int* vsat,
double err,
const ssat_t* ssat,
const int* slip,
745 int tdcp,
double* v,
double* H) {
746 double freq, rate, pos[3], E[9], a[3], e[3], vs[3], cosel, sig, lam, meas, tt;
747 int i, j, nv = 0, sat, use;
749 trace(NULL, 3,
"resdop : n=%d\n", n);
754 for (i = 0; i < n && i <
MAXOBS; i++) {
755 freq =
sat2freq(obs[i].sat, obs[i].code[0], nav);
756 if (freq == 0.0 || !vsat[i] ||
norm(rs + 3 + i * 6, 3) <= 0.0) {
765 if (tdcp && ssat && slip && !slip[i] && obs[i].L[0] != 0.0 && ssat[sat - 1].sph[0] != 0.0) {
766 tt =
timediff(obs[i].time, ssat[sat - 1].spt[0]);
767 if (fabs(tt) >=
DTTOL && fabs(tt) <= 3.0) {
768 meas = (obs[i].
L[0] - ssat[sat - 1].
sph[0]) / tt;
773 if (!use && obs[i].D[0] != 0.0) {
775 sig = (err <= 0.0) ? 1.0 : err * lam;
782 cosel = cos(azel[1 + i * 2]);
783 a[0] = sin(azel[i * 2]) * cosel;
784 a[1] = cos(azel[i * 2]) * cosel;
785 a[2] = sin(azel[1 + i * 2]);
786 matmul(
"TN", 3, 1, 3, 1.0, E, a, 0.0, e);
789 for (j = 0; j < 3; j++) {
790 vs[j] = rs[j + 3 + i * 6] - x[j];
795 OMGE /
CLIGHT * (rs[4 + i * 6] * rr[0] + rs[1 + i * 6] * x[0] - rs[3 + i * 6] * rr[1] - rs[i * 6] * x[1]);
798 v[nv] = (meas * lam - (rate + x[3] -
CLIGHT * dts[1 + i * 2])) / sig;
801 for (j = 0; j < 4; j++) {
802 H[j + nv * 4] = ((j < 3) ? -e[j] : 1.0) / sig;
811 sol_t* sol,
const double* azel,
const int* vsat,
const ssat_t* ssat,
const int* slip) {
812 double x[4] = {0}, dx[4], Q[16], *v, *H;
813 double err = opt->
err[4];
814 int i, j, nv, stat = 0, tdcp = (opt->
tdcp == 1 && ssat != NULL);
816 trace(NULL, 3,
"estvel : n=%d\n", n);
821 for (i = 0; i <
MAXITR; i++) {
823 if ((nv =
resdop(obs, n, rs, dts, nav, sol->
rr, x, azel, vsat, err, ssat, slip, tdcp, v, H)) < 4) {
827 if (
lsq(H, v, 4, nv, dx, Q)) {
831 for (j = 0; j < 4; j++) {
835 if (
norm(dx, 4) < 1E-6) {
837 sol->
qv[0] = (float)Q[0];
838 sol->
qv[1] = (float)Q[5];
839 sol->
qv[2] = (float)Q[10];
840 sol->
qv[3] = (float)Q[1];
841 sol->
qv[4] = (float)Q[6];
842 sol->
qv[5] = (float)Q[2];
866 ssat_t* ssat,
char* msg) {
868 double *rs, *dts, *var, *azel_, *resp;
874 trace(ctx, 3,
"pntpos : tobs=%s n=%d\n",
time_str(obs[0].time, 3), n);
879 strcpy(msg,
"no observation data");
884 prev_time = sol->
time;
886 has_prev = (prev_time.
time != 0 &&
norm(prev_rr, 3) > 0.0);
909 stat =
estpos(obs, n, rs, dts, var, svh, nav, &opt_, sol, azel_, vsat, resp, msg);
912 if (!stat && n >= 6 && opt->
posopt[4]) {
913 stat =
raim_fde(obs, n, rs, dts, var, svh, nav, &opt_, sol, azel_, vsat, resp, msg);
916 if (opt_.
tdcp == 1 && ssat) {
921 int velok =
estvel(obs, n, rs, dts, nav, &opt_, sol, azel_, vsat, ssat, slip);
928 if (opt_.
tdcp == 1 && ssat && has_prev && velok) {
929 double tt =
timediff(obs[0].time, prev_time);
930 if (fabs(tt) >
DTTOL && fabs(tt) <= 3.0) {
932 for (i = 0; i < 3; i++) {
933 d[i] = (sol->
rr[i] - prev_rr[i]) - sol->
rr[i + 3] * tt;
937 sprintf(msg,
"tdcp jump reject %.1fm", dn);
938 trace(ctx, 2,
"pntpos : %s\n", msg);
946 for (i = 0; i < n * 2; i++) {
951 for (i = 0; i <
MAXSAT; i++) {
953 ssat[i].
azel[0] = ssat[i].
azel[1] = 0.0;
954 ssat[i].
resp[0] = ssat[i].
resc[0] = 0.0;
957 for (i = 0; i < n; i++) {
959 ssat[obs[i].
sat - 1].
azel[0] = azel_[i * 2];
960 ssat[obs[i].
sat - 1].
azel[1] = azel_[1 + i * 2];
961 ssat[obs[i].
sat - 1].
snr[0] = obs[i].
SNR[0];
968 for (f = 0; f < NFREQ; f++) {
969 ssat[obs[i].
sat - 1].
sph[f] = obs[i].
L[f];
975 ssat[obs[i].
sat - 1].
vs = 1;
976 ssat[obs[i].
sat - 1].
resp[0] = resp[i];
int ionocorr(gtime_t time, const nav_t *nav, int sat, const double *pos, const double *azel, int ionoopt, double *ion, double *var)
Compute ionospheric correction.
int tropcorr(gtime_t time, const nav_t *nav, const double *pos, const double *azel, int tropopt, double *trp, double *var)
Compute tropospheric correction.
MRTKLIB Atmosphere Module — Ionospheric and tropospheric models.
void satno2id(int sat, char *id)
double sat2freq(int sat, uint8_t code, const nav_t *nav)
double geodist(const double *rs, const double *rr, double *e)
Compute geometric distance and receiver-to-satellite unit vector.
double satazel(const double *pos, const double *e, double *azel)
Compute satellite azimuth/elevation angle.
void xyz2enu(const double *pos, double *E)
Compute ECEF to local coordinate transformation matrix.
void dops(int ns, const double *azel, double elmin, double *dop)
Compute DOP (dilution of precision).
void ecef2pos(const double *r, double *pos)
Transform ECEF position to geodetic position.
MRTKLIB Coordinates Module — Coordinate transformations and geometry.
int satsys(int sat, int *prn)
int getseleph(int sys)
Get selected satellite ephemeris.
void satposs(gtime_t teph, const obsd_t *obs, int n, const nav_t *nav, int ephopt, double *rs, double *dts, double *var, int *svh)
Compute satellite positions, velocities and clocks.
MRTKLIB Broadcast Ephemeris Module — Satellite orbit/clock types and Kepler/GLONASS/SBAS orbit comput...
double * mat(int n, int m)
Allocate memory for a double matrix.
double * zeros(int n, int m)
Allocate a new zero matrix.
int lsq(const double *A, const double *y, int n, int m, double *x, double *Q)
Least square estimation by solving normal equation.
void matcpy(double *A, const double *B, int n, int m)
Copy matrix.
int * imat(int n, int m)
Allocate memory for an integer matrix.
double norm(const double *a, int n)
Euclidean norm of vector.
void matmul(const char *tr, int n, int k, int m, double alpha, const double *A, const double *B, double beta, double *C)
Multiply matrix by matrix (C = alpha*A*B + beta*C).
double dot(const double *a, const double *b, int n)
Inner product of vectors.
MRTKLIB Matrix Module — Matrix/vector operations and estimation.
int satsys_bd2(int sat, int *prn)
Distinguish BDS-2 from BDS-3.
int satexclude(int sat, double var, int svh, const struct prcopt_t *opt)
Test excluded satellite.
int testsnr(int base, int idx, double el, double snr, const snrmask_t *mask)
Test SNR mask.
static const double chisqr[100]
static double varerr(const prcopt_t *opt, double el, double snr, int sys)
static void spp_detslp(const obsd_t *obs, int n, const ssat_t *ssat, double thresdop, int *slip)
static int snrmask(const obsd_t *obs, const double *azel, const prcopt_t *opt)
static double igg3_weight(double rt, double k0, double k1)
static double median_abs(const double *x, int n, double *work)
static double gettgd(int sat, const nav_t *nav, int type)
static int cmp_dbl(const void *a, const void *b)
static int valsol(const double *azel, const int *vsat, int n, const prcopt_t *opt, const double *v, int nv, int nx, char *msg)
static double prange(const obsd_t *obs, const nav_t *nav, const prcopt_t *opt, double *var)
static int raim_fde(const obsd_t *obs, int n, const double *rs, const double *dts, const double *vare, const int *svh, const nav_t *nav, const prcopt_t *opt, sol_t *sol, double *azel, int *vsat, double *resp, char *msg)
static int resdop(const obsd_t *obs, int n, const double *rs, const double *dts, const nav_t *nav, const double *rr, const double *x, const double *azel, const int *vsat, double err, const ssat_t *ssat, const int *slip, int tdcp, double *v, double *H)
static int estvel(const obsd_t *obs, int n, const double *rs, const double *dts, const nav_t *nav, const prcopt_t *opt, sol_t *sol, const double *azel, const int *vsat, const ssat_t *ssat, const int *slip)
static int iflc_freq2_idx(const obsd_t *obs, const nav_t *nav, const prcopt_t *opt)
static void exclsat(const obsd_t *obs, const double *resp, const prcopt_t *opt, int n, const int *vsat, int *outp)
int pntpos(mrtk_ctx_t *ctx, const obsd_t *obs, int n, const nav_t *nav, const prcopt_t *opt, sol_t *sol, double *azel, ssat_t *ssat, char *msg)
Compute receiver position, velocity, clock bias by single-point positioning with pseudorange and dopp...
static int rescode(int iter, const obsd_t *obs, int n, const double *rs, const double *dts, const double *vare, const int *svh, const nav_t *nav, const double *x, const prcopt_t *opt, double *v, double *H, double *var, double *azel, int *vsat, double *resp, int *ns, const int *outp)
static int estpos(const obsd_t *obs, int n, const double *rs, const double *dts, const double *vare, const int *svh, const nav_t *nav, const prcopt_t *opt, sol_t *sol, double *azel, int *vsat, double *resp, char *msg)
MRTKLIB Single-Point Positioning Module — SPP functions.
void time2str(gtime_t t, char *s, int n)
Convert gtime_t struct to string.
double timediff(gtime_t t1, gtime_t t2)
Compute time difference (t1 - t2).
gtime_t timeadd(gtime_t t, double sec)
Add seconds to gtime_t.
char * time_str(gtime_t t, int n)
Get time string (not reentrant).
void trace(mrtk_ctx_t *ctx, int level, const char *format,...)
Output trace message.
MRTKLIB Trace Module — debug trace and logging functions.
GNSS time representation.
Runtime context for MRTKLIB processing.