MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_madoca_local_comb.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_madoca_local_comb.c : MADOCA local correction data combination
3 *
4 * Copyright (C) 2026 H.SHIONO (MRTKLIB Project)
5 * Copyright (C) 2023-2025 Cabinet Office, Japan
6 * Copyright (C) 2024-2025 Lighthouse Technology & Consulting Co. Ltd.
7 * Copyright (C) 2023-2025 Japan Aerospace Exploration Agency
8 * Copyright (C) 2023-2025 TOSHIBA ELECTRONIC TECHNOLOGIES CORPORATION
9 * Copyright (C) 2015- Mitsubishi Electric Corp.
10 * Copyright (C) 2014 Geospatial Information Authority of Japan
11 * Copyright (C) 2014 T.SUZUKI
12 * Copyright (C) 2007-2023 T.TAKASU
13 *
14 * SPDX-License-Identifier: BSD-2-Clause
15 *----------------------------------------------------------------------------*/
17
18#include <math.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include "mrtklib/mrtk_atmos.h"
24#include "mrtklib/mrtk_coords.h"
25#include "mrtklib/mrtk_mat.h"
26#include "mrtklib/mrtk_trace.h"
27
28/* local constants -----------------------------------------------------------*/
29#define D2R (3.1415926535897932 / 180.0)
30#define R2D (180.0 / 3.1415926535897932)
31
32/* local macros --------------------------------------------------------------*/
33#define GN(gp) (gp == 1 ? 64 : 16)
34
35/* forward declarations (implemented in rtkcmn.c/stream.c, resolved at link) -*/
36extern int strwrite(struct stream_tag* stream, uint8_t* buff, int n);
37
38/* substruct vector ----------------------------------------------------------*/
39static void vsub(const double a[3], const double b[3], double c[3]) {
40 int i;
41
42 for (i = 0; i < 3; i++) {
43 c[i] = a[i] - b[i];
44 }
45}
46/* equation of the plane -----------------------------------------------------*/
47static int plane(const double p1[3], const double p2[3], const double p3[3], double peq[4]) {
48 double a2b[3], a2c[3];
49
50 vsub(p2, p1, a2b);
51 vsub(p3, p1, a2c);
52 cross3(a2b, a2c, peq);
53 if (!normv3(peq, peq)) {
54 return 0;
55 }
56 peq[3] = -1 * (peq[0] * p1[0] + peq[1] * p1[1] + peq[2] * p1[2]);
57 return 1;
58}
59/* interpolation target ------------------------------------------------------*/
60static int intpt(const double p1[3], const double p2[3], const double p3[3], double t[3]) {
61 double peq[4];
62 if (!plane(p1, p2, p3, peq)) {
63 return 0;
64 }
65 t[2] = -1 * (t[0] * peq[0] + t[1] * peq[1] + peq[3]) / peq[2];
66 return 1;
67}
68/* get noramal vector z ------------------------------------------------------*/
69static double normvz(const double a[3], const double b[3], const double tgt[3]) {
70 double v1[3], v2[3];
71
72 vsub(a, b, v1);
73 vsub(tgt, a, v2);
74 return v1[0] * v2[1] - v1[1] * v2[0];
75}
76/* select peripheral stations based on distance ------------------------------*/
77static int selpersta(const stat_t* stat, const double* llh, int flag, double maxdist, int* id) {
78 int i, j, k, n = 0;
79 double d;
80 double sdist[MAXSITES];
81 double ecef[3], tllh[2][3];
82 const spos_t* spos;
83
84 for (i = 0; i < MAXSITES; i++) {
85 sdist[i] = maxdist * 1E3;
86 }
87 pos2ecef(llh, ecef);
88 for (i = 0; i < (flag == TYPE_TRP ? stat->nst : stat->nsi); i++) {
89 if (flag == TYPE_TRP) {
90 spos = &stat->strp[i].site;
91 } else {
92 spos = &stat->sion[i].site;
93 }
94 if (spos->ecef[0] == 0.0) {
95 continue;
96 }
97
98 d = posdist(spos->ecef, ecef);
99 ecef2pos(spos->ecef, tllh[0]);
100 ecef2pos(ecef, tllh[1]);
101 trace(NULL, 4, "get_site:targetpos llh=%f,%f,%f site pos llh=%f,%f,%f dist=%f\n", tllh[0][0] * R2D,
102 tllh[0][1] * R2D, tllh[0][2], tllh[1][0] * R2D, tllh[1][1] * R2D, tllh[1][2], d);
103 if (d > maxdist * 1E3) {
104 continue;
105 }
106
107 for (j = 0; j < MAXSITES; j++) {
108 if (sdist[j] < d) {
109 continue;
110 }
111 for (k = n; k > j && k > 0; k--) {
112 sdist[k] = sdist[k - 1];
113 id[k] = id[k - 1];
114 }
115 sdist[j] = d;
116 id[j] = i;
117 n++;
118 break;
119 }
120 }
121 return n;
122}
123/* collision detection -------------------------------------------------------*/
124static int coldet(const double p1[3], const double p2[3], const double p3[3], const double tgt[3]) {
125 double z[3] = {0.0};
126
127 z[0] = normvz(p2, p1, tgt);
128 z[1] = normvz(p3, p2, tgt);
129 z[2] = normvz(p1, p3, tgt);
130
131 if ((z[0] > 0 && z[1] > 0 && z[2] > 0) || (z[0] < 0 && z[1] < 0 && z[2] < 0)) {
132 return 1;
133 }
134 return 0;
135}
136/* get stations triangle (Distance designation) ------------------------------*/
137static int gettriangledd(const stat_t* stat, const double* llh, int flag, const double maxdist, const int extp,
138 int* staid) {
139 int i, j, k, stanum = 0, ret = 0;
140 int id[MAXSITES] = {0};
141 double sllh[3][3] = {{0.0}};
142 spos_t site[3];
143
144 stanum = selpersta(stat, llh, flag, maxdist, id);
145 if (stanum < 3) {
146 return 0;
147 }
148
149 /* detect target including triangle */
150 for (i = 0; i < stanum && i < MAXSITES; i++) {
151 if (flag == TYPE_TRP) {
152 memcpy(&site[0], &stat->strp[id[i]].site, sizeof(spos_t));
153 } else {
154 memcpy(&site[0], &stat->sion[id[i]].site, sizeof(spos_t));
155 }
156 ecef2pos(site[0].ecef, sllh[0]);
157 staid[0] = id[i];
158 for (j = i + 1; j < stanum && j < MAXSITES; j++) {
159 if (flag == TYPE_TRP) {
160 memcpy(&site[1], &stat->strp[id[j]].site, sizeof(spos_t));
161 } else {
162 memcpy(&site[1], &stat->sion[id[j]].site, sizeof(spos_t));
163 }
164 ecef2pos(site[1].ecef, sllh[1]);
165 staid[1] = id[j];
166 for (k = j + 1; k < stanum && k < MAXSITES; k++) {
167 if (flag == TYPE_TRP) {
168 memcpy(&site[2], &stat->strp[id[k]].site, sizeof(spos_t));
169 } else {
170 memcpy(&site[2], &stat->sion[id[k]].site, sizeof(spos_t));
171 }
172 ecef2pos(site[2].ecef, sllh[2]);
173 staid[2] = id[k];
174 ret = coldet(sllh[0], sllh[1], sllh[2], llh);
175 if (ret) {
176 trace(NULL, 3, "interpolation: %.1f %.1f site=%s %s %s\n", llh[0] * R2D, llh[1] * R2D, site[0].name,
177 site[1].name, site[2].name);
178 return 3;
179 }
180 }
181 }
182 }
183 /* extrapolation by nearest sites */
184 if (extp) {
185 for (i = 0; i < 3; i++) {
186 if (flag == TYPE_TRP) {
187 memcpy(&site[i], &stat->strp[id[i]].site, sizeof(spos_t));
188 } else {
189 memcpy(&site[i], &stat->sion[id[i]].site, sizeof(spos_t));
190 }
191 staid[i] = id[i];
192 }
193 trace(NULL, 3, "extrapolation: %.1f %.1f site=%s %s %s\n", llh[0] * R2D, llh[1] * R2D, site[0].name,
194 site[1].name, site[2].name);
195 return 3;
196 }
197 return 0;
198}
199/* calculate trop correction using planar interpolation with 3 points --------*/
200static int corr_trop_plane(const stat_t* stat, gtime_t time, const double* llh, double maxdist, int extp, double* trp,
201 double* std) {
202 int i, j, staid[3];
203 double zazel[] = {0.0, 90.0 * D2R}, zhd, trp_s[3][3] = {{0.0}}, std_s[3][3] = {{0.0}};
204 double tri[9] = {0.0}, trit[3];
205
206 if (gettriangledd(stat, llh, TYPE_TRP, maxdist, extp, staid) < 3) {
207 return 0;
208 }
209
210 /* convert station position & time interpolation */
211 for (i = 0; i < 3; i++) {
212 if (get_trop_sta(time, &stat->strp[staid[i]].trpd, trp_s[i], std_s[i]) == 0) {
213 return 0;
214 }
215 if (trp_s[i][0] == 0.0) {
216 return 0;
217 }
218 ecef2pos(stat->strp[staid[i]].site.ecef, &tri[i * 3]);
219 zhd = tropmodel(time, &tri[i * 3], zazel, 0.0);
220 trp_s[i][0] -= zhd;
221 }
222
223 /* set target position & zenith hydrostatic delay */
224 memcpy(trit, llh, sizeof(trit));
225 /* space interpolation */
226 /* loop [0]ztd -> [1]grade -> [2]gradn */
227 for (i = 0; i < 3; i++) {
228 for (j = 0; j < 3; j++) {
229 tri[j * 3 + 2] = trp_s[j][i];
230 }
231 intpt(&tri[0], &tri[3], &tri[6], &trit[0]);
232 trp[i] = trit[2];
233 for (j = 0; j < 3; j++) {
234 tri[j * 3 + 2] = std_s[j][i];
235 }
236 intpt(&tri[0], &tri[3], &tri[6], &trit[0]);
237 std[i] = trit[2];
238 }
239 trp[0] += tropmodel(time, llh, zazel, 0.0);
240 return 1;
241}
242/* calculate iono correction using planar interpolation with 3 points --------*/
243static int corr_iono_plane(const stat_t* stat, gtime_t time, const double* llh, double maxdist, int extp, double* ion,
244 double* std, double maxres, int* nrej, int* ncnt) {
245 int i, j, siteno[3];
246 double el_s[3][MAXSAT], ion_s[3][MAXSAT] = {{0.0}}, std_s[3][MAXSAT] = {{0.0}};
247 double tri[9] = {0.0}, trit[3], res;
248
249 if (gettriangledd(stat, llh, TYPE_ION, maxdist, extp, siteno) < 3) {
250 return 0;
251 }
252
253 /* convert station position & time interpolation */
254 for (i = 0; i < 3; i++) {
255 if (get_iono_sta(time, stat->sion[siteno[i]].iond, ion_s[i], std_s[i], el_s[i]) == 0) {
256 return 0;
257 }
258 ecef2pos(stat->sion[siteno[i]].site.ecef, &tri[i * 3]);
259 }
260
261 /* set target position & zenith hydrostatic delay */
262 memcpy(trit, llh, sizeof(trit));
263 /* space interpolation */
264 for (i = 0; i < MAXSAT; i++) {
265 for (j = 0; j < 3; j++) {
266 if (ion_s[j][i] == 0.0) {
267 break;
268 }
269 tri[j * 3 + 2] = ion_s[j][i];
270 }
271 if (j < 3) {
272 continue;
273 }
274 intpt(&tri[0], &tri[3], &tri[6], &trit[0]);
275 ion[i] = trit[2];
276 for (j = 0; j < 3; j++) {
277 if (ion_s[j][i] == 0.0) {
278 break;
279 }
280 tri[j * 3 + 2] = std_s[j][i];
281 }
282 intpt(&tri[0], &tri[3], &tri[6], &trit[0]);
283 std[i] = trit[2];
284 }
285 if (maxres > 0.0) {
286 for (i = 0; i < 3; i++) {
287 for (j = 0; j < MAXSAT; j++) {
288 if (ion_s[i][j] == 0.0) {
289 continue;
290 }
291 res = ion[i] - ion_s[i][j];
292 ncnt[siteno[i]]++;
293 if (fabs(res) > maxres) {
294 nrej[siteno[i]]++;
295 }
296 }
297 }
298 }
299 return 1;
300}
301/* initialize grid/station setting ---------------------------------------------
302 * initialize grid/station settings from a specified file
303 * args : const char *setfile I grid/station setting file path
304 * lclblock_t *lclblk IO local block information struct
305 * int btype I block type (BTYPE_GRID or BTYPE_STA)
306 * return : status (0: error, 1: success)
307 *-----------------------------------------------------------------------------*/
308extern int initgridsta(const char* setfile, lclblock_t* lclblk, int btype) {
309 FILE* sfp = NULL;
310 char *token, buff[256];
311 int* bnum;
312 double gp;
313 blkinf_t* bi;
314 char type[8];
315
316 if ((sfp = fopen(setfile, "r")) == NULL) {
317 trace(NULL, 2, "initgridsta : setting file open error :%s\n", setfile);
318 return 0;
319 }
320 while (fgets(buff, sizeof(buff), sfp) != NULL) {
321 if (buff[0] == '#') {
322 continue;
323 }
324
325 strcpy(type, strtok(buff, ","));
326 if (strncmp(type, "I", 1) == 0) {
327 bi = &lclblk->iblkinf[lclblk->inum];
328 bnum = &lclblk->inum;
329 bi->bs = ION_BLKSIZE;
330 } else if (strncmp(type, "T", 1) == 0) {
331 bi = &lclblk->tblkinf[lclblk->tnum];
332 bnum = &lclblk->tnum;
333 bi->bs = TRP_BLKSIZE;
334 } else {
335 trace(NULL, 2, "initgrid : grid setting file type error :%s\n", type);
336 continue;
337 }
338
339 /* init grid/station data */
340 bi->btype = btype;
341 token = strtok(NULL, ",");
342 if (token == NULL) {
343 trace(NULL, 2, "initgrid : grid setting file format error : bn\n");
344 continue;
345 }
346 bi->bn = atoi(token);
347 if (btype == BTYPE_GRID) {
348 token = strtok(NULL, ",");
349 if (token == NULL) {
350 trace(NULL, 2, "initgrid : grid setting file format error : gp\n");
351 continue;
352 }
353 gp = atoi(token);
354 if (gp == 16) {
355 bi->gpitch = 0;
356 } else if (gp == 64) {
357 bi->gpitch = 1;
358 } else {
359 trace(NULL, 2, "initgrid : grid setting file grid pitch error :%d\n", gp);
360 continue;
361 }
362 token = strtok(NULL, ",");
363 if (token == NULL) {
364 trace(NULL, 2, "initgrid : grid setting file format error : mask[0]\n");
365 continue;
366 }
367 bi->mask[0] = strtol(token, NULL, 0);
368 token = strtok(NULL, ",");
369 if (token == NULL) {
370 trace(NULL, 2, "initgrid : grid setting file format error : mask[1]\n");
371 continue;
372 }
373 bi->mask[1] = strtol(token, NULL, 0);
374 }
375
376 initblkinf(bi);
377 *bnum += 1;
378 trace(NULL, 3, "initgrid : read grid setting file [%s]\n", buff);
379 }
380 fclose(sfp);
381
382 return 1;
383}
384/* trop grid interpolation -----------------------------------------------------
385 * interpolate tropospheric grid data based on the given time and stat data
386 * args : gtime_t gt I time
387 * const stat_t *stat I stat data
388 * lclblock_t *lclblk IO local block information
389 *-----------------------------------------------------------------------------*/
390extern void grid_intp_trop(const gtime_t gt, const stat_t* stat, lclblock_t* lclblk) {
391 int i, j, n = 0;
392 blkinf_t* bi;
393 trp_t* trpp;
394
395 for (i = 0; i < lclblk->tnum; i++) {
396 bi = &lclblk->tblkinf[i];
397 bi->mask[0] = 0;
398 bi->mask[1] = 0;
399 memset(bi->gp, 0x00, sizeof(bi->gp));
400 bi->n = 0;
401 for (j = 0, n = 0; j < GN(bi->gpitch); j++) {
402 trpp = &lclblk->tstat[i][j].trpd;
403 if (lclblk->interp == MODE_PLANE) {
404 if (!corr_trop_plane(stat, gt, bi->grid[j], lclblk->tdist, lclblk->extp, trpp->trp, trpp->std)) {
405 continue;
406 }
407 } else {
408 if (!corr_trop_distwgt(stat, gt, bi->grid[j], lclblk->tdist, trpp->trp, trpp->std)) {
409 continue;
410 }
411 }
412 trpp->time = gt;
413 bi->gp[n] = j;
414 n++;
415 }
416 bi->n = n;
417 for (j = 0; j < n; j++) {
418 if (bi->gp[j] < 32) {
419 bi->mask[0] |= 1 << bi->gp[j];
420 } else {
421 bi->mask[1] |= 1 << (bi->gp[j] - 32);
422 }
423 }
424 }
425}
426/* select block tropospher -----------------------------------------------------
427 * select and assign tropospheric data blocks based on station positions
428 * args : gtime_t time I time
429 * const stat_t *stat I station data
430 * lclblock_t *lslblk IO local block information struct
431 *-----------------------------------------------------------------------------*/
432extern void sta_sel_trop(const gtime_t time, const stat_t* stat, lclblock_t* lslblk) {
433 int i, j, k;
434 double llh[3];
435 blkinf_t* bi;
436 sitetrp_t* strp;
437
438 for (i = 0; i < lslblk->tnum; i++) {
439 bi = &lslblk->tblkinf[i];
440 bi->n = 0;
441 for (j = 0; j < stat->nst; j++) {
442 ecef2pos(stat->strp[j].site.ecef, llh);
443 if (llh[0] >= bi->bpos[0]) {
444 continue;
445 }
446 if (llh[0] < bi->bpos[0] - bi->bs * D2R) {
447 continue;
448 }
449 if (llh[1] <= bi->bpos[1]) {
450 continue;
451 }
452 if (llh[1] > bi->bpos[1] + bi->bs * D2R) {
453 continue;
454 }
455
456 strp = &lslblk->tstat[i][bi->n];
457 for (k = 0; k < 3; k++) {
458 bi->grid[bi->n][k] = llh[k];
459 strp->site.ecef[k] = stat->strp[j].site.ecef[k];
460 }
461 memcpy(&strp->trpd, &stat->strp[j].trpd, sizeof(trp_t));
462 bi->n++;
463 }
464 }
465}
466/* ionospheric grid interpolation ----------------------------------------------
467 * interpolate ionospheric grid data based on the given time and stat data
468 * args : gtime_t gt I time
469 * const stat_t *stat I stat data
470 * lclblock_t *lclblk IO local block information struct
471 * double maxres I maximum residual
472 * int *nrej O number of rejections
473 * int *ncnt O number of counts
474 *-----------------------------------------------------------------------------*/
475extern void grid_intp_iono(const gtime_t gt, const stat_t* stat, lclblock_t* lclblk, double maxres, int* nrej,
476 int* ncnt) {
477 int i, j, k, n = 0;
478 double ion[MAXSAT] = {0.0}, std[MAXSAT] = {0.0};
479 blkinf_t* bi;
480 ion_t* ionp;
481
482 for (i = 0; i < lclblk->inum; i++) {
483 bi = &lclblk->iblkinf[i];
484 bi->mask[0] = 0;
485 bi->mask[1] = 0;
486 memset(bi->gp, 0x00, sizeof(bi->gp));
487 bi->n = 0;
488 for (j = 0, n = 0; j < GN(bi->gpitch); j++) {
489 if (lclblk->interp == MODE_PLANE) {
490 if (!corr_iono_plane(stat, gt, bi->grid[j], lclblk->idist, lclblk->extp, ion, std, maxres, nrej,
491 ncnt)) {
492 continue;
493 }
494 } else {
495 if (!corr_iono_distwgt(stat, gt, bi->grid[j], NULL, lclblk->idist, ion, std, maxres, nrej, ncnt)) {
496 continue;
497 }
498 }
499 for (k = 0; k < MAXSAT; k++) {
500 ionp = &lclblk->istat[i][j].iond[k];
501 if (ion[k] != 0.0) {
502 ionp->time = gt;
503 ionp->ion = ion[k];
504 ionp->std = std[k];
505 } else {
506 memset(ionp, 0x00, sizeof(ion_t));
507 }
508 }
509 bi->gp[n] = j;
510 n++;
511 }
512 bi->n = n;
513 for (j = 0; j < n; j++) {
514 if (bi->gp[j] < 32) {
515 bi->mask[0] |= 1 << bi->gp[j];
516 } else {
517 bi->mask[1] |= 1 << (bi->gp[j] - 32);
518 }
519 }
520 }
521}
522/* select block ionosphere -----------------------------------------------------
523 * select and assign ionospheric data blocks based on stat positions
524 * args : gtime_t gt I time
525 * const stat_t *stat I stat data
526 * lclblock_t *lslblk IO local block information struct
527 *-----------------------------------------------------------------------------*/
528extern void sta_sel_iono(const gtime_t gt, const stat_t* stat, lclblock_t* lslblk) {
529 int i, j, k;
530 double llh[3];
531 blkinf_t* bi;
532 siteion_t* sion;
533 double tt;
534
535 for (i = 0; i < lslblk->tnum; i++) {
536 bi = &lslblk->iblkinf[i];
537 bi->n = 0;
538
539 for (j = 0; j < stat->nsi; j++) {
540 ecef2pos(stat->sion[j].site.ecef, llh);
541 if (llh[0] >= bi->bpos[0]) {
542 continue;
543 }
544 if (llh[0] < bi->bpos[0] - bi->bs * D2R) {
545 continue;
546 }
547 if (llh[1] <= bi->bpos[1]) {
548 continue;
549 }
550 if (llh[1] > bi->bpos[1] + bi->bs * D2R) {
551 continue;
552 }
553
554 sion = &lslblk->istat[i][bi->n];
555 for (k = 0; k < 3; k++) {
556 bi->grid[bi->n][k] = llh[k];
557 sion->site.ecef[k] = stat->strp[j].site.ecef[k];
558 }
559 for (k = 0; k < MAXSAT; k++) {
560 tt = timediff(stat->sion[j].iond[k].time, sion->iond[k].time);
561 if (tt > 0.0) {
562 memcpy(&sion->iond[k], &stat->sion[j].iond[k], sizeof(sion->iond[k]));
563 } else {
564 sion->iond[k].ion = 0.0;
565 sion->iond[k].std = 0.0;
566 }
567 }
568
569 bi->n++;
570 }
571 }
572}
573/* generate rtcm3 local combination correction ---------------------------------
574 * generate and output RTCM3 local combination correction messages
575 * args : rtcm_t *rtcm IO rtcm control struct
576 * int btype I block type (BTYPE_GRID or BTYPE_STA)
577 * stream_t *ostr I output stream
578 *-----------------------------------------------------------------------------*/
579extern void output_lclcmb(rtcm_t* rtcm, int btype, struct stream_tag* ostr) {
580 int i, j, basemt;
581
582 if (!rtcm->lclblk) {
583 return;
584 }
585 if (btype == BTYPE_GRID) {
586 basemt = 2001;
587 } else if (btype == BTYPE_STA) {
588 basemt = 2011;
589 } else {
590 return;
591 }
592
593 for (i = 0; i < rtcm->lclblk->tnum; i++) {
594 rtcm->lclblk->outtn = i;
595 gen_rtcm3(rtcm, basemt, 0, 0);
596 strwrite(ostr, rtcm->buff, rtcm->nbyte);
597 }
598
599 for (i = 0; i < rtcm->lclblk->inum; i++) {
600 rtcm->lclblk->outin = i;
601 for (j = basemt + 1; j <= basemt + 5; j++) {
602 gen_rtcm3(rtcm, j, 0, 0);
603 strwrite(ostr, rtcm->buff, rtcm->nbyte);
604 }
605 }
606}
double tropmodel(gtime_t time, const double *pos, const double *azel, double humi)
Compute tropospheric delay by standard atmosphere and Saastamoinen.
Definition mrtk_atmos.c:162
MRTKLIB Atmosphere Module — Ionospheric and tropospheric models.
#define D2R
Definition mrtk_coords.c:36
void pos2ecef(const double *pos, double *r)
Transform geodetic position to ECEF position.
#define MAXSAT
Definition mrtk_coords.c:45
void ecef2pos(const double *r, double *pos)
Transform ECEF position to geodetic position.
MRTKLIB Coordinates Module — Coordinate transformations and geometry.
#define MAXSITES
static int plane(const double p1[3], const double p2[3], const double p3[3], double peq[4])
#define GN(gp)
int strwrite(struct stream_tag *stream, uint8_t *buff, int n)
void grid_intp_trop(const gtime_t gt, const stat_t *stat, lclblock_t *lclblk)
Interpolate tropospheric grid data.
static void vsub(const double a[3], const double b[3], double c[3])
int initgridsta(const char *setfile, lclblock_t *lclblk, int btype)
Initialize grid/station settings from a specified file.
static int gettriangledd(const stat_t *stat, const double *llh, int flag, const double maxdist, const int extp, int *staid)
static int corr_iono_plane(const stat_t *stat, gtime_t time, const double *llh, double maxdist, int extp, double *ion, double *std, double maxres, int *nrej, int *ncnt)
static double normvz(const double a[3], const double b[3], const double tgt[3])
static int coldet(const double p1[3], const double p2[3], const double p3[3], const double tgt[3])
void sta_sel_trop(const gtime_t time, const stat_t *stat, lclblock_t *lslblk)
Select and assign tropospheric data blocks based on station positions.
static int selpersta(const stat_t *stat, const double *llh, int flag, double maxdist, int *id)
void grid_intp_iono(const gtime_t gt, const stat_t *stat, lclblock_t *lclblk, double maxres, int *nrej, int *ncnt)
Interpolate ionospheric grid data.
void output_lclcmb(rtcm_t *rtcm, int btype, struct stream_tag *ostr)
Generate and output RTCM3 local combination correction messages.
void sta_sel_iono(const gtime_t gt, const stat_t *stat, lclblock_t *lslblk)
Select and assign ionospheric data blocks based on station positions.
static int corr_trop_plane(const stat_t *stat, gtime_t time, const double *llh, double maxdist, int extp, double *trp, double *std)
static int intpt(const double p1[3], const double p2[3], const double p3[3], double t[3])
MRTKLIB MADOCA Local Combination Module — local correction data combination functions.
double posdist(const double *ecef1, const double *ecef2)
Calculate the Euclidean distance between two ECEF positions.
int corr_trop_distwgt(const stat_t *stat, gtime_t time, const double *llh, double maxdist, double *trp, double *std)
Calculate tropospheric correction using weighted interpolation by distance.
int get_trop_sta(gtime_t time, const trp_t *trpd, double *trp, double *std)
Get tropospheric correction for a point.
int get_iono_sta(gtime_t time, const ion_t *iond, double *ion, double *std, double *el)
Get ionospheric correction for a point.
int corr_iono_distwgt(const stat_t *stat, gtime_t time, const double *llh, const double *el, double maxdist, double *ion, double *std, double maxres, int *nrej, int *ncnt)
Calculate ionospheric correction using weighted interpolation by distance.
#define MODE_PLANE
#define TYPE_TRP
#define TYPE_ION
void cross3(const double *a, const double *b, double *c)
Cross product of 3D vectors.
Definition mrtk_mat.c:172
int normv3(const double *a, double *b)
Normalize 3D vector.
Definition mrtk_mat.c:183
MRTKLIB Matrix Module — Matrix/vector operations and estimation.
#define R2D
Definition mrtk_obs.c:51
static rtcm_t * rtcm
#define ION_BLKSIZE
#define BTYPE_STA
#define TRP_BLKSIZE
void initblkinf(blkinf_t *b)
Initialize block information struct.
#define BTYPE_GRID
int gen_rtcm3(rtcm_t *rtcm, int type, int subtype, int sync)
Generate RTCM 3 message.
Definition mrtk_rtcm.c:392
double timediff(gtime_t t1, gtime_t t2)
Compute time difference (t1 - t2).
Definition mrtk_time.c:279
void trace(mrtk_ctx_t *ctx, int level, const char *format,...)
Output trace message.
Definition mrtk_trace.c:78
MRTKLIB Trace Module — debug trace and logging functions.
double bpos[3]
Definition mrtk_nav.h:327
unsigned int mask[2]
Definition mrtk_nav.h:325
double bs
Definition mrtk_nav.h:323
int btype
Definition mrtk_nav.h:321
int gpitch
Definition mrtk_nav.h:324
double grid[MAXTRPSTA][3]
Definition mrtk_nav.h:328
int gp[MAXTRPSTA]
Definition mrtk_nav.h:329
GNSS time representation.
Definition mrtk_time.h:49
gtime_t time
Definition mrtk_nav.h:262
double ion
Definition mrtk_nav.h:264
double std
Definition mrtk_nav.h:265
sitetrp_t tstat[MAXBLK][MAXTRPSTA]
Definition mrtk_nav.h:339
blkinf_t iblkinf[MAXBLK]
Definition mrtk_nav.h:338
siteion_t istat[MAXBLK][MAXTRPSTA]
Definition mrtk_nav.h:340
double idist
Definition mrtk_nav.h:333
blkinf_t tblkinf[MAXBLK]
Definition mrtk_nav.h:337
double tdist
Definition mrtk_nav.h:333
RTCM control struct type.
Definition mrtk_rtcm.h:50
ion_t iond[MAXSAT]
Definition mrtk_nav.h:280
spos_t site
Definition mrtk_nav.h:279
trp_t trpd
Definition mrtk_nav.h:285
spos_t site
Definition mrtk_nav.h:284
double ecef[3]
Definition mrtk_nav.h:258
siteion_t sion[MAXSITES]
Definition mrtk_nav.h:291
int nst
Definition mrtk_nav.h:290
sitetrp_t strp[MAXSITES]
Definition mrtk_nav.h:292
int nsi
Definition mrtk_nav.h:290
double std[3]
Definition mrtk_nav.h:274
double trp[3]
Definition mrtk_nav.h:273
gtime_t time
Definition mrtk_nav.h:272