gnss-js 1.56.0 → 1.58.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-BU6YC6VK.js → chunk-SWVIBUHS.js} +61 -8
- package/dist/{chunk-ZPNMIUNZ.js → chunk-UHLUAU6H.js} +131 -9
- package/dist/index.cjs +202 -17
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +22 -2
- package/dist/positioning.cjs +63 -8
- package/dist/positioning.d.cts +37 -1
- package/dist/positioning.d.ts +37 -1
- package/dist/positioning.js +5 -1
- package/dist/sbf.cjs +139 -9
- package/dist/sbf.d.cts +112 -28
- package/dist/sbf.d.ts +112 -28
- package/dist/sbf.js +17 -1
- package/package.json +1 -1
|
@@ -1270,6 +1270,17 @@ var DEGF = [
|
|
|
1270
1270
|
58e-4
|
|
1271
1271
|
];
|
|
1272
1272
|
var degfcorr = (ai) => ai > 0 && ai <= 15 ? DEGF[ai] : 58e-4;
|
|
1273
|
+
function sbasLongTermDeg(d, vel, ageSec) {
|
|
1274
|
+
if (vel) {
|
|
1275
|
+
if (ageSec > 0 && ageSec < d.iltcV1) return 0;
|
|
1276
|
+
return d.cltcLsb + d.cltcV1 * Math.max(0, -ageSec, ageSec - d.iltcV1);
|
|
1277
|
+
}
|
|
1278
|
+
return d.cltcV0 * Math.floor(Math.abs(ageSec) / d.iltcV0);
|
|
1279
|
+
}
|
|
1280
|
+
function sbasIonoDeg(d, ageSec) {
|
|
1281
|
+
const dt = Math.abs(ageSec);
|
|
1282
|
+
return d.cionoStep * Math.floor(dt / d.iiono) + d.cionoRamp * dt;
|
|
1283
|
+
}
|
|
1273
1284
|
var x1 = [-75, -65, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 65, 75, 85];
|
|
1274
1285
|
var x2 = [-55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55];
|
|
1275
1286
|
var x3 = [-75, -65, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 65, 75];
|
|
@@ -1323,6 +1334,7 @@ var SbasProcessor = class {
|
|
|
1323
1334
|
satIdx = /* @__PURE__ */ new Map();
|
|
1324
1335
|
iodp = -1;
|
|
1325
1336
|
tlat = 0;
|
|
1337
|
+
degr = null;
|
|
1326
1338
|
ion = [];
|
|
1327
1339
|
/** GEO PRN(s) whose messages have been ingested. */
|
|
1328
1340
|
geoPrns = /* @__PURE__ */ new Set();
|
|
@@ -1349,6 +1361,8 @@ var SbasProcessor = class {
|
|
|
1349
1361
|
return this.decodeIntegrity(msg) ? type : -1;
|
|
1350
1362
|
case 7:
|
|
1351
1363
|
return this.decodeDegradation(msg) ? type : -1;
|
|
1364
|
+
case 10:
|
|
1365
|
+
return this.decodeMt10(msg) ? type : -1;
|
|
1352
1366
|
case 18:
|
|
1353
1367
|
return this.decodeIgpMask(msg) ? type : -1;
|
|
1354
1368
|
case 24:
|
|
@@ -1417,6 +1431,30 @@ var SbasProcessor = class {
|
|
|
1417
1431
|
}
|
|
1418
1432
|
return true;
|
|
1419
1433
|
}
|
|
1434
|
+
/** MT10 degradation factors (DO-229D Table A-9). Fields follow the 8-bit
|
|
1435
|
+
* preamble + 6-bit type (start bit 14), MSB-first, with the listed LSBs.
|
|
1436
|
+
* Iiono / Iltc_v0 of 0 must be read as 1 (Table A-9, Note 3). */
|
|
1437
|
+
decodeMt10(msg) {
|
|
1438
|
+
const u = (p, n) => getBitU(msg, p, n);
|
|
1439
|
+
this.degr = {
|
|
1440
|
+
brrc: u(14, 10) * 2e-3,
|
|
1441
|
+
cltcLsb: u(24, 10) * 2e-3,
|
|
1442
|
+
cltcV1: u(34, 10) * 5e-5,
|
|
1443
|
+
iltcV1: u(44, 9),
|
|
1444
|
+
cltcV0: u(53, 10) * 2e-3,
|
|
1445
|
+
iltcV0: u(63, 9) || 1,
|
|
1446
|
+
cgeoLsb: u(72, 10) * 5e-4,
|
|
1447
|
+
cgeoV: u(82, 10) * 5e-5,
|
|
1448
|
+
igeo: u(92, 9),
|
|
1449
|
+
cer: u(101, 6) * 0.5,
|
|
1450
|
+
cionoStep: u(107, 10) * 1e-3,
|
|
1451
|
+
iiono: u(117, 9) || 1,
|
|
1452
|
+
cionoRamp: u(126, 10) * 5e-6,
|
|
1453
|
+
rssUdre: u(136, 1) === 1,
|
|
1454
|
+
rssIono: u(137, 1) === 1
|
|
1455
|
+
};
|
|
1456
|
+
return true;
|
|
1457
|
+
}
|
|
1420
1458
|
decodeMixed(msg, week, tow) {
|
|
1421
1459
|
if (this.iodp !== getBitU(msg, 110, 2)) return false;
|
|
1422
1460
|
const blk = getBitU(msg, 112, 2);
|
|
@@ -1463,7 +1501,8 @@ var SbasProcessor = class {
|
|
|
1463
1501
|
dvel: [0, 0, 0],
|
|
1464
1502
|
daf0: getBitS(msg, p + 41, 10) * P2_31,
|
|
1465
1503
|
daf1: 0,
|
|
1466
|
-
t0s: gpsSeconds(week, tow)
|
|
1504
|
+
t0s: gpsSeconds(week, tow),
|
|
1505
|
+
vel: false
|
|
1467
1506
|
};
|
|
1468
1507
|
return true;
|
|
1469
1508
|
}
|
|
@@ -1487,7 +1526,8 @@ var SbasProcessor = class {
|
|
|
1487
1526
|
],
|
|
1488
1527
|
daf0: getBitS(msg, p + 47, 11) * P2_31,
|
|
1489
1528
|
daf1: getBitS(msg, p + 82, 8) * P2_39,
|
|
1490
|
-
t0s: gpsSeconds(week, tow + t)
|
|
1529
|
+
t0s: gpsSeconds(week, tow + t),
|
|
1530
|
+
vel: true
|
|
1491
1531
|
};
|
|
1492
1532
|
return true;
|
|
1493
1533
|
}
|
|
@@ -1608,9 +1648,16 @@ var SbasProcessor = class {
|
|
|
1608
1648
|
const tf = now - s.fcorr.t0s + this.tlat;
|
|
1609
1649
|
if (Math.abs(tf) > MAXSBSAGEF || s.fcorr.udre >= 15) return null;
|
|
1610
1650
|
const prc = s.fcorr.prc;
|
|
1611
|
-
const
|
|
1651
|
+
const sigUdre = Math.sqrt(varfcorr(s.fcorr.udre));
|
|
1652
|
+
const efc = degfcorr(s.fcorr.ai) * tf * tf / 2;
|
|
1653
|
+
const eltc = this.degr && s.lcorr && s.lcorr.t0s !== 0 ? sbasLongTermDeg(this.degr, s.lcorr.vel, now - s.lcorr.t0s) : 0;
|
|
1654
|
+
const varM2 = this.degr?.rssUdre ? sigUdre * sigUdre + efc * efc + eltc * eltc : (sigUdre + efc + eltc) ** 2;
|
|
1612
1655
|
return { dPos: drs, dClkS: dclk + prc / C_LIGHT, prcM: prc, varM2, iode };
|
|
1613
1656
|
}
|
|
1657
|
+
/** The last-decoded MT10 degradation factors, or null if none seen. */
|
|
1658
|
+
get degradation() {
|
|
1659
|
+
return this.degr;
|
|
1660
|
+
}
|
|
1614
1661
|
/**
|
|
1615
1662
|
* Slant L1 ionospheric delay (m) at the pierce point for a receiver geodetic
|
|
1616
1663
|
* position (lat/lon rad, height m) and a satellite az/el (rad), interpolated
|
|
@@ -1659,14 +1706,18 @@ var SbasProcessor = class {
|
|
|
1659
1706
|
} else return null;
|
|
1660
1707
|
const now = gpsSeconds(week, tow);
|
|
1661
1708
|
let delay = 0;
|
|
1662
|
-
let
|
|
1709
|
+
let varVert = 0;
|
|
1663
1710
|
for (let i = 0; i < 4; i++) {
|
|
1664
1711
|
const g = pts[i];
|
|
1665
1712
|
if (!g) continue;
|
|
1666
1713
|
delay += w[i] * g.delay;
|
|
1667
|
-
|
|
1714
|
+
const sigGive = Math.sqrt(varicorr(g.give));
|
|
1715
|
+
const d = this.degr;
|
|
1716
|
+
const eiono = d ? sbasIonoDeg(d, now - g.t0s) : 0;
|
|
1717
|
+
const sig2 = d?.rssIono ? sigGive * sigGive + eiono * eiono : (sigGive + eiono) ** 2;
|
|
1718
|
+
varVert += w[i] * sig2;
|
|
1668
1719
|
}
|
|
1669
|
-
return { delayM: delay * fp, varM2:
|
|
1720
|
+
return { delayM: delay * fp, varM2: varVert * fp * fp };
|
|
1670
1721
|
}
|
|
1671
1722
|
/** Find the four IGPs bracketing a pierce point (RTKLIB `searchigp`). */
|
|
1672
1723
|
searchIgp(latP, lonP) {
|
|
@@ -3081,10 +3132,10 @@ function sagnac2(pos, travelTimeS) {
|
|
|
3081
3132
|
function sbasAirTropoVar(elRad) {
|
|
3082
3133
|
const elDeg = elRad * 180 / Math.PI;
|
|
3083
3134
|
const sigMp = 0.13 + 0.53 * Math.exp(-elDeg / 10);
|
|
3084
|
-
const
|
|
3135
|
+
const NOISE_DIVG_AADA = 0.36;
|
|
3085
3136
|
const m = 1.001 / Math.sqrt(2001e-6 + Math.sin(elRad) * Math.sin(elRad));
|
|
3086
3137
|
const sigTropo = 0.12 * m;
|
|
3087
|
-
return sigMp * sigMp +
|
|
3138
|
+
return sigMp * sigMp + NOISE_DIVG_AADA * NOISE_DIVG_AADA + sigTropo * sigTropo;
|
|
3088
3139
|
}
|
|
3089
3140
|
function invertMatrix(A) {
|
|
3090
3141
|
const n = A.length;
|
|
@@ -3380,6 +3431,8 @@ export {
|
|
|
3380
3431
|
solveDgnss,
|
|
3381
3432
|
RtkFloatEngine,
|
|
3382
3433
|
postProcessRtk,
|
|
3434
|
+
sbasLongTermDeg,
|
|
3435
|
+
sbasIonoDeg,
|
|
3383
3436
|
SbasProcessor,
|
|
3384
3437
|
niellMapping,
|
|
3385
3438
|
gmst,
|
|
@@ -756,13 +756,42 @@ function parseSbfGloNav(data) {
|
|
|
756
756
|
return { ephemerides, badCrc, messages };
|
|
757
757
|
}
|
|
758
758
|
|
|
759
|
+
// src/navbits/sbas-l5.ts
|
|
760
|
+
var SBAS_L5_PREAMBLE_UW = 6056250;
|
|
761
|
+
function isSbasL1Preamble(msg) {
|
|
762
|
+
return msg[0] === 83 || msg[0] === 154 || msg[0] === 198;
|
|
763
|
+
}
|
|
764
|
+
function sbasL5MessageType(msg) {
|
|
765
|
+
return getBitU(msg, 4, 6);
|
|
766
|
+
}
|
|
767
|
+
var SBAS_L5_MT_NAMES = {
|
|
768
|
+
0: "Do Not Use (test)",
|
|
769
|
+
31: "SBAS satellite mask",
|
|
770
|
+
32: "Satellite clock-ephemeris corrections + covariance",
|
|
771
|
+
34: "Integrity (DFREI/DFRECI)",
|
|
772
|
+
35: "Integrity (DFREI/DFRECI)",
|
|
773
|
+
36: "Integrity (DFREI/DFRECI)",
|
|
774
|
+
37: "Degradation parameters + DFREI scale table",
|
|
775
|
+
39: "SBAS satellite clock/ephemeris/covariance-1",
|
|
776
|
+
40: "SBAS satellite clock/ephemeris/covariance-2",
|
|
777
|
+
42: "SNT-to-UTC offset",
|
|
778
|
+
47: "SBAS satellite almanacs",
|
|
779
|
+
62: "Reserved",
|
|
780
|
+
63: "Null message"
|
|
781
|
+
};
|
|
782
|
+
function sbasL5MessageName(type) {
|
|
783
|
+
return SBAS_L5_MT_NAMES[type] ?? (type >= 1 && type <= 61 ? "Spare" : `Type ${type}`);
|
|
784
|
+
}
|
|
785
|
+
function isSbasL5Correction(type) {
|
|
786
|
+
return type === 31 || type === 32 || type >= 34 && type <= 37 || type === 39 || type === 40 || type === 42 || type === 47;
|
|
787
|
+
}
|
|
788
|
+
|
|
759
789
|
// src/sbf/rawnav-sbas.ts
|
|
760
|
-
function
|
|
790
|
+
function readGeoMessage(view, b) {
|
|
761
791
|
const tow = view.getUint32(b + 8, true);
|
|
762
792
|
const wnc = view.getUint16(b + 12, true);
|
|
763
|
-
const
|
|
764
|
-
|
|
765
|
-
if (!prnStr || prnStr[0] !== "S") return {};
|
|
793
|
+
const prnStr = svidToPrn(view.getUint8(b + 14));
|
|
794
|
+
if (!prnStr || prnStr[0] !== "S") return null;
|
|
766
795
|
const msg = new Uint8Array(32);
|
|
767
796
|
for (let k = 0; k < 8; k++) {
|
|
768
797
|
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
@@ -771,12 +800,29 @@ function feedGeoBlock(view, b, onSbasMessage) {
|
|
|
771
800
|
msg[4 * k + 2] = w >>> 8 & 255;
|
|
772
801
|
msg[4 * k + 3] = w & 255;
|
|
773
802
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
const
|
|
803
|
+
return { msg, prn: Number(prnStr.slice(1)) + 100, wnc, towSec: tow / 1e3 };
|
|
804
|
+
}
|
|
805
|
+
function feedGeoBlock(view, b, onSbasMessage) {
|
|
806
|
+
const g = readGeoMessage(view, b);
|
|
807
|
+
if (!g) return {};
|
|
808
|
+
if (!sbasCrcOk(g.msg)) return { badCrc: true };
|
|
809
|
+
onSbasMessage?.(g.msg, g.prn, g.wnc, g.towSec);
|
|
810
|
+
const eph = decodeSbasGeoNav(g.msg, g.prn, g.wnc, g.towSec);
|
|
778
811
|
return eph ? { eph } : {};
|
|
779
812
|
}
|
|
813
|
+
function feedGeoL5Block(view, b, onSbasMessage, onDfmcMessage) {
|
|
814
|
+
const g = readGeoMessage(view, b);
|
|
815
|
+
if (!g) return {};
|
|
816
|
+
if (!sbasCrcOk(g.msg)) return { badCrc: true };
|
|
817
|
+
if (isSbasL1Preamble(g.msg)) {
|
|
818
|
+
onSbasMessage?.(g.msg, g.prn, g.wnc, g.towSec);
|
|
819
|
+
const eph = decodeSbasGeoNav(g.msg, g.prn, g.wnc, g.towSec);
|
|
820
|
+
return eph ? { kind: "l1", eph } : { kind: "l1" };
|
|
821
|
+
}
|
|
822
|
+
const dfmcType = sbasL5MessageType(g.msg);
|
|
823
|
+
onDfmcMessage?.(g.msg, g.prn, g.wnc, g.towSec, dfmcType);
|
|
824
|
+
return { kind: "l5", dfmcType };
|
|
825
|
+
}
|
|
780
826
|
function parseSbfGeoNav(data, opts = {}) {
|
|
781
827
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
782
828
|
const ephemerides = [];
|
|
@@ -799,6 +845,47 @@ function parseSbfGeoNav(data, opts = {}) {
|
|
|
799
845
|
});
|
|
800
846
|
return { ephemerides, badCrc, messages };
|
|
801
847
|
}
|
|
848
|
+
function parseSbfGeoL5(data, opts = {}) {
|
|
849
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
850
|
+
const ephemerides = [];
|
|
851
|
+
const seen = /* @__PURE__ */ new Set();
|
|
852
|
+
const byType = {};
|
|
853
|
+
const dfmcPrns = /* @__PURE__ */ new Set();
|
|
854
|
+
let legacyMessages = 0;
|
|
855
|
+
let dfmcMessages = 0;
|
|
856
|
+
let badCrc = 0;
|
|
857
|
+
let messages = 0;
|
|
858
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
859
|
+
if (id !== 4021 || len < 52) return;
|
|
860
|
+
messages++;
|
|
861
|
+
const r = feedGeoL5Block(view, b, opts.onSbasMessage, opts.onDfmcMessage);
|
|
862
|
+
if (r.badCrc) {
|
|
863
|
+
badCrc++;
|
|
864
|
+
} else if (r.kind === "l1") {
|
|
865
|
+
legacyMessages++;
|
|
866
|
+
if (r.eph) {
|
|
867
|
+
const key = `${r.eph.prn}|${r.eph.tocDate.getTime()}`;
|
|
868
|
+
if (!seen.has(key)) {
|
|
869
|
+
seen.add(key);
|
|
870
|
+
ephemerides.push(r.eph);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
} else if (r.kind === "l5" && r.dfmcType !== void 0) {
|
|
874
|
+
dfmcMessages++;
|
|
875
|
+
byType[r.dfmcType] = (byType[r.dfmcType] ?? 0) + 1;
|
|
876
|
+
const prn = view.getUint8(b + 14);
|
|
877
|
+
const s = svidToPrn(prn);
|
|
878
|
+
if (s) dfmcPrns.add(s);
|
|
879
|
+
}
|
|
880
|
+
});
|
|
881
|
+
return {
|
|
882
|
+
ephemerides,
|
|
883
|
+
legacyMessages,
|
|
884
|
+
dfmc: { byType, prns: [...dfmcPrns].sort(), messages: dfmcMessages },
|
|
885
|
+
badCrc,
|
|
886
|
+
messages
|
|
887
|
+
};
|
|
888
|
+
}
|
|
802
889
|
|
|
803
890
|
// src/sbf/navigation.ts
|
|
804
891
|
var F4_DNU4 = -2e10;
|
|
@@ -821,8 +908,11 @@ function decodeSbfNavigation(data, opts = {}) {
|
|
|
821
908
|
gloRaw: 0,
|
|
822
909
|
bdsRaw: 0,
|
|
823
910
|
sbasRaw: 0,
|
|
911
|
+
sbasL5Raw: 0,
|
|
824
912
|
badFrames: 0
|
|
825
913
|
};
|
|
914
|
+
const dfmcByType = {};
|
|
915
|
+
const dfmcPrns = /* @__PURE__ */ new Set();
|
|
826
916
|
const cnavAsm = newCnavAssemblers();
|
|
827
917
|
const galAsm = newGalAssemblers();
|
|
828
918
|
const gloAsm = new GloStringAssembler();
|
|
@@ -932,6 +1022,25 @@ function decodeSbfNavigation(data, opts = {}) {
|
|
|
932
1022
|
else if (r.badCrc) counts.badFrames++;
|
|
933
1023
|
return;
|
|
934
1024
|
}
|
|
1025
|
+
case 4021: {
|
|
1026
|
+
if (len < 52) return;
|
|
1027
|
+
counts.sbasL5Raw++;
|
|
1028
|
+
const r = feedGeoL5Block(
|
|
1029
|
+
view,
|
|
1030
|
+
b,
|
|
1031
|
+
opts.onSbasMessage,
|
|
1032
|
+
opts.onDfmcMessage
|
|
1033
|
+
);
|
|
1034
|
+
if (r.badCrc) counts.badFrames++;
|
|
1035
|
+
else if (r.kind === "l1") {
|
|
1036
|
+
if (r.eph) addEph(r.eph);
|
|
1037
|
+
} else if (r.kind === "l5" && r.dfmcType !== void 0) {
|
|
1038
|
+
dfmcByType[r.dfmcType] = (dfmcByType[r.dfmcType] ?? 0) + 1;
|
|
1039
|
+
const s = svidToPrn(view.getUint8(b + 14));
|
|
1040
|
+
if (s) dfmcPrns.add(s);
|
|
1041
|
+
}
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
935
1044
|
/* ---- iono / UTC ---- */
|
|
936
1045
|
case 5893:
|
|
937
1046
|
// GPSIon
|
|
@@ -956,7 +1065,12 @@ function decodeSbfNavigation(data, opts = {}) {
|
|
|
956
1065
|
return;
|
|
957
1066
|
}
|
|
958
1067
|
});
|
|
959
|
-
|
|
1068
|
+
const dfmc = {
|
|
1069
|
+
byType: dfmcByType,
|
|
1070
|
+
prns: [...dfmcPrns].sort(),
|
|
1071
|
+
messages: Object.values(dfmcByType).reduce((a, v) => a + v, 0)
|
|
1072
|
+
};
|
|
1073
|
+
return { ephemerides, cnav, ionoCorrections, leapSeconds, dfmc, counts };
|
|
960
1074
|
}
|
|
961
1075
|
|
|
962
1076
|
// src/navbits/rs255.ts
|
|
@@ -2163,8 +2277,16 @@ export {
|
|
|
2163
2277
|
parseSbfGalNav,
|
|
2164
2278
|
parseSbfBdsNav,
|
|
2165
2279
|
parseSbfGloNav,
|
|
2280
|
+
SBAS_L5_PREAMBLE_UW,
|
|
2281
|
+
isSbasL1Preamble,
|
|
2282
|
+
sbasL5MessageType,
|
|
2283
|
+
SBAS_L5_MT_NAMES,
|
|
2284
|
+
sbasL5MessageName,
|
|
2285
|
+
isSbasL5Correction,
|
|
2166
2286
|
feedGeoBlock,
|
|
2287
|
+
feedGeoL5Block,
|
|
2167
2288
|
parseSbfGeoNav,
|
|
2289
|
+
parseSbfGeoL5,
|
|
2168
2290
|
decodeSbfNavigation,
|
|
2169
2291
|
parseSbfHas,
|
|
2170
2292
|
parseSbfMeas
|