gnss-js 1.22.0 → 1.23.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 +966 -0
- package/dist/{chunk-JNFV5BYB.js → chunk-MHGNKSSH.js} +2 -3
- package/dist/index.cjs +712 -7
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +9 -3
- package/dist/orbit.cjs +2 -3
- package/dist/orbit.js +1 -1
- package/dist/positioning.cjs +734 -9
- package/dist/positioning.d.cts +238 -1
- package/dist/positioning.d.ts +238 -1
- package/dist/positioning.js +10 -4
- package/package.json +1 -1
- package/dist/chunk-B5LU4746.js +0 -262
package/dist/positioning.cjs
CHANGED
|
@@ -20,10 +20,13 @@ 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
|
+
RtkFloatEngine: () => RtkFloatEngine,
|
|
23
24
|
ionoFree: () => ionoFree,
|
|
24
25
|
klobucharDelay: () => klobucharDelay,
|
|
25
26
|
satClockCorrection: () => satClockCorrection,
|
|
26
|
-
|
|
27
|
+
solveDgnss: () => solveDgnss,
|
|
28
|
+
solveSpp: () => solveSpp,
|
|
29
|
+
toRtkEpoch: () => toRtkEpoch
|
|
27
30
|
});
|
|
28
31
|
module.exports = __toCommonJS(positioning_exports);
|
|
29
32
|
|
|
@@ -155,8 +158,7 @@ var GM_GPS = 3986005e8;
|
|
|
155
158
|
var GM_GAL = 3986004418e5;
|
|
156
159
|
var GM_BDS = 3986004418e5;
|
|
157
160
|
var GM_GLO = 39860044e7;
|
|
158
|
-
var
|
|
159
|
-
var BDS_GEO_MIN_SEMIMAJOR_AXIS_M = 4e7;
|
|
161
|
+
var BDS_GEO_PRNS = /* @__PURE__ */ new Set([1, 2, 3, 4, 5, 59, 60, 61, 62, 63]);
|
|
160
162
|
var AE_GLO = 6378136;
|
|
161
163
|
var J2_GLO = 108263e-8;
|
|
162
164
|
var TWO_PI = 2 * Math.PI;
|
|
@@ -203,7 +205,7 @@ function keplerPosition(eph, t) {
|
|
|
203
205
|
const yp = rk * Math.sin(uk);
|
|
204
206
|
const xpDot = drkDot * Math.cos(uk) - rk * ukDot * Math.sin(uk);
|
|
205
207
|
const ypDot = drkDot * Math.sin(uk) + rk * ukDot * Math.cos(uk);
|
|
206
|
-
const isBdsGeo = eph.system === "C" &&
|
|
208
|
+
const isBdsGeo = eph.system === "C" && BDS_GEO_PRNS.has(Number(eph.prn.slice(1)));
|
|
207
209
|
if (isBdsGeo) {
|
|
208
210
|
const omegak2 = eph.omega0 + eph.omegaDot * tk - OMEGA_E * eph.toe;
|
|
209
211
|
const cosO2 = Math.cos(omegak2);
|
|
@@ -393,6 +395,12 @@ function invert4x4(m) {
|
|
|
393
395
|
}
|
|
394
396
|
return result;
|
|
395
397
|
}
|
|
398
|
+
function selectEphemeris(ephemerides, prn, timeMs) {
|
|
399
|
+
return selectBest(
|
|
400
|
+
ephemerides.filter((e) => e.prn === prn),
|
|
401
|
+
timeMs
|
|
402
|
+
);
|
|
403
|
+
}
|
|
396
404
|
function computeSatPosition(eph, timeMs) {
|
|
397
405
|
if (eph.system === "R" || eph.system === "S") {
|
|
398
406
|
const leapMs = getGpsLeap(new Date(timeMs)) * 1e3;
|
|
@@ -404,6 +412,20 @@ function computeSatPosition(eph, timeMs) {
|
|
|
404
412
|
if (eph.system === "C") tow = (tow - 14 + 604800) % 604800;
|
|
405
413
|
return keplerPosition(eph, tow);
|
|
406
414
|
}
|
|
415
|
+
function selectBest(ephs, timeMs) {
|
|
416
|
+
let best = null;
|
|
417
|
+
let bestDt = Infinity;
|
|
418
|
+
for (const eph of ephs) {
|
|
419
|
+
const dt = Math.abs(timeMs - eph.tocDate.getTime());
|
|
420
|
+
const maxAge = eph.system === "R" || eph.system === "S" ? 18e5 : 4 * 36e5;
|
|
421
|
+
if (dt > maxAge) continue;
|
|
422
|
+
if (dt < bestDt) {
|
|
423
|
+
bestDt = dt;
|
|
424
|
+
best = eph;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return best;
|
|
428
|
+
}
|
|
407
429
|
var GPS_EPOCH_MS = START_GPS_TIME.getTime();
|
|
408
430
|
var MS_PER_WEEK = 7 * 864e5;
|
|
409
431
|
var BDS_EPOCH_MS = START_BDS_TIME.getTime();
|
|
@@ -440,6 +462,706 @@ function klobucharDelay(coeffs, latRad, lonRad, azRad, elRad, gpsTowSec) {
|
|
|
440
462
|
return F * (5e-9 + amp * (1 - x2 / 2 + x2 * x2 / 24));
|
|
441
463
|
}
|
|
442
464
|
|
|
465
|
+
// src/positioning/rtk.ts
|
|
466
|
+
var L1_CODES = {
|
|
467
|
+
G: ["1C"],
|
|
468
|
+
E: ["1C"],
|
|
469
|
+
R: ["1C"],
|
|
470
|
+
J: ["1C"],
|
|
471
|
+
C: ["2I", "1P"]
|
|
472
|
+
// B1I first (classic B1), then B1C
|
|
473
|
+
};
|
|
474
|
+
function toRtkEpoch(meas) {
|
|
475
|
+
const out = /* @__PURE__ */ new Map();
|
|
476
|
+
const rank = /* @__PURE__ */ new Map();
|
|
477
|
+
for (const m of meas) {
|
|
478
|
+
const prefs = L1_CODES[m.prn[0]];
|
|
479
|
+
if (!prefs || m.pr === null || !Number.isFinite(m.pr)) continue;
|
|
480
|
+
const r = prefs.indexOf(m.code);
|
|
481
|
+
if (r < 0) continue;
|
|
482
|
+
const prev = rank.get(m.prn);
|
|
483
|
+
if (prev !== void 0 && prev <= r) continue;
|
|
484
|
+
rank.set(m.prn, r);
|
|
485
|
+
out.set(m.prn, {
|
|
486
|
+
code: m.code,
|
|
487
|
+
pr: m.pr,
|
|
488
|
+
cp: m.cp ?? null,
|
|
489
|
+
lockTimeMs: m.lockTimeS !== void 0 ? Math.round(m.lockTimeS * 1e3) : void 0,
|
|
490
|
+
gloChannel: m.gloChannel ?? null
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
return out;
|
|
494
|
+
}
|
|
495
|
+
function carrierFreqHz(sys, code, gloChannel) {
|
|
496
|
+
const band = code[0];
|
|
497
|
+
switch (sys) {
|
|
498
|
+
case "G":
|
|
499
|
+
case "J":
|
|
500
|
+
return band === "1" ? 157542e4 : band === "2" ? 12276e5 : 117645e4;
|
|
501
|
+
case "E":
|
|
502
|
+
return band === "1" ? 157542e4 : band === "5" ? 117645e4 : band === "7" ? 120714e4 : band === "8" ? 1191795e3 : 127875e4;
|
|
503
|
+
case "C":
|
|
504
|
+
return band === "1" ? 157542e4 : band === "2" ? 1561098e3 : band === "5" ? 117645e4 : band === "7" ? 120714e4 : 126852e4;
|
|
505
|
+
case "R": {
|
|
506
|
+
if (gloChannel === null) return 0;
|
|
507
|
+
if (band === "1") return 1602e6 + gloChannel * 562500;
|
|
508
|
+
if (band === "2") return 1246e6 + gloChannel * 437500;
|
|
509
|
+
return 1202025e3;
|
|
510
|
+
}
|
|
511
|
+
default:
|
|
512
|
+
return 0;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
function sagnac(pos, travelTimeS) {
|
|
516
|
+
const theta = OMEGA_E * travelTimeS;
|
|
517
|
+
const c = Math.cos(theta);
|
|
518
|
+
const s = Math.sin(theta);
|
|
519
|
+
return [pos.x * c + pos.y * s, -pos.x * s + pos.y * c, pos.z];
|
|
520
|
+
}
|
|
521
|
+
function tropoDelay(elevationRad) {
|
|
522
|
+
const sinEl = Math.sin(elevationRad);
|
|
523
|
+
return 2.47 / (sinEl + 0.0121);
|
|
524
|
+
}
|
|
525
|
+
function resolveEphemeris(src, prn, timeMs) {
|
|
526
|
+
if (Array.isArray(src))
|
|
527
|
+
return selectEphemeris(src, prn, timeMs);
|
|
528
|
+
return src.get(prn) ?? null;
|
|
529
|
+
}
|
|
530
|
+
function buildGeometry(rover, base, basePos, ephemerides, timeMs, maskRad, troposphere) {
|
|
531
|
+
const out = [];
|
|
532
|
+
for (const [prn, mR] of rover) {
|
|
533
|
+
const sys = prn[0];
|
|
534
|
+
if (!"GERCJ".includes(sys)) continue;
|
|
535
|
+
const mB = base.get(prn);
|
|
536
|
+
if (!mB || mB.code !== mR.code) continue;
|
|
537
|
+
if (mR.pr === null || mB.pr === null || !Number.isFinite(mR.pr) || !Number.isFinite(mB.pr))
|
|
538
|
+
continue;
|
|
539
|
+
const eph = resolveEphemeris(ephemerides, prn, timeMs);
|
|
540
|
+
if (!eph) continue;
|
|
541
|
+
const satAt = (pr) => {
|
|
542
|
+
const tTx = timeMs - pr / C_LIGHT * 1e3;
|
|
543
|
+
const dts = satClockCorrection(eph, tTx);
|
|
544
|
+
const sat = computeSatPosition(eph, tTx - dts * 1e3);
|
|
545
|
+
return Number.isFinite(sat.x) ? sat : null;
|
|
546
|
+
};
|
|
547
|
+
const satB = satAt(mB.pr);
|
|
548
|
+
const satR = satAt(mR.pr);
|
|
549
|
+
if (!satB || !satR) continue;
|
|
550
|
+
const travelB = Math.hypot(
|
|
551
|
+
satB.x - basePos[0],
|
|
552
|
+
satB.y - basePos[1],
|
|
553
|
+
satB.z - basePos[2]
|
|
554
|
+
) / C_LIGHT;
|
|
555
|
+
const [bx, by, bz] = sagnac(satB, travelB);
|
|
556
|
+
const rhoB = Math.hypot(bx - basePos[0], by - basePos[1], bz - basePos[2]);
|
|
557
|
+
const elB = ecefToAzEl(basePos[0], basePos[1], basePos[2], bx, by, bz).el;
|
|
558
|
+
if (elB < maskRad) continue;
|
|
559
|
+
const gloK = sys === "R" ? mR.gloChannel ?? mB.gloChannel ?? eph.freqNum ?? null : null;
|
|
560
|
+
const freq = carrierFreqHz(sys, mR.code, gloK);
|
|
561
|
+
out.push({
|
|
562
|
+
prn,
|
|
563
|
+
group: sys + mR.code,
|
|
564
|
+
lambda: freq > 0 ? C_LIGHT / freq : 0,
|
|
565
|
+
satR,
|
|
566
|
+
rhoB,
|
|
567
|
+
elB,
|
|
568
|
+
tropoB: troposphere ? tropoDelay(elB) : 0,
|
|
569
|
+
prR: mR.pr,
|
|
570
|
+
prB: mB.pr,
|
|
571
|
+
cpR: mR.cp ?? null,
|
|
572
|
+
cpB: mB.cp ?? null,
|
|
573
|
+
lockR: mR.lockTimeMs,
|
|
574
|
+
lockB: mB.lockTimeMs
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
return out;
|
|
578
|
+
}
|
|
579
|
+
function roverTerms(g, x, y, z, troposphere) {
|
|
580
|
+
const travel = Math.hypot(g.satR.x - x, g.satR.y - y, g.satR.z - z) / C_LIGHT;
|
|
581
|
+
const [sx, sy, sz] = sagnac(g.satR, travel);
|
|
582
|
+
const rho = Math.hypot(sx - x, sy - y, sz - z);
|
|
583
|
+
const u = [
|
|
584
|
+
(x - sx) / rho,
|
|
585
|
+
(y - sy) / rho,
|
|
586
|
+
(z - sz) / rho
|
|
587
|
+
];
|
|
588
|
+
let dTropo = 0;
|
|
589
|
+
if (troposphere) {
|
|
590
|
+
const elR = ecefToAzEl(x, y, z, sx, sy, sz).el;
|
|
591
|
+
dTropo = tropoDelay(Math.max(elR, 0.05)) - g.tropoB;
|
|
592
|
+
}
|
|
593
|
+
return { rho, u, dTropo };
|
|
594
|
+
}
|
|
595
|
+
function sdVariance(sigmaM, elRad) {
|
|
596
|
+
const sinEl = Math.max(Math.sin(elRad), 0.05);
|
|
597
|
+
return 2 * sigmaM * sigmaM * (1 + 1 / (sinEl * sinEl));
|
|
598
|
+
}
|
|
599
|
+
function zeros(n, m) {
|
|
600
|
+
return Array.from({ length: n }, () => new Array(m).fill(0));
|
|
601
|
+
}
|
|
602
|
+
function matInv(A) {
|
|
603
|
+
const n = A.length;
|
|
604
|
+
const M = A.map((row, i) => {
|
|
605
|
+
const r = [...row, ...new Array(n).fill(0)];
|
|
606
|
+
r[n + i] = 1;
|
|
607
|
+
return r;
|
|
608
|
+
});
|
|
609
|
+
for (let col = 0; col < n; col++) {
|
|
610
|
+
let pivot = col;
|
|
611
|
+
for (let r = col + 1; r < n; r++) {
|
|
612
|
+
if (Math.abs(M[r][col]) > Math.abs(M[pivot][col])) pivot = r;
|
|
613
|
+
}
|
|
614
|
+
if (Math.abs(M[pivot][col]) < 1e-13) return null;
|
|
615
|
+
[M[col], M[pivot]] = [M[pivot], M[col]];
|
|
616
|
+
const d = M[col][col];
|
|
617
|
+
for (let c = 0; c < 2 * n; c++) M[col][c] /= d;
|
|
618
|
+
for (let r = 0; r < n; r++) {
|
|
619
|
+
if (r === col) continue;
|
|
620
|
+
const f = M[r][col];
|
|
621
|
+
if (f === 0) continue;
|
|
622
|
+
for (let c = 0; c < 2 * n; c++) M[r][c] -= f * M[col][c];
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return M.map((row) => row.slice(n));
|
|
626
|
+
}
|
|
627
|
+
function matMul(A, B) {
|
|
628
|
+
const n = A.length;
|
|
629
|
+
const k = B.length;
|
|
630
|
+
const m = B[0]?.length ?? 0;
|
|
631
|
+
const C = zeros(n, m);
|
|
632
|
+
for (let i = 0; i < n; i++) {
|
|
633
|
+
for (let l = 0; l < k; l++) {
|
|
634
|
+
const a = A[i][l];
|
|
635
|
+
if (a === 0) continue;
|
|
636
|
+
for (let j = 0; j < m; j++) C[i][j] += a * B[l][j];
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return C;
|
|
640
|
+
}
|
|
641
|
+
function transpose(A) {
|
|
642
|
+
const n = A.length;
|
|
643
|
+
const m = A[0]?.length ?? 0;
|
|
644
|
+
const T = zeros(m, n);
|
|
645
|
+
for (let i = 0; i < n; i++) for (let j = 0; j < m; j++) T[j][i] = A[i][j];
|
|
646
|
+
return T;
|
|
647
|
+
}
|
|
648
|
+
function groupEntries(geom) {
|
|
649
|
+
const groups = /* @__PURE__ */ new Map();
|
|
650
|
+
for (const g of geom) {
|
|
651
|
+
const list = groups.get(g.group);
|
|
652
|
+
if (list) list.push(g);
|
|
653
|
+
else groups.set(g.group, [g]);
|
|
654
|
+
}
|
|
655
|
+
return groups;
|
|
656
|
+
}
|
|
657
|
+
function ddCovariance(rows, sigmaCode, sigmaPhase) {
|
|
658
|
+
const n = rows.length;
|
|
659
|
+
const R = zeros(n, n);
|
|
660
|
+
const sd = (r, g) => sdVariance(r.kind === "code" ? sigmaCode : sigmaPhase, g.elB);
|
|
661
|
+
for (let i = 0; i < n; i++) {
|
|
662
|
+
const ri = rows[i];
|
|
663
|
+
R[i][i] = sd(ri, ri.g) + sd(ri, ri.ref);
|
|
664
|
+
for (let j = i + 1; j < n; j++) {
|
|
665
|
+
const rj = rows[j];
|
|
666
|
+
if (ri.ref.prn === rj.ref.prn && ri.kind === rj.kind && ri.g.group === rj.g.group) {
|
|
667
|
+
R[i][j] = R[j][i] = sd(ri, ri.ref);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
return R;
|
|
672
|
+
}
|
|
673
|
+
function solveDgnss(rover, base, basePos, ephemerides, timeMs, opts = {}) {
|
|
674
|
+
const {
|
|
675
|
+
elevationMaskDeg = 10,
|
|
676
|
+
troposphere = true,
|
|
677
|
+
maxIterations = 15,
|
|
678
|
+
convergenceM = 1e-4,
|
|
679
|
+
codeSigmaM = 0.3,
|
|
680
|
+
rejectThresholdM = 20,
|
|
681
|
+
initialPosition
|
|
682
|
+
} = opts;
|
|
683
|
+
let geom = buildGeometry(
|
|
684
|
+
rover,
|
|
685
|
+
base,
|
|
686
|
+
basePos,
|
|
687
|
+
ephemerides,
|
|
688
|
+
timeMs,
|
|
689
|
+
elevationMaskDeg * Math.PI / 180,
|
|
690
|
+
troposphere
|
|
691
|
+
);
|
|
692
|
+
const rejected = [];
|
|
693
|
+
for (; ; ) {
|
|
694
|
+
const groups = groupEntries(geom);
|
|
695
|
+
const rows = [];
|
|
696
|
+
const refSatellites = {};
|
|
697
|
+
for (const [group, list] of groups) {
|
|
698
|
+
if (list.length < 2) continue;
|
|
699
|
+
const ref = list.reduce((a, b) => b.elB > a.elB ? b : a);
|
|
700
|
+
refSatellites[group] = ref.prn;
|
|
701
|
+
for (const g of list) {
|
|
702
|
+
if (g === ref) continue;
|
|
703
|
+
rows.push({
|
|
704
|
+
g,
|
|
705
|
+
ref,
|
|
706
|
+
kind: "code",
|
|
707
|
+
z: g.prR - g.prB - (ref.prR - ref.prB)
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
if (rows.length < 3) return null;
|
|
712
|
+
const W = matInv(ddCovariance(rows, codeSigmaM, codeSigmaM));
|
|
713
|
+
if (!W) return null;
|
|
714
|
+
let [x, y, z] = initialPosition ?? basePos;
|
|
715
|
+
let iterations = 0;
|
|
716
|
+
let converged = false;
|
|
717
|
+
const residuals = {};
|
|
718
|
+
let cov = null;
|
|
719
|
+
for (let iter = 0; iter < maxIterations; iter++) {
|
|
720
|
+
iterations = iter + 1;
|
|
721
|
+
const H = [];
|
|
722
|
+
const v = [];
|
|
723
|
+
const terms = /* @__PURE__ */ new Map();
|
|
724
|
+
const termOf = (g) => {
|
|
725
|
+
let t = terms.get(g.prn);
|
|
726
|
+
if (!t) {
|
|
727
|
+
t = roverTerms(g, x, y, z, troposphere);
|
|
728
|
+
terms.set(g.prn, t);
|
|
729
|
+
}
|
|
730
|
+
return t;
|
|
731
|
+
};
|
|
732
|
+
for (const row of rows) {
|
|
733
|
+
const ts = termOf(row.g);
|
|
734
|
+
const tr = termOf(row.ref);
|
|
735
|
+
const pred = ts.rho - row.g.rhoB + ts.dTropo - (tr.rho - row.ref.rhoB + tr.dTropo);
|
|
736
|
+
v.push(row.z - pred);
|
|
737
|
+
H.push([ts.u[0] - tr.u[0], ts.u[1] - tr.u[1], ts.u[2] - tr.u[2]]);
|
|
738
|
+
}
|
|
739
|
+
const Ht = transpose(H);
|
|
740
|
+
const HtW = matMul(Ht, W);
|
|
741
|
+
const N = matMul(HtW, H);
|
|
742
|
+
const b = matMul(
|
|
743
|
+
HtW,
|
|
744
|
+
v.map((s) => [s])
|
|
745
|
+
);
|
|
746
|
+
const Ninv = matInv(N);
|
|
747
|
+
if (!Ninv) return null;
|
|
748
|
+
const dx = matMul(
|
|
749
|
+
Ninv,
|
|
750
|
+
b.map((r) => [r[0]])
|
|
751
|
+
);
|
|
752
|
+
x += dx[0][0];
|
|
753
|
+
y += dx[1][0];
|
|
754
|
+
z += dx[2][0];
|
|
755
|
+
cov = Ninv;
|
|
756
|
+
rows.forEach((row, i) => {
|
|
757
|
+
residuals[row.g.prn] = v[i] - (H[i][0] * dx[0][0] + H[i][1] * dx[1][0] + H[i][2] * dx[2][0]);
|
|
758
|
+
});
|
|
759
|
+
if (Math.hypot(dx[0][0], dx[1][0], dx[2][0]) < convergenceM) {
|
|
760
|
+
converged = true;
|
|
761
|
+
break;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
let worst = null;
|
|
765
|
+
let worstAbs = rejectThresholdM;
|
|
766
|
+
for (const [prn, r] of Object.entries(residuals)) {
|
|
767
|
+
if (Math.abs(r) > worstAbs) {
|
|
768
|
+
worstAbs = Math.abs(r);
|
|
769
|
+
worst = prn;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
if (worst && geom.length > 4) {
|
|
773
|
+
rejected.push(worst);
|
|
774
|
+
geom = geom.filter((g) => g.prn !== worst);
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
777
|
+
const usedSatellites = [
|
|
778
|
+
...new Set(rows.flatMap((r) => [r.g.prn, r.ref.prn]))
|
|
779
|
+
].sort();
|
|
780
|
+
return {
|
|
781
|
+
position: [x, y, z],
|
|
782
|
+
baseline: [x - basePos[0], y - basePos[1], z - basePos[2]],
|
|
783
|
+
sigmas: cov ? [
|
|
784
|
+
Math.sqrt(Math.max(cov[0][0], 0)),
|
|
785
|
+
Math.sqrt(Math.max(cov[1][1], 0)),
|
|
786
|
+
Math.sqrt(Math.max(cov[2][2], 0))
|
|
787
|
+
] : [0, 0, 0],
|
|
788
|
+
usedSatellites,
|
|
789
|
+
refSatellites,
|
|
790
|
+
residuals,
|
|
791
|
+
rejectedSatellites: rejected,
|
|
792
|
+
nSats: usedSatellites.length,
|
|
793
|
+
iterations,
|
|
794
|
+
converged
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
var RtkFloatEngine = class {
|
|
799
|
+
basePos;
|
|
800
|
+
ephemerides;
|
|
801
|
+
o;
|
|
802
|
+
/** State vector [x, y, z, N₁…] and covariance; null before init. */
|
|
803
|
+
x = null;
|
|
804
|
+
P = [];
|
|
805
|
+
amb = [];
|
|
806
|
+
refs = /* @__PURE__ */ new Map();
|
|
807
|
+
track = /* @__PURE__ */ new Map();
|
|
808
|
+
lastMs = null;
|
|
809
|
+
constructor(basePos, ephemerides, opts = {}) {
|
|
810
|
+
this.basePos = basePos;
|
|
811
|
+
this.ephemerides = ephemerides;
|
|
812
|
+
this.o = {
|
|
813
|
+
mode: opts.mode ?? "kinematic",
|
|
814
|
+
elevationMaskDeg: opts.elevationMaskDeg ?? 10,
|
|
815
|
+
troposphere: opts.troposphere ?? true,
|
|
816
|
+
codeSigmaM: opts.codeSigmaM ?? 0.3,
|
|
817
|
+
phaseSigmaM: opts.phaseSigmaM ?? 3e-3,
|
|
818
|
+
processNoisePosM: opts.processNoisePosM ?? 0,
|
|
819
|
+
kinematicSigmaM: opts.kinematicSigmaM ?? 30,
|
|
820
|
+
ambProcessNoiseCycles: opts.ambProcessNoiseCycles ?? 1e-4,
|
|
821
|
+
ambInitSigmaCycles: opts.ambInitSigmaCycles ?? 30,
|
|
822
|
+
maxGapMs: opts.maxGapMs ?? 1e4,
|
|
823
|
+
codeGateM: opts.codeGateM ?? 30,
|
|
824
|
+
slipGateM: opts.slipGateM ?? 5,
|
|
825
|
+
updateIterations: opts.updateIterations ?? 2
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
/** Clear all filter state (position, ambiguities, lock history). */
|
|
829
|
+
reset() {
|
|
830
|
+
this.x = null;
|
|
831
|
+
this.P = [];
|
|
832
|
+
this.amb = [];
|
|
833
|
+
this.refs.clear();
|
|
834
|
+
this.track.clear();
|
|
835
|
+
this.lastMs = null;
|
|
836
|
+
}
|
|
837
|
+
ambIndex(prn) {
|
|
838
|
+
return this.amb.findIndex((a) => a.prn === prn);
|
|
839
|
+
}
|
|
840
|
+
/** Remove one ambiguity state (row/col) from x and P. */
|
|
841
|
+
dropAmb(idx) {
|
|
842
|
+
const s = 3 + idx;
|
|
843
|
+
this.amb.splice(idx, 1);
|
|
844
|
+
this.x.splice(s, 1);
|
|
845
|
+
this.P.splice(s, 1);
|
|
846
|
+
for (const row of this.P) row.splice(s, 1);
|
|
847
|
+
}
|
|
848
|
+
/** Append an ambiguity state with the given value and variance. */
|
|
849
|
+
addAmb(entry, value, variance) {
|
|
850
|
+
this.amb.push(entry);
|
|
851
|
+
this.x.push(value);
|
|
852
|
+
const n = this.x.length;
|
|
853
|
+
for (const row of this.P) row.push(0);
|
|
854
|
+
const newRow = new Array(n).fill(0);
|
|
855
|
+
newRow[n - 1] = variance;
|
|
856
|
+
this.P.push(newRow);
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* Re-map a group's DD ambiguities from the old reference r to the
|
|
860
|
+
* new reference r' (which must hold a state): N_i' = N_i − N_r' and
|
|
861
|
+
* the old reference's slot becomes N_r = −N_r'. Exact linear
|
|
862
|
+
* transform of state and covariance (P' = T P Tᵀ).
|
|
863
|
+
*/
|
|
864
|
+
retarget(group, oldRef, newRefIdx) {
|
|
865
|
+
const n = this.x.length;
|
|
866
|
+
const j = 3 + newRefIdx;
|
|
867
|
+
const T = zeros(n, n);
|
|
868
|
+
for (let i = 0; i < n; i++) T[i][i] = 1;
|
|
869
|
+
for (let k = 0; k < this.amb.length; k++) {
|
|
870
|
+
if (this.amb[k].group !== group) continue;
|
|
871
|
+
const s = 3 + k;
|
|
872
|
+
if (s === j) T[s][s] = -1;
|
|
873
|
+
else T[s][j] -= 1;
|
|
874
|
+
}
|
|
875
|
+
this.x = matMul(
|
|
876
|
+
T,
|
|
877
|
+
this.x.map((v) => [v])
|
|
878
|
+
).map((r) => r[0]);
|
|
879
|
+
this.P = matMul(matMul(T, this.P), transpose(T));
|
|
880
|
+
const entry = this.amb[newRefIdx];
|
|
881
|
+
entry.prn = oldRef;
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* Process one synchronized epoch (same nominal `timeMs` for both
|
|
885
|
+
* receivers). Returns null until a first position can be
|
|
886
|
+
* initialised (via an internal DGNSS solve) or when the epoch has
|
|
887
|
+
* fewer than 3 usable DD rows.
|
|
888
|
+
*/
|
|
889
|
+
process(rover, base, timeMs) {
|
|
890
|
+
const o = this.o;
|
|
891
|
+
const geom = buildGeometry(
|
|
892
|
+
rover,
|
|
893
|
+
base,
|
|
894
|
+
this.basePos,
|
|
895
|
+
this.ephemerides,
|
|
896
|
+
timeMs,
|
|
897
|
+
o.elevationMaskDeg * Math.PI / 180,
|
|
898
|
+
o.troposphere
|
|
899
|
+
);
|
|
900
|
+
const byPrn = new Map(geom.map((g) => [g.prn, g]));
|
|
901
|
+
const dtS = this.lastMs !== null ? (timeMs - this.lastMs) / 1e3 : 0;
|
|
902
|
+
if (this.x) {
|
|
903
|
+
for (let i = this.amb.length - 1; i >= 0; i--) {
|
|
904
|
+
const prn = this.amb[i].prn;
|
|
905
|
+
const tr = this.track.get(prn);
|
|
906
|
+
const seen = byPrn.get(prn);
|
|
907
|
+
const hasPhase = seen && seen.cpR !== null && seen.cpB !== null;
|
|
908
|
+
const staleMs = tr ? timeMs - tr.lastMs : Infinity;
|
|
909
|
+
if (!hasPhase && staleMs > o.maxGapMs) this.dropAmb(i);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
const slipped = /* @__PURE__ */ new Set();
|
|
913
|
+
for (const g of geom) {
|
|
914
|
+
if (g.cpR === null || g.cpB === null) continue;
|
|
915
|
+
const tr = this.track.get(g.prn);
|
|
916
|
+
if (!tr) continue;
|
|
917
|
+
if (timeMs - tr.lastMs > o.maxGapMs) slipped.add(g.prn);
|
|
918
|
+
else if (g.lockR !== void 0 && tr.lockR !== void 0 && g.lockR < tr.lockR || g.lockB !== void 0 && tr.lockB !== void 0 && g.lockB < tr.lockB)
|
|
919
|
+
slipped.add(g.prn);
|
|
920
|
+
}
|
|
921
|
+
if (!this.x) {
|
|
922
|
+
const dg = solveDgnss(
|
|
923
|
+
rover,
|
|
924
|
+
base,
|
|
925
|
+
this.basePos,
|
|
926
|
+
this.ephemerides,
|
|
927
|
+
timeMs,
|
|
928
|
+
{
|
|
929
|
+
elevationMaskDeg: o.elevationMaskDeg,
|
|
930
|
+
troposphere: o.troposphere,
|
|
931
|
+
codeSigmaM: o.codeSigmaM
|
|
932
|
+
}
|
|
933
|
+
);
|
|
934
|
+
if (!dg) return null;
|
|
935
|
+
this.x = [...dg.position];
|
|
936
|
+
this.P = zeros(3, 3);
|
|
937
|
+
for (let i = 0; i < 3; i++) {
|
|
938
|
+
const s = Math.max(dg.sigmas[i], 1);
|
|
939
|
+
this.P[i][i] = 25 * s * s;
|
|
940
|
+
}
|
|
941
|
+
this.amb = [];
|
|
942
|
+
} else if (o.mode === "kinematic") {
|
|
943
|
+
for (let i = 0; i < 3; i++) {
|
|
944
|
+
for (let j = 0; j < this.x.length; j++) {
|
|
945
|
+
this.P[i][j] = 0;
|
|
946
|
+
this.P[j][i] = 0;
|
|
947
|
+
}
|
|
948
|
+
this.P[i][i] = o.kinematicSigmaM * o.kinematicSigmaM;
|
|
949
|
+
}
|
|
950
|
+
} else {
|
|
951
|
+
const q = o.processNoisePosM * o.processNoisePosM * dtS;
|
|
952
|
+
for (let i = 0; i < 3; i++) this.P[i][i] += q;
|
|
953
|
+
}
|
|
954
|
+
const qAmb = o.ambProcessNoiseCycles * o.ambProcessNoiseCycles * dtS;
|
|
955
|
+
for (let k = 0; k < this.amb.length; k++) this.P[3 + k][3 + k] += qAmb;
|
|
956
|
+
const groups = groupEntries(geom);
|
|
957
|
+
const newRefs = /* @__PURE__ */ new Map();
|
|
958
|
+
for (const [group, list] of groups) {
|
|
959
|
+
if (list.length < 2) continue;
|
|
960
|
+
const phase = list.filter(
|
|
961
|
+
(g) => g.cpR !== null && g.cpB !== null && !slipped.has(g.prn)
|
|
962
|
+
);
|
|
963
|
+
const pool = phase.length >= 2 ? phase : list;
|
|
964
|
+
const prevRef = this.refs.get(group);
|
|
965
|
+
const best = pool.reduce((a, b) => b.elB > a.elB ? b : a);
|
|
966
|
+
let ref = best;
|
|
967
|
+
if (best.prn !== prevRef) {
|
|
968
|
+
const anyState = this.amb.some((a) => a.group === group);
|
|
969
|
+
if (anyState) {
|
|
970
|
+
if (this.ambIndex(best.prn) >= 0) {
|
|
971
|
+
this.retarget(group, prevRef ?? best.prn, this.ambIndex(best.prn));
|
|
972
|
+
} else if (prevRef && pool.some((g) => g.prn === prevRef)) {
|
|
973
|
+
ref = pool.find((g) => g.prn === prevRef);
|
|
974
|
+
} else {
|
|
975
|
+
for (let i = this.amb.length - 1; i >= 0; i--)
|
|
976
|
+
if (this.amb[i].group === group) this.dropAmb(i);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
newRefs.set(group, ref);
|
|
981
|
+
this.refs.set(group, ref.prn);
|
|
982
|
+
}
|
|
983
|
+
for (const group of [...this.refs.keys()])
|
|
984
|
+
if (!newRefs.has(group)) this.refs.delete(group);
|
|
985
|
+
for (const prn of slipped) {
|
|
986
|
+
const i = this.ambIndex(prn);
|
|
987
|
+
if (i >= 0) this.dropAmb(i);
|
|
988
|
+
}
|
|
989
|
+
const initAmb = (g, ref) => {
|
|
990
|
+
if (g.lambda <= 0 || ref.lambda <= 0) return;
|
|
991
|
+
const zPhi = g.lambda * (g.cpR - g.cpB) - ref.lambda * (ref.cpR - ref.cpB);
|
|
992
|
+
const zP = g.prR - g.prB - (ref.prR - ref.prB);
|
|
993
|
+
const n0 = (zPhi - zP) / g.lambda;
|
|
994
|
+
this.addAmb(
|
|
995
|
+
{ prn: g.prn, group: g.group, lambda: g.lambda },
|
|
996
|
+
n0,
|
|
997
|
+
o.ambInitSigmaCycles * o.ambInitSigmaCycles
|
|
998
|
+
);
|
|
999
|
+
};
|
|
1000
|
+
for (const [group, ref] of newRefs) {
|
|
1001
|
+
for (const g of groups.get(group)) {
|
|
1002
|
+
if (g === ref || g.cpR === null || g.cpB === null) continue;
|
|
1003
|
+
if (ref.cpR === null || ref.cpB === null) continue;
|
|
1004
|
+
const i = this.ambIndex(g.prn);
|
|
1005
|
+
if (i >= 0) {
|
|
1006
|
+
this.amb[i].lambda = g.lambda;
|
|
1007
|
+
this.amb[i].group = g.group;
|
|
1008
|
+
continue;
|
|
1009
|
+
}
|
|
1010
|
+
initAmb(g, ref);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
for (let i = this.amb.length - 1; i >= 0; i--) {
|
|
1014
|
+
const a = this.amb[i];
|
|
1015
|
+
if (newRefs.get(a.group)?.prn === a.prn) this.dropAmb(i);
|
|
1016
|
+
}
|
|
1017
|
+
let rows = [];
|
|
1018
|
+
for (const [group, ref] of newRefs) {
|
|
1019
|
+
for (const g of groups.get(group)) {
|
|
1020
|
+
if (g === ref) continue;
|
|
1021
|
+
rows.push({
|
|
1022
|
+
g,
|
|
1023
|
+
ref,
|
|
1024
|
+
kind: "code",
|
|
1025
|
+
z: g.prR - g.prB - (ref.prR - ref.prB),
|
|
1026
|
+
ambIdx: -1
|
|
1027
|
+
});
|
|
1028
|
+
const i = this.ambIndex(g.prn);
|
|
1029
|
+
if (i >= 0 && g.cpR !== null && g.cpB !== null && ref.cpR !== null && ref.cpB !== null && g.lambda > 0 && ref.lambda > 0) {
|
|
1030
|
+
rows.push({
|
|
1031
|
+
g,
|
|
1032
|
+
ref,
|
|
1033
|
+
kind: "phase",
|
|
1034
|
+
z: g.lambda * (g.cpR - g.cpB) - ref.lambda * (ref.cpR - ref.cpB),
|
|
1035
|
+
ambIdx: i
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
if (rows.length < 3) {
|
|
1041
|
+
this.lastMs = timeMs;
|
|
1042
|
+
return null;
|
|
1043
|
+
}
|
|
1044
|
+
const predict = (row, xs) => {
|
|
1045
|
+
const ts = roverTerms(row.g, xs[0], xs[1], xs[2], o.troposphere);
|
|
1046
|
+
const tr = roverTerms(row.ref, xs[0], xs[1], xs[2], o.troposphere);
|
|
1047
|
+
let pred = ts.rho - row.g.rhoB + ts.dTropo - (tr.rho - row.ref.rhoB + tr.dTropo);
|
|
1048
|
+
const h = new Array(this.x.length).fill(0);
|
|
1049
|
+
h[0] = ts.u[0] - tr.u[0];
|
|
1050
|
+
h[1] = ts.u[1] - tr.u[1];
|
|
1051
|
+
h[2] = ts.u[2] - tr.u[2];
|
|
1052
|
+
if (row.ambIdx >= 0) {
|
|
1053
|
+
pred += this.amb[row.ambIdx].lambda * this.x[3 + row.ambIdx];
|
|
1054
|
+
h[3 + row.ambIdx] = this.amb[row.ambIdx].lambda;
|
|
1055
|
+
}
|
|
1056
|
+
return { pred, h };
|
|
1057
|
+
};
|
|
1058
|
+
const dropPrns = /* @__PURE__ */ new Set();
|
|
1059
|
+
const codeInn = /* @__PURE__ */ new Map();
|
|
1060
|
+
for (const row of rows) {
|
|
1061
|
+
if (row.kind !== "code") continue;
|
|
1062
|
+
const v = row.z - predict(row, this.x).pred;
|
|
1063
|
+
codeInn.set(row.g.prn, v);
|
|
1064
|
+
if (Math.abs(v) > o.codeGateM) dropPrns.add(row.g.prn);
|
|
1065
|
+
}
|
|
1066
|
+
for (const row of rows) {
|
|
1067
|
+
if (row.kind !== "phase" || dropPrns.has(row.g.prn)) continue;
|
|
1068
|
+
const v = row.z - predict(row, this.x).pred;
|
|
1069
|
+
const vc = codeInn.get(row.g.prn) ?? 0;
|
|
1070
|
+
if (Math.abs(v - vc) > o.slipGateM) {
|
|
1071
|
+
const zP = row.g.prR - row.g.prB - (row.ref.prR - row.ref.prB);
|
|
1072
|
+
const lam = this.amb[row.ambIdx].lambda;
|
|
1073
|
+
this.x[3 + row.ambIdx] = (row.z - zP) / lam;
|
|
1074
|
+
const s = 3 + row.ambIdx;
|
|
1075
|
+
for (let j = 0; j < this.x.length; j++) {
|
|
1076
|
+
this.P[s][j] = 0;
|
|
1077
|
+
this.P[j][s] = 0;
|
|
1078
|
+
}
|
|
1079
|
+
this.P[s][s] = o.ambInitSigmaCycles * o.ambInitSigmaCycles;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
if (dropPrns.size) rows = rows.filter((r) => !dropPrns.has(r.g.prn));
|
|
1083
|
+
if (rows.length < 3) {
|
|
1084
|
+
this.lastMs = timeMs;
|
|
1085
|
+
return null;
|
|
1086
|
+
}
|
|
1087
|
+
const n = this.x.length;
|
|
1088
|
+
const R = ddCovariance(rows, o.codeSigmaM, o.phaseSigmaM);
|
|
1089
|
+
const xPrior = [...this.x];
|
|
1090
|
+
const PPrior = this.P;
|
|
1091
|
+
let xi = [...this.x];
|
|
1092
|
+
let K = [];
|
|
1093
|
+
let H = [];
|
|
1094
|
+
for (let it = 0; it < Math.max(o.updateIterations, 1); it++) {
|
|
1095
|
+
H = [];
|
|
1096
|
+
const v = [];
|
|
1097
|
+
for (const row of rows) {
|
|
1098
|
+
const { pred, h } = predict(row, xi);
|
|
1099
|
+
let corr = 0;
|
|
1100
|
+
for (let j = 0; j < n; j++) corr += h[j] * (xPrior[j] - xi[j]);
|
|
1101
|
+
v.push(row.z - pred - corr);
|
|
1102
|
+
H.push(h);
|
|
1103
|
+
}
|
|
1104
|
+
const Ht = transpose(H);
|
|
1105
|
+
const S = matMul(matMul(H, PPrior), Ht);
|
|
1106
|
+
for (let i = 0; i < rows.length; i++)
|
|
1107
|
+
for (let j = 0; j < rows.length; j++) S[i][j] += R[i][j];
|
|
1108
|
+
const Sinv = matInv(S);
|
|
1109
|
+
if (!Sinv) {
|
|
1110
|
+
this.lastMs = timeMs;
|
|
1111
|
+
return null;
|
|
1112
|
+
}
|
|
1113
|
+
K = matMul(matMul(PPrior, Ht), Sinv);
|
|
1114
|
+
const dx = matMul(
|
|
1115
|
+
K,
|
|
1116
|
+
v.map((s) => [s])
|
|
1117
|
+
);
|
|
1118
|
+
xi = xPrior.map((s, i) => s + dx[i][0]);
|
|
1119
|
+
}
|
|
1120
|
+
this.x = xi;
|
|
1121
|
+
const KH = matMul(K, H);
|
|
1122
|
+
const IKH = zeros(n, n);
|
|
1123
|
+
for (let i = 0; i < n; i++)
|
|
1124
|
+
for (let j = 0; j < n; j++) IKH[i][j] = (i === j ? 1 : 0) - KH[i][j];
|
|
1125
|
+
const Pnew = matMul(IKH, PPrior);
|
|
1126
|
+
for (let i = 0; i < n; i++)
|
|
1127
|
+
for (let j = i; j < n; j++) {
|
|
1128
|
+
const s = (Pnew[i][j] + Pnew[j][i]) / 2;
|
|
1129
|
+
Pnew[i][j] = s;
|
|
1130
|
+
Pnew[j][i] = s;
|
|
1131
|
+
}
|
|
1132
|
+
this.P = Pnew;
|
|
1133
|
+
for (const g of geom) {
|
|
1134
|
+
if (g.cpR === null || g.cpB === null) continue;
|
|
1135
|
+
this.track.set(g.prn, { lockR: g.lockR, lockB: g.lockB, lastMs: timeMs });
|
|
1136
|
+
}
|
|
1137
|
+
this.lastMs = timeMs;
|
|
1138
|
+
const ambiguities = {};
|
|
1139
|
+
for (let k = 0; k < this.amb.length; k++)
|
|
1140
|
+
ambiguities[this.amb[k].prn] = this.x[3 + k];
|
|
1141
|
+
const refSatellites = {};
|
|
1142
|
+
for (const [group, ref] of newRefs) refSatellites[group] = ref.prn;
|
|
1143
|
+
const nSats = new Set(rows.flatMap((r) => [r.g.prn, r.ref.prn])).size;
|
|
1144
|
+
return {
|
|
1145
|
+
timeMs,
|
|
1146
|
+
position: [this.x[0], this.x[1], this.x[2]],
|
|
1147
|
+
floatBaseline: [
|
|
1148
|
+
this.x[0] - this.basePos[0],
|
|
1149
|
+
this.x[1] - this.basePos[1],
|
|
1150
|
+
this.x[2] - this.basePos[2]
|
|
1151
|
+
],
|
|
1152
|
+
nSats,
|
|
1153
|
+
ratio: void 0,
|
|
1154
|
+
sigmas: [
|
|
1155
|
+
Math.sqrt(Math.max(this.P[0][0], 0)),
|
|
1156
|
+
Math.sqrt(Math.max(this.P[1][1], 0)),
|
|
1157
|
+
Math.sqrt(Math.max(this.P[2][2], 0))
|
|
1158
|
+
],
|
|
1159
|
+
ambiguities,
|
|
1160
|
+
refSatellites
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1163
|
+
};
|
|
1164
|
+
|
|
443
1165
|
// src/positioning/index.ts
|
|
444
1166
|
var GM_GPS2 = 3986005e8;
|
|
445
1167
|
var F_REL = -4442807633e-19;
|
|
@@ -476,11 +1198,11 @@ var PRIMARY_FREQ_HZ = {
|
|
|
476
1198
|
R: 1602e6
|
|
477
1199
|
};
|
|
478
1200
|
var F_L1 = 157542e4;
|
|
479
|
-
function
|
|
1201
|
+
function tropoDelay2(elevationRad) {
|
|
480
1202
|
const sinEl = Math.sin(elevationRad);
|
|
481
1203
|
return 2.47 / (sinEl + 0.0121);
|
|
482
1204
|
}
|
|
483
|
-
function
|
|
1205
|
+
function sagnac2(pos, travelTimeS) {
|
|
484
1206
|
const theta = OMEGA_E * travelTimeS;
|
|
485
1207
|
const c = Math.cos(theta);
|
|
486
1208
|
const s = Math.sin(theta);
|
|
@@ -551,7 +1273,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
551
1273
|
const isKepler = eph.system !== "R" && eph.system !== "S";
|
|
552
1274
|
const dts = dtsClock - (tgd && isKepler ? eph.tgd : 0);
|
|
553
1275
|
const travel = Math.hypot(sat.x - x2, sat.y - y2, sat.z - z2) / C_LIGHT;
|
|
554
|
-
const [sx, sy, sz] =
|
|
1276
|
+
const [sx, sy, sz] = sagnac2(sat, travel);
|
|
555
1277
|
const rho = Math.hypot(sx - x2, sy - y2, sz - z2);
|
|
556
1278
|
const ux = (x2 - sx) / rho;
|
|
557
1279
|
const uy = (y2 - sy) / rho;
|
|
@@ -568,7 +1290,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
568
1290
|
const sinEl = Math.max(Math.sin(elev), 0.1);
|
|
569
1291
|
weight = sinEl * sinEl;
|
|
570
1292
|
}
|
|
571
|
-
const tropo = troposphere && positionSane ?
|
|
1293
|
+
const tropo = troposphere && positionSane ? tropoDelay2(elev) : 0;
|
|
572
1294
|
let ionoM = 0;
|
|
573
1295
|
if (iono && positionSane) {
|
|
574
1296
|
const f = PRIMARY_FREQ_HZ[sys] ?? F_L1;
|
|
@@ -653,8 +1375,11 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
653
1375
|
}
|
|
654
1376
|
// Annotate the CommonJS export names for ESM import in node:
|
|
655
1377
|
0 && (module.exports = {
|
|
1378
|
+
RtkFloatEngine,
|
|
656
1379
|
ionoFree,
|
|
657
1380
|
klobucharDelay,
|
|
658
1381
|
satClockCorrection,
|
|
659
|
-
|
|
1382
|
+
solveDgnss,
|
|
1383
|
+
solveSpp,
|
|
1384
|
+
toRtkEpoch
|
|
660
1385
|
});
|