gnss-js 1.66.0 → 2.1.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/README.md +144 -132
- package/dist/{chunk-2CMAFEHI.js → chunk-DWUQRJ37.js} +284 -139
- package/dist/{chunk-REULRNJ5.js → chunk-WVTDVPKA.js} +151 -188
- package/dist/{ephemeris-Ohl6NAfw.d.cts → ephemeris-BAnBLLB9.d.cts} +0 -1
- package/dist/{ephemeris-Ohl6NAfw.d.ts → ephemeris-BAnBLLB9.d.ts} +0 -1
- package/dist/has-BaXnQarR.d.cts +123 -0
- package/dist/has-BaXnQarR.d.ts +123 -0
- package/dist/index.cjs +444 -331
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +14 -4
- package/dist/orbit.d.cts +1 -1
- package/dist/orbit.d.ts +1 -1
- package/dist/positioning.cjs +286 -137
- package/dist/positioning.d.cts +162 -3
- package/dist/positioning.d.ts +162 -3
- package/dist/positioning.js +9 -1
- package/dist/rtcm3.cjs +181 -217
- package/dist/rtcm3.d.cts +28 -15
- package/dist/rtcm3.d.ts +28 -15
- package/dist/rtcm3.js +5 -3
- package/dist/sbf.d.cts +2 -123
- package/dist/sbf.d.ts +2 -123
- package/package.json +1 -1
package/dist/positioning.cjs
CHANGED
|
@@ -21,8 +21,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var positioning_exports = {};
|
|
22
22
|
__export(positioning_exports, {
|
|
23
23
|
IONO_L1_M_PER_TECU: () => IONO_L1_M_PER_TECU,
|
|
24
|
+
PppEngine: () => PppEngine,
|
|
24
25
|
RtkFloatEngine: () => RtkFloatEngine,
|
|
25
26
|
SbasProcessor: () => SbasProcessor,
|
|
27
|
+
Sp3EphemerisSource: () => Sp3EphemerisSource,
|
|
28
|
+
applyOrbitClock: () => applyOrbitClock,
|
|
26
29
|
buildPppAntenna: () => buildPppAntenna,
|
|
27
30
|
createPppCorrections: () => createPppCorrections,
|
|
28
31
|
estimateNarrowlaneFcb: () => estimateNarrowlaneFcb,
|
|
@@ -33,6 +36,7 @@ __export(positioning_exports, {
|
|
|
33
36
|
gimSlantIonoDelayL1: () => gimSlantIonoDelayL1,
|
|
34
37
|
gimVerticalTec: () => gimVerticalTec,
|
|
35
38
|
gmst: () => gmst,
|
|
39
|
+
hasToOrbitClock: () => hasToOrbitClock,
|
|
36
40
|
ionoFree: () => ionoFree,
|
|
37
41
|
klobucharDelay: () => klobucharDelay,
|
|
38
42
|
lambdaReduction: () => lambdaReduction,
|
|
@@ -2394,6 +2398,55 @@ var SbasProcessor = class {
|
|
|
2394
2398
|
}
|
|
2395
2399
|
};
|
|
2396
2400
|
|
|
2401
|
+
// src/positioning/ssr-apply.ts
|
|
2402
|
+
var cross = (a, b) => [
|
|
2403
|
+
a[1] * b[2] - a[2] * b[1],
|
|
2404
|
+
a[2] * b[0] - a[0] * b[2],
|
|
2405
|
+
a[0] * b[1] - a[1] * b[0]
|
|
2406
|
+
];
|
|
2407
|
+
var norm = (a) => Math.hypot(a[0], a[1], a[2]);
|
|
2408
|
+
var unit = (a) => {
|
|
2409
|
+
const n = norm(a);
|
|
2410
|
+
return n > 0 ? [a[0] / n, a[1] / n, a[2] / n] : [0, 0, 0];
|
|
2411
|
+
};
|
|
2412
|
+
function applyOrbitClock(eph, corr, timeMs) {
|
|
2413
|
+
if (eph.system === "R" || eph.system === "S") return null;
|
|
2414
|
+
if (eph.iode !== corr.iod) return null;
|
|
2415
|
+
const age = (timeMs - corr.refTimeMs) / 1e3;
|
|
2416
|
+
if (corr.validitySeconds != null && (age < -1 || age > corr.validitySeconds))
|
|
2417
|
+
return null;
|
|
2418
|
+
const s = computeSatPosition(eph, timeMs);
|
|
2419
|
+
if (!Number.isFinite(s.x)) return null;
|
|
2420
|
+
const p = [s.x, s.y, s.z];
|
|
2421
|
+
const v = [s.vx, s.vy, s.vz];
|
|
2422
|
+
const er = unit(p);
|
|
2423
|
+
const en = unit(cross(p, v));
|
|
2424
|
+
const ea = cross(en, er);
|
|
2425
|
+
const dr = corr.radial + (corr.dotRadial ?? 0) * age;
|
|
2426
|
+
const da = corr.along + (corr.dotAlong ?? 0) * age;
|
|
2427
|
+
const dc = corr.cross + (corr.dotCross ?? 0) * age;
|
|
2428
|
+
const x = s.x + dr * er[0] + da * ea[0] + dc * en[0];
|
|
2429
|
+
const y = s.y + dr * er[1] + da * ea[1] + dc * en[1];
|
|
2430
|
+
const z = s.z + dr * er[2] + da * ea[2] + dc * en[2];
|
|
2431
|
+
const clockM = corr.clockC0 + (corr.clockC1 ?? 0) * age + (corr.clockC2 ?? 0) * age * age + (corr.highRateClock ?? 0);
|
|
2432
|
+
return { x, y, z, clockOffsetS: clockM / C_LIGHT };
|
|
2433
|
+
}
|
|
2434
|
+
function hasToOrbitClock(orbit, clock, refTimeMs, validitySeconds) {
|
|
2435
|
+
if (orbit.deltaRadial == null || orbit.deltaInTrack == null || orbit.deltaCrossTrack == null)
|
|
2436
|
+
return null;
|
|
2437
|
+
const clockC0 = clock && clock.deltaClock != null && !clock.notUsable ? clock.deltaClock : 0;
|
|
2438
|
+
return {
|
|
2439
|
+
prn: orbit.prn,
|
|
2440
|
+
iod: orbit.gnssIod,
|
|
2441
|
+
refTimeMs,
|
|
2442
|
+
radial: orbit.deltaRadial,
|
|
2443
|
+
along: orbit.deltaInTrack,
|
|
2444
|
+
cross: orbit.deltaCrossTrack,
|
|
2445
|
+
clockC0,
|
|
2446
|
+
validitySeconds
|
|
2447
|
+
};
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2397
2450
|
// src/rinex/sp3.ts
|
|
2398
2451
|
function sp3Position(sp3, prn, tMs, order = 9) {
|
|
2399
2452
|
const samples = sp3.satellites[prn];
|
|
@@ -2723,14 +2776,14 @@ function buildPppAntenna(antex) {
|
|
|
2723
2776
|
}
|
|
2724
2777
|
};
|
|
2725
2778
|
}
|
|
2726
|
-
function
|
|
2779
|
+
function cross2(a, b) {
|
|
2727
2780
|
return [
|
|
2728
2781
|
a[1] * b[2] - a[2] * b[1],
|
|
2729
2782
|
a[2] * b[0] - a[0] * b[2],
|
|
2730
2783
|
a[0] * b[1] - a[1] * b[0]
|
|
2731
2784
|
];
|
|
2732
2785
|
}
|
|
2733
|
-
function
|
|
2786
|
+
function norm2(a) {
|
|
2734
2787
|
const n = Math.hypot(a[0], a[1], a[2]) || 1;
|
|
2735
2788
|
return [a[0] / n, a[1] / n, a[2] / n];
|
|
2736
2789
|
}
|
|
@@ -2738,14 +2791,14 @@ function dot(a, b) {
|
|
|
2738
2791
|
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
2739
2792
|
}
|
|
2740
2793
|
function satBodyFrame(satEcef, sunEcef2) {
|
|
2741
|
-
const z =
|
|
2742
|
-
const eSun =
|
|
2794
|
+
const z = norm2([-satEcef[0], -satEcef[1], -satEcef[2]]);
|
|
2795
|
+
const eSun = norm2([
|
|
2743
2796
|
sunEcef2[0] - satEcef[0],
|
|
2744
2797
|
sunEcef2[1] - satEcef[1],
|
|
2745
2798
|
sunEcef2[2] - satEcef[2]
|
|
2746
2799
|
]);
|
|
2747
|
-
const y =
|
|
2748
|
-
const x =
|
|
2800
|
+
const y = norm2(cross2(z, eSun));
|
|
2801
|
+
const x = norm2(cross2(y, z));
|
|
2749
2802
|
return { x, y, z };
|
|
2750
2803
|
}
|
|
2751
2804
|
function satPcoToEcef(pcoBody, frame) {
|
|
@@ -2786,7 +2839,7 @@ function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
|
|
|
2786
2839
|
const kx = satFrame.x;
|
|
2787
2840
|
const ky = satFrame.y;
|
|
2788
2841
|
const kdotx = dot(k, kx);
|
|
2789
|
-
const kcrossY =
|
|
2842
|
+
const kcrossY = cross2(k, ky);
|
|
2790
2843
|
const dS = [
|
|
2791
2844
|
kx[0] - k[0] * kdotx - kcrossY[0],
|
|
2792
2845
|
kx[1] - k[1] * kdotx - kcrossY[1],
|
|
@@ -2795,7 +2848,7 @@ function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
|
|
|
2795
2848
|
const north = enuToEcef([0, 1, 0], latRad, lonRad);
|
|
2796
2849
|
const east = enuToEcef([1, 0, 0], latRad, lonRad);
|
|
2797
2850
|
const kdotn = dot(k, north);
|
|
2798
|
-
const kcrossE =
|
|
2851
|
+
const kcrossE = cross2(k, east);
|
|
2799
2852
|
const dR = [
|
|
2800
2853
|
north[0] - k[0] * kdotn + kcrossE[0],
|
|
2801
2854
|
north[1] - k[1] * kdotn + kcrossE[1],
|
|
@@ -2805,7 +2858,7 @@ function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
|
|
|
2805
2858
|
const nR = Math.hypot(dR[0], dR[1], dR[2]) || 1;
|
|
2806
2859
|
let cosPhi = dot(dS, dR) / (nS * nR);
|
|
2807
2860
|
cosPhi = Math.max(-1, Math.min(1, cosPhi));
|
|
2808
|
-
const zeta =
|
|
2861
|
+
const zeta = cross2(dS, dR);
|
|
2809
2862
|
const sign = dot(k, zeta) >= 0 ? 1 : -1;
|
|
2810
2863
|
const dphi = sign * Math.acos(cosPhi) / (2 * Math.PI);
|
|
2811
2864
|
const prev = state.get(prn);
|
|
@@ -2943,13 +2996,35 @@ function ifCoeffs(f1, f2) {
|
|
|
2943
2996
|
const lambdaIf = C_LIGHT / (f1 + f2);
|
|
2944
2997
|
return { g, lambdaIf };
|
|
2945
2998
|
}
|
|
2999
|
+
var Sp3EphemerisSource = class {
|
|
3000
|
+
constructor(sp3, clk) {
|
|
3001
|
+
this.sp3 = sp3;
|
|
3002
|
+
this.clk = clk;
|
|
3003
|
+
}
|
|
3004
|
+
satState(prn, tEmitMs) {
|
|
3005
|
+
const p = sp3Position(this.sp3, prn, tEmitMs);
|
|
3006
|
+
if (!p || p.clk == null) return null;
|
|
3007
|
+
const pPlus = sp3Position(this.sp3, prn, tEmitMs + 500);
|
|
3008
|
+
const pMinus = sp3Position(this.sp3, prn, tEmitMs - 500);
|
|
3009
|
+
let vx = 0;
|
|
3010
|
+
let vy = 0;
|
|
3011
|
+
let vz = 0;
|
|
3012
|
+
if (pPlus && pMinus) {
|
|
3013
|
+
vx = pPlus.x - pMinus.x;
|
|
3014
|
+
vy = pPlus.y - pMinus.y;
|
|
3015
|
+
vz = pPlus.z - pMinus.z;
|
|
3016
|
+
}
|
|
3017
|
+
const clkS = (this.clk ? clkBias(this.clk, prn, tEmitMs) : null) ?? p.clk;
|
|
3018
|
+
return { x: p.x, y: p.y, z: p.z, vx, vy, vz, clkS };
|
|
3019
|
+
}
|
|
3020
|
+
};
|
|
2946
3021
|
function sagnacRotate(x, y, z, travelS) {
|
|
2947
3022
|
const theta = OMEGA_E * travelS;
|
|
2948
3023
|
const c = Math.cos(theta);
|
|
2949
3024
|
const s = Math.sin(theta);
|
|
2950
3025
|
return [x * c + y * s, -x * s + y * c, z];
|
|
2951
3026
|
}
|
|
2952
|
-
function satStateAtEmission(
|
|
3027
|
+
function satStateAtEmission(source, prn, recvTimeMs, rcv) {
|
|
2953
3028
|
let travelS = 0.075;
|
|
2954
3029
|
let sx = 0;
|
|
2955
3030
|
let sy = 0;
|
|
@@ -2958,18 +3033,11 @@ function satStateAtEmission(sp3, prn, recvTimeMs, rcv, clk) {
|
|
|
2958
3033
|
let velDotPos = 0;
|
|
2959
3034
|
for (let iter = 0; iter < 3; iter++) {
|
|
2960
3035
|
const tEmit = recvTimeMs - travelS * 1e3;
|
|
2961
|
-
const
|
|
2962
|
-
if (!
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
const vx = (pPlus.x - pMinus.x) / 1;
|
|
2967
|
-
const vy = (pPlus.y - pMinus.y) / 1;
|
|
2968
|
-
const vz = (pPlus.z - pMinus.z) / 1;
|
|
2969
|
-
velDotPos = p.x * vx + p.y * vy + p.z * vz;
|
|
2970
|
-
}
|
|
2971
|
-
clkS = (clk && clkBias(clk, prn, tEmit)) ?? p.clk;
|
|
2972
|
-
const [rx, ry, rz] = sagnacRotate(p.x, p.y, p.z, travelS);
|
|
3036
|
+
const s = source.satState(prn, tEmit);
|
|
3037
|
+
if (!s) return null;
|
|
3038
|
+
velDotPos = s.x * s.vx + s.y * s.vy + s.z * s.vz;
|
|
3039
|
+
clkS = s.clkS;
|
|
3040
|
+
const [rx, ry, rz] = sagnacRotate(s.x, s.y, s.z, travelS);
|
|
2973
3041
|
sx = rx;
|
|
2974
3042
|
sy = ry;
|
|
2975
3043
|
sz = rz;
|
|
@@ -2991,39 +3059,72 @@ var IDX_ZWD = 3;
|
|
|
2991
3059
|
var NBASE = 4;
|
|
2992
3060
|
var CLK_VAR = 1e10;
|
|
2993
3061
|
var POS_VAR = 60 * 60;
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3062
|
+
var PppEngine = class {
|
|
3063
|
+
source;
|
|
3064
|
+
opts;
|
|
3065
|
+
elevMask;
|
|
3066
|
+
codeSigma;
|
|
3067
|
+
phaseSigma;
|
|
3068
|
+
ztdQ;
|
|
3069
|
+
kinematic;
|
|
3070
|
+
corrections;
|
|
3071
|
+
truth;
|
|
3072
|
+
// Filter state (reset() initialises; mutated in place across epochs).
|
|
3073
|
+
x;
|
|
3074
|
+
P;
|
|
3075
|
+
clkIdx;
|
|
3076
|
+
clockSeeded;
|
|
3077
|
+
ambIdx;
|
|
3078
|
+
lastSeen;
|
|
3079
|
+
arcs;
|
|
3080
|
+
arcSnap;
|
|
3081
|
+
mwState;
|
|
3082
|
+
series;
|
|
3083
|
+
ei = 0;
|
|
3084
|
+
t0 = 0;
|
|
3085
|
+
convergenceSec = null;
|
|
3086
|
+
convergedStreak = 0;
|
|
3087
|
+
constructor(opts, source) {
|
|
3088
|
+
this.opts = opts;
|
|
3089
|
+
this.source = source;
|
|
3090
|
+
this.elevMask = (opts.elevationMaskDeg ?? 10) * Math.PI / 180;
|
|
3091
|
+
this.codeSigma = opts.codeSigma ?? 3;
|
|
3092
|
+
this.phaseSigma = opts.phaseSigma ?? 0.01;
|
|
3093
|
+
this.ztdQ = opts.ztdProcessNoise ?? 1e-8;
|
|
3094
|
+
this.kinematic = opts.mode === "kinematic";
|
|
3095
|
+
this.corrections = opts.corrections;
|
|
3096
|
+
this.truth = opts.groundTruth;
|
|
3097
|
+
this.reset();
|
|
3098
|
+
}
|
|
3099
|
+
/** Reinitialise the filter (fresh session). */
|
|
3100
|
+
reset() {
|
|
3101
|
+
const { opts } = this;
|
|
3102
|
+
this.x = [opts.aprioriPos[0], opts.aprioriPos[1], opts.aprioriPos[2], 0.1];
|
|
3103
|
+
const P = [];
|
|
3104
|
+
for (let i = 0; i < NBASE; i++) P.push(new Array(NBASE).fill(0));
|
|
3105
|
+
P[IDX_X][IDX_X] = 100 * 100;
|
|
3106
|
+
P[IDX_Y][IDX_Y] = 100 * 100;
|
|
3107
|
+
P[IDX_Z][IDX_Z] = 100 * 100;
|
|
3108
|
+
P[IDX_ZWD][IDX_ZWD] = 0.5 * 0.5;
|
|
3109
|
+
this.P = P;
|
|
3110
|
+
this.clkIdx = /* @__PURE__ */ new Map();
|
|
3111
|
+
this.clockSeeded = /* @__PURE__ */ new Set();
|
|
3112
|
+
this.ambIdx = /* @__PURE__ */ new Map();
|
|
3113
|
+
this.lastSeen = /* @__PURE__ */ new Map();
|
|
3114
|
+
this.arcs = [];
|
|
3115
|
+
this.arcSnap = /* @__PURE__ */ new Map();
|
|
3116
|
+
this.mwState = /* @__PURE__ */ new Map();
|
|
3117
|
+
this.series = [];
|
|
3118
|
+
this.ei = 0;
|
|
3119
|
+
this.t0 = 0;
|
|
3120
|
+
this.convergenceSec = null;
|
|
3121
|
+
this.convergedStreak = 0;
|
|
3011
3122
|
}
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
P[IDX_ZWD][IDX_ZWD] = 0.5 * 0.5;
|
|
3016
|
-
const clkIdx = /* @__PURE__ */ new Map();
|
|
3017
|
-
const clockSeeded = /* @__PURE__ */ new Set();
|
|
3018
|
-
const ambIdx = /* @__PURE__ */ new Map();
|
|
3019
|
-
const lastSeen = /* @__PURE__ */ new Map();
|
|
3020
|
-
const arcs = [];
|
|
3021
|
-
const arcSnap = /* @__PURE__ */ new Map();
|
|
3022
|
-
const flushArc = (prn, minEpochs = 10) => {
|
|
3023
|
-
const s = arcSnap.get(prn);
|
|
3024
|
-
arcSnap.delete(prn);
|
|
3123
|
+
flushArc(prn, minEpochs = 10) {
|
|
3124
|
+
const s = this.arcSnap.get(prn);
|
|
3125
|
+
this.arcSnap.delete(prn);
|
|
3025
3126
|
if (!s || s.nEpochs < minEpochs) return;
|
|
3026
|
-
arcs.push({
|
|
3127
|
+
this.arcs.push({
|
|
3027
3128
|
prn,
|
|
3028
3129
|
aIF: s.aIF,
|
|
3029
3130
|
mwCyc: s.mwCyc,
|
|
@@ -3034,64 +3135,88 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
3034
3135
|
startMs: s.startMs,
|
|
3035
3136
|
endMs: s.endMs
|
|
3036
3137
|
});
|
|
3037
|
-
}
|
|
3038
|
-
|
|
3039
|
-
|
|
3138
|
+
}
|
|
3139
|
+
/** Detect a cycle slip via the Melbourne–Wübbena wide-lane ambiguity. */
|
|
3140
|
+
detectSlip(o, ei) {
|
|
3040
3141
|
const lamW = C_LIGHT / (o.f1 - o.f2);
|
|
3041
3142
|
const lw = o.l1 - o.l2;
|
|
3042
3143
|
const pn = (o.f1 * o.c1 + o.f2 * o.c2) / (o.f1 + o.f2);
|
|
3043
3144
|
const mw = lw - pn / lamW;
|
|
3044
|
-
const st = mwState.get(o.prn);
|
|
3145
|
+
const st = this.mwState.get(o.prn);
|
|
3045
3146
|
let slip = o.slip;
|
|
3046
3147
|
if (!st || ei - st.lastEi > 2)
|
|
3047
3148
|
slip = true;
|
|
3048
3149
|
else if (Math.abs(mw - st.mean) > 4) slip = true;
|
|
3049
|
-
if (slip) mwState.set(o.prn, { mean: mw, n: 1, lastEi: ei });
|
|
3150
|
+
if (slip) this.mwState.set(o.prn, { mean: mw, n: 1, lastEi: ei });
|
|
3050
3151
|
else {
|
|
3051
3152
|
const n = st.n + 1;
|
|
3052
|
-
mwState.set(o.prn, {
|
|
3153
|
+
this.mwState.set(o.prn, {
|
|
3053
3154
|
mean: st.mean + (mw - st.mean) / Math.min(n, 100),
|
|
3054
3155
|
n,
|
|
3055
3156
|
lastEi: ei
|
|
3056
3157
|
});
|
|
3057
3158
|
}
|
|
3058
3159
|
return slip;
|
|
3059
|
-
}
|
|
3060
|
-
|
|
3061
|
-
const idx = x.length;
|
|
3062
|
-
x.push(initVal);
|
|
3063
|
-
for (const row of P) row.push(0);
|
|
3064
|
-
P.push(new Array(x.length).fill(0));
|
|
3065
|
-
P[idx][idx] = initVar;
|
|
3160
|
+
}
|
|
3161
|
+
growState(initVal, initVar) {
|
|
3162
|
+
const idx = this.x.length;
|
|
3163
|
+
this.x.push(initVal);
|
|
3164
|
+
for (const row of this.P) row.push(0);
|
|
3165
|
+
this.P.push(new Array(this.x.length).fill(0));
|
|
3166
|
+
this.P[idx][idx] = initVar;
|
|
3066
3167
|
return idx;
|
|
3067
|
-
}
|
|
3068
|
-
|
|
3069
|
-
x.splice(idx, 1);
|
|
3070
|
-
P.splice(idx, 1);
|
|
3071
|
-
for (const row of P) row.splice(idx, 1);
|
|
3072
|
-
for (const [prn, i] of ambIdx) {
|
|
3073
|
-
if (i === idx) ambIdx.delete(prn);
|
|
3074
|
-
else if (i > idx) ambIdx.set(prn, i - 1);
|
|
3168
|
+
}
|
|
3169
|
+
dropState(idx) {
|
|
3170
|
+
this.x.splice(idx, 1);
|
|
3171
|
+
this.P.splice(idx, 1);
|
|
3172
|
+
for (const row of this.P) row.splice(idx, 1);
|
|
3173
|
+
for (const [prn, i] of this.ambIdx) {
|
|
3174
|
+
if (i === idx) this.ambIdx.delete(prn);
|
|
3175
|
+
else if (i > idx) this.ambIdx.set(prn, i - 1);
|
|
3075
3176
|
}
|
|
3076
|
-
for (const [sys, i] of clkIdx) {
|
|
3077
|
-
if (i > idx) clkIdx.set(sys, i - 1);
|
|
3177
|
+
for (const [sys, i] of this.clkIdx) {
|
|
3178
|
+
if (i > idx) this.clkIdx.set(sys, i - 1);
|
|
3078
3179
|
}
|
|
3079
|
-
}
|
|
3080
|
-
|
|
3081
|
-
|
|
3180
|
+
}
|
|
3181
|
+
/** State index of a constellation's receiver clock, creating it lazily. */
|
|
3182
|
+
clockOf(sys) {
|
|
3183
|
+
let i = this.clkIdx.get(sys);
|
|
3082
3184
|
if (i === void 0) {
|
|
3083
|
-
i = growState(0, CLK_VAR);
|
|
3084
|
-
clkIdx.set(sys, i);
|
|
3185
|
+
i = this.growState(0, CLK_VAR);
|
|
3186
|
+
this.clkIdx.set(sys, i);
|
|
3085
3187
|
}
|
|
3086
3188
|
return i;
|
|
3087
|
-
}
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3189
|
+
}
|
|
3190
|
+
/** Process one epoch, carrying the filter forward; returns its result. */
|
|
3191
|
+
process(epoch) {
|
|
3192
|
+
const {
|
|
3193
|
+
source,
|
|
3194
|
+
opts,
|
|
3195
|
+
elevMask,
|
|
3196
|
+
codeSigma,
|
|
3197
|
+
phaseSigma,
|
|
3198
|
+
ztdQ,
|
|
3199
|
+
kinematic,
|
|
3200
|
+
corrections,
|
|
3201
|
+
truth,
|
|
3202
|
+
x,
|
|
3203
|
+
P,
|
|
3204
|
+
clkIdx,
|
|
3205
|
+
clockSeeded,
|
|
3206
|
+
ambIdx,
|
|
3207
|
+
lastSeen,
|
|
3208
|
+
arcSnap,
|
|
3209
|
+
mwState,
|
|
3210
|
+
series
|
|
3211
|
+
} = this;
|
|
3212
|
+
const flushArc = this.flushArc.bind(this);
|
|
3213
|
+
const detectSlip = this.detectSlip.bind(this);
|
|
3214
|
+
const growState = this.growState.bind(this);
|
|
3215
|
+
const dropState = this.dropState.bind(this);
|
|
3216
|
+
const clockOf = this.clockOf.bind(this);
|
|
3217
|
+
const ei = this.ei;
|
|
3218
|
+
if (ei === 0) this.t0 = epoch.timeMs;
|
|
3219
|
+
const t0 = this.t0;
|
|
3095
3220
|
if (kinematic && ei > 0) {
|
|
3096
3221
|
for (const p of [IDX_X, IDX_Y, IDX_Z]) {
|
|
3097
3222
|
for (let j = 0; j < x.length; j++) {
|
|
@@ -3112,7 +3237,7 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
3112
3237
|
for (const o of epoch.obs) {
|
|
3113
3238
|
if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
|
|
3114
3239
|
const slip = detectSlip(o, ei);
|
|
3115
|
-
const sat = satStateAtEmission(
|
|
3240
|
+
const sat = satStateAtEmission(source, o.prn, epoch.timeMs, rcv);
|
|
3116
3241
|
if (!sat) continue;
|
|
3117
3242
|
const [elRad, azRad] = getAer(
|
|
3118
3243
|
sat.state.x,
|
|
@@ -3132,7 +3257,9 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
3132
3257
|
const lam1 = C_LIGHT / o.f1;
|
|
3133
3258
|
const lam2 = C_LIGHT / o.f2;
|
|
3134
3259
|
if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
|
|
3135
|
-
const
|
|
3260
|
+
const b1 = source.codeBias?.(o.prn, o.code1 ?? "", epoch.timeMs) ?? 0;
|
|
3261
|
+
const b2 = source.codeBias?.(o.prn, o.code2 ?? "", epoch.timeMs) ?? 0;
|
|
3262
|
+
const pIf = g * (o.c1 - b1) - (g - 1) * (o.c2 - b2);
|
|
3136
3263
|
const lIf = g * (o.l1 * lam1) - (g - 1) * (o.l2 * lam2);
|
|
3137
3264
|
if (!Number.isFinite(pIf) || !Number.isFinite(lIf)) continue;
|
|
3138
3265
|
const trop = opts.troposphere ?? true ? niellMapping(elRad, latRad, heightM, epoch.timeMs) : { zhd: 0, mh: 0, mw: 0 };
|
|
@@ -3319,16 +3446,16 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
3319
3446
|
pos[2] - truth[2]
|
|
3320
3447
|
);
|
|
3321
3448
|
if (error3d < 0.1) {
|
|
3322
|
-
convergedStreak++;
|
|
3323
|
-
if (convergedStreak >= 10 && convergenceSec == null) {
|
|
3324
|
-
convergenceSec = (epoch.timeMs - t0) / 1e3;
|
|
3449
|
+
this.convergedStreak++;
|
|
3450
|
+
if (this.convergedStreak >= 10 && this.convergenceSec == null) {
|
|
3451
|
+
this.convergenceSec = (epoch.timeMs - t0) / 1e3;
|
|
3325
3452
|
}
|
|
3326
3453
|
} else {
|
|
3327
|
-
convergedStreak = 0;
|
|
3328
|
-
convergenceSec = null;
|
|
3454
|
+
this.convergedStreak = 0;
|
|
3455
|
+
this.convergenceSec = null;
|
|
3329
3456
|
}
|
|
3330
3457
|
}
|
|
3331
|
-
|
|
3458
|
+
const result = {
|
|
3332
3459
|
timeMs: epoch.timeMs,
|
|
3333
3460
|
enu,
|
|
3334
3461
|
error3d,
|
|
@@ -3337,50 +3464,68 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
3337
3464
|
ztdWet: x[IDX_ZWD],
|
|
3338
3465
|
ztdHydrostatic: epochZhd,
|
|
3339
3466
|
phaseResRms: nPhaseRes > 0 ? Math.sqrt(sumPhaseResSq / nPhaseRes) : 0
|
|
3340
|
-
}
|
|
3467
|
+
};
|
|
3468
|
+
series.push(result);
|
|
3469
|
+
this.ei = ei + 1;
|
|
3470
|
+
return result;
|
|
3341
3471
|
}
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
const
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
ambs
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3472
|
+
/** Finalise the session: capture the AR state, flush open arcs, assemble. */
|
|
3473
|
+
solution() {
|
|
3474
|
+
const { opts, x, P, ambIdx, arcSnap, mwState, arcs, series, truth } = this;
|
|
3475
|
+
const flushArc = this.flushArc.bind(this);
|
|
3476
|
+
let finalState;
|
|
3477
|
+
if (opts.exposeState) {
|
|
3478
|
+
const ambs = [];
|
|
3479
|
+
for (const [prn, index] of ambIdx) {
|
|
3480
|
+
const s = arcSnap.get(prn);
|
|
3481
|
+
if (!s || s.nEpochs < 10) continue;
|
|
3482
|
+
ambs.push({
|
|
3483
|
+
prn,
|
|
3484
|
+
index,
|
|
3485
|
+
aIF: x[index],
|
|
3486
|
+
mwCyc: mwState.get(prn)?.mean ?? s.mwCyc,
|
|
3487
|
+
f1: s.f1,
|
|
3488
|
+
f2: s.f2,
|
|
3489
|
+
elevDeg: s.elevSum / s.nEpochs
|
|
3490
|
+
});
|
|
3491
|
+
}
|
|
3492
|
+
finalState = {
|
|
3493
|
+
position: [x[IDX_X], x[IDX_Y], x[IDX_Z]],
|
|
3494
|
+
covariance: P.map((row) => row.slice()),
|
|
3495
|
+
ambiguities: ambs
|
|
3496
|
+
};
|
|
3357
3497
|
}
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3498
|
+
for (const prn of [...arcSnap.keys()]) flushArc(prn);
|
|
3499
|
+
const finalPos = [
|
|
3500
|
+
x[IDX_X],
|
|
3501
|
+
x[IDX_Y],
|
|
3502
|
+
x[IDX_Z]
|
|
3503
|
+
];
|
|
3504
|
+
const llh = ecefToGeodetic(finalPos[0], finalPos[1], finalPos[2]);
|
|
3505
|
+
const finalError3d = truth ? Math.hypot(
|
|
3506
|
+
finalPos[0] - truth[0],
|
|
3507
|
+
finalPos[1] - truth[1],
|
|
3508
|
+
finalPos[2] - truth[2]
|
|
3509
|
+
) : null;
|
|
3510
|
+
return {
|
|
3511
|
+
position: finalPos,
|
|
3512
|
+
llh,
|
|
3513
|
+
series,
|
|
3514
|
+
ztdWet: x[IDX_ZWD],
|
|
3515
|
+
ztdHydrostatic: series.length ? series[series.length - 1].ztdHydrostatic : 0,
|
|
3516
|
+
epochsUsed: series.length,
|
|
3517
|
+
convergenceSec: this.convergenceSec,
|
|
3518
|
+
finalError3d,
|
|
3519
|
+
arcs,
|
|
3520
|
+
finalState
|
|
3362
3521
|
};
|
|
3363
3522
|
}
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
const
|
|
3367
|
-
const
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
finalPos[2] - truth[2]
|
|
3371
|
-
) : null;
|
|
3372
|
-
return {
|
|
3373
|
-
position: finalPos,
|
|
3374
|
-
llh,
|
|
3375
|
-
series,
|
|
3376
|
-
ztdWet: x[IDX_ZWD],
|
|
3377
|
-
ztdHydrostatic: series.length ? series[series.length - 1].ztdHydrostatic : 0,
|
|
3378
|
-
epochsUsed: epochs.length,
|
|
3379
|
-
convergenceSec,
|
|
3380
|
-
finalError3d,
|
|
3381
|
-
arcs,
|
|
3382
|
-
finalState
|
|
3383
|
-
};
|
|
3523
|
+
};
|
|
3524
|
+
function solvePpp(epochs, sp3OrSource, opts) {
|
|
3525
|
+
const source = "satState" in sp3OrSource ? sp3OrSource : new Sp3EphemerisSource(sp3OrSource, opts.clk);
|
|
3526
|
+
const eng = new PppEngine(opts, source);
|
|
3527
|
+
for (const epoch of epochs) eng.process(epoch);
|
|
3528
|
+
return eng.solution();
|
|
3384
3529
|
}
|
|
3385
3530
|
|
|
3386
3531
|
// src/positioning/ppp-ar.ts
|
|
@@ -4116,8 +4261,11 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
4116
4261
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4117
4262
|
0 && (module.exports = {
|
|
4118
4263
|
IONO_L1_M_PER_TECU,
|
|
4264
|
+
PppEngine,
|
|
4119
4265
|
RtkFloatEngine,
|
|
4120
4266
|
SbasProcessor,
|
|
4267
|
+
Sp3EphemerisSource,
|
|
4268
|
+
applyOrbitClock,
|
|
4121
4269
|
buildPppAntenna,
|
|
4122
4270
|
createPppCorrections,
|
|
4123
4271
|
estimateNarrowlaneFcb,
|
|
@@ -4128,6 +4276,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
4128
4276
|
gimSlantIonoDelayL1,
|
|
4129
4277
|
gimVerticalTec,
|
|
4130
4278
|
gmst,
|
|
4279
|
+
hasToOrbitClock,
|
|
4131
4280
|
ionoFree,
|
|
4132
4281
|
klobucharDelay,
|
|
4133
4282
|
lambdaReduction,
|