MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_clas_isb.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_clas_isb.c : ISB (inter-system bias) and L2C phase shift corrections
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) 2007-2013 T.TAKASU
12 *
13 * SPDX-License-Identifier: BSD-2-Clause
14 *----------------------------------------------------------------------------*/
15/**
16 * @file mrtk_clas_isb.c
17 * @brief ISB (inter-system bias) and L2C phase shift corrections.
18 *
19 * References:
20 * [1] claslib (https://github.com/mf-arai/claslib) — upstream isb.c
21 *
22 * Notes:
23 * - Ported from upstream claslib isb.c with minimal changes.
24 * - ISB corrects inter-system receiver biases between GPS/GLO/GAL/QZS.
25 * - L2C corrects 1/4 cycle phase shift on certain GPS L2C satellites.
26 */
27#include <ctype.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include "mrtklib/mrtk_clas.h"
33#include "mrtklib/mrtk_const.h"
35#include "mrtklib/mrtk_nav.h"
36#include "mrtklib/mrtk_obs.h"
37#include "mrtklib/mrtk_opt.h"
38#include "mrtklib/mrtk_sys.h"
39#include "mrtklib/mrtk_trace.h"
40
41#define NINCISB 256 /* ISB data realloc increment */
42
43/* strip leading/trailing spaces from a string ---------------------------------
44 * copy src to dst, stripping leading and trailing spaces.
45 * args : char *dst O destination string
46 * const char *src I source string
47 * int n I max chars to copy from src
48 *-----------------------------------------------------------------------------*/
49static void setstr(char* dst, const char* src, int n) {
50 char* p = dst;
51 const char* q = src;
52
53 while (*q && q < src + n) {
54 if (p == dst && *q == ' ') {
55 q++;
56 continue;
57 }
58 *p++ = *q++;
59 }
60 *p = '\0';
61 p--;
62 while (p >= dst && *p == ' ') {
63 *p = '\0';
64 if (p > dst) {
65 p--;
66 }
67 }
68}
69
70/* satellite code character to system ------------------------------------------*/
71static int code2sys(char code) {
72 if (code == 'G' || code == ' ') {
73 return SYS_GPS;
74 }
75 if (code == 'R') {
76 return SYS_GLO;
77 }
78 if (code == 'E') {
79 return SYS_GAL;
80 }
81 if (code == 'J') {
82 return SYS_QZS;
83 }
84 if (code == 'C') {
85 return SYS_CMP;
86 }
87 return SYS_NONE;
88}
89
90/* system to ISB array index ---------------------------------------------------
91 * maps satellite system to index in gsb[NSYS][NFREQ][2] array.
92 * GPS→0, GLO→1, GAL→2, QZS→3, CMP→4
93 *-----------------------------------------------------------------------------*/
94static int sys2isbidx(int sys) {
95 switch (sys) {
96 case SYS_GPS:
97 return NSYSGPS - 1;
98#ifdef ENAGLO
99 case SYS_GLO:
100 return NSYSGPS + NSYSGLO - 1;
101#endif
102#ifdef ENAGAL
103 case SYS_GAL:
104 return NSYSGPS + NSYSGLO + NSYSGAL - 1;
105#endif
106#ifdef ENAQZS
107 case SYS_QZS:
108 return NSYSGPS + NSYSGLO + NSYSGAL + NSYSQZS - 1;
109#endif
110#ifdef ENACMP
111 case SYS_CMP:
112 return NSYSGPS + NSYSGLO + NSYSGAL + NSYSQZS + NSYSCMP - 1;
113#endif
114 }
115 return -1;
116}
117
118/* discard trailing spaces and comments ----------------------------------------*/
119static void chop_isb(char* str) {
120 char* p;
121 if ((p = strchr(str, '#'))) {
122 *p = '\0';
123 }
124 for (p = str + strlen(str) - 1; p >= str && !isgraph((int)*p); p--) {
125 *p = '\0';
126 }
127}
128
129/* add ISB data to navigation data ---------------------------------------------*/
130static int addisbdata(nav_t* nav, const isb_t* data) {
131 isb_t* isb_data;
132
133 if (nav->nimax <= nav->ni) {
134 if (nav->nimax <= 0) {
135 nav->nimax = NINCISB;
136 } else {
137 nav->nimax *= 2;
138 }
139 if (!(isb_data = (isb_t*)realloc(nav->isb, sizeof(isb_t) * nav->nimax))) {
140 trace(NULL, 1, "addisbdata: memalloc error n=%d\n", nav->nimax);
141 free(nav->isb);
142 nav->isb = NULL;
143 nav->ni = nav->nimax = 0;
144 return -1;
145 }
146 nav->isb = isb_data;
147 }
148 nav->isb[nav->ni++] = *data;
149 return 1;
150}
151
152/* read ISB parameters from a single file --------------------------------------*/
153static int readisbf(const char* file, nav_t* nav) {
154 FILE* fp;
155 double bias;
156 char buff[256];
157 int sys, i, s_code, res;
158 char stationname[21] = {0};
159 char stationname0[21] = {0};
160 char stationname_base[21] = {0};
161 char stationname0_base[21] = {0};
162 isb_t data = {0};
163 int nbuf = 0;
164 int freq = 0;
165 char type = '\0';
166 int n = 0;
167 int ifreq = 0;
168 int itype = 0; /* 0:phase, 1:code */
169 int ver = -1;
170
171 trace(NULL, 3, "readisbf: file=%s\n", file);
172
173 if (!(fp = fopen(file, "r"))) {
174 trace(NULL, 2, "isb parameters file open error: %s\n", file);
175 return 0;
176 }
177 while (fgets(buff, sizeof(buff), fp)) {
178 ++n;
179 if (4 > n) {
180 continue;
181 }
182
183 chop_isb(buff);
184 if (4 == n) {
185 if (strcmp(buff, "******************** * * * **********************") == 0) {
186 ver = 0;
187 } else if (strcmp(buff, "******************** ******************** * * * **********************") == 0) {
188 ver = 1;
189 }
190 continue;
191 }
192
193 nbuf = (int)strlen(buff);
194 if (28 > nbuf) {
195 trace(NULL, 2, "isb parameter error: %s (%s:%d)\n", buff, file, n);
196 continue;
197 }
198
199 if (ver == 0) {
200 /* version 0: single receiver format */
201 setstr(stationname, buff, 20);
202 bias = str2num(buff, 27, nbuf - 27);
203 freq = (int)str2num(buff, 23, 1);
204 type = buff[25];
205 sys = code2sys(buff[21]);
206 s_code = sys2isbidx(sys);
207
208 if (' ' != buff[20] || ' ' != buff[22] || ' ' != buff[24] || ' ' != buff[26] ||
209 ('P' != type && 'L' != type) || (1 != freq && 2 != freq && 5 != freq) || -1 == s_code) {
210 trace(NULL, 2, "isb parameter error: %s (%s:%d)\n", buff, file, n);
211 continue;
212 }
213
214 ifreq = (5 == freq) ? 2 : freq - 1;
215 itype = ('L' == type) ? 0 : 1;
216
217 if (stationname[0] != '\0') {
218 strcpy(stationname0, stationname);
219 }
220 if (stationname0[0] != '\0') {
221 res = 0;
222 for (i = 0; i < nav->ni; i++) {
223 if (strcmp(nav->isb[i].sta_name, stationname0) == 0) {
224 nav->isb[i].gsb[s_code][ifreq][itype] = bias * 1E-9 * CLIGHT;
225 res = 1;
226 break;
227 }
228 }
229 if (res == 0) {
230 memset(&data, 0, sizeof(data));
231 strcpy(data.sta_name, stationname0);
232 data.gsb[s_code][ifreq][itype] = bias * 1E-9 * CLIGHT;
233 addisbdata(nav, &data);
234 }
235 }
236 } else if (ver == 1) {
237 /* version 1: rover+base receiver format */
238 setstr(stationname, buff, 20);
239 setstr(stationname_base, buff + 21, 20);
240 bias = str2num(buff, 48, nbuf - 48);
241 freq = (int)str2num(buff, 44, 1);
242 type = buff[46];
243 sys = code2sys(buff[42]);
244 s_code = sys2isbidx(sys);
245
246 if (' ' != buff[20] || ' ' != buff[41] || ' ' != buff[43] || ' ' != buff[45] || ' ' != buff[47] ||
247 ('P' != type && 'L' != type) || (1 != freq && 2 != freq && 5 != freq) || -1 == s_code) {
248 trace(NULL, 2, "isb parameter error: %s (%s:%d)\n", buff, file, n);
249 continue;
250 }
251
252 ifreq = (5 == freq) ? 2 : freq - 1;
253 itype = ('L' == type) ? 0 : 1;
254
255 if (stationname[0] != '\0') {
256 strcpy(stationname0, stationname);
257 stationname0_base[0] = '\0';
258 if (stationname_base[0] != '\0') {
259 strcpy(stationname0_base, stationname_base);
260 }
261 } else if (stationname0[0] != '\0') {
262 if (stationname_base[0] != '\0') {
263 strcpy(stationname0_base, stationname_base);
264 }
265 }
266
267 if (stationname0[0] != '\0') {
268 res = 0;
269 for (i = 0; i < nav->ni; i++) {
270 if (strcmp(nav->isb[i].sta_name, stationname0) == 0 &&
271 strcmp(nav->isb[i].sta_name_base, stationname0_base) == 0) {
272 nav->isb[i].gsb[s_code][ifreq][itype] = bias * 1E-9 * CLIGHT;
273 res = 1;
274 break;
275 }
276 }
277 if (res == 0) {
278 memset(&data, 0, sizeof(data));
279 strcpy(data.sta_name, stationname0);
280 strcpy(data.sta_name_base, stationname0_base);
281 data.gsb[s_code][ifreq][itype] = bias * 1E-9 * CLIGHT;
282 addisbdata(nav, &data);
283
284 /* add reverse entry */
285 if (stationname0_base[0] != '\0') {
286 memset(&data, 0, sizeof(data));
287 strcpy(data.sta_name_base, stationname0);
288 strcpy(data.sta_name, stationname0_base);
289 data.gsb[s_code][ifreq][itype] = -bias * 1E-9 * CLIGHT;
290 addisbdata(nav, &data);
291 }
292 }
293 }
294 }
295 }
296 fclose(fp);
297
298 trace(NULL, 3, "readisbf: ni=%d\n", nav->ni);
299 return 1;
300}
301
302/* read ISB parameters ---------------------------------------------------------
303 * read inter-system bias (ISB) parameters
304 * args : char *file I ISB parameters file (wild-card * expanded)
305 * nav_t *nav IO navigation data
306 * return : status (1:ok,0:error)
307 *-----------------------------------------------------------------------------*/
308extern int readisb(const char* file, nav_t* nav) {
309 int i, n;
310 char* efiles[MAXEXFILE] = {0};
311
312 trace(NULL, 3, "readisb: file=%s\n", file);
313
314 for (i = 0; i < MAXEXFILE; i++) {
315 if (!(efiles[i] = (char*)malloc(1024))) {
316 for (i--; i >= 0; i--) {
317 free(efiles[i]);
318 }
319 return 0;
320 }
321 }
322 nav->ni = nav->nimax = 0;
323
324 n = expath(file, efiles, MAXEXFILE);
325
326 for (i = 0; i < n; i++) {
327 readisbf(efiles[i], nav);
328 }
329 for (i = 0; i < MAXEXFILE; i++) {
330 free(efiles[i]);
331 }
332
333 trace(NULL, 3, "readisb: total ni=%d\n", nav->ni);
334 return 1;
335}
336
337/* set ISB corrections for rover and reference stations ------------------------
338 * match receiver types to ISB table and populate sta_t.isb arrays
339 *-----------------------------------------------------------------------------*/
340extern void setisb(const nav_t* nav, const char* rectype0, const char* rectype1, sta_t* sta0, sta_t* sta1) {
341 int i, j, k, m;
342 int r = 0;
343 isb_t* pisb[2] = {NULL, NULL};
344
345 trace(NULL, 3, "setisb: rover=%s ref=%s ni=%d\n", rectype0 ? rectype0 : "(null)", rectype1 ? rectype1 : "(null)",
346 nav->ni);
347
348 /* clear ISB arrays */
349 if (sta0) {
350 for (i = 0; i < NSYS; ++i) {
351 for (j = 0; j < NFREQ; ++j) {
352 for (k = 0; k < 2; ++k) {
353 sta0->isb[i][j][k] = 0.0;
354 }
355 }
356 }
357 }
358 if (sta1) {
359 for (i = 0; i < NSYS; ++i) {
360 for (j = 0; j < NFREQ; ++j) {
361 for (k = 0; k < 2; ++k) {
362 sta1->isb[i][j][k] = 0.0;
363 }
364 }
365 }
366 }
367
368 if (!rectype0) {
369 return;
370 }
371
372 for (m = 0; m < nav->ni; ++m) {
373 /* exact match: rover-base pair */
374 if (!strcmp(rectype0, nav->isb[m].sta_name)) {
375 if (rectype1 && !strcmp(rectype1, nav->isb[m].sta_name_base)) {
376 if (sta0) {
377 for (i = 0; i < NSYS; ++i) {
378 for (j = 0; j < NFREQ; ++j) {
379 for (k = 0; k < 2; ++k) {
380 sta0->isb[i][j][k] = nav->isb[m].gsb[i][j][k];
381 }
382 }
383 }
384 }
385 r = 1;
386 break;
387 }
388 }
389 /* reverse match: base-rover pair */
390 if (rectype1 && !strcmp(rectype1, nav->isb[m].sta_name)) {
391 if (!strcmp(rectype0, nav->isb[m].sta_name_base)) {
392 if (sta0) {
393 for (i = 0; i < NSYS; ++i) {
394 for (j = 0; j < NFREQ; ++j) {
395 for (k = 0; k < 2; ++k) {
396 sta0->isb[i][j][k] = -nav->isb[m].gsb[i][j][k];
397 }
398 }
399 }
400 }
401 r = 1;
402 break;
403 }
404 }
405 /* fallback: single receiver entries (no base) */
406 if (r == 0) {
407 if (!strcmp(rectype0, nav->isb[m].sta_name) && !strcmp(nav->isb[m].sta_name_base, "")) {
408 pisb[0] = &nav->isb[m];
409 } else if (rectype1 && !strcmp(rectype1, nav->isb[m].sta_name) && !strcmp(nav->isb[m].sta_name_base, "")) {
410 pisb[1] = &nav->isb[m];
411 }
412 }
413 }
414 if (r == 0) {
415 if (pisb[0] && sta0) {
416 for (i = 0; i < NSYS; ++i) {
417 for (j = 0; j < NFREQ; ++j) {
418 for (k = 0; k < 2; ++k) {
419 sta0->isb[i][j][k] = pisb[0]->gsb[i][j][k];
420 }
421 }
422 }
423 }
424 if (pisb[1] && sta1) {
425 for (i = 0; i < NSYS; ++i) {
426 for (j = 0; j < NFREQ; ++j) {
427 for (k = 0; k < 2; ++k) {
428 sta1->isb[i][j][k] = pisb[1]->gsb[i][j][k];
429 }
430 }
431 }
432 }
433 }
434
435 /* log ISB values */
436 if (sta0) {
437 for (i = 0; i < NSYS; ++i) {
438 for (j = 0; j < NFREQ; ++j) {
439 if (sta0->isb[i][j][0] != 0.0 || sta0->isb[i][j][1] != 0.0) {
440 trace(NULL, 3, "setisb: sys=%d freq=%d L=%.6f P=%.6f m\n", i, j, sta0->isb[i][j][0],
441 sta0->isb[i][j][1]);
442 }
443 }
444 }
445 }
446}
447
448/* get ISB correction for a satellite system -----------------------------------
449 * return ISB correction values for a given satellite system
450 *-----------------------------------------------------------------------------*/
451extern void chk_isb(int sysno, const prcopt_t* opt, const sta_t* sta, double y[NFREQ][2]) {
452 int i, j;
453 int isys = sys2isbidx(sysno);
454
455 for (i = 0; i < NFREQ; ++i) {
456 for (j = 0; j < 2; ++j) {
457 y[i][j] = 0.0;
458 }
459 }
460
461 if (isys < 0) {
462 return;
463 }
464 if (opt->isb != ISBOPT_TABLE) {
465 return;
466 }
467
468 for (i = 0; i < NFREQ; ++i) {
469 for (j = 0; j < 2; ++j) {
470 y[i][j] = sta->isb[isys][i][j];
471 }
472 }
473}
474
475/* trim trailing whitespace ----------------------------------------------------*/
476static void trim_str(char* str) {
477 char* p = str + strlen(str) - 1;
478 while (p >= str && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) {
479 *p-- = '\0';
480 }
481}
482
483/* read L2C 1/4 cycle phase shift table ----------------------------------------
484 * read L2C phase shift correction table from file
485 * args : char *file I L2C phase shift table file path
486 * nav_t *nav IO navigation data (sfts populated)
487 * return : status (0:ok, -1:error)
488 *-----------------------------------------------------------------------------*/
489extern int readL2C(const char* file, nav_t* nav) {
490 FILE* fp;
491 char buff[1024], ori[33] = "Quarter-Cycle Phase Shifts Table";
492 int countheader = 1, nod = 0;
493 int lenBuf = 0;
494
495 trace(NULL, 3, "readL2C: file=%s\n", file);
496
497 nav->sfts.n = 0;
498 memset(nav->sfts.rectyp, 0, sizeof(nav->sfts.rectyp));
499
500 if ((fp = fopen(file, "r")) == NULL) {
501 trace(NULL, 1, "l2c file open error: %s\n", file);
502 return -1;
503 }
504
505 while (fgets(buff, sizeof(buff), fp)) {
506 if (countheader == 1) {
507 if (strncmp(buff, ori, 32) != 0) {
508 trace(NULL, 1, "l2c file title error: %s\n", file);
509 fclose(fp);
510 return -1;
511 }
512 }
513 if (countheader > 4) {
514 lenBuf = (int)strlen(buff);
515 if (22 < lenBuf && 45 > lenBuf) {
516 strncpy(nav->sfts.rectyp[nod], buff, 20);
517 trim_str(nav->sfts.rectyp[nod]);
518 nav->sfts.bias[nod] = str2num(buff, 21, lenBuf - 21);
519 } else if (23 > lenBuf && buff[0] != '\n') {
520 strncpy(nav->sfts.rectyp[nod], buff, lenBuf - 1);
521 nav->sfts.bias[nod] = PHASE_CYCLE;
522 } else {
523 trace(NULL, 1, "l2c file format error: %s\n", file);
524 fclose(fp);
525 return -1;
526 }
527 nod++;
528 nav->sfts.n = nod;
529 if (nod >= MAXRECTYP) {
530 trace(NULL, 1, "l2c file size error: %s\n", file);
531 fclose(fp);
532 return -1;
533 }
534 }
535 countheader++;
536 }
537 fclose(fp);
538 trace(NULL, 3, "readL2C: n=%d\n", nav->sfts.n);
539 if (nav->sfts.n < 1) {
540 trace(NULL, 1, "no l2c data error: %s\n", file);
541 }
542 return 0;
543}
544
545/* check if observation code is L2C --------------------------------------------*/
546extern int isL2C(int code) { return (code == CODE_L2S || code == CODE_L2L || code == CODE_L2X) ? 1 : 0; }
CLAS (QZSS L6D) CSSR decoder and grid correction type definitions.
static void trim_str(char *str)
static int code2sys(char code)
int readL2C(const char *file, nav_t *nav)
Read L2C 1/4 cycle phase shift table from file.
static void setstr(char *dst, const char *src, int n)
static void chop_isb(char *str)
void chk_isb(int sysno, const prcopt_t *opt, const sta_t *sta, double y[5][2])
Get ISB correction values for a satellite system.
static int sys2isbidx(int sys)
#define NINCISB
static int readisbf(const char *file, nav_t *nav)
int readisb(const char *file, nav_t *nav)
Read ISB correction table from file.
int isL2C(int code)
Check if observation code is L2C.
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.
static int addisbdata(nav_t *nav, const isb_t *data)
MRTKLIB Constants — Physical, navigation, and system constants.
#define CLIGHT
Definition mrtk_coords.c:41
#define SYS_GPS
Definition mrtk_eph.c:65
#define SYS_NONE
Definition mrtk_eph.c:64
#define SYS_QZS
Definition mrtk_eph.c:69
#define SYS_CMP
Definition mrtk_eph.c:70
#define SYS_GAL
Definition mrtk_eph.c:68
#define SYS_GLO
Definition mrtk_eph.c:67
struct nav_s nav_t
Definition mrtk_eph.h:40
MRTKLIB Foundation — Common types, standard includes, and system constants (MAXSAT,...
#define NSYS
#define CODE_L2X
#define NSYSGLO
#define NSYSCMP
#define NSYSGPS
#define CODE_L2S
#define NSYSQZS
#define CODE_L2L
#define NSYSGAL
#define MAXEXFILE
MRTKLIB Navigation Module — Navigation data types and satellite/nav utility functions.
#define ISBOPT_TABLE
Definition mrtk_nav.h:349
#define PHASE_CYCLE
Definition mrtk_nav.h:351
#define MAXRECTYP
Definition mrtk_nav.h:350
MRTKLIB Observation Module — Observation data types and utility functions.
MRTKLIB Options Module — Processing and solution option types.
int expath(const char *path, char *paths[], int nmax)
Expand file path with wild-card (*) in file.
Definition mrtk_sys.c:96
double str2num(const char *s, int i, int n)
Convert substring in string to number.
Definition mrtk_sys.c:60
MRTKLIB System Module — OS/filesystem utility functions.
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.
char sta_name[20]
Definition mrtk_nav.h:354
double gsb[NSYS][5][2]
Definition mrtk_nav.h:356
char sta_name_base[20]
Definition mrtk_nav.h:355
int ni
Definition mrtk_nav.h:449
isb_t * isb
Definition mrtk_nav.h:448
sft_t sfts
Definition mrtk_nav.h:450
int nimax
Definition mrtk_nav.h:449
int isb
Definition mrtk_opt.h:260
char rectyp[100][MAXANT]
Definition mrtk_nav.h:361
int n
Definition mrtk_nav.h:360
double bias[100]
Definition mrtk_nav.h:362
double isb[NSYS][5][2]
Definition mrtk_nav.h:385
#define malloc(x)
Definition toml.c:52
#define free(x)
Definition toml.c:53