gnss-js 2.8.2 → 2.10.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-6SWJTN6H.js → chunk-56HM5B6T.js} +19 -5
- package/dist/{chunk-5OWRCF56.js → chunk-7T5DLVZL.js} +43 -15
- package/dist/{chunk-CLNLOYBX.js → chunk-K3GLUWZI.js} +62 -1
- package/dist/{chunk-7GNRNKBR.js → chunk-N6GQUHM4.js} +27 -9
- package/dist/index.cjs +172 -46
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +14 -4
- package/dist/msm-CcQJV3PC.d.ts +108 -0
- package/dist/msm-DWtoTvx2.d.cts +108 -0
- package/dist/orbit.cjs +46 -15
- package/dist/orbit.d.cts +39 -4
- package/dist/orbit.d.ts +39 -4
- package/dist/orbit.js +7 -1
- package/dist/positioning.cjs +109 -26
- package/dist/positioning.d.cts +19 -1
- package/dist/positioning.d.ts +19 -1
- package/dist/positioning.js +4 -2
- package/dist/rinex.cjs +20 -5
- package/dist/rinex.d.cts +10 -1
- package/dist/rinex.d.ts +10 -1
- package/dist/rinex.js +3 -1
- package/dist/rtcm3.cjs +27 -9
- package/dist/rtcm3.d.cts +6 -88
- package/dist/rtcm3.d.ts +6 -88
- package/dist/rtcm3.js +1 -1
- package/package.json +1 -1
|
@@ -1566,6 +1566,21 @@ function writeRinexObsBlob(header, epochs, obsTypes) {
|
|
|
1566
1566
|
comment: "Merged from multiple RINEX files"
|
|
1567
1567
|
});
|
|
1568
1568
|
}
|
|
1569
|
+
function modalIntervalS(epochs) {
|
|
1570
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1571
|
+
for (let i = 1; i < epochs.length; i++) {
|
|
1572
|
+
const d = Math.round(epochs[i].time - epochs[i - 1].time);
|
|
1573
|
+
if (d > 0) counts.set(d, (counts.get(d) ?? 0) + 1);
|
|
1574
|
+
}
|
|
1575
|
+
let best = null;
|
|
1576
|
+
let bestN = 0;
|
|
1577
|
+
for (const [d, n] of counts)
|
|
1578
|
+
if (n > bestN || n === bestN && best !== null && d < best) {
|
|
1579
|
+
best = d;
|
|
1580
|
+
bestN = n;
|
|
1581
|
+
}
|
|
1582
|
+
return best === null ? null : best / 1e3;
|
|
1583
|
+
}
|
|
1569
1584
|
async function writeModernObsBlob(header, epochs, obsTypes, opts) {
|
|
1570
1585
|
if (epochs.length === 0) return new Blob([], { type: "application/gzip" });
|
|
1571
1586
|
const sink = createGzipLineSink();
|
|
@@ -1612,11 +1627,9 @@ async function writeModernObsBlob(header, epochs, obsTypes, opts) {
|
|
|
1612
1627
|
"TIME OF LAST OBS"
|
|
1613
1628
|
)
|
|
1614
1629
|
);
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
sink.push(hdrLine(fmtF(interval, 10, 3), "INTERVAL"));
|
|
1619
|
-
}
|
|
1630
|
+
const interval = modalIntervalS(epochs);
|
|
1631
|
+
if (interval !== null && interval < 3600) {
|
|
1632
|
+
sink.push(hdrLine(fmtF(interval, 10, 3), "INTERVAL"));
|
|
1620
1633
|
}
|
|
1621
1634
|
if (header.glonassSlots && Object.keys(header.glonassSlots).length > 0) {
|
|
1622
1635
|
const entries = Object.entries(header.glonassSlots).sort(
|
|
@@ -1888,6 +1901,7 @@ export {
|
|
|
1888
1901
|
createGzipLineSink,
|
|
1889
1902
|
stationHeaderLines,
|
|
1890
1903
|
writeRinexObsBlob,
|
|
1904
|
+
modalIntervalS,
|
|
1891
1905
|
writeModernObsBlob,
|
|
1892
1906
|
writeRinex2ObsBlob,
|
|
1893
1907
|
writeRinex4ObsBlob
|
|
@@ -37,6 +37,42 @@ function invertMatrix(A) {
|
|
|
37
37
|
return M.map((row) => row.slice(n));
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
// src/orbit/validity.ts
|
|
41
|
+
var H = 36e5;
|
|
42
|
+
var MIN = 6e4;
|
|
43
|
+
var EPHEMERIS_VALIDITY_MS = {
|
|
44
|
+
G: 2 * H,
|
|
45
|
+
J: 2 * H,
|
|
46
|
+
E: 2.5 * H,
|
|
47
|
+
C: 90 * MIN,
|
|
48
|
+
R: 15 * MIN,
|
|
49
|
+
I: 2 * H,
|
|
50
|
+
S: 6 * MIN
|
|
51
|
+
};
|
|
52
|
+
function tocDistanceMs(eph, tGpsMs) {
|
|
53
|
+
const t = eph.system === "R" || eph.system === "S" ? tGpsMs - getGpsLeap(new Date(tGpsMs)) * 1e3 : tGpsMs;
|
|
54
|
+
return Math.abs(eph.tocDate.getTime() - t);
|
|
55
|
+
}
|
|
56
|
+
function isEphemerisValid(eph, tGpsMs) {
|
|
57
|
+
const w = EPHEMERIS_VALIDITY_MS[eph.system];
|
|
58
|
+
return w !== void 0 && tocDistanceMs(eph, tGpsMs) <= w;
|
|
59
|
+
}
|
|
60
|
+
function nearestValidEphemeris(ephs, tGpsMs) {
|
|
61
|
+
if (!ephs) return null;
|
|
62
|
+
let best = null;
|
|
63
|
+
let bestDt = Infinity;
|
|
64
|
+
for (const eph of ephs) {
|
|
65
|
+
const dt = tocDistanceMs(eph, tGpsMs);
|
|
66
|
+
const w = EPHEMERIS_VALIDITY_MS[eph.system];
|
|
67
|
+
if (w === void 0 || dt > w) continue;
|
|
68
|
+
if (dt < bestDt) {
|
|
69
|
+
bestDt = dt;
|
|
70
|
+
best = eph;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return best;
|
|
74
|
+
}
|
|
75
|
+
|
|
40
76
|
// src/orbit/almanac.ts
|
|
41
77
|
var GM_GPS = 3986005e8;
|
|
42
78
|
var GM_GAL = 3986004418e5;
|
|
@@ -419,20 +455,20 @@ function computeDop(satAzEls) {
|
|
|
419
455
|
const clocks = [...new Set(sats.map((s) => dopClock(s.prn)))];
|
|
420
456
|
const m = 3 + clocks.length;
|
|
421
457
|
if (n < Math.max(4, m)) return null;
|
|
422
|
-
const
|
|
458
|
+
const H2 = [];
|
|
423
459
|
for (const { az, el, prn } of sats) {
|
|
424
460
|
const cosEl = Math.cos(el);
|
|
425
461
|
const row = [cosEl * Math.sin(az), cosEl * Math.cos(az), Math.sin(el)];
|
|
426
462
|
const clock = dopClock(prn);
|
|
427
463
|
for (const c of clocks) row.push(c === clock ? 1 : 0);
|
|
428
|
-
|
|
464
|
+
H2.push(row);
|
|
429
465
|
}
|
|
430
466
|
const HtH = Array.from({ length: m }, () => new Array(m).fill(0));
|
|
431
467
|
for (let i = 0; i < m; i++) {
|
|
432
468
|
for (let j = 0; j < m; j++) {
|
|
433
469
|
let sum = 0;
|
|
434
470
|
for (let k = 0; k < n; k++) {
|
|
435
|
-
sum +=
|
|
471
|
+
sum += H2[k][i] * H2[k][j];
|
|
436
472
|
}
|
|
437
473
|
HtH[i][j] = sum;
|
|
438
474
|
}
|
|
@@ -533,18 +569,7 @@ function computeAllPositions(ephemerides, times, rxPos) {
|
|
|
533
569
|
return { prns, times, positions };
|
|
534
570
|
}
|
|
535
571
|
function selectBest(ephs, timeMs) {
|
|
536
|
-
|
|
537
|
-
let bestDt = Infinity;
|
|
538
|
-
for (const eph of ephs) {
|
|
539
|
-
const dt = Math.abs(timeMs - eph.tocDate.getTime());
|
|
540
|
-
const maxAge = eph.system === "R" || eph.system === "S" ? 18e5 : 4 * 36e5;
|
|
541
|
-
if (dt > maxAge) continue;
|
|
542
|
-
if (dt < bestDt) {
|
|
543
|
-
bestDt = dt;
|
|
544
|
-
best = eph;
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
return best;
|
|
572
|
+
return nearestValidEphemeris(ephs, timeMs);
|
|
548
573
|
}
|
|
549
574
|
var GPS_EPOCH_MS2 = START_GPS_TIME.getTime();
|
|
550
575
|
var MS_PER_WEEK = 7 * 864e5;
|
|
@@ -786,6 +811,9 @@ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
|
|
|
786
811
|
|
|
787
812
|
export {
|
|
788
813
|
invertMatrix,
|
|
814
|
+
EPHEMERIS_VALIDITY_MS,
|
|
815
|
+
isEphemerisValid,
|
|
816
|
+
nearestValidEphemeris,
|
|
789
817
|
almanacEpochMs,
|
|
790
818
|
almanacSatPosition,
|
|
791
819
|
glonassAlmanacEpochMs,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
ecefToAzEl,
|
|
8
8
|
invertMatrix,
|
|
9
9
|
selectEphemeris
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-7T5DLVZL.js";
|
|
11
11
|
import {
|
|
12
12
|
ecefToGeodetic,
|
|
13
13
|
getAer,
|
|
@@ -1621,6 +1621,66 @@ var ZeroBaselineEngine = class {
|
|
|
1621
1621
|
}
|
|
1622
1622
|
};
|
|
1623
1623
|
|
|
1624
|
+
// src/positioning/msm-resolve.ts
|
|
1625
|
+
var LIGHT_MS = C_LIGHT / 1e3;
|
|
1626
|
+
var MAX_FRACTION_MISFIT = 0.25;
|
|
1627
|
+
function predictedRange(eph, timeMs, rx) {
|
|
1628
|
+
let tau = 0.075;
|
|
1629
|
+
for (let i = 0; i < 2; i++) {
|
|
1630
|
+
const tEmit = timeMs - tau * 1e3;
|
|
1631
|
+
const p = computeSatPosition(eph, tEmit);
|
|
1632
|
+
if (!Number.isFinite(p.x)) return null;
|
|
1633
|
+
const rho = Math.hypot(p.x - rx[0], p.y - rx[1], p.z - rx[2]);
|
|
1634
|
+
tau = rho / C_LIGHT;
|
|
1635
|
+
if (i === 1) return rho - C_LIGHT * satClockCorrection(eph, tEmit);
|
|
1636
|
+
}
|
|
1637
|
+
return null;
|
|
1638
|
+
}
|
|
1639
|
+
function moduloRange(sat) {
|
|
1640
|
+
for (const s of sat.signals)
|
|
1641
|
+
if (s.pseudorange !== void 0) return s.pseudorange;
|
|
1642
|
+
for (const s of sat.signals)
|
|
1643
|
+
if (s.phase !== void 0 && s.wavelength > 0)
|
|
1644
|
+
return s.phase * s.wavelength;
|
|
1645
|
+
return null;
|
|
1646
|
+
}
|
|
1647
|
+
function resolveMsmRanges(epoch, opts) {
|
|
1648
|
+
if (!epoch.rangeModulo1ms) return epoch;
|
|
1649
|
+
const cand = [];
|
|
1650
|
+
for (const sat of epoch.observations) {
|
|
1651
|
+
const eph = opts.ephFor(sat.prn);
|
|
1652
|
+
const mod = moduloRange(sat);
|
|
1653
|
+
if (!eph || mod === null) continue;
|
|
1654
|
+
const pred = predictedRange(eph, opts.timeMs, opts.rxEcef);
|
|
1655
|
+
if (pred === null) continue;
|
|
1656
|
+
cand.push({ sat, k: (pred - mod) / LIGHT_MS });
|
|
1657
|
+
}
|
|
1658
|
+
const { rangeModulo1ms: _drop, ...rest } = epoch;
|
|
1659
|
+
if (cand.length === 0) return { ...rest, observations: [] };
|
|
1660
|
+
let sx = 0;
|
|
1661
|
+
let sy = 0;
|
|
1662
|
+
for (const c of cand) {
|
|
1663
|
+
sx += Math.cos(2 * Math.PI * c.k);
|
|
1664
|
+
sy += Math.sin(2 * Math.PI * c.k);
|
|
1665
|
+
}
|
|
1666
|
+
const b = Math.atan2(sy, sx) / (2 * Math.PI);
|
|
1667
|
+
const observations = [];
|
|
1668
|
+
for (const { sat, k } of cand) {
|
|
1669
|
+
const n = Math.round(k - b);
|
|
1670
|
+
if (Math.abs(k - b - n) > MAX_FRACTION_MISFIT) continue;
|
|
1671
|
+
const add = n * LIGHT_MS;
|
|
1672
|
+
observations.push({
|
|
1673
|
+
...sat,
|
|
1674
|
+
signals: sat.signals.map((s) => ({
|
|
1675
|
+
...s,
|
|
1676
|
+
...s.pseudorange !== void 0 ? { pseudorange: s.pseudorange + add } : {},
|
|
1677
|
+
...s.phase !== void 0 && s.wavelength > 0 ? { phase: s.phase + add / s.wavelength } : {}
|
|
1678
|
+
}))
|
|
1679
|
+
});
|
|
1680
|
+
}
|
|
1681
|
+
return { ...rest, observations };
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1624
1684
|
// src/positioning/sbas.ts
|
|
1625
1685
|
var P2_11 = 2 ** -11;
|
|
1626
1686
|
var P2_31 = 2 ** -31;
|
|
@@ -4011,6 +4071,7 @@ export {
|
|
|
4011
4071
|
RtkFloatEngine,
|
|
4012
4072
|
postProcessRtk,
|
|
4013
4073
|
ZeroBaselineEngine,
|
|
4074
|
+
resolveMsmRanges,
|
|
4014
4075
|
sbasLongTermDeg,
|
|
4015
4076
|
sbasIonoDeg,
|
|
4016
4077
|
SbasProcessor,
|
|
@@ -1138,12 +1138,14 @@ function satPrn(sys, satIdx1) {
|
|
|
1138
1138
|
const num = sys === "S" ? satIdx1 + 119 : satIdx1;
|
|
1139
1139
|
return `${prefix}${String(num).padStart(2, "0")}`;
|
|
1140
1140
|
}
|
|
1141
|
-
function decodeMsmFull(frame) {
|
|
1141
|
+
function decodeMsmFull(frame, opts = {}) {
|
|
1142
1142
|
const type = frame.messageType;
|
|
1143
1143
|
const sys = msmSystem(type);
|
|
1144
1144
|
if (!sys) return null;
|
|
1145
1145
|
const variant = type % 10;
|
|
1146
|
-
if (variant <
|
|
1146
|
+
if (variant < 1 || variant > 7) return null;
|
|
1147
|
+
const compact = variant <= 3;
|
|
1148
|
+
if (compact && !opts.compactMsm) return null;
|
|
1147
1149
|
const payload = frame.payload;
|
|
1148
1150
|
if (!payload || payload.length < 10) return null;
|
|
1149
1151
|
try {
|
|
@@ -1188,7 +1190,9 @@ function decodeMsmFull(frame) {
|
|
|
1188
1190
|
const rrmod = new Float64Array(numSat);
|
|
1189
1191
|
const extsat = new Int8Array(numSat);
|
|
1190
1192
|
const rdop = new Float64Array(numSat);
|
|
1191
|
-
if (
|
|
1193
|
+
if (compact) {
|
|
1194
|
+
for (let j = 0; j < numSat; j++) rrmod[j] = bits.readU(10) / 1024;
|
|
1195
|
+
} else if (variant === 4 || variant === 6) {
|
|
1192
1196
|
for (let j = 0; j < numSat; j++) rrint[j] = bits.readU(8);
|
|
1193
1197
|
for (let j = 0; j < numSat; j++) rrmod[j] = bits.readU(10) / 1024;
|
|
1194
1198
|
} else {
|
|
@@ -1214,7 +1218,18 @@ function decodeMsmFull(frame) {
|
|
|
1214
1218
|
psr.fill(-1e30);
|
|
1215
1219
|
cp.fill(-1e30);
|
|
1216
1220
|
dop.fill(-1e30);
|
|
1217
|
-
if (variant ===
|
|
1221
|
+
if (variant === 1) {
|
|
1222
|
+
for (let i = 0; i < activeCells; i++) psr[i] = bits.readS(15) / 2 ** 24;
|
|
1223
|
+
} else if (variant === 2) {
|
|
1224
|
+
for (let i = 0; i < activeCells; i++) cp[i] = bits.readS(22) / 2 ** 29;
|
|
1225
|
+
for (let i = 0; i < activeCells; i++) ll[i] = bits.readU(4);
|
|
1226
|
+
for (let i = 0; i < activeCells; i++) hc[i] = bits.readU(1);
|
|
1227
|
+
} else if (variant === 3) {
|
|
1228
|
+
for (let i = 0; i < activeCells; i++) psr[i] = bits.readS(15) / 2 ** 24;
|
|
1229
|
+
for (let i = 0; i < activeCells; i++) cp[i] = bits.readS(22) / 2 ** 29;
|
|
1230
|
+
for (let i = 0; i < activeCells; i++) ll[i] = bits.readU(4);
|
|
1231
|
+
for (let i = 0; i < activeCells; i++) hc[i] = bits.readU(1);
|
|
1232
|
+
} else if (variant === 4) {
|
|
1218
1233
|
for (let i = 0; i < activeCells; i++) psr[i] = bits.readS(15) / 2 ** 24;
|
|
1219
1234
|
for (let i = 0; i < activeCells; i++) cp[i] = bits.readS(22) / 2 ** 29;
|
|
1220
1235
|
for (let i = 0; i < activeCells; i++) ll[i] = bits.readU(4);
|
|
@@ -1290,8 +1305,10 @@ function decodeMsmFull(frame) {
|
|
|
1290
1305
|
if (cnrVal > 0) {
|
|
1291
1306
|
signal.cn0 = cnrVal;
|
|
1292
1307
|
}
|
|
1293
|
-
|
|
1294
|
-
|
|
1308
|
+
if (variant !== 1) {
|
|
1309
|
+
signal.lockTime = lockTimeSec(type, ll[cellIdx]);
|
|
1310
|
+
signal.halfCycle = hc[cellIdx] === 1;
|
|
1311
|
+
}
|
|
1295
1312
|
signals.push(signal);
|
|
1296
1313
|
cellIdx++;
|
|
1297
1314
|
}
|
|
@@ -1303,7 +1320,8 @@ function decodeMsmFull(frame) {
|
|
|
1303
1320
|
messageType: type,
|
|
1304
1321
|
epochMs,
|
|
1305
1322
|
system: sys,
|
|
1306
|
-
observations
|
|
1323
|
+
observations,
|
|
1324
|
+
...compact ? { rangeModulo1ms: true } : {}
|
|
1307
1325
|
};
|
|
1308
1326
|
} catch (err) {
|
|
1309
1327
|
reportDecodeError("msm", err);
|
|
@@ -1457,8 +1475,8 @@ function decodeLegacyObs(frame) {
|
|
|
1457
1475
|
}
|
|
1458
1476
|
return { messageType: type, epochMs, system, observations };
|
|
1459
1477
|
}
|
|
1460
|
-
function decodeObs(frame) {
|
|
1461
|
-
return decodeMsmFull(frame) ?? decodeLegacyObs(frame);
|
|
1478
|
+
function decodeObs(frame, opts = {}) {
|
|
1479
|
+
return decodeMsmFull(frame, opts) ?? decodeLegacyObs(frame);
|
|
1462
1480
|
}
|
|
1463
1481
|
|
|
1464
1482
|
// src/rtcm3/ssr.ts
|