MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_sbas.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_sbas.c : SBAS message decoding and correction 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/**
17 * @file mrtk_sbas.c
18 * @brief MRTKLIB SBAS Module — SBAS message decoding and corrections.
19 *
20 * option : -DRRCENA enable rrc correction
21 *
22 * references :
23 * [1] RTCA/DO-229C, Minimum operational performanc standards for global
24 * positioning system/wide area augmentation system airborne equipment,
25 * RTCA inc, November 28, 2001
26 * [2] IS-QZSS v.1.1, Quasi-Zenith Satellite System Navigation Service
27 * Interface Specification for QZSS, Japan Aerospace Exploration Agency,
28 * July 31, 2009
29 */
30#include "mrtklib/mrtk_sbas.h"
31
32#include <math.h>
33#include <stdlib.h>
34#include <string.h>
35
36#include "mrtklib/mrtk_atmos.h"
37#include "mrtklib/mrtk_bits.h"
38#include "mrtklib/mrtk_sys.h"
39#include "mrtklib/mrtk_trace.h"
40
41/*--- local constants (duplicated to avoid rtklib.h dependency) -------------*/
42#define SYS_NONE 0x00
43#define SYS_GPS 0x01
44#define SYS_SBS 0x02
45#define SYS_GLO 0x04
46#define SYS_QZS 0x10
47
48static const double PI = 3.1415926535897932;
49static const double D2R = 3.1415926535897932 / 180.0;
50static const double R2D = 180.0 / 3.1415926535897932;
51static const double CLIGHT = 299792458.0;
52static const double RE_WGS84 = 6378137.0;
53
54#define P2_11 4.882812500000000E-04 /* 2^-11 */
55#define P2_31 4.656612873077393E-10 /* 2^-31 */
56#define P2_39 1.818989403545856E-12 /* 2^-39 */
57#define MAXSBSAGEF 30.0 /* max age of SBAS fast correction (s) */
58#define MAXSBSAGEL 1800.0 /* max age of SBAS long term corr (s) */
59
60/*--- forward declarations for legacy functions resolved at link time -------*/
61
62/* constants -----------------------------------------------------------------*/
63
64#define WEEKOFFSET 1024 /* gps week offset for NovAtel OEM-3 */
65
66/* sbas igp definition -------------------------------------------------------*/
67static const int16_t x1[] = {-75, -65, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0,
68 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 65, 75, 85},
69 x2[] = {-55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0,
70 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55},
71 x3[] = {-75, -65, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0,
72 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 65, 75},
73 x4[] = {-85, -75, -65, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5,
74 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 65, 75},
75 x5[] = {-180, -175, -170, -165, -160, -155, -150, -145, -140, -135, -130, -125, -120, -115, -110,
76 -105, -100, -95, -90, -85, -80, -75, -70, -65, -60, -55, -50, -45, -40, -35,
77 -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40,
78 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115,
79 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170, 175},
80 x6[] = {-180, -170, -160, -150, -140, -130, -120, -110, -100, -90, -80, -70,
81 -60, -50, -40, -30, -20, -10, 0, 10, 20, 30, 40, 50,
82 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170},
83 x7[] = {-180, -150, -120, -90, -60, -30, 0, 30, 60, 90, 120, 150},
84 x8[] = {-170, -140, -110, -80, -50, -20, 10, 40, 70, 100, 130, 160};
85
86const sbsigpband_t igpband1[9][8] = {/* band 0-8 */
87 {{-180, x1, 1, 28},
88 {-175, x2, 29, 51},
89 {-170, x3, 52, 78},
90 {-165, x2, 79, 101},
91 {-160, x3, 102, 128},
92 {-155, x2, 129, 151},
93 {-150, x3, 152, 178},
94 {-145, x2, 179, 201}},
95 {{-140, x4, 1, 28},
96 {-135, x2, 29, 51},
97 {-130, x3, 52, 78},
98 {-125, x2, 79, 101},
99 {-120, x3, 102, 128},
100 {-115, x2, 129, 151},
101 {-110, x3, 152, 178},
102 {-105, x2, 179, 201}},
103 {{-100, x3, 1, 27},
104 {-95, x2, 28, 50},
105 {-90, x1, 51, 78},
106 {-85, x2, 79, 101},
107 {-80, x3, 102, 128},
108 {-75, x2, 129, 151},
109 {-70, x3, 152, 178},
110 {-65, x2, 179, 201}},
111 {{-60, x3, 1, 27},
112 {-55, x2, 28, 50},
113 {-50, x4, 51, 78},
114 {-45, x2, 79, 101},
115 {-40, x3, 102, 128},
116 {-35, x2, 129, 151},
117 {-30, x3, 152, 178},
118 {-25, x2, 179, 201}},
119 {{-20, x3, 1, 27},
120 {-15, x2, 28, 50},
121 {-10, x3, 51, 77},
122 {-5, x2, 78, 100},
123 {0, x1, 101, 128},
124 {5, x2, 129, 151},
125 {10, x3, 152, 178},
126 {15, x2, 179, 201}},
127 {{20, x3, 1, 27},
128 {25, x2, 28, 50},
129 {30, x3, 51, 77},
130 {35, x2, 78, 100},
131 {40, x4, 101, 128},
132 {45, x2, 129, 151},
133 {50, x3, 152, 178},
134 {55, x2, 179, 201}},
135 {{60, x3, 1, 27},
136 {65, x2, 28, 50},
137 {70, x3, 51, 77},
138 {75, x2, 78, 100},
139 {80, x3, 101, 127},
140 {85, x2, 128, 150},
141 {90, x1, 151, 178},
142 {95, x2, 179, 201}},
143 {{100, x3, 1, 27},
144 {105, x2, 28, 50},
145 {110, x3, 51, 77},
146 {115, x2, 78, 100},
147 {120, x3, 101, 127},
148 {125, x2, 128, 150},
149 {130, x4, 151, 178},
150 {135, x2, 179, 201}},
151 {{140, x3, 1, 27},
152 {145, x2, 28, 50},
153 {150, x3, 51, 77},
154 {155, x2, 78, 100},
155 {160, x3, 101, 127},
156 {165, x2, 128, 150},
157 {170, x3, 151, 177},
158 {175, x2, 178, 200}}};
160 {/* band 9-10 */
161 {{60, x5, 1, 72}, {65, x6, 73, 108}, {70, x6, 109, 144}, {75, x6, 145, 180}, {85, x7, 181, 192}},
162 {{-60, x5, 1, 72}, {-65, x6, 73, 108}, {-70, x6, 109, 144}, {-75, x6, 145, 180}, {-85, x8, 181, 192}}};
163/* extract field from line ---------------------------------------------------*/
164static char* getfield(char* p, int pos) {
165 for (pos--; pos > 0; pos--, p++) {
166 if (!(p = strchr(p, ','))) {
167 return NULL;
168 }
169 }
170 return p;
171}
172/* variance of fast correction (udre=UDRE+1) ---------------------------------*/
173static double varfcorr(int udre) {
174 const double var[14] = {0.052, 0.0924, 0.1444, 0.283, 0.4678, 0.8315, 1.2992,
175 1.8709, 2.5465, 3.326, 5.1968, 20.7870, 230.9661, 2078.695};
176 return 0 < udre && udre <= 14 ? var[udre - 1] : 0.0;
177}
178/* variance of ionosphere correction (give=GIVEI+1) --------------------------*/
179static double varicorr(int give) {
180 const double var[15] = {0.0084, 0.0333, 0.0749, 0.1331, 0.2079, 0.2994, 0.4075, 0.5322,
181 0.6735, 0.8315, 1.1974, 1.8709, 3.326, 20.787, 187.0826};
182 return 0 < give && give <= 15 ? var[give - 1] : 0.0;
183}
184/* fast correction degradation -----------------------------------------------*/
185static double degfcorr(int ai) {
186 const double degf[16] = {0.00000, 0.00005, 0.00009, 0.00012, 0.00015, 0.00020, 0.00030, 0.00045,
187 0.00060, 0.00090, 0.00150, 0.00210, 0.00270, 0.00330, 0.00460, 0.00580};
188 return 0 < ai && ai <= 15 ? degf[ai] : 0.0058;
189}
190/* decode type 1: prn masks --------------------------------------------------*/
191static int decode_sbstype1(const sbsmsg_t* msg, sbssat_t* sbssat) {
192 int i, n, sat;
193
194 trace(NULL, 4, "decode_sbstype1:\n");
195
196 for (i = 1, n = 0; i <= 210 && n < MAXSAT; i++) {
197 if (getbitu(msg->msg, 13 + i, 1)) {
198 if (i <= 37) {
199 sat = satno(SYS_GPS, i); /* 0- 37: gps */
200 } else if (i <= 61) {
201 sat = satno(SYS_GLO, i - 37); /* 38- 61: glonass */
202 } else if (i <= 119) {
203 sat = 0; /* 62-119: future gnss */
204 } else if (i <= 138) {
205 sat = satno(SYS_SBS, i); /* 120-138: geo/waas */
206 } else if (i <= 182) {
207 sat = 0; /* 139-182: reserved */
208 } else if (i <= 192) {
209 sat = satno(SYS_SBS, i + 10); /* 183-192: qzss ref [2] */
210 } else if (i <= 202) {
211 sat = satno(SYS_QZS, i); /* 193-202: qzss ref [2] */
212 } else {
213 sat = 0; /* 203- : reserved */
214 }
215 sbssat->sat[n++].sat = sat;
216 }
217 }
218 sbssat->iodp = getbitu(msg->msg, 224, 2);
219 sbssat->nsat = n;
220
221 trace(NULL, 5, "decode_sbstype1: nprn=%d iodp=%d\n", n, sbssat->iodp);
222 return 1;
223}
224/* decode type 2-5,0: fast corrections ---------------------------------------*/
225static int decode_sbstype2(const sbsmsg_t* msg, sbssat_t* sbssat) {
226 int i, j, iodf, type, udre;
227 double prc, dt;
228 gtime_t t0;
229
230 trace(NULL, 4, "decode_sbstype2:\n");
231
232 if (sbssat->iodp != (int)getbitu(msg->msg, 16, 2)) {
233 return 0;
234 }
235
236 type = getbitu(msg->msg, 8, 6);
237 iodf = getbitu(msg->msg, 14, 2);
238
239 for (i = 0; i < 13; i++) {
240 if ((j = 13 * ((type == 0 ? 2 : type) - 2) + i) >= sbssat->nsat) {
241 break;
242 }
243 udre = getbitu(msg->msg, 174 + 4 * i, 4);
244 t0 = sbssat->sat[j].fcorr.t0;
245 prc = sbssat->sat[j].fcorr.prc;
246 sbssat->sat[j].fcorr.t0 = gpst2time(msg->week, msg->tow);
247 sbssat->sat[j].fcorr.prc = getbits(msg->msg, 18 + i * 12, 12) * 0.125f;
248 sbssat->sat[j].fcorr.udre = udre + 1;
249 dt = timediff(sbssat->sat[j].fcorr.t0, t0);
250 if (t0.time == 0 || dt <= 0.0 || 18.0 < dt || sbssat->sat[j].fcorr.ai == 0) {
251 sbssat->sat[j].fcorr.rrc = 0.0;
252 sbssat->sat[j].fcorr.dt = 0.0;
253 } else {
254 sbssat->sat[j].fcorr.rrc = (sbssat->sat[j].fcorr.prc - prc) / dt;
255 sbssat->sat[j].fcorr.dt = dt;
256 }
257 sbssat->sat[j].fcorr.iodf = iodf;
258 }
259 trace(NULL, 5, "decode_sbstype2: type=%d iodf=%d\n", type, iodf);
260 return 1;
261}
262/* decode type 6: integrity info ---------------------------------------------*/
263static int decode_sbstype6(const sbsmsg_t* msg, sbssat_t* sbssat) {
264 int i, iodf[4], udre;
265
266 trace(NULL, 4, "decode_sbstype6:\n");
267
268 for (i = 0; i < 4; i++) {
269 iodf[i] = getbitu(msg->msg, 14 + i * 2, 2);
270 }
271 for (i = 0; i < sbssat->nsat && i < MAXSAT; i++) {
272 if (sbssat->sat[i].fcorr.iodf != iodf[i / 13]) {
273 continue;
274 }
275 udre = getbitu(msg->msg, 22 + i * 4, 4);
276 sbssat->sat[i].fcorr.udre = udre + 1;
277 }
278 trace(NULL, 5, "decode_sbstype6: iodf=%d %d %d %d\n", iodf[0], iodf[1], iodf[2], iodf[3]);
279 return 1;
280}
281/* decode type 7: fast correction degradation factor -------------------------*/
282static int decode_sbstype7(const sbsmsg_t* msg, sbssat_t* sbssat) {
283 int i;
284
285 trace(NULL, 4, "decode_sbstype7\n");
286
287 if (sbssat->iodp != (int)getbitu(msg->msg, 18, 2)) {
288 return 0;
289 }
290
291 sbssat->tlat = getbitu(msg->msg, 14, 4);
292
293 for (i = 0; i < sbssat->nsat && i < MAXSAT; i++) {
294 sbssat->sat[i].fcorr.ai = getbitu(msg->msg, 22 + i * 4, 4);
295 }
296 return 1;
297}
298/* decode type 9: geo navigation message -------------------------------------*/
299static int decode_sbstype9(const sbsmsg_t* msg, nav_t* nav) {
300 seph_t seph = {0};
301 int i, sat, t;
302
303 trace(NULL, 4, "decode_sbstype9:\n");
304
305 if (!(sat = satno(SYS_SBS, msg->prn))) {
306 trace(NULL, 2, "invalid prn in sbas type 9: prn=%3d\n", msg->prn);
307 return 0;
308 }
309 t = (int)getbitu(msg->msg, 22, 13) * 16 - (int)msg->tow % 86400;
310 if (t <= -43200) {
311 t += 86400;
312 } else if (t > 43200) {
313 t -= 86400;
314 }
315 seph.sat = sat;
316 seph.t0 = gpst2time(msg->week, msg->tow + t);
317 seph.tof = gpst2time(msg->week, msg->tow);
318 seph.sva = getbitu(msg->msg, 35, 4);
319 seph.svh = seph.sva == 15 ? 1 : 0; /* unhealthy if ura==15 */
320
321 seph.pos[0] = getbits(msg->msg, 39, 30) * 0.08;
322 seph.pos[1] = getbits(msg->msg, 69, 30) * 0.08;
323 seph.pos[2] = getbits(msg->msg, 99, 25) * 0.4;
324 seph.vel[0] = getbits(msg->msg, 124, 17) * 0.000625;
325 seph.vel[1] = getbits(msg->msg, 141, 17) * 0.000625;
326 seph.vel[2] = getbits(msg->msg, 158, 18) * 0.004;
327 seph.acc[0] = getbits(msg->msg, 176, 10) * 0.0000125;
328 seph.acc[1] = getbits(msg->msg, 186, 10) * 0.0000125;
329 seph.acc[2] = getbits(msg->msg, 196, 10) * 0.0000625;
330
331 seph.af0 = getbits(msg->msg, 206, 12) * P2_31;
332 seph.af1 = getbits(msg->msg, 218, 8) * P2_39 / 2.0;
333
334 i = msg->prn - MINPRNSBS;
335 if (!nav->seph || fabs(timediff(nav->seph[i].t0, seph.t0)) < 1E-3) { /* not change */
336 return 0;
337 }
338 nav->seph[NSATSBS + i] = nav->seph[i]; /* previous */
339 nav->seph[i] = seph; /* current */
340
341 trace(NULL, 5, "decode_sbstype9: prn=%d\n", msg->prn);
342 return 1;
343}
344/* decode type 18: ionospheric grid point masks ------------------------------*/
345static int decode_sbstype18(const sbsmsg_t* msg, sbsion_t* sbsion) {
346 const sbsigpband_t* p;
347 int i, j, n, m, band = getbitu(msg->msg, 18, 4);
348
349 trace(NULL, 4, "decode_sbstype18:\n");
350
351 if (0 <= band && band <= 8) {
352 p = igpband1[band];
353 m = 8;
354 } else if (9 <= band && band <= 10) {
355 p = igpband2[band - 9];
356 m = 5;
357 } else {
358 return 0;
359 }
360
361 sbsion[band].iodi = (int16_t)getbitu(msg->msg, 22, 2);
362
363 for (i = 1, n = 0; i <= 201; i++) {
364 if (!getbitu(msg->msg, 23 + i, 1)) {
365 continue;
366 }
367 for (j = 0; j < m; j++) {
368 if (i < p[j].bits || p[j].bite < i) {
369 continue;
370 }
371 sbsion[band].igp[n].lat = band <= 8 ? p[j].y[i - p[j].bits] : p[j].x;
372 sbsion[band].igp[n++].lon = band <= 8 ? p[j].x : p[j].y[i - p[j].bits];
373 break;
374 }
375 }
376 sbsion[band].nigp = n;
377
378 trace(NULL, 5, "decode_sbstype18: band=%d nigp=%d\n", band, n);
379 return 1;
380}
381/* decode half long term correction (vel code=0) -----------------------------*/
382static int decode_longcorr0(const sbsmsg_t* msg, int p, sbssat_t* sbssat) {
383 int i, n = getbitu(msg->msg, p, 6);
384
385 trace(NULL, 4, "decode_longcorr0:\n");
386
387 if (n == 0 || n > MAXSAT) {
388 return 0;
389 }
390
391 sbssat->sat[n - 1].lcorr.iode = getbitu(msg->msg, p + 6, 8);
392
393 for (i = 0; i < 3; i++) {
394 sbssat->sat[n - 1].lcorr.dpos[i] = getbits(msg->msg, p + 14 + 9 * i, 9) * 0.125;
395 sbssat->sat[n - 1].lcorr.dvel[i] = 0.0;
396 }
397 sbssat->sat[n - 1].lcorr.daf0 = getbits(msg->msg, p + 41, 10) * P2_31;
398 sbssat->sat[n - 1].lcorr.daf1 = 0.0;
399 sbssat->sat[n - 1].lcorr.t0 = gpst2time(msg->week, msg->tow);
400
401 trace(NULL, 5, "decode_longcorr0:sat=%2d\n", sbssat->sat[n - 1].sat);
402 return 1;
403}
404/* decode half long term correction (vel code=1) -----------------------------*/
405static int decode_longcorr1(const sbsmsg_t* msg, int p, sbssat_t* sbssat) {
406 int i, n = getbitu(msg->msg, p, 6), t;
407
408 trace(NULL, 4, "decode_longcorr1:\n");
409
410 if (n == 0 || n > MAXSAT) {
411 return 0;
412 }
413
414 sbssat->sat[n - 1].lcorr.iode = getbitu(msg->msg, p + 6, 8);
415
416 for (i = 0; i < 3; i++) {
417 sbssat->sat[n - 1].lcorr.dpos[i] = getbits(msg->msg, p + 14 + i * 11, 11) * 0.125;
418 sbssat->sat[n - 1].lcorr.dvel[i] = getbits(msg->msg, p + 58 + i * 8, 8) * P2_11;
419 }
420 sbssat->sat[n - 1].lcorr.daf0 = getbits(msg->msg, p + 47, 11) * P2_31;
421 sbssat->sat[n - 1].lcorr.daf1 = getbits(msg->msg, p + 82, 8) * P2_39;
422 t = (int)getbitu(msg->msg, p + 90, 13) * 16 - (int)msg->tow % 86400;
423 if (t <= -43200) {
424 t += 86400;
425 } else if (t > 43200) {
426 t -= 86400;
427 }
428 sbssat->sat[n - 1].lcorr.t0 = gpst2time(msg->week, msg->tow + t);
429
430 trace(NULL, 5, "decode_longcorr1: sat=%2d\n", sbssat->sat[n - 1].sat);
431 return 1;
432}
433/* decode half long term correction ------------------------------------------*/
434static int decode_longcorrh(const sbsmsg_t* msg, int p, sbssat_t* sbssat) {
435 trace(NULL, 4, "decode_longcorrh:\n");
436
437 if (getbitu(msg->msg, p, 1) == 0) { /* vel code=0 */
438 if (sbssat->iodp == (int)getbitu(msg->msg, p + 103, 2)) {
439 return decode_longcorr0(msg, p + 1, sbssat) && decode_longcorr0(msg, p + 52, sbssat);
440 }
441 } else if (sbssat->iodp == (int)getbitu(msg->msg, p + 104, 2)) {
442 return decode_longcorr1(msg, p + 1, sbssat);
443 }
444 return 0;
445}
446/* decode type 24: mixed fast/long term correction ---------------------------*/
447static int decode_sbstype24(const sbsmsg_t* msg, sbssat_t* sbssat) {
448 int i, j, iodf, blk, udre;
449
450 trace(NULL, 4, "decode_sbstype24:\n");
451
452 if (sbssat->iodp != (int)getbitu(msg->msg, 110, 2)) {
453 return 0; /* check IODP */
454 }
455
456 blk = getbitu(msg->msg, 112, 2);
457 iodf = getbitu(msg->msg, 114, 2);
458
459 for (i = 0; i < 6; i++) {
460 if ((j = 13 * blk + i) >= sbssat->nsat) {
461 break;
462 }
463 udre = getbitu(msg->msg, 86 + 4 * i, 4);
464
465 sbssat->sat[j].fcorr.t0 = gpst2time(msg->week, msg->tow);
466 sbssat->sat[j].fcorr.prc = getbits(msg->msg, 14 + i * 12, 12) * 0.125f;
467 sbssat->sat[j].fcorr.udre = udre + 1;
468 sbssat->sat[j].fcorr.iodf = iodf;
469 }
470 return decode_longcorrh(msg, 120, sbssat);
471}
472/* decode type 25: long term satellite error correction ----------------------*/
473static int decode_sbstype25(const sbsmsg_t* msg, sbssat_t* sbssat) {
474 trace(NULL, 4, "decode_sbstype25:\n");
475
476 return decode_longcorrh(msg, 14, sbssat) && decode_longcorrh(msg, 120, sbssat);
477}
478/* decode type 26: ionospheric delay corrections -----------------------------*/
479static int decode_sbstype26(const sbsmsg_t* msg, sbsion_t* sbsion) {
480 int i, j, block, delay, give, band = getbitu(msg->msg, 14, 4);
481
482 trace(NULL, 4, "decode_sbstype26:\n");
483
484 if (band > MAXBAND || sbsion[band].iodi != (int)getbitu(msg->msg, 217, 2)) {
485 return 0;
486 }
487
488 block = getbitu(msg->msg, 18, 4);
489
490 for (i = 0; i < 15; i++) {
491 if ((j = block * 15 + i) >= sbsion[band].nigp) {
492 continue;
493 }
494 give = getbitu(msg->msg, 22 + i * 13 + 9, 4);
495
496 delay = getbitu(msg->msg, 22 + i * 13, 9);
497 sbsion[band].igp[j].t0 = gpst2time(msg->week, msg->tow);
498 sbsion[band].igp[j].delay = delay == 0x1FF ? 0.0f : delay * 0.125f;
499 sbsion[band].igp[j].give = give + 1;
500
501 if (sbsion[band].igp[j].give >= 16) {
502 sbsion[band].igp[j].give = 0;
503 }
504 }
505 trace(NULL, 5, "decode_sbstype26: band=%d block=%d\n", band, block);
506 return 1;
507}
508/* update sbas corrections -----------------------------------------------------
509 * update sbas correction parameters in navigation data with a sbas message
510 * args : sbsmg_t *msg I sbas message
511 * nav_t *nav IO navigation data
512 * return : message type (-1: error or not supported type)
513 * notes : nav->seph must point to seph[NSATSBS*2] (array of seph_t)
514 * seph[prn-MINPRNSBS+1] : sat prn current epehmeris
515 * seph[prn-MINPRNSBS+1+MAXPRNSBS]: sat prn previous epehmeris
516 *-----------------------------------------------------------------------------*/
517int sbsupdatecorr(const sbsmsg_t* msg, nav_t* nav) {
518 int type = getbitu(msg->msg, 8, 6), stat = -1;
519
520 trace(NULL, 3, "sbsupdatecorr: type=%d\n", type);
521
522 if (msg->week == 0) {
523 return -1;
524 }
525
526 switch (type) {
527 case 0:
528 stat = decode_sbstype2(msg, &nav->sbssat);
529 break;
530 case 1:
531 stat = decode_sbstype1(msg, &nav->sbssat);
532 break;
533 case 2:
534 case 3:
535 case 4:
536 case 5:
537 stat = decode_sbstype2(msg, &nav->sbssat);
538 break;
539 case 6:
540 stat = decode_sbstype6(msg, &nav->sbssat);
541 break;
542 case 7:
543 stat = decode_sbstype7(msg, &nav->sbssat);
544 break;
545 case 9:
546 stat = decode_sbstype9(msg, nav);
547 break;
548 case 18:
549 stat = decode_sbstype18(msg, nav->sbsion);
550 break;
551 case 24:
552 stat = decode_sbstype24(msg, &nav->sbssat);
553 break;
554 case 25:
555 stat = decode_sbstype25(msg, &nav->sbssat);
556 break;
557 case 26:
558 stat = decode_sbstype26(msg, nav->sbsion);
559 break;
560 case 63:
561 break; /* null message */
562
563 /*default: trace(NULL,2,"unsupported sbas message: type=%d\n",type); break;*/
564 }
565 return stat ? type : -1;
566}
567/* read sbas log file --------------------------------------------------------*/
568static void readmsgs(const char* file, int sel, gtime_t ts, gtime_t te, sbs_t* sbs) {
569 sbsmsg_t* sbs_msgs;
570 int i, week, prn, ch, msg;
571 uint32_t b;
572 double tow, ep[6] = {0};
573 char buff[256], *p;
574 gtime_t time;
575 FILE* fp;
576
577 trace(NULL, 3, "readmsgs: file=%s sel=%d\n", file, sel);
578
579 if (!(fp = fopen(file, "r"))) {
580 trace(NULL, 2, "sbas message file open error: %s\n", file);
581 return;
582 }
583 while (fgets(buff, sizeof(buff), fp)) {
584 if (sscanf(buff, "%d %lf %d", &week, &tow, &prn) == 3 && (p = strstr(buff, ": "))) {
585 p += 2; /* rtklib form */
586 } else if (sscanf(buff, "%d %lf %lf %lf %lf %lf %lf %d", &prn, ep, ep + 1, ep + 2, ep + 3, ep + 4, ep + 5,
587 &msg) == 8) {
588 /* ems (EGNOS Message Service) form */
589 ep[0] += ep[0] < 70.0 ? 2000.0 : 1900.0;
590 tow = time2gpst(epoch2time(ep), &week);
591 p = buff + (msg >= 10 ? 25 : 24);
592 } else if (!strncmp(buff, "#RAWWAASFRAMEA", 14)) { /* NovAtel OEM4/V */
593 if (!(p = getfield(buff, 6))) {
594 continue;
595 }
596 if (sscanf(p, "%d,%lf", &week, &tow) < 2) {
597 continue;
598 }
599 if (!(p = strchr(++p, ';'))) {
600 continue;
601 }
602 if (sscanf(++p, "%d,%d", &ch, &prn) < 2) {
603 continue;
604 }
605 if (!(p = getfield(p, 4))) {
606 continue;
607 }
608 } else if (!strncmp(buff, "$FRMA", 5)) { /* NovAtel OEM3 */
609 if (!(p = getfield(buff, 2))) {
610 continue;
611 }
612 if (sscanf(p, "%d,%lf,%d", &week, &tow, &prn) < 3) {
613 continue;
614 }
615 if (!(p = getfield(p, 6))) {
616 continue;
617 }
618 if (week < WEEKOFFSET) {
619 week += WEEKOFFSET;
620 }
621 } else {
622 continue;
623 }
624
625 if (sel != 0 && sel != prn) {
626 continue;
627 }
628
629 time = gpst2time(week, tow);
630
631 if (!screent(time, ts, te, 0.0)) {
632 continue;
633 }
634
635 if (sbs->n >= sbs->nmax) {
636 sbs->nmax = sbs->nmax == 0 ? 1024 : sbs->nmax * 2;
637 if (!(sbs_msgs = (sbsmsg_t*)realloc(sbs->msgs, sbs->nmax * sizeof(sbsmsg_t)))) {
638 trace(NULL, 1, "readsbsmsg malloc error: nmax=%d\n", sbs->nmax);
639 free(sbs->msgs);
640 sbs->msgs = NULL;
641 sbs->n = sbs->nmax = 0;
642 return;
643 }
644 sbs->msgs = sbs_msgs;
645 }
646 sbs->msgs[sbs->n].week = week;
647 sbs->msgs[sbs->n].tow = (int)(tow + 0.5);
648 sbs->msgs[sbs->n].prn = prn;
649 for (i = 0; i < 29; i++) {
650 sbs->msgs[sbs->n].msg[i] = 0;
651 }
652 for (i = 0; *(p - 1) && *p && i < 29; p += 2, i++) {
653 if (sscanf(p, "%2X", &b) == 1) {
654 sbs->msgs[sbs->n].msg[i] = (uint8_t)b;
655 }
656 }
657 sbs->msgs[sbs->n++].msg[28] &= 0xC0;
658 }
659 fclose(fp);
660}
661/* compare sbas messages -----------------------------------------------------*/
662static int cmpmsgs(const void* p1, const void* p2) {
663 sbsmsg_t *q1 = (sbsmsg_t*)p1, *q2 = (sbsmsg_t*)p2;
664 return q1->week != q2->week ? q1->week - q2->week
665 : (q1->tow < q2->tow ? -1 : (q1->tow > q2->tow ? 1 : q1->prn - q2->prn));
666}
667/* read sbas message file ------------------------------------------------------
668 * read sbas message file
669 * args : char *file I sbas message file (wind-card * is expanded)
670 * int sel I sbas satellite prn number selection (0:all)
671 * (gtime_t ts I start time)
672 * (gtime_t te I end time )
673 * sbs_t *sbs IO sbas messages
674 * return : number of sbas messages
675 * notes : sbas message are appended and sorted. before calling the funciton,
676 * sbs->n, sbs->nmax and sbs->msgs must be set properly. (initially
677 * sbs->n=sbs->nmax=0, sbs->msgs=NULL)
678 * only the following file extentions after wild card expanded are valid
679 * to read. others are skipped
680 * .sbs, .SBS, .ems, .EMS
681 *-----------------------------------------------------------------------------*/
682int sbsreadmsgt(const char* file, int sel, gtime_t ts, gtime_t te, sbs_t* sbs) {
683 char *efiles[MAXEXFILE] = {0}, *ext;
684 int i, n;
685
686 trace(NULL, 3, "sbsreadmsgt: file=%s sel=%d\n", file, sel);
687
688 for (i = 0; i < MAXEXFILE; i++) {
689 if (!(efiles[i] = (char*)malloc(1024))) {
690 for (i--; i >= 0; i--) {
691 free(efiles[i]);
692 }
693 return 0;
694 }
695 }
696 /* expand wild card in file path */
697 n = expath(file, efiles, MAXEXFILE);
698
699 for (i = 0; i < n; i++) {
700 if (!(ext = strrchr(efiles[i], '.'))) {
701 continue;
702 }
703 if (strcmp(ext, ".sbs") && strcmp(ext, ".SBS") && strcmp(ext, ".ems") && strcmp(ext, ".EMS")) {
704 continue;
705 }
706
707 readmsgs(efiles[i], sel, ts, te, sbs);
708 }
709 for (i = 0; i < MAXEXFILE; i++) {
710 free(efiles[i]);
711 }
712
713 /* sort messages */
714 if (sbs->n > 0) {
715 qsort(sbs->msgs, sbs->n, sizeof(sbsmsg_t), cmpmsgs);
716 }
717 return sbs->n;
718}
719int sbsreadmsg(const char* file, int sel, sbs_t* sbs) {
720 gtime_t ts = {0}, te = {0};
721
722 trace(NULL, 3, "sbsreadmsg: file=%s sel=%d\n", file, sel);
723
724 return sbsreadmsgt(file, sel, ts, te, sbs);
725}
726/* output sbas messages --------------------------------------------------------
727 * output sbas message record to output file in rtklib sbas log format
728 * args : FILE *fp I output file pointer
729 * sbsmsg_t *sbsmsg I sbas messages
730 * return : none
731 *-----------------------------------------------------------------------------*/
732void sbsoutmsg(FILE* fp, sbsmsg_t* sbsmsg) {
733 int i, prn = sbsmsg->prn, type = sbsmsg->msg[1] >> 2;
734
735 trace(NULL, 4, "sbsoutmsg:\n");
736
737 fprintf(fp, "%4d %6d %3d %2d : ", sbsmsg->week, sbsmsg->tow, prn, type);
738 for (i = 0; i < 29; i++) {
739 fprintf(fp, "%02X", sbsmsg->msg[i]);
740 }
741 fprintf(fp, "\n");
742}
743/* search igps ---------------------------------------------------------------*/
744static void searchigp(gtime_t time, const double* pos, const sbsion_t* ion, const sbsigp_t** igp, double* x,
745 double* y) {
746 int i, latp[2], lonp[4];
747 double lat = pos[0] * R2D, lon = pos[1] * R2D;
748 const sbsigp_t* p;
749
750 trace(NULL, 4, "searchigp: pos=%.3f %.3f\n", pos[0] * R2D, pos[1] * R2D);
751
752 if (lon >= 180.0) {
753 lon -= 360.0;
754 }
755 if (-55.0 <= lat && lat < 55.0) {
756 latp[0] = (int)floor(lat / 5.0) * 5;
757 latp[1] = latp[0] + 5;
758 lonp[0] = lonp[1] = (int)floor(lon / 5.0) * 5;
759 lonp[2] = lonp[3] = lonp[0] + 5;
760 *x = (lon - lonp[0]) / 5.0;
761 *y = (lat - latp[0]) / 5.0;
762 } else {
763 latp[0] = (int)floor((lat - 5.0) / 10.0) * 10 + 5;
764 latp[1] = latp[0] + 10;
765 lonp[0] = lonp[1] = (int)floor(lon / 10.0) * 10;
766 lonp[2] = lonp[3] = lonp[0] + 10;
767 *x = (lon - lonp[0]) / 10.0;
768 *y = (lat - latp[0]) / 10.0;
769 if (75.0 <= lat && lat < 85.0) {
770 lonp[1] = (int)floor(lon / 90.0) * 90;
771 lonp[3] = lonp[1] + 90;
772 } else if (-85.0 <= lat && lat < -75.0) {
773 lonp[0] = (int)floor((lon - 50.0) / 90.0) * 90 + 40;
774 lonp[2] = lonp[0] + 90;
775 } else if (lat >= 85.0) {
776 for (i = 0; i < 4; i++) {
777 lonp[i] = (int)floor(lon / 90.0) * 90;
778 }
779 } else if (lat < -85.0) {
780 for (i = 0; i < 4; i++) {
781 lonp[i] = (int)floor((lon - 50.0) / 90.0) * 90 + 40;
782 }
783 }
784 }
785 for (i = 0; i < 4; i++) {
786 if (lonp[i] == 180) {
787 lonp[i] = -180;
788 }
789 }
790 for (i = 0; i <= MAXBAND; i++) {
791 for (p = ion[i].igp; p < ion[i].igp + ion[i].nigp; p++) {
792 if (p->t0.time == 0) {
793 continue;
794 }
795 if (p->lat == latp[0] && p->lon == lonp[0] && p->give > 0) {
796 igp[0] = p;
797 } else if (p->lat == latp[1] && p->lon == lonp[1] && p->give > 0) {
798 igp[1] = p;
799 } else if (p->lat == latp[0] && p->lon == lonp[2] && p->give > 0) {
800 igp[2] = p;
801 } else if (p->lat == latp[1] && p->lon == lonp[3] && p->give > 0) {
802 igp[3] = p;
803 }
804 if (igp[0] && igp[1] && igp[2] && igp[3]) {
805 return;
806 }
807 }
808 }
809}
810/* sbas ionospheric delay correction -------------------------------------------
811 * compute sbas ionosphric delay correction
812 * args : gtime_t time I time
813 * nav_t *nav I navigation data
814 * double *pos I receiver position {lat,lon,height} (rad/m)
815 * double *azel I satellite azimuth/elavation angle (rad)
816 * double *delay O slant ionospheric delay (L1) (m)
817 * double *var O variance of ionospheric delay (m^2)
818 * return : status (1:ok, 0:no correction)
819 * notes : before calling the function, sbas ionosphere correction parameters
820 * in navigation data (nav->sbsion) must be set by callig
821 * sbsupdatecorr()
822 *-----------------------------------------------------------------------------*/
823int sbsioncorr(gtime_t time, const nav_t* nav, const double* pos, const double* azel, double* delay, double* var) {
824 const double re = 6378.1363, hion = 350.0;
825 int i, err = 0;
826 double fp, posp[2], x = 0.0, y = 0.0, t, w[4] = {0};
827 const sbsigp_t* igp[4] = {0}; /* {ws,wn,es,en} */
828
829 trace(NULL, 4, "sbsioncorr: pos=%.3f %.3f azel=%.3f %.3f\n", pos[0] * R2D, pos[1] * R2D, azel[0] * R2D,
830 azel[1] * R2D);
831
832 *delay = *var = 0.0;
833 if (pos[2] < -100.0 || azel[1] <= 0) {
834 return 1;
835 }
836
837 /* ipp (ionospheric pierce point) position */
838 fp = ionppp(pos, azel, re, hion, posp);
839
840 /* search igps around ipp */
841 searchigp(time, posp, nav->sbsion, igp, &x, &y);
842
843 /* weight of igps */
844 if (igp[0] && igp[1] && igp[2] && igp[3]) {
845 w[0] = (1.0 - x) * (1.0 - y);
846 w[1] = (1.0 - x) * y;
847 w[2] = x * (1.0 - y);
848 w[3] = x * y;
849 } else if (igp[0] && igp[1] && igp[2]) {
850 w[1] = y;
851 w[2] = x;
852 if ((w[0] = 1.0 - w[1] - w[2]) < 0.0) {
853 err = 1;
854 }
855 } else if (igp[0] && igp[2] && igp[3]) {
856 w[0] = 1.0 - x;
857 w[3] = y;
858 if ((w[2] = 1.0 - w[0] - w[3]) < 0.0) {
859 err = 1;
860 }
861 } else if (igp[0] && igp[1] && igp[3]) {
862 w[0] = 1.0 - y;
863 w[3] = x;
864 if ((w[1] = 1.0 - w[0] - w[3]) < 0.0) {
865 err = 1;
866 }
867 } else if (igp[1] && igp[2] && igp[3]) {
868 w[1] = 1.0 - x;
869 w[2] = 1.0 - y;
870 if ((w[3] = 1.0 - w[1] - w[2]) < 0.0) {
871 err = 1;
872 }
873 } else {
874 err = 1;
875 }
876
877 if (err) {
878 trace(NULL, 2, "no sbas iono correction: lat=%3.0f lon=%4.0f\n", posp[0] * R2D, posp[1] * R2D);
879 return 0;
880 }
881 for (i = 0; i < 4; i++) {
882 if (!igp[i]) {
883 continue;
884 }
885 t = timediff(time, igp[i]->t0);
886 *delay += w[i] * igp[i]->delay;
887 *var += w[i] * varicorr(igp[i]->give) * 9E-8 * fabs(t);
888 }
889 *delay *= fp;
890 *var *= fp * fp;
891
892 trace(NULL, 5, "sbsioncorr: dion=%7.2f sig=%7.2f\n", *delay, sqrt(*var));
893 return 1;
894}
895/* get meterological parameters ----------------------------------------------*/
896static void getmet(double lat, double* met) {
897 static const double metprm[][10] = {/* lat=15,30,45,60,75 */
898 {1013.25, 299.65, 26.31, 6.30E-3, 2.77, 0.00, 0.00, 0.00, 0.00E-3, 0.00},
899 {1017.25, 294.15, 21.79, 6.05E-3, 3.15, -3.75, 7.00, 8.85, 0.25E-3, 0.33},
900 {1015.75, 283.15, 11.66, 5.58E-3, 2.57, -2.25, 11.00, 7.24, 0.32E-3, 0.46},
901 {1011.75, 272.15, 6.78, 5.39E-3, 1.81, -1.75, 15.00, 5.36, 0.81E-3, 0.74},
902 {1013.00, 263.65, 4.11, 4.53E-3, 1.55, -0.50, 14.50, 3.39, 0.62E-3, 0.30}};
903 int i, j;
904 double a;
905 lat = fabs(lat);
906 if (lat <= 15.0) {
907 for (i = 0; i < 10; i++) {
908 met[i] = metprm[0][i];
909 }
910 } else if (lat >= 75.0) {
911 for (i = 0; i < 10; i++) {
912 met[i] = metprm[4][i];
913 }
914 } else {
915 j = (int)(lat / 15.0);
916 a = (lat - j * 15.0) / 15.0;
917 for (i = 0; i < 10; i++) {
918 met[i] = (1.0 - a) * metprm[j - 1][i] + a * metprm[j][i];
919 }
920 }
921}
922/* tropospheric delay correction -----------------------------------------------
923 * compute sbas tropospheric delay correction (mops model)
924 * args : gtime_t time I time
925 * double *pos I receiver position {lat,lon,height} (rad/m)
926 * double *azel I satellite azimuth/elavation (rad)
927 * double *var O variance of troposphric error (m^2)
928 * return : slant tropospheric delay (m)
929 *-----------------------------------------------------------------------------*/
930double sbstropcorr(gtime_t time, const double* pos, const double* azel, double* var) {
931 const double k1 = 77.604, k2 = 382000.0, rd = 287.054, gm = 9.784, g = 9.80665;
932 static double pos_[3] = {0}, zh = 0.0, zw = 0.0;
933 int i;
934 double c, met[10], sinel = sin(azel[1]), h = pos[2], m;
935
936 trace(NULL, 4, "sbstropcorr: pos=%.3f %.3f azel=%.3f %.3f\n", pos[0] * R2D, pos[1] * R2D, azel[0] * R2D,
937 azel[1] * R2D);
938
939 if (pos[2] < -100.0 || 10000.0 < pos[2] || azel[1] <= 0) {
940 *var = 0.0;
941 return 0.0;
942 }
943 if (zh == 0.0 || fabs(pos[0] - pos_[0]) > 1E-7 || fabs(pos[1] - pos_[1]) > 1E-7 || fabs(pos[2] - pos_[2]) > 1.0) {
944 getmet(pos[0] * R2D, met);
945 c = cos(2.0 * PI * (time2doy(time) - (pos[0] >= 0.0 ? 28.0 : 211.0)) / 365.25);
946 for (i = 0; i < 5; i++) {
947 met[i] -= met[i + 5] * c;
948 }
949 zh = 1E-6 * k1 * rd * met[0] / gm;
950 zw = 1E-6 * k2 * rd / (gm * (met[4] + 1.0) - met[3] * rd) * met[2] / met[1];
951 zh *= pow(1.0 - met[3] * h / met[1], g / (rd * met[3]));
952 zw *= pow(1.0 - met[3] * h / met[1], (met[4] + 1.0) * g / (rd * met[3]) - 1.0);
953 for (i = 0; i < 3; i++) {
954 pos_[i] = pos[i];
955 }
956 }
957 m = 1.001 / sqrt(0.002001 + sinel * sinel);
958 *var = 0.12 * 0.12 * m * m;
959 return (zh + zw) * m;
960}
961/* long term correction ------------------------------------------------------*/
962static int sbslongcorr(gtime_t time, int sat, const sbssat_t* sbssat, double* drs, double* ddts) {
963 const sbssatp_t* p;
964 double t;
965 int i;
966
967 trace(NULL, 3, "sbslongcorr: sat=%2d\n", sat);
968
969 for (p = sbssat->sat; p < sbssat->sat + sbssat->nsat; p++) {
970 if (p->sat != sat || p->lcorr.t0.time == 0) {
971 continue;
972 }
973 t = timediff(time, p->lcorr.t0);
974 if (fabs(t) > MAXSBSAGEL) {
975 trace(NULL, 2, "sbas long-term correction expired: %s sat=%2d t=%5.0f\n", time_str(time, 0), sat, t);
976 return 0;
977 }
978 for (i = 0; i < 3; i++) {
979 drs[i] = p->lcorr.dpos[i] + p->lcorr.dvel[i] * t;
980 }
981 *ddts = p->lcorr.daf0 + p->lcorr.daf1 * t;
982
983 trace(NULL, 5, "sbslongcorr: sat=%2d drs=%7.2f%7.2f%7.2f ddts=%7.2f\n", sat, drs[0], drs[1], drs[2],
984 *ddts * CLIGHT);
985
986 return 1;
987 }
988 /* if sbas satellite without correction, no correction applied */
989 if (satsys(sat, NULL) == SYS_SBS) {
990 return 1;
991 }
992
993 trace(NULL, 2, "no sbas long-term correction: %s sat=%2d\n", time_str(time, 0), sat);
994 return 0;
995}
996/* fast correction -----------------------------------------------------------*/
997static int sbsfastcorr(gtime_t time, int sat, const sbssat_t* sbssat, double* prc, double* var) {
998 const sbssatp_t* p;
999 double t;
1000
1001 trace(NULL, 3, "sbsfastcorr: sat=%2d\n", sat);
1002
1003 for (p = sbssat->sat; p < sbssat->sat + sbssat->nsat; p++) {
1004 if (p->sat != sat) {
1005 continue;
1006 }
1007 if (p->fcorr.t0.time == 0) {
1008 break;
1009 }
1010 t = timediff(time, p->fcorr.t0) + sbssat->tlat;
1011
1012 /* expire age of correction or UDRE==14 (not monitored) */
1013 if (fabs(t) > MAXSBSAGEF || p->fcorr.udre >= 15) {
1014 continue;
1015 }
1016 *prc = p->fcorr.prc;
1017#ifdef RRCENA
1018 if (p->fcorr.ai > 0 && fabs(t) <= 8.0 * p->fcorr.dt) {
1019 *prc += p->fcorr.rrc * t;
1020 }
1021#endif
1022 *var = varfcorr(p->fcorr.udre) + degfcorr(p->fcorr.ai) * t * t / 2.0;
1023
1024 trace(NULL, 5, "sbsfastcorr: sat=%3d prc=%7.2f sig=%7.2f t=%5.0f\n", sat, *prc, sqrt(*var), t);
1025 return 1;
1026 }
1027 trace(NULL, 2, "no sbas fast correction: %s sat=%2d\n", time_str(time, 0), sat);
1028 return 0;
1029}
1030/* sbas satellite ephemeris and clock correction -------------------------------
1031 * correct satellite position and clock bias with sbas satellite corrections
1032 * args : gtime_t time I reception time
1033 * int sat I satellite
1034 * nav_t *nav I navigation data
1035 * double *rs IO sat position and corrected {x,y,z} (ecef) (m)
1036 * double *dts IO sat clock bias and corrected (s)
1037 * double *var O sat position and clock variance (m^2)
1038 * return : status (1:ok,0:no correction)
1039 * notes : before calling the function, sbas satellite correction parameters
1040 * in navigation data (nav->sbssat) must be set by callig
1041 * sbsupdatecorr().
1042 * satellite clock correction include long-term correction and fast
1043 * correction.
1044 * sbas clock correction is usually based on L1C/A code. TGD or DCB has
1045 * to be considered for other codes
1046 *-----------------------------------------------------------------------------*/
1047int sbssatcorr(gtime_t time, int sat, const nav_t* nav, double* rs, double* dts, double* var) {
1048 double drs[3] = {0}, dclk = 0.0, prc = 0.0;
1049 int i;
1050
1051 trace(NULL, 3, "sbssatcorr : sat=%2d\n", sat);
1052
1053 /* sbas long term corrections */
1054 if (!sbslongcorr(time, sat, &nav->sbssat, drs, &dclk)) {
1055 return 0;
1056 }
1057 /* sbas fast corrections */
1058 if (!sbsfastcorr(time, sat, &nav->sbssat, &prc, var)) {
1059 return 0;
1060 }
1061 for (i = 0; i < 3; i++) {
1062 rs[i] += drs[i];
1063 }
1064
1065 dts[0] += dclk + prc / CLIGHT;
1066
1067 trace(NULL, 5, "sbssatcorr: sat=%2d drs=%6.3f %6.3f %6.3f dclk=%.3f %.3f var=%.3f\n", sat, drs[0], drs[1], drs[2],
1068 dclk, prc / CLIGHT, *var);
1069
1070 return 1;
1071}
1072/* decode sbas message ---------------------------------------------------------
1073 * decode sbas message frame words and check crc
1074 * args : gtime_t time I reception time
1075 * int prn I sbas satellite prn number
1076 * uint32_t *word I message frame words (24bit x 10)
1077 * sbsmsg_t *sbsmsg O sbas message
1078 * return : status (1:ok,0:crc error)
1079 *-----------------------------------------------------------------------------*/
1080int sbsdecodemsg(gtime_t time, int prn, const uint32_t* words, sbsmsg_t* sbsmsg) {
1081 int i, j;
1082 uint8_t f[29];
1083 double tow;
1084
1085 trace(NULL, 5, "sbsdecodemsg: prn=%d\n", prn);
1086
1087 if (time.time == 0) {
1088 return 0;
1089 }
1090 tow = time2gpst(time, &sbsmsg->week);
1091 sbsmsg->tow = (int)(tow + DTTOL);
1092 sbsmsg->prn = prn;
1093 for (i = 0; i < 7; i++) {
1094 for (j = 0; j < 4; j++) {
1095 sbsmsg->msg[i * 4 + j] = (uint8_t)(words[i] >> ((3 - j) * 8));
1096 }
1097 }
1098 sbsmsg->msg[28] = (uint8_t)(words[7] >> 18) & 0xC0;
1099 for (i = 28; i > 0; i--) {
1100 f[i] = (sbsmsg->msg[i] >> 6) + (sbsmsg->msg[i - 1] << 2);
1101 }
1102 f[0] = sbsmsg->msg[0] >> 6;
1103
1104 return rtk_crc24q(f, 29) == (words[7] & 0xFFFFFF); /* check crc */
1105}
double ionppp(const double *pos, const double *azel, double re, double hion, double *posp)
Compute ionospheric pierce point (IPP) position and slant factor.
Definition mrtk_atmos.c:131
MRTKLIB Atmosphere Module — Ionospheric and tropospheric models.
uint32_t rtk_crc24q(const uint8_t *buff, int len)
Compute CRC-24Q parity for SBAS and RTCM3.
Definition mrtk_bits.c:181
uint32_t getbitu(const uint8_t *buff, int pos, int len)
Extract unsigned bits from byte data.
Definition mrtk_bits.c:99
int32_t getbits(const uint8_t *buff, int pos, int len)
Extract signed bits from byte data.
Definition mrtk_bits.c:107
MRTKLIB Bits Module — Binary bit operations and CRC functions.
#define D2R
Definition mrtk_coords.c:36
#define CLIGHT
Definition mrtk_coords.c:41
#define PI
Definition mrtk_coords.c:35
#define MAXSAT
Definition mrtk_coords.c:45
#define RE_WGS84
Definition mrtk_coords.c:38
int satsys(int sat, int *prn)
Definition mrtk_nav.c:117
#define SYS_GPS
Definition mrtk_eph.c:65
#define SYS_SBS
Definition mrtk_eph.c:66
#define SYS_QZS
Definition mrtk_eph.c:69
#define SYS_GLO
Definition mrtk_eph.c:67
struct nav_s nav_t
Definition mrtk_eph.h:40
#define NSATSBS
#define DTTOL
#define MAXBAND
#define MAXEXFILE
int satno(int sys, int prn)
Convert satellite system+prn/slot number to satellite number.
Definition mrtk_nav.c:58
#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
#define MINPRNSBS
#define P2_31
Definition mrtk_rcvraw.c:56
#define P2_11
Definition mrtk_rcvraw.c:45
static void searchigp(gtime_t time, const double *pos, const sbsion_t *ion, const sbsigp_t **igp, double *x, double *y)
Definition mrtk_sbas.c:744
#define MAXSBSAGEF
Definition mrtk_sbas.c:57
void sbsoutmsg(FILE *fp, sbsmsg_t *sbsmsg)
Output SBAS message record.
Definition mrtk_sbas.c:732
static int decode_longcorr1(const sbsmsg_t *msg, int p, sbssat_t *sbssat)
Definition mrtk_sbas.c:405
static int decode_sbstype2(const sbsmsg_t *msg, sbssat_t *sbssat)
Definition mrtk_sbas.c:225
static int decode_longcorrh(const sbsmsg_t *msg, int p, sbssat_t *sbssat)
Definition mrtk_sbas.c:434
static int decode_sbstype26(const sbsmsg_t *msg, sbsion_t *sbsion)
Definition mrtk_sbas.c:479
static int decode_sbstype6(const sbsmsg_t *msg, sbssat_t *sbssat)
Definition mrtk_sbas.c:263
int sbsreadmsg(const char *file, int sel, sbs_t *sbs)
Read SBAS message file.
Definition mrtk_sbas.c:719
#define MAXSBSAGEL
Definition mrtk_sbas.c:58
static const int16_t x3[]
Definition mrtk_sbas.c:71
static int decode_sbstype9(const sbsmsg_t *msg, nav_t *nav)
Definition mrtk_sbas.c:299
static const int16_t x6[]
Definition mrtk_sbas.c:80
static double varfcorr(int udre)
Definition mrtk_sbas.c:173
int sbsioncorr(gtime_t time, const nav_t *nav, const double *pos, const double *azel, double *delay, double *var)
SBAS ionospheric delay correction.
Definition mrtk_sbas.c:823
static double degfcorr(int ai)
Definition mrtk_sbas.c:185
static int decode_sbstype1(const sbsmsg_t *msg, sbssat_t *sbssat)
Definition mrtk_sbas.c:191
const sbsigpband_t igpband1[9][8]
Definition mrtk_sbas.c:86
static const int16_t x7[]
Definition mrtk_sbas.c:83
int sbsdecodemsg(gtime_t time, int prn, const uint32_t *words, sbsmsg_t *sbsmsg)
Decode SBAS message frame words.
Definition mrtk_sbas.c:1080
int sbsreadmsgt(const char *file, int sel, gtime_t ts, gtime_t te, sbs_t *sbs)
Read SBAS message file with time span.
Definition mrtk_sbas.c:682
static int sbsfastcorr(gtime_t time, int sat, const sbssat_t *sbssat, double *prc, double *var)
Definition mrtk_sbas.c:997
static char * getfield(char *p, int pos)
Definition mrtk_sbas.c:164
static int decode_sbstype18(const sbsmsg_t *msg, sbsion_t *sbsion)
Definition mrtk_sbas.c:345
#define P2_39
Definition mrtk_sbas.c:56
static const int16_t x4[]
Definition mrtk_sbas.c:73
static void getmet(double lat, double *met)
Definition mrtk_sbas.c:896
#define WEEKOFFSET
Definition mrtk_sbas.c:64
static int decode_sbstype25(const sbsmsg_t *msg, sbssat_t *sbssat)
Definition mrtk_sbas.c:473
double sbstropcorr(gtime_t time, const double *pos, const double *azel, double *var)
SBAS tropospheric delay correction.
Definition mrtk_sbas.c:930
int sbsupdatecorr(const sbsmsg_t *msg, nav_t *nav)
Update SBAS corrections in navigation data.
Definition mrtk_sbas.c:517
static const int16_t x1[]
Definition mrtk_sbas.c:67
static int decode_sbstype24(const sbsmsg_t *msg, sbssat_t *sbssat)
Definition mrtk_sbas.c:447
const sbsigpband_t igpband2[2][5]
Definition mrtk_sbas.c:159
static const int16_t x5[]
Definition mrtk_sbas.c:75
int sbssatcorr(gtime_t time, int sat, const nav_t *nav, double *rs, double *dts, double *var)
SBAS satellite ephemeris and clock correction.
Definition mrtk_sbas.c:1047
static int cmpmsgs(const void *p1, const void *p2)
Definition mrtk_sbas.c:662
static const int16_t x8[]
Definition mrtk_sbas.c:84
static int decode_longcorr0(const sbsmsg_t *msg, int p, sbssat_t *sbssat)
Definition mrtk_sbas.c:382
static int sbslongcorr(gtime_t time, int sat, const sbssat_t *sbssat, double *drs, double *ddts)
Definition mrtk_sbas.c:962
static double varicorr(int give)
Definition mrtk_sbas.c:179
static const int16_t x2[]
Definition mrtk_sbas.c:69
static void readmsgs(const char *file, int sel, gtime_t ts, gtime_t te, sbs_t *sbs)
Definition mrtk_sbas.c:568
static int decode_sbstype7(const sbsmsg_t *msg, sbssat_t *sbssat)
Definition mrtk_sbas.c:282
MRTKLIB SBAS Module — SBAS message decoding and corrections.
int expath(const char *path, char *paths[], int nmax)
Expand file path with wild-card (*) in file.
Definition mrtk_sys.c:96
MRTKLIB System Module — OS/filesystem utility functions.
gtime_t epoch2time(const double *ep)
Convert calendar day/time to gtime_t struct.
Definition mrtk_time.c:113
gtime_t gpst2time(int week, double sec)
Convert GPS week/tow to gtime_t.
Definition mrtk_time.c:165
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
double time2doy(gtime_t t)
Convert time to day of year.
Definition mrtk_time.c:540
char * time_str(gtime_t t, int n)
Get time string (not reentrant).
Definition mrtk_time.c:530
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.
GNSS time representation.
Definition mrtk_time.h:49
time_t time
Definition mrtk_time.h:50
sbssat_t sbssat
Definition mrtk_nav.h:431
seph_t * seph
Definition mrtk_nav.h:408
sbsion_t sbsion[MAXBAND+1]
Definition mrtk_nav.h:432
int nmax
Definition mrtk_nav.h:108
sbsmsg_t * msgs
Definition mrtk_nav.h:109
int n
Definition mrtk_nav.h:108
int16_t udre
Definition mrtk_nav.h:118
int16_t ai
Definition mrtk_nav.h:119
gtime_t t0
Definition mrtk_nav.h:113
double rrc
Definition mrtk_nav.h:115
double prc
Definition mrtk_nav.h:114
double dt
Definition mrtk_nav.h:116
int16_t lon
Definition mrtk_nav.h:145
float delay
Definition mrtk_nav.h:147
int16_t lat
Definition mrtk_nav.h:145
int16_t give
Definition mrtk_nav.h:146
gtime_t t0
Definition mrtk_nav.h:144
uint8_t bits
Definition mrtk_nav.h:153
int16_t x
Definition mrtk_nav.h:151
const int16_t * y
Definition mrtk_nav.h:152
sbsigp_t igp[MAXNIGP]
Definition mrtk_nav.h:160
int nigp
Definition mrtk_nav.h:159
int iodi
Definition mrtk_nav.h:158
double dpos[3]
Definition mrtk_nav.h:125
double daf0
Definition mrtk_nav.h:127
double daf1
Definition mrtk_nav.h:127
gtime_t t0
Definition mrtk_nav.h:123
double dvel[3]
Definition mrtk_nav.h:126
int tow
Definition mrtk_nav.h:102
uint8_t msg[29]
Definition mrtk_nav.h:104
uint8_t prn
Definition mrtk_nav.h:103
int week
Definition mrtk_nav.h:102
sbssatp_t sat[MAXSAT]
Definition mrtk_nav.h:140
int tlat
Definition mrtk_nav.h:139
int iodp
Definition mrtk_nav.h:137
int nsat
Definition mrtk_nav.h:138
sbslcorr_t lcorr
Definition mrtk_nav.h:133
sbsfcorr_t fcorr
Definition mrtk_nav.h:132
SBAS ephemeris type.
Definition mrtk_eph.h:130
int sva
Definition mrtk_eph.h:134
double pos[3]
Definition mrtk_eph.h:136
double vel[3]
Definition mrtk_eph.h:137
double acc[3]
Definition mrtk_eph.h:138
gtime_t tof
Definition mrtk_eph.h:133
double af0
Definition mrtk_eph.h:139
double af1
Definition mrtk_eph.h:139
int sat
Definition mrtk_eph.h:131
gtime_t t0
Definition mrtk_eph.h:132
int svh
Definition mrtk_eph.h:135
#define malloc(x)
Definition toml.c:52
#define free(x)
Definition toml.c:53