MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_nav.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_nav.c : navigation data 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_nav.c
18 * @brief MRTKLIB Navigation Module — Implementation.
19 *
20 * All functions and static data in this file are cut-and-paste extractions
21 * from the legacy rtkcmn.c with zero algorithmic changes.
22 */
23
24#include "mrtklib/mrtk_nav.h"
25
26#include <math.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include "mrtklib/mrtk_const.h"
32#include "mrtklib/mrtk_opt.h"
33#include "mrtklib/mrtk_trace.h"
34
35/*============================================================================
36 * Forward Declarations (resolved at link time)
37 *===========================================================================*/
38
39/*============================================================================
40 * Private Constants
41 *===========================================================================*/
42
43/* SYS_* constants are defined in mrtk_const.h (included above) */
44
45#define SQR(x) ((x) * (x))
46#define MAX_VAR_EPH SQR(300.0) /* max variance eph to reject satellite (m^2) */
47
48/*============================================================================
49 * Public Functions
50 *===========================================================================*/
51
52/* satellite system+prn/slot number to satellite number ------------------------
53 * convert satellite system+prn/slot number to satellite number
54 * args : int sys I satellite system (SYS_GPS,SYS_GLO,...)
55 * int prn I satellite prn/slot number
56 * return : satellite number (0:error)
57 *-----------------------------------------------------------------------------*/
58extern int satno(int sys, int prn) {
59 if (prn <= 0) {
60 return 0;
61 }
62 switch (sys) {
63 case SYS_GPS:
64 if (prn < MINPRNGPS || MAXPRNGPS < prn) {
65 return 0;
66 }
67 return prn - MINPRNGPS + 1;
68 case SYS_GLO:
69 if (prn < MINPRNGLO || MAXPRNGLO < prn) {
70 return 0;
71 }
72 return NSATGPS + prn - MINPRNGLO + 1;
73 case SYS_GAL:
74 if (prn < MINPRNGAL || MAXPRNGAL < prn) {
75 return 0;
76 }
77 return NSATGPS + NSATGLO + prn - MINPRNGAL + 1;
78 case SYS_QZS:
79 if (prn < MINPRNQZS || MAXPRNQZS < prn) {
80 return 0;
81 }
82 return NSATGPS + NSATGLO + NSATGAL + prn - MINPRNQZS + 1;
83 case SYS_CMP:
84 if (prn < MINPRNCMP || MAXPRNCMP < prn) {
85 return 0;
86 }
87 return NSATGPS + NSATGLO + NSATGAL + NSATQZS + prn - MINPRNCMP + 1;
88 case SYS_BD2:
89 if (prn < MINPRNCMP || MINPRNBDS3 <= prn || !is_bds2prn(prn)) {
90 return 0;
91 }
92 return NSATGPS + NSATGLO + NSATGAL + NSATQZS + prn - MINPRNCMP + 1;
93 case SYS_IRN:
94 if (prn < MINPRNIRN || MAXPRNIRN < prn) {
95 return 0;
96 }
97 return NSATGPS + NSATGLO + NSATGAL + NSATQZS + NSATCMP + prn - MINPRNIRN + 1;
98 case SYS_LEO:
99 if (prn < MINPRNLEO || MAXPRNLEO < prn) {
100 return 0;
101 }
102 return NSATGPS + NSATGLO + NSATGAL + NSATQZS + NSATCMP + NSATIRN + prn - MINPRNLEO + 1;
103 case SYS_SBS:
104 if (prn < MINPRNSBS || MAXPRNSBS < prn) {
105 return 0;
106 }
107 return NSATGPS + NSATGLO + NSATGAL + NSATQZS + NSATCMP + NSATIRN + NSATLEO + prn - MINPRNSBS + 1;
108 }
109 return 0;
110}
111/* satellite number to satellite system ----------------------------------------
112 * convert satellite number to satellite system
113 * args : int sat I satellite number (1-MAXSAT)
114 * int *prn IO satellite prn/slot number (NULL: no output)
115 * return : satellite system (SYS_GPS,SYS_GLO,...)
116 *-----------------------------------------------------------------------------*/
117extern int satsys(int sat, int* prn) {
118 int sys = SYS_NONE;
119 if (sat <= 0 || MAXSAT < sat) {
120 sat = 0;
121 } else if (sat <= NSATGPS) {
122 sys = SYS_GPS;
123 sat += MINPRNGPS - 1;
124 } else if ((sat -= NSATGPS) <= NSATGLO) {
125 sys = SYS_GLO;
126 sat += MINPRNGLO - 1;
127 } else if ((sat -= NSATGLO) <= NSATGAL) {
128 sys = SYS_GAL;
129 sat += MINPRNGAL - 1;
130 } else if ((sat -= NSATGAL) <= NSATQZS) {
131 sys = SYS_QZS;
132 sat += MINPRNQZS - 1;
133 } else if ((sat -= NSATQZS) <= NSATCMP) {
134 sys = SYS_CMP;
135 sat += MINPRNCMP - 1;
136 } else if ((sat -= NSATCMP) <= NSATIRN) {
137 sys = SYS_IRN;
138 sat += MINPRNIRN - 1;
139 } else if ((sat -= NSATIRN) <= NSATLEO) {
140 sys = SYS_LEO;
141 sat += MINPRNLEO - 1;
142 } else if ((sat -= NSATLEO) <= NSATSBS) {
143 sys = SYS_SBS;
144 sat += MINPRNSBS - 1;
145 } else {
146 sat = 0;
147 }
148 if (prn) {
149 *prn = sat;
150 }
151 return sys;
152}
153/* convert satellite number to satellite system (BDS2-aware) -------------------
154 * convert satellite number to satellite system, distinguishing BDS-2 from BDS-3
155 * args : int sat I satellite number (1-MAXSAT)
156 * int *prn IO satellite prn/slot number (NULL: no output)
157 * return : satellite system (SYS_GPS,SYS_GLO,...,SYS_BD2,SYS_CMP)
158 *-----------------------------------------------------------------------------*/
159extern int satsys_bd2(int sat, int* prn) {
160 int sys = SYS_NONE, _prn;
161
162 sys = satsys(sat, &_prn);
163#ifdef ENACMP
164 if (sys == SYS_CMP && is_bds2prn(_prn)) {
165 sys = SYS_BD2;
166 }
167#endif
168
169 if (prn) {
170 *prn = _prn;
171 }
172 return sys;
173}
174/* BeiDou generation of PRN 1-18 -----------------------------------------------
175 * Since the BeiDou PRN reassignment (2026-04-10 to 04-21) BDS-3 satellites are
176 * also on PRN 1-18, so the generation can no longer be told from the PRN. A PRN
177 * 1-18 is BDS-2 only when set_bds2prn() lists it; PRN >= MINPRNBDS3 is always
178 * BDS-3. Default (as upstream MADOCALIB 2.2): no BDS-2.
179 *-----------------------------------------------------------------------------*/
180#define NBDSTBL (MAXPRNCMP < 63 ? 64 : MAXPRNCMP + 1) /* table size, also valid when ENACMP is undefined */
181static uint8_t bdsgen_[NBDSTBL] = {0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3};
182
183/* BDS-3 IGSO satellites, excluded from the PPP-AR reference satellite selection.
184 * Default C06-C08 (since the PRN reassignment; C38-C40 before it). */
185static uint8_t bds3igso_[NBDSTBL] = {0, 0, 0, 0, 0, 0, 1, 1, 1};
186
187/* parse a BeiDou satellite list ("C09,C10", "C01-C18", comma/space separated)
188 * into list[prn]=val for prn in [MINPRNCMP,maxprn]; return the number of
189 * satellites listed, or -1 on a malformed entry */
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;
193
194 if (strlen(str) >= sizeof(buff)) { /* reject, never apply a truncated prefix */
195 return -1;
196 }
197 snprintf(buff, sizeof(buff), "%s", str);
198 for (p = strtok(buff, ", "); p; p = strtok(NULL, ", ")) {
199 if (*p != 'C' && *p != 'c') {
200 return -1;
201 }
202 /* each number must consume its token: "C09x", "C09-C10-C11" are errors */
203 prn1 = (int)strtol(p + 1, &q, 10);
204 if (q == p + 1) {
205 return -1;
206 }
207 if (*q == '-') {
208 if (*(q + 1) != 'C' && *(q + 1) != 'c') {
209 return -1;
210 }
211 p = q + 2;
212 prn2 = (int)strtol(p, &q, 10);
213 if (q == p) {
214 return -1;
215 }
216 } else {
217 prn2 = prn1;
218 }
219 if (*q || prn1 < MINPRNCMP || prn2 > maxprn || prn1 > prn2) {
220 return -1;
221 }
222 for (prn = prn1; prn <= prn2; prn++) {
223 if (list[prn] != val) {
224 n++;
225 }
226 list[prn] = val;
227 }
228 }
229 return n;
230}
231extern int set_bds2prn(const char* str) {
232 uint8_t list[NBDSTBL] = {0};
233 int prn, n;
234
235 for (prn = MINPRNCMP; prn < MINPRNBDS3 && prn <= MAXPRNCMP; prn++) {
236 list[prn] = BDSGEN_3;
237 }
238 memcpy(bdsgen_, list, sizeof(bdsgen_));
239
240 if (!str || !*str) {
241 return 0;
242 }
243 if ((n = parse_bdslist(str, MINPRNBDS3 - 1, BDSGEN_2, list)) < 0) {
244 return -1;
245 }
246 memcpy(bdsgen_, list, sizeof(bdsgen_));
247 return n;
248}
249extern int is_bds2prn(int prn) { return bds_gen(prn) == BDSGEN_2; }
250
251extern int set_bds3igso(const char* str) {
252 uint8_t list[NBDSTBL] = {0};
253 int n;
254
255 memset(bds3igso_, 0, sizeof(bds3igso_));
256 bds3igso_[6] = bds3igso_[7] = bds3igso_[8] = 1;
257
258 if (!str || !*str) {
259 return 3;
260 }
261 if ((n = parse_bdslist(str, MAXPRNCMP, 1, list)) < 0) {
262 return -1;
263 }
264 memcpy(bds3igso_, list, sizeof(bds3igso_));
265 return n;
266}
267extern int is_bds3igso(int prn) {
268 if (prn < MINPRNCMP || MAXPRNCMP < prn) {
269 return 0;
270 }
271 return bds3igso_[prn];
272}
273extern int bds_gen(int prn) {
274 if (prn < MINPRNCMP || MAXPRNCMP < prn) {
275 return 0;
276 }
277 if (MINPRNBDS3 <= prn) {
278 return BDSGEN_3;
279 }
280 return bdsgen_[prn];
281}
282extern int set_bdsopt(const prcopt_t* opt, int warn) {
283 int stat = 1;
284
285 if (set_bds2prn(opt->bds2prn) < 0) {
286 trace(NULL, 1, "set_bdsopt: invalid bds2prn=%s (all BDS-3)\n", opt->bds2prn);
287 if (warn) {
288 fprintf(stderr,
289 "warning : invalid [positioning] bds2_sats = \"%s\"; all BeiDou PRN 1-18 treated as BDS-3\n",
290 opt->bds2prn);
291 }
292 stat = 0;
293 }
294 if (set_bds3igso(opt->bds3igso) < 0) {
295 trace(NULL, 1, "set_bdsopt: invalid bds3igso=%s (C06-C08)\n", opt->bds3igso);
296 if (warn) {
297 fprintf(stderr, "warning : invalid [ambiguity_resolution] bds3_igso_sats = \"%s\"; C06-C08 used\n",
298 opt->bds3igso);
299 }
300 stat = 0;
301 }
302 /* the PRN reassignment left BDS-2 on C09/C10, so an unset list silently
303 misclassifies current data as well as pre-reassignment data */
304 if (warn && (opt->navsys & SYS_CMP) && !opt->bds2prn_set) {
305 fprintf(stderr,
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");
311 }
312 return stat;
313}
314/* observation definition type for frequency mapping ---------------------------*/
315typedef struct {
316 int freq_num; /* frequency number [1,2,5,...] */
317 double freq_hz; /* frequency [Hz] */
318} obsdef_t;
319
321 /* freq-index:freq */
322 {1, FREQ1}, /* 0:L1 (MRTK_BAND_GPS_L1) */
323 {2, FREQ2}, /* 1:L2 (MRTK_BAND_GPS_L2) */
324 {5, FREQ5}, /* 2:L5 (MRTK_BAND_GPS_L5) */
325 {0, 0.0}, /* 3 */
326 {0, 0.0}, /* 4 */
327 {0, 0.0}, /* 5 */
328 {0, 0.0}, /* 6 */
329};
331 /* freq-index:freq */
332 {1, FREQ1_GLO}, /* 0:G1 (MRTK_BAND_GLO_G1) */
333 {2, FREQ2_GLO}, /* 1:G2 (MRTK_BAND_GLO_G2) */
334 {0, 0.0}, /* 2 */
335 {0, 0.0}, /* 3 */
336 {0, 0.0}, /* 4 */
337 {0, 0.0}, /* 5 */
338 {0, 0.0}, /* 6 */
339};
341 /* freq-index:freq */
342 {1, FREQ1}, /* 0:E1 (MRTK_BAND_GAL_E1) */
343 {5, FREQ5}, /* 1:E5a (MRTK_BAND_GAL_E5a) */
344 {7, FREQ7}, /* 2:E5b (MRTK_BAND_GAL_E5b) */
345 {6, FREQ6}, /* 3:E6 (MRTK_BAND_GAL_E6) */
346 {8, FREQ8}, /* 4:E5ab(MRTK_BAND_GAL_E5ab)*/
347 {0, 0.0}, /* 5 */
348 {0, 0.0}, /* 6 */
349};
351 /* freq-index:freq */
352 {1, FREQ1}, /* 0:L1 (MRTK_BAND_QZS_L1) */
353 {5, FREQ5}, /* 1:L5 (MRTK_BAND_QZS_L5) */
354 {2, FREQ2}, /* 2:L2 (MRTK_BAND_QZS_L2) */
355 {6, FREQ6}, /* 3:L6 (MRTK_BAND_QZS_L6) */
356 {0, 0.0}, /* 4 */
357 {0, 0.0}, /* 5 */
358 {0, 0.0}, /* 6 */
359};
361 /* freq-index:freq */
362 {1, FREQ1}, /* 0:L1 (MRTK_BAND_SBS_L1) */
363 {5, FREQ5}, /* 1:L5 (MRTK_BAND_SBS_L5) */
364 {0, 0.0}, /* 2 */
365 {0, 0.0}, /* 3 */
366 {0, 0.0}, /* 4 */
367 {0, 0.0}, /* 5 */
368 {0, 0.0}, /* 6 */
369};
371 /* freq-index:freq */
372 {2, FREQ1_CMP}, /* 0:B1I (MRTK_BAND_BDS_B1I) */
373 {6, FREQ3_CMP}, /* 1:B3I (MRTK_BAND_BDS_B3) */
374 {7, FREQ2_CMP}, /* 2:B2I/B2b(MRTK_BAND_BDS_B2b) */
375 {1, FREQ1}, /* 3:B1C (MRTK_BAND_BDS_B1C) */
376 {5, FREQ5}, /* 4:B2a (MRTK_BAND_BDS_B2a) */
377 {8, FREQ8}, /* 5:B2 (MRTK_BAND_BDS_B2ab) */
378 {0, 0.0}, /* 6 */
379};
381 /* freq-index:freq */
382 {2, FREQ1_CMP}, /* 0:B1I (MRTK_BAND_BDS_B1I) */
383 {6, FREQ3_CMP}, /* 1:B3I (MRTK_BAND_BDS_B3) */
384 {7, FREQ2_CMP}, /* 2:B2I (MRTK_BAND_BDS_B2b) */
385 {0, 0.0}, /* 3 */
386 {0, 0.0}, /* 4 */
387 {0, 0.0}, /* 5 */
388 {0, 0.0}, /* 6 */
389};
391 /* freq-index:freq */
392 {5, FREQ5}, /* 0:L5 (MRTK_BAND_IRN_L5) */
393 {9, FREQ9}, /* 1:S (MRTK_BAND_IRN_S) */
394 {0, 0.0}, /* 2 */
395 {0, 0.0}, /* 3 */
396 {0, 0.0}, /* 4 */
397 {0, 0.0}, /* 5 */
398 {0, 0.0}, /* 6 */
399};
400/* helper: select obsdef table by system -------------------------------------*/
401static obsdef_t* get_obsdef(int sys) {
402 switch (sys) {
403 case SYS_GPS:
404 return obsdef_GPS;
405 case SYS_GLO:
406 return obsdef_GLO;
407 case SYS_GAL:
408 return obsdef_GAL;
409 case SYS_QZS:
410 return obsdef_QZS;
411 case SYS_SBS:
412 return obsdef_SBS;
413 case SYS_CMP:
414 return obsdef_BDS;
415 case SYS_BD2:
416 return obsdef_BD2;
417 case SYS_IRN:
418 return obsdef_IRN;
419 default:
420 return NULL;
421 }
422}
423/* pristine default snapshots of the obsdef tables ----------------------------
424 * #186: set_obsdef() rewrites the working tables in place, zeroing the bands
425 * not in the selected pair. Without a pristine reference, signal selection is
426 * not idempotent across rtkrcv restarts — a band trimmed by one selection
427 * cannot be restored by a later one, and switching to correction=igs (which
428 * skips apply_pppsig) leaves the tables trimmed. We snapshot the default tables
429 * on first use, before any mutation, so set_obsdef() / reset_obsdef() can always
430 * rebuild from them. The working-table initialisers above stay the single
431 * source of truth for the default values.
432 *---------------------------------------------------------------------------*/
436
437/* helper: select pristine-default obsdef table by system (mirrors get_obsdef) */
438static obsdef_t* get_obsdef_default(int sys) {
439 switch (sys) {
440 case SYS_GPS:
441 return obsdef_GPS_def;
442 case SYS_GLO:
443 return obsdef_GLO_def;
444 case SYS_GAL:
445 return obsdef_GAL_def;
446 case SYS_QZS:
447 return obsdef_QZS_def;
448 case SYS_SBS:
449 return obsdef_SBS_def;
450 case SYS_CMP:
451 return obsdef_BDS_def;
452 case SYS_BD2:
453 return obsdef_BD2_def;
454 case SYS_IRN:
455 return obsdef_IRN_def;
456 default:
457 return NULL;
458 }
459}
460
461/* capture the pristine default tables on first use (before any mutation) */
462static void save_obsdef_defaults(void) {
464 return;
465 }
466 memcpy(obsdef_GPS_def, obsdef_GPS, sizeof(obsdef_GPS));
467 memcpy(obsdef_GLO_def, obsdef_GLO, sizeof(obsdef_GLO));
468 memcpy(obsdef_GAL_def, obsdef_GAL, sizeof(obsdef_GAL));
469 memcpy(obsdef_QZS_def, obsdef_QZS, sizeof(obsdef_QZS));
470 memcpy(obsdef_SBS_def, obsdef_SBS, sizeof(obsdef_SBS));
471 memcpy(obsdef_BDS_def, obsdef_BDS, sizeof(obsdef_BDS));
472 memcpy(obsdef_BD2_def, obsdef_BD2, sizeof(obsdef_BD2));
473 memcpy(obsdef_IRN_def, obsdef_IRN, sizeof(obsdef_IRN));
475}
476
477/* reset obsdef tables to their pristine defaults -----------------------------
478 * #186: restore the full multi-band tables, e.g. before re-applying signal
479 * selection on an rtkrcv restart, or when switching to correction=igs (which
480 * skips apply_pppsig and must see the receiver's actual bands, #135).
481 * return : none
482 *-----------------------------------------------------------------------------*/
483extern void reset_obsdef(void) {
485 memcpy(obsdef_GPS, obsdef_GPS_def, sizeof(obsdef_GPS));
486 memcpy(obsdef_GLO, obsdef_GLO_def, sizeof(obsdef_GLO));
487 memcpy(obsdef_GAL, obsdef_GAL_def, sizeof(obsdef_GAL));
488 memcpy(obsdef_QZS, obsdef_QZS_def, sizeof(obsdef_QZS));
489 memcpy(obsdef_SBS, obsdef_SBS_def, sizeof(obsdef_SBS));
490 memcpy(obsdef_BDS, obsdef_BDS_def, sizeof(obsdef_BDS));
491 memcpy(obsdef_BD2, obsdef_BD2_def, sizeof(obsdef_BD2));
492 memcpy(obsdef_IRN, obsdef_IRN_def, sizeof(obsdef_IRN));
493}
494
495/* set observation definition by frequency number array -----------------------
496 * rearrange obsdef table so that freq_nums[0..MAXFREQ-1] appear at indices
497 * 0,1,2,... — used to apply pos2-sig* signal selection options.
498 * args : int sys I satellite system (SYS_GPS,SYS_CMP,...)
499 * const int *freq_nums I array of frequency numbers (1 x MAXFREQ)
500 * return : none
501 *-----------------------------------------------------------------------------*/
502extern void set_obsdef(int sys, const int* freq_nums) {
503 obsdef_t* obsdef;
504 const obsdef_t* def;
505 obsdef_t obsdef0 = {0};
506 int i, j;
507
509
510 if (!(obsdef = get_obsdef(sys)) || !(def = get_obsdef_default(sys))) {
511 return;
512 }
513 /* #186: rebuild from the pristine defaults (not the current table) so a band
514 trimmed by a previous selection can still be restored — idempotent. On the
515 first call the defaults equal the current table, so the result is
516 bit-identical to the historical in-place behaviour. */
517 for (i = 0; i < MAXFREQ; i++) {
518 obsdef[i] = obsdef0;
519 }
520 for (i = 0; i < MAXFREQ; i++) {
521 for (j = 0; j < MAXFREQ; j++) {
522 if (def[j].freq_num == freq_nums[i]) {
523 break;
524 }
525 }
526 if (j == MAXFREQ) {
527 continue;
528 }
529 obsdef[i].freq_num = def[j].freq_num;
530 obsdef[i].freq_hz = def[j].freq_hz;
531 }
532}
533/* apply PPP signal selection options to obsdef tables -----------------------
534 * rearrange obsdef tables based on pppsig[] options for madocalib PPP engine.
535 * args : const int *pppsig I signal selection [0]GPS,[1]QZS,[2]GAL,
536 * [3]BDS2,[4]BDS3 (from prcopt_t.pppsig)
537 * return : none
538 *-----------------------------------------------------------------------------*/
539extern void apply_pppsig(const int* pppsig) {
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};
544
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};
550
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};
556
557 /* GPS signal selection */
558 switch (pppsig[0]) {
559 case 0:
560 set_obsdef(SYS_GPS, fn_l1l2);
561 break;
562 case 1:
563 set_obsdef(SYS_GPS, fn_l1l5);
564 break;
565 case 2:
566 set_obsdef(SYS_GPS, fn_l1l2l5);
567 break;
568 }
569 /* QZS signal selection */
570 switch (pppsig[1]) {
571 case 0:
572 set_obsdef(SYS_QZS, fn_l1l5);
573 break;
574 case 1:
575 set_obsdef(SYS_QZS, fn_l1l2);
576 break;
577 case 2:
578 set_obsdef(SYS_QZS, fn_l1l5l2);
579 break;
580 }
581 /* GAL signal selection */
582 switch (pppsig[2]) {
583 case 0:
584 set_obsdef(SYS_GAL, fn_e1e5a);
585 break;
586 case 1:
587 set_obsdef(SYS_GAL, fn_e1e5b);
588 break;
589 case 2:
590 set_obsdef(SYS_GAL, fn_e1e6);
591 break;
592 case 3:
593 set_obsdef(SYS_GAL, fn_e1e5ae5be6);
594 break;
595 case 4:
596 set_obsdef(SYS_GAL, fn_e1e5ae6e5b);
597 break;
598 }
599 /* BDS-2 signal selection */
600 switch (pppsig[3]) {
601 case 0:
602 set_obsdef(SYS_BD2, fn_b1b3);
603 break;
604 case 1:
605 set_obsdef(SYS_BD2, fn_b1b2i);
606 break;
607 case 2:
608 set_obsdef(SYS_BD2, fn_b1b3b2i);
609 break;
610 }
611 /* BDS-3 signal selection */
612 switch (pppsig[4]) {
613 case 0:
614 set_obsdef(SYS_CMP, fn_b1b3);
615 break;
616 case 1:
617 set_obsdef(SYS_CMP, fn_b1b2a);
618 break;
619 case 2:
620 set_obsdef(SYS_CMP, fn_b1b3b2a);
621 break;
622 }
623}
624
625/* apply upstream claslib PPP-RTK slot layout ---------------------------------
626 * claslib/RTKLIB uses abstract frequency slots from obsfreqs[]:
627 * GPS: L1, L2, L5
628 * GAL: E1, unused L2 slot, E5a, E6, E5b, E5ab
629 * QZS: L1, L2, L5, L6
630 * MRTK's normal obsdef is physical-band oriented (GAL E5a and QZS L5 at slot 1).
631 * For QZSS CLAS PPP-RTK, keep the post-processing path slot-compatible with
632 * upstream so cssr2osr's GAL slot-1 skip and QZS L2 default select the same
633 * ambiguities as claslib.
634 *-----------------------------------------------------------------------------*/
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};
639
640 set_obsdef(SYS_GPS, fn_gps_clas);
641 set_obsdef(SYS_GAL, fn_gal_clas);
642 set_obsdef(SYS_QZS, fn_qzs_clas);
643}
644/* convert frequency index to frequency number --------------------------------
645 * args : int sys I satellite system
646 * int freq_idx I frequency index (0,1,2,...)
647 * return : frequency number (1,2,5,6,7,...) or 0 on error
648 *-----------------------------------------------------------------------------*/
649extern int freq_idx2freq_num(int sys, int freq_idx) {
650 obsdef_t* obsdef = get_obsdef(sys);
651 if (!obsdef || freq_idx < 0 || MAXFREQ <= freq_idx) {
652 return 0;
653 }
654 return obsdef[freq_idx].freq_num;
655}
656/* convert frequency number to frequency index --------------------------------
657 * args : int sys I satellite system
658 * int freq_num I frequency number (1,2,5,6,7,...)
659 * return : frequency index (0,1,2,...) or -1 on error
660 *-----------------------------------------------------------------------------*/
661extern int freq_num2freq_idx(int sys, int freq_num) {
662 obsdef_t* obsdef = get_obsdef(sys);
663 int i;
664 if (!obsdef || freq_num <= 0) {
665 return -1;
666 }
667 for (i = 0; i < MAXFREQ; i++) {
668 if (obsdef[i].freq_num == freq_num) {
669 return i;
670 }
671 }
672 return -1;
673}
674/* convert frequency number to frequency (Hz) ---------------------------------
675 * args : int sys I satellite system
676 * int freq_num I frequency number (1,2,5,6,7,...)
677 * int fcn I GLONASS frequency channel number (-7..6)
678 * return : carrier frequency (Hz) or 0.0 on error
679 *-----------------------------------------------------------------------------*/
680extern double freq_num2freq(int sys, int freq_num, int fcn) {
681 const double dfrq_glo[] = {DFRQ1_GLO, DFRQ2_GLO, 0.0};
682 obsdef_t* obsdef = get_obsdef(sys);
683 double freq = 0.0, dfrq = 0.0;
684 int i;
685 if (!obsdef || freq_num <= 0) {
686 return 0.0;
687 }
688
689 if (sys == SYS_GLO) {
690 if (fcn < -7 || fcn > 6) {
691 return 0.0;
692 }
693 if (freq_num == 1 || freq_num == 2) {
694 dfrq = dfrq_glo[freq_num - 1];
695 }
696 }
697 for (i = 0; i < MAXFREQ; i++) {
698 if (obsdef[i].freq_num == freq_num) {
699 freq = obsdef[i].freq_hz + dfrq * fcn;
700 break;
701 }
702 }
703 return freq;
704}
705/* convert frequency number to antenna PCV index ------------------------------
706 * args : int sys I satellite system
707 * int freq_num I frequency number (1,2,5,6,7,...)
708 * return : antenna PCV index (0..NFREQPCV-1)
709 *-----------------------------------------------------------------------------*/
710extern int freq_num2ant_idx(int sys, int freq_num) {
711 int idx = NFREQPCV - 1;
712
713 if ((sys & (SYS_GPS | SYS_GAL | SYS_QZS | SYS_SBS | SYS_CMP | SYS_BD2)) && (freq_num == 1)) {
714 idx = 0;
715 } else if ((sys & (SYS_GPS | SYS_QZS)) && (freq_num == 2)) {
716 idx = 1;
717 } else if ((sys & (SYS_GPS | SYS_GAL | SYS_QZS | SYS_SBS | SYS_CMP | SYS_BD2)) && (freq_num == 5)) {
718 idx = 2;
719 } else if ((sys & SYS_GLO) && (freq_num == 1 || freq_num == 4)) {
720 idx = 3;
721 } else if ((sys & (SYS_CMP | SYS_BD2)) && (freq_num == 2)) {
722 idx = 4;
723 } else if ((sys & (SYS_GAL | SYS_QZS)) && (freq_num == 6)) {
724 idx = 5;
725 } else if ((sys & (SYS_CMP | SYS_BD2)) && (freq_num == 6)) {
726 idx = 6;
727 } else if ((sys & SYS_GLO) && (freq_num == 2 || freq_num == 6)) {
728 idx = 7;
729 } else if ((sys & (SYS_GAL | SYS_CMP | SYS_BD2)) && (freq_num == 7)) {
730 idx = 8;
731 } else if ((sys & SYS_GLO) && (freq_num == 3)) {
732 idx = 9;
733 } else if ((sys & (SYS_GAL | SYS_CMP | SYS_BD2)) && (freq_num == 8)) {
734 idx = 10;
735 }
736 return idx;
737}
738/* convert frequency index to antenna PCV index --------------------------------
739 * args : int sys I satellite system
740 * int freq_idx I frequency index (0,1,2,...)
741 * return : antenna PCV index (0..NFREQPCV-1)
742 *-----------------------------------------------------------------------------*/
743extern int freq_idx2ant_idx(int sys, int freq_idx) {
744 int fn = freq_idx2freq_num(sys, freq_idx);
745 return freq_num2ant_idx(sys, fn);
746}
747/* satellite id to satellite number --------------------------------------------
748 * convert satellite id to satellite number
749 * args : char *id I satellite id (nn,Gnn,Rnn,Enn,Jnn,Cnn,Inn or Snn)
750 * return : satellite number (0: error)
751 * notes : 120-142 and 193-199 are also recognized as sbas and qzss
752 *-----------------------------------------------------------------------------*/
753extern int satid2no(const char* id) {
754 int sys, prn;
755 char code;
756
757 if (sscanf(id, "%d", &prn) == 1) {
758 if (MINPRNGPS <= prn && prn <= MAXPRNGPS) {
759 sys = SYS_GPS;
760 } else if (MINPRNSBS <= prn && prn <= MAXPRNSBS) {
761 sys = SYS_SBS;
762 } else if (MINPRNQZS <= prn && prn <= MAXPRNQZS) {
763 sys = SYS_QZS;
764 } else {
765 return 0;
766 }
767 return satno(sys, prn);
768 }
769 if (sscanf(id, "%c%d", &code, &prn) < 2) {
770 return 0;
771 }
772
773 switch (code) {
774 case 'G':
775 sys = SYS_GPS;
776 prn += MINPRNGPS - 1;
777 break;
778 case 'R':
779 sys = SYS_GLO;
780 prn += MINPRNGLO - 1;
781 break;
782 case 'E':
783 sys = SYS_GAL;
784 prn += MINPRNGAL - 1;
785 break;
786 case 'J':
787 sys = SYS_QZS;
788 prn += MINPRNQZS - 1;
789 break;
790 case 'C':
791 sys = SYS_CMP;
792 prn += MINPRNCMP - 1;
793 break;
794 case 'I':
795 sys = SYS_IRN;
796 prn += MINPRNIRN - 1;
797 break;
798 case 'L':
799 sys = SYS_LEO;
800 prn += MINPRNLEO - 1;
801 break;
802 case 'S':
803 sys = SYS_SBS;
804 prn += 100;
805 break;
806 default:
807 return 0;
808 }
809 return satno(sys, prn);
810}
811/* satellite number to satellite id --------------------------------------------
812 * convert satellite number to satellite id
813 * args : int sat I satellite number
814 * char *id O satellite id (Gnn,Rnn,Enn,Jnn,Cnn,Inn or nnn)
815 * return : none
816 *-----------------------------------------------------------------------------*/
817extern void satno2id(int sat, char* id) {
818 int prn;
819 switch (satsys(sat, &prn)) {
820 case SYS_GPS:
821 sprintf(id, "G%02d", prn - MINPRNGPS + 1);
822 return;
823 case SYS_GLO:
824 sprintf(id, "R%02d", prn - MINPRNGLO + 1);
825 return;
826 case SYS_GAL:
827 sprintf(id, "E%02d", prn - MINPRNGAL + 1);
828 return;
829 case SYS_QZS:
830 sprintf(id, "J%02d", prn - MINPRNQZS + 1);
831 return;
832 case SYS_CMP:
833 sprintf(id, "C%02d", prn - MINPRNCMP + 1);
834 return;
835 case SYS_IRN:
836 sprintf(id, "I%02d", prn - MINPRNIRN + 1);
837 return;
838 case SYS_LEO:
839 sprintf(id, "L%02d", prn - MINPRNLEO + 1);
840 return;
841 case SYS_SBS:
842 sprintf(id, "%03d", prn);
843 return;
844 }
845 strcpy(id, "");
846}
847/* compare ephemeris ---------------------------------------------------------*/
848static int cmpeph(const void* p1, const void* p2) {
849 eph_t *q1 = (eph_t*)p1, *q2 = (eph_t*)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);
853}
854/* sort and unique ephemeris -------------------------------------------------*/
855static void uniqeph(nav_t* nav) {
856 eph_t* nav_eph;
857 int i, j;
858
859 trace(NULL, 3, "uniqeph: n=%d\n", nav->n);
860
861 if (nav->n <= 0) {
862 return;
863 }
864
865 qsort(nav->eph, nav->n, sizeof(eph_t), cmpeph);
866
867 for (i = 1, j = 0; i < nav->n; i++) {
868 if (nav->eph[i].sat != nav->eph[j].sat || nav->eph[i].iode != nav->eph[j].iode ||
869 nav->eph[i].type != nav->eph[j].type) {
870 nav->eph[++j] = nav->eph[i];
871 }
872 }
873 nav->n = j + 1;
874
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);
877 free(nav->eph);
878 nav->eph = NULL;
879 nav->n = nav->nmax = 0;
880 return;
881 }
882 nav->eph = nav_eph;
883 nav->nmax = nav->n;
884
885 trace(NULL, 4, "uniqeph: n=%d\n", nav->n);
886}
887/* compare glonass ephemeris -------------------------------------------------*/
888static int cmpgeph(const void* p1, const void* p2) {
889 geph_t *q1 = (geph_t*)p1, *q2 = (geph_t*)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);
893}
894/* sort and unique glonass ephemeris -----------------------------------------*/
895static void uniqgeph(nav_t* nav) {
896 geph_t* nav_geph;
897 int i, j;
898
899 trace(NULL, 3, "uniqgeph: ng=%d\n", nav->ng);
900
901 if (nav->ng <= 0) {
902 return;
903 }
904
905 qsort(nav->geph, nav->ng, sizeof(geph_t), cmpgeph);
906
907 for (i = j = 0; i < nav->ng; i++) {
908 if (nav->geph[i].sat != nav->geph[j].sat || nav->geph[i].toe.time != nav->geph[j].toe.time ||
909 nav->geph[i].svh != nav->geph[j].svh) {
910 nav->geph[++j] = nav->geph[i];
911 }
912 }
913 nav->ng = j + 1;
914
915 if (!(nav_geph = (geph_t*)realloc(nav->geph, sizeof(geph_t) * nav->ng))) {
916 trace(NULL, 1, "uniqgeph malloc error ng=%d\n", nav->ng);
917 free(nav->geph);
918 nav->geph = NULL;
919 nav->ng = nav->ngmax = 0;
920 return;
921 }
922 nav->geph = nav_geph;
923 nav->ngmax = nav->ng;
924
925 trace(NULL, 4, "uniqgeph: ng=%d\n", nav->ng);
926}
927/* compare sbas ephemeris ----------------------------------------------------*/
928static int cmpseph(const void* p1, const void* p2) {
929 seph_t *q1 = (seph_t*)p1, *q2 = (seph_t*)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);
933}
934/* sort and unique sbas ephemeris --------------------------------------------*/
935static void uniqseph(nav_t* nav) {
936 seph_t* nav_seph;
937 int i, j;
938
939 trace(NULL, 3, "uniqseph: ns=%d\n", nav->ns);
940
941 if (nav->ns <= 0) {
942 return;
943 }
944
945 qsort(nav->seph, nav->ns, sizeof(seph_t), cmpseph);
946
947 for (i = j = 0; i < nav->ns; i++) {
948 if (nav->seph[i].sat != nav->seph[j].sat || nav->seph[i].t0.time != nav->seph[j].t0.time) {
949 nav->seph[++j] = nav->seph[i];
950 }
951 }
952 nav->ns = j + 1;
953
954 if (!(nav_seph = (seph_t*)realloc(nav->seph, sizeof(seph_t) * nav->ns))) {
955 trace(NULL, 1, "uniqseph malloc error ns=%d\n", nav->ns);
956 free(nav->seph);
957 nav->seph = NULL;
958 nav->ns = nav->nsmax = 0;
959 return;
960 }
961 nav->seph = nav_seph;
962 nav->nsmax = nav->ns;
963
964 trace(NULL, 4, "uniqseph: ns=%d\n", nav->ns);
965}
966/* unique ephemerides ----------------------------------------------------------
967 * unique ephemerides in navigation data
968 * args : nav_t *nav IO navigation data
969 * return : number of epochs
970 *-----------------------------------------------------------------------------*/
971extern void uniqnav(nav_t* nav) {
972 trace(NULL, 3, "uniqnav: neph=%d ngeph=%d nseph=%d\n", nav->n, nav->ng, nav->ns);
973
974 /* unique ephemeris */
975 uniqeph(nav);
976 uniqgeph(nav);
977 uniqseph(nav);
978}
979/* read/save navigation data ---------------------------------------------------
980 * save or load navigation data
981 * args : char file I file path
982 * nav_t nav O/I navigation data
983 * return : status (1:ok,0:no file)
984 *-----------------------------------------------------------------------------*/
985extern int readnav(const char* file, nav_t* nav) {
986 FILE* fp;
987 eph_t eph0 = {0};
988 geph_t geph0 = {0};
989 char buff[4096], *p;
990 long toe_time, tof_time, toc_time, ttr_time;
991 int i, sat, prn;
992
993 trace(NULL, 3, "loadnav: file=%s\n", file);
994
995 if (!(fp = fopen(file, "r"))) {
996 return 0;
997 }
998
999 while (fgets(buff, sizeof(buff), fp)) {
1000 if (!strncmp(buff, "IONUTC", 6)) {
1001 for (i = 0; i < 8; i++) {
1002 nav->ion_gps[i] = 0.0;
1003 }
1004 for (i = 0; i < 8; i++) {
1005 nav->utc_gps[i] = 0.0;
1006 }
1007 sscanf(buff, "IONUTC,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf", &nav->ion_gps[0],
1008 &nav->ion_gps[1], &nav->ion_gps[2], &nav->ion_gps[3], &nav->ion_gps[4], &nav->ion_gps[5],
1009 &nav->ion_gps[6], &nav->ion_gps[7], &nav->utc_gps[0], &nav->utc_gps[1], &nav->utc_gps[2],
1010 &nav->utc_gps[3], &nav->utc_gps[4]);
1011 continue;
1012 }
1013 if ((p = strchr(buff, ','))) {
1014 *p = '\0';
1015 } else {
1016 continue;
1017 }
1018 if (!(sat = satid2no(buff))) {
1019 continue;
1020 }
1021 if (satsys(sat, &prn) == SYS_GLO) {
1022 nav->geph[prn - 1] = geph0;
1023 nav->geph[prn - 1].sat = sat;
1024 toe_time = tof_time = 0;
1025 sscanf(p + 1,
1026 "%d,%d,%d,%d,%d,%ld,%ld,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,"
1027 "%lf,%lf,%lf,%lf",
1028 &nav->geph[prn - 1].iode, &nav->geph[prn - 1].frq, &nav->geph[prn - 1].svh, &nav->geph[prn - 1].sva,
1029 &nav->geph[prn - 1].age, &toe_time, &tof_time, &nav->geph[prn - 1].pos[0],
1030 &nav->geph[prn - 1].pos[1], &nav->geph[prn - 1].pos[2], &nav->geph[prn - 1].vel[0],
1031 &nav->geph[prn - 1].vel[1], &nav->geph[prn - 1].vel[2], &nav->geph[prn - 1].acc[0],
1032 &nav->geph[prn - 1].acc[1], &nav->geph[prn - 1].acc[2], &nav->geph[prn - 1].taun,
1033 &nav->geph[prn - 1].gamn, &nav->geph[prn - 1].dtaun);
1034 nav->geph[prn - 1].toe.time = toe_time;
1035 nav->geph[prn - 1].tof.time = tof_time;
1036 } else {
1037 nav->eph[sat - 1] = eph0;
1038 nav->eph[sat - 1].sat = sat;
1039 toe_time = toc_time = ttr_time = 0;
1040 sscanf(p + 1,
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",
1043 &nav->eph[sat - 1].iode, &nav->eph[sat - 1].iodc, &nav->eph[sat - 1].sva, &nav->eph[sat - 1].svh,
1044 &toe_time, &toc_time, &ttr_time, &nav->eph[sat - 1].A, &nav->eph[sat - 1].e, &nav->eph[sat - 1].i0,
1045 &nav->eph[sat - 1].OMG0, &nav->eph[sat - 1].omg, &nav->eph[sat - 1].M0, &nav->eph[sat - 1].deln,
1046 &nav->eph[sat - 1].OMGd, &nav->eph[sat - 1].idot, &nav->eph[sat - 1].crc, &nav->eph[sat - 1].crs,
1047 &nav->eph[sat - 1].cuc, &nav->eph[sat - 1].cus, &nav->eph[sat - 1].cic, &nav->eph[sat - 1].cis,
1048 &nav->eph[sat - 1].toes, &nav->eph[sat - 1].fit, &nav->eph[sat - 1].f0, &nav->eph[sat - 1].f1,
1049 &nav->eph[sat - 1].f2, &nav->eph[sat - 1].tgd[0], &nav->eph[sat - 1].code, &nav->eph[sat - 1].flag);
1050 nav->eph[sat - 1].toe.time = toe_time;
1051 nav->eph[sat - 1].toc.time = toc_time;
1052 nav->eph[sat - 1].ttr.time = ttr_time;
1053 }
1054 }
1055 fclose(fp);
1056 return 1;
1057}
1058extern int savenav(const char* file, const nav_t* nav) {
1059 FILE* fp;
1060 int i;
1061 char id[32];
1062
1063 trace(NULL, 3, "savenav: file=%s\n", file);
1064
1065 if (!(fp = fopen(file, "w"))) {
1066 return 0;
1067 }
1068
1069 for (i = 0; i < MAXSAT; i++) {
1070 if (nav->eph[i].ttr.time == 0) {
1071 continue;
1072 }
1073 satno2id(nav->eph[i].sat, id);
1074 fprintf(fp,
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",
1078 id, nav->eph[i].iode, nav->eph[i].iodc, nav->eph[i].sva, nav->eph[i].svh, (int)nav->eph[i].toe.time,
1079 (int)nav->eph[i].toc.time, (int)nav->eph[i].ttr.time, nav->eph[i].A, nav->eph[i].e, nav->eph[i].i0,
1080 nav->eph[i].OMG0, nav->eph[i].omg, nav->eph[i].M0, nav->eph[i].deln, nav->eph[i].OMGd, nav->eph[i].idot,
1081 nav->eph[i].crc, nav->eph[i].crs, nav->eph[i].cuc, nav->eph[i].cus, nav->eph[i].cic, nav->eph[i].cis,
1082 nav->eph[i].toes, nav->eph[i].fit, nav->eph[i].f0, nav->eph[i].f1, nav->eph[i].f2, nav->eph[i].tgd[0],
1083 nav->eph[i].code, nav->eph[i].flag);
1084 }
1085 for (i = 0; i < MAXPRNGLO; i++) {
1086 if (nav->geph[i].tof.time == 0) {
1087 continue;
1088 }
1089 satno2id(nav->geph[i].sat, id);
1090 fprintf(fp,
1091 "%s,%d,%d,%d,%d,%d,%d,%d,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,"
1092 "%.14E,%.14E,%.14E,%.14E,%.14E,%.14E\n",
1093 id, nav->geph[i].iode, nav->geph[i].frq, nav->geph[i].svh, nav->geph[i].sva, nav->geph[i].age,
1094 (int)nav->geph[i].toe.time, (int)nav->geph[i].tof.time, nav->geph[i].pos[0], nav->geph[i].pos[1],
1095 nav->geph[i].pos[2], nav->geph[i].vel[0], nav->geph[i].vel[1], nav->geph[i].vel[2], nav->geph[i].acc[0],
1096 nav->geph[i].acc[1], nav->geph[i].acc[2], nav->geph[i].taun, nav->geph[i].gamn, nav->geph[i].dtaun);
1097 }
1098 fprintf(fp,
1099 "IONUTC,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,"
1100 "%.14E,%.14E,%.14E,%.0f",
1101 nav->ion_gps[0], nav->ion_gps[1], nav->ion_gps[2], nav->ion_gps[3], nav->ion_gps[4], nav->ion_gps[5],
1102 nav->ion_gps[6], nav->ion_gps[7], nav->utc_gps[0], nav->utc_gps[1], nav->utc_gps[2], nav->utc_gps[3],
1103 nav->utc_gps[4]);
1104
1105 fclose(fp);
1106 return 1;
1107}
1108/* free navigation data ---------------------------------------------------------
1109 * free memory for navigation data
1110 * args : nav_t *nav IO navigation data
1111 * int opt I option (or of followings)
1112 * (0x01: gps/qzs ephmeris, 0x02: glonass ephemeris,
1113 * 0x04: sbas ephemeris, 0x08: precise ephemeris,
1114 * 0x10: precise clock 0x20: almanac,
1115 * 0x40: tec data 0x80: pppiono data)
1116 * return : none
1117 *-----------------------------------------------------------------------------*/
1118extern void freenav(nav_t* nav, int opt) {
1119 if (opt & 0x01) {
1120 free(nav->eph);
1121 nav->eph = NULL;
1122 nav->n = nav->nmax = 0;
1123 free(nav->eph_prev);
1124 nav->eph_prev = NULL;
1125 }
1126 if (opt & 0x02) {
1127 free(nav->geph);
1128 nav->geph = NULL;
1129 nav->ng = nav->ngmax = 0;
1130 }
1131 if (opt & 0x04) {
1132 free(nav->seph);
1133 nav->seph = NULL;
1134 nav->ns = nav->nsmax = 0;
1135 }
1136 if (opt & 0x08) {
1137 free(nav->peph);
1138 nav->peph = NULL;
1139 nav->ne = nav->nemax = 0;
1140 }
1141 if (opt & 0x10) {
1142 free(nav->pclk);
1143 nav->pclk = NULL;
1144 nav->nc = nav->ncmax = 0;
1145 }
1146 if (opt & 0x20) {
1147 free(nav->alm);
1148 nav->alm = NULL;
1149 nav->na = nav->namax = 0;
1150 }
1151 if (opt & 0x40) {
1152 free(nav->tec);
1153 nav->tec = NULL;
1154 nav->nt = nav->ntmax = 0;
1155 }
1156 if (opt & 0x80) {
1157 free(nav->pppiono);
1158 nav->pppiono = NULL;
1159 }
1160}
1161/* test excluded satellite ------------------------------------------------------
1162 * test excluded satellite
1163 * args : int sat I satellite number
1164 * double var I variance of ephemeris (m^2)
1165 * int svh I sv health flag
1166 * prcopt_t *opt I processing options (NULL: not used)
1167 * return : status (1:excluded,0:not excluded)
1168 *-----------------------------------------------------------------------------*/
1169int satexclude(int sat, double var, int svh, const struct prcopt_t* opt) {
1170 int sys = satsys(sat, NULL);
1171
1172 if (svh < 0) {
1173 return 1; /* ephemeris unavailable */
1174 }
1175
1176 if (opt) {
1177 if (opt->exsats[sat - 1] == 1) {
1178 return 1; /* excluded satellite */
1179 }
1180 if (opt->exsats[sat - 1] == 2) {
1181 return 0; /* included satellite */
1182 }
1183 if (!(sys & opt->navsys)) {
1184 return 1; /* unselected sat sys */
1185 }
1186 }
1187 if (sys == SYS_QZS) {
1188 svh &= 0xFE; /* mask QZSS LEX health */
1189 }
1190 if (sys == SYS_CMP) {
1191 svh &= ~0x1D; /* mask BeiDou health by reserved bit */
1192 }
1193 if (sys == SYS_GLO) {
1194 /* GLONASS ICD health: bit0=L1 bad, bit3=sat malfunction,
1195 bits1-2=01 (binary) means L2 bad — all three cases excluded */
1196 if ((svh & 9) != 0 || (svh & 6) == 4) {
1197 trace(NULL, 3, "unhealthy satellite: sat=%3d svh=%02X\n", sat, svh);
1198 return 1;
1199 }
1200 } else if (svh) {
1201 trace(NULL, 3, "unhealthy satellite: sat=%3d svh=%02X\n", sat, svh);
1202 return 1;
1203 }
1204 if (var > MAX_VAR_EPH) {
1205 trace(NULL, 3, "invalid ura satellite: sat=%3d ura=%.2f\n", sat, sqrt(var));
1206 return 1;
1207 }
1208 return 0;
1209}
MRTKLIB Constants — Physical, navigation, and system constants.
#define BDSGEN_2
Definition mrtk_const.h:218
#define BDSGEN_3
Definition mrtk_const.h:219
#define MAXSAT
Definition mrtk_coords.c:45
#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 NSATCMP
#define NSATSBS
#define NSATQZS
#define MINPRNIRN
#define NSATGPS
#define MINPRNCMP
#define MINPRNQZS
#define MINPRNLEO
#define MAXPRNQZS
#define MINPRNBDS3
#define MAXPRNIRN
#define MAXPRNGAL
#define NSATIRN
#define NFREQPCV
#define MINPRNGAL
#define MAXPRNLEO
#define MINPRNGLO
#define NSATGLO
#define MAXPRNCMP
#define MAXPRNGLO
#define NSATLEO
#define NSATGAL
int savenav(const char *file, const nav_t *nav)
Save navigation data to file.
Definition mrtk_nav.c:1058
void satno2id(int sat, char *id)
Convert satellite number to satellite id.
Definition mrtk_nav.c:817
void apply_pppsig(const int *pppsig)
Apply PPP signal selection options to obsdef tables.
Definition mrtk_nav.c:539
int readnav(const char *file, nav_t *nav)
Read navigation data from file.
Definition mrtk_nav.c:985
int satsys(int sat, int *prn)
Convert satellite number to satellite system.
Definition mrtk_nav.c:117
void apply_claslib_ppprtk_obsdef(void)
Apply the upstream claslib PPP-RTK observation slot layout.
Definition mrtk_nav.c:635
static obsdef_t obsdef_GLO[MAXFREQ]
Definition mrtk_nav.c:330
static void save_obsdef_defaults(void)
Definition mrtk_nav.c:462
int bds_gen(int prn)
BeiDou generation of a PRN.
Definition mrtk_nav.c:273
static obsdef_t obsdef_GPS_def[MAXFREQ]
Definition mrtk_nav.c:433
static obsdef_t * get_obsdef(int sys)
Definition mrtk_nav.c:401
static void uniqgeph(nav_t *nav)
Definition mrtk_nav.c:895
static obsdef_t obsdef_BDS_def[MAXFREQ]
Definition mrtk_nav.c:434
int freq_idx2ant_idx(int sys, int freq_idx)
Convert frequency index to antenna PCV index.
Definition mrtk_nav.c:743
int set_bds2prn(const char *str)
Set the BDS-2 satellites in BeiDou PRN 1-18.
Definition mrtk_nav.c:231
static obsdef_t obsdef_GAL[MAXFREQ]
Definition mrtk_nav.c:340
void set_obsdef(int sys, const int *freq_nums)
Rearrange obsdef table for a satellite system by frequency numbers.
Definition mrtk_nav.c:502
#define NBDSTBL
Definition mrtk_nav.c:180
static obsdef_t obsdef_BD2[MAXFREQ]
Definition mrtk_nav.c:380
static int cmpseph(const void *p1, const void *p2)
Definition mrtk_nav.c:928
static obsdef_t obsdef_GPS[MAXFREQ]
Definition mrtk_nav.c:320
static obsdef_t obsdef_IRN[MAXFREQ]
Definition mrtk_nav.c:390
static int obsdef_defaults_saved
Definition mrtk_nav.c:435
static void uniqeph(nav_t *nav)
Definition mrtk_nav.c:855
int is_bds3igso(int prn)
Test whether a BeiDou PRN is listed as BDS-3 IGSO (see set_bds3igso()).
Definition mrtk_nav.c:267
int satno(int sys, int prn)
Convert satellite system+prn/slot number to satellite number.
Definition mrtk_nav.c:58
static obsdef_t obsdef_QZS[MAXFREQ]
Definition mrtk_nav.c:350
static uint8_t bds3igso_[(MAXPRNCMP< 63 ? 64 :MAXPRNCMP+1)]
Definition mrtk_nav.c:185
int set_bds3igso(const char *str)
Set the BDS-3 IGSO satellites (excluded as PPP-AR reference satellite).
Definition mrtk_nav.c:251
static int cmpgeph(const void *p1, const void *p2)
Definition mrtk_nav.c:888
static obsdef_t obsdef_SBS_def[MAXFREQ]
Definition mrtk_nav.c:434
void uniqnav(nav_t *nav)
Unique ephemerides in navigation data.
Definition mrtk_nav.c:971
int freq_num2ant_idx(int sys, int freq_num)
Convert frequency number to antenna PCV index.
Definition mrtk_nav.c:710
int satid2no(const char *id)
Convert satellite id to satellite number.
Definition mrtk_nav.c:753
static obsdef_t obsdef_BD2_def[MAXFREQ]
Definition mrtk_nav.c:434
int satsys_bd2(int sat, int *prn)
Distinguish BDS-2 from BDS-3.
Definition mrtk_nav.c:159
double freq_num2freq(int sys, int freq_num, int fcn)
Convert frequency number to frequency in Hz.
Definition mrtk_nav.c:680
static obsdef_t obsdef_GLO_def[MAXFREQ]
Definition mrtk_nav.c:433
int satexclude(int sat, double var, int svh, const struct prcopt_t *opt)
Test excluded satellite.
Definition mrtk_nav.c:1169
static void uniqseph(nav_t *nav)
Definition mrtk_nav.c:935
void freenav(nav_t *nav, int opt)
Free navigation data memory.
Definition mrtk_nav.c:1118
static obsdef_t obsdef_QZS_def[MAXFREQ]
Definition mrtk_nav.c:433
static obsdef_t * get_obsdef_default(int sys)
Definition mrtk_nav.c:438
static int parse_bdslist(const char *str, int maxprn, uint8_t val, uint8_t *list)
Definition mrtk_nav.c:190
int is_bds2prn(int prn)
Test whether a BeiDou PRN is BDS-2 (see set_bds2prn()).
Definition mrtk_nav.c:249
static uint8_t bdsgen_[(MAXPRNCMP< 63 ? 64 :MAXPRNCMP+1)]
Definition mrtk_nav.c:181
static obsdef_t obsdef_SBS[MAXFREQ]
Definition mrtk_nav.c:360
static obsdef_t obsdef_BDS[MAXFREQ]
Definition mrtk_nav.c:370
static obsdef_t obsdef_GAL_def[MAXFREQ]
Definition mrtk_nav.c:433
#define MAX_VAR_EPH
Definition mrtk_nav.c:46
static obsdef_t obsdef_IRN_def[MAXFREQ]
Definition mrtk_nav.c:434
int freq_num2freq_idx(int sys, int freq_num)
Convert frequency number to frequency index using obsdef table.
Definition mrtk_nav.c:661
int freq_idx2freq_num(int sys, int freq_idx)
Convert frequency index to frequency number using obsdef table.
Definition mrtk_nav.c:649
int set_bdsopt(const prcopt_t *opt, int warn)
Apply the BeiDou PRN-reassignment options process-wide.
Definition mrtk_nav.c:282
static int cmpeph(const void *p1, const void *p2)
Definition mrtk_nav.c:848
void reset_obsdef(void)
Reset all obsdef tables to their pristine default frequency layout.
Definition mrtk_nav.c:483
MRTKLIB Navigation Module — Navigation data types and satellite/nav utility functions.
#define DFRQ2_GLO
Definition mrtk_obs.c:77
#define FREQ5
Definition mrtk_obs.c:69
#define FREQ2
Definition mrtk_obs.c:68
#define FREQ8
Definition mrtk_obs.c:72
#define FREQ6
Definition mrtk_obs.c:70
#define FREQ2_CMP
Definition mrtk_obs.c:82
#define FREQ9
Definition mrtk_obs.c:73
#define SYS_BD2
Definition mrtk_obs.c:62
#define FREQ7
Definition mrtk_obs.c:71
#define FREQ1
Definition mrtk_obs.c:67
#define FREQ2_GLO
Definition mrtk_obs.c:76
#define FREQ1_GLO
Definition mrtk_obs.c:74
#define FREQ3_CMP
Definition mrtk_obs.c:83
#define FREQ1_CMP
Definition mrtk_obs.c:81
#define SYS_LEO
Definition mrtk_obs.c:61
#define DFRQ1_GLO
Definition mrtk_obs.c:75
#define MAXFREQ
Definition mrtk_obs.c:65
MRTKLIB Options Module — Processing and solution option types.
#define MAXPRNSBS
#define MINPRNSBS
#define MINPRNGPS
#define MAXPRNGPS
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.
GPS/GAL/QZS/BDS/IRN broadcast ephemeris type.
Definition mrtk_eph.h:77
double OMG0
Definition mrtk_eph.h:90
double omg
Definition mrtk_eph.h:90
int sat
Definition mrtk_eph.h:78
gtime_t ttr
Definition mrtk_eph.h:88
double OMGd
Definition mrtk_eph.h:90
double f1
Definition mrtk_eph.h:94
double f0
Definition mrtk_eph.h:94
int svh
Definition mrtk_eph.h:81
double e
Definition mrtk_eph.h:90
double idot
Definition mrtk_eph.h:90
double M0
Definition mrtk_eph.h:90
double A
Definition mrtk_eph.h:90
double cis
Definition mrtk_eph.h:91
int flag
Definition mrtk_eph.h:86
gtime_t toe
Definition mrtk_eph.h:88
double fit
Definition mrtk_eph.h:93
gtime_t toc
Definition mrtk_eph.h:88
double cic
Definition mrtk_eph.h:91
double tgd[6]
Definition mrtk_eph.h:95
double cus
Definition mrtk_eph.h:91
double cuc
Definition mrtk_eph.h:91
double toes
Definition mrtk_eph.h:92
int code
Definition mrtk_eph.h:83
int type
Definition mrtk_eph.h:100
double crs
Definition mrtk_eph.h:91
double i0
Definition mrtk_eph.h:90
int iode
Definition mrtk_eph.h:79
int sva
Definition mrtk_eph.h:80
double deln
Definition mrtk_eph.h:90
double crc
Definition mrtk_eph.h:91
double f2
Definition mrtk_eph.h:94
int iodc
Definition mrtk_eph.h:79
GLONASS broadcast ephemeris type.
Definition mrtk_eph.h:111
double vel[3]
Definition mrtk_eph.h:121
double dtaun
Definition mrtk_eph.h:124
gtime_t toe
Definition mrtk_eph.h:118
double pos[3]
Definition mrtk_eph.h:120
int sva
Definition mrtk_eph.h:117
int iode
Definition mrtk_eph.h:113
double gamn
Definition mrtk_eph.h:123
double acc[3]
Definition mrtk_eph.h:122
int age
Definition mrtk_eph.h:117
int svh
Definition mrtk_eph.h:115
double taun
Definition mrtk_eph.h:123
gtime_t tof
Definition mrtk_eph.h:119
int sat
Definition mrtk_eph.h:112
int frq
Definition mrtk_eph.h:114
time_t time
Definition mrtk_time.h:50
int nt
Definition mrtk_nav.h:399
tec_t * tec
Definition mrtk_nav.h:412
eph_t * eph_prev
Definition mrtk_nav.h:401
pppiono_t * pppiono
Definition mrtk_nav.h:438
int ng
Definition mrtk_nav.h:394
int nemax
Definition mrtk_nav.h:396
seph_t * seph
Definition mrtk_nav.h:408
int na
Definition mrtk_nav.h:398
double utc_gps[8]
Definition mrtk_nav.h:414
geph_t * geph
Definition mrtk_nav.h:407
int ntmax
Definition mrtk_nav.h:399
pclk_t * pclk
Definition mrtk_nav.h:410
peph_t * peph
Definition mrtk_nav.h:409
alm_t * alm
Definition mrtk_nav.h:411
int ncmax
Definition mrtk_nav.h:397
eph_t * eph
Definition mrtk_nav.h:400
int namax
Definition mrtk_nav.h:398
int nc
Definition mrtk_nav.h:397
int nsmax
Definition mrtk_nav.h:395
double ion_gps[8]
Definition mrtk_nav.h:421
int ngmax
Definition mrtk_nav.h:394
int nmax
Definition mrtk_nav.h:393
int ns
Definition mrtk_nav.h:395
int n
Definition mrtk_nav.h:393
int ne
Definition mrtk_nav.h:396
double freq_hz
Definition mrtk_nav.c:317
int freq_num
Definition mrtk_nav.c:316
uint8_t exsats[MAXSAT]
Definition mrtk_opt.h:225
int bds2prn_set
Definition mrtk_opt.h:335
int navsys
Definition mrtk_opt.h:175
char bds3igso[256]
Definition mrtk_opt.h:334
char bds2prn[256]
Definition mrtk_opt.h:333
SBAS ephemeris type.
Definition mrtk_eph.h:130
gtime_t tof
Definition mrtk_eph.h:133
int sat
Definition mrtk_eph.h:131
gtime_t t0
Definition mrtk_eph.h:132
#define free(x)
Definition toml.c:53