gnss-js 2.0.0 → 2.2.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-2CMAFEHI.js → chunk-DWUQRJ37.js} +284 -139
- package/dist/{chunk-WVTDVPKA.js → chunk-XPQ4BU6W.js} +2 -1
- package/dist/has-BaXnQarR.d.cts +123 -0
- package/dist/has-BaXnQarR.d.ts +123 -0
- package/dist/index.cjs +294 -144
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +10 -2
- package/dist/positioning.cjs +286 -137
- package/dist/positioning.d.cts +161 -2
- package/dist/positioning.d.ts +161 -2
- package/dist/positioning.js +9 -1
- package/dist/rtcm3.cjs +2 -1
- package/dist/rtcm3.d.cts +4 -1
- package/dist/rtcm3.d.ts +4 -1
- package/dist/rtcm3.js +1 -1
- package/dist/sbf.d.cts +2 -123
- package/dist/sbf.d.ts +2 -123
- package/package.json +1 -1
|
@@ -1918,6 +1918,55 @@ var SbasProcessor = class {
|
|
|
1918
1918
|
}
|
|
1919
1919
|
};
|
|
1920
1920
|
|
|
1921
|
+
// src/positioning/ssr-apply.ts
|
|
1922
|
+
var cross = (a, b) => [
|
|
1923
|
+
a[1] * b[2] - a[2] * b[1],
|
|
1924
|
+
a[2] * b[0] - a[0] * b[2],
|
|
1925
|
+
a[0] * b[1] - a[1] * b[0]
|
|
1926
|
+
];
|
|
1927
|
+
var norm = (a) => Math.hypot(a[0], a[1], a[2]);
|
|
1928
|
+
var unit = (a) => {
|
|
1929
|
+
const n = norm(a);
|
|
1930
|
+
return n > 0 ? [a[0] / n, a[1] / n, a[2] / n] : [0, 0, 0];
|
|
1931
|
+
};
|
|
1932
|
+
function applyOrbitClock(eph, corr, timeMs) {
|
|
1933
|
+
if (eph.system === "R" || eph.system === "S") return null;
|
|
1934
|
+
if (eph.iode !== corr.iod) return null;
|
|
1935
|
+
const age = (timeMs - corr.refTimeMs) / 1e3;
|
|
1936
|
+
if (corr.validitySeconds != null && (age < -1 || age > corr.validitySeconds))
|
|
1937
|
+
return null;
|
|
1938
|
+
const s = computeSatPosition(eph, timeMs);
|
|
1939
|
+
if (!Number.isFinite(s.x)) return null;
|
|
1940
|
+
const p = [s.x, s.y, s.z];
|
|
1941
|
+
const v = [s.vx, s.vy, s.vz];
|
|
1942
|
+
const er = unit(p);
|
|
1943
|
+
const en = unit(cross(p, v));
|
|
1944
|
+
const ea = cross(en, er);
|
|
1945
|
+
const dr = corr.radial + (corr.dotRadial ?? 0) * age;
|
|
1946
|
+
const da = corr.along + (corr.dotAlong ?? 0) * age;
|
|
1947
|
+
const dc = corr.cross + (corr.dotCross ?? 0) * age;
|
|
1948
|
+
const x = s.x + dr * er[0] + da * ea[0] + dc * en[0];
|
|
1949
|
+
const y = s.y + dr * er[1] + da * ea[1] + dc * en[1];
|
|
1950
|
+
const z = s.z + dr * er[2] + da * ea[2] + dc * en[2];
|
|
1951
|
+
const clockM = corr.clockC0 + (corr.clockC1 ?? 0) * age + (corr.clockC2 ?? 0) * age * age + (corr.highRateClock ?? 0);
|
|
1952
|
+
return { x, y, z, clockOffsetS: clockM / C_LIGHT };
|
|
1953
|
+
}
|
|
1954
|
+
function hasToOrbitClock(orbit, clock, refTimeMs, validitySeconds) {
|
|
1955
|
+
if (orbit.deltaRadial == null || orbit.deltaInTrack == null || orbit.deltaCrossTrack == null)
|
|
1956
|
+
return null;
|
|
1957
|
+
const clockC0 = clock && clock.deltaClock != null && !clock.notUsable ? clock.deltaClock : 0;
|
|
1958
|
+
return {
|
|
1959
|
+
prn: orbit.prn,
|
|
1960
|
+
iod: orbit.gnssIod,
|
|
1961
|
+
refTimeMs,
|
|
1962
|
+
radial: orbit.deltaRadial,
|
|
1963
|
+
along: orbit.deltaInTrack,
|
|
1964
|
+
cross: orbit.deltaCrossTrack,
|
|
1965
|
+
clockC0,
|
|
1966
|
+
validitySeconds
|
|
1967
|
+
};
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1921
1970
|
// src/positioning/ppp-tropo.ts
|
|
1922
1971
|
var HYD_AVG_A = [
|
|
1923
1972
|
0.0012769934,
|
|
@@ -2175,14 +2224,14 @@ function buildPppAntenna(antex) {
|
|
|
2175
2224
|
}
|
|
2176
2225
|
};
|
|
2177
2226
|
}
|
|
2178
|
-
function
|
|
2227
|
+
function cross2(a, b) {
|
|
2179
2228
|
return [
|
|
2180
2229
|
a[1] * b[2] - a[2] * b[1],
|
|
2181
2230
|
a[2] * b[0] - a[0] * b[2],
|
|
2182
2231
|
a[0] * b[1] - a[1] * b[0]
|
|
2183
2232
|
];
|
|
2184
2233
|
}
|
|
2185
|
-
function
|
|
2234
|
+
function norm2(a) {
|
|
2186
2235
|
const n = Math.hypot(a[0], a[1], a[2]) || 1;
|
|
2187
2236
|
return [a[0] / n, a[1] / n, a[2] / n];
|
|
2188
2237
|
}
|
|
@@ -2190,14 +2239,14 @@ function dot(a, b) {
|
|
|
2190
2239
|
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
2191
2240
|
}
|
|
2192
2241
|
function satBodyFrame(satEcef, sunEcef2) {
|
|
2193
|
-
const z =
|
|
2194
|
-
const eSun =
|
|
2242
|
+
const z = norm2([-satEcef[0], -satEcef[1], -satEcef[2]]);
|
|
2243
|
+
const eSun = norm2([
|
|
2195
2244
|
sunEcef2[0] - satEcef[0],
|
|
2196
2245
|
sunEcef2[1] - satEcef[1],
|
|
2197
2246
|
sunEcef2[2] - satEcef[2]
|
|
2198
2247
|
]);
|
|
2199
|
-
const y =
|
|
2200
|
-
const x =
|
|
2248
|
+
const y = norm2(cross2(z, eSun));
|
|
2249
|
+
const x = norm2(cross2(y, z));
|
|
2201
2250
|
return { x, y, z };
|
|
2202
2251
|
}
|
|
2203
2252
|
function satPcoToEcef(pcoBody, frame) {
|
|
@@ -2238,7 +2287,7 @@ function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
|
|
|
2238
2287
|
const kx = satFrame.x;
|
|
2239
2288
|
const ky = satFrame.y;
|
|
2240
2289
|
const kdotx = dot(k, kx);
|
|
2241
|
-
const kcrossY =
|
|
2290
|
+
const kcrossY = cross2(k, ky);
|
|
2242
2291
|
const dS = [
|
|
2243
2292
|
kx[0] - k[0] * kdotx - kcrossY[0],
|
|
2244
2293
|
kx[1] - k[1] * kdotx - kcrossY[1],
|
|
@@ -2247,7 +2296,7 @@ function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
|
|
|
2247
2296
|
const north = enuToEcef([0, 1, 0], latRad, lonRad);
|
|
2248
2297
|
const east = enuToEcef([1, 0, 0], latRad, lonRad);
|
|
2249
2298
|
const kdotn = dot(k, north);
|
|
2250
|
-
const kcrossE =
|
|
2299
|
+
const kcrossE = cross2(k, east);
|
|
2251
2300
|
const dR = [
|
|
2252
2301
|
north[0] - k[0] * kdotn + kcrossE[0],
|
|
2253
2302
|
north[1] - k[1] * kdotn + kcrossE[1],
|
|
@@ -2257,7 +2306,7 @@ function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
|
|
|
2257
2306
|
const nR = Math.hypot(dR[0], dR[1], dR[2]) || 1;
|
|
2258
2307
|
let cosPhi = dot(dS, dR) / (nS * nR);
|
|
2259
2308
|
cosPhi = Math.max(-1, Math.min(1, cosPhi));
|
|
2260
|
-
const zeta =
|
|
2309
|
+
const zeta = cross2(dS, dR);
|
|
2261
2310
|
const sign = dot(k, zeta) >= 0 ? 1 : -1;
|
|
2262
2311
|
const dphi = sign * Math.acos(cosPhi) / (2 * Math.PI);
|
|
2263
2312
|
const prev = state.get(prn);
|
|
@@ -2395,13 +2444,35 @@ function ifCoeffs(f1, f2) {
|
|
|
2395
2444
|
const lambdaIf = C_LIGHT / (f1 + f2);
|
|
2396
2445
|
return { g, lambdaIf };
|
|
2397
2446
|
}
|
|
2447
|
+
var Sp3EphemerisSource = class {
|
|
2448
|
+
constructor(sp3, clk) {
|
|
2449
|
+
this.sp3 = sp3;
|
|
2450
|
+
this.clk = clk;
|
|
2451
|
+
}
|
|
2452
|
+
satState(prn, tEmitMs) {
|
|
2453
|
+
const p = sp3Position(this.sp3, prn, tEmitMs);
|
|
2454
|
+
if (!p || p.clk == null) return null;
|
|
2455
|
+
const pPlus = sp3Position(this.sp3, prn, tEmitMs + 500);
|
|
2456
|
+
const pMinus = sp3Position(this.sp3, prn, tEmitMs - 500);
|
|
2457
|
+
let vx = 0;
|
|
2458
|
+
let vy = 0;
|
|
2459
|
+
let vz = 0;
|
|
2460
|
+
if (pPlus && pMinus) {
|
|
2461
|
+
vx = pPlus.x - pMinus.x;
|
|
2462
|
+
vy = pPlus.y - pMinus.y;
|
|
2463
|
+
vz = pPlus.z - pMinus.z;
|
|
2464
|
+
}
|
|
2465
|
+
const clkS = (this.clk ? clkBias(this.clk, prn, tEmitMs) : null) ?? p.clk;
|
|
2466
|
+
return { x: p.x, y: p.y, z: p.z, vx, vy, vz, clkS };
|
|
2467
|
+
}
|
|
2468
|
+
};
|
|
2398
2469
|
function sagnacRotate(x, y, z, travelS) {
|
|
2399
2470
|
const theta = OMEGA_E * travelS;
|
|
2400
2471
|
const c = Math.cos(theta);
|
|
2401
2472
|
const s = Math.sin(theta);
|
|
2402
2473
|
return [x * c + y * s, -x * s + y * c, z];
|
|
2403
2474
|
}
|
|
2404
|
-
function satStateAtEmission(
|
|
2475
|
+
function satStateAtEmission(source, prn, recvTimeMs, rcv) {
|
|
2405
2476
|
let travelS = 0.075;
|
|
2406
2477
|
let sx = 0;
|
|
2407
2478
|
let sy = 0;
|
|
@@ -2410,18 +2481,11 @@ function satStateAtEmission(sp3, prn, recvTimeMs, rcv, clk) {
|
|
|
2410
2481
|
let velDotPos = 0;
|
|
2411
2482
|
for (let iter = 0; iter < 3; iter++) {
|
|
2412
2483
|
const tEmit = recvTimeMs - travelS * 1e3;
|
|
2413
|
-
const
|
|
2414
|
-
if (!
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
const vx = (pPlus.x - pMinus.x) / 1;
|
|
2419
|
-
const vy = (pPlus.y - pMinus.y) / 1;
|
|
2420
|
-
const vz = (pPlus.z - pMinus.z) / 1;
|
|
2421
|
-
velDotPos = p.x * vx + p.y * vy + p.z * vz;
|
|
2422
|
-
}
|
|
2423
|
-
clkS = (clk && clkBias(clk, prn, tEmit)) ?? p.clk;
|
|
2424
|
-
const [rx, ry, rz] = sagnacRotate(p.x, p.y, p.z, travelS);
|
|
2484
|
+
const s = source.satState(prn, tEmit);
|
|
2485
|
+
if (!s) return null;
|
|
2486
|
+
velDotPos = s.x * s.vx + s.y * s.vy + s.z * s.vz;
|
|
2487
|
+
clkS = s.clkS;
|
|
2488
|
+
const [rx, ry, rz] = sagnacRotate(s.x, s.y, s.z, travelS);
|
|
2425
2489
|
sx = rx;
|
|
2426
2490
|
sy = ry;
|
|
2427
2491
|
sz = rz;
|
|
@@ -2443,39 +2507,72 @@ var IDX_ZWD = 3;
|
|
|
2443
2507
|
var NBASE = 4;
|
|
2444
2508
|
var CLK_VAR = 1e10;
|
|
2445
2509
|
var POS_VAR = 60 * 60;
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2510
|
+
var PppEngine = class {
|
|
2511
|
+
source;
|
|
2512
|
+
opts;
|
|
2513
|
+
elevMask;
|
|
2514
|
+
codeSigma;
|
|
2515
|
+
phaseSigma;
|
|
2516
|
+
ztdQ;
|
|
2517
|
+
kinematic;
|
|
2518
|
+
corrections;
|
|
2519
|
+
truth;
|
|
2520
|
+
// Filter state (reset() initialises; mutated in place across epochs).
|
|
2521
|
+
x;
|
|
2522
|
+
P;
|
|
2523
|
+
clkIdx;
|
|
2524
|
+
clockSeeded;
|
|
2525
|
+
ambIdx;
|
|
2526
|
+
lastSeen;
|
|
2527
|
+
arcs;
|
|
2528
|
+
arcSnap;
|
|
2529
|
+
mwState;
|
|
2530
|
+
series;
|
|
2531
|
+
ei = 0;
|
|
2532
|
+
t0 = 0;
|
|
2533
|
+
convergenceSec = null;
|
|
2534
|
+
convergedStreak = 0;
|
|
2535
|
+
constructor(opts, source) {
|
|
2536
|
+
this.opts = opts;
|
|
2537
|
+
this.source = source;
|
|
2538
|
+
this.elevMask = (opts.elevationMaskDeg ?? 10) * Math.PI / 180;
|
|
2539
|
+
this.codeSigma = opts.codeSigma ?? 3;
|
|
2540
|
+
this.phaseSigma = opts.phaseSigma ?? 0.01;
|
|
2541
|
+
this.ztdQ = opts.ztdProcessNoise ?? 1e-8;
|
|
2542
|
+
this.kinematic = opts.mode === "kinematic";
|
|
2543
|
+
this.corrections = opts.corrections;
|
|
2544
|
+
this.truth = opts.groundTruth;
|
|
2545
|
+
this.reset();
|
|
2546
|
+
}
|
|
2547
|
+
/** Reinitialise the filter (fresh session). */
|
|
2548
|
+
reset() {
|
|
2549
|
+
const { opts } = this;
|
|
2550
|
+
this.x = [opts.aprioriPos[0], opts.aprioriPos[1], opts.aprioriPos[2], 0.1];
|
|
2551
|
+
const P = [];
|
|
2552
|
+
for (let i = 0; i < NBASE; i++) P.push(new Array(NBASE).fill(0));
|
|
2553
|
+
P[IDX_X][IDX_X] = 100 * 100;
|
|
2554
|
+
P[IDX_Y][IDX_Y] = 100 * 100;
|
|
2555
|
+
P[IDX_Z][IDX_Z] = 100 * 100;
|
|
2556
|
+
P[IDX_ZWD][IDX_ZWD] = 0.5 * 0.5;
|
|
2557
|
+
this.P = P;
|
|
2558
|
+
this.clkIdx = /* @__PURE__ */ new Map();
|
|
2559
|
+
this.clockSeeded = /* @__PURE__ */ new Set();
|
|
2560
|
+
this.ambIdx = /* @__PURE__ */ new Map();
|
|
2561
|
+
this.lastSeen = /* @__PURE__ */ new Map();
|
|
2562
|
+
this.arcs = [];
|
|
2563
|
+
this.arcSnap = /* @__PURE__ */ new Map();
|
|
2564
|
+
this.mwState = /* @__PURE__ */ new Map();
|
|
2565
|
+
this.series = [];
|
|
2566
|
+
this.ei = 0;
|
|
2567
|
+
this.t0 = 0;
|
|
2568
|
+
this.convergenceSec = null;
|
|
2569
|
+
this.convergedStreak = 0;
|
|
2570
|
+
}
|
|
2571
|
+
flushArc(prn, minEpochs = 10) {
|
|
2572
|
+
const s = this.arcSnap.get(prn);
|
|
2573
|
+
this.arcSnap.delete(prn);
|
|
2477
2574
|
if (!s || s.nEpochs < minEpochs) return;
|
|
2478
|
-
arcs.push({
|
|
2575
|
+
this.arcs.push({
|
|
2479
2576
|
prn,
|
|
2480
2577
|
aIF: s.aIF,
|
|
2481
2578
|
mwCyc: s.mwCyc,
|
|
@@ -2486,64 +2583,88 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
2486
2583
|
startMs: s.startMs,
|
|
2487
2584
|
endMs: s.endMs
|
|
2488
2585
|
});
|
|
2489
|
-
}
|
|
2490
|
-
|
|
2491
|
-
|
|
2586
|
+
}
|
|
2587
|
+
/** Detect a cycle slip via the Melbourne–Wübbena wide-lane ambiguity. */
|
|
2588
|
+
detectSlip(o, ei) {
|
|
2492
2589
|
const lamW = C_LIGHT / (o.f1 - o.f2);
|
|
2493
2590
|
const lw = o.l1 - o.l2;
|
|
2494
2591
|
const pn = (o.f1 * o.c1 + o.f2 * o.c2) / (o.f1 + o.f2);
|
|
2495
2592
|
const mw = lw - pn / lamW;
|
|
2496
|
-
const st = mwState.get(o.prn);
|
|
2593
|
+
const st = this.mwState.get(o.prn);
|
|
2497
2594
|
let slip = o.slip;
|
|
2498
2595
|
if (!st || ei - st.lastEi > 2)
|
|
2499
2596
|
slip = true;
|
|
2500
2597
|
else if (Math.abs(mw - st.mean) > 4) slip = true;
|
|
2501
|
-
if (slip) mwState.set(o.prn, { mean: mw, n: 1, lastEi: ei });
|
|
2598
|
+
if (slip) this.mwState.set(o.prn, { mean: mw, n: 1, lastEi: ei });
|
|
2502
2599
|
else {
|
|
2503
2600
|
const n = st.n + 1;
|
|
2504
|
-
mwState.set(o.prn, {
|
|
2601
|
+
this.mwState.set(o.prn, {
|
|
2505
2602
|
mean: st.mean + (mw - st.mean) / Math.min(n, 100),
|
|
2506
2603
|
n,
|
|
2507
2604
|
lastEi: ei
|
|
2508
2605
|
});
|
|
2509
2606
|
}
|
|
2510
2607
|
return slip;
|
|
2511
|
-
}
|
|
2512
|
-
|
|
2513
|
-
const idx = x.length;
|
|
2514
|
-
x.push(initVal);
|
|
2515
|
-
for (const row of P) row.push(0);
|
|
2516
|
-
P.push(new Array(x.length).fill(0));
|
|
2517
|
-
P[idx][idx] = initVar;
|
|
2608
|
+
}
|
|
2609
|
+
growState(initVal, initVar) {
|
|
2610
|
+
const idx = this.x.length;
|
|
2611
|
+
this.x.push(initVal);
|
|
2612
|
+
for (const row of this.P) row.push(0);
|
|
2613
|
+
this.P.push(new Array(this.x.length).fill(0));
|
|
2614
|
+
this.P[idx][idx] = initVar;
|
|
2518
2615
|
return idx;
|
|
2519
|
-
}
|
|
2520
|
-
|
|
2521
|
-
x.splice(idx, 1);
|
|
2522
|
-
P.splice(idx, 1);
|
|
2523
|
-
for (const row of P) row.splice(idx, 1);
|
|
2524
|
-
for (const [prn, i] of ambIdx) {
|
|
2525
|
-
if (i === idx) ambIdx.delete(prn);
|
|
2526
|
-
else if (i > idx) ambIdx.set(prn, i - 1);
|
|
2616
|
+
}
|
|
2617
|
+
dropState(idx) {
|
|
2618
|
+
this.x.splice(idx, 1);
|
|
2619
|
+
this.P.splice(idx, 1);
|
|
2620
|
+
for (const row of this.P) row.splice(idx, 1);
|
|
2621
|
+
for (const [prn, i] of this.ambIdx) {
|
|
2622
|
+
if (i === idx) this.ambIdx.delete(prn);
|
|
2623
|
+
else if (i > idx) this.ambIdx.set(prn, i - 1);
|
|
2527
2624
|
}
|
|
2528
|
-
for (const [sys, i] of clkIdx) {
|
|
2529
|
-
if (i > idx) clkIdx.set(sys, i - 1);
|
|
2625
|
+
for (const [sys, i] of this.clkIdx) {
|
|
2626
|
+
if (i > idx) this.clkIdx.set(sys, i - 1);
|
|
2530
2627
|
}
|
|
2531
|
-
}
|
|
2532
|
-
|
|
2533
|
-
|
|
2628
|
+
}
|
|
2629
|
+
/** State index of a constellation's receiver clock, creating it lazily. */
|
|
2630
|
+
clockOf(sys) {
|
|
2631
|
+
let i = this.clkIdx.get(sys);
|
|
2534
2632
|
if (i === void 0) {
|
|
2535
|
-
i = growState(0, CLK_VAR);
|
|
2536
|
-
clkIdx.set(sys, i);
|
|
2633
|
+
i = this.growState(0, CLK_VAR);
|
|
2634
|
+
this.clkIdx.set(sys, i);
|
|
2537
2635
|
}
|
|
2538
2636
|
return i;
|
|
2539
|
-
}
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2637
|
+
}
|
|
2638
|
+
/** Process one epoch, carrying the filter forward; returns its result. */
|
|
2639
|
+
process(epoch) {
|
|
2640
|
+
const {
|
|
2641
|
+
source,
|
|
2642
|
+
opts,
|
|
2643
|
+
elevMask,
|
|
2644
|
+
codeSigma,
|
|
2645
|
+
phaseSigma,
|
|
2646
|
+
ztdQ,
|
|
2647
|
+
kinematic,
|
|
2648
|
+
corrections,
|
|
2649
|
+
truth,
|
|
2650
|
+
x,
|
|
2651
|
+
P,
|
|
2652
|
+
clkIdx,
|
|
2653
|
+
clockSeeded,
|
|
2654
|
+
ambIdx,
|
|
2655
|
+
lastSeen,
|
|
2656
|
+
arcSnap,
|
|
2657
|
+
mwState,
|
|
2658
|
+
series
|
|
2659
|
+
} = this;
|
|
2660
|
+
const flushArc = this.flushArc.bind(this);
|
|
2661
|
+
const detectSlip = this.detectSlip.bind(this);
|
|
2662
|
+
const growState = this.growState.bind(this);
|
|
2663
|
+
const dropState = this.dropState.bind(this);
|
|
2664
|
+
const clockOf = this.clockOf.bind(this);
|
|
2665
|
+
const ei = this.ei;
|
|
2666
|
+
if (ei === 0) this.t0 = epoch.timeMs;
|
|
2667
|
+
const t0 = this.t0;
|
|
2547
2668
|
if (kinematic && ei > 0) {
|
|
2548
2669
|
for (const p of [IDX_X, IDX_Y, IDX_Z]) {
|
|
2549
2670
|
for (let j = 0; j < x.length; j++) {
|
|
@@ -2564,7 +2685,7 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
2564
2685
|
for (const o of epoch.obs) {
|
|
2565
2686
|
if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
|
|
2566
2687
|
const slip = detectSlip(o, ei);
|
|
2567
|
-
const sat = satStateAtEmission(
|
|
2688
|
+
const sat = satStateAtEmission(source, o.prn, epoch.timeMs, rcv);
|
|
2568
2689
|
if (!sat) continue;
|
|
2569
2690
|
const [elRad, azRad] = getAer(
|
|
2570
2691
|
sat.state.x,
|
|
@@ -2584,7 +2705,9 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
2584
2705
|
const lam1 = C_LIGHT / o.f1;
|
|
2585
2706
|
const lam2 = C_LIGHT / o.f2;
|
|
2586
2707
|
if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
|
|
2587
|
-
const
|
|
2708
|
+
const b1 = source.codeBias?.(o.prn, o.code1 ?? "", epoch.timeMs) ?? 0;
|
|
2709
|
+
const b2 = source.codeBias?.(o.prn, o.code2 ?? "", epoch.timeMs) ?? 0;
|
|
2710
|
+
const pIf = g * (o.c1 - b1) - (g - 1) * (o.c2 - b2);
|
|
2588
2711
|
const lIf = g * (o.l1 * lam1) - (g - 1) * (o.l2 * lam2);
|
|
2589
2712
|
if (!Number.isFinite(pIf) || !Number.isFinite(lIf)) continue;
|
|
2590
2713
|
const trop = opts.troposphere ?? true ? niellMapping(elRad, latRad, heightM, epoch.timeMs) : { zhd: 0, mh: 0, mw: 0 };
|
|
@@ -2771,16 +2894,16 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
2771
2894
|
pos[2] - truth[2]
|
|
2772
2895
|
);
|
|
2773
2896
|
if (error3d < 0.1) {
|
|
2774
|
-
convergedStreak++;
|
|
2775
|
-
if (convergedStreak >= 10 && convergenceSec == null) {
|
|
2776
|
-
convergenceSec = (epoch.timeMs - t0) / 1e3;
|
|
2897
|
+
this.convergedStreak++;
|
|
2898
|
+
if (this.convergedStreak >= 10 && this.convergenceSec == null) {
|
|
2899
|
+
this.convergenceSec = (epoch.timeMs - t0) / 1e3;
|
|
2777
2900
|
}
|
|
2778
2901
|
} else {
|
|
2779
|
-
convergedStreak = 0;
|
|
2780
|
-
convergenceSec = null;
|
|
2902
|
+
this.convergedStreak = 0;
|
|
2903
|
+
this.convergenceSec = null;
|
|
2781
2904
|
}
|
|
2782
2905
|
}
|
|
2783
|
-
|
|
2906
|
+
const result = {
|
|
2784
2907
|
timeMs: epoch.timeMs,
|
|
2785
2908
|
enu,
|
|
2786
2909
|
error3d,
|
|
@@ -2789,50 +2912,68 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
2789
2912
|
ztdWet: x[IDX_ZWD],
|
|
2790
2913
|
ztdHydrostatic: epochZhd,
|
|
2791
2914
|
phaseResRms: nPhaseRes > 0 ? Math.sqrt(sumPhaseResSq / nPhaseRes) : 0
|
|
2792
|
-
}
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2915
|
+
};
|
|
2916
|
+
series.push(result);
|
|
2917
|
+
this.ei = ei + 1;
|
|
2918
|
+
return result;
|
|
2919
|
+
}
|
|
2920
|
+
/** Finalise the session: capture the AR state, flush open arcs, assemble. */
|
|
2921
|
+
solution() {
|
|
2922
|
+
const { opts, x, P, ambIdx, arcSnap, mwState, arcs, series, truth } = this;
|
|
2923
|
+
const flushArc = this.flushArc.bind(this);
|
|
2924
|
+
let finalState;
|
|
2925
|
+
if (opts.exposeState) {
|
|
2926
|
+
const ambs = [];
|
|
2927
|
+
for (const [prn, index] of ambIdx) {
|
|
2928
|
+
const s = arcSnap.get(prn);
|
|
2929
|
+
if (!s || s.nEpochs < 10) continue;
|
|
2930
|
+
ambs.push({
|
|
2931
|
+
prn,
|
|
2932
|
+
index,
|
|
2933
|
+
aIF: x[index],
|
|
2934
|
+
mwCyc: mwState.get(prn)?.mean ?? s.mwCyc,
|
|
2935
|
+
f1: s.f1,
|
|
2936
|
+
f2: s.f2,
|
|
2937
|
+
elevDeg: s.elevSum / s.nEpochs
|
|
2938
|
+
});
|
|
2939
|
+
}
|
|
2940
|
+
finalState = {
|
|
2941
|
+
position: [x[IDX_X], x[IDX_Y], x[IDX_Z]],
|
|
2942
|
+
covariance: P.map((row) => row.slice()),
|
|
2943
|
+
ambiguities: ambs
|
|
2944
|
+
};
|
|
2809
2945
|
}
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2946
|
+
for (const prn of [...arcSnap.keys()]) flushArc(prn);
|
|
2947
|
+
const finalPos = [
|
|
2948
|
+
x[IDX_X],
|
|
2949
|
+
x[IDX_Y],
|
|
2950
|
+
x[IDX_Z]
|
|
2951
|
+
];
|
|
2952
|
+
const llh = ecefToGeodetic(finalPos[0], finalPos[1], finalPos[2]);
|
|
2953
|
+
const finalError3d = truth ? Math.hypot(
|
|
2954
|
+
finalPos[0] - truth[0],
|
|
2955
|
+
finalPos[1] - truth[1],
|
|
2956
|
+
finalPos[2] - truth[2]
|
|
2957
|
+
) : null;
|
|
2958
|
+
return {
|
|
2959
|
+
position: finalPos,
|
|
2960
|
+
llh,
|
|
2961
|
+
series,
|
|
2962
|
+
ztdWet: x[IDX_ZWD],
|
|
2963
|
+
ztdHydrostatic: series.length ? series[series.length - 1].ztdHydrostatic : 0,
|
|
2964
|
+
epochsUsed: series.length,
|
|
2965
|
+
convergenceSec: this.convergenceSec,
|
|
2966
|
+
finalError3d,
|
|
2967
|
+
arcs,
|
|
2968
|
+
finalState
|
|
2814
2969
|
};
|
|
2815
2970
|
}
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
const
|
|
2819
|
-
const
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
finalPos[2] - truth[2]
|
|
2823
|
-
) : null;
|
|
2824
|
-
return {
|
|
2825
|
-
position: finalPos,
|
|
2826
|
-
llh,
|
|
2827
|
-
series,
|
|
2828
|
-
ztdWet: x[IDX_ZWD],
|
|
2829
|
-
ztdHydrostatic: series.length ? series[series.length - 1].ztdHydrostatic : 0,
|
|
2830
|
-
epochsUsed: epochs.length,
|
|
2831
|
-
convergenceSec,
|
|
2832
|
-
finalError3d,
|
|
2833
|
-
arcs,
|
|
2834
|
-
finalState
|
|
2835
|
-
};
|
|
2971
|
+
};
|
|
2972
|
+
function solvePpp(epochs, sp3OrSource, opts) {
|
|
2973
|
+
const source = "satState" in sp3OrSource ? sp3OrSource : new Sp3EphemerisSource(sp3OrSource, opts.clk);
|
|
2974
|
+
const eng = new PppEngine(opts, source);
|
|
2975
|
+
for (const epoch of epochs) eng.process(epoch);
|
|
2976
|
+
return eng.solution();
|
|
2836
2977
|
}
|
|
2837
2978
|
|
|
2838
2979
|
// src/positioning/ppp-ar.ts
|
|
@@ -3580,6 +3721,8 @@ export {
|
|
|
3580
3721
|
sbasLongTermDeg,
|
|
3581
3722
|
sbasIonoDeg,
|
|
3582
3723
|
SbasProcessor,
|
|
3724
|
+
applyOrbitClock,
|
|
3725
|
+
hasToOrbitClock,
|
|
3583
3726
|
niellMapping,
|
|
3584
3727
|
gmst,
|
|
3585
3728
|
sunEcef,
|
|
@@ -3587,6 +3730,8 @@ export {
|
|
|
3587
3730
|
solidEarthTide,
|
|
3588
3731
|
buildPppAntenna,
|
|
3589
3732
|
createPppCorrections,
|
|
3733
|
+
Sp3EphemerisSource,
|
|
3734
|
+
PppEngine,
|
|
3590
3735
|
solvePpp,
|
|
3591
3736
|
wlWavelength,
|
|
3592
3737
|
nlWavelength,
|
|
@@ -1839,7 +1839,8 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
1839
1839
|
stats.satellites.set(obs.prn, {
|
|
1840
1840
|
prn: obs.prn,
|
|
1841
1841
|
system: obs.system,
|
|
1842
|
-
cn0: bestCn0,
|
|
1842
|
+
cn0: bestCn0 > 0 ? bestCn0 : null,
|
|
1843
|
+
// null = no C/N0 reported
|
|
1843
1844
|
lastSeen: now,
|
|
1844
1845
|
signals
|
|
1845
1846
|
});
|