MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_peph.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_peph.c : precise ephemeris and earth rotation parameter 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_peph.c
18 * @brief MRTKLIB Precise Ephemeris Module — Earth rotation parameter I/O,
19 * precise ephemeris/clock computation, and satellite antenna offset
20 * functions.
21 *
22 * This file contains the ERP functions extracted from rtkcmn.c, plus all
23 * precise ephemeris functions absorbed from preceph.c with zero algorithmic
24 * changes (pure cut-and-paste).
25 */
26#include "mrtklib/mrtk_peph.h"
27
28#include <stdio.h>
29#include <stdlib.h>
30
32#include "mrtklib/mrtk_astro.h"
33#include "mrtklib/mrtk_mat.h"
34#include "mrtklib/mrtk_nav.h"
35#include "mrtklib/mrtk_sys.h"
36
37/* forward declarations for functions in mrtk_nav.c */
38extern int satsys_bd2(int sat, int* prn);
39extern int freq_idx2freq_num(int sys, int freq_idx);
40extern double freq_num2freq(int sys, int freq_num, int fcn);
41extern int freq_idx2ant_idx(int sys, int freq_idx);
42#include <math.h>
43#include <string.h>
44
45#include "mrtklib/mrtk_trace.h"
46
47/*============================================================================
48 * Constants (duplicated from rtklib.h to avoid header dependency)
49 *===========================================================================*/
50
51#define PI 3.1415926535897932 /* pi */
52#define D2R (PI / 180.0) /* deg to rad */
53#define AS2R (D2R / 3600.0) /* arc sec to radian */
54#define CLIGHT 299792458.0 /* speed of light (m/s) */
55#define OMGE 7.2921151467E-5 /* earth angular velocity (IS-GPS) (rad/s) */
56
57#define SQR(x) ((x) * (x))
58
59/* navigation system identifiers */
60#define SYS_NONE 0x00
61#define SYS_GPS 0x01
62#define SYS_SBS 0x02
63#define SYS_GLO 0x04
64#define SYS_GAL 0x08
65#define SYS_QZS 0x10
66#define SYS_CMP 0x20
67#define SYS_IRN 0x40
68#define SYS_LEO 0x80
69
70/* carrier frequencies */
71#define FREQ1 1.57542E9 /* L1/E1/B1C frequency (Hz) */
72#define FREQ2 1.22760E9 /* L2 frequency (Hz) */
73#define FREQ5 1.17645E9 /* L5/E5a/B2a frequency (Hz) */
74#define FREQ7 1.20714E9 /* E5b frequency (Hz) */
75#define FREQ9 2.492028E9 /* S frequency (Hz) */
76#define FREQ1_CMP 1.561098E9 /* BDS B1I frequency (Hz) */
77#define FREQ2_CMP 1.20714E9 /* BDS B2I/B2b frequency (Hz) */
78
79/* precise ephemeris constants */
80#define NMAX 10 /* order of polynomial interpolation */
81#define MAXDTE 900.0 /* max time difference to ephem time (s) */
82#define EXTERR_CLK 1E-3 /* extrapolation error for clock (m/s) */
83#define EXTERR_EPH 5E-7 /* extrapolation error for ephem (m/s^2) */
84
85/*============================================================================
86 * Forward declarations for legacy functions (resolved at link time)
87 *===========================================================================*/
88
89/*============================================================================
90 * Public Functions
91 *===========================================================================*/
92
93/* read earth rotation parameters ----------------------------------------------
94 * read earth rotation parameters
95 * args : char *file I IGS ERP file (IGS ERP ver.2)
96 * erp_t *erp O earth rotation parameters
97 * return : status (1:ok,0:file open error)
98 *-----------------------------------------------------------------------------*/
99extern int readerp(const char* file, erp_t* erp) {
100 FILE* fp;
101 erpd_t* erp_data;
102 double v[14] = {0};
103 char buff[256];
104
105 trace(NULL, 3, "readerp: file=%s\n", file);
106
107 if (!(fp = fopen(file, "r"))) {
108 trace(NULL, 2, "erp file open error: file=%s\n", file);
109 return 0;
110 }
111 while (fgets(buff, sizeof(buff), fp)) {
112 if (sscanf(buff, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", v, v + 1, v + 2, v + 3, v + 4,
113 v + 5, v + 6, v + 7, v + 8, v + 9, v + 10, v + 11, v + 12, v + 13) < 5) {
114 continue;
115 }
116 if (erp->n >= erp->nmax) {
117 erp->nmax = erp->nmax <= 0 ? 128 : erp->nmax * 2;
118 erp_data = (erpd_t*)realloc(erp->data, sizeof(erpd_t) * erp->nmax);
119 if (!erp_data) {
120 free(erp->data);
121 erp->data = NULL;
122 erp->n = erp->nmax = 0;
123 fclose(fp);
124 return 0;
125 }
126 erp->data = erp_data;
127 }
128 erp->data[erp->n].mjd = v[0];
129 erp->data[erp->n].xp = v[1] * 1E-6 * AS2R;
130 erp->data[erp->n].yp = v[2] * 1E-6 * AS2R;
131 erp->data[erp->n].ut1_utc = v[3] * 1E-7;
132 erp->data[erp->n].lod = v[4] * 1E-7;
133 erp->data[erp->n].xpr = v[12] * 1E-6 * AS2R;
134 erp->data[erp->n++].ypr = v[13] * 1E-6 * AS2R;
135 }
136 fclose(fp);
137 return 1;
138}
139/* get earth rotation parameter values -----------------------------------------
140 * get earth rotation parameter values
141 * args : erp_t *erp I earth rotation parameters
142 * gtime_t time I time (gpst)
143 * double *erpv O erp values {xp,yp,ut1_utc,lod} (rad,rad,s,s/d)
144 * return : status (1:ok,0:error)
145 *-----------------------------------------------------------------------------*/
146extern int geterp(const erp_t* erp, gtime_t time, double* erpv) {
147 const double ep[] = {2000, 1, 1, 12, 0, 0};
148 double mjd, day, a;
149 int i, j, k;
150
151 trace(NULL, 4, "geterp:\n");
152
153 if (erp->n <= 0) {
154 return 0;
155 }
156
157 mjd = 51544.5 + (timediff(gpst2utc(time), epoch2time(ep))) / 86400.0;
158
159 if (mjd <= erp->data[0].mjd) {
160 day = mjd - erp->data[0].mjd;
161 erpv[0] = erp->data[0].xp + erp->data[0].xpr * day;
162 erpv[1] = erp->data[0].yp + erp->data[0].ypr * day;
163 erpv[2] = erp->data[0].ut1_utc - erp->data[0].lod * day;
164 erpv[3] = erp->data[0].lod;
165 return 1;
166 }
167 if (mjd >= erp->data[erp->n - 1].mjd) {
168 day = mjd - erp->data[erp->n - 1].mjd;
169 erpv[0] = erp->data[erp->n - 1].xp + erp->data[erp->n - 1].xpr * day;
170 erpv[1] = erp->data[erp->n - 1].yp + erp->data[erp->n - 1].ypr * day;
171 erpv[2] = erp->data[erp->n - 1].ut1_utc - erp->data[erp->n - 1].lod * day;
172 erpv[3] = erp->data[erp->n - 1].lod;
173 return 1;
174 }
175 for (j = 0, k = erp->n - 1; j < k - 1;) {
176 i = (j + k) / 2;
177 if (mjd < erp->data[i].mjd) {
178 k = i;
179 } else {
180 j = i;
181 }
182 }
183 if (erp->data[j].mjd == erp->data[j + 1].mjd) {
184 a = 0.5;
185 } else {
186 a = (mjd - erp->data[j].mjd) / (erp->data[j + 1].mjd - erp->data[j].mjd);
187 }
188 erpv[0] = (1.0 - a) * erp->data[j].xp + a * erp->data[j + 1].xp;
189 erpv[1] = (1.0 - a) * erp->data[j].yp + a * erp->data[j + 1].yp;
190 erpv[2] = (1.0 - a) * erp->data[j].ut1_utc + a * erp->data[j + 1].ut1_utc;
191 erpv[3] = (1.0 - a) * erp->data[j].lod + a * erp->data[j + 1].lod;
192 return 1;
193}
194
195/*============================================================================
196 * Precise Ephemeris Functions
197 * (absorbed from preceph.c — pure cut-and-paste)
198 *===========================================================================*/
199
200/* satellite code to satellite system ----------------------------------------*/
201static int code2sys(char code) {
202 if (code == 'G' || code == ' ') {
203 return SYS_GPS;
204 }
205 if (code == 'R') {
206 return SYS_GLO;
207 }
208 if (code == 'E') {
209 return SYS_GAL; /* SP3-d */
210 }
211 if (code == 'J') {
212 return SYS_QZS; /* SP3-d */
213 }
214 if (code == 'C') {
215 return SYS_CMP; /* SP3-d */
216 }
217 if (code == 'I') {
218 return SYS_IRN; /* SP3-d */
219 }
220 if (code == 'L') {
221 return SYS_LEO; /* SP3-d */
222 }
223 return SYS_NONE;
224}
225/* read SP3 header -----------------------------------------------------------*/
226static int readsp3h(FILE* fp, gtime_t* time, char* type, int* sats, double* bfact, char* tsys) {
227 int i, j, k = 0, ns = 0, sys, prn;
228 char buff[1024];
229
230 trace(NULL, 3, "readsp3h:\n");
231
232 for (i = 0;; i++) {
233 if (!fgets(buff, sizeof(buff), fp)) {
234 break;
235 }
236
237 if (i == 0) {
238 *type = buff[2];
239 if (str2time(buff, 3, 28, time)) {
240 return 0;
241 }
242 } else if (!strncmp(buff, "+ ", 2)) { /* satellite id */
243 if (ns == 0) {
244 ns = (int)str2num(buff, 3, 3);
245 }
246 for (j = 0; j < 17 && k < ns; j++) {
247 sys = code2sys(buff[9 + 3 * j]);
248 prn = (int)str2num(buff, 10 + 3 * j, 2);
249 if (k < MAXSAT) {
250 sats[k++] = satno(sys, prn);
251 }
252 }
253 } else if (!strncmp(buff, "++", 2)) { /* orbit accuracy */
254 continue;
255 } else if (!strncmp(buff, "%c", 2)) { /* time system */
256 sprintf(tsys, "%.3s", buff + 9);
257 } else if (!strncmp(buff, "%f", 2) && bfact[0] == 0.0) { /* fp base number */
258 bfact[0] = str2num(buff, 3, 10);
259 bfact[1] = str2num(buff, 14, 12);
260 } else if (!strncmp(buff, "%i", 2)) {
261 continue;
262 } else if (!strncmp(buff, "/*", 2)) { /* comment */
263 continue;
264 } else if (!strncmp(buff, "* ", 2)) { /* first record */
265 rewind(fp); /* rollback to start */
266 break;
267 }
268 }
269 return ns;
270}
271/* add precise ephemeris -----------------------------------------------------*/
272static int addpeph(nav_t* nav, peph_t* peph) {
273 peph_t* nav_peph;
274
275 if (nav->ne >= nav->nemax) {
276 nav->nemax += 256;
277 if (!(nav_peph = (peph_t*)realloc(nav->peph, sizeof(peph_t) * nav->nemax))) {
278 trace(NULL, 1, "readsp3b malloc error n=%d\n", nav->nemax);
279 free(nav->peph);
280 nav->peph = NULL;
281 nav->ne = nav->nemax = 0;
282 return 0;
283 }
284 nav->peph = nav_peph;
285 }
286 nav->peph[nav->ne++] = *peph;
287 return 1;
288}
289/* read SP3 body -------------------------------------------------------------*/
290static void readsp3b(FILE* fp, char type, int* sats, int ns, double* bfact, char* tsys, int index, int opt,
291 nav_t* nav) {
292 peph_t peph;
293 gtime_t time;
294 double val, std, base;
295 int i, j, sat, sys, prn, n = ns * (type == 'P' ? 1 : 2), pred_o, pred_c, v;
296 char buff[1024];
297
298 trace(NULL, 3, "readsp3b: type=%c ns=%d index=%d opt=%d\n", type, ns, index, opt);
299
300 while (fgets(buff, sizeof(buff), fp)) {
301 if (!strncmp(buff, "EOF", 3)) {
302 break;
303 }
304
305 /* skip header or invalid records */
306 if (buff[0] != '*' || str2time(buff, 3, 28, &time)) {
307 continue;
308 }
309 if (!strcmp(tsys, "UTC")) {
310 time = utc2gpst(time); /* utc->gpst */
311 }
312 peph.time = time;
313 peph.index = index;
314
315 for (i = 0; i < MAXSAT; i++) {
316 for (j = 0; j < 4; j++) {
317 peph.pos[i][j] = 0.0;
318 peph.std[i][j] = 0.0f;
319 peph.vel[i][j] = 0.0;
320 peph.vst[i][j] = 0.0f;
321 }
322 for (j = 0; j < 3; j++) {
323 peph.cov[i][j] = 0.0f;
324 peph.vco[i][j] = 0.0f;
325 }
326 }
327 for (i = pred_o = pred_c = v = 0; i < n && fgets(buff, sizeof(buff), fp); i++) {
328 if (strlen(buff) < 4 || (buff[0] != 'P' && buff[0] != 'V')) {
329 continue;
330 }
331
332 sys = buff[1] == ' ' ? SYS_GPS : code2sys(buff[1]);
333 prn = (int)str2num(buff, 2, 2);
334 if (sys == SYS_SBS) {
335 prn += 100;
336 } else if (sys == SYS_QZS) {
337 prn += 192; /* extension to sp3-c */
338 }
339
340 if (!(sat = satno(sys, prn))) {
341 continue;
342 }
343
344 if (buff[0] == 'P') {
345 pred_c = strlen(buff) >= 76 && buff[75] == 'P';
346 pred_o = strlen(buff) >= 80 && buff[79] == 'P';
347 }
348 for (j = 0; j < 4; j++) {
349 /* read option for predicted value */
350 if (j < 3 && (opt & 1) && pred_o) {
351 continue;
352 }
353 if (j < 3 && (opt & 2) && !pred_o) {
354 continue;
355 }
356 if (j == 3 && (opt & 1) && pred_c) {
357 continue;
358 }
359 if (j == 3 && (opt & 2) && !pred_c) {
360 continue;
361 }
362
363 val = str2num(buff, 4 + j * 14, 14);
364 std = str2num(buff, 61 + j * 3, j < 3 ? 2 : 3);
365
366 if (buff[0] == 'P') { /* position */
367 if (val != 0.0 && fabs(val - 999999.999999) >= 1E-6) {
368 peph.pos[sat - 1][j] = val * (j < 3 ? 1000.0 : 1E-6);
369 v = 1; /* valid epoch */
370 }
371 if ((base = bfact[j < 3 ? 0 : 1]) > 0.0 && std > 0.0) {
372 peph.std[sat - 1][j] = (float)(pow(base, std) * (j < 3 ? 1E-3 : 1E-12));
373 }
374 } else if (v) { /* velocity */
375 if (val != 0.0 && fabs(val - 999999.999999) >= 1E-6) {
376 peph.vel[sat - 1][j] = val * (j < 3 ? 0.1 : 1E-10);
377 }
378 if ((base = bfact[j < 3 ? 0 : 1]) > 0.0 && std > 0.0) {
379 peph.vst[sat - 1][j] = (float)(pow(base, std) * (j < 3 ? 1E-7 : 1E-16));
380 }
381 }
382 }
383 }
384 if (v) {
385 if (!addpeph(nav, &peph)) {
386 return;
387 }
388 }
389 }
390}
391/* compare precise ephemeris -------------------------------------------------*/
392static int cmppeph(const void* p1, const void* p2) {
393 peph_t *q1 = (peph_t*)p1, *q2 = (peph_t*)p2;
394 double tt = timediff(q1->time, q2->time);
395 return tt < -1E-9 ? -1 : (tt > 1E-9 ? 1 : q1->index - q2->index);
396}
397/* combine precise ephemeris -------------------------------------------------*/
398static void combpeph(nav_t* nav, int opt) {
399 int i, j, k, m;
400
401 trace(NULL, 3, "combpeph: ne=%d\n", nav->ne);
402
403 qsort(nav->peph, nav->ne, sizeof(peph_t), cmppeph);
404
405 if (opt & 4) {
406 return;
407 }
408
409 for (i = 0, j = 1; j < nav->ne; j++) {
410 if (fabs(timediff(nav->peph[i].time, nav->peph[j].time)) < 1E-9) {
411 for (k = 0; k < MAXSAT; k++) {
412 if (norm(nav->peph[j].pos[k], 4) <= 0.0) {
413 continue;
414 }
415 for (m = 0; m < 4; m++) {
416 nav->peph[i].pos[k][m] = nav->peph[j].pos[k][m];
417 }
418 for (m = 0; m < 4; m++) {
419 nav->peph[i].std[k][m] = nav->peph[j].std[k][m];
420 }
421 for (m = 0; m < 4; m++) {
422 nav->peph[i].vel[k][m] = nav->peph[j].vel[k][m];
423 }
424 for (m = 0; m < 4; m++) {
425 nav->peph[i].vst[k][m] = nav->peph[j].vst[k][m];
426 }
427 }
428 } else if (++i < j) {
429 nav->peph[i] = nav->peph[j];
430 }
431 }
432 nav->ne = i + 1;
433
434 trace(NULL, 4, "combpeph: ne=%d\n", nav->ne);
435}
436/* read sp3 precise ephemeris file ---------------------------------------------
437 * read sp3 precise ephemeris/clock files and set them to navigation data
438 * args : char *file I sp3-c precise ephemeris file
439 * (wind-card * is expanded)
440 * nav_t *nav IO navigation data
441 * int opt I options (1: only observed + 2: only predicted +
442 * 4: not combined)
443 * return : none
444 * notes : see ref [1]
445 * precise ephemeris is appended and combined
446 * nav->peph and nav->ne must by properly initialized before calling the
447 * function
448 * only files with extensions of .sp3, .SP3, .eph* and .EPH* are read
449 *-----------------------------------------------------------------------------*/
450extern void readsp3(const char* file, nav_t* nav, int opt) {
451 FILE* fp;
452 gtime_t time = {0};
453 double bfact[2] = {0};
454 int i, j, n, ns, sats[MAXSAT] = {0};
455 char *efiles[MAXEXFILE], *ext, type = ' ', tsys[4] = "";
456
457 trace(NULL, 3, "readpephs: file=%s\n", file);
458
459 for (i = 0; i < MAXEXFILE; i++) {
460 if (!(efiles[i] = (char*)malloc(1024))) {
461 for (i--; i >= 0; i--) {
462 free(efiles[i]);
463 }
464 return;
465 }
466 }
467 /* expand wild card in file path */
468 n = expath(file, efiles, MAXEXFILE);
469
470 for (i = j = 0; i < n; i++) {
471 if (!(ext = strrchr(efiles[i], '.'))) {
472 continue;
473 }
474
475 if (!strstr(ext, ".sp3") && !strstr(ext, ".SP3") && !strstr(ext, ".eph") && !strstr(ext, ".EPH")) {
476 continue;
477 }
478
479 if (!(fp = fopen(efiles[i], "r"))) {
480 trace(NULL, 2, "sp3 file open error %s\n", efiles[i]);
481 continue;
482 }
483 /* read sp3 header */
484 ns = readsp3h(fp, &time, &type, sats, bfact, tsys);
485
486 /* read sp3 body */
487 readsp3b(fp, type, sats, ns, bfact, tsys, j++, opt, nav);
488
489 fclose(fp);
490 }
491 for (i = 0; i < MAXEXFILE; i++) {
492 free(efiles[i]);
493 }
494
495 /* combine precise ephemeris */
496 if (nav->ne > 0) {
497 combpeph(nav, opt);
498 }
499}
500/* read satellite antenna parameters -------------------------------------------
501 * read satellite antenna parameters
502 * args : char *file I antenna parameter file
503 * gtime_t time I time
504 * nav_t *nav IO navigation data
505 * return : status (1:ok,0:error)
506 * notes : only support antex format for the antenna parameter file
507 *-----------------------------------------------------------------------------*/
508extern int readsap(const char* file, gtime_t time, nav_t* nav) {
509 pcvs_t pcvs = {0};
510 pcv_t pcv0 = {0}, *pcv;
511 int i;
512
513 trace(NULL, 3, "readsap : file=%s time=%s\n", file, time_str(time, 0));
514
515 if (!readpcv(file, &pcvs)) {
516 return 0;
517 }
518
519 for (i = 0; i < MAXSAT; i++) {
520 pcv = searchpcv(i + 1, "", time, &pcvs);
521 nav->pcvs[i] = pcv ? *pcv : pcv0;
522 }
523 free(pcvs.pcv);
524 return 1;
525}
526/* read DCB parameters file --------------------------------------------------*/
527static int readdcbf(const char* file, nav_t* nav, const sta_t* sta) {
528 FILE* fp;
529 double cbias;
530 char buff[256], str1[32], str2[32] = "";
531 int i, j, sat, type = 0;
532
533 trace(NULL, 3, "readdcbf: file=%s\n", file);
534
535 if (!(fp = fopen(file, "r"))) {
536 trace(NULL, 2, "dcb parameters file open error: %s\n", file);
537 return 0;
538 }
539 while (fgets(buff, sizeof(buff), fp)) {
540 if (strstr(buff, "DIFFERENTIAL (P1-P2) CODE BIASES")) {
541 type = 1;
542 } else if (strstr(buff, "DIFFERENTIAL (P1-C1) CODE BIASES")) {
543 type = 2;
544 } else if (strstr(buff, "DIFFERENTIAL (P2-C2) CODE BIASES")) {
545 type = 3;
546 }
547
548 if (!type || sscanf(buff, "%s %s", str1, str2) < 1) {
549 continue;
550 }
551
552 if ((cbias = str2num(buff, 26, 9)) == 0.0) {
553 continue;
554 }
555
556 if (sta && (!strcmp(str1, "G") || !strcmp(str1, "R"))) { /* receiver DCB */
557 for (i = 0; i < MAXRCV; i++) {
558 if (!strcmp(sta[i].name, str2)) {
559 break;
560 }
561 }
562 if (i < MAXRCV) {
563 j = !strcmp(str1, "G") ? 0 : 1;
564 nav->rbias[i][j][type - 1] = cbias * 1E-9 * CLIGHT; /* ns -> m */
565 }
566 } else if ((sat = satid2no(str1))) { /* satellite dcb */
567 nav->cbias[sat - 1][type - 1] = cbias * 1E-9 * CLIGHT; /* ns -> m */
568 }
569 }
570 fclose(fp);
571
572 return 1;
573}
574/* read DCB parameters ---------------------------------------------------------
575 * read differential code bias (DCB) parameters
576 * args : char *file I DCB parameters file (wild-card * expanded)
577 * nav_t *nav IO navigation data
578 * sta_t *sta I station info data to inport receiver DCB
579 * (NULL: no use)
580 * return : status (1:ok,0:error)
581 * notes : currently only support P1-P2, P1-C1, P2-C2, bias in DCB file
582 *-----------------------------------------------------------------------------*/
583extern int readdcb(const char* file, nav_t* nav, const sta_t* sta) {
584 int i, j, n;
585 char* efiles[MAXEXFILE] = {0};
586
587 trace(NULL, 3, "readdcb : file=%s\n", file);
588
589 for (i = 0; i < MAXSAT; i++) {
590 for (j = 0; j < 3; j++) {
591 nav->cbias[i][j] = 0.0;
592 }
593 }
594 for (i = 0; i < MAXEXFILE; i++) {
595 if (!(efiles[i] = (char*)malloc(1024))) {
596 for (i--; i >= 0; i--) {
597 free(efiles[i]);
598 }
599 return 0;
600 }
601 }
602 n = expath(file, efiles, MAXEXFILE);
603
604 for (i = 0; i < n; i++) {
605 readdcbf(efiles[i], nav, sta);
606 }
607 for (i = 0; i < MAXEXFILE; i++) {
608 free(efiles[i]);
609 }
610
611 return 1;
612}
613/* polynomial interpolation by Neville's algorithm ---------------------------*/
614static double interppol(const double* x, double* y, int n) {
615 int i, j;
616
617 for (j = 1; j < n; j++) {
618 for (i = 0; i < n - j; i++) {
619 y[i] = (x[i + j] * y[i] - x[i] * y[i + 1]) / (x[i + j] - x[i]);
620 }
621 }
622 return y[0];
623}
624/* satellite position by precise ephemeris -----------------------------------*/
625static int pephpos(gtime_t time, int sat, const nav_t* nav, double* rs, double* dts, double* vare, double* varc) {
626 double t[NMAX + 1], p[3][NMAX + 1], c[2], *pos, std = 0.0, s[3], sinl, cosl;
627 int i, j, k, index;
628
629 trace(NULL, 4, "pephpos : time=%s sat=%2d\n", time_str(time, 3), sat);
630
631 rs[0] = rs[1] = rs[2] = dts[0] = 0.0;
632
633 if (nav->ne < NMAX + 1 || timediff(time, nav->peph[0].time) < -MAXDTE ||
634 timediff(time, nav->peph[nav->ne - 1].time) > MAXDTE) {
635 trace(NULL, 3, "no prec ephem %s sat=%2d\n", time_str(time, 0), sat);
636 return 0;
637 }
638 /* binary search */
639 for (i = 0, j = nav->ne - 1; i < j;) {
640 k = (i + j) / 2;
641 if (timediff(nav->peph[k].time, time) < 0.0) {
642 i = k + 1;
643 } else {
644 j = k;
645 }
646 }
647 index = i <= 0 ? 0 : i - 1;
648
649 /* polynomial interpolation for orbit */
650 i = index - (NMAX + 1) / 2;
651 if (i < 0) {
652 i = 0;
653 } else if (i + NMAX >= nav->ne) {
654 i = nav->ne - NMAX - 1;
655 }
656
657 for (j = 0; j <= NMAX; j++) {
658 t[j] = timediff(nav->peph[i + j].time, time);
659 if (norm(nav->peph[i + j].pos[sat - 1], 3) <= 0.0) {
660 trace(NULL, 3, "prec ephem outage %s sat=%2d\n", time_str(time, 0), sat);
661 return 0;
662 }
663 }
664 for (j = 0; j <= NMAX; j++) {
665 pos = nav->peph[i + j].pos[sat - 1];
666 /* correciton for earh rotation ver.2.4.0 */
667 sinl = sin(OMGE * t[j]);
668 cosl = cos(OMGE * t[j]);
669 p[0][j] = cosl * pos[0] - sinl * pos[1];
670 p[1][j] = sinl * pos[0] + cosl * pos[1];
671 p[2][j] = pos[2];
672 }
673 for (i = 0; i < 3; i++) {
674 rs[i] = interppol(t, p[i], NMAX + 1);
675 }
676 if (vare) {
677 for (i = 0; i < 3; i++) {
678 s[i] = nav->peph[index].std[sat - 1][i];
679 }
680 std = norm(s, 3);
681
682 /* extrapolation error for orbit */
683 if (t[0] > 0.0) {
684 std += EXTERR_EPH * SQR(t[0]) / 2.0;
685 } else if (t[NMAX] < 0.0) {
686 std += EXTERR_EPH * SQR(t[NMAX]) / 2.0;
687 }
688 *vare = SQR(std);
689 }
690 /* linear interpolation for clock */
691 t[0] = timediff(time, nav->peph[index].time);
692 t[1] = timediff(time, nav->peph[index + 1].time);
693 c[0] = nav->peph[index].pos[sat - 1][3];
694 c[1] = nav->peph[index + 1].pos[sat - 1][3];
695
696 if (t[0] <= 0.0) {
697 if ((dts[0] = c[0]) != 0.0) {
698 std = nav->peph[index].std[sat - 1][3] * CLIGHT - EXTERR_CLK * t[0];
699 }
700 } else if (t[1] >= 0.0) {
701 if ((dts[0] = c[1]) != 0.0) {
702 std = nav->peph[index + 1].std[sat - 1][3] * CLIGHT + EXTERR_CLK * t[1];
703 }
704 } else if (c[0] != 0.0 && c[1] != 0.0) {
705 dts[0] = (c[1] * t[0] - c[0] * t[1]) / (t[0] - t[1]);
706 i = t[0] < -t[1] ? 0 : 1;
707 std = nav->peph[index + i].std[sat - 1][3] + EXTERR_CLK * fabs(t[i]);
708 } else {
709 dts[0] = 0.0;
710 }
711 if (varc) {
712 *varc = SQR(std);
713 }
714 return 1;
715}
716/* satellite clock by precise clock ------------------------------------------*/
717static int pephclk(gtime_t time, int sat, const nav_t* nav, double* dts, double* varc) {
718 double t[2], c[2], std;
719 int i, j, k, index;
720
721 trace(NULL, 4, "pephclk : time=%s sat=%2d\n", time_str(time, 3), sat);
722
723 if (nav->nc < 2 || timediff(time, nav->pclk[0].time) < -MAXDTE ||
724 timediff(time, nav->pclk[nav->nc - 1].time) > MAXDTE) {
725 trace(NULL, 3, "no prec clock %s sat=%2d\n", time_str(time, 0), sat);
726 return 1;
727 }
728 /* binary search */
729 for (i = 0, j = nav->nc - 1; i < j;) {
730 k = (i + j) / 2;
731 if (timediff(nav->pclk[k].time, time) < 0.0) {
732 i = k + 1;
733 } else {
734 j = k;
735 }
736 }
737 index = i <= 0 ? 0 : i - 1;
738
739 /* linear interpolation for clock */
740 t[0] = timediff(time, nav->pclk[index].time);
741 t[1] = timediff(time, nav->pclk[index + 1].time);
742 c[0] = nav->pclk[index].clk[sat - 1][0];
743 c[1] = nav->pclk[index + 1].clk[sat - 1][0];
744
745 if (t[0] <= 0.0) {
746 if ((dts[0] = c[0]) == 0.0) {
747 return 0;
748 }
749 std = nav->pclk[index].std[sat - 1][0] * CLIGHT - EXTERR_CLK * t[0];
750 } else if (t[1] >= 0.0) {
751 if ((dts[0] = c[1]) == 0.0) {
752 return 0;
753 }
754 std = nav->pclk[index + 1].std[sat - 1][0] * CLIGHT + EXTERR_CLK * t[1];
755 } else if (c[0] != 0.0 && c[1] != 0.0) {
756 dts[0] = (c[1] * t[0] - c[0] * t[1]) / (t[0] - t[1]);
757 i = t[0] < -t[1] ? 0 : 1;
758 std = nav->pclk[index + i].std[sat - 1][0] * CLIGHT + EXTERR_CLK * fabs(t[i]);
759 } else {
760 trace(NULL, 3, "prec clock outage %s sat=%2d\n", time_str(time, 0), sat);
761 return 0;
762 }
763 if (varc) {
764 *varc = SQR(std);
765 }
766 return 1;
767}
768/* satellite antenna phase center offset ---------------------------------------
769 * compute satellite antenna phase center offset in ecef
770 * args : gtime_t time I time (gpst)
771 * double *rs I satellite position and velocity (ecef)
772 * {x,y,z,vx,vy,vz} (m|m/s)
773 * int sat I satellite number
774 * nav_t *nav I navigation data
775 * double *dant I satellite antenna phase center offset (ecef)
776 * {dx,dy,dz} (m) (iono-free LC value)
777 * return : none
778 * notes : iono-free LC frequencies defined as follows:
779 * GPS/QZSS : L1-L2
780 * GLONASS : G1-G2
781 * Galileo : E1-E5b
782 * BDS : B1I-B2I
783 * NavIC : L5-S
784 *-----------------------------------------------------------------------------*/
785extern void satantoff(gtime_t time, const double* rs, int sat, const nav_t* nav, double* dant) {
786 const pcv_t* pcv = nav->pcvs + sat - 1;
787 double ex[3], ey[3], ez[3], es[3], r[3], rsun[3], gmst, erpv[5] = {0}, freq[2];
788 double C1, C2, dant1, dant2;
789 int i, sys;
790
791 trace(NULL, 4, "satantoff: time=%s sat=%2d\n", time_str(time, 3), sat);
792
793 dant[0] = dant[1] = dant[2] = 0.0;
794
795 /* sun position in ecef */
796 sunmoonpos(gpst2utc(time), erpv, rsun, NULL, &gmst);
797
798 /* unit vectors of satellite fixed coordinates */
799 for (i = 0; i < 3; i++) {
800 r[i] = -rs[i];
801 }
802 if (!normv3(r, ez)) {
803 return;
804 }
805 for (i = 0; i < 3; i++) {
806 r[i] = rsun[i] - rs[i];
807 }
808 if (!normv3(r, es)) {
809 return;
810 }
811 cross3(ez, es, r);
812 if (!normv3(r, ey)) {
813 return;
814 }
815 cross3(ey, ez, ex);
816
817 /* iono-free LC coefficients */
818 sys = satsys_bd2(sat, NULL);
819 freq[0] = freq_num2freq(sys, freq_idx2freq_num(sys, 0), 0);
820 freq[1] = freq_num2freq(sys, freq_idx2freq_num(sys, 1), 0);
821
822 if (sys == SYS_GLO) { /* GLONASS: use sat-dependent freq */
823 freq[0] = sat2freq(sat, CODE_L1C, nav);
824 freq[1] = sat2freq(sat, CODE_L2C, nav);
825 }
826 if (freq[0] == 0.0 || freq[1] == 0.0) {
827 return;
828 }
829
830 C1 = SQR(freq[0]) / (SQR(freq[0]) - SQR(freq[1]));
831 C2 = -SQR(freq[1]) / (SQR(freq[0]) - SQR(freq[1]));
832
833 /* antenna indices for each frequency */
834 {
835 int a1 = freq_idx2ant_idx(sys, 0);
836 int a2 = freq_idx2ant_idx(sys, 1);
837
838 /* iono-free LC */
839 for (i = 0; i < 3; i++) {
840 dant1 = pcv->off[a1][0] * ex[i] + pcv->off[a1][1] * ey[i] + pcv->off[a1][2] * ez[i];
841 dant2 = pcv->off[a2][0] * ex[i] + pcv->off[a2][1] * ey[i] + pcv->off[a2][2] * ez[i];
842 dant[i] = C1 * dant1 + C2 * dant2;
843 }
844 }
845}
846/* satellite position/clock by precise ephemeris/clock -------------------------
847 * compute satellite position/clock with precise ephemeris/clock
848 * args : gtime_t time I time (gpst)
849 * int sat I satellite number
850 * nav_t *nav I navigation data
851 * int opt I sat position option
852 * (0: center of mass, 1: antenna phase center)
853 * double *rs O sat position and velocity (ecef)
854 * {x,y,z,vx,vy,vz} (m|m/s)
855 * double *dts O sat clock {bias,drift} (s|s/s)
856 * double *var IO sat position and clock error variance (m)
857 * (NULL: no output)
858 * return : status (1:ok,0:error or data outage)
859 * notes : clock includes relativistic correction but does not contain code bias
860 * before calling the function, nav->peph, nav->ne, nav->pclk and
861 * nav->nc must be set by calling readsp3(), readrnx() or readrnxt()
862 * if precise clocks are not set, clocks in sp3 are used instead
863 *-----------------------------------------------------------------------------*/
864extern int peph2pos(gtime_t time, int sat, const nav_t* nav, int opt, double* rs, double* dts, double* var) {
865 gtime_t time_tt;
866 double rss[3], rst[3], dtss[1], dtst[1], dant[3] = {0}, vare = 0.0, varc = 0.0, tt = 1E-3;
867 int i;
868
869 trace(NULL, 4, "peph2pos: time=%s sat=%2d opt=%d\n", time_str(time, 3), sat, opt);
870
871 if (sat <= 0 || MAXSAT < sat) {
872 return 0;
873 }
874
875 /* satellite position and clock bias */
876 if (!pephpos(time, sat, nav, rss, dtss, &vare, &varc) || !pephclk(time, sat, nav, dtss, &varc)) {
877 return 0;
878 }
879
880 time_tt = timeadd(time, tt);
881 if (!pephpos(time_tt, sat, nav, rst, dtst, NULL, NULL) || !pephclk(time_tt, sat, nav, dtst, NULL)) {
882 return 0;
883 }
884
885 /* satellite antenna offset correction */
886 if (opt) {
887 satantoff(time, rss, sat, nav, dant);
888 }
889 for (i = 0; i < 3; i++) {
890 rs[i] = rss[i] + dant[i];
891 rs[i + 3] = (rst[i] - rss[i]) / tt;
892 }
893 /* relativistic effect correction */
894 if (dtss[0] != 0.0) {
895 dts[0] = dtss[0] - 2.0 * dot(rs, rs + 3, 3) / CLIGHT / CLIGHT;
896 dts[1] = (dtst[0] - dtss[0]) / tt;
897 } else { /* no precise clock */
898 dts[0] = dts[1] = 0.0;
899 }
900 if (var) {
901 *var = vare + varc;
902 }
903
904 return 1;
905}
int readpcv(const char *file, pcvs_t *pcvs)
Read antenna parameters from file (ANTEX or NGS format).
pcv_t * searchpcv(int sat, const char *type, gtime_t time, const pcvs_t *pcvs)
Search antenna parameter by satellite number or antenna type.
MRTKLIB Antenna Module — Antenna phase center model and parameter I/O.
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.
int satid2no(const char *id)
Definition mrtk_nav.c:753
double sat2freq(int sat, uint8_t code, const nav_t *nav)
Definition mrtk_obs.c:244
#define CLIGHT
Definition mrtk_coords.c:41
#define MAXSAT
Definition mrtk_coords.c:45
#define AS2R
Definition mrtk_coords.c:37
#define OMGE
Definition mrtk_coords.c:40
#define SYS_GPS
Definition mrtk_eph.c:65
#define SYS_NONE
Definition mrtk_eph.c:64
#define SYS_SBS
Definition mrtk_eph.c:66
#define SYS_QZS
Definition mrtk_eph.c:69
#define SYS_IRN
Definition mrtk_eph.c:71
#define SYS_CMP
Definition mrtk_eph.c:70
#define SYS_GAL
Definition mrtk_eph.c:68
#define SYS_GLO
Definition mrtk_eph.c:67
struct nav_s nav_t
Definition mrtk_eph.h:40
#define MAXRCV
#define CODE_L1C
#define CODE_L2C
#define MAXEXFILE
void cross3(const double *a, const double *b, double *c)
Cross product of 3D vectors.
Definition mrtk_mat.c:172
double norm(const double *a, int n)
Euclidean norm of vector.
Definition mrtk_mat.c:165
int normv3(const double *a, double *b)
Normalize 3D vector.
Definition mrtk_mat.c:183
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.
int satno(int sys, int prn)
Convert satellite system+prn/slot number to satellite number.
Definition mrtk_nav.c:58
MRTKLIB Navigation Module — Navigation data types and satellite/nav utility functions.
#define SYS_LEO
Definition mrtk_obs.c:61
void readsp3(const char *file, nav_t *nav, int opt)
Read sp3 precise ephemeris file.
Definition mrtk_peph.c:450
static int code2sys(char code)
Definition mrtk_peph.c:201
int freq_idx2ant_idx(int sys, int freq_idx)
Definition mrtk_nav.c:743
static int pephclk(gtime_t time, int sat, const nav_t *nav, double *dts, double *varc)
Definition mrtk_peph.c:717
int readdcb(const char *file, nav_t *nav, const sta_t *sta)
Read differential code bias (DCB) parameters.
Definition mrtk_peph.c:583
static void readsp3b(FILE *fp, char type, int *sats, int ns, double *bfact, char *tsys, int index, int opt, nav_t *nav)
Definition mrtk_peph.c:290
#define EXTERR_EPH
Definition mrtk_peph.c:83
#define NMAX
Definition mrtk_peph.c:80
#define EXTERR_CLK
Definition mrtk_peph.c:82
static int readsp3h(FILE *fp, gtime_t *time, char *type, int *sats, double *bfact, char *tsys)
Definition mrtk_peph.c:226
static double interppol(const double *x, double *y, int n)
Definition mrtk_peph.c:614
static int cmppeph(const void *p1, const void *p2)
Definition mrtk_peph.c:392
#define SQR(x)
Definition mrtk_peph.c:57
static void combpeph(nav_t *nav, int opt)
Definition mrtk_peph.c:398
int satsys_bd2(int sat, int *prn)
Definition mrtk_nav.c:159
int readerp(const char *file, erp_t *erp)
Read earth rotation parameters from IGS ERP file (ver.2).
Definition mrtk_peph.c:99
#define MAXDTE
Definition mrtk_peph.c:81
double freq_num2freq(int sys, int freq_num, int fcn)
Definition mrtk_nav.c:680
static int pephpos(gtime_t time, int sat, const nav_t *nav, double *rs, double *dts, double *vare, double *varc)
Definition mrtk_peph.c:625
int peph2pos(gtime_t time, int sat, const nav_t *nav, int opt, double *rs, double *dts, double *var)
Compute satellite position/clock with precise ephemeris/clock.
Definition mrtk_peph.c:864
static int readdcbf(const char *file, nav_t *nav, const sta_t *sta)
Definition mrtk_peph.c:527
int readsap(const char *file, gtime_t time, nav_t *nav)
Read satellite antenna parameters.
Definition mrtk_peph.c:508
int freq_idx2freq_num(int sys, int freq_idx)
Definition mrtk_nav.c:649
void satantoff(gtime_t time, const double *rs, int sat, const nav_t *nav, double *dant)
Compute satellite antenna phase center offset in ecef.
Definition mrtk_peph.c:785
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 int addpeph(nav_t *nav, peph_t *peph)
Definition mrtk_peph.c:272
MRTKLIB Precise Ephemeris Module — Earth rotation parameter types and ERP I/O functions.
int expath(const char *path, char *paths[], int nmax)
Expand file path with wild-card (*) in file.
Definition mrtk_sys.c:96
double str2num(const char *s, int i, int n)
Convert substring in string to number.
Definition mrtk_sys.c:60
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 gpst2utc(gtime_t t)
Convert GPS time to UTC considering leap seconds.
Definition mrtk_time.c:422
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
int str2time(const char *s, int i, int n, gtime_t *t)
Convert substring in string to gtime_t struct.
Definition mrtk_time.c:87
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
int n
Definition mrtk_peph.h:60
erpd_t * data
Definition mrtk_peph.h:61
int nmax
Definition mrtk_peph.h:60
ERP (earth rotation parameter) data type.
Definition mrtk_peph.h:48
double ypr
Definition mrtk_peph.h:51
double xp
Definition mrtk_peph.h:50
double yp
Definition mrtk_peph.h:50
double ut1_utc
Definition mrtk_peph.h:52
double mjd
Definition mrtk_peph.h:49
double xpr
Definition mrtk_peph.h:51
double lod
Definition mrtk_peph.h:53
GNSS time representation.
Definition mrtk_time.h:49
time_t time
Definition mrtk_time.h:50
double rbias[MAXRCV][2][3]
Definition mrtk_nav.h:428
int nemax
Definition mrtk_nav.h:396
double cbias[MAXSAT][3]
Definition mrtk_nav.h:427
pclk_t * pclk
Definition mrtk_nav.h:410
pcv_t pcvs[MAXSAT]
Definition mrtk_nav.h:430
peph_t * peph
Definition mrtk_nav.h:409
int nc
Definition mrtk_nav.h:397
int ne
Definition mrtk_nav.h:396
double clk[MAXSAT][1]
Definition mrtk_nav.h:78
gtime_t time
Definition mrtk_nav.h:76
float std[MAXSAT][1]
Definition mrtk_nav.h:79
double off[NFREQPCV][3]
Definition mrtk_nav.h:50
pcv_t * pcv
Definition mrtk_nav.h:57
float std[MAXSAT][4]
Definition mrtk_nav.h:68
double pos[MAXSAT][4]
Definition mrtk_nav.h:67
float vco[MAXSAT][3]
Definition mrtk_nav.h:72
double vel[MAXSAT][4]
Definition mrtk_nav.h:69
gtime_t time
Definition mrtk_nav.h:65
float cov[MAXSAT][3]
Definition mrtk_nav.h:71
int index
Definition mrtk_nav.h:66
float vst[MAXSAT][4]
Definition mrtk_nav.h:70
#define malloc(x)
Definition toml.c:52
#define free(x)
Definition toml.c:53