44#define MAX_GRID_CACHE 20
46#define MAXAGESSR_TROP 120.0
47#define MAXAGESSR_IONO 120.0
49#define SQR(x) ((x) * (x))
50#define MIN(x, y) ((x) < (y) ? (x) : (y))
51#define MAX(x, y) ((x) > (y) ? (x) : (y))
73static double Interp1(
const double* x,
const double* y,
int nx,
int ny,
double xi) {
77 for (i = 0; i < nx - 1; i++) {
82 dx = (xi - x[i]) / (x[i + 1] - x[i]);
84 return y[i] * (1.0 - dx) + y[i + 1] * dx;
88static int get_mops(
const double lat,
const double doy,
double* pre,
double* temp,
double* wpre,
double* ltemp,
91 double cos_, latdeg = lat *
R2D;
92 const double dminN = 28;
93 const double interval[] = {15.0, 30.0, 45.0, 60.0, 75.0};
96 const double pTave[] = {1013.25, 1017.25, 1015.75, 1011.75, 1013.00};
97 const double tTave[] = {299.65, 294.15, 283.15, 272.15, 263.65};
98 const double wTave[] = {26.31, 21.79, 11.66, 6.78, 4.11};
99 const double tlTave[] = {6.30e-3, 6.05e-3, 5.58e-3, 5.39e-3, 4.53e-3};
100 const double wlTave[] = {2.77, 3.15, 2.57, 1.81, 1.55};
103 const double pTableS[] = {0.00, -3.75, -2.25, -1.75, -0.50};
104 const double tTableS[] = {0.00, 7.00, 11.00, 15.00, 14.50};
105 const double wTableS[] = {0.00, 8.85, 7.24, 5.36, 3.39};
106 const double tlTableS[] = {0.00e-3, 0.25e-3, 0.32e-3, 0.81e-3, 0.62e-3};
107 const double wlTableS[] = {0.00, 0.33, 0.46, 0.74, 0.30};
109 double calcPsta[5], calcTsta[5], calcWsta[5], calcTLsta[5], calcWLsta[5];
111 for (i = 0; i < 5; i++) {
112 cos_ = cos(2.0 *
PI * (doy - dminN) / 365.25);
113 calcPsta[i] = pTave[i] - pTableS[i] * cos_;
114 calcTsta[i] = tTave[i] - tTableS[i] * cos_;
115 calcWsta[i] = wTave[i] - wTableS[i] * cos_;
116 calcTLsta[i] = tlTave[i] - tlTableS[i] * cos_;
117 calcWLsta[i] = wlTave[i] - wlTableS[i] * cos_;
120 if (75.0 <= latdeg) {
124 *ltemp = calcTLsta[4];
125 *wvap = calcWLsta[4];
126 }
else if (latdeg <= 15.0) {
130 *ltemp = calcTLsta[0];
131 *wvap = calcWLsta[0];
132 }
else if (15.0 < latdeg && latdeg < 75.0) {
133 *pre =
Interp1(interval, calcPsta, 5, 5, latdeg);
134 *temp =
Interp1(interval, calcTsta, 5, 5, latdeg);
135 *wpre =
Interp1(interval, calcWsta, 5, 5, latdeg);
136 *ltemp =
Interp1(interval, calcTLsta, 5, 5, latdeg);
137 *wvap =
Interp1(interval, calcWLsta, 5, 5, latdeg);
145static double get_Tdv(
const double lat,
const double Hs,
const double Ps) {
146 return 2.2768 / (1.0 - 0.00266 * cos(2.0 * lat) - (2.8e-7) * Hs) * Ps * 0.001;
150static double get_Twv(
const double Ts,
const double es) {
return 2.2768 * (1255.0 / Ts + 0.05) * es * 0.001; }
163int get_stTv(
gtime_t t,
const double lat,
const double hs,
const double hg,
double* tdv,
double* twv) {
164 double P0, T0, e0, beta0, lambda0, Hs, Ts, Ps, es, t0, tk, tc, ET, doy;
165 const double g = 9.80665, Rd = 287.0537625;
169 if (
get_mops(lat, doy, &P0, &T0, &e0, &beta0, &lambda0)) {
175 Ts = T0 - beta0 * Hs;
176 Ps = P0 * pow(1 - beta0 * Hs / T0, g / (Rd * beta0));
177 es = e0 * pow(1 - beta0 * Hs / T0, (lambda0 + 1.0) * g / (Rd * beta0));
182 ET = 6.11 * pow(tk / t0, -5.3) * exp(25.2 * tc / tk);
188 *tdv =
get_Tdv(lat, Hs + hg, Ps);
201 int start = (network > 0 ? network : 1);
203 int inet, i, j, k, n = 0;
206 for (inet = start; inet < end; ++inet) {
209 if (fabs(-1.0 - ctx->
grid_pos[inet][i][0]) < 0.0001 && fabs(-1.0 - ctx->
grid_pos[inet][i][1]) < 0.0001 &&
210 fabs(-1.0 - ctx->
grid_pos[inet][i][2]) < 0.0001) {
214 if (fabs(ctx->
grid_pos[inet][i][2]) > 0.0001 || ctx->
grid_stat[ch][inet][i] == 0) {
226 "get_grid_index: inet=%2d, pos=%3.3f %3.3f, "
237 gridinfo[n].
index = i;
240 for (j = 0; j < n; j++) {
241 if (d < gridinfo[j].weight) {
249 gridinfo[k] = gridinfo[k - 1];
256 gridinfo[j].
index = i;
269 double dd12[2], dd13[2], dd14[2];
276 for (i = 1, gridindex[0] = &gridinfo[first_index], flag = 0; i < n; ++i) {
277 if (gridinfo[first_index].network == gridinfo[i].network && first_index != i) {
278 dd12[0] = gridinfo[i].
pos[0] *
D2R - gridinfo[first_index].
pos[0] *
D2R;
279 dd12[1] = gridinfo[i].
pos[1] *
D2R - gridinfo[first_index].
pos[1] *
D2R;
280 gridindex[1] = &gridinfo[i];
281 grid2 = &gridinfo[i];
287 trace(NULL, 2,
"can't find second grid: network=%d\n", gridinfo[first_index].network);
292 for (i = 1, flag = 0; i < n; i++) {
293 if (gridindex[1]->index == gridinfo[i].index || gridinfo[first_index].network != gridinfo[i].network ||
297 dd13[0] = gridinfo[i].
pos[0] *
D2R - gridinfo[first_index].
pos[0] *
D2R;
298 dd13[1] = gridinfo[i].
pos[1] *
D2R - gridinfo[first_index].
pos[1] *
D2R;
299 if (fabs(
dot(dd12, dd13, 2) / (
norm(dd12, 2) *
norm(dd13, 2))) < 1.0) {
300 gridindex[2] = &gridinfo[i];
301 grid3 = &gridinfo[i];
307 trace(NULL, 2,
"can't find third grid: network=%d\n", gridinfo[first_index].network);
312 for (i = 1, flag = 0; i < n; i++) {
313 if (gridindex[1]->index == gridinfo[i].index || gridindex[2]->index == gridinfo[i].index ||
314 gridinfo[first_index].network != gridinfo[i].network || first_index == i) {
317 dd14[0] = gridinfo[i].
pos[0] *
D2R - gridinfo[first_index].
pos[0] *
D2R;
318 dd14[1] = gridinfo[i].
pos[1] *
D2R - gridinfo[first_index].
pos[1] *
D2R;
319 if (fabs(
dot(dd12, dd14, 2) / (
norm(dd12, 2) *
norm(dd14, 2))) < 1.0 &&
320 fabs(
dot(dd13, dd14, 2) / (
norm(dd13, 2) *
norm(dd14, 2))) < 1.0) {
321 if ((fabs(grid2->
pos[1] - gridinfo[i].
pos[1]) < 0.04 && fabs(grid3->pos[0] - gridinfo[i].
pos[0]) < 0.04) ||
322 (fabs(grid2->
pos[0] - gridinfo[i].
pos[0]) < 0.04 && fabs(grid3->pos[1] - gridinfo[i].
pos[1]) < 0.04)) {
323 gridindex[3] = &gridinfo[i];
331 trace(NULL, 2,
"can't find fourth grid: network=%d\n", gridinfo[first_index].network);
341 double *U, *E, dd[2];
346 for (i = 1; i < 3; i++) {
347 U[(i - 1) * 2 + 0] = gridindex[i]->pos[0] - gridindex[0]->pos[0];
348 U[(i - 1) * 2 + 1] = gridindex[i]->pos[1] - gridindex[0]->pos[1];
350 trace(NULL, 5,
"Umat=\n");
354 trace(NULL, 2,
"calculation error of G inverse\n");
356 trace(NULL, 5,
"Umat=\n");
359 E[0] = pos[0] *
R2D - gridindex[0]->
pos[0];
360 E[1] = pos[1] *
R2D - gridindex[0]->
pos[1];
361 matmul(
"NN", 2, 1, 2, 1.0, U, E, 0.0, dd);
365 weight[0] = 1.0 - dd[0] - dd[1];
377 "change to the nearest grid: inet=%d, index=%d, "
378 "pos=%6.3f %6.3f %6.3f, distance=%.2fKm\n",
380 nearestgrid->
pos[2], nearestgrid->
weight / 1000.0);
381 gridindex[0] = nearestgrid;
385 "change to the nearest grid: inet=%d, index=%d, "
386 "pos=%6.3f %6.3f %6.3f, distance=%.2fKm\n",
387 gridindex[0]->network, gridindex[0]->index, gridindex[0]->pos[0], gridindex[0]->pos[1],
388 gridindex[0]->pos[2], gridindex[0]->weight / 1000.0);
401 for (i = 0; i < n; i++) {
402 sum += 1.0 / gridindex[i]->
weight;
404 for (i = 0; i < n; i++) {
405 weight[i] = 1.0 / (gridindex[i]->
weight * sum);
414 static int savenetwork[4];
415 static int saveindex[4];
416 static int savenum = -1;
420 for (i = 0; i < savenum; ++i) {
421 if (savenetwork[i] != gridindex[i]->network || saveindex[i] != gridindex[i]->index) {
426 if (savenum == n && !flag) {
430 trace(NULL, 1,
"pos est: pos=%6.3f %6.3f\n", pos[0] /
D2R, pos[1] /
D2R);
431 for (i = 0; i < n; i++) {
433 "selected_grid%d: inet=%d, weight=%.2f, "
434 "pos=%6.3f %6.3f, dist=%.2fkm, index=%d\n",
435 i + 1, gridindex[i]->network, weight[i], gridindex[i]->pos[0], gridindex[i]->pos[1],
436 gridindex[i]->weight / 1000.0, gridindex[i]->index);
439 for (i = 0; i < n; ++i) {
440 savenetwork[i] = gridindex[i]->
network;
441 saveindex[i] = gridindex[i]->
index;
465 trace(NULL, 3,
"clas_get_grid: pos=%.3f %.3f\n", pos[0] *
R2D, pos[1] *
R2D);
471 ch = nch[0] >= nch[1] ? 0 : 1;
474 if (n >= 3 && gridinfo[ch][0].network <= 12) {
475 if (gridsel == 0 || gridinfo[ch][0].weight > (
double)gridsel) {
478 gridindex[0] = &gridinfo[ch][0];
482 trace(NULL, 2,
"can't find nearby grid: rover pos=%3.3f %3.3f\n", pos[0] *
R2D, pos[1] *
R2D);
485 gridindex[0] = &gridinfo[ch][0];
495 double* U =
mat(n, n);
496 for (i = 0; i < n; i++) {
497 dlat = gridindex[i]->
pos[0] - gridindex[0]->
pos[0];
498 dlon = gridindex[i]->
pos[1] - gridindex[0]->
pos[1];
501 U[2 * n + i] = dlat * dlon;
504 trace(NULL, 5,
"Umat=\n");
508 trace(NULL, 2,
"calculation error of G inverse\n");
511 trace(NULL, 5,
"Gmat=\n");
517 dlat = pos[0] *
R2D - gridindex[0]->
pos[0];
518 dlon = pos[1] *
R2D - gridindex[0]->
pos[1];
519 grid->
Emat[0] = dlat;
520 grid->
Emat[1] = dlon;
521 grid->
Emat[2] = dlat * dlon;
525 for (i = 0; i < n; i++) {
547 for (k = flag = 0; k < stec->
n; k++) {
548 if (sat == stec->
data[k].
sat) {
554 trace(NULL, 3,
"search_data: no iono (no sat data) %s sat=%2d\n",
time_str(time, 0), sat);
560 trace(NULL, 2,
"age of ssr iono error %s sat=%2d tt=%.0f\n",
time_str(time, 0), sat, tt);
589 const double* Gmat,
const double* Emat,
double* iono,
double* rate,
double* var,
592 double *ionos, *rates, *rms, *quals;
593 double *ionos_, *rates_, *sqrms, *sqrms_, *quals_;
610 if (!
stec_data(&corr->
stec[index[0]], time, sat, iono, rate, rms, quals, &slip)) {
639 for (i = 0; i < n; i++) {
640 if (!
stec_data(&corr->
stec[index[i]], time, sat, ionos + i, rates + i, rms + i, quals + i, &slip)) {
657 *iono = *rate = *var = 0.0;
659 if (n == 4 && Gmat && Emat) {
661 for (i = 0; i < n; i++) {
662 sqrms[i] =
SQR(rms[i]);
664 matmul(
"NN", n, 1, n, 1.0, Gmat, ionos, 0.0, ionos_);
665 matmul(
"NN", n, 1, n, 1.0, Gmat, rates, 0.0, rates_);
666 matmul(
"NN", n, 1, n, 1.0, Gmat, sqrms, 0.0, sqrms_);
667 matmul(
"NN", n, 1, n, 1.0, Gmat, quals, 0.0, quals_);
668 *iono =
dot(Emat, ionos_, 4);
669 *rate =
dot(Emat, rates_, 4);
670 *var =
dot(Emat, sqrms_, 4);
673 for (i = 0; i < n; i++) {
674 *iono += ionos[i] * weight[i];
675 *rate += rates[i] * weight[i];
676 *var +=
SQR(rms[i]) * weight[i];
701 double tdvd, twvd, gh, pos[2];
711 trace(NULL, 2,
"age of ssr trop error %s tt=%.0f idx=%d\n",
time_str(time, 0), tt, idx);
718 if (
get_stTv(time, pos[0], 0.0, gh, &tdvd, &twvd)) {
723 trace(NULL, 2,
"invalid trop correction %s ztd=%.2f zwd=%.2f\n",
time_str(time, 0), z->
data[k].
ztd,
750 const double* Gmat,
const double* Emat,
double* zwd,
double* ztd,
int* tbrk) {
751 int i, *valid, valid_ = 0, ret = 0;
752 double *zwds, *ztds, *zwds_, *ztds_, *quals, *quals_;
764 ret =
trop_data(&corr->
zwd[index[0]], time, ztd, zwd, quals, index[0], valid);
773 for (i = 0; i < n; i++) {
774 if (!
trop_data(&corr->
zwd[index[i]], time, ztds + i, zwds + i, quals + i, index[i], valid + i)) {
785 if (n == 4 && Gmat && Emat) {
790 matmul(
"NN", n, 1, n, 1.0, Gmat, ztds, 0.0, ztds_);
791 matmul(
"NN", n, 1, n, 1.0, Gmat, zwds, 0.0, zwds_);
792 matmul(
"NN", n, 1, n, 1.0, Gmat, quals, 0.0, quals_);
793 *ztd =
dot(Emat, ztds_, 4);
794 *zwd =
dot(Emat, zwds_, 4);
800 for (i = 0; i < n; i++) {
801 *zwd += zwds[i] * weight[i];
802 *ztd += ztds[i] * weight[i];
806 for (i = 0; i < n; i++) {
809 *tbrk = valid_ == n ? 0 : 1;
841 char buff[256], *str, *str2;
844 trace(NULL, 3,
"readblqgrid: file=%s\n", file);
846 if (!(fp = fopen(file,
"r"))) {
847 trace(NULL, 2,
"blq grid file open error: file=%s\n", file);
850 while (fgets(buff,
sizeof(buff), fp)) {
851 if (!strncmp(buff,
"$$", 2) || strlen(buff) < 2) {
856 str = strtok(buff,
"-");
861 str = strtok(NULL,
"-");
868 trace(NULL, 1,
"readblqgrid: net/grid overflow [%d-%d]\n", net, gridno);
873 for (i = 0; i < 3; i++) {
874 if (!fgets(buff,
sizeof(buff), fp)) {
884 str = strtok(buff,
":");
885 str = strtok(NULL,
":");
887 str2 = strtok(str,
" ");
889 ctx->
oload[net - 1].
pos[gridno - 1][0] = atof(str2);
891 str2 = strtok(NULL,
" ");
893 ctx->
oload[net - 1].
pos[gridno - 1][1] = atof(str2);
899 trace(NULL, 1,
"readblqgrid: format error at net=%d grid=%d\n", net, gridno);
907 trace(NULL, 3,
"readblqgrid: loaded grid OTL data\n");
CLAS (QZSS L6D) CSSR decoder and grid correction type definitions.
#define CSSR_INVALID_VALUE
static void calc_3points_weight(double *weight, const double *pos, grid_info **gridindex)
int clas_trop_grid_data(clas_corr_t *corr, const int *index, gtime_t time, int n, const double *weight, const double *Gmat, const double *Emat, double *zwd, double *ztd, int *tbrk)
Interpolate troposphere delay from grid points.
static int trop_data(zwd_t *z, gtime_t time, double *ztd, double *zwd, double *quality, int idx, int *valid)
void clas_init_oload(clas_ctx_t *ctx)
Initialize ocean loading data in context.
static int find_grid_surround_pos(grid_info **gridindex, int n, grid_info *gridinfo)
static int pickup_candidates_of_grid(const clas_ctx_t *ctx, grid_info *gridinfo, const int network, const double *pos, int ch)
static double get_Twv(const double Ts, const double es)
static void output_selected_grid(const double *pos, int n, grid_info **gridindex, double *weight)
static double get_Tdv(const double lat, const double Hs, const double Ps)
int clas_get_grid_index(clas_ctx_t *ctx, const double *pos, clas_grid_t *grid, int gridsel, gtime_t obstime)
Select surrounding grid points and compute interpolation weights.
static int stec_data(stec_t *stec, gtime_t time, int sat, double *iono, double *rate, double *rms, double *quality, int *slip)
int readblqgrid(const char *file, clas_ctx_t *ctx)
Read BLQ ocean tide loading parameters for CLAS grid points.
static int get_mops(const double lat, const double doy, double *pre, double *temp, double *wpre, double *ltemp, double *wvap)
int clas_stec_grid_data(clas_corr_t *corr, const int *index, gtime_t time, int sat, int n, const double *weight, const double *Gmat, const double *Emat, double *iono, double *rate, double *var, int *brk)
Interpolate STEC (ionosphere delay) from grid points.
static double Interp1(const double *x, const double *y, int nx, int ny, double xi)
static void calc_grid_weight(double *weight, const double *pos, int n, grid_info **gridindex)
static int is_exists_inside(const double *pos, int n, grid_info **gridindex, grid_info *nearestgrid)
int get_stTv(gtime_t t, const double lat, const double hs, const double hg, double *tdv, double *twv)
MRTKLIB Constants — Physical, navigation, and system constants.
double geoidh(const double *pos)
Get geoid height from geoid model.
MRTKLIB Geoid Module — Geoid height models.
double * mat(int n, int m)
Allocate memory for a double matrix.
int matinv(double *A, int n)
Inverse of matrix (A = A^-1).
void matcpy(double *A, const double *B, int n, int m)
Copy matrix.
int * imat(int n, int m)
Allocate memory for an integer matrix.
double norm(const double *a, int n)
Euclidean norm of vector.
void matmul(const char *tr, int n, int k, int m, double alpha, const double *A, const double *B, double beta, double *C)
Multiply matrix by matrix (C = alpha*A*B + beta*C).
double dot(const double *a, const double *b, int n)
Inner product of vectors.
MRTKLIB Matrix Module — Matrix/vector operations and estimation.
int readblqrecord(FILE *fp, double *odisp)
Read a single BLQ record (6 lines x 11 values).
MRTKLIB Station Module — Site environment parameter I/O.
double timediff(gtime_t t1, gtime_t t2)
Compute time difference (t1 - t2).
double time2doy(gtime_t t)
Convert time to day of year.
char * time_str(gtime_t t, int n)
Get time string (not reentrant).
MRTKLIB Time Module — GNSS time types and conversion functions.
void tracemat(mrtk_ctx_t *ctx, int level, const double *A, int n, int m, int p, int q)
Output trace matrix.
void trace(mrtk_ctx_t *ctx, int level, const char *format,...)
Output trace message.
MRTKLIB Trace Module — debug trace and logging functions.
double grid_pos[13][80][3]
GNSS time representation.