gnss-js 1.59.0 → 1.60.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-7NZ4SJTJ.js → chunk-4WNIGDNR.js} +96 -3
- package/dist/index.cjs +96 -3
- package/dist/index.js +1 -1
- package/dist/positioning.cjs +96 -3
- package/dist/positioning.d.cts +13 -2
- package/dist/positioning.d.ts +13 -2
- package/dist/positioning.js +1 -1
- package/package.json +1 -1
|
@@ -1270,6 +1270,44 @@ var DEGF = [
|
|
|
1270
1270
|
58e-4
|
|
1271
1271
|
];
|
|
1272
1272
|
var degfcorr = (ai) => ai > 0 && ai <= 15 ? DEGF[ai] : 58e-4;
|
|
1273
|
+
var DELTA_UDRE = [
|
|
1274
|
+
1,
|
|
1275
|
+
1.1,
|
|
1276
|
+
1.25,
|
|
1277
|
+
1.5,
|
|
1278
|
+
2,
|
|
1279
|
+
3,
|
|
1280
|
+
4,
|
|
1281
|
+
5,
|
|
1282
|
+
6,
|
|
1283
|
+
8,
|
|
1284
|
+
10,
|
|
1285
|
+
20,
|
|
1286
|
+
30,
|
|
1287
|
+
40,
|
|
1288
|
+
50,
|
|
1289
|
+
100
|
|
1290
|
+
];
|
|
1291
|
+
function pointInRegion(lat, lon, rg) {
|
|
1292
|
+
const poly = rg.square ? [
|
|
1293
|
+
[rg.lat1, rg.lon1],
|
|
1294
|
+
[rg.lat1, rg.lon2],
|
|
1295
|
+
[rg.lat2, rg.lon2],
|
|
1296
|
+
[rg.lat2, rg.lon1]
|
|
1297
|
+
] : [
|
|
1298
|
+
[rg.lat1, rg.lon1],
|
|
1299
|
+
[rg.lat2, rg.lon2],
|
|
1300
|
+
[rg.lat1, rg.lon2]
|
|
1301
|
+
];
|
|
1302
|
+
let inside = false;
|
|
1303
|
+
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
|
|
1304
|
+
const [yi, xi] = poly[i];
|
|
1305
|
+
const [yj, xj] = poly[j];
|
|
1306
|
+
if (yi > lat !== yj > lat && lon < (xj - xi) * (lat - yi) / (yj - yi) + xi)
|
|
1307
|
+
inside = !inside;
|
|
1308
|
+
}
|
|
1309
|
+
return inside;
|
|
1310
|
+
}
|
|
1273
1311
|
function sbasLongTermDeg(d, vel, ageSec) {
|
|
1274
1312
|
if (vel) {
|
|
1275
1313
|
if (ageSec > 0 && ageSec < d.iltcV1) return 0;
|
|
@@ -1335,6 +1373,7 @@ var SbasProcessor = class {
|
|
|
1335
1373
|
iodp = -1;
|
|
1336
1374
|
tlat = 0;
|
|
1337
1375
|
degr = null;
|
|
1376
|
+
mt27 = null;
|
|
1338
1377
|
ion = [];
|
|
1339
1378
|
/** GEO PRN(s) whose messages have been ingested. */
|
|
1340
1379
|
geoPrns = /* @__PURE__ */ new Set();
|
|
@@ -1363,6 +1402,8 @@ var SbasProcessor = class {
|
|
|
1363
1402
|
return this.decodeDegradation(msg) ? type : -1;
|
|
1364
1403
|
case 10:
|
|
1365
1404
|
return this.decodeMt10(msg) ? type : -1;
|
|
1405
|
+
case 27:
|
|
1406
|
+
return this.decodeMt27(msg) ? type : -1;
|
|
1366
1407
|
case 18:
|
|
1367
1408
|
return this.decodeIgpMask(msg) ? type : -1;
|
|
1368
1409
|
case 24:
|
|
@@ -1455,6 +1496,54 @@ var SbasProcessor = class {
|
|
|
1455
1496
|
};
|
|
1456
1497
|
return true;
|
|
1457
1498
|
}
|
|
1499
|
+
/** MT27 SBAS service message (DO-229D §A.4.4.13, Table A-20): regions with a
|
|
1500
|
+
* δUDRE that inflates σ_UDRE for users inside/outside them. */
|
|
1501
|
+
decodeMt27(msg) {
|
|
1502
|
+
const iods = getBitU(msg, 14, 3);
|
|
1503
|
+
const svcNum = getBitU(msg, 20, 3) + 1;
|
|
1504
|
+
const nRegions = getBitU(msg, 23, 3);
|
|
1505
|
+
const priority = getBitU(msg, 26, 2);
|
|
1506
|
+
const udreInside = getBitU(msg, 28, 4);
|
|
1507
|
+
const udreOutside = getBitU(msg, 32, 4);
|
|
1508
|
+
if (!this.mt27 || this.mt27.iods !== iods)
|
|
1509
|
+
this.mt27 = { iods, udreOutside, msgs: /* @__PURE__ */ new Map() };
|
|
1510
|
+
this.mt27.udreOutside = udreOutside;
|
|
1511
|
+
const regions = [];
|
|
1512
|
+
for (let r = 0; r < nRegions && r < 5; r++) {
|
|
1513
|
+
const p = 36 + r * 35;
|
|
1514
|
+
regions.push({
|
|
1515
|
+
lat1: getBitS(msg, p, 8),
|
|
1516
|
+
lon1: getBitS(msg, p + 8, 9),
|
|
1517
|
+
lat2: getBitS(msg, p + 17, 8),
|
|
1518
|
+
lon2: getBitS(msg, p + 25, 9),
|
|
1519
|
+
square: getBitU(msg, p + 34, 1) === 1
|
|
1520
|
+
});
|
|
1521
|
+
}
|
|
1522
|
+
this.mt27.msgs.set(svcNum, { priority, udreInside, regions });
|
|
1523
|
+
return true;
|
|
1524
|
+
}
|
|
1525
|
+
/** δUDRE multiplier (DO-229D Table A-21) for a user location from the MT27
|
|
1526
|
+
* set: the highest-priority containing region wins (ties → lower δUDRE),
|
|
1527
|
+
* else the outside value. 1 when no MT27 has been received. */
|
|
1528
|
+
deltaUdre(latDeg, lonDeg) {
|
|
1529
|
+
const s = this.mt27;
|
|
1530
|
+
if (!s) return 1;
|
|
1531
|
+
let best = null;
|
|
1532
|
+
let bestPri = -1;
|
|
1533
|
+
for (const m of s.msgs.values()) {
|
|
1534
|
+
for (const rg of m.regions) {
|
|
1535
|
+
if (!pointInRegion(latDeg, lonDeg, rg)) continue;
|
|
1536
|
+
const val = DELTA_UDRE[m.udreInside] ?? 1;
|
|
1537
|
+
if (m.priority > bestPri) {
|
|
1538
|
+
bestPri = m.priority;
|
|
1539
|
+
best = val;
|
|
1540
|
+
} else if (m.priority === bestPri && best !== null) {
|
|
1541
|
+
best = Math.min(best, val);
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
return best ?? DELTA_UDRE[s.udreOutside] ?? 1;
|
|
1546
|
+
}
|
|
1458
1547
|
decodeMixed(msg, week, tow) {
|
|
1459
1548
|
if (this.iodp !== getBitU(msg, 110, 2)) return false;
|
|
1460
1549
|
const blk = getBitU(msg, 112, 2);
|
|
@@ -1626,7 +1715,7 @@ var SbasProcessor = class {
|
|
|
1626
1715
|
* no valid (unexpired) long-term + fast correction is available. Add `dPos`
|
|
1627
1716
|
* to the satellite ECEF position and `dClkS` to its clock bias.
|
|
1628
1717
|
*/
|
|
1629
|
-
satCorrection(prn, week, tow) {
|
|
1718
|
+
satCorrection(prn, week, tow, userLatRad, userLonRad) {
|
|
1630
1719
|
const idx = this.satIdx.get(prn);
|
|
1631
1720
|
if (idx === void 0) return null;
|
|
1632
1721
|
const s = this.sats[idx];
|
|
@@ -1648,7 +1737,11 @@ var SbasProcessor = class {
|
|
|
1648
1737
|
const tf = now - s.fcorr.t0s + this.tlat;
|
|
1649
1738
|
if (Math.abs(tf) > MAXSBSAGEF || s.fcorr.udre >= 15) return null;
|
|
1650
1739
|
const prc = s.fcorr.prc;
|
|
1651
|
-
const
|
|
1740
|
+
const dudre = userLatRad != null && userLonRad != null ? this.deltaUdre(
|
|
1741
|
+
userLatRad * 180 / Math.PI,
|
|
1742
|
+
userLonRad * 180 / Math.PI
|
|
1743
|
+
) : 1;
|
|
1744
|
+
const sigUdre = Math.sqrt(varfcorr(s.fcorr.udre)) * dudre;
|
|
1652
1745
|
const efc = degfcorr(s.fcorr.ai) * tf * tf / 2;
|
|
1653
1746
|
const eltc = this.degr && s.lcorr && s.lcorr.t0s !== 0 ? sbasLongTermDeg(this.degr, s.lcorr.vel, now - s.lcorr.t0s) : 0;
|
|
1654
1747
|
const varM2 = this.degr?.rssUdre ? sigUdre * sigUdre + efc * efc + eltc * eltc : (sigUdre + efc + eltc) ** 2;
|
|
@@ -3387,7 +3480,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
3387
3480
|
used.push(prn);
|
|
3388
3481
|
azels.push(azel);
|
|
3389
3482
|
if (sbas) {
|
|
3390
|
-
const sc = sbas.satCorrection(prn, gpsWeek, gpsTow);
|
|
3483
|
+
const sc = sbas.satCorrection(prn, gpsWeek, gpsTow, rxLat, rxLon);
|
|
3391
3484
|
const si = sbas.ionoDelay(
|
|
3392
3485
|
gpsWeek,
|
|
3393
3486
|
gpsTow,
|
package/dist/index.cjs
CHANGED
|
@@ -13480,6 +13480,44 @@ var DEGF = [
|
|
|
13480
13480
|
58e-4
|
|
13481
13481
|
];
|
|
13482
13482
|
var degfcorr = (ai) => ai > 0 && ai <= 15 ? DEGF[ai] : 58e-4;
|
|
13483
|
+
var DELTA_UDRE = [
|
|
13484
|
+
1,
|
|
13485
|
+
1.1,
|
|
13486
|
+
1.25,
|
|
13487
|
+
1.5,
|
|
13488
|
+
2,
|
|
13489
|
+
3,
|
|
13490
|
+
4,
|
|
13491
|
+
5,
|
|
13492
|
+
6,
|
|
13493
|
+
8,
|
|
13494
|
+
10,
|
|
13495
|
+
20,
|
|
13496
|
+
30,
|
|
13497
|
+
40,
|
|
13498
|
+
50,
|
|
13499
|
+
100
|
|
13500
|
+
];
|
|
13501
|
+
function pointInRegion(lat, lon, rg) {
|
|
13502
|
+
const poly = rg.square ? [
|
|
13503
|
+
[rg.lat1, rg.lon1],
|
|
13504
|
+
[rg.lat1, rg.lon2],
|
|
13505
|
+
[rg.lat2, rg.lon2],
|
|
13506
|
+
[rg.lat2, rg.lon1]
|
|
13507
|
+
] : [
|
|
13508
|
+
[rg.lat1, rg.lon1],
|
|
13509
|
+
[rg.lat2, rg.lon2],
|
|
13510
|
+
[rg.lat1, rg.lon2]
|
|
13511
|
+
];
|
|
13512
|
+
let inside = false;
|
|
13513
|
+
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
|
|
13514
|
+
const [yi, xi] = poly[i];
|
|
13515
|
+
const [yj, xj] = poly[j];
|
|
13516
|
+
if (yi > lat !== yj > lat && lon < (xj - xi) * (lat - yi) / (yj - yi) + xi)
|
|
13517
|
+
inside = !inside;
|
|
13518
|
+
}
|
|
13519
|
+
return inside;
|
|
13520
|
+
}
|
|
13483
13521
|
function sbasLongTermDeg(d, vel, ageSec) {
|
|
13484
13522
|
if (vel) {
|
|
13485
13523
|
if (ageSec > 0 && ageSec < d.iltcV1) return 0;
|
|
@@ -13545,6 +13583,7 @@ var SbasProcessor = class {
|
|
|
13545
13583
|
iodp = -1;
|
|
13546
13584
|
tlat = 0;
|
|
13547
13585
|
degr = null;
|
|
13586
|
+
mt27 = null;
|
|
13548
13587
|
ion = [];
|
|
13549
13588
|
/** GEO PRN(s) whose messages have been ingested. */
|
|
13550
13589
|
geoPrns = /* @__PURE__ */ new Set();
|
|
@@ -13573,6 +13612,8 @@ var SbasProcessor = class {
|
|
|
13573
13612
|
return this.decodeDegradation(msg) ? type : -1;
|
|
13574
13613
|
case 10:
|
|
13575
13614
|
return this.decodeMt10(msg) ? type : -1;
|
|
13615
|
+
case 27:
|
|
13616
|
+
return this.decodeMt27(msg) ? type : -1;
|
|
13576
13617
|
case 18:
|
|
13577
13618
|
return this.decodeIgpMask(msg) ? type : -1;
|
|
13578
13619
|
case 24:
|
|
@@ -13665,6 +13706,54 @@ var SbasProcessor = class {
|
|
|
13665
13706
|
};
|
|
13666
13707
|
return true;
|
|
13667
13708
|
}
|
|
13709
|
+
/** MT27 SBAS service message (DO-229D §A.4.4.13, Table A-20): regions with a
|
|
13710
|
+
* δUDRE that inflates σ_UDRE for users inside/outside them. */
|
|
13711
|
+
decodeMt27(msg) {
|
|
13712
|
+
const iods = getBitU(msg, 14, 3);
|
|
13713
|
+
const svcNum = getBitU(msg, 20, 3) + 1;
|
|
13714
|
+
const nRegions = getBitU(msg, 23, 3);
|
|
13715
|
+
const priority = getBitU(msg, 26, 2);
|
|
13716
|
+
const udreInside = getBitU(msg, 28, 4);
|
|
13717
|
+
const udreOutside = getBitU(msg, 32, 4);
|
|
13718
|
+
if (!this.mt27 || this.mt27.iods !== iods)
|
|
13719
|
+
this.mt27 = { iods, udreOutside, msgs: /* @__PURE__ */ new Map() };
|
|
13720
|
+
this.mt27.udreOutside = udreOutside;
|
|
13721
|
+
const regions = [];
|
|
13722
|
+
for (let r = 0; r < nRegions && r < 5; r++) {
|
|
13723
|
+
const p = 36 + r * 35;
|
|
13724
|
+
regions.push({
|
|
13725
|
+
lat1: getBitS(msg, p, 8),
|
|
13726
|
+
lon1: getBitS(msg, p + 8, 9),
|
|
13727
|
+
lat2: getBitS(msg, p + 17, 8),
|
|
13728
|
+
lon2: getBitS(msg, p + 25, 9),
|
|
13729
|
+
square: getBitU(msg, p + 34, 1) === 1
|
|
13730
|
+
});
|
|
13731
|
+
}
|
|
13732
|
+
this.mt27.msgs.set(svcNum, { priority, udreInside, regions });
|
|
13733
|
+
return true;
|
|
13734
|
+
}
|
|
13735
|
+
/** δUDRE multiplier (DO-229D Table A-21) for a user location from the MT27
|
|
13736
|
+
* set: the highest-priority containing region wins (ties → lower δUDRE),
|
|
13737
|
+
* else the outside value. 1 when no MT27 has been received. */
|
|
13738
|
+
deltaUdre(latDeg, lonDeg) {
|
|
13739
|
+
const s = this.mt27;
|
|
13740
|
+
if (!s) return 1;
|
|
13741
|
+
let best = null;
|
|
13742
|
+
let bestPri = -1;
|
|
13743
|
+
for (const m of s.msgs.values()) {
|
|
13744
|
+
for (const rg of m.regions) {
|
|
13745
|
+
if (!pointInRegion(latDeg, lonDeg, rg)) continue;
|
|
13746
|
+
const val = DELTA_UDRE[m.udreInside] ?? 1;
|
|
13747
|
+
if (m.priority > bestPri) {
|
|
13748
|
+
bestPri = m.priority;
|
|
13749
|
+
best = val;
|
|
13750
|
+
} else if (m.priority === bestPri && best !== null) {
|
|
13751
|
+
best = Math.min(best, val);
|
|
13752
|
+
}
|
|
13753
|
+
}
|
|
13754
|
+
}
|
|
13755
|
+
return best ?? DELTA_UDRE[s.udreOutside] ?? 1;
|
|
13756
|
+
}
|
|
13668
13757
|
decodeMixed(msg, week, tow) {
|
|
13669
13758
|
if (this.iodp !== getBitU(msg, 110, 2)) return false;
|
|
13670
13759
|
const blk = getBitU(msg, 112, 2);
|
|
@@ -13836,7 +13925,7 @@ var SbasProcessor = class {
|
|
|
13836
13925
|
* no valid (unexpired) long-term + fast correction is available. Add `dPos`
|
|
13837
13926
|
* to the satellite ECEF position and `dClkS` to its clock bias.
|
|
13838
13927
|
*/
|
|
13839
|
-
satCorrection(prn, week, tow) {
|
|
13928
|
+
satCorrection(prn, week, tow, userLatRad, userLonRad) {
|
|
13840
13929
|
const idx = this.satIdx.get(prn);
|
|
13841
13930
|
if (idx === void 0) return null;
|
|
13842
13931
|
const s = this.sats[idx];
|
|
@@ -13858,7 +13947,11 @@ var SbasProcessor = class {
|
|
|
13858
13947
|
const tf = now - s.fcorr.t0s + this.tlat;
|
|
13859
13948
|
if (Math.abs(tf) > MAXSBSAGEF || s.fcorr.udre >= 15) return null;
|
|
13860
13949
|
const prc = s.fcorr.prc;
|
|
13861
|
-
const
|
|
13950
|
+
const dudre = userLatRad != null && userLonRad != null ? this.deltaUdre(
|
|
13951
|
+
userLatRad * 180 / Math.PI,
|
|
13952
|
+
userLonRad * 180 / Math.PI
|
|
13953
|
+
) : 1;
|
|
13954
|
+
const sigUdre = Math.sqrt(varfcorr(s.fcorr.udre)) * dudre;
|
|
13862
13955
|
const efc = degfcorr(s.fcorr.ai) * tf * tf / 2;
|
|
13863
13956
|
const eltc = this.degr && s.lcorr && s.lcorr.t0s !== 0 ? sbasLongTermDeg(this.degr, s.lcorr.vel, now - s.lcorr.t0s) : 0;
|
|
13864
13957
|
const varM2 = this.degr?.rssUdre ? sigUdre * sigUdre + efc * efc + eltc * eltc : (sigUdre + efc + eltc) ** 2;
|
|
@@ -15597,7 +15690,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
15597
15690
|
used.push(prn);
|
|
15598
15691
|
azels.push(azel);
|
|
15599
15692
|
if (sbas) {
|
|
15600
|
-
const sc = sbas.satCorrection(prn, gpsWeek, gpsTow);
|
|
15693
|
+
const sc = sbas.satCorrection(prn, gpsWeek, gpsTow, rxLat, rxLon);
|
|
15601
15694
|
const si = sbas.ionoDelay(
|
|
15602
15695
|
gpsWeek,
|
|
15603
15696
|
gpsTow,
|
package/dist/index.js
CHANGED
package/dist/positioning.cjs
CHANGED
|
@@ -1746,6 +1746,44 @@ var DEGF = [
|
|
|
1746
1746
|
58e-4
|
|
1747
1747
|
];
|
|
1748
1748
|
var degfcorr = (ai) => ai > 0 && ai <= 15 ? DEGF[ai] : 58e-4;
|
|
1749
|
+
var DELTA_UDRE = [
|
|
1750
|
+
1,
|
|
1751
|
+
1.1,
|
|
1752
|
+
1.25,
|
|
1753
|
+
1.5,
|
|
1754
|
+
2,
|
|
1755
|
+
3,
|
|
1756
|
+
4,
|
|
1757
|
+
5,
|
|
1758
|
+
6,
|
|
1759
|
+
8,
|
|
1760
|
+
10,
|
|
1761
|
+
20,
|
|
1762
|
+
30,
|
|
1763
|
+
40,
|
|
1764
|
+
50,
|
|
1765
|
+
100
|
|
1766
|
+
];
|
|
1767
|
+
function pointInRegion(lat, lon, rg) {
|
|
1768
|
+
const poly = rg.square ? [
|
|
1769
|
+
[rg.lat1, rg.lon1],
|
|
1770
|
+
[rg.lat1, rg.lon2],
|
|
1771
|
+
[rg.lat2, rg.lon2],
|
|
1772
|
+
[rg.lat2, rg.lon1]
|
|
1773
|
+
] : [
|
|
1774
|
+
[rg.lat1, rg.lon1],
|
|
1775
|
+
[rg.lat2, rg.lon2],
|
|
1776
|
+
[rg.lat1, rg.lon2]
|
|
1777
|
+
];
|
|
1778
|
+
let inside = false;
|
|
1779
|
+
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
|
|
1780
|
+
const [yi, xi] = poly[i];
|
|
1781
|
+
const [yj, xj] = poly[j];
|
|
1782
|
+
if (yi > lat !== yj > lat && lon < (xj - xi) * (lat - yi) / (yj - yi) + xi)
|
|
1783
|
+
inside = !inside;
|
|
1784
|
+
}
|
|
1785
|
+
return inside;
|
|
1786
|
+
}
|
|
1749
1787
|
function sbasLongTermDeg(d, vel, ageSec) {
|
|
1750
1788
|
if (vel) {
|
|
1751
1789
|
if (ageSec > 0 && ageSec < d.iltcV1) return 0;
|
|
@@ -1811,6 +1849,7 @@ var SbasProcessor = class {
|
|
|
1811
1849
|
iodp = -1;
|
|
1812
1850
|
tlat = 0;
|
|
1813
1851
|
degr = null;
|
|
1852
|
+
mt27 = null;
|
|
1814
1853
|
ion = [];
|
|
1815
1854
|
/** GEO PRN(s) whose messages have been ingested. */
|
|
1816
1855
|
geoPrns = /* @__PURE__ */ new Set();
|
|
@@ -1839,6 +1878,8 @@ var SbasProcessor = class {
|
|
|
1839
1878
|
return this.decodeDegradation(msg) ? type : -1;
|
|
1840
1879
|
case 10:
|
|
1841
1880
|
return this.decodeMt10(msg) ? type : -1;
|
|
1881
|
+
case 27:
|
|
1882
|
+
return this.decodeMt27(msg) ? type : -1;
|
|
1842
1883
|
case 18:
|
|
1843
1884
|
return this.decodeIgpMask(msg) ? type : -1;
|
|
1844
1885
|
case 24:
|
|
@@ -1931,6 +1972,54 @@ var SbasProcessor = class {
|
|
|
1931
1972
|
};
|
|
1932
1973
|
return true;
|
|
1933
1974
|
}
|
|
1975
|
+
/** MT27 SBAS service message (DO-229D §A.4.4.13, Table A-20): regions with a
|
|
1976
|
+
* δUDRE that inflates σ_UDRE for users inside/outside them. */
|
|
1977
|
+
decodeMt27(msg) {
|
|
1978
|
+
const iods = getBitU(msg, 14, 3);
|
|
1979
|
+
const svcNum = getBitU(msg, 20, 3) + 1;
|
|
1980
|
+
const nRegions = getBitU(msg, 23, 3);
|
|
1981
|
+
const priority = getBitU(msg, 26, 2);
|
|
1982
|
+
const udreInside = getBitU(msg, 28, 4);
|
|
1983
|
+
const udreOutside = getBitU(msg, 32, 4);
|
|
1984
|
+
if (!this.mt27 || this.mt27.iods !== iods)
|
|
1985
|
+
this.mt27 = { iods, udreOutside, msgs: /* @__PURE__ */ new Map() };
|
|
1986
|
+
this.mt27.udreOutside = udreOutside;
|
|
1987
|
+
const regions = [];
|
|
1988
|
+
for (let r = 0; r < nRegions && r < 5; r++) {
|
|
1989
|
+
const p = 36 + r * 35;
|
|
1990
|
+
regions.push({
|
|
1991
|
+
lat1: getBitS(msg, p, 8),
|
|
1992
|
+
lon1: getBitS(msg, p + 8, 9),
|
|
1993
|
+
lat2: getBitS(msg, p + 17, 8),
|
|
1994
|
+
lon2: getBitS(msg, p + 25, 9),
|
|
1995
|
+
square: getBitU(msg, p + 34, 1) === 1
|
|
1996
|
+
});
|
|
1997
|
+
}
|
|
1998
|
+
this.mt27.msgs.set(svcNum, { priority, udreInside, regions });
|
|
1999
|
+
return true;
|
|
2000
|
+
}
|
|
2001
|
+
/** δUDRE multiplier (DO-229D Table A-21) for a user location from the MT27
|
|
2002
|
+
* set: the highest-priority containing region wins (ties → lower δUDRE),
|
|
2003
|
+
* else the outside value. 1 when no MT27 has been received. */
|
|
2004
|
+
deltaUdre(latDeg, lonDeg) {
|
|
2005
|
+
const s = this.mt27;
|
|
2006
|
+
if (!s) return 1;
|
|
2007
|
+
let best = null;
|
|
2008
|
+
let bestPri = -1;
|
|
2009
|
+
for (const m of s.msgs.values()) {
|
|
2010
|
+
for (const rg of m.regions) {
|
|
2011
|
+
if (!pointInRegion(latDeg, lonDeg, rg)) continue;
|
|
2012
|
+
const val = DELTA_UDRE[m.udreInside] ?? 1;
|
|
2013
|
+
if (m.priority > bestPri) {
|
|
2014
|
+
bestPri = m.priority;
|
|
2015
|
+
best = val;
|
|
2016
|
+
} else if (m.priority === bestPri && best !== null) {
|
|
2017
|
+
best = Math.min(best, val);
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
return best ?? DELTA_UDRE[s.udreOutside] ?? 1;
|
|
2022
|
+
}
|
|
1934
2023
|
decodeMixed(msg, week, tow) {
|
|
1935
2024
|
if (this.iodp !== getBitU(msg, 110, 2)) return false;
|
|
1936
2025
|
const blk = getBitU(msg, 112, 2);
|
|
@@ -2102,7 +2191,7 @@ var SbasProcessor = class {
|
|
|
2102
2191
|
* no valid (unexpired) long-term + fast correction is available. Add `dPos`
|
|
2103
2192
|
* to the satellite ECEF position and `dClkS` to its clock bias.
|
|
2104
2193
|
*/
|
|
2105
|
-
satCorrection(prn, week, tow) {
|
|
2194
|
+
satCorrection(prn, week, tow, userLatRad, userLonRad) {
|
|
2106
2195
|
const idx = this.satIdx.get(prn);
|
|
2107
2196
|
if (idx === void 0) return null;
|
|
2108
2197
|
const s = this.sats[idx];
|
|
@@ -2124,7 +2213,11 @@ var SbasProcessor = class {
|
|
|
2124
2213
|
const tf = now - s.fcorr.t0s + this.tlat;
|
|
2125
2214
|
if (Math.abs(tf) > MAXSBSAGEF || s.fcorr.udre >= 15) return null;
|
|
2126
2215
|
const prc = s.fcorr.prc;
|
|
2127
|
-
const
|
|
2216
|
+
const dudre = userLatRad != null && userLonRad != null ? this.deltaUdre(
|
|
2217
|
+
userLatRad * 180 / Math.PI,
|
|
2218
|
+
userLonRad * 180 / Math.PI
|
|
2219
|
+
) : 1;
|
|
2220
|
+
const sigUdre = Math.sqrt(varfcorr(s.fcorr.udre)) * dudre;
|
|
2128
2221
|
const efc = degfcorr(s.fcorr.ai) * tf * tf / 2;
|
|
2129
2222
|
const eltc = this.degr && s.lcorr && s.lcorr.t0s !== 0 ? sbasLongTermDeg(this.degr, s.lcorr.vel, now - s.lcorr.t0s) : 0;
|
|
2130
2223
|
const varM2 = this.degr?.rssUdre ? sigUdre * sigUdre + efc * efc + eltc * eltc : (sigUdre + efc + eltc) ** 2;
|
|
@@ -3935,7 +4028,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
3935
4028
|
used.push(prn);
|
|
3936
4029
|
azels.push(azel);
|
|
3937
4030
|
if (sbas) {
|
|
3938
|
-
const sc = sbas.satCorrection(prn, gpsWeek, gpsTow);
|
|
4031
|
+
const sc = sbas.satCorrection(prn, gpsWeek, gpsTow, rxLat, rxLon);
|
|
3939
4032
|
const si = sbas.ionoDelay(
|
|
3940
4033
|
gpsWeek,
|
|
3941
4034
|
gpsTow,
|
package/dist/positioning.d.cts
CHANGED
|
@@ -605,6 +605,7 @@ declare class SbasProcessor {
|
|
|
605
605
|
private iodp;
|
|
606
606
|
private tlat;
|
|
607
607
|
private degr;
|
|
608
|
+
private mt27;
|
|
608
609
|
private ion;
|
|
609
610
|
/** GEO PRN(s) whose messages have been ingested. */
|
|
610
611
|
readonly geoPrns: Set<string>;
|
|
@@ -622,6 +623,13 @@ declare class SbasProcessor {
|
|
|
622
623
|
* preamble + 6-bit type (start bit 14), MSB-first, with the listed LSBs.
|
|
623
624
|
* Iiono / Iltc_v0 of 0 must be read as 1 (Table A-9, Note 3). */
|
|
624
625
|
private decodeMt10;
|
|
626
|
+
/** MT27 SBAS service message (DO-229D §A.4.4.13, Table A-20): regions with a
|
|
627
|
+
* δUDRE that inflates σ_UDRE for users inside/outside them. */
|
|
628
|
+
private decodeMt27;
|
|
629
|
+
/** δUDRE multiplier (DO-229D Table A-21) for a user location from the MT27
|
|
630
|
+
* set: the highest-priority containing region wins (ties → lower δUDRE),
|
|
631
|
+
* else the outside value. 1 when no MT27 has been received. */
|
|
632
|
+
deltaUdre(latDeg: number, lonDeg: number): number;
|
|
625
633
|
private decodeMixed;
|
|
626
634
|
private decodeLongCorrHalf;
|
|
627
635
|
private decodeLong0;
|
|
@@ -657,7 +665,7 @@ declare class SbasProcessor {
|
|
|
657
665
|
* no valid (unexpired) long-term + fast correction is available. Add `dPos`
|
|
658
666
|
* to the satellite ECEF position and `dClkS` to its clock bias.
|
|
659
667
|
*/
|
|
660
|
-
satCorrection(prn: string, week: number, tow: number): SbasSatCorrection | null;
|
|
668
|
+
satCorrection(prn: string, week: number, tow: number, userLatRad?: number, userLonRad?: number): SbasSatCorrection | null;
|
|
661
669
|
/** The last-decoded MT10 degradation factors, or null if none seen. */
|
|
662
670
|
get degradation(): Readonly<Degradation> | null;
|
|
663
671
|
/**
|
|
@@ -1292,7 +1300,10 @@ interface SppOptions {
|
|
|
1292
1300
|
/** The two SBAS corrections `solveSpp` consumes — {@link ./sbas.SbasProcessor}
|
|
1293
1301
|
* satisfies this structurally. */
|
|
1294
1302
|
interface SbasCorrectionSource {
|
|
1295
|
-
satCorrection(prn: string, week: number, tow: number
|
|
1303
|
+
satCorrection(prn: string, week: number, tow: number,
|
|
1304
|
+
/** User geodetic lat/lon (rad) for the MT27 service-region δUDRE, when
|
|
1305
|
+
* known (the final protection-level pass). Omitted during iteration. */
|
|
1306
|
+
userLatRad?: number, userLonRad?: number): {
|
|
1296
1307
|
dPos: [number, number, number];
|
|
1297
1308
|
dClkS: number;
|
|
1298
1309
|
varM2: number;
|
package/dist/positioning.d.ts
CHANGED
|
@@ -605,6 +605,7 @@ declare class SbasProcessor {
|
|
|
605
605
|
private iodp;
|
|
606
606
|
private tlat;
|
|
607
607
|
private degr;
|
|
608
|
+
private mt27;
|
|
608
609
|
private ion;
|
|
609
610
|
/** GEO PRN(s) whose messages have been ingested. */
|
|
610
611
|
readonly geoPrns: Set<string>;
|
|
@@ -622,6 +623,13 @@ declare class SbasProcessor {
|
|
|
622
623
|
* preamble + 6-bit type (start bit 14), MSB-first, with the listed LSBs.
|
|
623
624
|
* Iiono / Iltc_v0 of 0 must be read as 1 (Table A-9, Note 3). */
|
|
624
625
|
private decodeMt10;
|
|
626
|
+
/** MT27 SBAS service message (DO-229D §A.4.4.13, Table A-20): regions with a
|
|
627
|
+
* δUDRE that inflates σ_UDRE for users inside/outside them. */
|
|
628
|
+
private decodeMt27;
|
|
629
|
+
/** δUDRE multiplier (DO-229D Table A-21) for a user location from the MT27
|
|
630
|
+
* set: the highest-priority containing region wins (ties → lower δUDRE),
|
|
631
|
+
* else the outside value. 1 when no MT27 has been received. */
|
|
632
|
+
deltaUdre(latDeg: number, lonDeg: number): number;
|
|
625
633
|
private decodeMixed;
|
|
626
634
|
private decodeLongCorrHalf;
|
|
627
635
|
private decodeLong0;
|
|
@@ -657,7 +665,7 @@ declare class SbasProcessor {
|
|
|
657
665
|
* no valid (unexpired) long-term + fast correction is available. Add `dPos`
|
|
658
666
|
* to the satellite ECEF position and `dClkS` to its clock bias.
|
|
659
667
|
*/
|
|
660
|
-
satCorrection(prn: string, week: number, tow: number): SbasSatCorrection | null;
|
|
668
|
+
satCorrection(prn: string, week: number, tow: number, userLatRad?: number, userLonRad?: number): SbasSatCorrection | null;
|
|
661
669
|
/** The last-decoded MT10 degradation factors, or null if none seen. */
|
|
662
670
|
get degradation(): Readonly<Degradation> | null;
|
|
663
671
|
/**
|
|
@@ -1292,7 +1300,10 @@ interface SppOptions {
|
|
|
1292
1300
|
/** The two SBAS corrections `solveSpp` consumes — {@link ./sbas.SbasProcessor}
|
|
1293
1301
|
* satisfies this structurally. */
|
|
1294
1302
|
interface SbasCorrectionSource {
|
|
1295
|
-
satCorrection(prn: string, week: number, tow: number
|
|
1303
|
+
satCorrection(prn: string, week: number, tow: number,
|
|
1304
|
+
/** User geodetic lat/lon (rad) for the MT27 service-region δUDRE, when
|
|
1305
|
+
* known (the final protection-level pass). Omitted during iteration. */
|
|
1306
|
+
userLatRad?: number, userLonRad?: number): {
|
|
1296
1307
|
dPos: [number, number, number];
|
|
1297
1308
|
dClkS: number;
|
|
1298
1309
|
varM2: number;
|
package/dist/positioning.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gnss-js",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.60.0",
|
|
4
4
|
"description": "Comprehensive GNSS library for JavaScript — time scales, coordinates, RINEX parsing, RTCM3 decoding, orbit computation, and signal analysis",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|