MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_postpos.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_postpos.c : post-processing positioning functions
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 *----------------------------------------------------------------------------*/
16/* mrtklib modular headers */
18
19#include <ctype.h>
20#include <math.h>
21#include <stdarg.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
27#include "mrtklib/mrtk_bits.h"
28#include "mrtklib/mrtk_clas.h"
29#include "mrtklib/mrtk_coords.h"
30#include "mrtklib/mrtk_geoid.h"
31#include "mrtklib/mrtk_has.h"
32#include "mrtklib/mrtk_ionex.h"
33#include "mrtklib/mrtk_madoca.h"
35#include "mrtklib/mrtk_mat.h"
36#include "mrtklib/mrtk_nav.h"
37#include "mrtklib/mrtk_obs.h"
38#include "mrtklib/mrtk_peph.h"
39#include "mrtklib/mrtk_ppp.h"
40#include "mrtklib/mrtk_rcvraw.h"
41#include "mrtklib/mrtk_rinex.h"
42#include "mrtklib/mrtk_rtcm.h"
43#include "mrtklib/mrtk_rtkpos.h"
44#include "mrtklib/mrtk_sbas.h"
45#include "mrtklib/mrtk_sol.h"
46#include "mrtklib/mrtk_spp.h"
48#include "mrtklib/mrtk_sys.h"
49#include "mrtklib/mrtk_tides.h"
50#include "mrtklib/mrtk_trace.h"
51
52/* local constants (duplicated from rtklib.h to avoid rtklib.h dependency) ----*/
53#define R2D (180.0 / 3.1415926535897932384626433832795)
54#define D2R (3.1415926535897932384626433832795 / 180.0)
55
56#define COMMENTH "%" /* comment line indicator for solution */
57
58#include "mrtklib/mrtk_version.h"
59
60#ifndef PROGNAME
61#define PROGNAME "rnx2rtkp" /* default program name */
62#endif
63
64#define FILEPATHSEP '/'
65
66/* forward declarations for functions still in legacy rtkcmn.c ----------------*/
67extern int showmsg(const char* format, ...);
68extern void settspan(gtime_t ts, gtime_t te);
69extern void settime(gtime_t time);
70
71#define MIN(x, y) ((x) < (y) ? (x) : (y))
72#define SQRT(x) ((x) <= 0.0 || (x) != (x) ? 0.0 : sqrt(x))
73
74#define MAXPRCDAYS 100 /* max days of continuous processing */
75#define MAXINFILE 1000 /* max number of input files */
76
77/* constants/global variables ------------------------------------------------*/
78
79static pcvs_t pcvss = {0}; /* satellite antenna parameters */
80static pcvs_t pcvsr = {0}; /* receiver antenna parameters */
81static obs_t obss = {0}; /* observation data */
82static nav_t navs = {0}; /* navigation data */
83static sbs_t sbss = {0}; /* sbas messages */
84static sta_t stas[MAXRCV]; /* station information */
85static int nepoch = 0; /* number of observation epochs */
86static int iobsu = 0; /* current rover observation data index */
87static int iobsr = 0; /* current reference observation data index */
88static int isbs = 0; /* current sbas message index */
89static int revs = 0; /* analysis direction (0:forward,1:backward) */
90static int aborts = 0; /* abort status */
91static sol_t* solf; /* forward solutions */
92static sol_t* solb; /* backward solutions */
93static double* rbf; /* forward base positions */
94static double* rbb; /* backward base positions */
95static int isolf = 0; /* current forward solutions index */
96static int isolb = 0; /* current backward solutions index */
97static char proc_rov[64] = ""; /* rover for current processing */
98static char proc_base[64] = ""; /* base station for current processing */
99static char rtcm_file[1024] = ""; /* rtcm data file */
100static char rtcm_path[1024] = ""; /* rtcm data path */
101static rtcm_t* rtcm; /* rtcm control struct (heap) */
102static rtcm_t* l6e; /* l6e control struct (heap) */
103static FILE* fp_rtcm = NULL; /* rtcm data file pointer */
104static char qzssl6e_file[1024] = ""; /* QZSS L6E data file */
105static char qzssl6e_path[1024] = ""; /* QZSS L6E data path */
106static FILE* fp_qzssl6e = NULL; /* QZSS L6E data file pointer */
107static has_t* gal_has = NULL; /* Galileo HAS decode context (heap) */
108static char gal_has_file[1024] = ""; /* Galileo HAS data file */
109static char gal_has_path[1024] = ""; /* Galileo HAS data path */
110static FILE* fp_gal_has = NULL; /* Galileo HAS data file pointer */
111static mdcl6d_t mdcl6d[MIONO_MAX_PRN]; /* QZSS L6D control struct */
112static char qzssl6d_file[MIONO_MAX_PRN][1024]; /* QZSS L6D data file */
113static char qzssl6d_path[MIONO_MAX_PRN][1024]; /* QZSS L6D data path */
114static FILE* fp_qzssl6d[MIONO_MAX_PRN]; /* QZSS L6D data file pointer */
115static char stat_file[1024] = ""; /* stat data file */
116static char cstat_file[1024] = ""; /* current stat data file */
117static FILE* fp_stat = NULL; /* stat data file pointer */
118static clas_ctx_t* clas_ctx = NULL; /* CLAS decoder context */
119static FILE* fp_clas[CLAS_CH_NUM]; /* CLAS L6 file pointers */
120static char clas_file[CLAS_CH_NUM][1024]; /* CLAS L6 data file */
121static char clas_path[CLAS_CH_NUM][1024]; /* CLAS L6 data path */
122
123/* show message and check break ----------------------------------------------*/
124static int checkbrk(const char* format, ...) {
125 va_list arg;
126 char buff[1024], *p = buff;
127 if (!*format) {
128 return showmsg("");
129 }
130 va_start(arg, format);
131 p += vsprintf(p, format, arg);
132 va_end(arg);
133 if (*proc_rov && *proc_base) {
134 sprintf(p, " (%s-%s)", proc_rov, proc_base);
135 } else if (*proc_rov) {
136 sprintf(p, " (%s)", proc_rov);
137 } else if (*proc_base) {
138 sprintf(p, " (%s)", proc_base);
139 }
140 return showmsg(buff);
141}
142/* output reference position -------------------------------------------------*/
143static void outrpos(FILE* fp, const double* r, const solopt_t* opt) {
144 double pos[3], dms1[3], dms2[3];
145 const char* sep = opt->sep;
146
147 trace(NULL, 3, "outrpos :\n");
148
149 if (opt->posf == SOLF_LLH || opt->posf == SOLF_ENU) {
150 ecef2pos(r, pos);
151 if (opt->degf) {
152 deg2dms(pos[0] * R2D, dms1, 5);
153 deg2dms(pos[1] * R2D, dms2, 5);
154 fprintf(fp, "%3.0f%s%02.0f%s%08.5f%s%4.0f%s%02.0f%s%08.5f%s%10.4f", dms1[0], sep, dms1[1], sep, dms1[2],
155 sep, dms2[0], sep, dms2[1], sep, dms2[2], sep, pos[2]);
156 } else {
157 fprintf(fp, "%13.9f%s%14.9f%s%10.4f", pos[0] * R2D, sep, pos[1] * R2D, sep, pos[2]);
158 }
159 } else if (opt->posf == SOLF_XYZ) {
160 fprintf(fp, "%14.4f%s%14.4f%s%14.4f", r[0], sep, r[1], sep, r[2]);
161 }
162}
163/* output header -------------------------------------------------------------*/
164static void outheader(FILE* fp, char** file, int n, const prcopt_t* popt, const solopt_t* sopt) {
165 const char* s1[] = {"GPST", "UTC", "JST"};
166 gtime_t ts, te;
167 double t1, t2;
168 int i, j, w1, w2;
169 char s2[32], s3[32];
170
171 trace(NULL, 3, "outheader: n=%d\n", n);
172
173 if (sopt->posf == SOLF_NMEA || sopt->posf == SOLF_STAT) {
174 return;
175 }
176 if (sopt->outhead) {
177 if (!*sopt->prog) {
178 fprintf(fp, "%s program : %s(%s ver.%s)\n", COMMENTH, PROGNAME, MRTKLIB_SOFTNAME, MRTKLIB_VERSION_STRING);
179 } else {
180 fprintf(fp, "%s program : %s\n", COMMENTH, sopt->prog);
181 }
182 for (i = 0; i < n; i++) {
183 fprintf(fp, "%s inp file : %s\n", COMMENTH, file[i]);
184 }
185 for (i = 0; i < obss.n; i++) {
186 if (obss.data[i].rcv == 1) {
187 break;
188 }
189 }
190 for (j = obss.n - 1; j >= 0; j--) {
191 if (obss.data[j].rcv == 1) {
192 break;
193 }
194 }
195 if (j < i) {
196 fprintf(fp, "\n%s no rover obs data\n", COMMENTH);
197 return;
198 }
199 ts = obss.data[i].time;
200 te = obss.data[j].time;
201 t1 = time2gpst(ts, &w1);
202 t2 = time2gpst(te, &w2);
203 if (sopt->times >= 1) {
204 ts = gpst2utc(ts);
205 }
206 if (sopt->times >= 1) {
207 te = gpst2utc(te);
208 }
209 if (sopt->times == 2) {
210 ts = timeadd(ts, 9 * 3600.0);
211 }
212 if (sopt->times == 2) {
213 te = timeadd(te, 9 * 3600.0);
214 }
215 time2str(ts, s2, 1);
216 time2str(te, s3, 1);
217 fprintf(fp, "%s obs start : %s %s (week%04d %8.1fs)\n", COMMENTH, s2, s1[sopt->times], w1, t1);
218 fprintf(fp, "%s obs end : %s %s (week%04d %8.1fs)\n", COMMENTH, s3, s1[sopt->times], w2, t2);
219 }
220 if (sopt->outopt) {
221 outprcopt(fp, popt);
222 }
223 if (PMODE_DGPS <= popt->mode && popt->mode <= PMODE_FIXED && popt->mode != PMODE_MOVEB) {
224 fprintf(fp, "%s ref pos :", COMMENTH);
225 outrpos(fp, popt->rb, sopt);
226 fprintf(fp, "\n");
227 }
228 if (sopt->outhead || sopt->outopt) {
229 fprintf(fp, "%s\n", COMMENTH);
230 }
231
232 outsolhead(fp, sopt);
233}
234/* search next observation data index ----------------------------------------*/
235static int nextobsf(const obs_t* obs, int* i, int rcv) {
236 double tt;
237 int n;
238
239 for (; *i < obs->n; (*i)++) {
240 if (obs->data[*i].rcv == rcv) {
241 break;
242 }
243 }
244 for (n = 0; *i + n < obs->n; n++) {
245 tt = timediff(obs->data[*i + n].time, obs->data[*i].time);
246 if (obs->data[*i + n].rcv != rcv || tt > DTTOL) {
247 break;
248 }
249 }
250 return n;
251}
252static int nextobsb(const obs_t* obs, int* i, int rcv) {
253 double tt;
254 int n;
255
256 for (; *i >= 0; (*i)--) {
257 if (obs->data[*i].rcv == rcv) {
258 break;
259 }
260 }
261 for (n = 0; *i - n >= 0; n++) {
262 tt = timediff(obs->data[*i - n].time, obs->data[*i].time);
263 if (obs->data[*i - n].rcv != rcv || tt < -DTTOL) {
264 break;
265 }
266 }
267 return n;
268}
269/* update rtcm ssr correction ------------------------------------------------*/
270static void update_rtcm(gtime_t time) {
271 char path[1024], tstr[32];
272 int i;
273
274 /* open or swap rtcm file */
275 reppath(rtcm_file, path, time, "", "");
276
277 if (strcmp(path, rtcm_path)) {
278 strcpy(rtcm_path, path);
279
280 if (fp_rtcm) {
281 fclose(fp_rtcm);
282 }
283 fp_rtcm = fopen(path, "rb");
284 if (fp_rtcm) {
285 rtcm->time = time;
287 trace(NULL, 2, "rtcm file open: %s\n", path);
288 }
289 }
290 if (!fp_rtcm) {
291 return;
292 }
293
294 /* read rtcm file until current time */
295 while (timediff(rtcm->time, time) < 1E-3) {
296 strcpy(tstr, time_str(rtcm->time, 3));
297 if (input_rtcm3f(rtcm, fp_rtcm) < -1) {
298 break;
299 }
300 trace(NULL, 3, "update_rtcm: %s %s\n", time_str(time, 3), tstr);
301
302 /* update ssr corrections */
303 for (i = 0; i < MAXSAT; i++) {
304 if (!rtcm->ssr[i].update || rtcm->ssr[i].iod[0] != rtcm->ssr[i].iod[1] ||
305 timediff(time, rtcm->ssr[i].t0[0]) < -1E-3) {
306 continue;
307 }
308 navs.ssr_ch[0][i] = rtcm->ssr[i];
309 rtcm->ssr[i].update = 0;
310 }
311 /* update iono/trop corrections */
312 block2stat(rtcm, &navs.stat);
313 }
314}
315/* update QZSS L6E MADOCA-PPP corrections ------------------------------------*/
316static void update_qzssl6e(gtime_t time) {
317 static int init_flg = 1;
318 char path[1024], tstr[32];
319 int i;
320
321 /* open or swap QZSS L6E file, record bit size is 1744(w/o R-S) or 2000 */
322 reppath(qzssl6e_file, path, time, "", "");
323
324 if (strcmp(path, qzssl6e_path)) {
325 strcpy(qzssl6e_path, path);
326
327 if (fp_qzssl6e) {
328 fclose(fp_qzssl6e);
329 }
330 fp_qzssl6e = fopen(path, "rb");
331 if (fp_qzssl6e) {
332 trace(NULL, 2, "qzssl6e file open: %s\n", path);
333 }
334 }
335 if (!fp_qzssl6e) {
336 return;
337 }
338
339 if (init_flg) {
340 init_mcssr(time);
341 init_flg = 0;
342 }
343
344 while (timediff(l6e->time, time) < 1E-3) {
345 strcpy(tstr, time_str(l6e->time, 3));
346 trace(NULL, 3, "update_qzssl6e: %s %s\n", time_str(time, 3), tstr);
347
348 /* update QZSS L6E MADOCA-PPP corrections */
349 for (i = 0; i < MAXSAT; i++) {
350 if (!l6e->ssr[i].update || l6e->ssr[i].iod[0] != l6e->ssr[i].iod[1] ||
351 timediff(time, l6e->ssr[i].t0[0]) < -1E-3) {
352 continue;
353 }
354 navs.ssr_ch[0][i] = l6e->ssr[i];
355 l6e->ssr[i].update = 0;
356 }
357
358 if (input_qzssl6ef(l6e, fp_qzssl6e) < -1) {
359 break;
360 }
361 }
362}
363/* update Galileo HAS PPP corrections ----------------------------------------*/
364static void update_gal_has(gtime_t time) {
365 char path[1024], tstr[32];
366 int i;
367
368 /* open or swap Galileo HAS .has file (64-byte little-endian records) */
369 reppath(gal_has_file, path, time, "", "");
370
371 if (strcmp(path, gal_has_path)) {
372 strcpy(gal_has_path, path);
373
374 if (fp_gal_has) {
375 fclose(fp_gal_has);
376 }
377 fp_gal_has = fopen(path, "rb");
378 if (fp_gal_has) {
379 trace(NULL, 2, "gal_has file open: %s\n", path);
380 }
381 }
382 if (!fp_gal_has || !gal_has) {
383 return;
384 }
385
386 /* feed all records up to the current epoch (has_input_file rewinds the first
387 * future record, so a single call per epoch advances the file in lock-step) */
389
390 strcpy(tstr, time_str(time, 3));
391 trace(NULL, 3, "update_gal_has: %s\n", tstr);
392
393 /* copy updated HAS corrections into the SSR channel */
394 for (i = 0; i < MAXSAT; i++) {
395 if (!gal_has->ssr[i].update || gal_has->ssr[i].iod[0] != gal_has->ssr[i].iod[1] ||
396 timediff(time, gal_has->ssr[i].t0[0]) < -1E-3) {
397 continue;
398 }
399 navs.ssr_ch[0][i] = gal_has->ssr[i];
400 gal_has->ssr[i].update = 0;
401 }
402}
403/* initialize QZSS L6D control struct ----------------------------------------*/
404static void init_mdcl6d(gtime_t time, const char* pppopt) {
405 int i, j, k;
406 trace(NULL, 2, "init_mdcl6d: time=%s\n", time_str(time, 0));
407
408 for (k = 0; k < MIONO_MAX_PRN; k++) {
409 strcpy(mdcl6d[k].opt, pppopt);
410 mdcl6d[k].time = time;
411 mdcl6d[k].nbyte = mdcl6d[k].re.rvalid = 0;
412 for (i = 0; i < MIONO_MAX_ANUM; i++) {
413 mdcl6d[k].re.area[i].avalid = 0;
414 for (j = 0; j < MAXSAT; j++) {
415 mdcl6d[k].re.area[i].sat[j].t0.time = 0;
416 }
417 }
418 init_miono(time);
419 }
420}
421/* update QZSS L6D MADOCA-PPP ionospheric corrections ------------------------*/
422static void update_qzssl6d(gtime_t time, int n, const char* pppopt) {
423 static int init_flg = 1;
424 char path[1024], tstr[32];
425 int i, j;
426
427 /* open or swap QZSS L6D file */
428 reppath(qzssl6d_file[n], path, timeadd(time, -1), "", "");
429
430 if (strcmp(path, qzssl6d_path[n])) {
431 strcpy(qzssl6d_path[n], path);
432
433 if (fp_qzssl6d[n]) {
434 fclose(fp_qzssl6d[n]);
435 }
436 fp_qzssl6d[n] = fopen(path, "rb");
437 if (fp_qzssl6d[n]) {
438 trace(NULL, 2, "qzssl6d file open: %s\n", path);
439 } else {
440 trace(NULL, 2, "qzssl6d file open error: %s\n", path);
441 }
442 }
443 if (!fp_qzssl6d[n]) {
444 return;
445 }
446
447 if (init_flg) {
448 init_mdcl6d(time, pppopt);
449 init_flg = 0;
450 }
451 while (timediff(mdcl6d[n].time, time) < 1E-3) {
452 strcpy(tstr, time_str(mdcl6d[n].time, 3));
453 trace(NULL, 3, "update_qzssl6d: %s %s\n", time_str(time, 3), tstr);
454
455 /* update QZSS L6D MADOCA-PPP ionospheric corrections */
456 if (mdcl6d[n].re.rvalid) {
457 navs.pppiono->re[mdcl6d[n].rid] = mdcl6d[n].re;
458 mdcl6d[n].re.rvalid = 0;
459 for (i = 0; i < MIONO_MAX_ANUM; i++) {
460 mdcl6d[n].re.area[i].avalid = 0;
461 for (j = 0; j < MAXSAT; j++) {
462 mdcl6d[n].re.area[i].sat[j].t0.time = 0;
463 }
464 }
465 }
466
467 if (input_qzssl6df(&mdcl6d[n], fp_qzssl6d[n]) < -1) {
468 break;
469 }
470 }
471}
472/* update stat corrections ---------------------------------------------------*/
473static void update_stat(gtime_t time) {
474 char path[1024], tstr[32], *p, st[64] = "";
475 int i, siteno = 0;
476 static sstat_t sstat = {0};
477 static char buff[4096];
478 static int nbyte = 0;
479
480 /* open or swap stat file */
481 reppath(stat_file, path, time, "", "");
482
483 if (strcmp(path, cstat_file) != 0) {
484 if (fp_stat) {
485 fclose(fp_stat);
486 }
487 fp_stat = fopen(path, "rb");
488 if (fp_stat == NULL) {
489 trace(NULL, 2, "stat file open error: %s\n", path);
490 } else {
491 strcpy(cstat_file, path);
492 }
493 }
494 if (!fp_stat) {
495 return;
496 }
497
498 /* station name as first 4 character of file */
499 if ((p = strrchr(cstat_file, FILEPATHSEP))) {
500 strncpy(st, p + 1, 4);
501 } else {
502 strncpy(st, cstat_file, 4);
503 }
504 st[4] = '\0';
505 for (i = 0; i < 4 && st[i]; i++) {
506 st[i] = toupper(st[i]);
507 }
508
509 siteno = getstano(&navs.stat, st);
510
511 while (timediff(sstat.time, time) < 1E-3) {
512 strcpy(tstr, time_str(sstat.time, 3));
513 trace(NULL, 3, "update_stat: %s %s st=%d\n", time_str(time, 3), tstr, siteno);
514
515 navs.stat.time[siteno] = sstat.time;
516 memcpy(&navs.stat.sion[siteno], &sstat.sion, sizeof(ion_t) * MAXSAT);
517 memcpy(&navs.stat.strp[siteno], &sstat.strp, sizeof(trp_t));
518
519 if (input_statf(&sstat, fp_stat, buff, &nbyte) < -1) {
520 break;
521 }
522 }
523 trace(NULL, 3, "update_stat: %s %s\n", time_str(time, 3), tstr);
524}
525
526static int clas_has_orbit_bank(const clas_ctx_t* ctx, int ch) {
527 int i;
528
529 if (!ctx || ch < 0 || ch >= CLAS_CH_NUM || !ctx->bank[ch]) {
530 return 0;
531 }
532 for (i = 0; i < CLAS_BANK_NUM; i++) {
533 if (ctx->bank[ch]->OrbitBank[i].use) {
534 return 1;
535 }
536 }
537 return 0;
538}
539
540/* update CLAS L6 corrections -----------------------------------------------*/
541static void update_clas(gtime_t time) {
542 int ch, ret;
543 char path[1024];
544
545 /* initialize GPS week reference from observation time (once) */
546 if (clas_ctx && clas_ctx->week_ref[0] == 0 && time.time != 0) {
547 int i, week;
548 time2gpst(time, &week);
549 for (i = 0; i < CSSR_REF_MAX; i++) {
550 clas_ctx->week_ref[i] = week;
551 clas_ctx->tow_ref[i] = -1; /* mark as unset for rollover detection */
552 }
553 trace(NULL, 2, "clas week_ref initialized: week=%d\n", week);
554 }
555
556 for (ch = 0; ch < CLAS_CH_NUM; ch++) {
557 if (!*clas_file[ch]) {
558 continue;
559 }
560
561 /* open or swap CLAS L6 file */
562 reppath(clas_file[ch], path, time, "", "");
563
564 if (strcmp(path, clas_path[ch])) {
565 strcpy(clas_path[ch], path);
566 if (fp_clas[ch]) {
567 fclose(fp_clas[ch]);
568 }
569 fp_clas[ch] = fopen(path, "rb");
570 if (fp_clas[ch]) {
571 trace(NULL, 2, "clas l6 file open: %s\n", path);
572 }
573 }
574 if (!fp_clas[ch]) {
575 continue;
576 }
577
578 /* Read CSSR through the correction set whose mask time is at the
579 * observation epoch, then stop at the next future mask boundary. */
580 for (;;) {
581 if (clas_ctx->l6buf[ch].subtype == CSSR_TYPE_MASK && timediff(clas_ctx->l6buf[ch].time, time) > 0.0 &&
583 break;
584 }
585 ret = clas_input_cssrf(clas_ctx, fp_clas[ch], ch);
586 if (ret < -1) {
587 break; /* EOF */
588 }
589 }
591 /* bootstrap: when network is unknown, scan all networks to
592 * populate grid_stat so clas_get_grid_index() can determine
593 * the correct network from the rover position.
594 * Uses a heap-allocated temporary corr to avoid corrupting
595 * current[ch] and stack overflow (clas_corr_t is ~352KB). */
596 if (clas_ctx->grid[ch].network <= 0 && clas_ctx->bank[ch]->use) {
597 clas_corr_t* tmp_corr = (clas_corr_t*)calloc(1, sizeof(clas_corr_t));
598 int net;
599 if (tmp_corr) {
600 for (net = 1; net < CLAS_MAX_NETWORK; net++) {
601 if (clas_bank_get_close(clas_ctx, time, net, ch, tmp_corr) == 0) {
602 clas_check_grid_status(clas_ctx, tmp_corr, ch);
603 /* apply global corrections (orbit/clock/bias) from any
604 * successful network — these are shared across networks */
605 clas_update_global(&navs, tmp_corr, ch);
606 }
607 }
608 free(tmp_corr);
609 }
610 trace(NULL, 3, "clas bootstrap: scanned %d networks for ch=%d\n", CLAS_MAX_NETWORK - 1, ch);
611 }
612 }
613}
614/* input obs data, navigation messages and sbas correction -------------------*/
615static int inputobs(obsd_t* obs, int solq, const prcopt_t* popt) {
616 gtime_t time = {0};
617 int i, nu, nr, n = 0;
618
619 trace(NULL, 3, "infunc : revs=%d iobsu=%d iobsr=%d isbs=%d\n", revs, iobsu, iobsr, isbs);
620
621 if (0 <= iobsu && iobsu < obss.n) {
622 settime((time = obss.data[iobsu].time));
623 if (checkbrk("processing : %s Q=%d", time_str(time, 0), solq)) {
624 aborts = 1;
625 showmsg("aborted");
626 return -1;
627 }
628 }
629 if (!revs) { /* input forward data */
630 if ((nu = nextobsf(&obss, &iobsu, 1)) <= 0) {
631 return -1;
632 }
633 if (popt->intpref) {
634 for (; (nr = nextobsf(&obss, &iobsr, 2)) > 0; iobsr += nr) {
635 if (timediff(obss.data[iobsr].time, obss.data[iobsu].time) > -DTTOL) {
636 break;
637 }
638 }
639 } else {
640 for (i = iobsr; (nr = nextobsf(&obss, &i, 2)) > 0; iobsr = i, i += nr) {
641 if (timediff(obss.data[i].time, obss.data[iobsu].time) > DTTOL) {
642 break;
643 }
644 }
645 }
646 nr = nextobsf(&obss, &iobsr, 2);
647 if (nr <= 0) {
648 nr = nextobsf(&obss, &iobsr, 2);
649 }
650 for (i = 0; i < nu && n < MAXOBS * 2; i++) {
651 obs[n++] = obss.data[iobsu + i];
652 }
653 for (i = 0; i < nr && n < MAXOBS * 2; i++) {
654 obs[n++] = obss.data[iobsr + i];
655 }
656 iobsu += nu;
657
658 /* update sbas corrections */
659 while (isbs < sbss.n) {
660 time = gpst2time(sbss.msgs[isbs].week, sbss.msgs[isbs].tow);
661
662 if (getbitu(sbss.msgs[isbs].msg, 8, 6) != 9) { /* except for geo nav */
663 sbsupdatecorr(sbss.msgs + isbs, &navs);
664 }
665 if (timediff(time, obs[0].time) > -1.0 - DTTOL) {
666 break;
667 }
668 isbs++;
669 }
670 /* update rtcm ssr corrections */
671 if (*rtcm_file) {
672 update_rtcm(obs[0].time);
673 }
674 /* update QZSS L6E MADOCA-PPP corrections */
675 if (*qzssl6e_file) {
676 update_qzssl6e(obs[0].time);
677 }
678 /* update Galileo HAS PPP corrections */
679 if (*gal_has_file) {
680 update_gal_has(obs[0].time);
681 }
682 /* update QZSS L6D MADOCA-PPP ionospheric corrections */
683 if (popt->ionocorr) {
684 int j;
685 for (j = 0; j < MIONO_MAX_PRN; j++) {
686 if (*qzssl6d_file[j]) {
687 update_qzssl6d(obs[0].time, j, popt->pppopt);
688 }
689 }
690 }
691 /* update CLAS L6 corrections */
692 if (clas_ctx) {
693 if (popt->l6mrg && !*clas_file[1]) {
694 static int warned_l6mrg_1file = 0;
695 if (!warned_l6mrg_1file) {
696 warned_l6mrg_1file = 1;
697 trace(NULL, 2, "l6_merge enabled but only one L6 source supplied - running single-channel\n");
698 }
699 }
700 update_clas(obs[0].time);
701 }
702 /* update stat corrections */
703 if (*stat_file) {
704 update_stat(obs[0].time);
705 }
706 } else { /* input backward data */
707 if ((nu = nextobsb(&obss, &iobsu, 1)) <= 0) {
708 return -1;
709 }
710 if (popt->intpref) {
711 for (; (nr = nextobsb(&obss, &iobsr, 2)) > 0; iobsr -= nr) {
712 if (timediff(obss.data[iobsr].time, obss.data[iobsu].time) < DTTOL) {
713 break;
714 }
715 }
716 } else {
717 for (i = iobsr; (nr = nextobsb(&obss, &i, 2)) > 0; iobsr = i, i -= nr) {
718 if (timediff(obss.data[i].time, obss.data[iobsu].time) < -DTTOL) {
719 break;
720 }
721 }
722 }
723 nr = nextobsb(&obss, &iobsr, 2);
724 for (i = 0; i < nu && n < MAXOBS * 2; i++) {
725 obs[n++] = obss.data[iobsu - nu + 1 + i];
726 }
727 for (i = 0; i < nr && n < MAXOBS * 2; i++) {
728 obs[n++] = obss.data[iobsr - nr + 1 + i];
729 }
730 iobsu -= nu;
731
732 /* update sbas corrections */
733 while (isbs >= 0) {
734 time = gpst2time(sbss.msgs[isbs].week, sbss.msgs[isbs].tow);
735
736 if (getbitu(sbss.msgs[isbs].msg, 8, 6) != 9) { /* except for geo nav */
737 sbsupdatecorr(sbss.msgs + isbs, &navs);
738 }
739 if (timediff(time, obs[0].time) < 1.0 + DTTOL) {
740 break;
741 }
742 isbs--;
743 }
744 }
745 return n;
746}
747/* process positioning -------------------------------------------------------*/
748static void procpos(mrtk_ctx_t* ctx, FILE* fp, const prcopt_t* popt, const solopt_t* sopt, int mode) {
749 gtime_t time = {0};
750 sol_t sol = {{0}};
751 rtk_t rtk;
752 obsd_t obs[MAXOBS * 2]; /* for rover and base */
753 double rb[3] = {0};
754 int i, nobs, n, solstatic, pri[] = {6, 1, 2, 3, 4, 5, 1, 6};
755
756 trace(ctx, 3, "procpos : mode=%d\n", mode);
757
758 solstatic = sopt->solstatic && (popt->mode == PMODE_STATIC || popt->mode == PMODE_PPP_STATIC);
759
760 rtkinit(&rtk, popt);
761 rtcm_path[0] = '\0';
762
763 while ((nobs = inputobs(obs, rtk.sol.stat, popt)) >= 0) {
764 /* exclude satellites */
765 for (i = n = 0; i < nobs; i++) {
766 if ((satsys(obs[i].sat, NULL) & popt->navsys) && popt->exsats[obs[i].sat - 1] != 1) {
767 obs[n++] = obs[i];
768 }
769 }
770 if (n <= 0) {
771 continue;
772 }
773
774 if (!rtkpos(ctx, &rtk, obs, n, &navs)) {
775 continue;
776 }
777
778 for (i = 0; i < 6; i++) {
779 rtk.prev_qr[i] = rtk.sol.qr[i];
780 }
781
782 if (mode == 0) { /* forward/backward */
783 if (!solstatic) {
784 outsol(fp, &rtk.sol, rtk.rb, sopt);
785 } else if (time.time == 0 || pri[rtk.sol.stat] <= pri[sol.stat]) {
786 sol = rtk.sol;
787 for (i = 0; i < 3; i++) {
788 rb[i] = rtk.rb[i];
789 }
790 if (time.time == 0 || timediff(rtk.sol.time, time) < 0.0) {
791 time = rtk.sol.time;
792 }
793 }
794 } else if (!revs) { /* combined-forward */
795 if (isolf >= nepoch) {
796 return;
797 }
798 solf[isolf] = rtk.sol;
799 for (i = 0; i < 3; i++) {
800 rbf[i + isolf * 3] = rtk.rb[i];
801 }
802 isolf++;
803 } else { /* combined-backward */
804 if (isolb >= nepoch) {
805 return;
806 }
807 solb[isolb] = rtk.sol;
808 for (i = 0; i < 3; i++) {
809 rbb[i + isolb * 3] = rtk.rb[i];
810 }
811 isolb++;
812 }
813 }
814 if (mode == 0 && solstatic && time.time != 0.0) {
815 sol.time = time;
816 outsol(fp, &sol, rb, sopt);
817 }
818 rtkfree(&rtk);
819}
820/* validation of combined solutions ------------------------------------------*/
821static int valcomb(const sol_t* solf, const sol_t* solb) {
822 double dr[3], var[3];
823 int i;
824 char tstr[32];
825
826 trace(NULL, 3, "valcomb :\n");
827
828 /* compare forward and backward solution */
829 for (i = 0; i < 3; i++) {
830 dr[i] = solf->rr[i] - solb->rr[i];
831 var[i] = solf->qr[i] + solb->qr[i];
832 }
833 for (i = 0; i < 3; i++) {
834 if (dr[i] * dr[i] <= 16.0 * var[i]) {
835 continue; /* ok if in 4-sigma */
836 }
837
838 time2str(solf->time, tstr, 2);
839 trace(NULL, 2, "degrade fix to float: %s dr=%.3f %.3f %.3f std=%.3f %.3f %.3f\n", tstr + 11, dr[0], dr[1],
840 dr[2], SQRT(var[0]), SQRT(var[1]), SQRT(var[2]));
841 return 0;
842 }
843 return 1;
844}
845/* combine forward/backward solutions and output results ---------------------*/
846static void combres(FILE* fp, const prcopt_t* popt, const solopt_t* sopt) {
847 gtime_t time = {0};
848 sol_t sols = {{0}}, sol = {{0}};
849 double tt, Qf[9], Qb[9], Qs[9], rbs[3] = {0}, rb[3] = {0}, rr_f[3], rr_b[3], rr_s[3];
850 int i, j, k, solstatic, pri[] = {0, 1, 2, 3, 4, 5, 1, 6};
851
852 trace(NULL, 3, "combres : isolf=%d isolb=%d\n", isolf, isolb);
853
854 solstatic = sopt->solstatic && (popt->mode == PMODE_STATIC || popt->mode == PMODE_PPP_STATIC);
855
856 for (i = 0, j = isolb - 1; i < isolf && j >= 0; i++, j--) {
857 if ((tt = timediff(solf[i].time, solb[j].time)) < -DTTOL) {
858 sols = solf[i];
859 for (k = 0; k < 3; k++) {
860 rbs[k] = rbf[k + i * 3];
861 }
862 j++;
863 } else if (tt > DTTOL) {
864 sols = solb[j];
865 for (k = 0; k < 3; k++) {
866 rbs[k] = rbb[k + j * 3];
867 }
868 i--;
869 } else if (solf[i].stat < solb[j].stat) {
870 sols = solf[i];
871 for (k = 0; k < 3; k++) {
872 rbs[k] = rbf[k + i * 3];
873 }
874 } else if (solf[i].stat > solb[j].stat) {
875 sols = solb[j];
876 for (k = 0; k < 3; k++) {
877 rbs[k] = rbb[k + j * 3];
878 }
879 } else {
880 sols = solf[i];
881 sols.time = timeadd(sols.time, -tt / 2.0);
882
883 if ((popt->mode == PMODE_KINEMA || popt->mode == PMODE_MOVEB) && sols.stat == SOLQ_FIX) {
884 /* degrade fix to float if validation failed */
885 if (!valcomb(solf + i, solb + j)) {
886 sols.stat = SOLQ_FLOAT;
887 }
888 }
889 for (k = 0; k < 3; k++) {
890 Qf[k + k * 3] = solf[i].qr[k];
891 Qb[k + k * 3] = solb[j].qr[k];
892 }
893 Qf[1] = Qf[3] = solf[i].qr[3];
894 Qf[5] = Qf[7] = solf[i].qr[4];
895 Qf[2] = Qf[6] = solf[i].qr[5];
896 Qb[1] = Qb[3] = solb[j].qr[3];
897 Qb[5] = Qb[7] = solb[j].qr[4];
898 Qb[2] = Qb[6] = solb[j].qr[5];
899
900 if (popt->mode == PMODE_MOVEB) {
901 for (k = 0; k < 3; k++) {
902 rr_f[k] = solf[i].rr[k] - rbf[k + i * 3];
903 }
904 for (k = 0; k < 3; k++) {
905 rr_b[k] = solb[j].rr[k] - rbb[k + j * 3];
906 }
907 if (smoother(rr_f, Qf, rr_b, Qb, 3, rr_s, Qs)) {
908 continue;
909 }
910 for (k = 0; k < 3; k++) {
911 sols.rr[k] = rbs[k] + rr_s[k];
912 }
913 } else {
914 if (smoother(solf[i].rr, Qf, solb[j].rr, Qb, 3, sols.rr, Qs)) {
915 continue;
916 }
917 }
918 sols.qr[0] = (float)Qs[0];
919 sols.qr[1] = (float)Qs[4];
920 sols.qr[2] = (float)Qs[8];
921 sols.qr[3] = (float)Qs[1];
922 sols.qr[4] = (float)Qs[5];
923 sols.qr[5] = (float)Qs[2];
924
925 /* smoother for velocity solution */
926 if (popt->dynamics) {
927 for (k = 0; k < 3; k++) {
928 Qf[k + k * 3] = solf[i].qv[k];
929 Qb[k + k * 3] = solb[j].qv[k];
930 }
931 Qf[1] = Qf[3] = solf[i].qv[3];
932 Qf[5] = Qf[7] = solf[i].qv[4];
933 Qf[2] = Qf[6] = solf[i].qv[5];
934 Qb[1] = Qb[3] = solb[j].qv[3];
935 Qb[5] = Qb[7] = solb[j].qv[4];
936 Qb[2] = Qb[6] = solb[j].qv[5];
937 if (smoother(solf[i].rr + 3, Qf, solb[j].rr + 3, Qb, 3, sols.rr + 3, Qs)) {
938 continue;
939 }
940 sols.qv[0] = (float)Qs[0];
941 sols.qv[1] = (float)Qs[4];
942 sols.qv[2] = (float)Qs[8];
943 sols.qv[3] = (float)Qs[1];
944 sols.qv[4] = (float)Qs[5];
945 sols.qv[5] = (float)Qs[2];
946 }
947 }
948 if (!solstatic) {
949 outsol(fp, &sols, rbs, sopt);
950 } else if (time.time == 0 || pri[sols.stat] <= pri[sol.stat]) {
951 sol = sols;
952 for (k = 0; k < 3; k++) {
953 rb[k] = rbs[k];
954 }
955 if (time.time == 0 || timediff(sols.time, time) < 0.0) {
956 time = sols.time;
957 }
958 }
959 }
960 if (solstatic && time.time != 0.0) {
961 sol.time = time;
962 outsol(fp, &sol, rb, sopt);
963 }
964}
965/* read prec ephemeris, sbas data, tec grid and open rtcm --------------------*/
966static void readpreceph(char** infile, int n, const prcopt_t* prcopt, nav_t* nav, sbs_t* sbs, gtime_t ts) {
967 seph_t seph0 = {0};
968 int i;
969 char* ext;
970
971 trace(NULL, 2, "readpreceph: n=%d\n", n);
972
973 nav->ne = nav->nemax = 0;
974 nav->nc = nav->ncmax = 0;
975 sbs->n = sbs->nmax = 0;
976
977 /* read precise ephemeris files */
978 for (i = 0; i < n; i++) {
979 if (strstr(infile[i], "%r") || strstr(infile[i], "%b")) {
980 continue;
981 }
982 readsp3(infile[i], nav, 0);
983 }
984 /* read precise clock files */
985 for (i = 0; i < n; i++) {
986 if (strstr(infile[i], "%r") || strstr(infile[i], "%b") || l6_file_type(infile[i])) {
987 continue;
988 }
989 readrnxc(infile[i], nav);
990 }
991 /* read sbas message files */
992 for (i = 0; i < n; i++) {
993 if (strstr(infile[i], "%r") || strstr(infile[i], "%b")) {
994 continue;
995 }
996 sbsreadmsg(infile[i], prcopt->sbassatsel, sbs);
997 }
998 /* allocate sbas ephemeris */
999 nav->ns = nav->nsmax = NSATSBS * 2;
1000 if (!(nav->seph = (seph_t*)malloc(sizeof(seph_t) * nav->ns))) {
1001 showmsg("error : sbas ephem memory allocation");
1002 trace(NULL, 1, "error : sbas ephem memory allocation");
1003 return;
1004 }
1005 for (i = 0; i < nav->ns; i++) {
1006 nav->seph[i] = seph0;
1007 }
1008
1009 /* set rtcm file and initialize rtcm struct */
1010 rtcm_file[0] = rtcm_path[0] = '\0';
1011 fp_rtcm = NULL;
1012 qzssl6e_file[0] = qzssl6e_path[0] = '\0';
1013 fp_qzssl6e = NULL;
1014 for (i = 0; i < MIONO_MAX_PRN; i++) {
1015 qzssl6d_file[i][0] = qzssl6d_path[i][0] = '\0';
1016 fp_qzssl6d[i] = NULL;
1017 }
1018 for (i = 0; i < CLAS_CH_NUM; i++) {
1019 clas_file[i][0] = clas_path[i][0] = '\0';
1020 fp_clas[i] = NULL;
1021 }
1022 stat_file[0] = cstat_file[0] = '\0';
1023 fp_stat = NULL;
1024
1025 for (i = 0; i < n; i++) {
1026 if ((ext = strrchr(infile[i], '.')) && (!strcmp(ext, ".rtcm3") || !strcmp(ext, ".RTCM3"))) {
1027 strcpy(rtcm_file, infile[i]);
1028 if (!rtcm) {
1029 rtcm = (rtcm_t*)calloc(1, sizeof(rtcm_t));
1030 if (!rtcm) {
1031 rtcm_file[0] = '\0';
1032 break;
1033 }
1034 }
1035 if (!init_rtcm(rtcm)) {
1036 rtcm_file[0] = '\0';
1037 free(rtcm);
1038 rtcm = NULL;
1039 break;
1040 }
1041 strcpy(rtcm->opt, prcopt->rtcmopt);
1042 break;
1043 }
1044 }
1045
1046 /* Galileo HAS .has file (first match only) */
1047 for (i = 0; i < n; i++) {
1048 if ((ext = strrchr(infile[i], '.')) && (!strcmp(ext, ".has") || !strcmp(ext, ".HAS"))) {
1049 strcpy(gal_has_file, infile[i]);
1050 if (!gal_has) {
1051 gal_has = has_new();
1052 if (!gal_has) {
1053 gal_has_file[0] = '\0';
1054 break;
1055 }
1056 }
1057 break;
1058 }
1059 }
1060
1061 /* QZSS L6 files (.l6 / .l6d / .l6e): MADOCA-PPP iono L6D, CLAS L6D, MADOCA-PPP L6E.
1062 * Legacy .l6: *.200.l6 / *.201.l6 are iono, others CLAS in CLAS mode, else L6E.
1063 * .l6d: iono by name (*.200.l6d / *.201.l6d) or by the first frame header,
1064 * otherwise CLAS (CLAS mode only). A time-keyword path (%Y ...) is
1065 * expanded at the session start for the content check only; the
1066 * template itself is kept for the per-epoch file switching.
1067 * .l6e: MADOCA-PPP L6E; in CLAS mode reserved for CLAS CMA (not yet used). */
1068 {
1069 int nf_l6d = 0, nf_clas = 0;
1070 int clas_mode = (prcopt->mode == PMODE_PPP_RTK) ||
1071 (prcopt->mode >= PMODE_SSR2OSR && prcopt->mode <= PMODE_SSR2OSR_FIXED) ||
1072 strstr(prcopt->pppopt, "-clas") != NULL;
1073
1074 for (i = 0; i < n; i++) {
1075 l6_file_type_t type = l6_file_type(infile[i]);
1076 int is_l6d = type == L6_FILE_L6D, is_l6e = type == L6_FILE_L6E, iono;
1077
1078 if (type == L6_FILE_NONE) {
1079 continue;
1080 }
1081 ext = strrchr(infile[i], '.');
1082 iono = !is_l6e && ext - infile[i] >= 4 && (!strncmp(ext - 4, ".200", 4) || !strncmp(ext - 4, ".201", 4));
1083 if (is_l6d && !iono) {
1084 char probe[1024];
1085 if (strchr(infile[i], '%') && ts.time) {
1086 reppath(infile[i], probe, ts, "", "");
1087 } else {
1088 snprintf(probe, sizeof(probe), "%s", infile[i]);
1089 }
1090 iono = l6_file_service(probe) == L6_SVC_MADOCA_IONO;
1091 }
1092 if (iono) { /* MADOCA-PPP L6D iono (PRN 200/201) — always detected */
1093 if (nf_l6d < MIONO_MAX_PRN) {
1094 strcpy(qzssl6d_file[nf_l6d++], infile[i]);
1095 }
1096 } else if (is_l6e && clas_mode) {
1097 showmsg("warning: CLAS CMA input not supported yet, ignored: %s", infile[i]);
1098 trace(NULL, 2, "L6E file ignored in CLAS mode (CMA not supported): %s\n", infile[i]);
1099 } else if (clas_mode && !is_l6e) { /* CLAS L6D */
1100 if (nf_clas < CLAS_CH_NUM) {
1101 strcpy(clas_file[nf_clas++], infile[i]);
1102 }
1103 } else if (is_l6d) {
1104 showmsg("warning: L6D file ignored outside CLAS mode: %s", infile[i]);
1105 trace(NULL, 2, "L6D file ignored outside CLAS mode: %s\n", infile[i]);
1106 } else if (!*qzssl6e_file) { /* MADOCA-PPP L6E (first match only) */
1107 strcpy(qzssl6e_file, infile[i]);
1108 if (!l6e) {
1109 l6e = (rtcm_t*)calloc(1, sizeof(rtcm_t));
1110 if (!l6e) {
1111 qzssl6e_file[0] = '\0';
1112 continue;
1113 }
1114 }
1115 if (!init_rtcm(l6e)) {
1116 qzssl6e_file[0] = '\0';
1117 free(l6e);
1118 l6e = NULL;
1119 continue;
1120 }
1121 strcpy(l6e->opt, prcopt->rtcmopt);
1122 }
1123 }
1124
1125 /* allocate pppiono if L6D files found */
1126 if (nf_l6d > 0 && !nav->pppiono) {
1127 nav->pppiono = (pppiono_t*)calloc(1, sizeof(pppiono_t));
1128 }
1129
1130 /* initialize CLAS context if files found */
1131 if (nf_clas > 0 && !clas_ctx) {
1132 clas_ctx = (clas_ctx_t*)calloc(1, sizeof(clas_ctx_t));
1133 if (clas_ctx) {
1135 }
1136 }
1137 /* wire CLAS context into nav for PPP-RTK engine access */
1138 navs.clas_ctx = clas_ctx;
1139 }
1140
1141 for (i = 0; i < n; i++) {
1142 if ((ext = strrchr(infile[i], '.')) && (!strcmp(ext, ".stat") || !strcmp(ext, ".STAT"))) {
1143 strcpy(stat_file, infile[i]);
1144 break;
1145 }
1146 }
1147}
1148/* free prec ephemeris and sbas data -----------------------------------------*/
1149static void freepreceph(nav_t* nav, sbs_t* sbs) {
1150 int i;
1151
1152 trace(NULL, 3, "freepreceph:\n");
1153
1154 free(nav->peph);
1155 nav->peph = NULL;
1156 nav->ne = nav->nemax = 0;
1157 free(nav->pclk);
1158 nav->pclk = NULL;
1159 nav->nc = nav->ncmax = 0;
1160 free(nav->seph);
1161 nav->seph = NULL;
1162 nav->ns = nav->nsmax = 0;
1163 free(sbs->msgs);
1164 sbs->msgs = NULL;
1165 sbs->n = sbs->nmax = 0;
1166 for (i = 0; i < nav->nt; i++) {
1167 free(nav->tec[i].data);
1168 free(nav->tec[i].rms);
1169 }
1170 free(nav->tec);
1171 nav->tec = NULL;
1172 nav->nt = nav->ntmax = 0;
1173
1174 if (fp_rtcm) {
1175 fclose(fp_rtcm);
1176 }
1177 if (rtcm) {
1178 free_rtcm(rtcm);
1179 free(rtcm);
1180 rtcm = NULL;
1181 }
1182 if (l6e) {
1183 free_rtcm(l6e);
1184 free(l6e);
1185 l6e = NULL;
1186 }
1187
1188 /* free Galileo HAS context */
1189 if (fp_gal_has) {
1190 fclose(fp_gal_has);
1191 fp_gal_has = NULL;
1192 }
1193 if (gal_has) {
1195 gal_has = NULL;
1196 }
1197 gal_has_file[0] = gal_has_path[0] = '\0';
1198
1199 /* free CLAS context */
1200 if (clas_ctx) {
1201 for (i = 0; i < CLAS_CH_NUM; i++) {
1202 if (fp_clas[i]) {
1203 fclose(fp_clas[i]);
1204 fp_clas[i] = NULL;
1205 }
1206 }
1208 free(clas_ctx);
1209 clas_ctx = NULL;
1210 }
1211}
1212/* read obs and nav data -----------------------------------------------------*/
1213static int readobsnav(gtime_t ts, gtime_t te, double ti, char** infile, const int* index, int n, const prcopt_t* prcopt,
1214 obs_t* obs, nav_t* nav, sta_t* sta) {
1215 int i, j, ind = 0, nobs = 0, rcv = 1;
1216
1217 trace(NULL, 3, "readobsnav: ts=%s n=%d\n", time_str(ts, 0), n);
1218
1219 obs->data = NULL;
1220 obs->n = obs->nmax = 0;
1221 nav->eph = NULL;
1222 nav->n = nav->nmax = 0;
1223 nav->geph = NULL;
1224 nav->ng = nav->ngmax = 0;
1225 nav->seph = NULL;
1226 nav->ns = nav->nsmax = 0;
1227 nepoch = 0;
1228
1229 for (i = 0; i < n; i++) {
1230 const char* ext;
1231 if (checkbrk("")) {
1232 return 0;
1233 }
1234
1235 if (index[i] != ind) {
1236 if (obs->n > nobs) {
1237 rcv++;
1238 }
1239 ind = index[i];
1240 nobs = obs->n;
1241 }
1242 if (l6_file_type(infile[i])) {
1243 continue; /* QZSS L6 frames, not RINEX (".l6d" would also trip the
1244 * Hatanaka 4th-char-'d' test in rtk_uncompress) */
1245 }
1246 ext = strrchr(infile[i], '.');
1247 if (ext && !strcmp(ext, ".bnx")) {
1248 /* read binex file */
1249 if (readbnxt(infile[i], rcv, ts, te, ti, prcopt->rnxopt[rcv <= 1 ? 0 : 1], obs, nav,
1250 rcv <= 2 ? sta + rcv - 1 : NULL, prcopt) < 0) {
1251 checkbrk("error : insufficient memory");
1252 trace(NULL, 1, "insufficient memory\n");
1253 return 0;
1254 }
1255 } else {
1256 /* read rinex obs and nav file */
1257 if (readrnxt(infile[i], rcv, ts, te, ti, prcopt->rnxopt[rcv <= 1 ? 0 : 1], obs, nav,
1258 rcv <= 2 ? sta + rcv - 1 : NULL) < 0) {
1259 checkbrk("error : insufficient memory");
1260 trace(NULL, 1, "insufficient memory\n");
1261 return 0;
1262 }
1263 }
1264 }
1265 if (obs->n <= 0) {
1266 checkbrk("error : no obs data");
1267 trace(NULL, 1, "\n");
1268 return 0;
1269 }
1270 if (nav->n <= 0 && nav->ng <= 0 && nav->ns <= 0) {
1271 checkbrk("error : no nav data");
1272 trace(NULL, 1, "\n");
1273 return 0;
1274 }
1275 /* sort observation data */
1276 nepoch = sortobs(obs);
1277
1278 /* delete duplicated ephemeris */
1279 uniqnav(nav);
1280
1281 /* set time span for progress display */
1282 if (ts.time == 0 || te.time == 0) {
1283 for (i = 0; i < obs->n; i++) {
1284 if (obs->data[i].rcv == 1) {
1285 break;
1286 }
1287 }
1288 for (j = obs->n - 1; j >= 0; j--) {
1289 if (obs->data[j].rcv == 1) {
1290 break;
1291 }
1292 }
1293 if (i < j) {
1294 if (ts.time == 0) {
1295 ts = obs->data[i].time;
1296 }
1297 if (te.time == 0) {
1298 te = obs->data[j].time;
1299 }
1300 settspan(ts, te);
1301 }
1302 }
1303 return 1;
1304}
1305/* free obs and nav data -----------------------------------------------------*/
1306static void freeobsnav(obs_t* obs, nav_t* nav) {
1307 trace(NULL, 3, "freeobsnav:\n");
1308
1309 free(obs->data);
1310 obs->data = NULL;
1311 obs->n = obs->nmax = 0;
1312 free(nav->eph);
1313 nav->eph = NULL;
1314 nav->n = nav->nmax = 0;
1315 free(nav->geph);
1316 nav->geph = NULL;
1317 nav->ng = nav->ngmax = 0;
1318 free(nav->seph);
1319 nav->seph = NULL;
1320 nav->ns = nav->nsmax = 0;
1321 free(nav->isb);
1322 nav->isb = NULL;
1323 nav->ni = nav->nimax = 0;
1324}
1325/* average of single position ------------------------------------------------*/
1326static int avepos(mrtk_ctx_t* ctx, double* ra, int rcv, const obs_t* obs, const nav_t* nav, const prcopt_t* opt) {
1327 obsd_t data[MAXOBS];
1328 gtime_t ts = {0};
1329 sol_t sol = {{0}};
1330 int i, j, n = 0, m, iobs;
1331 char msg[128];
1332
1333 trace(ctx, 3, "avepos: rcv=%d obs.n=%d\n", rcv, obs->n);
1334
1335 for (i = 0; i < 3; i++) {
1336 ra[i] = 0.0;
1337 }
1338
1339 for (iobs = 0; (m = nextobsf(obs, &iobs, rcv)) > 0; iobs += m) {
1340 for (i = j = 0; i < m && i < MAXOBS; i++) {
1341 data[j] = obs->data[iobs + i];
1342 if ((satsys(data[j].sat, NULL) & opt->navsys) && opt->exsats[data[j].sat - 1] != 1) {
1343 j++;
1344 }
1345 }
1346 if (j <= 0 || !screent(data[0].time, ts, ts, 1.0)) {
1347 continue; /* only 1 hz */
1348 }
1349
1350 if (!pntpos(ctx, data, j, nav, opt, &sol, NULL, NULL, msg)) {
1351 continue;
1352 }
1353
1354 for (i = 0; i < 3; i++) {
1355 ra[i] += sol.rr[i];
1356 }
1357 n++;
1358 }
1359 if (n <= 0) {
1360 trace(ctx, 1, "no average of base station position\n");
1361 return 0;
1362 }
1363 for (i = 0; i < 3; i++) {
1364 ra[i] /= n;
1365 }
1366 return 1;
1367}
1368/* station position from file ------------------------------------------------*/
1369static int getstapos(const char* file, char* name, double* r) {
1370 FILE* fp;
1371 char buff[256], sname[256], *p, *q;
1372 double pos[3];
1373
1374 trace(NULL, 3, "getstapos: file=%s name=%s\n", file, name);
1375
1376 if (!(fp = fopen(file, "r"))) {
1377 trace(NULL, 1, "station position file open error: %s\n", file);
1378 return 0;
1379 }
1380 while (fgets(buff, sizeof(buff), fp)) {
1381 if ((p = strchr(buff, '%'))) {
1382 *p = '\0';
1383 }
1384
1385 if (sscanf(buff, "%lf %lf %lf %s", pos, pos + 1, pos + 2, sname) < 4) {
1386 continue;
1387 }
1388
1389 for (p = sname, q = name; *p && *q; p++, q++) {
1390 if (toupper((int)*p) != toupper((int)*q)) {
1391 break;
1392 }
1393 }
1394 if (!*p) {
1395 pos[0] *= D2R;
1396 pos[1] *= D2R;
1397 pos2ecef(pos, r);
1398 fclose(fp);
1399 return 1;
1400 }
1401 }
1402 fclose(fp);
1403 trace(NULL, 1, "no station position: %s %s\n", name, file);
1404 return 0;
1405}
1406/* antenna phase center position ---------------------------------------------*/
1407static int antpos(mrtk_ctx_t* ctx, prcopt_t* opt, int rcvno, const obs_t* obs, const nav_t* nav, const sta_t* sta,
1408 const char* posfile) {
1409 double *rr = rcvno == 1 ? opt->ru : opt->rb, del[3], pos[3], dr[3] = {0};
1410 int i, postype = rcvno == 1 ? opt->rovpos : opt->refpos;
1411 char* name;
1412
1413 trace(ctx, 3, "antpos : rcvno=%d\n", rcvno);
1414
1415 if (postype == POSOPT_SINGLE) { /* average of single position */
1416 if (!avepos(ctx, rr, rcvno, obs, nav, opt)) {
1417 showmsg("error : station pos computation");
1418 return 0;
1419 }
1420 } else if (postype == POSOPT_FILE) { /* read from position file */
1421 name = stas[rcvno == 1 ? 0 : 1].name;
1422 if (!getstapos(posfile, name, rr)) {
1423 showmsg("error : no position of %s in %s", name, posfile);
1424 return 0;
1425 }
1426 } else if (postype == POSOPT_RINEX) { /* get from rinex header */
1427 if (norm(stas[rcvno == 1 ? 0 : 1].pos, 3) <= 0.0) {
1428 showmsg("error : no position in rinex header");
1429 trace(ctx, 1, "no position in rinex header\n");
1430 return 0;
1431 }
1432 /* antenna delta */
1433 if (stas[rcvno == 1 ? 0 : 1].deltype == 0) { /* enu */
1434 for (i = 0; i < 3; i++) {
1435 del[i] = stas[rcvno == 1 ? 0 : 1].del[i];
1436 }
1437 del[2] += stas[rcvno == 1 ? 0 : 1].hgt;
1438 ecef2pos(stas[rcvno == 1 ? 0 : 1].pos, pos);
1439 enu2ecef(pos, del, dr);
1440 } else { /* xyz */
1441 for (i = 0; i < 3; i++) {
1442 dr[i] = stas[rcvno == 1 ? 0 : 1].del[i];
1443 }
1444 }
1445 for (i = 0; i < 3; i++) {
1446 rr[i] = stas[rcvno == 1 ? 0 : 1].pos[i] + dr[i];
1447 }
1448 }
1449 return 1;
1450}
1451/* open procssing session ----------------------------------------------------*/
1452static int openses(mrtk_ctx_t* ctx, const prcopt_t* popt, const solopt_t* sopt, const filopt_t* fopt, nav_t* nav,
1453 pcvs_t* pcvs, pcvs_t* pcvr) {
1454 trace(ctx, 3, "openses :\n");
1455
1456 /* read satellite antenna parameters */
1457 if (*fopt->satantp && !(readpcv(fopt->satantp, pcvs))) {
1458 showmsg("error : no sat ant pcv in %s", fopt->satantp);
1459 trace(ctx, 1, "sat antenna pcv read error: %s\n", fopt->satantp);
1460 return 0;
1461 }
1462 /* read receiver antenna parameters */
1463 if (*fopt->rcvantp && !(readpcv(fopt->rcvantp, pcvr))) {
1464 showmsg("error : no rec ant pcv in %s", fopt->rcvantp);
1465 trace(ctx, 1, "rec antenna pcv read error: %s\n", fopt->rcvantp);
1466 return 0;
1467 }
1468 /* open geoid data */
1469 if (sopt->geoid > 0 && *fopt->geoid) {
1470 if (!opengeoid(sopt->geoid, fopt->geoid)) {
1471 showmsg("error : no geoid data %s", fopt->geoid);
1472 trace(ctx, 2, "no geoid data %s\n", fopt->geoid);
1473 }
1474 }
1475 return 1;
1476}
1477/* close procssing session ---------------------------------------------------*/
1478static void closeses(mrtk_ctx_t* ctx, nav_t* nav, pcvs_t* pcvs, pcvs_t* pcvr) {
1479 trace(ctx, 3, "closeses:\n");
1480
1481 /* free antenna parameters */
1482 free(pcvs->pcv);
1483 pcvs->pcv = NULL;
1484 pcvs->n = pcvs->nmax = 0;
1485 free(pcvr->pcv);
1486 pcvr->pcv = NULL;
1487 pcvr->n = pcvr->nmax = 0;
1488
1489 /* close geoid data */
1490 closegeoid();
1491
1492 /* free erp data */
1493 free(nav->erp.data);
1494 nav->erp.data = NULL;
1495 nav->erp.n = nav->erp.nmax = 0;
1496
1497 /* close solution statistics and debug trace */
1498 rtkclosestat();
1499 traceclose(ctx);
1500}
1501/* set antenna parameters ----------------------------------------------------*/
1502static void setpcv(gtime_t time, prcopt_t* popt, nav_t* nav, const pcvs_t* pcvs, const pcvs_t* pcvr, const sta_t* sta) {
1503 pcv_t *pcv, pcv0 = {0};
1504 double pos[3], del[3];
1505 int i, j, mode = PMODE_DGPS <= popt->mode && popt->mode <= PMODE_FIXED;
1506 char id[64];
1507
1508 /* set satellite antenna parameters */
1509 for (i = 0; i < MAXSAT; i++) {
1510 nav->pcvs[i] = pcv0;
1511 if (!(satsys(i + 1, NULL) & popt->navsys)) {
1512 continue;
1513 }
1514 if (!(pcv = searchpcv(i + 1, "", time, pcvs))) {
1515 satno2id(i + 1, id);
1516 trace(NULL, 3, "no satellite antenna pcv: %s\n", id);
1517 continue;
1518 }
1519 nav->pcvs[i] = *pcv;
1520 }
1521 for (i = 0; i < (mode ? 2 : 1); i++) {
1522 popt->pcvr[i] = pcv0;
1523 if (!strcmp(popt->anttype[i], "*")) { /* set by station parameters */
1524 strcpy(popt->anttype[i], sta[i].antdes);
1525 if (sta[i].deltype == 1) { /* xyz */
1526 if (norm(sta[i].pos, 3) > 0.0) {
1527 ecef2pos(sta[i].pos, pos);
1528 ecef2enu(pos, sta[i].del, del);
1529 for (j = 0; j < 3; j++) {
1530 popt->antdel[i][j] = del[j];
1531 }
1532 }
1533 } else { /* enu */
1534 for (j = 0; j < 3; j++) {
1535 popt->antdel[i][j] = stas[i].del[j];
1536 }
1537 }
1538 }
1539 if (!(pcv = searchpcv(0, popt->anttype[i], time, pcvr))) {
1540 trace(NULL, 2, "no receiver antenna pcv: %s\n", popt->anttype[i]);
1541 *popt->anttype[i] = '\0';
1542 continue;
1543 }
1544 strcpy(popt->anttype[i], pcv->type);
1545 popt->pcvr[i] = *pcv;
1546 }
1547}
1548/* read ocean tide loading parameters ----------------------------------------*/
1549static void readotl(prcopt_t* popt, const char* file, const sta_t* sta) {
1550 int i, mode = PMODE_DGPS <= popt->mode && popt->mode <= PMODE_FIXED;
1551
1552 for (i = 0; i < (mode ? 2 : 1); i++) {
1553 readblq(file, sta[i].name, popt->odisp[i]);
1554 }
1555}
1556/* write header to output file -----------------------------------------------*/
1557static int outhead(const char* outfile, char** infile, int n, const prcopt_t* popt, const solopt_t* sopt) {
1558 FILE* fp = stdout;
1559
1560 trace(NULL, 3, "outhead: outfile=%s n=%d\n", outfile, n);
1561
1562 if (*outfile) {
1563 createdir(outfile);
1564
1565 if (!(fp = fopen(outfile, "wb"))) {
1566 showmsg("error : open output file %s", outfile);
1567 return 0;
1568 }
1569 }
1570 /* output header */
1571 outheader(fp, infile, n, popt, sopt);
1572
1573 if (*outfile) {
1574 fclose(fp);
1575 }
1576
1577 return 1;
1578}
1579/* open output file for append -----------------------------------------------*/
1580static FILE* openfile(const char* outfile) {
1581 trace(NULL, 3, "openfile: outfile=%s\n", outfile);
1582
1583 return !*outfile ? stdout : fopen(outfile, "ab");
1584}
1585/* execute processing session ------------------------------------------------*/
1586static int execses(mrtk_ctx_t* ctx, gtime_t ts, gtime_t te, double ti, const prcopt_t* popt, const solopt_t* sopt,
1587 const filopt_t* fopt, int flag, char** infile, const int* index, int n, char* outfile) {
1588 FILE* fp;
1589 prcopt_t popt_ = *popt;
1590 char tracefile[1024], statfile[1024], path[1024], *ext;
1591
1592 trace(ctx, 3, "execses : n=%d outfile=%s\n", n, outfile);
1593
1594 /* open debug trace */
1595 if (flag && sopt->trace > 0) {
1596 if (*outfile) {
1597 strcpy(tracefile, outfile);
1598 strcat(tracefile, ".trace");
1599 } else {
1600 strcpy(tracefile, fopt->trace);
1601 }
1602 traceclose(ctx);
1603 traceopen(ctx, tracefile);
1604 tracelevel(ctx, sopt->trace);
1605 }
1606 /* read ionosphere data file */
1607 if (*fopt->iono && (ext = strrchr(fopt->iono, '.'))) {
1608 if (strlen(ext) == 4 && (ext[3] == 'i' || ext[3] == 'I')) {
1609 reppath(fopt->iono, path, ts, "", "");
1610 readtec(path, &navs, 1);
1611 }
1612 }
1613 /* read erp data */
1614 if (*fopt->eop) {
1615 free(navs.erp.data);
1616 navs.erp.data = NULL;
1617 navs.erp.n = navs.erp.nmax = 0;
1618 reppath(fopt->eop, path, ts, "", "");
1619 if (!readerp(path, &navs.erp)) {
1620 showmsg("error : no erp data %s", path);
1621 trace(ctx, 2, "no erp data %s\n", path);
1622 }
1623 }
1624 /* read obs and nav data */
1625 if (!readobsnav(ts, te, ti, infile, index, n, &popt_, &obss, &navs, stas)) {
1626 freeobsnav(&obss, &navs);
1627 return 0;
1628 }
1629 /* read dcb parameters */
1630 if (*fopt->dcb) {
1631 reppath(fopt->dcb, path, ts, "", "");
1632 readdcb(path, &navs, stas);
1633 }
1634 /* set antenna paramters */
1635 if (popt_.mode != PMODE_SINGLE) {
1636 setpcv(obss.n > 0 ? obss.data[0].time : timeget(), &popt_, &navs, &pcvss, &pcvsr, stas);
1637 }
1638 /* read ocean tide loading parameters */
1639 if (popt_.mode > PMODE_SINGLE && *fopt->blq) {
1640 readotl(&popt_, fopt->blq, stas);
1641 }
1642 /* read CLAS grid definition file */
1643 if (clas_ctx && *fopt->grid) {
1644 if (clas_read_grid_def(clas_ctx, fopt->grid) != 0) {
1645 trace(NULL, 1, "clas grid file error: %s\n", fopt->grid);
1646 }
1647 }
1648 /* read ISB correction table */
1649 if (clas_ctx && popt_.isb == ISBOPT_TABLE && *fopt->isb) {
1650 readisb(fopt->isb, &navs);
1651 trace(NULL, 3, "execses: ISB table loaded ni=%d\n", navs.ni);
1652 }
1653 /* read L2C phase shift table */
1654 if (clas_ctx && popt_.phasshft == ISBOPT_TABLE && *fopt->phacyc) {
1655 readL2C(fopt->phacyc, &navs);
1656 trace(NULL, 3, "execses: L2C table loaded n=%d\n", navs.sfts.n);
1657 }
1658 /* read grid BLQ file for CLAS grid OTL (tidecorr=3) */
1659 if (clas_ctx && popt_.tidecorr == 3 && *fopt->blq) {
1660 if (!readblqgrid(fopt->blq, clas_ctx)) {
1661 trace(NULL, 1, "grid blq file error: %s\n", fopt->blq);
1662 } else {
1663 trace(NULL, 3, "execses: grid BLQ loaded from %s\n", fopt->blq);
1664 }
1665 }
1666 /* copy station info to nav and set ISB */
1667 if (clas_ctx) {
1668 memcpy(navs.stas, stas, sizeof(sta_t) * MAXRCV);
1669 if (popt_.isb == ISBOPT_TABLE) {
1670 setisb(&navs, popt_.rectype[0], popt_.rectype[1], &navs.stas[0], &navs.stas[1]);
1671 }
1672 }
1673 /* rover/reference fixed position */
1674 if (popt_.mode == PMODE_FIXED) {
1675 if (!antpos(ctx, &popt_, 1, &obss, &navs, stas, fopt->stapos)) {
1676 freeobsnav(&obss, &navs);
1677 return 0;
1678 }
1679 } else if ((PMODE_DGPS <= popt_.mode && popt_.mode <= PMODE_STATIC) || popt_.mode == PMODE_VRS_RTK) {
1680 if (!antpos(ctx, &popt_, 2, &obss, &navs, stas, fopt->stapos)) {
1681 freeobsnav(&obss, &navs);
1682 return 0;
1683 }
1684 }
1685 /* open solution statistics */
1686 if (flag && sopt->sstat > 0) {
1687 strcpy(statfile, outfile);
1688 strcat(statfile, ".stat");
1689 rtkclosestat();
1690 rtkopenstat(statfile, sopt->sstat);
1691 }
1692 /* write header to output file */
1693 if (flag && !outhead(outfile, infile, n, &popt_, sopt)) {
1694 freeobsnav(&obss, &navs);
1695 return 0;
1696 }
1697 iobsu = iobsr = isbs = revs = aborts = 0;
1698
1699 /* check and set station name */
1700 if (strlen(popt_.staname) == 0) {
1701 strncpy(popt_.staname, stas[0].name, sizeof(popt_.staname));
1702 popt_.staname[sizeof(popt_.staname) - 1] = '\0';
1703 }
1704
1705 if (popt_.mode == PMODE_SINGLE || popt_.soltype == 0) {
1706 if ((fp = openfile(outfile))) {
1707 procpos(ctx, fp, &popt_, sopt, 0); /* forward */
1708 fclose(fp);
1709 }
1710 } else if (popt_.soltype == 1) {
1711 if ((fp = openfile(outfile))) {
1712 revs = 1;
1713 iobsu = iobsr = obss.n - 1;
1714 isbs = sbss.n - 1;
1715 procpos(ctx, fp, &popt_, sopt, 0); /* backward */
1716 fclose(fp);
1717 }
1718 } else { /* combined */
1719 solf = (sol_t*)malloc(sizeof(sol_t) * nepoch);
1720 solb = (sol_t*)malloc(sizeof(sol_t) * nepoch);
1721 rbf = (double*)malloc(sizeof(double) * nepoch * 3);
1722 rbb = (double*)malloc(sizeof(double) * nepoch * 3);
1723
1724 if (solf && solb) {
1725 isolf = isolb = 0;
1726 procpos(ctx, NULL, &popt_, sopt, 1); /* forward */
1727 revs = 1;
1728 iobsu = iobsr = obss.n - 1;
1729 isbs = sbss.n - 1;
1730 procpos(ctx, NULL, &popt_, sopt, 1); /* backward */
1731
1732 /* combine forward/backward solutions */
1733 if (!aborts && (fp = openfile(outfile))) {
1734 combres(fp, &popt_, sopt);
1735 fclose(fp);
1736 }
1737 } else {
1738 showmsg("error : memory allocation");
1739 }
1740 free(solf);
1741 free(solb);
1742 free(rbf);
1743 free(rbb);
1744 }
1745 /* free obs and nav data */
1746 freeobsnav(&obss, &navs);
1747
1748 return aborts ? 1 : 0;
1749}
1750/* execute processing session for each rover ---------------------------------*/
1751static int execses_r(mrtk_ctx_t* ctx, gtime_t ts, gtime_t te, double ti, const prcopt_t* popt, const solopt_t* sopt,
1752 const filopt_t* fopt, int flag, char** infile, const int* index, int n, char* outfile,
1753 const char* rov) {
1754 gtime_t t0 = {0};
1755 int i, stat = 0;
1756 char *ifile[MAXINFILE], ofile[1024], *rov_, *p, *q, s[64] = "";
1757
1758 trace(ctx, 3, "execses_r: n=%d outfile=%s\n", n, outfile);
1759
1760 for (i = 0; i < n; i++) {
1761 if (strstr(infile[i], "%r")) {
1762 break;
1763 }
1764 }
1765
1766 if (i < n) { /* include rover keywords */
1767 if (!(rov_ = (char*)malloc(strlen(rov) + 1))) {
1768 return 0;
1769 }
1770 strcpy(rov_, rov);
1771
1772 for (i = 0; i < n; i++) {
1773 if (!(ifile[i] = (char*)malloc(1024))) {
1774 free(rov_);
1775 for (; i >= 0; i--) {
1776 free(ifile[i]);
1777 }
1778 return 0;
1779 }
1780 }
1781 for (p = rov_;; p = q + 1) { /* for each rover */
1782 if ((q = strchr(p, ' '))) {
1783 *q = '\0';
1784 }
1785
1786 if (*p) {
1787 strcpy(proc_rov, p);
1788 if (ts.time) {
1789 time2str(ts, s, 0);
1790 } else {
1791 *s = '\0';
1792 }
1793 if (checkbrk("reading : %s", s)) {
1794 stat = 1;
1795 break;
1796 }
1797 for (i = 0; i < n; i++) {
1798 reppath(infile[i], ifile[i], t0, p, "");
1799 }
1800 reppath(outfile, ofile, t0, p, "");
1801
1802 /* execute processing session */
1803 stat = execses(ctx, ts, te, ti, popt, sopt, fopt, flag, ifile, index, n, ofile);
1804 }
1805 if (stat == 1 || !q) {
1806 break;
1807 }
1808 }
1809 free(rov_);
1810 for (i = 0; i < n; i++) {
1811 free(ifile[i]);
1812 }
1813 } else {
1814 /* execute processing session */
1815 stat = execses(ctx, ts, te, ti, popt, sopt, fopt, flag, infile, index, n, outfile);
1816 }
1817 return stat;
1818}
1819/* execute processing session for each base station --------------------------*/
1820static int execses_b(mrtk_ctx_t* ctx, gtime_t ts, gtime_t te, double ti, const prcopt_t* popt, const solopt_t* sopt,
1821 const filopt_t* fopt, int flag, char** infile, const int* index, int n, char* outfile,
1822 const char* rov, const char* base) {
1823 gtime_t t0 = {0};
1824 int i, stat = 0;
1825 char *ifile[MAXINFILE], ofile[1024], *base_, *p, *q, s[64];
1826
1827 trace(ctx, 3, "execses_b: n=%d outfile=%s\n", n, outfile);
1828
1829 /* read prec ephemeris and sbas data */
1830 readpreceph(infile, n, popt, &navs, &sbss, ts);
1831
1832 for (i = 0; i < n; i++) {
1833 if (strstr(infile[i], "%b")) {
1834 break;
1835 }
1836 }
1837
1838 if (i < n) { /* include base station keywords */
1839 if (!(base_ = (char*)malloc(strlen(base) + 1))) {
1840 freepreceph(&navs, &sbss);
1841 return 0;
1842 }
1843 strcpy(base_, base);
1844
1845 for (i = 0; i < n; i++) {
1846 if (!(ifile[i] = (char*)malloc(1024))) {
1847 free(base_);
1848 for (; i >= 0; i--) {
1849 free(ifile[i]);
1850 }
1851 freepreceph(&navs, &sbss);
1852 return 0;
1853 }
1854 }
1855 for (p = base_;; p = q + 1) { /* for each base station */
1856 if ((q = strchr(p, ' '))) {
1857 *q = '\0';
1858 }
1859
1860 if (*p) {
1861 strcpy(proc_base, p);
1862 if (ts.time) {
1863 time2str(ts, s, 0);
1864 } else {
1865 *s = '\0';
1866 }
1867 if (checkbrk("reading : %s", s)) {
1868 stat = 1;
1869 break;
1870 }
1871 for (i = 0; i < n; i++) {
1872 reppath(infile[i], ifile[i], t0, "", p);
1873 }
1874 reppath(outfile, ofile, t0, "", p);
1875
1876 stat = execses_r(ctx, ts, te, ti, popt, sopt, fopt, flag, ifile, index, n, ofile, rov);
1877 }
1878 if (stat == 1 || !q) {
1879 break;
1880 }
1881 }
1882 free(base_);
1883 for (i = 0; i < n; i++) {
1884 free(ifile[i]);
1885 }
1886 } else {
1887 stat = execses_r(ctx, ts, te, ti, popt, sopt, fopt, flag, infile, index, n, outfile, rov);
1888 }
1889 /* free prec ephemeris and sbas data */
1890 freepreceph(&navs, &sbss);
1891
1892 return stat;
1893}
1894/* post-processing positioning -------------------------------------------------
1895 * post-processing positioning
1896 * args : gtime_t ts I processing start time (ts.time==0: no limit)
1897 * : gtime_t te I processing end time (te.time==0: no limit)
1898 * double ti I processing interval (s) (0:all)
1899 * double tu I processing unit time (s) (0:all)
1900 * prcopt_t *popt I processing options
1901 * solopt_t *sopt I solution options
1902 * filopt_t *fopt I file options
1903 * char **infile I input files (see below)
1904 * int n I number of input files
1905 * char *outfile I output file ("":stdout, see below)
1906 * char *rov I rover id list (separated by " ")
1907 * char *base I base station id list (separated by " ")
1908 * return : status (0:ok,0>:error,1:aborted)
1909 * notes : input files should contain observation data, navigation data, precise
1910 * ephemeris/clock (optional), sbas log file (optional), ssr message
1911 * log file (optional) and tec grid file (optional). only the first
1912 * observation data file in the input files is recognized as the rover
1913 * data.
1914 *
1915 * the type of an input file is recognized by the file extention as ]
1916 * follows:
1917 * .sp3,.SP3,.eph*,.EPH*: precise ephemeris (sp3c)
1918 * .sbs,.SBS,.ems,.EMS : sbas message log files (rtklib or ems)
1919 * .rtcm3,.RTCM3 : ssr message log files (rtcm3)
1920 * .l6,.l6d,.l6e : QZSS L6 frame files, case-insensitive (CLAS, MADOCA-PPP)
1921 * .*i,.*I : tec grid files (ionex)
1922 * others : rinex obs, nav, gnav, hnav, qnav or clock
1923 *
1924 * inputs files can include wild-cards (*). if an file includes
1925 * wild-cards, the wild-card expanded multiple files are used.
1926 *
1927 * inputs files can include keywords. if an file includes keywords,
1928 * the keywords are replaced by date, time, rover id and base station
1929 * id and multiple session analyses run. refer reppath() for the
1930 * keywords.
1931 *
1932 * the output file can also include keywords. if the output file does
1933 * not include keywords. the results of all multiple session analyses
1934 * are output to a single output file.
1935 *
1936 * ssr corrections are valid only for forward estimation.
1937 *-----------------------------------------------------------------------------*/
1938extern int postpos(mrtk_ctx_t* ctx, gtime_t ts, gtime_t te, double ti, double tu, const prcopt_t* popt,
1939 const solopt_t* sopt, const filopt_t* fopt, char** infile, int n, char* outfile, const char* rov,
1940 const char* base) {
1941 gtime_t tts, tte, ttte;
1942 double tunit, tss;
1943 int i, j, k, nf, stat = 0, week, flag = 1, index[MAXINFILE] = {0};
1944 char *ifile[MAXINFILE], ofile[1024], *ext;
1945
1946 trace(ctx, 3, "postpos : ti=%.0f tu=%.0f n=%d outfile=%s\n", ti, tu, n, outfile);
1947
1948 /* BeiDou generation of PRN 1-18 and BDS-3 IGSO (#401): set before reading
1949 files, since RINEX reading already depends on the generation */
1950 set_bdsopt(popt, 1);
1951
1952 /* open processing session */
1953 if (!openses(ctx, popt, sopt, fopt, &navs, &pcvss, &pcvsr)) {
1954 return -1;
1955 }
1956
1957 if (ts.time != 0 && te.time != 0 && tu >= 0.0) {
1958 if (timediff(te, ts) < 0.0) {
1959 showmsg("error : no period");
1960 closeses(ctx, &navs, &pcvss, &pcvsr);
1961 return 0;
1962 }
1963 for (i = 0; i < MAXINFILE; i++) {
1964 if (!(ifile[i] = (char*)malloc(1024))) {
1965 for (; i >= 0; i--) {
1966 free(ifile[i]);
1967 }
1968 closeses(ctx, &navs, &pcvss, &pcvsr);
1969 return -1;
1970 }
1971 }
1972 if (tu == 0.0 || tu > 86400.0 * MAXPRCDAYS) {
1973 tu = 86400.0 * MAXPRCDAYS;
1974 }
1975 settspan(ts, te);
1976 tunit = tu < 86400.0 ? tu : 86400.0;
1977 tss = tunit * (int)floor(time2gpst(ts, &week) / tunit);
1978
1979 for (i = 0;; i++) { /* for each periods */
1980 tts = gpst2time(week, tss + i * tu);
1981 tte = timeadd(tts, tu - DTTOL);
1982 if (timediff(tts, te) > 0.0) {
1983 break;
1984 }
1985 if (timediff(tts, ts) < 0.0) {
1986 tts = ts;
1987 }
1988 if (timediff(tte, te) > 0.0) {
1989 tte = te;
1990 }
1991
1992 strcpy(proc_rov, "");
1993 strcpy(proc_base, "");
1994 if (checkbrk("reading : %s", time_str(tts, 0))) {
1995 stat = 1;
1996 break;
1997 }
1998 for (j = k = nf = 0; j < n; j++) {
1999 ext = strrchr(infile[j], '.');
2000
2001 if ((ext && (!strcmp(ext, ".rtcm3") || !strcmp(ext, ".RTCM3"))) || l6_file_type(infile[j])) {
2002 strcpy(ifile[nf++], infile[j]);
2003 } else {
2004 /* include next day precise ephemeris or rinex brdc nav */
2005 ttte = tte;
2006 if (ext && (!strcmp(ext, ".sp3") || !strcmp(ext, ".SP3") || !strcmp(ext, ".eph") ||
2007 !strcmp(ext, ".EPH"))) {
2008 ttte = timeadd(ttte, 3600.0);
2009 } else if (strstr(infile[j], "brdc")) {
2010 ttte = timeadd(ttte, 7200.0);
2011 }
2012 nf += reppaths(infile[j], ifile + nf, MAXINFILE - nf, tts, ttte, "", "");
2013 }
2014 if (ext && (!strcmp(ext, ".bia") || !strcmp(ext, ".BIA"))) {
2015 strcpy(navs.biapath, infile[j]);
2016 }
2017 if (ext && (!strcmp(ext, ".fcb") || !strcmp(ext, ".FCB"))) {
2018 strcpy(navs.fcbpath, infile[j]);
2019 }
2020 while (k < nf) {
2021 index[k++] = j;
2022 }
2023
2024 if (nf >= MAXINFILE) {
2025 trace(ctx, 2, "too many input files. trancated\n");
2026 break;
2027 }
2028 }
2029 if (!reppath(outfile, ofile, tts, "", "") && i > 0) {
2030 flag = 0;
2031 }
2032
2033 if (strlen(navs.biapath) == 0 && strlen(fopt->bia) > 0) {
2034 strcpy(navs.biapath, fopt->bia);
2035 }
2036 if (strlen(navs.fcbpath) == 0 && strlen(fopt->fcb) > 0) {
2037 strcpy(navs.fcbpath, fopt->fcb);
2038 }
2039 /* execute processing session */
2040 stat = execses_b(ctx, tts, tte, ti, popt, sopt, fopt, flag, ifile, index, nf, ofile, rov, base);
2041
2042 if (stat == 1) {
2043 break;
2044 }
2045 }
2046 for (i = 0; i < MAXINFILE; i++) {
2047 free(ifile[i]);
2048 }
2049 } else if (ts.time != 0) {
2050 for (i = 0; i < n && i < MAXINFILE; i++) {
2051 if (!(ifile[i] = (char*)malloc(1024))) {
2052 for (; i >= 0; i--) {
2053 free(ifile[i]);
2054 }
2055 return -1;
2056 }
2057 reppath(infile[i], ifile[i], ts, "", "");
2058 index[i] = i;
2059 }
2060 reppath(outfile, ofile, ts, "", "");
2061
2062 /* execute processing session */
2063 stat = execses_b(ctx, ts, te, ti, popt, sopt, fopt, 1, ifile, index, n, ofile, rov, base);
2064
2065 for (i = 0; i < n && i < MAXINFILE; i++) {
2066 free(ifile[i]);
2067 }
2068 } else {
2069 for (i = 0; i < n; i++) {
2070 index[i] = i;
2071 }
2072
2073 /* execute processing session */
2074 stat = execses_b(ctx, ts, te, ti, popt, sopt, fopt, 1, infile, index, n, outfile, rov, base);
2075 }
2076 /* close processing session */
2077 closeses(ctx, &navs, &pcvss, &pcvsr);
2078
2079 return stat;
2080}
int readpcv(const char *file, pcvs_t *pcvs)
Read antenna parameters from file (ANTEX or NGS format).
pcv_t * searchpcv(int sat, const char *type, gtime_t time, const pcvs_t *pcvs)
Search antenna parameter by satellite number or antenna type.
MRTKLIB Antenna Module — Antenna phase center model and parameter I/O.
void satno2id(int sat, char *id)
Definition mrtk_nav.c:817
uint32_t getbitu(const uint8_t *buff, int pos, int len)
Extract unsigned bits from byte data.
Definition mrtk_bits.c:99
MRTKLIB Bits Module — Binary bit operations and CRC functions.
void clas_check_grid_status(clas_ctx_t *ctx, const clas_corr_t *corr, int ch)
Check and update grid status flags based on correction availability.
Definition mrtk_clas.c:1320
void clas_ctx_free(clas_ctx_t *ctx)
Free CLAS context (release heap-allocated bank control).
Definition mrtk_clas.c:88
int clas_bank_get_close(const clas_ctx_t *ctx, gtime_t time, int network, int ch, clas_corr_t *corr)
Merge closest corrections from all banks into a clas_corr_t snapshot.
Definition mrtk_clas.c:1121
int clas_input_cssrf(clas_ctx_t *ctx, FILE *fp, int ch)
Input CSSR from file (one message at a time, post-processing).
Definition mrtk_clas.c:3217
int clas_read_grid_def(clas_ctx_t *ctx, const char *gridfile)
Read CLAS grid definition file.
Definition mrtk_clas.c:3238
void clas_check_grid_status_time(clas_ctx_t *ctx, gtime_t time, int ch)
Definition mrtk_clas.c:1365
void clas_update_global(nav_t *nav, const clas_corr_t *corr, int ch)
Apply global corrections (orbit/clock/bias) to nav_t.ssr[].
Definition mrtk_clas.c:1430
int clas_ctx_init(clas_ctx_t *ctx)
Initialize CLAS context (allocate bank control on heap).
Definition mrtk_clas.c:54
CLAS (QZSS L6D) CSSR decoder and grid correction type definitions.
#define CSSR_TYPE_MASK
Definition mrtk_clas.h:87
#define CLAS_CH_NUM
Definition mrtk_clas.h:185
#define CLAS_MAX_NETWORK
Definition mrtk_clas.h:186
@ CSSR_REF_MAX
Definition mrtk_clas.h:169
#define CLAS_BANK_NUM
Definition mrtk_clas.h:187
int readblqgrid(const char *file, clas_ctx_t *ctx)
Read BLQ ocean tide loading parameters for CLAS grid points.
int readL2C(const char *file, nav_t *nav)
Read L2C 1/4 cycle phase shift table from file.
int readisb(const char *file, nav_t *nav)
Read ISB correction table from file.
void setisb(const nav_t *nav, const char *rectype0, const char *rectype1, sta_t *sta0, sta_t *sta1)
Set ISB corrections for rover and reference stations.
#define D2R
Definition mrtk_coords.c:36
void enu2ecef(const double *pos, const double *e, double *r)
Transform local tangential coordinate vector to ECEF.
void pos2ecef(const double *pos, double *r)
Transform geodetic position to ECEF position.
#define MAXSAT
Definition mrtk_coords.c:45
void deg2dms(double deg, double *dms, int ndec)
Convert degree to degree-minute-second.
Definition mrtk_coords.c:63
void ecef2pos(const double *r, double *pos)
Transform ECEF position to geodetic position.
void ecef2enu(const double *pos, const double *r, double *e)
Transform ECEF vector to local tangential coordinate.
MRTKLIB Coordinates Module — Coordinate transformations and geometry.
int satsys(int sat, int *prn)
Definition mrtk_nav.c:117
struct nav_s nav_t
Definition mrtk_eph.h:40
#define MIONO_MAX_PRN
#define NSATSBS
#define MAXRCV
#define MAXOBS
#define DTTOL
#define MIONO_MAX_ANUM
void closegeoid(void)
Close geoid model file.
Definition mrtk_geoid.c:251
int opengeoid(int model, const char *file)
Open geoid model file.
Definition mrtk_geoid.c:227
MRTKLIB Geoid Module — Geoid height models.
void has_free(has_t *has)
Free a Galileo HAS decode context.
Definition mrtk_has.c:801
int has_input_file(has_t *has, FILE *fp, gtime_t tmax)
Read .has records from a file and feed them to has_input_page().
Definition mrtk_has.c:872
has_t * has_new(void)
Allocate and initialize a Galileo HAS decode context.
Definition mrtk_has.c:790
MRTKLIB Galileo HAS Module — E6-B C/NAV HAS page collection and Message Type 1 (MT1) decode into ssr_...
void readtec(const char *file, nav_t *nav, int opt)
Read IONEX ionospheric TEC grid file.
Definition mrtk_ionex.c:301
MRTKLIB IONEX Module — IONEX ionospheric TEC map I/O and interpolation.
l6_file_type_t l6_file_type(const char *file)
Classify a file name by its QZSS L6 extension (case-insensitive).
Definition mrtk_l6.c:100
l6_service_t l6_file_service(const char *file)
Service of an L6 frame file, from the first non-null frame header.
Definition mrtk_l6.c:120
@ L6_SVC_MADOCA_IONO
Definition mrtk_l6.h:63
l6_file_type_t
QZSS L6 file type from the file name extension.
Definition mrtk_l6.h:142
@ L6_FILE_L6E
Definition mrtk_l6.h:146
@ L6_FILE_NONE
Definition mrtk_l6.h:143
@ L6_FILE_L6D
Definition mrtk_l6.h:145
int input_qzssl6ef(rtcm_t *rtcm, FILE *fp)
Fetch next QZSS L6E message and input a message from file.
void init_mcssr(const gtime_t gt)
Initialize MADOCA-PPP CSSR control struct for current channel.
MRTKLIB MADOCA-PPP Module — QZSS L6E CSSR message decode functions.
void init_miono(const gtime_t gt)
Initialize MADOCA-PPP L6D ionospheric correction control.
int input_qzssl6df(mdcl6d_t *mdcl6d, FILE *fp)
Input QZSS L6D message from file.
int input_statf(sstat_t *sstat, FILE *fp, char *buff, int *nbyte)
Fetch next stat message and input a message from file.
int getstano(stat_t *stat, const char *pntname)
Search for a point by name or add a new point if not found.
int block2stat(rtcm_t *rtcm, stat_t *stat)
Convert RTCM3 block data to station statistics.
MRTKLIB MADOCA Local Correction Module — local correction common functions and constants.
int smoother(const double *xf, const double *Qf, const double *xb, const double *Qb, int n, double *xs, double *Qs)
Combine forward and backward filters by fixed-interval smoother.
Definition mrtk_mat.c:579
double norm(const double *a, int n)
Euclidean norm of vector.
Definition mrtk_mat.c:165
MRTKLIB Matrix Module — Matrix/vector operations and estimation.
void uniqnav(nav_t *nav)
Unique ephemerides in navigation data.
Definition mrtk_nav.c:971
int set_bdsopt(const prcopt_t *opt, int warn)
Apply the BeiDou PRN-reassignment options process-wide.
Definition mrtk_nav.c:282
MRTKLIB Navigation Module — Navigation data types and satellite/nav utility functions.
#define ISBOPT_TABLE
Definition mrtk_nav.h:349
int sortobs(obs_t *obs)
Sort observation data by time, receiver, and satellite.
Definition mrtk_obs.c:350
#define R2D
Definition mrtk_obs.c:51
int screent(gtime_t time, gtime_t ts, gtime_t te, double tint)
Screen data by time range and interval.
Definition mrtk_obs.c:424
MRTKLIB Observation Module — Observation data types and utility functions.
#define PMODE_PPP_RTK
Definition mrtk_opt.h:54
#define POSOPT_RINEX
Definition mrtk_opt.h:152
#define SOLF_STAT
Definition mrtk_opt.h:67
#define PMODE_MOVEB
Definition mrtk_opt.h:49
#define POSOPT_FILE
Definition mrtk_opt.h:151
#define POSOPT_SINGLE
Definition mrtk_opt.h:150
#define SOLQ_FLOAT
Definition mrtk_opt.h:72
#define SOLF_NMEA
Definition mrtk_opt.h:66
#define PMODE_DGPS
Definition mrtk_opt.h:46
#define SOLF_ENU
Definition mrtk_opt.h:65
#define PMODE_PPP_STATIC
Definition mrtk_opt.h:52
#define PMODE_KINEMA
Definition mrtk_opt.h:47
#define PMODE_SSR2OSR_FIXED
Definition mrtk_opt.h:56
#define PMODE_FIXED
Definition mrtk_opt.h:50
#define PMODE_STATIC
Definition mrtk_opt.h:48
#define SOLF_XYZ
Definition mrtk_opt.h:64
#define PMODE_VRS_RTK
Definition mrtk_opt.h:57
#define SOLF_LLH
Definition mrtk_opt.h:63
#define PMODE_SSR2OSR
Definition mrtk_opt.h:55
#define SOLQ_FIX
Definition mrtk_opt.h:71
#define PMODE_SINGLE
Definition mrtk_opt.h:45
void readsp3(const char *file, nav_t *nav, int opt)
Read sp3 precise ephemeris file.
Definition mrtk_peph.c:450
int readdcb(const char *file, nav_t *nav, const sta_t *sta)
Read differential code bias (DCB) parameters.
Definition mrtk_peph.c:583
int readerp(const char *file, erp_t *erp)
Read earth rotation parameters from IGS ERP file (ver.2).
Definition mrtk_peph.c:99
MRTKLIB Precise Ephemeris Module — Earth rotation parameter types and ERP I/O functions.
static int avepos(mrtk_ctx_t *ctx, double *ra, int rcv, const obs_t *obs, const nav_t *nav, const prcopt_t *opt)
static char clas_file[CLAS_CH_NUM][1024]
static void combres(FILE *fp, const prcopt_t *popt, const solopt_t *sopt)
static void init_mdcl6d(gtime_t time, const char *pppopt)
static void freepreceph(nav_t *nav, sbs_t *sbs)
static void update_gal_has(gtime_t time)
static int execses_b(mrtk_ctx_t *ctx, gtime_t ts, gtime_t te, double ti, const prcopt_t *popt, const solopt_t *sopt, const filopt_t *fopt, int flag, char **infile, const int *index, int n, char *outfile, const char *rov, const char *base)
static int isbs
static void outheader(FILE *fp, char **file, int n, const prcopt_t *popt, const solopt_t *sopt)
static void freeobsnav(obs_t *obs, nav_t *nav)
static int execses_r(mrtk_ctx_t *ctx, gtime_t ts, gtime_t te, double ti, const prcopt_t *popt, const solopt_t *sopt, const filopt_t *fopt, int flag, char **infile, const int *index, int n, char *outfile, const char *rov)
static mdcl6d_t mdcl6d[MIONO_MAX_PRN]
static void update_stat(gtime_t time)
static char qzssl6e_file[1024]
static int iobsu
static char clas_path[CLAS_CH_NUM][1024]
static char qzssl6d_file[MIONO_MAX_PRN][1024]
static int nextobsb(const obs_t *obs, int *i, int rcv)
static FILE * fp_rtcm
static FILE * fp_gal_has
static void update_rtcm(gtime_t time)
static char proc_base[64]
static sbs_t sbss
static int execses(mrtk_ctx_t *ctx, gtime_t ts, gtime_t te, double ti, const prcopt_t *popt, const solopt_t *sopt, const filopt_t *fopt, int flag, char **infile, const int *index, int n, char *outfile)
static char gal_has_file[1024]
static char qzssl6e_path[1024]
static FILE * fp_clas[CLAS_CH_NUM]
void settime(gtime_t time)
static void update_clas(gtime_t time)
static int getstapos(const char *file, char *name, double *r)
static char proc_rov[64]
static double * rbf
static void closeses(mrtk_ctx_t *ctx, nav_t *nav, pcvs_t *pcvs, pcvs_t *pcvr)
static obs_t obss
static int antpos(mrtk_ctx_t *ctx, prcopt_t *opt, int rcvno, const obs_t *obs, const nav_t *nav, const sta_t *sta, const char *posfile)
static int isolf
static void update_qzssl6d(gtime_t time, int n, const char *pppopt)
static sol_t * solb
static char rtcm_file[1024]
static int isolb
static int checkbrk(const char *format,...)
static double * rbb
static int revs
static FILE * fp_qzssl6d[MIONO_MAX_PRN]
static sta_t stas[MAXRCV]
#define PROGNAME
int postpos(mrtk_ctx_t *ctx, gtime_t ts, gtime_t te, double ti, double tu, const prcopt_t *popt, const solopt_t *sopt, const filopt_t *fopt, char **infile, int n, char *outfile, const char *rov, const char *base)
Post-processing positioning.
static pcvs_t pcvsr
static void procpos(mrtk_ctx_t *ctx, FILE *fp, const prcopt_t *popt, const solopt_t *sopt, int mode)
static rtcm_t * l6e
static int clas_has_orbit_bank(const clas_ctx_t *ctx, int ch)
static int outhead(const char *outfile, char **infile, int n, const prcopt_t *popt, const solopt_t *sopt)
static int openses(mrtk_ctx_t *ctx, const prcopt_t *popt, const solopt_t *sopt, const filopt_t *fopt, nav_t *nav, pcvs_t *pcvs, pcvs_t *pcvr)
static void readpreceph(char **infile, int n, const prcopt_t *prcopt, nav_t *nav, sbs_t *sbs, gtime_t ts)
static char stat_file[1024]
static char rtcm_path[1024]
static int nepoch
static FILE * fp_qzssl6e
static int inputobs(obsd_t *obs, int solq, const prcopt_t *popt)
static int valcomb(const sol_t *solf, const sol_t *solb)
#define COMMENTH
static void setpcv(gtime_t time, prcopt_t *popt, nav_t *nav, const pcvs_t *pcvs, const pcvs_t *pcvr, const sta_t *sta)
static rtcm_t * rtcm
static has_t * gal_has
static int iobsr
static int readobsnav(gtime_t ts, gtime_t te, double ti, char **infile, const int *index, int n, const prcopt_t *prcopt, obs_t *obs, nav_t *nav, sta_t *sta)
static char gal_has_path[1024]
static FILE * fp_stat
static int nextobsf(const obs_t *obs, int *i, int rcv)
static char cstat_file[1024]
static void update_qzssl6e(gtime_t time)
static void outrpos(FILE *fp, const double *r, const solopt_t *opt)
#define MAXPRCDAYS
void settspan(gtime_t ts, gtime_t te)
static FILE * openfile(const char *outfile)
int showmsg(const char *format,...)
static char qzssl6d_path[MIONO_MAX_PRN][1024]
#define SQRT(x)
static void readotl(prcopt_t *popt, const char *file, const sta_t *sta)
static pcvs_t pcvss
static sol_t * solf
static int aborts
#define MAXINFILE
static nav_t navs
static clas_ctx_t * clas_ctx
MRTKLIB Post-Processing Positioning Module — Post-processing positioning orchestrator.
MRTKLIB Precise Point Positioning (PPP) Module.
int readbnxt(const char *file, int rcv, gtime_t ts, gtime_t te, double tint, const char *opt, obs_t *obs, nav_t *nav, sta_t *sta, const prcopt_t *popt)
Read BINEX observation/navigation data from file(s).
MRTKLIB Receiver Raw Data Module — Receiver raw data types and decoder functions for various GNSS rec...
int readrnxt(const char *file, int rcv, gtime_t ts, gtime_t te, double tint, const char *opt, obs_t *obs, nav_t *nav, sta_t *sta)
Read RINEX OBS and NAV files with time span.
int readrnxc(const char *file, nav_t *nav)
Read RINEX clock files.
MRTKLIB RINEX Module — RINEX file read/write types and functions.
void free_rtcm(rtcm_t *rtcm)
Free RTCM control struct.
Definition mrtk_rtcm.c:118
int input_rtcm3f(rtcm_t *rtcm, FILE *fp)
Input RTCM 3 message from file.
Definition mrtk_rtcm.c:347
int init_rtcm(rtcm_t *rtcm)
Initialize RTCM control struct.
Definition mrtk_rtcm.c:37
MRTKLIB RTCM Module — RTCM message types and functions.
int rtkpos(mrtk_ctx_t *ctx, rtk_t *rtk, const obsd_t *obs, int n, nav_t *nav)
Compute rover position by precise positioning.
void rtkfree(rtk_t *rtk)
Free memory for RTK control struct.
int rtkopenstat(const char *file, int level)
Open solution status file and set output level.
void rtkclosestat(void)
Close solution status file.
void rtkinit(rtk_t *rtk, const prcopt_t *opt)
Initialize RTK control struct.
MRTKLIB RTK Positioning Module — relative and precise positioning.
int sbsreadmsg(const char *file, int sel, sbs_t *sbs)
Read SBAS message file.
Definition mrtk_sbas.c:719
int sbsupdatecorr(const sbsmsg_t *msg, nav_t *nav)
Update SBAS corrections in navigation data.
Definition mrtk_sbas.c:517
MRTKLIB SBAS Module — SBAS message decoding and corrections.
void outprcopt(FILE *fp, const prcopt_t *opt)
Output processing options to file.
Definition mrtk_sol.c:1871
void outsolhead(FILE *fp, const solopt_t *opt)
Output solution header to file.
Definition mrtk_sol.c:1887
void outsol(FILE *fp, const sol_t *sol, const double *rb, const solopt_t *opt)
Output solution to file.
Definition mrtk_sol.c:1905
MRTKLIB Solution Module — Solution data types and I/O functions.
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...
Definition mrtk_spp.c:865
MRTKLIB Single-Point Positioning Module — SPP functions.
int readblq(const char *file, const char *sta, double *odisp)
Read BLQ ocean tide loading parameters.
MRTKLIB Station Module — Site environment parameter I/O.
#define FILEPATHSEP
Definition mrtk_sys.c:48
void createdir(const char *path)
Create directory if not exists (recursively).
Definition mrtk_sys.c:187
int reppath(const char *path, char *rpath, gtime_t time, const char *rov, const char *base)
Replace keywords in file path with date, time, rover and base station id.
Definition mrtk_sys.c:248
int reppaths(const char *path, char *rpath[], int nmax, gtime_t ts, gtime_t te, const char *rov, const char *base)
Replace keywords in file path and generate multiple paths.
Definition mrtk_sys.c:321
MRTKLIB System Module — OS/filesystem utility functions.
MRTKLIB Tides Module — Tidal displacement corrections.
gtime_t gpst2time(int week, double sec)
Convert GPS week/tow to gtime_t.
Definition mrtk_time.c:165
void time2str(gtime_t t, char *s, int n)
Convert gtime_t struct to string.
Definition mrtk_time.c:507
gtime_t gpst2utc(gtime_t t)
Convert GPS time to UTC considering leap seconds.
Definition mrtk_time.c:422
double timediff(gtime_t t1, gtime_t t2)
Compute time difference (t1 - t2).
Definition mrtk_time.c:279
double time2gpst(gtime_t t, int *week)
Convert gtime_t to GPS week/tow.
Definition mrtk_time.c:181
gtime_t timeadd(gtime_t t, double sec)
Add seconds to gtime_t.
Definition mrtk_time.c:265
char * time_str(gtime_t t, int n)
Get time string (not reentrant).
Definition mrtk_time.c:530
gtime_t timeget(void)
Get current time in UTC.
Definition mrtk_time.c:289
void traceopen(mrtk_ctx_t *ctx, const char *file)
Open trace output (initializes tick counter for tracet).
Definition mrtk_trace.c:34
void tracelevel(mrtk_ctx_t *ctx, int level)
Set trace level.
Definition mrtk_trace.c:71
void traceclose(mrtk_ctx_t *ctx)
Close trace output.
Definition mrtk_trace.c:60
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.
clas_orbit_bank_t OrbitBank[32]
Definition mrtk_clas.h:442
clas_bank_ctrl_t * bank[2]
Definition mrtk_clas.h:585
int n
Definition mrtk_peph.h:60
erpd_t * data
Definition mrtk_peph.h:61
int nmax
Definition mrtk_peph.h:60
char satantp[MAXSTRPATH]
Definition mrtk_opt.h:378
char fcb[MAXSTRPATH]
Definition mrtk_opt.h:392
char stapos[MAXSTRPATH]
Definition mrtk_opt.h:380
char trace[MAXSTRPATH]
Definition mrtk_opt.h:390
char eop[MAXSTRPATH]
Definition mrtk_opt.h:384
char phacyc[MAXSTRPATH]
Definition mrtk_opt.h:395
char bia[MAXSTRPATH]
Definition mrtk_opt.h:391
char blq[MAXSTRPATH]
Definition mrtk_opt.h:385
char iono[MAXSTRPATH]
Definition mrtk_opt.h:382
char geoid[MAXSTRPATH]
Definition mrtk_opt.h:381
char rcvantp[MAXSTRPATH]
Definition mrtk_opt.h:379
char grid[MAXSTRPATH]
Definition mrtk_opt.h:393
char isb[MAXSTRPATH]
Definition mrtk_opt.h:394
char dcb[MAXSTRPATH]
Definition mrtk_opt.h:383
GNSS time representation.
Definition mrtk_time.h:49
time_t time
Definition mrtk_time.h:50
QZSS L6D message control struct.
Definition mrtk_ppp.h:50
Runtime context for MRTKLIB processing.
int nt
Definition mrtk_nav.h:399
tec_t * tec
Definition mrtk_nav.h:412
pppiono_t * pppiono
Definition mrtk_nav.h:438
int ng
Definition mrtk_nav.h:394
int ni
Definition mrtk_nav.h:449
int nemax
Definition mrtk_nav.h:396
isb_t * isb
Definition mrtk_nav.h:448
seph_t * seph
Definition mrtk_nav.h:408
erp_t erp
Definition mrtk_nav.h:413
geph_t * geph
Definition mrtk_nav.h:407
int ntmax
Definition mrtk_nav.h:399
pclk_t * pclk
Definition mrtk_nav.h:410
int nimax
Definition mrtk_nav.h:449
pcv_t pcvs[MAXSAT]
Definition mrtk_nav.h:430
peph_t * peph
Definition mrtk_nav.h:409
int ncmax
Definition mrtk_nav.h:397
eph_t * eph
Definition mrtk_nav.h:400
int nc
Definition mrtk_nav.h:397
int nsmax
Definition mrtk_nav.h:395
int ngmax
Definition mrtk_nav.h:394
int nmax
Definition mrtk_nav.h:393
int ns
Definition mrtk_nav.h:395
int n
Definition mrtk_nav.h:393
int ne
Definition mrtk_nav.h:396
Observation data collection.
Definition mrtk_obs.h:59
obsd_t * data
Definition mrtk_obs.h:61
int nmax
Definition mrtk_obs.h:60
int n
Definition mrtk_obs.h:60
Observation data record.
Definition mrtk_obs.h:44
gtime_t time
Definition mrtk_obs.h:45
uint8_t sat
Definition mrtk_obs.h:46
uint8_t rcv
Definition mrtk_obs.h:46
char type[MAXANT]
Definition mrtk_nav.h:47
pcv_t * pcv
Definition mrtk_nav.h:57
int n
Definition mrtk_nav.h:56
int nmax
Definition mrtk_nav.h:56
int sbassatsel
Definition mrtk_opt.h:195
int isb
Definition mrtk_opt.h:260
int ionocorr
Definition mrtk_opt.h:248
int soltype
Definition mrtk_opt.h:173
int phasshft
Definition mrtk_opt.h:259
char anttype[2][MAXANT]
Definition mrtk_opt.h:222
pcv_t pcvr[2]
Definition mrtk_opt.h:224
char rnxopt[2][256]
Definition mrtk_opt.h:236
int rovpos
Definition mrtk_opt.h:196
int dynamics
Definition mrtk_opt.h:189
int intpref
Definition mrtk_opt.h:193
char rectype[2][MAXANT]
Definition mrtk_opt.h:274
uint8_t exsats[MAXSAT]
Definition mrtk_opt.h:225
double odisp[2][6 *11]
Definition mrtk_opt.h:239
char pppopt[256]
Definition mrtk_opt.h:243
int mode
Definition mrtk_opt.h:172
int tidecorr
Definition mrtk_opt.h:190
double antdel[2][3]
Definition mrtk_opt.h:223
double ru[3]
Definition mrtk_opt.h:220
int navsys
Definition mrtk_opt.h:175
double rb[3]
Definition mrtk_opt.h:221
char staname[32]
Definition mrtk_opt.h:246
int l6mrg
Definition mrtk_opt.h:275
int refpos
Definition mrtk_opt.h:197
char rtcmopt[256]
Definition mrtk_opt.h:244
RTCM control struct type.
Definition mrtk_rtcm.h:50
double prev_qr[6]
Definition mrtk_rtkpos.h:65
double rb[6]
Definition mrtk_rtkpos.h:51
sol_t sol
Definition mrtk_rtkpos.h:50
int nmax
Definition mrtk_nav.h:108
sbsmsg_t * msgs
Definition mrtk_nav.h:109
int n
Definition mrtk_nav.h:108
SBAS ephemeris type.
Definition mrtk_eph.h:130
float qr[6]
Definition mrtk_sol.h:48
double rr[6]
Definition mrtk_sol.h:46
uint8_t stat
Definition mrtk_sol.h:54
float qv[6]
Definition mrtk_sol.h:51
gtime_t time
Definition mrtk_sol.h:45
int degf
Definition mrtk_opt.h:356
int sstat
Definition mrtk_opt.h:364
int outopt
Definition mrtk_opt.h:358
int trace
Definition mrtk_opt.h:365
int times
Definition mrtk_opt.h:353
int geoid
Definition mrtk_opt.h:362
int posf
Definition mrtk_opt.h:352
int outhead
Definition mrtk_opt.h:357
char sep[64]
Definition mrtk_opt.h:368
char prog[64]
Definition mrtk_opt.h:369
int solstatic
Definition mrtk_opt.h:363
siteion_t sion
Definition mrtk_nav.h:297
gtime_t time
Definition mrtk_nav.h:296
sitetrp_t strp
Definition mrtk_nav.h:298
char antdes[MAXANT]
Definition mrtk_nav.h:372
float * rms
Definition mrtk_nav.h:94
double * data
Definition mrtk_nav.h:93
#define malloc(x)
Definition toml.c:52
#define calloc(x, y)
Definition toml.c:54
#define free(x)
Definition toml.c:53