27static const double PI = 3.1415926535897932;
28static const double R2D = 180.0 / 3.1415926535897932;
29static const double CLIGHT = 299792458.0;
30static const double FREQ1 = 1.57542E9;
32#define SQR(x) ((x) * (x))
33#define VAR_NOTEC SQR(30.0)
35#define MIN_HGT -1000.0
41 if (
range[2] == 0.0) {
50 return (
int)floor((value -
range[0]) /
range[2] + 0.5);
55static int dataindex(
int i,
int j,
int k,
const int* ndata) {
56 if (i < 0 || ndata[0] <= i || j < 0 || ndata[1] <= j || k < 0 || ndata[2] <= k) {
59 return i + ndata[0] * (j + ndata[1] * k);
62static tec_t*
addtec(
const double* lats,
const double* lons,
const double* hgts,
double rb,
nav_t* nav) {
67 trace(NULL, 3,
"addtec :\n");
69 ndata[0] =
nitem(lats);
70 ndata[1] =
nitem(lons);
71 ndata[2] =
nitem(hgts);
72 if (ndata[0] <= 1 || ndata[1] <= 1 || ndata[2] <= 0) {
79 trace(NULL, 1,
"readionex malloc error ntmax=%d\n", nav->
ntmax);
87 p = nav->
tec + nav->
nt;
90 for (i = 0; i < 3; i++) {
91 p->
ndata[i] = ndata[i];
96 n = ndata[0] * ndata[1] * ndata[2];
98 if (!(p->
data = (
double*)
malloc(
sizeof(
double) * n)) || !(p->
rms = (
float*)
malloc(
sizeof(
float) * n))) {
101 for (i = 0; i < n; i++) {
111 char buff[1024],
id[32], *label;
113 trace(NULL, 3,
"readionexdcb:\n");
115 for (i = 0; i <
MAXSAT; i++) {
116 dcb[i] = rms[i] = 0.0;
119 while (fgets(buff,
sizeof(buff), fp)) {
120 if (strlen(buff) < 60) {
125 if (strstr(label,
"PRN / BIAS / RMS") == label) {
126 strncpy(
id, buff + 3, 3);
130 trace(NULL, 2,
"ionex invalid satellite: %s\n",
id);
133 dcb[sat - 1] =
str2num(buff, 6, 10);
134 rms[sat - 1] =
str2num(buff, 16, 10);
135 }
else if (strstr(label,
"END OF AUX DATA") == label) {
141static double readionexh(FILE* fp,
double* lats,
double* lons,
double* hgts,
double* rb,
double* nexp,
double* dcb,
144 char buff[1024], *label;
146 trace(NULL, 3,
"readionexh:\n");
148 while (fgets(buff,
sizeof(buff), fp)) {
149 if (strlen(buff) < 60) {
154 if (strstr(label,
"IONEX VERSION / TYPE") == label) {
155 if (buff[20] ==
'I') {
158 }
else if (strstr(label,
"BASE RADIUS") == label) {
160 }
else if (strstr(label,
"HGT1 / HGT2 / DHGT") == label) {
163 hgts[2] =
str2num(buff, 14, 6);
164 }
else if (strstr(label,
"LAT1 / LAT2 / DLAT") == label) {
167 lats[2] =
str2num(buff, 14, 6);
168 }
else if (strstr(label,
"LON1 / LON2 / DLON") == label) {
171 lons[2] =
str2num(buff, 14, 6);
172 }
else if (strstr(label,
"EXPONENT") == label) {
174 }
else if (strstr(label,
"START OF AUX DATA") == label && strstr(buff,
"DIFFERENTIAL CODE BIASES")) {
176 }
else if (strstr(label,
"END OF HEADER") == label) {
183static int readionexb(FILE* fp,
const double* lats,
const double* lons,
const double* hgts,
double rb,
double nexp,
187 double lat, lon[3], hgt, x;
188 int i, j, k, n, m, index, type = 0;
189 char buff[1024], *label = buff + 60;
191 trace(NULL, 3,
"readionexb:\n");
193 while (fgets(buff,
sizeof(buff), fp)) {
194 if (strlen(buff) < 60) {
198 if (strstr(label,
"START OF TEC MAP") == label) {
199 if ((p =
addtec(lats, lons, hgts, rb, nav))) {
202 }
else if (strstr(label,
"END OF TEC MAP") == label) {
205 }
else if (strstr(label,
"START OF RMS MAP") == label) {
208 }
else if (strstr(label,
"END OF RMS MAP") == label) {
211 }
else if (strstr(label,
"EPOCH OF CURRENT MAP") == label) {
213 trace(NULL, 2,
"ionex epoch invalid: %-36.36s\n", buff);
217 for (i = nav->
nt - 1; i >= 0; i--) {
227 }
else if (strstr(label,
"LAT/LON1/LON2/DLON/H") == label && p) {
238 for (m = 0; m < n; m++) {
239 if (m % 16 == 0 && !fgets(buff,
sizeof(buff), fp)) {
248 if ((x =
str2num(buff, m % 16 * 5, 5)) == 9999.0) {
253 p->
data[index] = x * pow(10.0, nexp);
255 p->
rms[index] = (float)(x * pow(10.0, nexp));
267 trace(NULL, 3,
"combtec : nav->nt=%d\n", nav->
nt);
269 for (i = 0; i < nav->
nt - 1; i++) {
270 for (j = i + 1; j < nav->
nt; j++) {
273 nav->
tec[i] = nav->
tec[j];
278 for (i = 0; i < nav->
nt; i++) {
282 nav->
tec[n - 1] = nav->
tec[i];
285 nav->
tec[n++] = nav->
tec[i];
289 trace(NULL, 4,
"combtec : nav->nt=%d\n", nav->
nt);
303 double lats[3] = {0}, lons[3] = {0}, hgts[3] = {0}, rb = 0.0, nexp = -1.0;
308 trace(NULL, 3,
"readtec : file=%s\n", file);
317 if (!(efiles[i] = (
char*)
malloc(1024))) {
318 for (i--; i >= 0; i--) {
327 for (i = 0; i < n; i++) {
328 if (!(fp = fopen(efiles[i],
"r"))) {
329 trace(NULL, 2,
"ionex file open error %s\n", efiles[i]);
333 if (
readionexh(fp, lats, lons, hgts, &rb, &nexp, dcb, rms) <= 0.0) {
334 trace(NULL, 2,
"ionex file format error %s\n", efiles[i]);
338 readionexb(fp, lats, lons, hgts, rb, nexp, nav);
352 for (i = 0; i <
MAXSAT; i++) {
357static int interptec(
const tec_t* tec,
int k,
const double* posp,
double* value,
double* rms) {
358 double dlat, dlon, a, b, d[4] = {0}, r[4] = {0};
361 trace(NULL, 3,
"interptec: k=%d posp=%.2f %.2f\n", k, posp[0] *
R2D, posp[1] *
R2D);
364 if (tec->
lats[2] == 0.0 || tec->
lons[2] == 0.0) {
368 dlat = posp[0] *
R2D - tec->
lats[0];
369 dlon = posp[1] *
R2D - tec->
lons[0];
370 if (tec->
lons[2] > 0.0) {
371 dlon -= floor(dlon / 360) * 360.0;
373 dlon += floor(-dlon / 360) * 360.0;
376 a = dlat / tec->
lats[2];
377 b = dlon / tec->
lons[2];
384 for (n = 0; n < 4; n++) {
385 if ((index =
dataindex(i + (n % 2), j + (n < 2 ? 0 : 1), k, tec->
ndata)) < 0) {
388 d[n] = tec->
data[index];
389 r[n] = tec->
rms[index];
391 if (d[0] > 0.0 && d[1] > 0.0 && d[2] > 0.0 && d[3] > 0.0) {
393 *value = (1.0 - a) * (1.0 - b) * d[0] + a * (1.0 - b) * d[1] + (1.0 - a) * b * d[2] + a * b * d[3];
394 *rms = (1.0 - a) * (1.0 - b) * r[0] + a * (1.0 - b) * r[1] + (1.0 - a) * b * r[2] + a * b * r[3];
397 else if (a <= 0.5 && b <= 0.5 && d[0] > 0.0) {
400 }
else if (a > 0.5 && b <= 0.5 && d[1] > 0.0) {
403 }
else if (a <= 0.5 && b > 0.5 && d[2] > 0.0) {
406 }
else if (a > 0.5 && b > 0.5 && d[3] > 0.0) {
411 for (n = 0; n < 4; n++) {
427static int iondelay(
gtime_t time,
const tec_t* tec,
const double* pos,
const double* azel,
int opt,
double* delay,
430 double fs, posp[3] = {0}, vtec, rms, hion, rp;
433 trace(NULL, 3,
"iondelay: time=%s pos=%.1f %.1f azel=%.1f %.1f\n",
time_str(time, 0), pos[0] *
R2D, pos[1] *
R2D,
434 azel[0] *
R2D, azel[1] *
R2D);
438 for (i = 0; i < tec->
ndata[2]; i++) {
440 hion = tec->
hgts[0] + tec->
hgts[2] * i;
443 fs =
ionppp(pos, azel, tec->
rb, hion, posp);
447 rp = tec->
rb / (tec->
rb + hion) * sin(0.9782 * (
PI / 2.0 - azel[1]));
448 fs = 1.0 / sqrt(1.0 - rp * rp);
455 if (!
interptec(tec, i, posp, &vtec, &rms)) {
459 *delay += fact * fs * vtec;
460 *var += fact * fact * fs * fs * rms * rms;
462 trace(NULL, 4,
"iondelay: delay=%7.2f std=%6.2f\n", *delay, sqrt(*var));
481int iontec(
gtime_t time,
const nav_t* nav,
const double* pos,
const double* azel,
int opt,
double* delay,
double* var) {
482 double dels[2], vars[2], a, tt;
485 trace(NULL, 3,
"iontec : time=%s pos=%.1f %.1f azel=%.1f %.1f\n",
time_str(time, 0), pos[0] *
R2D, pos[1] *
R2D,
486 azel[0] *
R2D, azel[1] *
R2D);
493 for (i = 0; i < nav->
nt; i++) {
498 if (i == 0 || i >= nav->
nt) {
499 trace(NULL, 2,
"%s: tec grid out of period\n",
time_str(time, 0));
503 trace(NULL, 2,
"tec grid time interval error\n");
507 stat[0] =
iondelay(time, nav->
tec + i - 1, pos, azel, opt, dels, vars);
508 stat[1] =
iondelay(time, nav->
tec + i, pos, azel, opt, dels + 1, vars + 1);
510 if (!stat[0] && !stat[1]) {
511 trace(NULL, 2,
"%s: tec grid out of area pos=%6.2f %7.2f azel=%6.1f %5.1f\n",
time_str(time, 0), pos[0] *
R2D,
512 pos[1] *
R2D, azel[0] *
R2D, azel[1] *
R2D);
515 if (stat[0] && stat[1]) {
517 *delay = dels[0] * (1.0 - a) + dels[1] * a;
518 *var = vars[0] * (1.0 - a) + vars[1] * a;
519 }
else if (stat[0]) {
526 trace(NULL, 3,
"iontec : delay=%5.2f std=%5.2f\n", *delay, sqrt(*var));
double ionppp(const double *pos, const double *azel, double re, double hion, double *posp)
Compute ionospheric pierce point (IPP) position and slant factor.
MRTKLIB Atmosphere Module — Ionospheric and tropospheric models.
int satid2no(const char *id)
static const double range[4]
static tec_t * addtec(const double *lats, const double *lons, const double *hgts, double rb, nav_t *nav)
static void combtec(nav_t *nav)
void readtec(const char *file, nav_t *nav, int opt)
Read IONEX ionospheric TEC grid file.
int iontec(gtime_t time, const nav_t *nav, const double *pos, const double *azel, int opt, double *delay, double *var)
Compute ionospheric delay by TEC grid data.
static void readionexdcb(FILE *fp, double *dcb, double *rms)
static int dataindex(int i, int j, int k, const int *ndata)
static int readionexb(FILE *fp, const double *lats, const double *lons, const double *hgts, double rb, double nexp, nav_t *nav)
static double readionexh(FILE *fp, double *lats, double *lons, double *hgts, double *rb, double *nexp, double *dcb, double *rms)
static int getindex(double value, const double *range)
static int nitem(const double *range)
static int iondelay(gtime_t time, const tec_t *tec, const double *pos, const double *azel, int opt, double *delay, double *var)
static int interptec(const tec_t *tec, int k, const double *posp, double *value, double *rms)
MRTKLIB IONEX Module — IONEX ionospheric TEC map I/O and interpolation.
int expath(const char *path, char *paths[], int nmax)
Expand file path with wild-card (*) in file.
double str2num(const char *s, int i, int n)
Convert substring in string to number.
MRTKLIB System Module — OS/filesystem utility functions.
double timediff(gtime_t t1, gtime_t t2)
Compute time difference (t1 - t2).
char * time_str(gtime_t t, int n)
Get time string (not reentrant).
int str2time(const char *s, int i, int n, gtime_t *t)
Convert substring in string to gtime_t struct.
void trace(mrtk_ctx_t *ctx, int level, const char *format,...)
Output trace message.
MRTKLIB Trace Module — debug trace and logging functions.
GNSS time representation.