35#define PI 3.1415926535897932
36#define D2R (PI / 180.0)
37#define R2D (180.0 / PI)
38#define CLIGHT 299792458.0
39#define RE_WGS84 6378137.0
47extern int gmf_(
double* mjd,
double* lat,
double* lon,
double* hgt,
double* zd,
double* gmfh,
double* gmfw);
48extern double geoidh(
const double* pos);
63extern double ionmodel(
gtime_t t,
const double* ion,
const double* pos,
const double* azel) {
64 const double ion_default[] = {
66 0.1118E-07, -0.7451E-08, -0.5961E-07, 0.1192E-06, 0.1167E+06, -0.2294E+06, -0.1311E+06, 0.1049E+07};
67 double tt, f, psi, phi, lam, amp, per, x;
70 if (pos[2] < -1E3 || azel[1] <= 0) {
73 if (
norm(ion, 8) <= 0.0) {
78 psi = 0.0137 / (azel[1] /
PI + 0.11) - 0.022;
81 phi = pos[0] /
PI + psi * cos(azel[0]);
84 }
else if (phi < -0.416) {
87 lam = pos[1] /
PI + psi * sin(azel[0]) / cos(phi *
PI);
90 phi += 0.064 * cos((lam - 1.617) *
PI);
94 tt -= floor(tt / 86400.0) * 86400.0;
97 f = 1.0 + 16.0 * pow(0.53 - azel[1] /
PI, 3.0);
100 amp = ion[0] + phi * (ion[1] + phi * (ion[2] + phi * ion[3]));
101 per = ion[4] + phi * (ion[5] + phi * (ion[6] + phi * ion[7]));
102 amp = amp < 0.0 ? 0.0 : amp;
103 per = per < 72000.0 ? 72000.0 : per;
104 x = 2.0 *
PI * (tt - 50400.0) / per;
106 return CLIGHT * f * (fabs(x) < 1.57 ? 5E-9 + amp * (1.0 + x * x * (-0.5 + x * x / 24.0)) : 5E-9);
114extern double ionmapf(
const double* pos,
const double* azel) {
115 if (pos[2] >=
HION) {
131extern double ionppp(
const double* pos,
const double* azel,
double re,
double hion,
double* posp) {
132 double cosaz, rp, ap, sinap, tanap;
134 rp = re / (re + hion) * cos(azel[1]);
135 ap =
PI / 2.0 - azel[1] - asin(rp);
138 cosaz = cos(azel[0]);
139 posp[0] = asin(sin(pos[0]) * cos(ap) + cos(pos[0]) * sinap * cosaz);
141 if ((pos[0] > 70.0 *
D2R && tanap * cosaz > tan(
PI / 2.0 - pos[0])) ||
142 (pos[0] < -70.0 *
D2R && -tanap * cosaz > tan(
PI / 2.0 + pos[0]))) {
143 posp[1] = pos[1] +
PI - asin(sinap * sin(azel[0]) / cos(posp[0]));
145 posp[1] = pos[1] + asin(sinap * sin(azel[0]) / cos(posp[0]));
147 return 1.0 / sqrt(1.0 - rp * rp);
163 const double temp0 = 15.0;
164 double hgt, pres, temp, e, z, trph, trpw;
166 if (pos[2] < -100.0 || 1E4 < pos[2] || azel[1] <= 0) {
171 hgt = pos[2] < 0.0 ? 0.0 : pos[2];
173 pres = 1013.25 * pow(1.0 - 2.2557E-5 * hgt, 5.2568);
174 temp = temp0 - 6.5E-3 * hgt + 273.16;
175 e = 6.108 * humi * exp((17.15 * temp - 4684.0) / (temp - 38.45));
178 z =
PI / 2.0 - azel[1];
179 trph = 0.0022768 * pres / (1.0 - 0.00266 * cos(2.0 * pos[0]) - 0.00028 * hgt / 1E3) / cos(z);
180 trpw = 0.002277 * (1255.0 / temp + 0.05) * e / cos(z);
185static double interpc(
const double coef[],
double lat) {
186 int i = (int)(lat / 15.0);
192 return coef[i - 1] * (1.0 - lat / 15.0 + i) + coef[i] * (lat / 15.0 - i);
194static double mapf(
double el,
double a,
double b,
double c) {
195 double sinel = sin(el);
196 return (1.0 + a / (1.0 + b / (1.0 + c))) / (sinel + (a / (sinel + b / (sinel + c))));
198static double nmf(
gtime_t time,
const double pos[],
const double azel[],
double* mapfw) {
201 const double coef[][5] = {{1.2769934E-3, 1.2683230E-3, 1.2465397E-3, 1.2196049E-3, 1.2045996E-3},
202 {2.9153695E-3, 2.9152299E-3, 2.9288445E-3, 2.9022565E-3, 2.9024912E-3},
203 {62.610505E-3, 62.837393E-3, 63.721774E-3, 63.824265E-3, 64.258455E-3},
205 {0.0000000E-0, 1.2709626E-5, 2.6523662E-5, 3.4000452E-5, 4.1202191E-5},
206 {0.0000000E-0, 2.1414979E-5, 3.0160779E-5, 7.2562722E-5, 11.723375E-5},
207 {0.0000000E-0, 9.0128400E-5, 4.3497037E-5, 84.795348E-5, 170.37206E-5},
209 {5.8021897E-4, 5.6794847E-4, 5.8118019E-4, 5.9727542E-4, 6.1641693E-4},
210 {1.4275268E-3, 1.5138625E-3, 1.4572752E-3, 1.5007428E-3, 1.7599082E-3},
211 {4.3472961E-2, 4.6729510E-2, 4.3908931E-2, 4.4626982E-2, 5.4736038E-2}};
212 const double aht[] = {2.53E-5, 5.49E-3, 1.14E-3};
214 double y, cosy, ah[3], aw[3], dm, el = azel[1], lat = pos[0] *
R2D, hgt = pos[2];
224 y = (
time2doy(time) - 28.0) / 365.25 + (lat < 0.0 ? 0.5 : 0.0);
226 cosy = cos(2.0 *
PI * y);
229 for (i = 0; i < 3; i++) {
231 aw[i] =
interpc(coef[i + 6], lat);
234 dm = (1.0 / sin(el) -
mapf(el, aht[0], aht[1], aht[2])) * hgt / 1E3;
237 *mapfw =
mapf(el, aw[0], aw[1], aw[2]);
240 return mapf(el, ah[0], ah[1], ah[2]) + dm;
256extern double tropmapf(
gtime_t time,
const double pos[],
const double azel[],
double* mapfw) {
258 const double ep[] = {2000, 1, 1, 12, 0, 0};
259 double mjd, lat, lon, hgt, zd, gmfh, gmfw;
261 trace(NULL, 4,
"tropmapf: pos=%10.6f %11.6f %6.1f azel=%5.1f %4.1f\n", pos[0] *
R2D, pos[1] *
R2D, pos[2],
262 azel[0] *
R2D, azel[1] *
R2D);
264 if (pos[2] < -1000.0 || pos[2] > 20000.0) {
274 hgt = pos[2] -
geoidh(pos);
275 zd =
PI / 2.0 - azel[1];
278 gmf_(&mjd, &lat, &lon, &hgt, &zd, &gmfh, &gmfw);
280 if (mapfw) *mapfw = gmfw;
283 return nmf(time, pos, azel, mapfw);
291#define SQR(x) ((x) * (x))
310int ionocorr(
gtime_t time,
const nav_t* nav,
int sat,
const double* pos,
const double* azel,
int ionoopt,
double* ion,
312 trace(NULL, 4,
"ionocorr: time=%s opt=%d sat=%2d pos=%.3f %.3f azel=%.3f %.3f\n",
time_str(time, 3), ionoopt, sat,
313 pos[0] *
R2D, pos[1] *
R2D, azel[0] *
R2D, azel[1] *
R2D);
323 return sbsioncorr(time, nav, pos, azel, ion, var);
327 return iontec(time, nav, pos, azel, 1, ion, var);
352 trace(NULL, 4,
"tropcorr: time=%s opt=%d pos=%.3f %.3f azel=%.3f %.3f\n",
time_str(time, 3), tropopt, pos[0] *
R2D,
353 pos[1] *
R2D, azel[0] *
R2D, azel[1] *
R2D);
double tropmodel(gtime_t time, const double *pos, const double *azel, double humi)
Compute tropospheric delay by standard atmosphere and Saastamoinen.
int ionocorr(gtime_t time, const nav_t *nav, int sat, const double *pos, const double *azel, int ionoopt, double *ion, double *var)
Compute ionospheric correction.
static double mapf(double el, double a, double b, double c)
double ionmodel(gtime_t t, const double *ion, const double *pos, const double *azel)
Compute ionospheric delay by broadcast ionosphere model (Klobuchar).
static double interpc(const double coef[], double lat)
static double nmf(gtime_t time, const double pos[], const double azel[], double *mapfw)
double tropmapf(gtime_t time, const double pos[], const double azel[], double *mapfw)
double ionppp(const double *pos, const double *azel, double re, double hion, double *posp)
Compute ionospheric pierce point (IPP) position and slant factor.
double ionmapf(const double *pos, const double *azel)
Compute ionospheric delay mapping function by single layer model.
int tropcorr(gtime_t time, const nav_t *nav, const double *pos, const double *azel, int tropopt, double *trp, double *var)
Compute tropospheric correction.
MRTKLIB Atmosphere Module — Ionospheric and tropospheric models.
double geoidh(const double *pos)
Get geoid height from geoid model.
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.
MRTKLIB IONEX Module — IONEX ionospheric TEC map I/O and interpolation.
double norm(const double *a, int n)
Euclidean norm of vector.
int sbsioncorr(gtime_t time, const nav_t *nav, const double *pos, const double *azel, double *delay, double *var)
SBAS ionospheric delay correction.
double sbstropcorr(gtime_t time, const double *pos, const double *azel, double *var)
SBAS tropospheric delay correction.
MRTKLIB SBAS Module — SBAS message decoding and corrections.
gtime_t epoch2time(const double *ep)
Convert calendar day/time to gtime_t struct.
double timediff(gtime_t t1, gtime_t t2)
Compute time difference (t1 - t2).
double time2gpst(gtime_t t, int *week)
Convert gtime_t to GPS week/tow.
double time2doy(gtime_t t)
Convert time to day of year.
char * time_str(gtime_t t, int n)
Get time string (not reentrant).
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.