gnss-js 1.30.0 → 1.32.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-KDM2NVBO.js → chunk-5RNDQQ6J.js} +81 -0
- package/dist/{chunk-CRFFUU5Y.js → chunk-HOH27N42.js} +211 -0
- package/dist/index.cjs +297 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +19 -3
- package/dist/positioning.cjs +218 -2
- package/dist/positioning.d.cts +167 -1
- package/dist/positioning.d.ts +167 -1
- package/dist/positioning.js +13 -3
- package/dist/rinex.cjs +82 -0
- package/dist/rinex.d.cts +49 -1
- package/dist/rinex.d.ts +49 -1
- package/dist/rinex.js +7 -1
- package/package.json +1 -1
|
@@ -5,6 +5,9 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
GPS_PI
|
|
7
7
|
} from "./chunk-IQ5OIMQD.js";
|
|
8
|
+
import {
|
|
9
|
+
C_LIGHT
|
|
10
|
+
} from "./chunk-FIEWO4J4.js";
|
|
8
11
|
|
|
9
12
|
// src/rinex/crx-writer.ts
|
|
10
13
|
var ARC_ORDER = 3;
|
|
@@ -1417,6 +1420,81 @@ function parseIonex(text) {
|
|
|
1417
1420
|
return { epochs, lats, lons, maps };
|
|
1418
1421
|
}
|
|
1419
1422
|
|
|
1423
|
+
// src/rinex/bias-sinex.ts
|
|
1424
|
+
function parseEpoch(s, openTo) {
|
|
1425
|
+
const m = /^(\d{4}):(\d{3}):(\d{5})$/.exec(s.trim());
|
|
1426
|
+
if (!m) return openTo;
|
|
1427
|
+
const y = +m[1];
|
|
1428
|
+
if (y === 0) return openTo;
|
|
1429
|
+
const doy = +m[2];
|
|
1430
|
+
const sod = +m[3];
|
|
1431
|
+
return Date.UTC(y, 0, 1) + (doy - 1) * 864e5 + sod * 1e3;
|
|
1432
|
+
}
|
|
1433
|
+
function parseBiasSinex(text) {
|
|
1434
|
+
const records = [];
|
|
1435
|
+
let inBlock = false;
|
|
1436
|
+
for (const line of text.split("\n")) {
|
|
1437
|
+
if (line.startsWith("+BIAS/SOLUTION")) {
|
|
1438
|
+
inBlock = true;
|
|
1439
|
+
continue;
|
|
1440
|
+
}
|
|
1441
|
+
if (line.startsWith("-BIAS/SOLUTION")) {
|
|
1442
|
+
inBlock = false;
|
|
1443
|
+
continue;
|
|
1444
|
+
}
|
|
1445
|
+
if (!inBlock || line.length < 65 || line.startsWith("*")) continue;
|
|
1446
|
+
const type = line.slice(1, 4).trim();
|
|
1447
|
+
if (type !== "DSB" && type !== "OSB" && type !== "ISB") continue;
|
|
1448
|
+
const prn = line.slice(11, 14).trim();
|
|
1449
|
+
const station = line.slice(15, 24).trim();
|
|
1450
|
+
const obs1 = line.slice(25, 29).trim();
|
|
1451
|
+
const obs2 = line.slice(30, 34).trim();
|
|
1452
|
+
const startMs = parseEpoch(line.slice(35, 49), -Infinity);
|
|
1453
|
+
const endMs = parseEpoch(line.slice(50, 64), Infinity);
|
|
1454
|
+
const tail = line.slice(65).trim().split(/\s+/);
|
|
1455
|
+
if (tail.length < 2) continue;
|
|
1456
|
+
const unit = tail[0];
|
|
1457
|
+
const value = Number(tail[1]);
|
|
1458
|
+
if (!Number.isFinite(value)) continue;
|
|
1459
|
+
records.push({
|
|
1460
|
+
type,
|
|
1461
|
+
prn,
|
|
1462
|
+
station,
|
|
1463
|
+
obs1,
|
|
1464
|
+
obs2,
|
|
1465
|
+
startMs,
|
|
1466
|
+
endMs,
|
|
1467
|
+
value,
|
|
1468
|
+
unit
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
const bySat = /* @__PURE__ */ new Map();
|
|
1472
|
+
for (const r of records) {
|
|
1473
|
+
if (!r.prn || r.station) continue;
|
|
1474
|
+
let a = bySat.get(r.prn);
|
|
1475
|
+
if (!a) {
|
|
1476
|
+
a = [];
|
|
1477
|
+
bySat.set(r.prn, a);
|
|
1478
|
+
}
|
|
1479
|
+
a.push(r);
|
|
1480
|
+
}
|
|
1481
|
+
return { records, bySat };
|
|
1482
|
+
}
|
|
1483
|
+
function biasMetres(r) {
|
|
1484
|
+
return r.unit === "ns" ? r.value * 1e-9 * C_LIGHT : r.value;
|
|
1485
|
+
}
|
|
1486
|
+
function findSatBias(bias, prn, obs1, obs2, tMs) {
|
|
1487
|
+
const recs = bias.bySat.get(prn);
|
|
1488
|
+
if (!recs) return null;
|
|
1489
|
+
for (const r of recs) {
|
|
1490
|
+
if (r.obs1 !== obs1) continue;
|
|
1491
|
+
if (obs2 === void 0 ? r.obs2 !== "" : r.obs2 !== obs2) continue;
|
|
1492
|
+
if (tMs != null && (tMs < r.startMs || tMs > r.endMs)) continue;
|
|
1493
|
+
return r;
|
|
1494
|
+
}
|
|
1495
|
+
return null;
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1420
1498
|
// src/rinex/obs-writer-common.ts
|
|
1421
1499
|
function createGzipLineSink() {
|
|
1422
1500
|
const encoder = new TextEncoder();
|
|
@@ -1804,6 +1882,9 @@ export {
|
|
|
1804
1882
|
writeRinexNav,
|
|
1805
1883
|
writeRinexNav4,
|
|
1806
1884
|
parseIonex,
|
|
1885
|
+
parseBiasSinex,
|
|
1886
|
+
biasMetres,
|
|
1887
|
+
findSatBias,
|
|
1807
1888
|
createGzipLineSink,
|
|
1808
1889
|
stationHeaderLines,
|
|
1809
1890
|
writeRinexObsBlob,
|
|
@@ -1911,6 +1911,212 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
1911
1911
|
};
|
|
1912
1912
|
}
|
|
1913
1913
|
|
|
1914
|
+
// src/positioning/ppp-ar.ts
|
|
1915
|
+
function wlWavelength(f1, f2) {
|
|
1916
|
+
return C_LIGHT / (f1 - f2);
|
|
1917
|
+
}
|
|
1918
|
+
function nlWavelength(f1, f2) {
|
|
1919
|
+
return C_LIGHT / (f1 + f2);
|
|
1920
|
+
}
|
|
1921
|
+
function resolvePppAmbiguities(sats, Qaif, opts = {}) {
|
|
1922
|
+
const wlThreshold = opts.wlThreshold ?? 0.25;
|
|
1923
|
+
const ratioThreshold = opts.ratioThreshold ?? 3;
|
|
1924
|
+
const kept = [];
|
|
1925
|
+
const nWl = [];
|
|
1926
|
+
const rejectedWl = [];
|
|
1927
|
+
for (let i = 0; i < sats.length; i++) {
|
|
1928
|
+
const s = sats[i];
|
|
1929
|
+
const wlFloat = s.mwCyc - (s.wlBiasCyc ?? 0);
|
|
1930
|
+
const r = Math.round(wlFloat);
|
|
1931
|
+
if (Math.abs(wlFloat - r) <= wlThreshold) {
|
|
1932
|
+
kept.push(i);
|
|
1933
|
+
nWl.push(r);
|
|
1934
|
+
} else {
|
|
1935
|
+
rejectedWl.push(s.prn);
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
if (kept.length < 2) {
|
|
1939
|
+
return {
|
|
1940
|
+
fixed: false,
|
|
1941
|
+
ratio: 0,
|
|
1942
|
+
refPrn: null,
|
|
1943
|
+
sats: [],
|
|
1944
|
+
rejectedWl
|
|
1945
|
+
};
|
|
1946
|
+
}
|
|
1947
|
+
const n1Float = [];
|
|
1948
|
+
const lamNl = [];
|
|
1949
|
+
for (let k = 0; k < kept.length; k++) {
|
|
1950
|
+
const s = sats[kept[k]];
|
|
1951
|
+
const lNl = nlWavelength(s.f1, s.f2);
|
|
1952
|
+
lamNl.push(lNl);
|
|
1953
|
+
const n1 = s.aIF / lNl - s.f2 / (s.f1 - s.f2) * nWl[k] - (s.nlBiasCyc ?? 0);
|
|
1954
|
+
n1Float.push(n1);
|
|
1955
|
+
}
|
|
1956
|
+
let ref = 0;
|
|
1957
|
+
for (let k = 1; k < kept.length; k++) {
|
|
1958
|
+
const e = sats[kept[k]].elevDeg ?? -1;
|
|
1959
|
+
if (e > (sats[kept[ref]].elevDeg ?? -1)) ref = k;
|
|
1960
|
+
}
|
|
1961
|
+
const m = kept.length - 1;
|
|
1962
|
+
const sd = new Float64Array(m);
|
|
1963
|
+
const Qsd = new Float64Array(m * m);
|
|
1964
|
+
const others = [];
|
|
1965
|
+
for (let k = 0; k < kept.length; k++) if (k !== ref) others.push(k);
|
|
1966
|
+
const n = sats.length;
|
|
1967
|
+
const qN1 = (ka, kb) => Qaif[kept[ka] * n + kept[kb]] / (lamNl[ka] * lamNl[kb]);
|
|
1968
|
+
for (let a = 0; a < m; a++) {
|
|
1969
|
+
const ka = others[a];
|
|
1970
|
+
sd[a] = n1Float[ka] - n1Float[ref];
|
|
1971
|
+
for (let b = 0; b < m; b++) {
|
|
1972
|
+
const kb = others[b];
|
|
1973
|
+
Qsd[a * m + b] = qN1(ka, kb) - qN1(ka, ref) - qN1(ref, kb) + qN1(ref, ref);
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
const res = lambdaSearch(sd, Qsd, m, 2);
|
|
1977
|
+
const ratio = res ? Math.min(res.ratio, 999.9) : 0;
|
|
1978
|
+
const fixed = !!res && ratio >= ratioThreshold;
|
|
1979
|
+
const refN1 = Math.round(n1Float[ref]);
|
|
1980
|
+
const sdFix = res?.candidates[0];
|
|
1981
|
+
const outSats = [];
|
|
1982
|
+
for (let k = 0; k < kept.length; k++) {
|
|
1983
|
+
const s = sats[kept[k]];
|
|
1984
|
+
let n1;
|
|
1985
|
+
if (k === ref) {
|
|
1986
|
+
n1 = refN1;
|
|
1987
|
+
} else {
|
|
1988
|
+
const a = others.indexOf(k);
|
|
1989
|
+
n1 = fixed && sdFix ? refN1 + Math.round(sdFix[a]) : Math.round(n1Float[k]);
|
|
1990
|
+
}
|
|
1991
|
+
const lNl = lamNl[k];
|
|
1992
|
+
const aIF = lNl * n1 + lNl * (s.f2 / (s.f1 - s.f2)) * nWl[k];
|
|
1993
|
+
outSats.push({ prn: s.prn, nWl: nWl[k], n1, aIF });
|
|
1994
|
+
}
|
|
1995
|
+
return {
|
|
1996
|
+
fixed,
|
|
1997
|
+
ratio,
|
|
1998
|
+
refPrn: sats[kept[ref]].prn,
|
|
1999
|
+
sats: outSats,
|
|
2000
|
+
rejectedWl
|
|
2001
|
+
};
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
// src/positioning/ppp-fcb.ts
|
|
2005
|
+
function extractWidelaneArcs(station, epochs, opts = {}) {
|
|
2006
|
+
const slipCyc = opts.slipCyc ?? 4;
|
|
2007
|
+
const gapMs = opts.gapMs ?? 12e4;
|
|
2008
|
+
const minObs = opts.minObs ?? 20;
|
|
2009
|
+
const state = /* @__PURE__ */ new Map();
|
|
2010
|
+
const out = [];
|
|
2011
|
+
const flush = (prn) => {
|
|
2012
|
+
const s = state.get(prn);
|
|
2013
|
+
if (s && s.n >= minObs)
|
|
2014
|
+
out.push({ station, prn, wlFloat: s.sum / s.n, nObs: s.n });
|
|
2015
|
+
};
|
|
2016
|
+
for (const ep of epochs) {
|
|
2017
|
+
for (const o of ep.obs) {
|
|
2018
|
+
if (!o.c1 || !o.c2 || !o.l1 || !o.l2) continue;
|
|
2019
|
+
const lamW = C_LIGHT / (o.f1 - o.f2);
|
|
2020
|
+
const codeNl = (o.f1 * o.c1 + o.f2 * o.c2) / (o.f1 + o.f2);
|
|
2021
|
+
const mw = o.l1 - o.l2 - codeNl / lamW;
|
|
2022
|
+
const s = state.get(o.prn);
|
|
2023
|
+
if (!s || ep.timeMs - s.lastT > gapMs || Math.abs(mw - s.mean) > slipCyc) {
|
|
2024
|
+
if (s) flush(o.prn);
|
|
2025
|
+
state.set(o.prn, { sum: mw, n: 1, mean: mw, lastT: ep.timeMs });
|
|
2026
|
+
} else {
|
|
2027
|
+
s.sum += mw;
|
|
2028
|
+
s.n += 1;
|
|
2029
|
+
s.mean = s.sum / s.n;
|
|
2030
|
+
s.lastT = ep.timeMs;
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
for (const prn of state.keys()) flush(prn);
|
|
2035
|
+
return out;
|
|
2036
|
+
}
|
|
2037
|
+
function wrapHalf(x) {
|
|
2038
|
+
return x - Math.round(x);
|
|
2039
|
+
}
|
|
2040
|
+
function circMean(vals, weights) {
|
|
2041
|
+
let s = 0;
|
|
2042
|
+
let c = 0;
|
|
2043
|
+
for (let i = 0; i < vals.length; i++) {
|
|
2044
|
+
const a = 2 * Math.PI * vals[i];
|
|
2045
|
+
s += weights[i] * Math.sin(a);
|
|
2046
|
+
c += weights[i] * Math.cos(a);
|
|
2047
|
+
}
|
|
2048
|
+
if (s === 0 && c === 0) return 0;
|
|
2049
|
+
return wrapHalf(Math.atan2(s, c) / (2 * Math.PI));
|
|
2050
|
+
}
|
|
2051
|
+
function estimateWidelaneFcb(arcs, opts = {}) {
|
|
2052
|
+
const maxIter = opts.maxIter ?? 50;
|
|
2053
|
+
const tol = opts.tol ?? 1e-4;
|
|
2054
|
+
const fixWindow = opts.fixWindow ?? 0.25;
|
|
2055
|
+
const sats = [...new Set(arcs.map((a) => a.prn))].sort();
|
|
2056
|
+
const stations = [...new Set(arcs.map((a) => a.station))].sort();
|
|
2057
|
+
const refStation = stations[0] ?? "";
|
|
2058
|
+
const satFcb = new Map(sats.map((s) => [s, 0]));
|
|
2059
|
+
const rcvBias = new Map(stations.map((s) => [s, 0]));
|
|
2060
|
+
const nInt = new Array(arcs.length).fill(0);
|
|
2061
|
+
let iterations = 0;
|
|
2062
|
+
for (let it = 0; it < maxIter; it++) {
|
|
2063
|
+
iterations = it + 1;
|
|
2064
|
+
for (let i = 0; i < arcs.length; i++) {
|
|
2065
|
+
const a = arcs[i];
|
|
2066
|
+
nInt[i] = Math.round(
|
|
2067
|
+
a.wlFloat - rcvBias.get(a.station) - satFcb.get(a.prn)
|
|
2068
|
+
);
|
|
2069
|
+
}
|
|
2070
|
+
let maxChange = 0;
|
|
2071
|
+
for (const s of sats) {
|
|
2072
|
+
const vals = [];
|
|
2073
|
+
const w = [];
|
|
2074
|
+
for (let i = 0; i < arcs.length; i++) {
|
|
2075
|
+
const a = arcs[i];
|
|
2076
|
+
if (a.prn !== s) continue;
|
|
2077
|
+
vals.push(a.wlFloat - nInt[i] - rcvBias.get(a.station));
|
|
2078
|
+
w.push(a.nObs);
|
|
2079
|
+
}
|
|
2080
|
+
if (!vals.length) continue;
|
|
2081
|
+
const nv = circMean(vals, w);
|
|
2082
|
+
maxChange = Math.max(maxChange, Math.abs(wrapHalf(nv - satFcb.get(s))));
|
|
2083
|
+
satFcb.set(s, nv);
|
|
2084
|
+
}
|
|
2085
|
+
for (const r of stations) {
|
|
2086
|
+
const vals = [];
|
|
2087
|
+
const w = [];
|
|
2088
|
+
for (let i = 0; i < arcs.length; i++) {
|
|
2089
|
+
const a = arcs[i];
|
|
2090
|
+
if (a.station !== r) continue;
|
|
2091
|
+
vals.push(a.wlFloat - nInt[i] - satFcb.get(a.prn));
|
|
2092
|
+
w.push(a.nObs);
|
|
2093
|
+
}
|
|
2094
|
+
if (!vals.length) continue;
|
|
2095
|
+
rcvBias.set(r, circMean(vals, w));
|
|
2096
|
+
}
|
|
2097
|
+
const shift = rcvBias.get(refStation);
|
|
2098
|
+
if (shift !== 0) {
|
|
2099
|
+
for (const r of stations)
|
|
2100
|
+
rcvBias.set(r, wrapHalf(rcvBias.get(r) - shift));
|
|
2101
|
+
for (const s of sats) satFcb.set(s, wrapHalf(satFcb.get(s) + shift));
|
|
2102
|
+
}
|
|
2103
|
+
if (maxChange < tol) break;
|
|
2104
|
+
}
|
|
2105
|
+
let sumSq = 0;
|
|
2106
|
+
let fixed = 0;
|
|
2107
|
+
for (let i = 0; i < arcs.length; i++) {
|
|
2108
|
+
const a = arcs[i];
|
|
2109
|
+
const resid = wrapHalf(
|
|
2110
|
+
a.wlFloat - nInt[i] - rcvBias.get(a.station) - satFcb.get(a.prn)
|
|
2111
|
+
);
|
|
2112
|
+
sumSq += resid * resid;
|
|
2113
|
+
if (Math.abs(resid) <= fixWindow) fixed++;
|
|
2114
|
+
}
|
|
2115
|
+
const residRms = arcs.length ? Math.sqrt(sumSq / arcs.length) : 0;
|
|
2116
|
+
const fixRate = arcs.length ? fixed / arcs.length : 0;
|
|
2117
|
+
return { satFcb, rcvBias, residRms, fixRate, refStation, iterations };
|
|
2118
|
+
}
|
|
2119
|
+
|
|
1914
2120
|
// src/positioning/index.ts
|
|
1915
2121
|
var GM_GPS = 3986005e8;
|
|
1916
2122
|
var F_REL = -4442807633e-19;
|
|
@@ -2157,6 +2363,11 @@ export {
|
|
|
2157
2363
|
buildPppAntenna,
|
|
2158
2364
|
createPppCorrections,
|
|
2159
2365
|
solvePpp,
|
|
2366
|
+
wlWavelength,
|
|
2367
|
+
nlWavelength,
|
|
2368
|
+
resolvePppAmbiguities,
|
|
2369
|
+
extractWidelaneArcs,
|
|
2370
|
+
estimateWidelaneFcb,
|
|
2160
2371
|
satClockCorrection,
|
|
2161
2372
|
ionoFree,
|
|
2162
2373
|
solveSpp
|
package/dist/index.cjs
CHANGED
|
@@ -111,6 +111,7 @@ __export(src_exports, {
|
|
|
111
111
|
analyzeQuality: () => analyzeQuality,
|
|
112
112
|
applyHelmert: () => applyHelmert,
|
|
113
113
|
applyIonoDcb: () => applyIonoDcb,
|
|
114
|
+
biasMetres: () => biasMetres,
|
|
114
115
|
binexCrc16: () => binexCrc16,
|
|
115
116
|
binexCrc32: () => binexCrc32,
|
|
116
117
|
binexCsum8: () => binexCsum8,
|
|
@@ -148,8 +149,11 @@ __export(src_exports, {
|
|
|
148
149
|
ecefToAzEl: () => ecefToAzEl,
|
|
149
150
|
ecefToGeodetic: () => ecefToGeodetic,
|
|
150
151
|
ephInfoToEphemeris: () => ephInfoToEphemeris,
|
|
152
|
+
estimateWidelaneFcb: () => estimateWidelaneFcb,
|
|
151
153
|
euclidean3D: () => euclidean3D,
|
|
154
|
+
extractWidelaneArcs: () => extractWidelaneArcs,
|
|
152
155
|
fetchSourcetable: () => fetchSourcetable,
|
|
156
|
+
findSatBias: () => findSatBias,
|
|
153
157
|
fmtD: () => fmtD,
|
|
154
158
|
fmtF: () => fmtF,
|
|
155
159
|
formatUTCTime: () => formatUTCTime,
|
|
@@ -232,11 +236,13 @@ __export(src_exports, {
|
|
|
232
236
|
msmEpochToDate: () => msmEpochToDate,
|
|
233
237
|
navTimesFromEph: () => navTimesFromEph,
|
|
234
238
|
niellMapping: () => niellMapping,
|
|
239
|
+
nlWavelength: () => nlWavelength,
|
|
235
240
|
nmeaCoordToDecimal: () => nmeaCoordToDecimal,
|
|
236
241
|
oem4Frames: () => oem4Frames,
|
|
237
242
|
padL: () => padL,
|
|
238
243
|
padR: () => padR,
|
|
239
244
|
parseAntex: () => parseAntex,
|
|
245
|
+
parseBiasSinex: () => parseBiasSinex,
|
|
240
246
|
parseBinex: () => parseBinex,
|
|
241
247
|
parseClk: () => parseClk,
|
|
242
248
|
parseCrxDataLine: () => parseCrxDataLine,
|
|
@@ -274,6 +280,7 @@ __export(src_exports, {
|
|
|
274
280
|
readString: () => readString,
|
|
275
281
|
reportDecodeError: () => reportDecodeError,
|
|
276
282
|
resetGloFreqCache: () => resetGloFreqCache,
|
|
283
|
+
resolvePppAmbiguities: () => resolvePppAmbiguities,
|
|
277
284
|
rhumbLine: () => rhumbLine,
|
|
278
285
|
rtcm3Constellation: () => rtcm3Constellation,
|
|
279
286
|
satClockCorrection: () => satClockCorrection,
|
|
@@ -299,6 +306,7 @@ __export(src_exports, {
|
|
|
299
306
|
updateStreamStats: () => updateStreamStats,
|
|
300
307
|
verifyChecksum: () => verifyChecksum,
|
|
301
308
|
vincenty: () => vincenty,
|
|
309
|
+
wlWavelength: () => wlWavelength,
|
|
302
310
|
writeCrx: () => writeCrx,
|
|
303
311
|
writeModernObsBlob: () => writeModernObsBlob,
|
|
304
312
|
writeRinex2ObsBlob: () => writeRinex2ObsBlob,
|
|
@@ -3958,6 +3966,81 @@ function clkBias(clk, prn, tMs) {
|
|
|
3958
3966
|
return c[lo] + f * (c[lo + 1] - c[lo]);
|
|
3959
3967
|
}
|
|
3960
3968
|
|
|
3969
|
+
// src/rinex/bias-sinex.ts
|
|
3970
|
+
function parseEpoch(s, openTo) {
|
|
3971
|
+
const m = /^(\d{4}):(\d{3}):(\d{5})$/.exec(s.trim());
|
|
3972
|
+
if (!m) return openTo;
|
|
3973
|
+
const y = +m[1];
|
|
3974
|
+
if (y === 0) return openTo;
|
|
3975
|
+
const doy = +m[2];
|
|
3976
|
+
const sod = +m[3];
|
|
3977
|
+
return Date.UTC(y, 0, 1) + (doy - 1) * 864e5 + sod * 1e3;
|
|
3978
|
+
}
|
|
3979
|
+
function parseBiasSinex(text) {
|
|
3980
|
+
const records = [];
|
|
3981
|
+
let inBlock = false;
|
|
3982
|
+
for (const line of text.split("\n")) {
|
|
3983
|
+
if (line.startsWith("+BIAS/SOLUTION")) {
|
|
3984
|
+
inBlock = true;
|
|
3985
|
+
continue;
|
|
3986
|
+
}
|
|
3987
|
+
if (line.startsWith("-BIAS/SOLUTION")) {
|
|
3988
|
+
inBlock = false;
|
|
3989
|
+
continue;
|
|
3990
|
+
}
|
|
3991
|
+
if (!inBlock || line.length < 65 || line.startsWith("*")) continue;
|
|
3992
|
+
const type = line.slice(1, 4).trim();
|
|
3993
|
+
if (type !== "DSB" && type !== "OSB" && type !== "ISB") continue;
|
|
3994
|
+
const prn = line.slice(11, 14).trim();
|
|
3995
|
+
const station = line.slice(15, 24).trim();
|
|
3996
|
+
const obs1 = line.slice(25, 29).trim();
|
|
3997
|
+
const obs2 = line.slice(30, 34).trim();
|
|
3998
|
+
const startMs = parseEpoch(line.slice(35, 49), -Infinity);
|
|
3999
|
+
const endMs = parseEpoch(line.slice(50, 64), Infinity);
|
|
4000
|
+
const tail = line.slice(65).trim().split(/\s+/);
|
|
4001
|
+
if (tail.length < 2) continue;
|
|
4002
|
+
const unit = tail[0];
|
|
4003
|
+
const value = Number(tail[1]);
|
|
4004
|
+
if (!Number.isFinite(value)) continue;
|
|
4005
|
+
records.push({
|
|
4006
|
+
type,
|
|
4007
|
+
prn,
|
|
4008
|
+
station,
|
|
4009
|
+
obs1,
|
|
4010
|
+
obs2,
|
|
4011
|
+
startMs,
|
|
4012
|
+
endMs,
|
|
4013
|
+
value,
|
|
4014
|
+
unit
|
|
4015
|
+
});
|
|
4016
|
+
}
|
|
4017
|
+
const bySat = /* @__PURE__ */ new Map();
|
|
4018
|
+
for (const r of records) {
|
|
4019
|
+
if (!r.prn || r.station) continue;
|
|
4020
|
+
let a = bySat.get(r.prn);
|
|
4021
|
+
if (!a) {
|
|
4022
|
+
a = [];
|
|
4023
|
+
bySat.set(r.prn, a);
|
|
4024
|
+
}
|
|
4025
|
+
a.push(r);
|
|
4026
|
+
}
|
|
4027
|
+
return { records, bySat };
|
|
4028
|
+
}
|
|
4029
|
+
function biasMetres(r) {
|
|
4030
|
+
return r.unit === "ns" ? r.value * 1e-9 * C_LIGHT : r.value;
|
|
4031
|
+
}
|
|
4032
|
+
function findSatBias(bias, prn, obs1, obs2, tMs) {
|
|
4033
|
+
const recs = bias.bySat.get(prn);
|
|
4034
|
+
if (!recs) return null;
|
|
4035
|
+
for (const r of recs) {
|
|
4036
|
+
if (r.obs1 !== obs1) continue;
|
|
4037
|
+
if (obs2 === void 0 ? r.obs2 !== "" : r.obs2 !== obs2) continue;
|
|
4038
|
+
if (tMs != null && (tMs < r.startMs || tMs > r.endMs)) continue;
|
|
4039
|
+
return r;
|
|
4040
|
+
}
|
|
4041
|
+
return null;
|
|
4042
|
+
}
|
|
4043
|
+
|
|
3961
4044
|
// src/rinex/obs-writer-common.ts
|
|
3962
4045
|
function createGzipLineSink() {
|
|
3963
4046
|
const encoder = new TextEncoder();
|
|
@@ -13224,6 +13307,212 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
13224
13307
|
};
|
|
13225
13308
|
}
|
|
13226
13309
|
|
|
13310
|
+
// src/positioning/ppp-ar.ts
|
|
13311
|
+
function wlWavelength(f1, f2) {
|
|
13312
|
+
return C_LIGHT / (f1 - f2);
|
|
13313
|
+
}
|
|
13314
|
+
function nlWavelength(f1, f2) {
|
|
13315
|
+
return C_LIGHT / (f1 + f2);
|
|
13316
|
+
}
|
|
13317
|
+
function resolvePppAmbiguities(sats, Qaif, opts = {}) {
|
|
13318
|
+
const wlThreshold = opts.wlThreshold ?? 0.25;
|
|
13319
|
+
const ratioThreshold = opts.ratioThreshold ?? 3;
|
|
13320
|
+
const kept = [];
|
|
13321
|
+
const nWl = [];
|
|
13322
|
+
const rejectedWl = [];
|
|
13323
|
+
for (let i = 0; i < sats.length; i++) {
|
|
13324
|
+
const s = sats[i];
|
|
13325
|
+
const wlFloat = s.mwCyc - (s.wlBiasCyc ?? 0);
|
|
13326
|
+
const r = Math.round(wlFloat);
|
|
13327
|
+
if (Math.abs(wlFloat - r) <= wlThreshold) {
|
|
13328
|
+
kept.push(i);
|
|
13329
|
+
nWl.push(r);
|
|
13330
|
+
} else {
|
|
13331
|
+
rejectedWl.push(s.prn);
|
|
13332
|
+
}
|
|
13333
|
+
}
|
|
13334
|
+
if (kept.length < 2) {
|
|
13335
|
+
return {
|
|
13336
|
+
fixed: false,
|
|
13337
|
+
ratio: 0,
|
|
13338
|
+
refPrn: null,
|
|
13339
|
+
sats: [],
|
|
13340
|
+
rejectedWl
|
|
13341
|
+
};
|
|
13342
|
+
}
|
|
13343
|
+
const n1Float = [];
|
|
13344
|
+
const lamNl = [];
|
|
13345
|
+
for (let k = 0; k < kept.length; k++) {
|
|
13346
|
+
const s = sats[kept[k]];
|
|
13347
|
+
const lNl = nlWavelength(s.f1, s.f2);
|
|
13348
|
+
lamNl.push(lNl);
|
|
13349
|
+
const n1 = s.aIF / lNl - s.f2 / (s.f1 - s.f2) * nWl[k] - (s.nlBiasCyc ?? 0);
|
|
13350
|
+
n1Float.push(n1);
|
|
13351
|
+
}
|
|
13352
|
+
let ref = 0;
|
|
13353
|
+
for (let k = 1; k < kept.length; k++) {
|
|
13354
|
+
const e = sats[kept[k]].elevDeg ?? -1;
|
|
13355
|
+
if (e > (sats[kept[ref]].elevDeg ?? -1)) ref = k;
|
|
13356
|
+
}
|
|
13357
|
+
const m = kept.length - 1;
|
|
13358
|
+
const sd2 = new Float64Array(m);
|
|
13359
|
+
const Qsd = new Float64Array(m * m);
|
|
13360
|
+
const others = [];
|
|
13361
|
+
for (let k = 0; k < kept.length; k++) if (k !== ref) others.push(k);
|
|
13362
|
+
const n = sats.length;
|
|
13363
|
+
const qN1 = (ka, kb) => Qaif[kept[ka] * n + kept[kb]] / (lamNl[ka] * lamNl[kb]);
|
|
13364
|
+
for (let a = 0; a < m; a++) {
|
|
13365
|
+
const ka = others[a];
|
|
13366
|
+
sd2[a] = n1Float[ka] - n1Float[ref];
|
|
13367
|
+
for (let b = 0; b < m; b++) {
|
|
13368
|
+
const kb = others[b];
|
|
13369
|
+
Qsd[a * m + b] = qN1(ka, kb) - qN1(ka, ref) - qN1(ref, kb) + qN1(ref, ref);
|
|
13370
|
+
}
|
|
13371
|
+
}
|
|
13372
|
+
const res = lambdaSearch(sd2, Qsd, m, 2);
|
|
13373
|
+
const ratio = res ? Math.min(res.ratio, 999.9) : 0;
|
|
13374
|
+
const fixed = !!res && ratio >= ratioThreshold;
|
|
13375
|
+
const refN1 = Math.round(n1Float[ref]);
|
|
13376
|
+
const sdFix = res?.candidates[0];
|
|
13377
|
+
const outSats = [];
|
|
13378
|
+
for (let k = 0; k < kept.length; k++) {
|
|
13379
|
+
const s = sats[kept[k]];
|
|
13380
|
+
let n1;
|
|
13381
|
+
if (k === ref) {
|
|
13382
|
+
n1 = refN1;
|
|
13383
|
+
} else {
|
|
13384
|
+
const a = others.indexOf(k);
|
|
13385
|
+
n1 = fixed && sdFix ? refN1 + Math.round(sdFix[a]) : Math.round(n1Float[k]);
|
|
13386
|
+
}
|
|
13387
|
+
const lNl = lamNl[k];
|
|
13388
|
+
const aIF = lNl * n1 + lNl * (s.f2 / (s.f1 - s.f2)) * nWl[k];
|
|
13389
|
+
outSats.push({ prn: s.prn, nWl: nWl[k], n1, aIF });
|
|
13390
|
+
}
|
|
13391
|
+
return {
|
|
13392
|
+
fixed,
|
|
13393
|
+
ratio,
|
|
13394
|
+
refPrn: sats[kept[ref]].prn,
|
|
13395
|
+
sats: outSats,
|
|
13396
|
+
rejectedWl
|
|
13397
|
+
};
|
|
13398
|
+
}
|
|
13399
|
+
|
|
13400
|
+
// src/positioning/ppp-fcb.ts
|
|
13401
|
+
function extractWidelaneArcs(station, epochs, opts = {}) {
|
|
13402
|
+
const slipCyc = opts.slipCyc ?? 4;
|
|
13403
|
+
const gapMs = opts.gapMs ?? 12e4;
|
|
13404
|
+
const minObs = opts.minObs ?? 20;
|
|
13405
|
+
const state = /* @__PURE__ */ new Map();
|
|
13406
|
+
const out = [];
|
|
13407
|
+
const flush = (prn) => {
|
|
13408
|
+
const s = state.get(prn);
|
|
13409
|
+
if (s && s.n >= minObs)
|
|
13410
|
+
out.push({ station, prn, wlFloat: s.sum / s.n, nObs: s.n });
|
|
13411
|
+
};
|
|
13412
|
+
for (const ep of epochs) {
|
|
13413
|
+
for (const o of ep.obs) {
|
|
13414
|
+
if (!o.c1 || !o.c2 || !o.l1 || !o.l2) continue;
|
|
13415
|
+
const lamW = C_LIGHT / (o.f1 - o.f2);
|
|
13416
|
+
const codeNl = (o.f1 * o.c1 + o.f2 * o.c2) / (o.f1 + o.f2);
|
|
13417
|
+
const mw = o.l1 - o.l2 - codeNl / lamW;
|
|
13418
|
+
const s = state.get(o.prn);
|
|
13419
|
+
if (!s || ep.timeMs - s.lastT > gapMs || Math.abs(mw - s.mean) > slipCyc) {
|
|
13420
|
+
if (s) flush(o.prn);
|
|
13421
|
+
state.set(o.prn, { sum: mw, n: 1, mean: mw, lastT: ep.timeMs });
|
|
13422
|
+
} else {
|
|
13423
|
+
s.sum += mw;
|
|
13424
|
+
s.n += 1;
|
|
13425
|
+
s.mean = s.sum / s.n;
|
|
13426
|
+
s.lastT = ep.timeMs;
|
|
13427
|
+
}
|
|
13428
|
+
}
|
|
13429
|
+
}
|
|
13430
|
+
for (const prn of state.keys()) flush(prn);
|
|
13431
|
+
return out;
|
|
13432
|
+
}
|
|
13433
|
+
function wrapHalf(x) {
|
|
13434
|
+
return x - Math.round(x);
|
|
13435
|
+
}
|
|
13436
|
+
function circMean(vals, weights) {
|
|
13437
|
+
let s = 0;
|
|
13438
|
+
let c = 0;
|
|
13439
|
+
for (let i = 0; i < vals.length; i++) {
|
|
13440
|
+
const a = 2 * Math.PI * vals[i];
|
|
13441
|
+
s += weights[i] * Math.sin(a);
|
|
13442
|
+
c += weights[i] * Math.cos(a);
|
|
13443
|
+
}
|
|
13444
|
+
if (s === 0 && c === 0) return 0;
|
|
13445
|
+
return wrapHalf(Math.atan2(s, c) / (2 * Math.PI));
|
|
13446
|
+
}
|
|
13447
|
+
function estimateWidelaneFcb(arcs, opts = {}) {
|
|
13448
|
+
const maxIter = opts.maxIter ?? 50;
|
|
13449
|
+
const tol = opts.tol ?? 1e-4;
|
|
13450
|
+
const fixWindow = opts.fixWindow ?? 0.25;
|
|
13451
|
+
const sats = [...new Set(arcs.map((a) => a.prn))].sort();
|
|
13452
|
+
const stations = [...new Set(arcs.map((a) => a.station))].sort();
|
|
13453
|
+
const refStation = stations[0] ?? "";
|
|
13454
|
+
const satFcb = new Map(sats.map((s) => [s, 0]));
|
|
13455
|
+
const rcvBias = new Map(stations.map((s) => [s, 0]));
|
|
13456
|
+
const nInt = new Array(arcs.length).fill(0);
|
|
13457
|
+
let iterations = 0;
|
|
13458
|
+
for (let it = 0; it < maxIter; it++) {
|
|
13459
|
+
iterations = it + 1;
|
|
13460
|
+
for (let i = 0; i < arcs.length; i++) {
|
|
13461
|
+
const a = arcs[i];
|
|
13462
|
+
nInt[i] = Math.round(
|
|
13463
|
+
a.wlFloat - rcvBias.get(a.station) - satFcb.get(a.prn)
|
|
13464
|
+
);
|
|
13465
|
+
}
|
|
13466
|
+
let maxChange = 0;
|
|
13467
|
+
for (const s of sats) {
|
|
13468
|
+
const vals = [];
|
|
13469
|
+
const w = [];
|
|
13470
|
+
for (let i = 0; i < arcs.length; i++) {
|
|
13471
|
+
const a = arcs[i];
|
|
13472
|
+
if (a.prn !== s) continue;
|
|
13473
|
+
vals.push(a.wlFloat - nInt[i] - rcvBias.get(a.station));
|
|
13474
|
+
w.push(a.nObs);
|
|
13475
|
+
}
|
|
13476
|
+
if (!vals.length) continue;
|
|
13477
|
+
const nv = circMean(vals, w);
|
|
13478
|
+
maxChange = Math.max(maxChange, Math.abs(wrapHalf(nv - satFcb.get(s))));
|
|
13479
|
+
satFcb.set(s, nv);
|
|
13480
|
+
}
|
|
13481
|
+
for (const r of stations) {
|
|
13482
|
+
const vals = [];
|
|
13483
|
+
const w = [];
|
|
13484
|
+
for (let i = 0; i < arcs.length; i++) {
|
|
13485
|
+
const a = arcs[i];
|
|
13486
|
+
if (a.station !== r) continue;
|
|
13487
|
+
vals.push(a.wlFloat - nInt[i] - satFcb.get(a.prn));
|
|
13488
|
+
w.push(a.nObs);
|
|
13489
|
+
}
|
|
13490
|
+
if (!vals.length) continue;
|
|
13491
|
+
rcvBias.set(r, circMean(vals, w));
|
|
13492
|
+
}
|
|
13493
|
+
const shift = rcvBias.get(refStation);
|
|
13494
|
+
if (shift !== 0) {
|
|
13495
|
+
for (const r of stations)
|
|
13496
|
+
rcvBias.set(r, wrapHalf(rcvBias.get(r) - shift));
|
|
13497
|
+
for (const s of sats) satFcb.set(s, wrapHalf(satFcb.get(s) + shift));
|
|
13498
|
+
}
|
|
13499
|
+
if (maxChange < tol) break;
|
|
13500
|
+
}
|
|
13501
|
+
let sumSq = 0;
|
|
13502
|
+
let fixed = 0;
|
|
13503
|
+
for (let i = 0; i < arcs.length; i++) {
|
|
13504
|
+
const a = arcs[i];
|
|
13505
|
+
const resid = wrapHalf(
|
|
13506
|
+
a.wlFloat - nInt[i] - rcvBias.get(a.station) - satFcb.get(a.prn)
|
|
13507
|
+
);
|
|
13508
|
+
sumSq += resid * resid;
|
|
13509
|
+
if (Math.abs(resid) <= fixWindow) fixed++;
|
|
13510
|
+
}
|
|
13511
|
+
const residRms = arcs.length ? Math.sqrt(sumSq / arcs.length) : 0;
|
|
13512
|
+
const fixRate = arcs.length ? fixed / arcs.length : 0;
|
|
13513
|
+
return { satFcb, rcvBias, residRms, fixRate, refStation, iterations };
|
|
13514
|
+
}
|
|
13515
|
+
|
|
13227
13516
|
// src/positioning/index.ts
|
|
13228
13517
|
var GM_GPS3 = 3986005e8;
|
|
13229
13518
|
var F_REL = -4442807633e-19;
|
|
@@ -15803,6 +16092,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
15803
16092
|
analyzeQuality,
|
|
15804
16093
|
applyHelmert,
|
|
15805
16094
|
applyIonoDcb,
|
|
16095
|
+
biasMetres,
|
|
15806
16096
|
binexCrc16,
|
|
15807
16097
|
binexCrc32,
|
|
15808
16098
|
binexCsum8,
|
|
@@ -15840,8 +16130,11 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
15840
16130
|
ecefToAzEl,
|
|
15841
16131
|
ecefToGeodetic,
|
|
15842
16132
|
ephInfoToEphemeris,
|
|
16133
|
+
estimateWidelaneFcb,
|
|
15843
16134
|
euclidean3D,
|
|
16135
|
+
extractWidelaneArcs,
|
|
15844
16136
|
fetchSourcetable,
|
|
16137
|
+
findSatBias,
|
|
15845
16138
|
fmtD,
|
|
15846
16139
|
fmtF,
|
|
15847
16140
|
formatUTCTime,
|
|
@@ -15924,11 +16217,13 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
15924
16217
|
msmEpochToDate,
|
|
15925
16218
|
navTimesFromEph,
|
|
15926
16219
|
niellMapping,
|
|
16220
|
+
nlWavelength,
|
|
15927
16221
|
nmeaCoordToDecimal,
|
|
15928
16222
|
oem4Frames,
|
|
15929
16223
|
padL,
|
|
15930
16224
|
padR,
|
|
15931
16225
|
parseAntex,
|
|
16226
|
+
parseBiasSinex,
|
|
15932
16227
|
parseBinex,
|
|
15933
16228
|
parseClk,
|
|
15934
16229
|
parseCrxDataLine,
|
|
@@ -15966,6 +16261,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
15966
16261
|
readString,
|
|
15967
16262
|
reportDecodeError,
|
|
15968
16263
|
resetGloFreqCache,
|
|
16264
|
+
resolvePppAmbiguities,
|
|
15969
16265
|
rhumbLine,
|
|
15970
16266
|
rtcm3Constellation,
|
|
15971
16267
|
satClockCorrection,
|
|
@@ -15991,6 +16287,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
15991
16287
|
updateStreamStats,
|
|
15992
16288
|
verifyChecksum,
|
|
15993
16289
|
vincenty,
|
|
16290
|
+
wlWavelength,
|
|
15994
16291
|
writeCrx,
|
|
15995
16292
|
writeModernObsBlob,
|
|
15996
16293
|
writeRinex2ObsBlob,
|