gnss-js 1.23.0 → 1.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-CUWF56ST.js → chunk-4XGKCVE3.js} +384 -13
- package/dist/index.cjs +389 -13
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +11 -1
- package/dist/ionex-DaW5x9nq.d.cts +23 -0
- package/dist/ionex-DaW5x9nq.d.ts +23 -0
- package/dist/positioning.cjs +389 -13
- package/dist/positioning.d.cts +225 -7
- package/dist/positioning.d.ts +225 -7
- package/dist/positioning.js +11 -1
- package/dist/rinex.d.cts +2 -23
- package/dist/rinex.d.ts +2 -23
- package/package.json +1 -1
package/dist/positioning.cjs
CHANGED
|
@@ -20,9 +20,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/positioning/index.ts
|
|
21
21
|
var positioning_exports = {};
|
|
22
22
|
__export(positioning_exports, {
|
|
23
|
+
IONO_L1_M_PER_TECU: () => IONO_L1_M_PER_TECU,
|
|
23
24
|
RtkFloatEngine: () => RtkFloatEngine,
|
|
25
|
+
gimSlantIonoDelayL1: () => gimSlantIonoDelayL1,
|
|
26
|
+
gimVerticalTec: () => gimVerticalTec,
|
|
24
27
|
ionoFree: () => ionoFree,
|
|
25
28
|
klobucharDelay: () => klobucharDelay,
|
|
29
|
+
lambdaReduction: () => lambdaReduction,
|
|
30
|
+
lambdaSearch: () => lambdaSearch,
|
|
26
31
|
satClockCorrection: () => satClockCorrection,
|
|
27
32
|
solveDgnss: () => solveDgnss,
|
|
28
33
|
solveSpp: () => solveSpp,
|
|
@@ -462,6 +467,252 @@ function klobucharDelay(coeffs, latRad, lonRad, azRad, elRad, gpsTowSec) {
|
|
|
462
467
|
return F * (5e-9 + amp * (1 - x2 / 2 + x2 * x2 / 24));
|
|
463
468
|
}
|
|
464
469
|
|
|
470
|
+
// src/positioning/gim.ts
|
|
471
|
+
var R_E = 6371e3;
|
|
472
|
+
var H_ION = 45e4;
|
|
473
|
+
var F_L1 = 157542e4;
|
|
474
|
+
var IONO_L1_M_PER_TECU = 403e15 / (F_L1 * F_L1);
|
|
475
|
+
function tecAtMap(grid, mapIdx, latDeg, lonDeg) {
|
|
476
|
+
const m = grid.maps[mapIdx];
|
|
477
|
+
const { lats, lons } = grid;
|
|
478
|
+
const w = lons.length;
|
|
479
|
+
const fi = (latDeg - lats[0]) / (lats[lats.length - 1] - lats[0]) * (lats.length - 1);
|
|
480
|
+
const fj = (lonDeg - lons[0]) / (lons[w - 1] - lons[0]) * (w - 1);
|
|
481
|
+
const i0 = Math.max(0, Math.min(lats.length - 2, Math.floor(fi)));
|
|
482
|
+
const j0 = Math.max(0, Math.min(w - 2, Math.floor(fj)));
|
|
483
|
+
const di = Math.max(0, Math.min(1, fi - i0));
|
|
484
|
+
const dj = Math.max(0, Math.min(1, fj - j0));
|
|
485
|
+
return m[i0 * w + j0] * (1 - di) * (1 - dj) + m[i0 * w + j0 + 1] * (1 - di) * dj + m[(i0 + 1) * w + j0] * di * (1 - dj) + m[(i0 + 1) * w + j0 + 1] * di * dj;
|
|
486
|
+
}
|
|
487
|
+
function gimVerticalTec(grid, timeMs, latDeg, lonDeg) {
|
|
488
|
+
const e = grid.epochs;
|
|
489
|
+
if (e.length === 0 || timeMs < e[0] || timeMs > e[e.length - 1]) return null;
|
|
490
|
+
let i = 0;
|
|
491
|
+
while (i < e.length - 2 && e[i + 1] <= timeMs) i++;
|
|
492
|
+
const span = e[i + 1] - e[i];
|
|
493
|
+
const f = span > 0 ? (timeMs - e[i]) / span : 0;
|
|
494
|
+
const a = tecAtMap(grid, i, latDeg, lonDeg);
|
|
495
|
+
const b = tecAtMap(grid, i + 1, latDeg, lonDeg);
|
|
496
|
+
if (!Number.isFinite(a) || !Number.isFinite(b)) return null;
|
|
497
|
+
return a * (1 - f) + b * f;
|
|
498
|
+
}
|
|
499
|
+
function gimSlantIonoDelayL1(grid, latRad, lonRad, azRad, elRad, timeMs) {
|
|
500
|
+
if (elRad <= 0) return null;
|
|
501
|
+
const sinZp = R_E / (R_E + H_ION) * Math.cos(elRad);
|
|
502
|
+
const mapping = 1 / Math.sqrt(1 - sinZp * sinZp);
|
|
503
|
+
const psi = Math.PI / 2 - elRad - Math.asin(sinZp);
|
|
504
|
+
const latI = Math.asin(
|
|
505
|
+
Math.sin(latRad) * Math.cos(psi) + Math.cos(latRad) * Math.sin(psi) * Math.cos(azRad)
|
|
506
|
+
);
|
|
507
|
+
const lonI = lonRad + Math.asin(Math.sin(psi) * Math.sin(azRad) / Math.cos(latI));
|
|
508
|
+
const latDeg = latI * 180 / Math.PI;
|
|
509
|
+
const lonDeg = ((lonI * 180 / Math.PI + 540) % 360 + 360) % 360 - 180;
|
|
510
|
+
const vtec = gimVerticalTec(grid, timeMs, latDeg, lonDeg);
|
|
511
|
+
if (vtec === null) return null;
|
|
512
|
+
return IONO_L1_M_PER_TECU * vtec * mapping;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// src/positioning/lambda.ts
|
|
516
|
+
var LOOPMAX = 1e4;
|
|
517
|
+
var ROUND = (x) => Math.floor(x + 0.5);
|
|
518
|
+
var SGN = (x) => x <= 0 ? -1 : 1;
|
|
519
|
+
function ldFactor(n, Q, L, D) {
|
|
520
|
+
const A = Float64Array.from(Q);
|
|
521
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
522
|
+
D[i] = A[i + i * n];
|
|
523
|
+
if (D[i] <= 0) return false;
|
|
524
|
+
const a = Math.sqrt(D[i]);
|
|
525
|
+
for (let j = 0; j <= i; j++) L[i + j * n] = A[i + j * n] / a;
|
|
526
|
+
for (let j = 0; j <= i - 1; j++)
|
|
527
|
+
for (let k = 0; k <= j; k++) A[j + k * n] -= L[i + k * n] * L[i + j * n];
|
|
528
|
+
for (let j = 0; j <= i; j++) L[i + j * n] /= L[i + i * n];
|
|
529
|
+
}
|
|
530
|
+
return true;
|
|
531
|
+
}
|
|
532
|
+
function gauss(n, L, Z, i, j) {
|
|
533
|
+
const mu = ROUND(L[i + j * n]);
|
|
534
|
+
if (mu !== 0) {
|
|
535
|
+
for (let k = i; k < n; k++) L[k + n * j] -= mu * L[k + i * n];
|
|
536
|
+
for (let k = 0; k < n; k++) Z[k + n * j] -= mu * Z[k + i * n];
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
function perm(n, L, D, j, del, Z) {
|
|
540
|
+
const eta = D[j] / del;
|
|
541
|
+
const lam = D[j + 1] * L[j + 1 + j * n] / del;
|
|
542
|
+
D[j] = eta * D[j + 1];
|
|
543
|
+
D[j + 1] = del;
|
|
544
|
+
for (let k = 0; k <= j - 1; k++) {
|
|
545
|
+
const a0 = L[j + k * n];
|
|
546
|
+
const a1 = L[j + 1 + k * n];
|
|
547
|
+
L[j + k * n] = -L[j + 1 + j * n] * a0 + a1;
|
|
548
|
+
L[j + 1 + k * n] = eta * a0 + lam * a1;
|
|
549
|
+
}
|
|
550
|
+
L[j + 1 + j * n] = lam;
|
|
551
|
+
for (let k = j + 2; k < n; k++) {
|
|
552
|
+
const t = L[k + j * n];
|
|
553
|
+
L[k + j * n] = L[k + (j + 1) * n];
|
|
554
|
+
L[k + (j + 1) * n] = t;
|
|
555
|
+
}
|
|
556
|
+
for (let k = 0; k < n; k++) {
|
|
557
|
+
const t = Z[k + j * n];
|
|
558
|
+
Z[k + j * n] = Z[k + (j + 1) * n];
|
|
559
|
+
Z[k + (j + 1) * n] = t;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
function reduction(n, L, D, Z) {
|
|
563
|
+
let j = n - 2;
|
|
564
|
+
let k = n - 2;
|
|
565
|
+
while (j >= 0) {
|
|
566
|
+
if (j <= k) for (let i = j + 1; i < n; i++) gauss(n, L, Z, i, j);
|
|
567
|
+
const del = D[j] + L[j + 1 + j * n] * L[j + 1 + j * n] * D[j + 1];
|
|
568
|
+
if (del + 1e-6 < D[j + 1]) {
|
|
569
|
+
perm(n, L, D, j, del, Z);
|
|
570
|
+
k = j;
|
|
571
|
+
j = n - 2;
|
|
572
|
+
} else j--;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
function search(n, m, L, D, zs, zn, s) {
|
|
576
|
+
let nn = 0;
|
|
577
|
+
let imax = 0;
|
|
578
|
+
let maxdist = 1e99;
|
|
579
|
+
const S = new Float64Array(n * n);
|
|
580
|
+
const dist = new Float64Array(n);
|
|
581
|
+
const zb = new Float64Array(n);
|
|
582
|
+
const z = new Float64Array(n);
|
|
583
|
+
const step = new Float64Array(n);
|
|
584
|
+
let k = n - 1;
|
|
585
|
+
dist[k] = 0;
|
|
586
|
+
zb[k] = zs[k];
|
|
587
|
+
z[k] = ROUND(zb[k]);
|
|
588
|
+
let y = zb[k] - z[k];
|
|
589
|
+
step[k] = SGN(y);
|
|
590
|
+
let c = 0;
|
|
591
|
+
for (; c < LOOPMAX; c++) {
|
|
592
|
+
const newdist = dist[k] + y * y / D[k];
|
|
593
|
+
if (newdist < maxdist) {
|
|
594
|
+
if (k !== 0) {
|
|
595
|
+
dist[--k] = newdist;
|
|
596
|
+
for (let i = 0; i <= k; i++)
|
|
597
|
+
S[k + i * n] = S[k + 1 + i * n] + (z[k + 1] - zb[k + 1]) * L[k + 1 + i * n];
|
|
598
|
+
zb[k] = zs[k] + S[k + k * n];
|
|
599
|
+
z[k] = ROUND(zb[k]);
|
|
600
|
+
y = zb[k] - z[k];
|
|
601
|
+
step[k] = SGN(y);
|
|
602
|
+
} else {
|
|
603
|
+
if (nn < m) {
|
|
604
|
+
if (nn === 0 || newdist > s[imax]) imax = nn;
|
|
605
|
+
for (let i = 0; i < n; i++) zn[i + nn * n] = z[i];
|
|
606
|
+
s[nn++] = newdist;
|
|
607
|
+
} else {
|
|
608
|
+
if (newdist < s[imax]) {
|
|
609
|
+
for (let i = 0; i < n; i++) zn[i + imax * n] = z[i];
|
|
610
|
+
s[imax] = newdist;
|
|
611
|
+
imax = 0;
|
|
612
|
+
for (let i = 0; i < m; i++) if (s[imax] < s[i]) imax = i;
|
|
613
|
+
}
|
|
614
|
+
maxdist = s[imax];
|
|
615
|
+
}
|
|
616
|
+
z[0] += step[0];
|
|
617
|
+
y = zb[0] - z[0];
|
|
618
|
+
step[0] = -step[0] - SGN(step[0]);
|
|
619
|
+
}
|
|
620
|
+
} else {
|
|
621
|
+
if (k === n - 1) break;
|
|
622
|
+
k++;
|
|
623
|
+
z[k] += step[k];
|
|
624
|
+
y = zb[k] - z[k];
|
|
625
|
+
step[k] = -step[k] - SGN(step[k]);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
for (let i = 0; i < m - 1; i++) {
|
|
629
|
+
for (let j = i + 1; j < m; j++) {
|
|
630
|
+
if (s[i] < s[j]) continue;
|
|
631
|
+
const t = s[i];
|
|
632
|
+
s[i] = s[j];
|
|
633
|
+
s[j] = t;
|
|
634
|
+
for (let l = 0; l < n; l++) {
|
|
635
|
+
const u = zn[l + i * n];
|
|
636
|
+
zn[l + i * n] = zn[l + j * n];
|
|
637
|
+
zn[l + j * n] = u;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
return c < LOOPMAX;
|
|
642
|
+
}
|
|
643
|
+
function solveZt(n, m, Z, E) {
|
|
644
|
+
const w = n + m;
|
|
645
|
+
const M = new Float64Array(n * w);
|
|
646
|
+
for (let r = 0; r < n; r++) {
|
|
647
|
+
for (let cIdx = 0; cIdx < n; cIdx++) M[r * w + cIdx] = Z[cIdx + r * n];
|
|
648
|
+
for (let cIdx = 0; cIdx < m; cIdx++) M[r * w + n + cIdx] = E[r + cIdx * n];
|
|
649
|
+
}
|
|
650
|
+
for (let col = 0; col < n; col++) {
|
|
651
|
+
let piv = col;
|
|
652
|
+
for (let r = col + 1; r < n; r++)
|
|
653
|
+
if (Math.abs(M[r * w + col]) > Math.abs(M[piv * w + col])) piv = r;
|
|
654
|
+
if (Math.abs(M[piv * w + col]) < 1e-12) return null;
|
|
655
|
+
if (piv !== col) {
|
|
656
|
+
for (let cIdx = col; cIdx < w; cIdx++) {
|
|
657
|
+
const t = M[col * w + cIdx];
|
|
658
|
+
M[col * w + cIdx] = M[piv * w + cIdx];
|
|
659
|
+
M[piv * w + cIdx] = t;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
const d = M[col * w + col];
|
|
663
|
+
for (let cIdx = col; cIdx < w; cIdx++) M[col * w + cIdx] /= d;
|
|
664
|
+
for (let r = 0; r < n; r++) {
|
|
665
|
+
if (r === col) continue;
|
|
666
|
+
const f = M[r * w + col];
|
|
667
|
+
if (f === 0) continue;
|
|
668
|
+
for (let cIdx = col; cIdx < w; cIdx++)
|
|
669
|
+
M[r * w + cIdx] -= f * M[col * w + cIdx];
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
const X = new Float64Array(n * m);
|
|
673
|
+
for (let r = 0; r < n; r++)
|
|
674
|
+
for (let cIdx = 0; cIdx < m; cIdx++) X[r + cIdx * n] = M[r * w + n + cIdx];
|
|
675
|
+
return X;
|
|
676
|
+
}
|
|
677
|
+
function lambdaSearch(a, Q, n, m = 2) {
|
|
678
|
+
if (n <= 0 || m <= 0 || a.length < n || Q.length < n * n) return null;
|
|
679
|
+
const L = new Float64Array(n * n);
|
|
680
|
+
const D = new Float64Array(n);
|
|
681
|
+
if (!ldFactor(n, Q, L, D)) return null;
|
|
682
|
+
const Z = new Float64Array(n * n);
|
|
683
|
+
for (let i = 0; i < n; i++) Z[i + i * n] = 1;
|
|
684
|
+
reduction(n, L, D, Z);
|
|
685
|
+
const z = new Float64Array(n);
|
|
686
|
+
for (let j = 0; j < n; j++) {
|
|
687
|
+
let sum = 0;
|
|
688
|
+
for (let k = 0; k < n; k++) sum += Z[k + j * n] * a[k];
|
|
689
|
+
z[j] = sum;
|
|
690
|
+
}
|
|
691
|
+
const E = new Float64Array(n * m);
|
|
692
|
+
const s = new Float64Array(m);
|
|
693
|
+
if (!search(n, m, L, D, z, E, s)) return null;
|
|
694
|
+
const F = solveZt(n, m, Z, E);
|
|
695
|
+
if (!F) return null;
|
|
696
|
+
const candidates = [];
|
|
697
|
+
for (let c = 0; c < m; c++) {
|
|
698
|
+
const v = new Float64Array(n);
|
|
699
|
+
for (let i = 0; i < n; i++) v[i] = ROUND(F[i + c * n]);
|
|
700
|
+
candidates.push(v);
|
|
701
|
+
}
|
|
702
|
+
const ratio = m >= 2 && s[0] > 0 ? s[1] / s[0] : Infinity;
|
|
703
|
+
return { candidates, residuals: s, ratio };
|
|
704
|
+
}
|
|
705
|
+
function lambdaReduction(Q, n) {
|
|
706
|
+
if (n <= 0 || Q.length < n * n) return null;
|
|
707
|
+
const L = new Float64Array(n * n);
|
|
708
|
+
const D = new Float64Array(n);
|
|
709
|
+
if (!ldFactor(n, Q, L, D)) return null;
|
|
710
|
+
const Z = new Float64Array(n * n);
|
|
711
|
+
for (let i = 0; i < n; i++) Z[i + i * n] = 1;
|
|
712
|
+
reduction(n, L, D, Z);
|
|
713
|
+
return Z;
|
|
714
|
+
}
|
|
715
|
+
|
|
465
716
|
// src/positioning/rtk.ts
|
|
466
717
|
var L1_CODES = {
|
|
467
718
|
G: ["1C"],
|
|
@@ -822,7 +1073,13 @@ var RtkFloatEngine = class {
|
|
|
822
1073
|
maxGapMs: opts.maxGapMs ?? 1e4,
|
|
823
1074
|
codeGateM: opts.codeGateM ?? 30,
|
|
824
1075
|
slipGateM: opts.slipGateM ?? 5,
|
|
825
|
-
updateIterations: opts.updateIterations ?? 2
|
|
1076
|
+
updateIterations: opts.updateIterations ?? 2,
|
|
1077
|
+
ambiguityResolution: opts.ambiguityResolution ?? "off",
|
|
1078
|
+
ratioThreshold: opts.ratioThreshold ?? 3,
|
|
1079
|
+
arElevationMaskDeg: opts.arElevationMaskDeg ?? 0,
|
|
1080
|
+
glonassAr: opts.glonassAr ?? false,
|
|
1081
|
+
partialFixing: opts.partialFixing ?? true,
|
|
1082
|
+
minFixAmbiguities: opts.minFixAmbiguities ?? 4
|
|
826
1083
|
};
|
|
827
1084
|
}
|
|
828
1085
|
/** Clear all filter state (position, ambiguities, lock history). */
|
|
@@ -880,6 +1137,56 @@ var RtkFloatEngine = class {
|
|
|
880
1137
|
const entry = this.amb[newRefIdx];
|
|
881
1138
|
entry.prn = oldRef;
|
|
882
1139
|
}
|
|
1140
|
+
/**
|
|
1141
|
+
* Try to fix the ambiguity subset `idxs` (indices into `this.amb`):
|
|
1142
|
+
* extract the float subvector b and covariance Q_b from the filter,
|
|
1143
|
+
* run MLAMBDA and, without touching the filter state, condition the
|
|
1144
|
+
* position on the best integer candidate,
|
|
1145
|
+
* xa = x − P_xb·Q_b⁻¹·(b − ǎ)
|
|
1146
|
+
* (RTKLIB rtkpos.c `resamb_LAMBDA`). Returns null when Q_b is not
|
|
1147
|
+
* positive definite / invertible or the search fails; ratio
|
|
1148
|
+
* validation is the caller's job.
|
|
1149
|
+
*/
|
|
1150
|
+
tryFix(idxs) {
|
|
1151
|
+
const k = idxs.length;
|
|
1152
|
+
const b = new Float64Array(k);
|
|
1153
|
+
const Qb = new Float64Array(k * k);
|
|
1154
|
+
const QbRows = [];
|
|
1155
|
+
for (let i = 0; i < k; i++) {
|
|
1156
|
+
const si = 3 + idxs[i];
|
|
1157
|
+
b[i] = this.x[si];
|
|
1158
|
+
const row = [];
|
|
1159
|
+
for (let j = 0; j < k; j++) {
|
|
1160
|
+
const sj = 3 + idxs[j];
|
|
1161
|
+
const q = (this.P[si][sj] + this.P[sj][si]) / 2;
|
|
1162
|
+
Qb[i + j * k] = q;
|
|
1163
|
+
row.push(q);
|
|
1164
|
+
}
|
|
1165
|
+
QbRows.push(row);
|
|
1166
|
+
}
|
|
1167
|
+
const res = lambdaSearch(b, Qb, k, 2);
|
|
1168
|
+
if (!res) return null;
|
|
1169
|
+
const best = res.candidates[0];
|
|
1170
|
+
const QbInv = matInv(QbRows);
|
|
1171
|
+
if (!QbInv) return null;
|
|
1172
|
+
const db = [];
|
|
1173
|
+
for (let i = 0; i < k; i++) db.push(b[i] - best[i]);
|
|
1174
|
+
const position = [
|
|
1175
|
+
this.x[0],
|
|
1176
|
+
this.x[1],
|
|
1177
|
+
this.x[2]
|
|
1178
|
+
];
|
|
1179
|
+
for (let r = 0; r < 3; r++) {
|
|
1180
|
+
let dx = 0;
|
|
1181
|
+
for (let i = 0; i < k; i++) {
|
|
1182
|
+
let yi = 0;
|
|
1183
|
+
for (let j = 0; j < k; j++) yi += QbInv[i][j] * db[j];
|
|
1184
|
+
dx += this.P[r][3 + idxs[i]] * yi;
|
|
1185
|
+
}
|
|
1186
|
+
position[r] -= dx;
|
|
1187
|
+
}
|
|
1188
|
+
return { ratio: res.ratio, position, intAmb: [...best] };
|
|
1189
|
+
}
|
|
883
1190
|
/**
|
|
884
1191
|
* Process one synchronized epoch (same nominal `timeMs` for both
|
|
885
1192
|
* receivers). Returns null until a first position can be
|
|
@@ -1130,6 +1437,47 @@ var RtkFloatEngine = class {
|
|
|
1130
1437
|
Pnew[j][i] = s;
|
|
1131
1438
|
}
|
|
1132
1439
|
this.P = Pnew;
|
|
1440
|
+
let status = rows.some(
|
|
1441
|
+
(r) => r.kind === "phase"
|
|
1442
|
+
) ? "float" : "dgnss";
|
|
1443
|
+
let ratio;
|
|
1444
|
+
let nFixed;
|
|
1445
|
+
let fixedPos = null;
|
|
1446
|
+
let fixedAmbiguities;
|
|
1447
|
+
if (o.ambiguityResolution === "instant") {
|
|
1448
|
+
const cands = [];
|
|
1449
|
+
for (const row of rows) {
|
|
1450
|
+
if (row.kind !== "phase") continue;
|
|
1451
|
+
if (row.g.prn[0] === "R" && !o.glonassAr) continue;
|
|
1452
|
+
if (row.g.elB < o.arElevationMaskDeg * Math.PI / 180) continue;
|
|
1453
|
+
cands.push({ idx: row.ambIdx, el: row.g.elB });
|
|
1454
|
+
}
|
|
1455
|
+
cands.sort((a, b) => b.el - a.el);
|
|
1456
|
+
const floor = Math.max(
|
|
1457
|
+
o.minFixAmbiguities,
|
|
1458
|
+
Math.ceil(cands.length / 2),
|
|
1459
|
+
1
|
|
1460
|
+
);
|
|
1461
|
+
while (cands.length >= floor) {
|
|
1462
|
+
const fix = this.tryFix(cands.map((c) => c.idx));
|
|
1463
|
+
if (!fix) break;
|
|
1464
|
+
const capped = Math.min(fix.ratio, 999.9);
|
|
1465
|
+
ratio ??= capped;
|
|
1466
|
+
if (fix.ratio >= o.ratioThreshold) {
|
|
1467
|
+
ratio = capped;
|
|
1468
|
+
status = "fixed";
|
|
1469
|
+
nFixed = cands.length;
|
|
1470
|
+
fixedPos = fix.position;
|
|
1471
|
+
fixedAmbiguities = {};
|
|
1472
|
+
cands.forEach((c, i) => {
|
|
1473
|
+
fixedAmbiguities[this.amb[c.idx].prn] = fix.intAmb[i];
|
|
1474
|
+
});
|
|
1475
|
+
break;
|
|
1476
|
+
}
|
|
1477
|
+
if (!o.partialFixing) break;
|
|
1478
|
+
cands.pop();
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1133
1481
|
for (const g of geom) {
|
|
1134
1482
|
if (g.cpR === null || g.cpB === null) continue;
|
|
1135
1483
|
this.track.set(g.prn, { lockR: g.lockR, lockB: g.lockB, lastMs: timeMs });
|
|
@@ -1143,14 +1491,22 @@ var RtkFloatEngine = class {
|
|
|
1143
1491
|
const nSats = new Set(rows.flatMap((r) => [r.g.prn, r.ref.prn])).size;
|
|
1144
1492
|
return {
|
|
1145
1493
|
timeMs,
|
|
1146
|
-
position: [this.x[0], this.x[1], this.x[2]],
|
|
1494
|
+
position: fixedPos ?? [this.x[0], this.x[1], this.x[2]],
|
|
1147
1495
|
floatBaseline: [
|
|
1148
1496
|
this.x[0] - this.basePos[0],
|
|
1149
1497
|
this.x[1] - this.basePos[1],
|
|
1150
1498
|
this.x[2] - this.basePos[2]
|
|
1151
1499
|
],
|
|
1500
|
+
status,
|
|
1152
1501
|
nSats,
|
|
1153
|
-
ratio
|
|
1502
|
+
ratio,
|
|
1503
|
+
nFixed,
|
|
1504
|
+
fixedBaseline: fixedPos ? [
|
|
1505
|
+
fixedPos[0] - this.basePos[0],
|
|
1506
|
+
fixedPos[1] - this.basePos[1],
|
|
1507
|
+
fixedPos[2] - this.basePos[2]
|
|
1508
|
+
] : void 0,
|
|
1509
|
+
fixedAmbiguities,
|
|
1154
1510
|
sigmas: [
|
|
1155
1511
|
Math.sqrt(Math.max(this.P[0][0], 0)),
|
|
1156
1512
|
Math.sqrt(Math.max(this.P[1][1], 0)),
|
|
@@ -1197,10 +1553,17 @@ var PRIMARY_FREQ_HZ = {
|
|
|
1197
1553
|
C: 1561098e3,
|
|
1198
1554
|
R: 1602e6
|
|
1199
1555
|
};
|
|
1200
|
-
var
|
|
1201
|
-
function tropoDelay2(elevationRad) {
|
|
1202
|
-
|
|
1203
|
-
|
|
1556
|
+
var F_L12 = 157542e4;
|
|
1557
|
+
function tropoDelay2(elevationRad, latRad, heightM) {
|
|
1558
|
+
if (elevationRad <= 0) return 0;
|
|
1559
|
+
const h = heightM < 0 ? 0 : heightM > 1e4 ? 1e4 : heightM;
|
|
1560
|
+
const humi = 0.7;
|
|
1561
|
+
const pres = 1013.25 * Math.pow(1 - 22557e-9 * h, 5.2568);
|
|
1562
|
+
const temp = 15 - 65e-4 * h + 273.16;
|
|
1563
|
+
const e = 6.108 * humi * Math.exp((17.15 * temp - 4684) / (temp - 38.45));
|
|
1564
|
+
const zhd = 22768e-7 * pres / (1 - 266e-5 * Math.cos(2 * latRad) - 28e-5 * (h / 1e3));
|
|
1565
|
+
const zwd = 2277e-6 * (1255 / temp + 0.05) * e;
|
|
1566
|
+
return (zhd + zwd) / Math.sin(elevationRad);
|
|
1204
1567
|
}
|
|
1205
1568
|
function sagnac2(pos, travelTimeS) {
|
|
1206
1569
|
const theta = OMEGA_E * travelTimeS;
|
|
@@ -1233,7 +1596,8 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
1233
1596
|
maxIterations = 15,
|
|
1234
1597
|
convergenceM = 1e-4,
|
|
1235
1598
|
tgd = true,
|
|
1236
|
-
iono
|
|
1599
|
+
iono,
|
|
1600
|
+
gim
|
|
1237
1601
|
} = opts;
|
|
1238
1602
|
const gpsTow = (timeMs - GPS_EPOCH_MS_SPP) / 1e3 % 604800;
|
|
1239
1603
|
const all = [...pseudoranges.keys()].filter((p) => ephemerides.has(p));
|
|
@@ -1260,7 +1624,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
1260
1624
|
let rows = 0;
|
|
1261
1625
|
for (const k of Object.keys(residuals2)) delete residuals2[k];
|
|
1262
1626
|
const positionSaneIter = x2 * x2 + y2 * y2 + z2 * z2 > 1e12;
|
|
1263
|
-
const [rxLat, rxLon] = positionSaneIter ? ecefToGeodetic(x2, y2, z2) : [0, 0];
|
|
1627
|
+
const [rxLat, rxLon, rxHgt] = positionSaneIter ? ecefToGeodetic(x2, y2, z2) : [0, 0, 0];
|
|
1264
1628
|
for (const prn of prns) {
|
|
1265
1629
|
const psr = pseudoranges.get(prn);
|
|
1266
1630
|
const eph = ephemerides.get(prn);
|
|
@@ -1290,11 +1654,18 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
1290
1654
|
const sinEl = Math.max(Math.sin(elev), 0.1);
|
|
1291
1655
|
weight = sinEl * sinEl;
|
|
1292
1656
|
}
|
|
1293
|
-
const tropo = troposphere && positionSane ? tropoDelay2(elev) : 0;
|
|
1657
|
+
const tropo = troposphere && positionSane ? tropoDelay2(elev, rxLat, rxHgt) : 0;
|
|
1294
1658
|
let ionoM = 0;
|
|
1295
|
-
if (iono && positionSane) {
|
|
1296
|
-
|
|
1297
|
-
|
|
1659
|
+
if ((gim || iono) && positionSane) {
|
|
1660
|
+
let l1M = null;
|
|
1661
|
+
if (gim) l1M = gimSlantIonoDelayL1(gim, rxLat, rxLon, azim, elev, timeMs);
|
|
1662
|
+
if (l1M === null && iono) {
|
|
1663
|
+
l1M = C_LIGHT * klobucharDelay(iono, rxLat, rxLon, azim, elev, gpsTow);
|
|
1664
|
+
}
|
|
1665
|
+
if (l1M !== null) {
|
|
1666
|
+
const f = PRIMARY_FREQ_HZ[sys] ?? F_L12;
|
|
1667
|
+
ionoM = l1M * (F_L12 / f * (F_L12 / f));
|
|
1668
|
+
}
|
|
1298
1669
|
}
|
|
1299
1670
|
const predicted = rho + clk - C_LIGHT * dts + tropo + ionoM;
|
|
1300
1671
|
const v = psr - predicted;
|
|
@@ -1375,9 +1746,14 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
1375
1746
|
}
|
|
1376
1747
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1377
1748
|
0 && (module.exports = {
|
|
1749
|
+
IONO_L1_M_PER_TECU,
|
|
1378
1750
|
RtkFloatEngine,
|
|
1751
|
+
gimSlantIonoDelayL1,
|
|
1752
|
+
gimVerticalTec,
|
|
1379
1753
|
ionoFree,
|
|
1380
1754
|
klobucharDelay,
|
|
1755
|
+
lambdaReduction,
|
|
1756
|
+
lambdaSearch,
|
|
1381
1757
|
satClockCorrection,
|
|
1382
1758
|
solveDgnss,
|
|
1383
1759
|
solveSpp,
|