MRTKLIB 0.7.14
Modernized GNSS Positioning Library
Loading...
Searching...
No Matches
mrtk_ppp_ar.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------------
2 * mrtk_ppp_ar.c : PPP ambiguity resolution 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 * reference :
17 * [1] H.Okumura, C-gengo niyoru saishin algorithm jiten (in Japanese),
18 * Software Technology, 1991
19 * [2] CAO IS-QZSS-MDC-004, May, 2025
20 *
21 * version : $Revision:$ $Date:$
22 * history : 2013/03/11 1.0 new
23 * 2015/05/15 1.1 refine complete algorithms
24 * 2015/05/31 1.2 delete WL-ambiguity resolution by ILS
25 * add PAR (partial ambiguity resolution)
26 * 2015/11/26 1.3 support option opt->pppopt=-TRACE_AR
27 * 2023/02/01 1.4 branch from MALIB PP for MADOCALIB
28 * 2023/03/08 1.5 change sys to GPS only
29 * 2024/01/10 1.6 add references [2]
30 * support MADOCA-PPP ionospheric corrections, add NM
31 * delete L5-receiver-dcb estimation, ND
32 * support option opt->arsys in gen_sat_sd()
33 * 2024/09/27 1.7 delete NM
34 * 2025/03/18 1.8 support triple/quad-frequency ppp-ar.
35 * support bds-2 and bds-3.
36 *-----------------------------------------------------------------------------*/
37#include "mrtklib/mrtk_ppp_ar.h"
38
39#include <math.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43
44#include "mrtklib/mrtk_const.h"
46#include "mrtklib/mrtk_lambda.h"
47#include "mrtklib/mrtk_madoca.h"
48#include "mrtklib/mrtk_mat.h"
49#include "mrtklib/mrtk_obs.h"
50#include "mrtklib/mrtk_sys.h"
51#include "mrtklib/mrtk_trace.h"
52
53/* forward declarations */
54extern int satsys(int sat, int* prn);
55extern int satsys_bd2(int sat, int* prn);
56extern void satno2id(int sat, char* id);
57extern int satid2no(const char* id);
58extern char* time_str(gtime_t t, int n);
59extern void time2str(gtime_t t, char* s, int n);
60extern void time2epoch(gtime_t t, double* ep);
61extern gtime_t epoch2time(const double* ep);
62extern gtime_t timeadd(gtime_t t, double sec);
63extern double timediff(gtime_t t1, gtime_t t2);
64extern double norm(const double* a, int n);
65extern void matcpy(double* A, const double* B, int n, int m);
66extern void matmul(const char* tr, int n, int k, int m, double alpha, const double* A, const double* B, double beta,
67 double* C);
68extern double* mat(int n, int m);
69extern double* zeros(int n, int m);
70extern int filter(double* x, double* P, const double* H, const double* v, const double* R, int n, int m);
71extern int lambda(int n, int m, const double* a, const double* Q, double* F, double* s);
72extern unsigned int tickget(void);
73extern int freq_idx2freq_num(int sys, int freq_idx);
74extern double freq_num2freq(int sys, int freq_num, int fcn);
75
76#define MIN_AMB_RES 4 /* min number of ambiguities for ILS-AR */
77#define CONST_AMB 0.01 /* constraint to fixed ambiguity */
78#define CONST_AMB_BDS 0.05 /* constraint to fixed ambiguity for BDS2,BDS3 */
79#define CONST_AMB_BDS_B2a 0.10 /* constraint to fixed ambiguity for BDS3 B2a */
80#define CONST_AMB_GAL_E6 0.10 /* constraint to fixed ambiguity for GAL E6 */
81#define CONST_AMB_EWL 0.10 /* constraint to fixed ewl ambiguity for GPS,BDS */
82#define MAX_STD_FIX 0.15 /* max std-dev (3d-pos) to fix solution */
83#define MIN_MATCH_RATE 0.10 /* min match rate between the first and second candidates to fix solution */
84#define REL_MATCH_RATE 0.90 /* match rate between the first and second candidates to relax threshold */
85#define MAX_FRAC_WL_FIX 0.20 /* max fraction to fix wide-lane ambiguity (cycle) */
86#define MAX_STD_WL_FIX 1.00 /* max std-dev to fix wide-lane ambiguity (cycle) */
87
88#define STEP_EWL 3
89#define STEP_WL 2
90#define STEP_NL 1
91
92#define MIN(x, y) ((x) < (y) ? (x) : (y))
93#define MAX(x, y) ((x) > (y) ? (x) : (y))
94#define SQR(x) ((x) * (x))
95#define ROUND(x) (int)floor((x) + 0.5)
96#define SWAP_I(x, y) \
97 do { \
98 int _tmp = x; \
99 x = y; \
100 y = _tmp; \
101 } while (0)
102#define SWAP_D(x, y) \
103 do { \
104 double _tmp = x; \
105 x = y; \
106 y = _tmp; \
107 } while (0)
108
109/* number and index of ekf states */
110#define NF(opt) ((opt)->ionoopt == IONOOPT_IFLC ? 1 : (opt)->nf)
111#define NP(opt) ((opt)->dynamics ? 9 : 3)
112#define NC(opt) (NSYS + 1) /* BDS3 and BDS2 */
113static inline int NT(const prcopt_t* opt) {
114 if (opt->tropopt < TROPOPT_EST) return 0;
115 if (opt->tropopt == TROPOPT_EST) return 1;
116 return 3;
117}
118#define NI(opt) ((opt)->ionoopt == IONOOPT_EST ? MAXSAT : 0)
119#define N3(opt) (NF(opt) >= 3 ? NC(opt) : 0) /* 3rd-frequency receivre bias */
120#define N4(opt) (NF(opt) >= 4 ? NC(opt) : 0) /* 4th-frequency receivre bias */
121#define NR(opt) (NP(opt) + NC(opt) + NT(opt) + NI(opt) + N3(opt) + N4(opt))
122#define IT(opt) (NP(opt) + NC(opt))
123#define IB(s, f, opt) (NR(opt) + MAXSAT * (f) + (s) - 1)
124
125/* get wave length -----------------------------------------------------------*/
126static void get_wavelength(int sat, double* lam) {
127 double freq;
128 int i, sys;
129
130 sys = satsys_bd2(sat, NULL);
131 for (i = 0; i < NFREQ; i++) {
132 freq = freq_num2freq(sys, freq_idx2freq_num(sys, i), 0);
133 if (freq > 0.0) {
134 lam[i] = CLIGHT / freq;
135 } else {
136 lam[i] = 0.0;
137 }
138 }
139}
140/* BDS-3 IGSO satellite listed by set_bds3igso() (default C06-C08) ----------*/
141static int is_bds3_igso(int sat) {
142 int prn;
143
144 if (satsys_bd2(sat, &prn) != SYS_CMP) {
145 return 0;
146 }
147 return is_bds3igso(prn);
148}
149/* exclude satellite ---------------------------------------------------------*/
150static int exc_sat_sd(rtk_t* rtk, const obsd_t* obs, int exc, double el, int nf, int sys) {
151 double elmask;
152 int arsys = rtk->opt.arsys;
153
154 elmask = MAX(rtk->opt.elmaskar, rtk->opt.elmin);
155
156 trace(NULL, 4, "exc_sat_sd(%4d): nf=%d arsys=%d elmaskar=%2.0f\n", __LINE__, nf, arsys, rtk->opt.elmaskar);
157
158 if (exc) {
159 return 0;
160 }
161 if (!(satsys_bd2(obs->sat, NULL) & sys)) {
162 return 0;
163 }
164 if (!(satsys(obs->sat, NULL) & arsys)) {
165 return 0;
166 }
167 if (!rtk->ssat[obs->sat - 1].vsat[0] || el < elmask) {
168 trace(NULL, 2, "exc_sat_sd(%4d): sys=%2d sat=%3d excluded by el=%4.1f / %4.1f\n", __LINE__,
169 satsys_bd2(obs->sat, NULL), obs->sat, el * R2D, elmask * R2D);
170 return 0;
171 }
172 trace(NULL, 4, "exc_sat_sd(%4d): sat=%d\n", __LINE__, obs->sat);
173
174 return 1;
175}
176/* generate satellite SD (single-difference) ---------------------------------*/
177static int gen_sat_sd(rtk_t* rtk, const obsd_t* obs, int n, const int* exc, const double* azel, int nf, int* sat1,
178 int* sat2, double* el1, double* el2) {
179 const int sys[] = {SYS_GPS, SYS_GAL, SYS_CMP, SYS_QZS, SYS_BD2, 0};
180 double elmask, el[MAXOBS], maxel;
181 int i, j, k, m, f, ns = 0, sat[MAXOBS];
182 int stat = 0, maxsat, excmask[MAXOBS];
183 char s1[5], s2[5];
184
185 trace(NULL, 3, "gen_sat_sd(%4d): nf=%d arsys=%d elmaskar=%2.0f\n", __LINE__, nf, rtk->opt.arsys,
186 rtk->opt.elmaskar * R2D);
187
188 elmask = MAX(rtk->opt.elmaskar, rtk->opt.elmin);
189
190 for (i = 0; sys[i]; i++) { /* for each system */
191
192 for (j = 0; j < n; j++) {
193 excmask[j] = 0;
194 }
195
196 /* search highest elevation angle */
197 for (j = 0, maxsat = 0, maxel = 0.0; j < n; j++) {
198 if (!exc_sat_sd(rtk, obs + j, exc[j], azel[1 + j * 2], nf, sys[i])) {
199 excmask[j] = 1;
200 continue;
201 }
202 for (f = 0, stat = 0; f < 2; f++) {
203 stat |= (obs[j].L[f] == 0.0);
204 trace(NULL, 4, "gen_sat_sd(%4d): sys=%d sat=%3d f=%d obs[j].L[f]=%14.3f stat=%d\n", __LINE__, sys[i],
205 obs[j].sat, f, obs[j].L[f], stat);
206 }
207 if (stat) {
208 continue;
209 }
210
211 /* exclude IGSO for reference satellite */
212 if (is_bds3_igso(obs[j].sat)) {
213 continue;
214 }
215
216 if (azel[1 + j * 2] > maxel) {
217 maxel = azel[1 + j * 2];
218 maxsat = obs[j].sat;
219 }
220 }
221 if (maxsat == 0) {
222 trace(NULL, 4, "gen_sat_sd(%4d): no reference satellite sys=%d maxsat=%3d maxel=%4.1f\n", __LINE__, sys[i],
223 maxsat, maxel * R2D);
224 continue;
225 }
226 trace(NULL, 4, "gen_sat_sd(%4d): sys=%d maxsat=%3d maxel=%4.1f\n", __LINE__, sys[i], maxsat, maxel * R2D);
227
228 /* sort by elevation angle */
229 for (j = m = 0; j < n; j++) {
230 if (excmask[j]) {
231 continue;
232 }
233 if (obs[j].sat == maxsat) {
234 continue;
235 }
236
237 sat[m] = obs[j].sat;
238 el[m++] = azel[1 + j * 2];
239 }
240 for (j = 0; j < m - 1; j++) {
241 for (k = j + 1; k < m; k++) {
242 if (el[j] >= el[k]) {
243 continue;
244 }
245 SWAP_I(sat[j], sat[k]);
246 SWAP_D(el[j], el[k]);
247 }
248 }
249 /* generate SD referenced to max elevation angle */
250 for (j = 0; j < m; j++) {
251 el1[ns] = el[j];
252 el2[ns] = maxel;
253
254 sat1[ns] = sat[j];
255 sat2[ns++] = maxsat;
256
257 satno2id(sat[j], s1);
258 satno2id(maxsat, s2);
259 trace(NULL, 3, "gen_sat_sd(%4d): %s %s el=%4.1f %4.1f[deg]\n", __LINE__, s1, s2, el[j] * R2D, maxel * R2D);
260 }
261 }
262 trace(NULL, 4, "gen_sat_sd(%4d): ns=%d\n", __LINE__, ns);
263 return ns; /* # of Satellite */
264}
265/* write debug trace for PAR -------------------------------------------------*/
266static void write_trace_amb(rtk_t* rtk, const double* a, const double* Q, int na, const int* sat1s, const int* sat2s,
267 const int* frqs, const char label[NFREQ][10], int step) {
268 char s1[32], s2[32];
269 double ep[6] = {0.0};
270 gtime_t t0;
271 int i;
272 trace(NULL, 2, "write_trace_amb: EPOCH=%s\n", time_str(rtk->sol.time, 0));
273
274 time2epoch(timeadd(rtk->sol.time, 1.0), ep);
275 ep[3] = 0.0;
276 ep[4] = 0.0;
277 ep[5] = 0.0;
278 t0 = epoch2time(ep);
279
280 for (i = 0; i < na; i++) {
281 satno2id(sat1s[i], s1);
282 satno2id(sat2s[i], s2);
283 trace(NULL, 2, "write_trace_amb:, STEP_%d, %5.0f, %s_%s, %s, %14.3f, %7.3f, %7.3f\n", step,
284 timediff(rtk->sol.time, t0), s2, s1, label[frqs[i]], a[i], sqrt(Q[i + i * na]), ROUND(a[i]) - a[i]);
285 }
286}
287static void write_trace_sd_amb(rtk_t* rtk, const double* x, const double* P, const int* sat1, const int* sat2, int ns,
288 int nf, int* sat1s, int* sat2s, int* frqs, double* a, int post, int step) {
289 int i, f, j, k, j1, j2, k1, k2, na = 0;
290 double *D, *Q, *W;
291 double lam[NFREQ];
292 const char label1[NFREQ][10] = {"PRE-N1 ", "PRE-WL ", "PRE-EWL", "PRE-EW2"};
293 const char label2[NFREQ][10] = {"POST-N1 ", "POST-WL ", "POST-EWL", "POST-EW2"};
294
295 if (!strstr(rtk->opt.pppopt, "-TRACE_AR")) {
296 return;
297 }
298 trace(NULL, 4, "write_trace_sd_amb(%4d): ns=%d nf=%d\n", __LINE__, ns, nf);
299
300 D = zeros(rtk->nx, ns * nf);
301 Q = mat(ns * NFREQ, ns * nf);
302
303 /* freq-ambiguity SD-matrix */
304 for (i = 0; i < ns; i++) {
305 if (sat1[i] <= 0 || sat2[i] <= 0) {
306 continue;
307 }
308 get_wavelength(sat1[i], lam);
309
310 for (f = 0; f < nf; f++) {
311 sat1s[na] = sat1[i];
312 sat2s[na] = sat2[i];
313 frqs[na] = f;
314
315 if (f == 0) { /* N1 */
316 j = IB(sat1[i], 0, &rtk->opt);
317 k = IB(sat2[i], 0, &rtk->opt);
318
319 if (lam[0] == 0.0) {
320 continue;
321 }
322 if (x[j] == 0.0 || x[k] == 0.0) {
323 continue;
324 }
325
326 D[j + na * rtk->nx] = 1.0 / lam[0];
327 D[k + na * rtk->nx] = -1.0 / lam[0];
328 na++;
329 } else if (f == 1) { /* WL (F1-F2) */
330 j1 = IB(sat1[i], 0, &rtk->opt);
331 j2 = IB(sat1[i], 1, &rtk->opt);
332 k1 = IB(sat2[i], 0, &rtk->opt);
333 k2 = IB(sat2[i], 1, &rtk->opt);
334
335 if (lam[0] == 0.0 || lam[1] == 0.0) {
336 continue;
337 }
338 if (x[j1] == 0.0 || x[j2] == 0.0) {
339 continue;
340 }
341 if (x[k1] == 0.0 || x[k2] == 0.0) {
342 continue;
343 }
344
345 D[j1 + na * rtk->nx] = 1.0 / lam[0];
346 D[j2 + na * rtk->nx] = -1.0 / lam[1];
347 D[k1 + na * rtk->nx] = -1.0 / lam[0];
348 D[k2 + na * rtk->nx] = 1.0 / lam[1];
349 na++;
350 } else if (f == 2) { /* EWL (F2-F3) */
351 j1 = IB(sat1[i], 1, &rtk->opt);
352 j2 = IB(sat1[i], 2, &rtk->opt);
353 k1 = IB(sat2[i], 1, &rtk->opt);
354 k2 = IB(sat2[i], 2, &rtk->opt);
355
356 if (lam[1] == 0.0 || lam[2] == 0.0) {
357 continue;
358 }
359 if (x[j1] == 0.0 || x[j2] == 0.0) {
360 continue;
361 }
362 if (x[k1] == 0.0 || x[k2] == 0.0) {
363 continue;
364 }
365
366 D[j1 + na * rtk->nx] = 1.0 / lam[1];
367 D[j2 + na * rtk->nx] = -1.0 / lam[2];
368 D[k1 + na * rtk->nx] = -1.0 / lam[1];
369 D[k2 + na * rtk->nx] = 1.0 / lam[2];
370 na++;
371 } else if (f == 3) { /* EWL (F2-F4) */
372 j1 = IB(sat1[i], 1, &rtk->opt);
373 j2 = IB(sat1[i], 3, &rtk->opt);
374 k1 = IB(sat2[i], 1, &rtk->opt);
375 k2 = IB(sat2[i], 3, &rtk->opt);
376
377 if (lam[1] == 0.0 || lam[3] == 0.0) {
378 continue;
379 }
380 if (x[j1] == 0.0 || x[j2] == 0.0) {
381 continue;
382 }
383 if (x[k1] == 0.0 || x[k2] == 0.0) {
384 continue;
385 }
386
387 D[j1 + na * rtk->nx] = 1.0 / lam[1];
388 D[j2 + na * rtk->nx] = -1.0 / lam[3];
389 D[k1 + na * rtk->nx] = -1.0 / lam[1];
390 D[k2 + na * rtk->nx] = 1.0 / lam[3];
391 na++;
392 }
393 }
394 }
395
396 /* a=D'*x, Q_wl=D'*P*D */
397 W = mat(rtk->nx, na);
398 matmul("TN", na, 1, rtk->nx, 1.0, D, x, 0.0, a);
399 matmul("TN", na, rtk->nx, rtk->nx, 1.0, D, P, 0.0, W);
400 matmul("NN", na, na, rtk->nx, 1.0, W, D, 0.0, Q);
401
402 if (post) {
403 write_trace_amb(rtk, a, Q, na, sat1s, sat2s, frqs, label2, step);
404 } else {
405 write_trace_amb(rtk, a, Q, na, sat1s, sat2s, frqs, label1, step);
406 }
407
408 free(W);
409 free(D);
410 free(Q);
411}
412/* search extra wide-lane integer ambiguity ----------------------------------*/
413static int search_amb_ewl(rtk_t* rtk, const double* x, const double* P, const int* sat1, const int* sat2, int ns,
414 int nf, int* sat1s, int* sat2s, int* frqs, double* a, double* N, double* D) {
415 int i, j1, j2, k1, k2, na = 0;
416 int f, f1, f2;
417 double lam[NFREQ];
418 double b, n, var, frac;
419 double th_frac = MAX_FRAC_WL_FIX, th_std = MAX_STD_WL_FIX;
420 char s1[32], s2[32];
421
422 if (nf < 3) {
423 return 0;
424 }
425
426 /* initialize D-matrix */
427 for (i = 0; i < rtk->nx * (ns * 2); i++) {
428 D[i] = 0.0;
429 }
430
431 /* freq-ambiguity SD-matrix extra WL (F2-F3, F2-F4) */
432 for (i = 0; i < ns; i++) {
433 if (sat1[i] <= 0 || sat2[i] <= 0) {
434 continue;
435 }
436 get_wavelength(sat1[i], lam);
437 satno2id(sat1[i], s1);
438 satno2id(sat2[i], s2);
439
440 for (f = 2; f < rtk->opt.nf; f++) {
441 if (f == 2) {
442 f1 = 1; /* 2nd frequency */
443 f2 = 2; /* 3rd frequency */
444 } else if (f == 3) {
445 f1 = 1; /* 2nd frequency */
446 f2 = 3; /* 4th frequency */
447 }
448
449 j1 = IB(sat1[i], f1, &rtk->opt);
450 j2 = IB(sat1[i], f2, &rtk->opt);
451 k1 = IB(sat2[i], f1, &rtk->opt);
452 k2 = IB(sat2[i], f2, &rtk->opt);
453
454 if (lam[f1] == 0.0 || lam[f2] == 0.0 || x[j1] == 0.0 || x[j2] == 0.0 || x[k1] == 0.0 || x[k2] == 0.0) {
455 trace(NULL, 3, "search_amb_ewl(%4d): skipped %s %s x(j1,j2,k1,k2)=%8.3f %8.3f %8.3f %8.3f\n", __LINE__,
456 s1, s2, x[j1], x[j2], x[k1], x[k2]);
457 continue;
458 }
459
460 b = (x[j1] / lam[f1] - x[j2] / lam[f2]) - (x[k1] / lam[f1] - x[k2] / lam[f2]);
461 n = ROUND(b);
462 frac = fabs(n - b);
463 var = P[j1 + j1 * rtk->nx] / SQR(lam[f1]) + P[j2 + j2 * rtk->nx] / SQR(lam[f2]) -
464 2.0 * P[j1 + j2 * rtk->nx] / (lam[f1] * lam[f2]);
465 var += P[k1 + k1 * rtk->nx] / SQR(lam[f1]) + P[k2 + k2 * rtk->nx] / SQR(lam[f2]) -
466 2.0 * P[k1 + k2 * rtk->nx] / (lam[f1] * lam[f2]);
467
468 if (sqrt(var) > th_std || frac > th_frac) {
469 trace(NULL, 2,
470 "search_amb_ewl(%4d): excluded %s %s N,a= %8.3f %8.3f "
471 "sig=%8.3f frac=%8.3f/%8.3f std=%8.3f/%8.3f\n",
472 __LINE__, s1, s2, n, b, sqrt(var), frac, th_frac, sqrt(var), th_std);
473 continue;
474 }
475
476 sat1s[na] = sat1[i];
477 sat2s[na] = sat2[i];
478 frqs[na] = f;
479
480 a[na] = b;
481 N[na] = n;
482 D[j1 + na * rtk->nx] = 1.0 / lam[f1];
483 D[j2 + na * rtk->nx] = -1.0 / lam[f2];
484 D[k1 + na * rtk->nx] = -1.0 / lam[f1];
485 D[k2 + na * rtk->nx] = 1.0 / lam[f2];
486 rtk->ssat[sat1s[na] - 1].fix[f2] = rtk->ssat[sat2s[na] - 1].fix[f2] = 1;
487 na++;
488
489 if (strstr(rtk->opt.pppopt, "-TRACE_AR")) {
490 trace(NULL, 3, "search_amb_ewl(%4d): %s %s N,a= %8.3f %8.3f sig=%8.3f\n", __LINE__, s1, s2, n, b,
491 sqrt(var));
492 }
493 }
494 }
495 trace(NULL, 4, "search_amb_ewl(%4d): number of fixed extra wide-lane ambiguity = %d / %d\n", __LINE__, na, ns);
496 return na;
497}
498/* search wide-lane integer ambiguity ----------------------------------------*/
499static int search_amb_wl(rtk_t* rtk, const double* x, const double* P, int* sat1, int* sat2, int ns, int nf, int* sat1s,
500 int* sat2s, int* frqs, double* a, double* N, double* D) {
501 int i, j1, j2, k1, k2, na = 0;
502 double lam[NFREQ];
503 double b, n, var, frac;
504 double th_frac = MAX_FRAC_WL_FIX, th_std = MAX_STD_WL_FIX;
505 char s1[32], s2[32];
506
507 if (nf < 2) {
508 return 0;
509 }
510
511 /* initialize D-matrix */
512 for (i = 0; i < rtk->nx * ns; i++) {
513 D[i] = 0.0;
514 }
515
516 /* freq-ambiguity SD-matrix WL (L1-L2) */
517 for (i = 0; i < ns; i++) {
518 if (sat1[i] <= 0 || sat2[i] <= 0) {
519 continue;
520 }
521 get_wavelength(sat1[i], lam);
522 satno2id(sat1[i], s1);
523 satno2id(sat2[i], s2);
524
525 j1 = IB(sat1[i], 0, &rtk->opt);
526 j2 = IB(sat1[i], 1, &rtk->opt);
527 k1 = IB(sat2[i], 0, &rtk->opt);
528 k2 = IB(sat2[i], 1, &rtk->opt);
529
530 if (lam[0] == 0.0 || lam[1] == 0.0 || x[j1] == 0.0 || x[j2] == 0.0 || x[k1] == 0.0 || x[k2] == 0.0) {
531 trace(NULL, 3, "search_amb_wl(%4d): excluded %s %s x(j1,j2,k1,k2)=%.3f %.3f %.3f %.3f\n", __LINE__, s1, s2,
532 x[j1], x[j2], x[k1], x[k2]);
533
534 sat1[i] = 0;
535 sat2[i] = 0;
536 continue;
537 }
538
539 b = (x[j1] / lam[0] - x[j2] / lam[1]) - (x[k1] / lam[0] - x[k2] / lam[1]);
540 n = ROUND(b);
541 frac = fabs(n - b);
542 var = P[j1 + j1 * rtk->nx] / SQR(lam[0]) + P[j2 + j2 * rtk->nx] / SQR(lam[1]) -
543 2.0 * P[j1 + j2 * rtk->nx] / (lam[0] * lam[1]);
544 var += P[k1 + k1 * rtk->nx] / SQR(lam[0]) + P[k2 + k2 * rtk->nx] / SQR(lam[1]) -
545 2.0 * P[k1 + k2 * rtk->nx] / (lam[0] * lam[1]);
546
547 if (sqrt(var) > th_std || frac > th_frac) {
548 trace(NULL, 2,
549 "search_amb_wl(%4d): excluded %s %s N,a= %8.3f %8.3f "
550 "sig=%8.3f frac=%8.3f/%8.3f std=%8.3f/%8.3f\n",
551 __LINE__, s1, s2, n, b, sqrt(var), frac, th_frac, sqrt(var), th_std);
552
553 sat1[i] = 0;
554 sat2[i] = 0;
555
556 continue;
557 }
558
559 sat1s[na] = sat1[i];
560 sat2s[na] = sat2[i];
561 frqs[na] = 1;
562
563 a[na] = b;
564 N[na] = n;
565 D[j1 + na * rtk->nx] = 1.0 / lam[0];
566 D[j2 + na * rtk->nx] = -1.0 / lam[1];
567 D[k1 + na * rtk->nx] = -1.0 / lam[0];
568 D[k2 + na * rtk->nx] = 1.0 / lam[1];
569 rtk->ssat[sat1s[na] - 1].fix[1] = rtk->ssat[sat2s[na] - 1].fix[1] = 1;
570 na++;
571
572 if (strstr(rtk->opt.pppopt, "-TRACE_AR")) {
573 trace(NULL, 3, "search_amb_wl(%4d): %s %s N,a= %8.3f %8.3f sig=%8.3f\n", __LINE__, s1, s2, n, b, sqrt(var));
574 }
575 }
576 trace(NULL, 4, "search_amb_wl(%4d): number of fixed wide-lane ambiguity = %d / %d\n", __LINE__, na, ns);
577 return na;
578}
579/* generate SD-matrix of narrow-lane ambiguity --------------------------------*/
580static int gen_sd_matrix_n1(rtk_t* rtk, const double* x, const double* P, const int* sat1, const int* sat2, int ns,
581 int nf, int* sat1s, int* sat2s, int* frqs, double* a, double* Q, double* D) {
582 int i, j, k, na = 0, ind[MAXOBS][2], i0, i1, j0, j1;
583 double q, lam[NFREQ];
584 char s1[32], s2[32];
585 const char label[NFREQ][10] = {"N1 ", "WL ", "EWL", "EW2"};
586 unsigned int tick = tickget();
587
588 /* initialize D-matrix */
589 for (i = 0; i < rtk->nx * ns; i++) {
590 D[i] = 0.0;
591 }
592
593 /* freq-ambiguity SD-matrix N1 */
594 for (i = 0; i < ns; i++) {
595 if (sat1[i] <= 0 || sat2[i] <= 0) {
596 continue;
597 }
598 get_wavelength(sat1[i], lam);
599 satno2id(sat1[i], s1);
600 satno2id(sat2[i], s2);
601
602 sat1s[na] = sat1[i];
603 sat2s[na] = sat2[i];
604 frqs[na] = 0;
605
606 j = IB(sat1[i], 0, &rtk->opt);
607 k = IB(sat2[i], 0, &rtk->opt);
608
609 if (lam[0] == 0.0) {
610 continue;
611 }
612 if (x[j] == 0.0 || x[k] == 0.0) {
613 continue;
614 }
615
616 D[j + na * rtk->nx] = 1.0 / lam[0];
617 D[k + na * rtk->nx] = -1.0 / lam[0];
618 ind[na][0] = j;
619 ind[na][1] = k;
620 na++;
621 }
622 trace(NULL, 3, "gen_sd_matrix_n1(%4d): ns=%d proc_time=%d [ms]\n", __LINE__, ns, (int)(tickget() - tick));
623
624 /* a=D'*x, Q=D'*P*D */
625 for (j = 0; j < na; j++) {
626 j0 = ind[j][0];
627 j1 = ind[j][1];
628 a[j] = D[j0 + j * rtk->nx] * x[j0] + D[j1 + j * rtk->nx] * x[j1];
629
630 for (i = j; i < na; i++) {
631 i0 = ind[i][0];
632 i1 = ind[i][1];
633 q = D[i0 + i * rtk->nx] * P[i0 + j0 * rtk->nx] * D[j0 + j * rtk->nx];
634 q += D[i0 + i * rtk->nx] * P[i0 + j1 * rtk->nx] * D[j1 + j * rtk->nx];
635 q += D[i1 + i * rtk->nx] * P[i1 + j0 * rtk->nx] * D[j0 + j * rtk->nx];
636 q += D[i1 + i * rtk->nx] * P[i1 + j1 * rtk->nx] * D[j1 + j * rtk->nx];
637 Q[i + j * na] = Q[j + i * na] = q;
638 }
639 }
640 if (strstr(rtk->opt.pppopt, "-TRACE_AR")) {
641 write_trace_amb(rtk, a, Q, na, sat1s, sat2s, frqs, label, 8);
642 }
643 trace(NULL, 3, "gen_sd_matrix_n1(%4d): na=%d proc_time=%d [ms]\n", __LINE__, na, (int)(tickget() - tick));
644 return na;
645}
646/* search integer ambiguity by LAMBDA ----------------------------------------*/
647static int search_amb_lambda(rtk_t* rtk, const obsd_t* obs, int n, const double* azel, const int* sat1s,
648 const int* sat2s, const int* frq, const double* x, const double* P, const double* D,
649 const double* Q, const double* a, double* N, int na, int* exc_sat_flag) {
650 const double thres_fact[] = {5.0, 5.0, 3.0, 2.0, 1.5};
651 double s[2], thres = 0.0;
652 int i, trace_AR = 0, nm = 0;
653 char s1[32], s2[32], tstr[30];
654 unsigned int tick = tickget();
655 trace(NULL, 3, "search_amb_lambda(%4d): na=%d\n", __LINE__, na);
656
657 if (strstr(rtk->opt.pppopt, "-TRACE_AR")) {
658 trace_AR = 1;
659 }
660
661 time2str(rtk->sol.time, tstr, 0);
662
663 /* integer least-square (a->N) */
664 if (lambda(na, 2, a, Q, N, s) || s[0] <= 0.0) {
665 trace(NULL, 2, "search_amb_lambda(%4d): error lambda\n", __LINE__);
666 return 0;
667 }
668
669 /* threshold for ratio test */
670 thres = rtk->opt.thresar[0];
671 if (na - MIN_AMB_RES < (sizeof(thres_fact) / sizeof(thres_fact[0]))) {
672 thres *= thres_fact[na - MIN_AMB_RES];
673 trace(NULL, 2, "search_amb_lambda(%4d): inflated threshold na-MIN_AMB_RES=%d thres_fact=%.2f thres=%.2f\n",
674 __LINE__, na - MIN_AMB_RES, thres_fact[na - MIN_AMB_RES], thres);
675 }
676 for (i = 0; i < MAXSAT; i++) {
677 exc_sat_flag[i] = 0;
678 }
679 for (i = 0; i < na; i++) {
680 if (fabs(N[i] - N[i + na]) < 0.001) {
681 nm++;
682 } else {
683 exc_sat_flag[sat1s[i] - 1] = (int)fabs(N[i] - N[i + na]);
684 }
685 }
686 trace(NULL, 3, "search_amb_lambda(%4d): %s na=%2d nm= %2d match_rate=%7.2f\n", __LINE__, tstr, na, nm,
687 (double)nm / (double)na);
688 if ((double)nm / (double)na > REL_MATCH_RATE) {
689 thres *= 0.8;
690 }
691 if ((double)nm / (double)na < MIN_MATCH_RATE) {
692 thres = 99.99;
693 }
694
695 if (trace_AR) {
696 trace(NULL, 2, "search_amb_lambda(%4d): na= %2d ratio= %.3f (s[1](%.3f)/s[0](%.3f)) thres= %.3f\n", __LINE__,
697 na, s[1] / s[0], s[1], s[0], thres);
698 trace(NULL, 2, "search_amb_lambda(%4d): first candidate\n", __LINE__);
699 for (i = 0; i < na; i++) {
700 satno2id(sat1s[i], s1);
701 satno2id(sat2s[i], s2);
702 trace(NULL, 2, "search_amb_lambda(%4d): i= %2d na= %2d %s %s N,a= %8.3f %8.3f frac=%8.3f\n", __LINE__, i,
703 na, s1, s2, N[i], a[i], N[i] - a[i]);
704 }
705 trace(NULL, 2, "search_amb_lambda(%4d): second candidate\n", __LINE__);
706 for (i = 0; i < na; i++) {
707 satno2id(sat1s[i], s1);
708 satno2id(sat2s[i], s2);
709 trace(NULL, 2, "search_amb_lambda(%4d): i= %2d na= %2d %s %s N,a= %8.3f %8.3f frac=%8.3f\n", __LINE__, i,
710 na, s1, s2, N[i + na], a[i], N[i + na] - a[i]);
711 }
712 trace(NULL, 2, "search_amb_lambda(%4d): difference\n", __LINE__);
713 for (i = 0; i < na; i++) {
714 satno2id(sat1s[i], s1);
715 satno2id(sat2s[i], s2);
716 trace(NULL, 2, "search_amb_lambda(%4d): i= %2d na= %2d %s %s N1,N2= %8.3f %8.3f diff=%8.3f\n", __LINE__, i,
717 na, s1, s2, N[i], N[i + na], N[i] - N[i + na]);
718 }
719 }
720
721 rtk->sol.ratio = (float)MIN(s[1] / s[0], 999.9);
722 if (s[1] / s[0] < thres) {
723 trace(NULL, 2, "search_amb_lambda(%4d): failed to fix. na=%d ratio=%.2f/%.2f proc_time=%d [ms]\n", __LINE__, na,
724 s[1] / s[0], thres, (int)(tickget() - tick));
725 return 0;
726 }
727
728 /* update fix flags */
729 for (i = 0; i < na; i++) {
730 rtk->ssat[sat1s[i] - 1].fix[frq[i]] = rtk->ssat[sat2s[i] - 1].fix[frq[i]] = 2;
731 }
732
733 trace(NULL, 2, "search_amb_lambda(%4d): successed to fix. na=%d ratio=%.2f/%.2f proc_time=%d [ms]\n", __LINE__, na,
734 s[1] / s[0], thres, (int)(tickget() - tick));
735 return na;
736}
737/* update states with integer ambiguity constraints --------------------------*/
738static int update_states(double* x, double* P, const double* D, int nx, const double* N, const double* a, int na,
739 const int* sats, const int* frqs, int step) {
740 double *R, b[MAXOBS * NFREQ * 2];
741 double var;
742 int i, info, sys;
743 unsigned int tick = tickget();
744
745 /* nothing to update: skip the filter so it is not called with a zero-size
746 * gain matrix. This happens for the extra-wide-lane step on a dual-frequency
747 * setup (no 3rd frequency -> no EWL ambiguity); without the guard filter()
748 * invokes LAPACK DGETRF with n=0 (XERBLA "parameter 4 illegal") and returns
749 * an error, which previously aborted the whole AR before wide-/narrow-lane. */
750 if (na <= 0) {
751 return 0;
752 }
753
754 R = zeros(na, na);
755 for (i = 0; i < na; i++) {
756 var = SQR(CONST_AMB);
757
758 /* de-weight for a specific system or frequency */
759 sys = satsys_bd2(sats[i], NULL);
760 if (sys & (SYS_BD2)) {
761 var = SQR(CONST_AMB_BDS);
762 }
763 if (sys & (SYS_CMP)) {
764 var = SQR(CONST_AMB_BDS);
765 if (freq_idx2freq_num(SYS_CMP, frqs[i]) == 5) { /* B2a */
766 var = SQR(CONST_AMB_BDS_B2a);
767 }
768 }
769 if (step == STEP_EWL) {
770 switch (sys) {
771 case SYS_GPS:
772 var = SQR(CONST_AMB_EWL);
773 break;
774 case SYS_QZS:
775 break;
776 case SYS_CMP:
777 var = SQR(CONST_AMB_EWL);
778 break;
779 case SYS_BD2:
780 var = SQR(CONST_AMB_EWL);
781 break;
782 case SYS_GAL:
783 if (freq_idx2freq_num(SYS_GAL, frqs[i]) == 6) { /* E6 */
784 var = SQR(CONST_AMB_GAL_E6);
785 }
786 break;
787 }
788 }
789 b[i] = N[i] - a[i];
790 R[i + i * na] = var;
791 trace(NULL, 4,
792 "update_states(%4d): sat=%3d frqs=%d fn=%d i=%2d na=%2d N,a=%10.3f %10.3f frac=%8.3f sig=%6.3f\n",
793 __LINE__, sats[i], frqs[i], freq_idx2freq_num(sys, frqs[i]), i, na, N[i], a[i], b[i], sqrt(var));
794 }
795 if ((info = filter(x, P, D, b, R, nx, na))) {
796 trace(NULL, 1, "update_states(%4d): filter error (info=%d)\n", __LINE__, info);
797 }
798 free(R);
799
800 trace(NULL, 3, "update_states(%4d): na=%d proc_time=%d [ms]\n", __LINE__, na, (int)(tickget() - tick));
801 return info;
802}
803/* exclude satellite for partial AR ------------------------------------------*/
804static int exc_sat_par(rtk_t* rtk, int* sat1, int* sat2, const double* el1, const double* el2, int ns,
805 const int* exc_sat_flag) {
806 int i, minidx = 0, sys;
807 double minel = 9999.9;
808 double el, offset = PI / 2.0;
809 char s1[32], s2[32];
810
811 for (i = 0; i < ns; i++) {
812 if (!sat1[i]) {
813 continue;
814 }
815 if (!exc_sat_flag[sat1[i] - 1]) {
816 continue;
817 }
818 el = el1[i];
819
820 /* exclude IGSO satellites first */
821 sys = satsys_bd2(sat1[i], NULL);
822 if (sys & SYS_BD2) {
823 el -= offset;
824 } else if (sys & SYS_CMP) {
825 if (is_bds3_igso(sat1[i])) {
826 el -= offset;
827 }
828 } else if (sys & SYS_QZS) {
829 el -= offset;
830 }
831
832 if (el < minel) {
833 minidx = i;
834 minel = el;
835 }
836 trace(NULL, 4, "exc_sat_par(%4d): i=%2d sat1=%3d sat2=%3d el=%4.1f %4.1f minidx=%2d minel=%.3f\n", __LINE__, i,
837 sat1[i], sat2[i], el1[i] * R2D, el2[i] * R2D, minidx, minel * R2D);
838 }
839 satno2id(sat1[minidx], s1);
840 satno2id(sat2[minidx], s2);
841 trace(NULL, 2, "exc_sat_par(%4d): excluded %s %s sat1=%3d sat2=%3d el=%4.1f %4.1f\n", __LINE__, s1, s2,
842 sat1[minidx], sat2[minidx], el1[minidx] * R2D, el2[minidx] * R2D);
843 sat1[minidx] = 0;
844 sat2[minidx] = 0;
845
846 for (i = 0; i < ns; i++) {
847 trace(NULL, 4, "exc_sat_par(%4d): i=%2d sat1=%3d sat2=%3d el1=%4.1f\n", __LINE__, i, sat1[i], sat2[i],
848 el1[i] * R2D);
849 }
850
851 return ns - 1;
852}
853/* ambiguity resolution by ILS (integer-least-square) ------------------------*/
854static int ppp_amb_ILS(rtk_t* rtk, const obsd_t* obs, int n, int* exc, const nav_t* nav, const double* azel, double* x,
855 double* P) {
856 double *D, *Q, a[MAXOBS * NFREQ], N[MAXOBS * NFREQ * 2], *xp, *Pp;
857 double el1[MAXOBS], el2[MAXOBS], std[3];
858 int sat1[MAXOBS], sat2[MAXOBS], exc_sat_flag[MAXSAT];
859 int sat1s[MAXOBS * NFREQ], sat2s[MAXOBS * NFREQ], frqs[MAXOBS * NFREQ];
860 int i, ns, na = 0, info = 0;
861 int nf = rtk->opt.nf, sol_fix_wl = 1;
862 char tstr[30];
863 unsigned int tick = tickget();
864
865 if (strstr(rtk->opt.pppopt, "-AR_NOFIX_WL")) {
866 sol_fix_wl = 0;
867 }
868
869 time2str(rtk->sol.time, tstr, 0);
870 trace(NULL, 3, "ppp_amb_ILS(%4d): nf=%d\n", __LINE__, nf);
871
872 /* generate satellite SD */
873 ns = gen_sat_sd(rtk, obs, n, exc, azel, nf, sat1, sat2, el1, el2);
874 if (ns <= 0) {
875 trace(NULL, 2, "ppp_amb_ILS(%4d): no generated satellite SD ns= %d\n", __LINE__, ns);
876 return 0;
877 }
878 trace(NULL, 3, "ppp_amb_ILS(%4d): %s generate satellite SD ns= %d\n", __LINE__, tstr, ns);
879
880 Pp = mat(rtk->nx, rtk->nx);
881 xp = mat(rtk->nx, 1);
882 D = zeros(rtk->nx, n * nf);
883 Q = mat(ns * nf, ns * nf);
884
885 write_trace_sd_amb(rtk, x, P, sat1, sat2, ns, nf, sat1s, sat2s, frqs, a, 0, STEP_EWL);
886
887 /* extra wide-lane */
888 na = search_amb_ewl(rtk, x, P, sat1, sat2, ns, nf, sat1s, sat2s, frqs, a, N, D);
889 info = update_states(x, P, D, rtk->nx, N, a, na, sat1s, frqs, STEP_EWL);
890 if (info) {
891 trace(NULL, 1, "ppp_amb_ILS(%4d): %s update error\n", __LINE__, tstr);
892 free(D);
893 free(Q);
894 free(xp);
895 free(Pp);
896 return 0;
897 }
898 trace(NULL, 3, "ppp_amb_ILS(%4d): %s extra wide-lane ambiguity fixed. nfix=%2d nsat=%2d\n", __LINE__, tstr, na, ns);
899
900 write_trace_sd_amb(rtk, x, P, sat1, sat2, ns, nf, sat1s, sat2s, frqs, a, 0, STEP_WL);
901
902 /* wide-lane */
903 na = search_amb_wl(rtk, x, P, sat1, sat2, ns, nf, sat1s, sat2s, frqs, a, N, D);
904 if (na == 0) {
905 trace(NULL, 2, "ppp_amb_ILS(%4d): %s wide-lane ambiguity search error\n", __LINE__, tstr);
906 rtk->sol.age = 0;
907 free(D);
908 free(Q);
909 free(xp);
910 free(Pp);
911 return 0;
912 }
913 info = update_states(x, P, D, rtk->nx, N, a, na, sat1s, frqs, STEP_WL);
914 if (info) {
915 trace(NULL, 1, "ppp_amb_ILS(%4d): %s update error\n", __LINE__, tstr);
916 free(D);
917 free(Q);
918 free(xp);
919 free(Pp);
920 return 0;
921 }
922 trace(NULL, 3, "ppp_amb_ILS(%4d): %s wide-lane ambiguity fixed. nfix=%2d nsat=%2d proc_time=%d [ms]\n", __LINE__,
923 tstr, na, ns, (int)(tickget() - tick));
924
925 matcpy(Pp, P, rtk->nx, rtk->nx);
926 matcpy(xp, x, rtk->nx, 1);
927 write_trace_sd_amb(rtk, x, P, sat1, sat2, ns, nf, sat1s, sat2s, frqs, a, 0, STEP_NL);
928
929 /* narrow-lane */
930 for (i = 0; i < 3; i++) {
931 std[i] = sqrt(P[i + i * rtk->nx]);
932 }
933 if (norm(std, 3) < rtk->opt.thresar[1]) {
934 trace(NULL, 3, "ppp_amb_ILS(%4d): %s narrow-lane search. nsat=%d std=%.2f\n", __LINE__, tstr, ns, norm(std, 3));
935
936 for (i = 0; i < rtk->opt.armaxiter; i++) {
937 na = gen_sd_matrix_n1(rtk, x, P, sat1, sat2, ns, nf, sat1s, sat2s, frqs, a, Q, D);
938 if (na < MIN_AMB_RES) {
939 trace(NULL, 2, "ppp_amb_ILS(%4d): %s no integer ambiguity candidate. na=%d/%d\n", __LINE__, tstr, na,
941 na = 0;
942 break;
943 }
944
945 na = search_amb_lambda(rtk, obs, n, azel, sat1s, sat2s, frqs, x, P, D, Q, a, N, na, exc_sat_flag);
946 if (na > 0) {
947 break;
948 }
949
950 /* exclude satellite for partial AR */
951 exc_sat_par(rtk, sat1, sat2, el1, el2, ns, exc_sat_flag);
952 }
953 } else {
954 na = 0;
955 i = 0;
956 trace(NULL, 2, "ppp_amb_ILS(%4d): %s std is greater than the threshold. std=%.2f / %.2f\n", __LINE__, tstr,
957 norm(std, 3), rtk->opt.thresar[1]);
958 }
959 if (na == 0) {
960 rtk->sol.age = (float)i;
961 free(D);
962 free(Q);
963 free(xp);
964 free(Pp);
965 trace(NULL, 2, "ppp_amb_ILS(%4d): %s narrow-lane search error. iter=%d proc_time=%d [ms]\n", __LINE__, tstr,
966 (int)rtk->sol.age, (int)(tickget() - tick));
967 return sol_fix_wl; /* wide-lane fixed */
968 }
969 info = update_states(x, P, D, rtk->nx, N, a, na, sat1s, frqs, STEP_NL);
970 rtk->sol.age = (float)i;
971
972 /* test by standard deviation of position */
973 for (i = 0; i < 3; i++) {
974 std[i] = sqrt(P[i + i * rtk->nx]);
975 }
976 if (norm(std, 3) > MAX_STD_FIX) {
977 /* reset fix flag */
978 for (i = 0; i < na; i++) {
979 rtk->ssat[sat1s[i] - 1].fix[0] = rtk->ssat[sat2s[i] - 1].fix[0] = 0;
980 }
981 matcpy(P, Pp, rtk->nx, rtk->nx);
982 matcpy(x, xp, rtk->nx, 1);
983 free(D);
984 free(Q);
985 free(xp);
986 free(Pp);
987 trace(NULL, 2, "ppp_amb_ILS(%4d): %s failed to std test. std=%.3f / %.3f iter=%d proc_time=%d [ms]\n", __LINE__,
988 tstr, norm(std, 3), MAX_STD_FIX, (int)rtk->sol.age, (int)(tickget() - tick));
989 return sol_fix_wl; /* wide-lane fixed */
990 }
991
992 write_trace_sd_amb(rtk, x, P, sat1, sat2, ns, nf, sat1s, sat2s, frqs, a, 1, 9);
993 trace(NULL, 3, "ppp_amb_ILS(%4d): %s ambiguity fixed. nfix=%2d nsat=%2d std=%.3f iter=%d proc_time=%d [ms]\n",
994 __LINE__, tstr, na, ns, norm(std, 3), (int)rtk->sol.age, (int)(tickget() - tick));
995
996 free(D);
997 free(Q);
998 free(xp);
999 free(Pp);
1000 return info ? sol_fix_wl : 2; /* narrow-lane fixed */
1001}
1002/* ambiguity resolution in ppp -----------------------------------------------*/
1003extern int ppp_ar(mrtk_ctx_t* ctx, rtk_t* rtk, const obsd_t* obs, int n, int* exc, const nav_t* nav, const double* azel,
1004 double* x, double* P) {
1005 if (n <= 0 || rtk->opt.modear < ARMODE_CONT) {
1006 return 0;
1007 }
1008
1009 if (rtk->opt.ionoopt != IONOOPT_EST) {
1010 return 0;
1011 }
1012 return ppp_amb_ILS(rtk, obs, n, exc, nav, azel, x, P);
1013}
MRTKLIB Constants — Physical, navigation, and system constants.
MRTKLIB Context — runtime context for processing, trace, and error handling.
#define CLIGHT
Definition mrtk_coords.c:41
#define PI
Definition mrtk_coords.c:35
#define MAXSAT
Definition mrtk_coords.c:45
#define SYS_GPS
Definition mrtk_eph.c:65
#define SYS_QZS
Definition mrtk_eph.c:69
#define SYS_CMP
Definition mrtk_eph.c:70
#define SYS_GAL
Definition mrtk_eph.c:68
struct nav_s nav_t
Definition mrtk_eph.h:40
#define MAXOBS
MRTKLIB Integer Ambiguity Resolution Module — LAMBDA method.
MRTKLIB MADOCA-PPP Module — QZSS L6E CSSR message decode functions.
MRTKLIB Matrix Module — Matrix/vector operations and estimation.
int is_bds3igso(int prn)
Test whether a BeiDou PRN is listed as BDS-3 IGSO (see set_bds3igso()).
Definition mrtk_nav.c:267
#define R2D
Definition mrtk_obs.c:51
#define SYS_BD2
Definition mrtk_obs.c:62
MRTKLIB Observation Module — Observation data types and utility functions.
#define IONOOPT_EST
Definition mrtk_opt.h:96
#define TROPOPT_EST
Definition mrtk_opt.h:105
#define ARMODE_CONT
Definition mrtk_opt.h:129
#define REL_MATCH_RATE
Definition mrtk_ppp_ar.c:84
void satno2id(int sat, char *id)
Definition mrtk_nav.c:817
#define CONST_AMB_BDS_B2a
Definition mrtk_ppp_ar.c:79
int satsys(int sat, int *prn)
Definition mrtk_nav.c:117
static int ppp_amb_ILS(rtk_t *rtk, const obsd_t *obs, int n, int *exc, const nav_t *nav, const double *azel, double *x, double *P)
#define STEP_NL
Definition mrtk_ppp_ar.c:90
double * mat(int n, int m)
Definition mrtk_mat.c:76
#define STEP_EWL
Definition mrtk_ppp_ar.c:88
#define SWAP_D(x, y)
static int exc_sat_sd(rtk_t *rtk, const obsd_t *obs, int exc, double el, int nf, int sys)
gtime_t epoch2time(const double *ep)
Definition mrtk_time.c:113
int lambda(int n, int m, const double *a, const double *Q, double *F, double *s)
static int exc_sat_par(rtk_t *rtk, int *sat1, int *sat2, const double *el1, const double *el2, int ns, const int *exc_sat_flag)
double * zeros(int n, int m)
Definition mrtk_mat.c:108
static void write_trace_amb(rtk_t *rtk, const double *a, const double *Q, int na, const int *sat1s, const int *sat2s, const int *frqs, const char label[5][10], int step)
static int search_amb_lambda(rtk_t *rtk, const obsd_t *obs, int n, const double *azel, const int *sat1s, const int *sat2s, const int *frq, const double *x, const double *P, const double *D, const double *Q, const double *a, double *N, int na, int *exc_sat_flag)
void matcpy(double *A, const double *B, int n, int m)
Definition mrtk_mat.c:205
#define MAX_FRAC_WL_FIX
Definition mrtk_ppp_ar.c:85
unsigned int tickget(void)
Definition mrtk_time.c:566
void time2epoch(gtime_t t, double *ep)
Definition mrtk_time.c:136
#define MIN(x, y)
Definition mrtk_ppp_ar.c:92
void time2str(gtime_t t, char *s, int n)
Definition mrtk_time.c:507
static void write_trace_sd_amb(rtk_t *rtk, const double *x, const double *P, const int *sat1, const int *sat2, int ns, int nf, int *sat1s, int *sat2s, int *frqs, double *a, int post, int step)
static int search_amb_wl(rtk_t *rtk, const double *x, const double *P, int *sat1, int *sat2, int ns, int nf, int *sat1s, int *sat2s, int *frqs, double *a, double *N, double *D)
int filter(double *x, double *P, const double *H, const double *v, const double *R, int n, int m)
Definition mrtk_mat.c:524
#define STEP_WL
Definition mrtk_ppp_ar.c:89
double timediff(gtime_t t1, gtime_t t2)
Definition mrtk_time.c:279
int satid2no(const char *id)
Definition mrtk_nav.c:753
static int is_bds3_igso(int sat)
#define MIN_AMB_RES
Definition mrtk_ppp_ar.c:76
#define SQR(x)
Definition mrtk_ppp_ar.c:94
#define MAX(x, y)
Definition mrtk_ppp_ar.c:93
#define MIN_MATCH_RATE
Definition mrtk_ppp_ar.c:83
#define SWAP_I(x, y)
Definition mrtk_ppp_ar.c:96
gtime_t timeadd(gtime_t t, double sec)
Definition mrtk_time.c:265
double norm(const double *a, int n)
Definition mrtk_mat.c:165
int satsys_bd2(int sat, int *prn)
Definition mrtk_nav.c:159
char * time_str(gtime_t t, int n)
Definition mrtk_time.c:530
static int gen_sat_sd(rtk_t *rtk, const obsd_t *obs, int n, const int *exc, const double *azel, int nf, int *sat1, int *sat2, double *el1, double *el2)
double freq_num2freq(int sys, int freq_num, int fcn)
Definition mrtk_nav.c:680
#define CONST_AMB
Definition mrtk_ppp_ar.c:77
#define ROUND(x)
Definition mrtk_ppp_ar.c:95
#define IB(s, f, opt)
static int gen_sd_matrix_n1(rtk_t *rtk, const double *x, const double *P, const int *sat1, const int *sat2, int ns, int nf, int *sat1s, int *sat2s, int *frqs, double *a, double *Q, double *D)
void matmul(const char *tr, int n, int k, int m, double alpha, const double *A, const double *B, double beta, double *C)
Definition mrtk_mat.c:310
static int update_states(double *x, double *P, const double *D, int nx, const double *N, const double *a, int na, const int *sats, const int *frqs, int step)
#define MAX_STD_WL_FIX
Definition mrtk_ppp_ar.c:86
int freq_idx2freq_num(int sys, int freq_idx)
Definition mrtk_nav.c:649
static void get_wavelength(int sat, double *lam)
#define CONST_AMB_GAL_E6
Definition mrtk_ppp_ar.c:80
#define CONST_AMB_BDS
Definition mrtk_ppp_ar.c:78
int ppp_ar(mrtk_ctx_t *ctx, rtk_t *rtk, const obsd_t *obs, int n, int *exc, const nav_t *nav, const double *azel, double *x, double *P)
Ambiguity resolution in PPP.
static int search_amb_ewl(rtk_t *rtk, const double *x, const double *P, const int *sat1, const int *sat2, int ns, int nf, int *sat1s, int *sat2s, int *frqs, double *a, double *N, double *D)
#define MAX_STD_FIX
Definition mrtk_ppp_ar.c:82
#define CONST_AMB_EWL
Definition mrtk_ppp_ar.c:81
MRTKLIB PPP Ambiguity Resolution Module.
#define NT(opt)
MRTKLIB System Module — OS/filesystem utility functions.
uint32_t tickget(void)
Get current tick in milliseconds.
Definition mrtk_time.c:566
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.
GNSS time representation.
Definition mrtk_time.h:49
Runtime context for MRTKLIB processing.
Observation data record.
Definition mrtk_obs.h:44
uint8_t sat
Definition mrtk_obs.h:46
double L[5+5]
Definition mrtk_obs.h:50
int armaxiter
Definition mrtk_opt.h:186
double elmin
Definition mrtk_opt.h:176
int ionoopt
Definition mrtk_opt.h:187
int arsys
Definition mrtk_opt.h:182
int tropopt
Definition mrtk_opt.h:188
char pppopt[256]
Definition mrtk_opt.h:243
double thresar[8]
Definition mrtk_opt.h:211
double elmaskar
Definition mrtk_opt.h:212
int nx
Definition mrtk_rtkpos.h:52
prcopt_t opt
Definition mrtk_rtkpos.h:63
ssat_t ssat[MAXSAT]
Definition mrtk_rtkpos.h:60
sol_t sol
Definition mrtk_rtkpos.h:50
float ratio
Definition mrtk_sol.h:57
float age
Definition mrtk_sol.h:56
gtime_t time
Definition mrtk_sol.h:45
uint8_t vsat[5]
Definition mrtk_sol.h:104
uint8_t fix[5]
Definition mrtk_sol.h:106
#define free(x)
Definition toml.c:53