MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_tides.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_tides.c : tide displacement 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_tides.c
18 * @brief MRTKLIB Tides Module — Tidal displacement corrections.
19 *
20 * options : -DIERS_MODEL use IERS tide model
21 *
22 * references :
23 * [1] D.D.McCarthy, IERS Technical Note 21, IERS Conventions 1996, July 1996
24 * [2] D.D.McCarthy and G.Petit, IERS Technical Note 32, IERS Conventions
25 * 2003, November 2003
26 * [3] D.A.Vallado, Fundamentals of Astrodynamics and Applications 2nd ed,
27 * Space Technology Library, 2004
28 * [4] J.Kouba, A Guide to using International GNSS Service (IGS) products,
29 * May 2009
30 * [5] G.Petit and B.Luzum (eds), IERS Technical Note No. 36, IERS
31 * Conventions (2010), 2010
32 */
33#include "mrtklib/mrtk_tides.h"
34
35#include <math.h>
36
37#include "mrtklib/mrtk_astro.h"
38#include "mrtklib/mrtk_coords.h"
39#include "mrtklib/mrtk_mat.h"
40#include "mrtklib/mrtk_trace.h"
41
42/*--- local constants (duplicated to avoid rtklib.h dependency) -------------*/
43static const double PI = 3.1415926535897932;
44static const double D2R = 3.1415926535897932 / 180.0;
45static const double R2D = 180.0 / 3.1415926535897932;
46static const double RE_WGS84 = 6378137.0;
47
48/*--- forward declarations for legacy functions resolved at link time -------*/
49
50#define SQR(x) ((x) * (x))
51
52#define AS2R (D2R / 3600.0) /* arc sec to radian */
53#define GME 3.986004415E+14 /* earth gravitational constant */
54#define GMS 1.327124E+20 /* sun gravitational constant */
55#define GMM 4.902801E+12 /* moon gravitational constant */
56
57/* function prototypes -------------------------------------------------------*/
58#ifdef IERS_MODEL
59extern int dehanttideinel_(double* xsta, int* year, int* mon, int* day, double* fhr, double* xsun, double* xmon,
60 double* dxtide);
61#endif
62
63/* solar/lunar tides (ref [2] 7) ---------------------------------------------*/
64#ifndef IERS_MODEL
65static void tide_pl(const double* eu, const double* rp, double GMp, const double* pos, double* dr) {
66 const double H3 = 0.292, L3 = 0.015;
67 double r, ep[3], latp, lonp, p, K2, K3, a, H2, L2, dp, du, cosp, sinl, cosl;
68 int i;
69
70 trace(NULL, 4, "tide_pl : pos=%.3f %.3f\n", pos[0] * R2D, pos[1] * R2D);
71
72 if ((r = norm(rp, 3)) <= 0.0) {
73 return;
74 }
75
76 for (i = 0; i < 3; i++) {
77 ep[i] = rp[i] / r;
78 }
79
80 K2 = GMp / GME * SQR(RE_WGS84) * SQR(RE_WGS84) / (r * r * r);
81 K3 = K2 * RE_WGS84 / r;
82 latp = asin(ep[2]);
83 lonp = atan2(ep[1], ep[0]);
84 cosp = cos(latp);
85 sinl = sin(pos[0]);
86 cosl = cos(pos[0]);
87
88 /* step1 in phase (degree 2) */
89 p = (3.0 * sinl * sinl - 1.0) / 2.0;
90 H2 = 0.6078 - 0.0006 * p;
91 L2 = 0.0847 + 0.0002 * p;
92 a = dot(ep, eu, 3);
93 dp = K2 * 3.0 * L2 * a;
94 du = K2 * (H2 * (1.5 * a * a - 0.5) - 3.0 * L2 * a * a);
95
96 /* step1 in phase (degree 3) */
97 dp += K3 * L3 * (7.5 * a * a - 1.5);
98 du += K3 * (H3 * (2.5 * a * a * a - 1.5 * a) - L3 * (7.5 * a * a - 1.5) * a);
99
100 /* step1 out-of-phase (only radial) */
101 du += 3.0 / 4.0 * 0.0025 * K2 * sin(2.0 * latp) * sin(2.0 * pos[0]) * sin(pos[1] - lonp);
102 du += 3.0 / 4.0 * 0.0022 * K2 * cosp * cosp * cosl * cosl * sin(2.0 * (pos[1] - lonp));
103
104 dr[0] = dp * ep[0] + du * eu[0];
105 dr[1] = dp * ep[1] + du * eu[1];
106 dr[2] = dp * ep[2] + du * eu[2];
107
108 trace(NULL, 5, "tide_pl : dr=%.3f %.3f %.3f\n", dr[0], dr[1], dr[2]);
109}
110/* displacement by solid earth tide (ref [2] 7) ------------------------------*/
111static void tide_solid(const double* rsun, const double* rmoon, const double* pos, const double* E, double gmst,
112 int opt, double* dr) {
113 double dr1[3], dr2[3], eu[3], du, dn, sinl, sin2l;
114
115 trace(NULL, 3, "tide_solid: pos=%.3f %.3f opt=%d\n", pos[0] * R2D, pos[1] * R2D, opt);
116
117 /* step1: time domain */
118 eu[0] = E[2];
119 eu[1] = E[5];
120 eu[2] = E[8];
121 tide_pl(eu, rsun, GMS, pos, dr1);
122 tide_pl(eu, rmoon, GMM, pos, dr2);
123
124 /* step2: frequency domain, only K1 radial */
125 sin2l = sin(2.0 * pos[0]);
126 du = -0.012 * sin2l * sin(gmst + pos[1]);
127
128 dr[0] = dr1[0] + dr2[0] + du * E[2];
129 dr[1] = dr1[1] + dr2[1] + du * E[5];
130 dr[2] = dr1[2] + dr2[2] + du * E[8];
131
132 /* eliminate permanent deformation */
133 if (opt & 8) {
134 sinl = sin(pos[0]);
135 du = 0.1196 * (1.5 * sinl * sinl - 0.5);
136 dn = 0.0247 * sin2l;
137 dr[0] += du * E[2] + dn * E[1];
138 dr[1] += du * E[5] + dn * E[4];
139 dr[2] += du * E[8] + dn * E[7];
140 }
141 trace(NULL, 5, "tide_solid: dr=%.3f %.3f %.3f\n", dr[0], dr[1], dr[2]);
142}
143#endif /* !IERS_MODEL */
144
145/* displacement by ocean tide loading (ref [2] 7) ----------------------------*/
146extern void tide_oload(gtime_t tut, const double* odisp, double* denu) {
147 const double args[][5] = {
148 {1.40519E-4, 2.0, -2.0, 0.0, 0.00}, /* M2 */
149 {1.45444E-4, 0.0, 0.0, 0.0, 0.00}, /* S2 */
150 {1.37880E-4, 2.0, -3.0, 1.0, 0.00}, /* N2 */
151 {1.45842E-4, 2.0, 0.0, 0.0, 0.00}, /* K2 */
152 {0.72921E-4, 1.0, 0.0, 0.0, 0.25}, /* K1 */
153 {0.67598E-4, 1.0, -2.0, 0.0, -0.25}, /* O1 */
154 {0.72523E-4, -1.0, 0.0, 0.0, -0.25}, /* P1 */
155 {0.64959E-4, 1.0, -3.0, 1.0, -0.25}, /* Q1 */
156 {0.53234E-5, 0.0, 2.0, 0.0, 0.00}, /* Mf */
157 {0.26392E-5, 0.0, 1.0, -1.0, 0.00}, /* Mm */
158 {0.03982E-5, 2.0, 0.0, 0.0, 0.00} /* Ssa */
159 };
160 const double ep1975[] = {1975, 1, 1, 0, 0, 0};
161 double ep[6], fday, days, t, t2, t3, a[5], ang, dp[3] = {0};
162 int i, j;
163
164 trace(NULL, 3, "tide_oload:\n");
165
166 /* angular argument: see subroutine arg.f for reference [1] */
167 time2epoch(tut, ep);
168 fday = ep[3] * 3600.0 + ep[4] * 60.0 + ep[5];
169 ep[3] = ep[4] = ep[5] = 0.0;
170 days = timediff(epoch2time(ep), epoch2time(ep1975)) / 86400.0 + 1.0;
171 t = (27392.500528 + 1.000000035 * days) / 36525.0;
172 t2 = t * t;
173 t3 = t2 * t;
174
175 a[0] = fday;
176 a[1] = (279.69668 + 36000.768930485 * t + 3.03E-4 * t2) * D2R; /* H0 */
177 a[2] = (270.434358 + 481267.88314137 * t - 0.001133 * t2 + 1.9E-6 * t3) * D2R; /* S0 */
178 a[3] = (334.329653 + 4069.0340329577 * t - 0.010325 * t2 - 1.2E-5 * t3) * D2R; /* P0 */
179 a[4] = 2.0 * PI;
180
181 /* displacements by 11 constituents */
182 for (i = 0; i < 11; i++) {
183 ang = 0.0;
184 for (j = 0; j < 5; j++) {
185 ang += a[j] * args[i][j];
186 }
187 for (j = 0; j < 3; j++) {
188 dp[j] += odisp[j + i * 6] * cos(ang - odisp[j + 3 + i * 6] * D2R);
189 }
190 }
191 denu[0] = -dp[1];
192 denu[1] = -dp[2];
193 denu[2] = dp[0];
194
195 trace(NULL, 5, "tide_oload: denu=%.3f %.3f %.3f\n", denu[0], denu[1], denu[2]);
196}
197/* iers mean pole (ref [7] eq.7.25) ------------------------------------------*/
198static void iers_mean_pole(gtime_t tut, double* xp_bar, double* yp_bar) {
199 const double ep2000[] = {2000, 1, 1, 0, 0, 0};
200 double y, y2, y3;
201
202 y = timediff(tut, epoch2time(ep2000)) / 86400.0 / 365.25;
203
204 if (y < 3653.0 / 365.25) { /* until 2010.0 */
205 y2 = y * y;
206 y3 = y2 * y;
207 *xp_bar = 55.974 + 1.8243 * y + 0.18413 * y2 + 0.007024 * y3; /* (mas) */
208 *yp_bar = 346.346 + 1.7896 * y - 0.10729 * y2 - 0.000908 * y3;
209 } else { /* after 2010.0 */
210 *xp_bar = 23.513 + 7.6141 * y; /* (mas) */
211 *yp_bar = 358.891 - 0.6287 * y;
212 }
213}
214/* displacement by pole tide (ref [7] eq.7.26) --------------------------------*/
215static void tide_pole(gtime_t tut, const double* pos, const double* erpv, double* denu) {
216 double xp_bar, yp_bar, m1, m2, cosl, sinl;
217
218 trace(NULL, 3, "tide_pole: pos=%.3f %.3f\n", pos[0] * R2D, pos[1] * R2D);
219
220 /* iers mean pole (mas) */
221 iers_mean_pole(tut, &xp_bar, &yp_bar);
222
223 /* ref [7] eq.7.24 */
224 m1 = erpv[0] / AS2R - xp_bar * 1E-3; /* (as) */
225 m2 = -erpv[1] / AS2R + yp_bar * 1E-3;
226
227 /* sin(2*theta) = sin(2*phi), cos(2*theta)=-cos(2*phi) */
228 cosl = cos(pos[1]);
229 sinl = sin(pos[1]);
230 denu[0] = 9E-3 * sin(pos[0]) * (m1 * sinl - m2 * cosl); /* de= Slambda (m) */
231 denu[1] = -9E-3 * cos(2.0 * pos[0]) * (m1 * cosl + m2 * sinl); /* dn=-Stheta (m) */
232 denu[2] = -33E-3 * sin(2.0 * pos[0]) * (m1 * cosl + m2 * sinl); /* du= Sr (m) */
233
234 trace(NULL, 5, "tide_pole : denu=%.3f %.3f %.3f\n", denu[0], denu[1], denu[2]);
235}
236/* tidal displacement ----------------------------------------------------------
237 * displacements by earth tides
238 * args : gtime_t tutc I time in utc
239 * double *rr I site position (ecef) (m)
240 * int opt I options (or of the followings)
241 * 1: solid earth tide
242 * 2: ocean tide loading
243 * 4: pole tide
244 * 8: elimate permanent deformation
245 * double *erp I earth rotation parameters (NULL: not used)
246 * double *odisp I ocean loading parameters (NULL: not used)
247 * odisp[0+i*6]: consituent i amplitude radial(m)
248 * odisp[1+i*6]: consituent i amplitude west (m)
249 * odisp[2+i*6]: consituent i amplitude south (m)
250 * odisp[3+i*6]: consituent i phase radial (deg)
251 * odisp[4+i*6]: consituent i phase west (deg)
252 * odisp[5+i*6]: consituent i phase south (deg)
253 * (i=0:M2,1:S2,2:N2,3:K2,4:K1,5:O1,6:P1,7:Q1,
254 * 8:Mf,9:Mm,10:Ssa)
255 * double *dr O displacement by earth tides (ecef) (m)
256 * return : none
257 * notes : see ref [1], [2] chap 7
258 * see ref [4] 5.2.1, 5.2.2, 5.2.3
259 * ver.2.4.0 does not use ocean loading and pole tide corrections
260 *-----------------------------------------------------------------------------*/
261void tidedisp(gtime_t tutc, const double* rr, int opt, const erp_t* erp, const double* odisp, double* dr) {
262 gtime_t tut;
263 double pos[2], E[9], drt[3], denu[3], rs[3], rm[3], gmst, erpv[5] = {0};
264 int i;
265#ifdef IERS_MODEL
266 double ep[6], fhr;
267 int year, mon, day;
268#endif
269
270 trace(NULL, 3, "tidedisp: tutc=%s\n", time_str(tutc, 0));
271
272 if (erp) {
273 geterp(erp, utc2gpst(tutc), erpv);
274 }
275 tut = timeadd(tutc, erpv[2]);
276
277 dr[0] = dr[1] = dr[2] = 0.0;
278
279 if (norm(rr, 3) <= 0.0) {
280 return;
281 }
282
283 pos[0] = asin(rr[2] / norm(rr, 3));
284 pos[1] = atan2(rr[1], rr[0]);
285 xyz2enu(pos, E);
286
287 if (opt & 1) { /* solid earth tides */
288
289 /* sun and moon position in ecef */
290 sunmoonpos(tutc, erpv, rs, rm, &gmst);
291
292#ifdef IERS_MODEL
293 time2epoch(tutc, ep);
294 year = (int)ep[0];
295 mon = (int)ep[1];
296 day = (int)ep[2];
297 fhr = ep[3] + ep[4] / 60.0 + ep[5] / 3600.0;
298
299 /* call DEHANTTIDEINEL */
300 dehanttideinel_((double*)rr, &year, &mon, &day, &fhr, rs, rm, drt);
301#else
302 tide_solid(rs, rm, pos, E, gmst, opt, drt);
303#endif
304 for (i = 0; i < 3; i++) {
305 dr[i] += drt[i];
306 }
307 }
308 if ((opt & 2) && odisp) { /* ocean tide loading */
309 tide_oload(tut, odisp, denu);
310 matmul("TN", 3, 1, 3, 1.0, E, denu, 0.0, drt);
311 for (i = 0; i < 3; i++) {
312 dr[i] += drt[i];
313 }
314 }
315 if ((opt & 4) && erp) { /* pole tide */
316 tide_pole(tut, pos, erpv, denu);
317 matmul("TN", 3, 1, 3, 1.0, E, denu, 0.0, drt);
318 for (i = 0; i < 3; i++) {
319 dr[i] += drt[i];
320 }
321 }
322 trace(NULL, 5, "tidedisp: dr=%.3f %.3f %.3f\n", dr[0], dr[1], dr[2]);
323}
void sunmoonpos(gtime_t tutc, const double *erpv, double *rsun, double *rmoon, double *gmst)
Compute sun and moon position in ECEF.
Definition mrtk_astro.c:135
MRTKLIB Astronomy Module — Sun and moon position computation.
#define GME
#define D2R
Definition mrtk_coords.c:36
#define PI
Definition mrtk_coords.c:35
void xyz2enu(const double *pos, double *E)
Compute ECEF to local coordinate transformation matrix.
#define RE_WGS84
Definition mrtk_coords.c:38
#define AS2R
Definition mrtk_coords.c:37
MRTKLIB Coordinates Module — Coordinate transformations and geometry.
double norm(const double *a, int n)
Euclidean norm of vector.
Definition mrtk_mat.c:165
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).
Definition mrtk_mat.c:310
double dot(const double *a, const double *b, int n)
Inner product of vectors.
Definition mrtk_mat.c:151
MRTKLIB Matrix Module — Matrix/vector operations and estimation.
#define R2D
Definition mrtk_obs.c:51
int geterp(const erp_t *erp, gtime_t time, double *erpv)
Get earth rotation parameter values at specified time.
Definition mrtk_peph.c:146
static void tide_pole(gtime_t tut, const double *pos, const double *erpv, double *denu)
Definition mrtk_tides.c:215
#define GMM
Definition mrtk_tides.c:55
static void iers_mean_pole(gtime_t tut, double *xp_bar, double *yp_bar)
Definition mrtk_tides.c:198
static void tide_solid(const double *rsun, const double *rmoon, const double *pos, const double *E, double gmst, int opt, double *dr)
Definition mrtk_tides.c:111
void tidedisp(gtime_t tutc, const double *rr, int opt, const erp_t *erp, const double *odisp, double *dr)
Compute displacements by earth tides.
Definition mrtk_tides.c:261
static void tide_pl(const double *eu, const double *rp, double GMp, const double *pos, double *dr)
Definition mrtk_tides.c:65
void tide_oload(gtime_t tut, const double *odisp, double *denu)
Compute displacement by ocean tide loading (11 constituents).
Definition mrtk_tides.c:146
#define SQR(x)
Definition mrtk_tides.c:50
#define GMS
Definition mrtk_tides.c:54
MRTKLIB Tides Module — Tidal displacement corrections.
gtime_t epoch2time(const double *ep)
Convert calendar day/time to gtime_t struct.
Definition mrtk_time.c:113
void time2epoch(gtime_t t, double *ep)
Convert gtime_t struct to calendar day/time.
Definition mrtk_time.c:136
double timediff(gtime_t t1, gtime_t t2)
Compute time difference (t1 - t2).
Definition mrtk_time.c:279
gtime_t timeadd(gtime_t t, double sec)
Add seconds to gtime_t.
Definition mrtk_time.c:265
char * time_str(gtime_t t, int n)
Get time string (not reentrant).
Definition mrtk_time.c:530
gtime_t utc2gpst(gtime_t t)
Convert UTC to GPS time considering leap seconds.
Definition mrtk_time.c:440
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.
ERP (earth rotation parameter) type.
Definition mrtk_peph.h:59
GNSS time representation.
Definition mrtk_time.h:49