45#define SQR(x) ((x) * (x))
46#define MAX_VAR_EPH SQR(300.0)
58extern int satno(
int sys,
int prn) {
119 if (sat <= 0 ||
MAXSAT < sat) {
180#define NBDSTBL (MAXPRNCMP < 63 ? 64 : MAXPRNCMP + 1)
181static uint8_t
bdsgen_[
NBDSTBL] = {0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3};
190static int parse_bdslist(
const char* str,
int maxprn, uint8_t val, uint8_t* list) {
191 char buff[1024], *p, *q;
192 int prn1, prn2, prn, n = 0;
194 if (strlen(str) >=
sizeof(buff)) {
197 snprintf(buff,
sizeof(buff),
"%s", str);
198 for (p = strtok(buff,
", "); p; p = strtok(NULL,
", ")) {
199 if (*p !=
'C' && *p !=
'c') {
203 prn1 = (int)strtol(p + 1, &q, 10);
208 if (*(q + 1) !=
'C' && *(q + 1) !=
'c') {
212 prn2 = (int)strtol(p, &q, 10);
219 if (*q || prn1 < MINPRNCMP || prn2 > maxprn || prn1 > prn2) {
222 for (prn = prn1; prn <= prn2; prn++) {
223 if (list[prn] != val) {
286 trace(NULL, 1,
"set_bdsopt: invalid bds2prn=%s (all BDS-3)\n", opt->
bds2prn);
289 "warning : invalid [positioning] bds2_sats = \"%s\"; all BeiDou PRN 1-18 treated as BDS-3\n",
295 trace(NULL, 1,
"set_bdsopt: invalid bds3igso=%s (C06-C08)\n", opt->
bds3igso);
297 fprintf(stderr,
"warning : invalid [ambiguity_resolution] bds3_igso_sats = \"%s\"; C06-C08 used\n",
306 "warning : BeiDou is enabled but [positioning] bds2_sats is not set, so every BeiDou PRN 1-18 is "
307 "treated as BDS-3.\n"
308 " Set bds2_sats = [\"C09\", \"C10\"] for data after 2026-04-21, [\"C01-C18\"] for data "
309 "before 2026-04-10,\n"
310 " or [] to silence this warning (see the BeiDou PRN Reassignment guide).\n");
517 for (i = 0; i <
MAXFREQ; i++) {
520 for (i = 0; i <
MAXFREQ; i++) {
521 for (j = 0; j <
MAXFREQ; j++) {
522 if (def[j].freq_num == freq_nums[i]) {
540 static const int fn_l1l2[
MAXFREQ] = {1, 2, 0, 0, 0, 0, 0};
541 static const int fn_l1l5[
MAXFREQ] = {1, 5, 0, 0, 0, 0, 0};
542 static const int fn_l1l2l5[
MAXFREQ] = {1, 2, 5, 0, 0, 0, 0};
543 static const int fn_l1l5l2[
MAXFREQ] = {1, 5, 2, 0, 0, 0, 0};
545 static const int fn_e1e5a[
MAXFREQ] = {1, 5, 0, 0, 0, 0, 0};
546 static const int fn_e1e5b[
MAXFREQ] = {1, 7, 0, 0, 0, 0, 0};
547 static const int fn_e1e6[
MAXFREQ] = {1, 6, 0, 0, 0, 0, 0};
548 static const int fn_e1e5ae5be6[
MAXFREQ] = {1, 5, 7, 6, 0, 0, 0};
549 static const int fn_e1e5ae6e5b[
MAXFREQ] = {1, 5, 6, 7, 0, 0, 0};
551 static const int fn_b1b3[
MAXFREQ] = {2, 6, 0, 0, 0, 0, 0};
552 static const int fn_b1b2i[
MAXFREQ] = {2, 7, 0, 0, 0, 0, 0};
553 static const int fn_b1b2a[
MAXFREQ] = {2, 5, 0, 0, 0, 0, 0};
554 static const int fn_b1b3b2i[
MAXFREQ] = {2, 6, 7, 0, 0, 0, 0};
555 static const int fn_b1b3b2a[
MAXFREQ] = {2, 6, 5, 0, 0, 0, 0};
636 static const int fn_gps_clas[
MAXFREQ] = {1, 2, 5, 0, 0, 0, 0};
637 static const int fn_gal_clas[
MAXFREQ] = {1, 0, 5, 6, 7, 8, 0};
638 static const int fn_qzs_clas[
MAXFREQ] = {1, 2, 5, 6, 0, 0, 0};
651 if (!obsdef || freq_idx < 0 ||
MAXFREQ <= freq_idx) {
664 if (!obsdef || freq_num <= 0) {
667 for (i = 0; i <
MAXFREQ; i++) {
668 if (obsdef[i].freq_num == freq_num) {
683 double freq = 0.0, dfrq = 0.0;
685 if (!obsdef || freq_num <= 0) {
690 if (fcn < -7 || fcn > 6) {
693 if (freq_num == 1 || freq_num == 2) {
694 dfrq = dfrq_glo[freq_num - 1];
697 for (i = 0; i <
MAXFREQ; i++) {
698 if (obsdef[i].freq_num == freq_num) {
699 freq = obsdef[i].
freq_hz + dfrq * fcn;
719 }
else if ((sys &
SYS_GLO) && (freq_num == 1 || freq_num == 4)) {
727 }
else if ((sys &
SYS_GLO) && (freq_num == 2 || freq_num == 6)) {
731 }
else if ((sys &
SYS_GLO) && (freq_num == 3)) {
757 if (sscanf(
id,
"%d", &prn) == 1) {
767 return satno(sys, prn);
769 if (sscanf(
id,
"%c%d", &code, &prn) < 2) {
809 return satno(sys, prn);
819 switch (
satsys(sat, &prn)) {
821 sprintf(
id,
"G%02d", prn -
MINPRNGPS + 1);
824 sprintf(
id,
"R%02d", prn -
MINPRNGLO + 1);
827 sprintf(
id,
"E%02d", prn -
MINPRNGAL + 1);
830 sprintf(
id,
"J%02d", prn -
MINPRNQZS + 1);
833 sprintf(
id,
"C%02d", prn -
MINPRNCMP + 1);
836 sprintf(
id,
"I%02d", prn -
MINPRNIRN + 1);
839 sprintf(
id,
"L%02d", prn -
MINPRNLEO + 1);
842 sprintf(
id,
"%03d", prn);
848static int cmpeph(
const void* p1,
const void* p2) {
850 return q1->
ttr.
time != q2->ttr.time
851 ? (int)(q1->
ttr.
time - q2->ttr.time)
852 : (q1->
toe.
time != q2->toe.time ? (int)(q1->
toe.
time - q2->toe.time) : q1->
sat - q2->sat);
859 trace(NULL, 3,
"uniqeph: n=%d\n", nav->
n);
867 for (i = 1, j = 0; i < nav->
n; i++) {
870 nav->
eph[++j] = nav->
eph[i];
875 if (!(nav_eph = (
eph_t*)realloc(nav->
eph,
sizeof(
eph_t) * nav->
n))) {
876 trace(NULL, 1,
"uniqeph malloc error n=%d\n", nav->
n);
879 nav->
n = nav->
nmax = 0;
885 trace(NULL, 4,
"uniqeph: n=%d\n", nav->
n);
888static int cmpgeph(
const void* p1,
const void* p2) {
890 return q1->
tof.
time != q2->tof.time
891 ? (int)(q1->
tof.
time - q2->tof.time)
892 : (q1->
toe.
time != q2->toe.time ? (int)(q1->
toe.
time - q2->toe.time) : q1->
sat - q2->sat);
899 trace(NULL, 3,
"uniqgeph: ng=%d\n", nav->
ng);
907 for (i = j = 0; i < nav->
ng; i++) {
916 trace(NULL, 1,
"uniqgeph malloc error ng=%d\n", nav->
ng);
922 nav->
geph = nav_geph;
925 trace(NULL, 4,
"uniqgeph: ng=%d\n", nav->
ng);
928static int cmpseph(
const void* p1,
const void* p2) {
930 return q1->
tof.
time != q2->tof.time
931 ? (int)(q1->
tof.
time - q2->tof.time)
932 : (q1->
t0.
time != q2->t0.time ? (int)(q1->
t0.
time - q2->t0.time) : q1->
sat - q2->sat);
939 trace(NULL, 3,
"uniqseph: ns=%d\n", nav->
ns);
947 for (i = j = 0; i < nav->
ns; i++) {
955 trace(NULL, 1,
"uniqseph malloc error ns=%d\n", nav->
ns);
961 nav->
seph = nav_seph;
964 trace(NULL, 4,
"uniqseph: ns=%d\n", nav->
ns);
972 trace(NULL, 3,
"uniqnav: neph=%d ngeph=%d nseph=%d\n", nav->
n, nav->
ng, nav->
ns);
990 long toe_time, tof_time, toc_time, ttr_time;
993 trace(NULL, 3,
"loadnav: file=%s\n", file);
995 if (!(fp = fopen(file,
"r"))) {
999 while (fgets(buff,
sizeof(buff), fp)) {
1000 if (!strncmp(buff,
"IONUTC", 6)) {
1001 for (i = 0; i < 8; i++) {
1004 for (i = 0; i < 8; i++) {
1007 sscanf(buff,
"IONUTC,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf", &nav->
ion_gps[0],
1013 if ((p = strchr(buff,
','))) {
1022 nav->
geph[prn - 1] = geph0;
1024 toe_time = tof_time = 0;
1026 "%d,%d,%d,%d,%d,%ld,%ld,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,"
1029 &nav->
geph[prn - 1].
age, &toe_time, &tof_time, &nav->
geph[prn - 1].
pos[0],
1037 nav->
eph[sat - 1] = eph0;
1038 nav->
eph[sat - 1].
sat = sat;
1039 toe_time = toc_time = ttr_time = 0;
1041 "%d,%d,%d,%d,%ld,%ld,%ld,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,"
1042 "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%d,%d",
1044 &toe_time, &toc_time, &ttr_time, &nav->
eph[sat - 1].
A, &nav->
eph[sat - 1].
e, &nav->
eph[sat - 1].
i0,
1063 trace(NULL, 3,
"savenav: file=%s\n", file);
1065 if (!(fp = fopen(file,
"w"))) {
1069 for (i = 0; i <
MAXSAT; i++) {
1075 "%s,%d,%d,%d,%d,%d,%d,%d,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,"
1076 "%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,"
1077 "%.14E,%.14E,%.14E,%.14E,%.14E,%d,%d\n",
1091 "%s,%d,%d,%d,%d,%d,%d,%d,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,"
1092 "%.14E,%.14E,%.14E,%.14E,%.14E,%.14E\n",
1099 "IONUTC,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,"
1100 "%.14E,%.14E,%.14E,%.0f",
1122 nav->
n = nav->
nmax = 0;
1170 int sys =
satsys(sat, NULL);
1177 if (opt->
exsats[sat - 1] == 1) {
1180 if (opt->
exsats[sat - 1] == 2) {
1183 if (!(sys & opt->
navsys)) {
1196 if ((svh & 9) != 0 || (svh & 6) == 4) {
1197 trace(NULL, 3,
"unhealthy satellite: sat=%3d svh=%02X\n", sat, svh);
1201 trace(NULL, 3,
"unhealthy satellite: sat=%3d svh=%02X\n", sat, svh);
1205 trace(NULL, 3,
"invalid ura satellite: sat=%3d ura=%.2f\n", sat, sqrt(var));
MRTKLIB Constants — Physical, navigation, and system constants.
int savenav(const char *file, const nav_t *nav)
Save navigation data to file.
void satno2id(int sat, char *id)
Convert satellite number to satellite id.
void apply_pppsig(const int *pppsig)
Apply PPP signal selection options to obsdef tables.
int readnav(const char *file, nav_t *nav)
Read navigation data from file.
int satsys(int sat, int *prn)
Convert satellite number to satellite system.
void apply_claslib_ppprtk_obsdef(void)
Apply the upstream claslib PPP-RTK observation slot layout.
static obsdef_t obsdef_GLO[MAXFREQ]
static void save_obsdef_defaults(void)
int bds_gen(int prn)
BeiDou generation of a PRN.
static obsdef_t obsdef_GPS_def[MAXFREQ]
static obsdef_t * get_obsdef(int sys)
static void uniqgeph(nav_t *nav)
static obsdef_t obsdef_BDS_def[MAXFREQ]
int freq_idx2ant_idx(int sys, int freq_idx)
Convert frequency index to antenna PCV index.
int set_bds2prn(const char *str)
Set the BDS-2 satellites in BeiDou PRN 1-18.
static obsdef_t obsdef_GAL[MAXFREQ]
void set_obsdef(int sys, const int *freq_nums)
Rearrange obsdef table for a satellite system by frequency numbers.
static obsdef_t obsdef_BD2[MAXFREQ]
static int cmpseph(const void *p1, const void *p2)
static obsdef_t obsdef_GPS[MAXFREQ]
static obsdef_t obsdef_IRN[MAXFREQ]
static int obsdef_defaults_saved
static void uniqeph(nav_t *nav)
int is_bds3igso(int prn)
Test whether a BeiDou PRN is listed as BDS-3 IGSO (see set_bds3igso()).
int satno(int sys, int prn)
Convert satellite system+prn/slot number to satellite number.
static obsdef_t obsdef_QZS[MAXFREQ]
static uint8_t bds3igso_[(MAXPRNCMP< 63 ? 64 :MAXPRNCMP+1)]
int set_bds3igso(const char *str)
Set the BDS-3 IGSO satellites (excluded as PPP-AR reference satellite).
static int cmpgeph(const void *p1, const void *p2)
static obsdef_t obsdef_SBS_def[MAXFREQ]
void uniqnav(nav_t *nav)
Unique ephemerides in navigation data.
int freq_num2ant_idx(int sys, int freq_num)
Convert frequency number to antenna PCV index.
int satid2no(const char *id)
Convert satellite id to satellite number.
static obsdef_t obsdef_BD2_def[MAXFREQ]
int satsys_bd2(int sat, int *prn)
Distinguish BDS-2 from BDS-3.
double freq_num2freq(int sys, int freq_num, int fcn)
Convert frequency number to frequency in Hz.
static obsdef_t obsdef_GLO_def[MAXFREQ]
int satexclude(int sat, double var, int svh, const struct prcopt_t *opt)
Test excluded satellite.
static void uniqseph(nav_t *nav)
void freenav(nav_t *nav, int opt)
Free navigation data memory.
static obsdef_t obsdef_QZS_def[MAXFREQ]
static obsdef_t * get_obsdef_default(int sys)
static int parse_bdslist(const char *str, int maxprn, uint8_t val, uint8_t *list)
int is_bds2prn(int prn)
Test whether a BeiDou PRN is BDS-2 (see set_bds2prn()).
static uint8_t bdsgen_[(MAXPRNCMP< 63 ? 64 :MAXPRNCMP+1)]
static obsdef_t obsdef_SBS[MAXFREQ]
static obsdef_t obsdef_BDS[MAXFREQ]
static obsdef_t obsdef_GAL_def[MAXFREQ]
static obsdef_t obsdef_IRN_def[MAXFREQ]
int freq_num2freq_idx(int sys, int freq_num)
Convert frequency number to frequency index using obsdef table.
int freq_idx2freq_num(int sys, int freq_idx)
Convert frequency index to frequency number using obsdef table.
int set_bdsopt(const prcopt_t *opt, int warn)
Apply the BeiDou PRN-reassignment options process-wide.
static int cmpeph(const void *p1, const void *p2)
void reset_obsdef(void)
Reset all obsdef tables to their pristine default frequency layout.
MRTKLIB Navigation Module — Navigation data types and satellite/nav utility functions.
MRTKLIB Options Module — Processing and solution option types.
void trace(mrtk_ctx_t *ctx, int level, const char *format,...)
Output trace message.
MRTKLIB Trace Module — debug trace and logging functions.
GPS/GAL/QZS/BDS/IRN broadcast ephemeris type.
GLONASS broadcast ephemeris type.