gnss-js 1.48.0 → 1.49.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/index.js CHANGED
@@ -50,7 +50,7 @@ import {
50
50
  parseUbxRawNav,
51
51
  parseUbxRawx,
52
52
  ubxFrames
53
- } from "./chunk-EQNC24OB.js";
53
+ } from "./chunk-DEVUKH6A.js";
54
54
  import {
55
55
  crc16,
56
56
  decodeSbfNavigation,
@@ -68,7 +68,7 @@ import {
68
68
  parseSbfNav,
69
69
  parseSbfReceiverSetup,
70
70
  scanSbfFrames
71
- } from "./chunk-MEDAWNWM.js";
71
+ } from "./chunk-XFPDTGSV.js";
72
72
  import "./chunk-FA2UTLEQ.js";
73
73
  import {
74
74
  OEM4_HLEN,
@@ -76,8 +76,7 @@ import {
76
76
  oem4Frames,
77
77
  parseNovatelNav,
78
78
  parseNovatelRange
79
- } from "./chunk-ROVSSEGZ.js";
80
- import "./chunk-ZIGMN3E5.js";
79
+ } from "./chunk-2IM5JYKP.js";
81
80
  import {
82
81
  parseTrimble,
83
82
  parseTrimbleNav,
@@ -137,6 +136,7 @@ import {
137
136
  import {
138
137
  IONO_L1_M_PER_TECU,
139
138
  RtkFloatEngine,
139
+ SbasProcessor,
140
140
  buildPppAntenna,
141
141
  createPppCorrections,
142
142
  estimateNarrowlaneFcb,
@@ -164,7 +164,8 @@ import {
164
164
  sunEcef,
165
165
  toRtkEpoch,
166
166
  wlWavelength
167
- } from "./chunk-KRXX4UGR.js";
167
+ } from "./chunk-DWLVCXA6.js";
168
+ import "./chunk-WQX354KD.js";
168
169
  import {
169
170
  almanacEpochMs,
170
171
  almanacSatPosition,
@@ -236,8 +237,6 @@ import {
236
237
  writeRinexNav4,
237
238
  writeRinexObsBlob
238
239
  } from "./chunk-6SWJTN6H.js";
239
- import "./chunk-YUW33VXK.js";
240
- import "./chunk-V2D5KUKH.js";
241
240
  import {
242
241
  SYSTEM_ORDER,
243
242
  crxDecompress,
@@ -253,6 +252,8 @@ import {
253
252
  parseSp3,
254
253
  sp3Position
255
254
  } from "./chunk-GPEP67TG.js";
255
+ import "./chunk-YUW33VXK.js";
256
+ import "./chunk-V2D5KUKH.js";
256
257
  import {
257
258
  BitReader,
258
259
  RTCM3_MESSAGE_NAMES,
@@ -435,6 +436,7 @@ export {
435
436
  SYSTEM_NAMES,
436
437
  SYSTEM_ORDER,
437
438
  SYS_SHORT,
439
+ SbasProcessor,
438
440
  Scale,
439
441
  WGS84_ECCENTRICITY_SQUARED,
440
442
  WGS84_FLATTENING,
package/dist/novatel.js CHANGED
@@ -4,8 +4,8 @@ import {
4
4
  oem4Frames,
5
5
  parseNovatelNav,
6
6
  parseNovatelRange
7
- } from "./chunk-ROVSSEGZ.js";
8
- import "./chunk-ZIGMN3E5.js";
7
+ } from "./chunk-2IM5JYKP.js";
8
+ import "./chunk-WQX354KD.js";
9
9
  import "./chunk-YUW33VXK.js";
10
10
  import "./chunk-V2D5KUKH.js";
11
11
  import "./chunk-HVXYFUCB.js";
@@ -22,6 +22,7 @@ var positioning_exports = {};
22
22
  __export(positioning_exports, {
23
23
  IONO_L1_M_PER_TECU: () => IONO_L1_M_PER_TECU,
24
24
  RtkFloatEngine: () => RtkFloatEngine,
25
+ SbasProcessor: () => SbasProcessor,
25
26
  buildPppAntenna: () => buildPppAntenna,
26
27
  createPppCorrections: () => createPppCorrections,
27
28
  estimateNarrowlaneFcb: () => estimateNarrowlaneFcb,
@@ -450,8 +451,8 @@ function computeSatPosition(eph, timeMs) {
450
451
  return glonassPosition(eph, (timeMs - leapMs) / 1e3);
451
452
  }
452
453
  const GPS_EPOCH = START_GPS_TIME.getTime();
453
- const gpsSeconds = (timeMs - GPS_EPOCH) / 1e3;
454
- let tow = gpsSeconds % (7 * 86400);
454
+ const gpsSeconds2 = (timeMs - GPS_EPOCH) / 1e3;
455
+ let tow = gpsSeconds2 % (7 * 86400);
455
456
  if (eph.system === "C") tow = (tow - 14 + 604800) % 604800;
456
457
  return keplerPosition(eph, tow);
457
458
  }
@@ -501,8 +502,8 @@ function klobucharDelay(coeffs, latRad, lonRad, azRad, elRad, gpsTowSec) {
501
502
  const F = 1 + 16 * Math.pow(0.53 - E, 3);
502
503
  const x = 2 * Math.PI * (t - 50400) / per;
503
504
  if (Math.abs(x) >= 1.57) return F * 5e-9;
504
- const x2 = x * x;
505
- return F * (5e-9 + amp * (1 - x2 / 2 + x2 * x2 / 24));
505
+ const x22 = x * x;
506
+ return F * (5e-9 + amp * (1 - x22 / 2 + x22 * x22 / 24));
506
507
  }
507
508
 
508
509
  // src/positioning/gim.ts
@@ -1654,6 +1655,515 @@ function postProcessRtk(base, rover, ephemerides, baseEcef, opts = {}) {
1654
1655
  return { track, solved, unmatched, fixRate: solved ? fixed / solved : 0 };
1655
1656
  }
1656
1657
 
1658
+ // src/navbits/index.ts
1659
+ var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
1660
+ var SEC_PER_WEEK = 7 * 86400;
1661
+ function getBitU(buff, pos, len) {
1662
+ let bits = 0;
1663
+ for (let i = pos; i < pos + len; i++) {
1664
+ bits = bits * 2 + (buff[i >> 3] >> 7 - (i & 7) & 1);
1665
+ }
1666
+ return bits;
1667
+ }
1668
+ function getBitS(buff, pos, len) {
1669
+ const bits = getBitU(buff, pos, len);
1670
+ if (len <= 0 || bits < 2 ** (len - 1)) return bits;
1671
+ return bits - 2 ** len;
1672
+ }
1673
+
1674
+ // src/navbits/sbas.ts
1675
+ var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
1676
+ var MS_PER_WEEK2 = 7 * 86400 * 1e3;
1677
+ function sbasMessageType(msg) {
1678
+ return getBitU(msg, 8, 6);
1679
+ }
1680
+
1681
+ // src/positioning/sbas.ts
1682
+ var P2_11 = 2 ** -11;
1683
+ var P2_31 = 2 ** -31;
1684
+ var P2_39 = 2 ** -39;
1685
+ var D2R = Math.PI / 180;
1686
+ var R2D = 180 / Math.PI;
1687
+ var SEC_PER_WEEK2 = 604800;
1688
+ var MAXSBSAGEF = 30;
1689
+ var MAXSBSAGEL = 1800;
1690
+ var MAXBAND = 10;
1691
+ var two = (n) => String(n).padStart(2, "0");
1692
+ var VAR_FCORR = [
1693
+ 0.052,
1694
+ 0.0924,
1695
+ 0.1444,
1696
+ 0.283,
1697
+ 0.4678,
1698
+ 0.8315,
1699
+ 1.2992,
1700
+ 1.8709,
1701
+ 2.5465,
1702
+ 3.326,
1703
+ 5.1968,
1704
+ 20.787,
1705
+ 230.9661,
1706
+ 2078.695
1707
+ ];
1708
+ var varfcorr = (udre) => udre > 0 && udre <= 14 ? VAR_FCORR[udre - 1] : 0;
1709
+ var VAR_ICORR = [
1710
+ 84e-4,
1711
+ 0.0333,
1712
+ 0.0749,
1713
+ 0.1331,
1714
+ 0.2079,
1715
+ 0.2994,
1716
+ 0.4075,
1717
+ 0.5322,
1718
+ 0.6735,
1719
+ 0.8315,
1720
+ 1.1974,
1721
+ 1.8709,
1722
+ 3.326,
1723
+ 20.787,
1724
+ 187.0826
1725
+ ];
1726
+ var varicorr = (give) => give > 0 && give <= 15 ? VAR_ICORR[give - 1] : 0;
1727
+ var DEGF = [
1728
+ 0,
1729
+ 5e-5,
1730
+ 9e-5,
1731
+ 12e-5,
1732
+ 15e-5,
1733
+ 2e-4,
1734
+ 3e-4,
1735
+ 45e-5,
1736
+ 6e-4,
1737
+ 9e-4,
1738
+ 15e-4,
1739
+ 21e-4,
1740
+ 27e-4,
1741
+ 33e-4,
1742
+ 46e-4,
1743
+ 58e-4
1744
+ ];
1745
+ var degfcorr = (ai) => ai > 0 && ai <= 15 ? DEGF[ai] : 58e-4;
1746
+ 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];
1747
+ 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];
1748
+ 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];
1749
+ var x4 = [-85, -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];
1750
+ var x5 = [-180, -175, -170, -165, -160, -155, -150, -145, -140, -135, -130, -125, -120, -115, -110, -105, -100, -95, -90, -85, -80, -75, -70, -65, -60, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170, 175];
1751
+ var x6 = [-180, -170, -160, -150, -140, -130, -120, -110, -100, -90, -80, -70, -60, -50, -40, -30, -20, -10, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170];
1752
+ var x7 = [-180, -150, -120, -90, -60, -30, 0, 30, 60, 90, 120, 150];
1753
+ var x8 = [-170, -140, -110, -80, -50, -20, 10, 40, 70, 100, 130, 160];
1754
+ var igpband1 = [
1755
+ [{ coord: -180, arr: x1, bits: 1, bite: 28 }, { coord: -175, arr: x2, bits: 29, bite: 51 }, { coord: -170, arr: x3, bits: 52, bite: 78 }, { coord: -165, arr: x2, bits: 79, bite: 101 }, { coord: -160, arr: x3, bits: 102, bite: 128 }, { coord: -155, arr: x2, bits: 129, bite: 151 }, { coord: -150, arr: x3, bits: 152, bite: 178 }, { coord: -145, arr: x2, bits: 179, bite: 201 }],
1756
+ [{ coord: -140, arr: x4, bits: 1, bite: 28 }, { coord: -135, arr: x2, bits: 29, bite: 51 }, { coord: -130, arr: x3, bits: 52, bite: 78 }, { coord: -125, arr: x2, bits: 79, bite: 101 }, { coord: -120, arr: x3, bits: 102, bite: 128 }, { coord: -115, arr: x2, bits: 129, bite: 151 }, { coord: -110, arr: x3, bits: 152, bite: 178 }, { coord: -105, arr: x2, bits: 179, bite: 201 }],
1757
+ [{ coord: -100, arr: x3, bits: 1, bite: 27 }, { coord: -95, arr: x2, bits: 28, bite: 50 }, { coord: -90, arr: x1, bits: 51, bite: 78 }, { coord: -85, arr: x2, bits: 79, bite: 101 }, { coord: -80, arr: x3, bits: 102, bite: 128 }, { coord: -75, arr: x2, bits: 129, bite: 151 }, { coord: -70, arr: x3, bits: 152, bite: 178 }, { coord: -65, arr: x2, bits: 179, bite: 201 }],
1758
+ [{ coord: -60, arr: x3, bits: 1, bite: 27 }, { coord: -55, arr: x2, bits: 28, bite: 50 }, { coord: -50, arr: x4, bits: 51, bite: 78 }, { coord: -45, arr: x2, bits: 79, bite: 101 }, { coord: -40, arr: x3, bits: 102, bite: 128 }, { coord: -35, arr: x2, bits: 129, bite: 151 }, { coord: -30, arr: x3, bits: 152, bite: 178 }, { coord: -25, arr: x2, bits: 179, bite: 201 }],
1759
+ [{ coord: -20, arr: x3, bits: 1, bite: 27 }, { coord: -15, arr: x2, bits: 28, bite: 50 }, { coord: -10, arr: x3, bits: 51, bite: 77 }, { coord: -5, arr: x2, bits: 78, bite: 100 }, { coord: 0, arr: x1, bits: 101, bite: 128 }, { coord: 5, arr: x2, bits: 129, bite: 151 }, { coord: 10, arr: x3, bits: 152, bite: 178 }, { coord: 15, arr: x2, bits: 179, bite: 201 }],
1760
+ [{ coord: 20, arr: x3, bits: 1, bite: 27 }, { coord: 25, arr: x2, bits: 28, bite: 50 }, { coord: 30, arr: x3, bits: 51, bite: 77 }, { coord: 35, arr: x2, bits: 78, bite: 100 }, { coord: 40, arr: x4, bits: 101, bite: 128 }, { coord: 45, arr: x2, bits: 129, bite: 151 }, { coord: 50, arr: x3, bits: 152, bite: 178 }, { coord: 55, arr: x2, bits: 179, bite: 201 }],
1761
+ [{ coord: 60, arr: x3, bits: 1, bite: 27 }, { coord: 65, arr: x2, bits: 28, bite: 50 }, { coord: 70, arr: x3, bits: 51, bite: 77 }, { coord: 75, arr: x2, bits: 78, bite: 100 }, { coord: 80, arr: x3, bits: 101, bite: 127 }, { coord: 85, arr: x2, bits: 128, bite: 150 }, { coord: 90, arr: x1, bits: 151, bite: 178 }, { coord: 95, arr: x2, bits: 179, bite: 201 }],
1762
+ [{ coord: 100, arr: x3, bits: 1, bite: 27 }, { coord: 105, arr: x2, bits: 28, bite: 50 }, { coord: 110, arr: x3, bits: 51, bite: 77 }, { coord: 115, arr: x2, bits: 78, bite: 100 }, { coord: 120, arr: x3, bits: 101, bite: 127 }, { coord: 125, arr: x2, bits: 128, bite: 150 }, { coord: 130, arr: x4, bits: 151, bite: 178 }, { coord: 135, arr: x2, bits: 179, bite: 201 }],
1763
+ [{ coord: 140, arr: x3, bits: 1, bite: 27 }, { coord: 145, arr: x2, bits: 28, bite: 50 }, { coord: 150, arr: x3, bits: 51, bite: 77 }, { coord: 155, arr: x2, bits: 78, bite: 100 }, { coord: 160, arr: x3, bits: 101, bite: 127 }, { coord: 165, arr: x2, bits: 128, bite: 150 }, { coord: 170, arr: x3, bits: 151, bite: 177 }, { coord: 175, arr: x2, bits: 178, bite: 200 }]
1764
+ ];
1765
+ var igpband2 = [
1766
+ [{ coord: 60, arr: x5, bits: 1, bite: 72 }, { coord: 65, arr: x6, bits: 73, bite: 108 }, { coord: 70, arr: x6, bits: 109, bite: 144 }, { coord: 75, arr: x6, bits: 145, bite: 180 }, { coord: 85, arr: x7, bits: 181, bite: 192 }],
1767
+ [{ coord: -60, arr: x5, bits: 1, bite: 72 }, { coord: -65, arr: x6, bits: 73, bite: 108 }, { coord: -70, arr: x6, bits: 109, bite: 144 }, { coord: -75, arr: x6, bits: 145, bite: 180 }, { coord: -85, arr: x8, bits: 181, bite: 192 }]
1768
+ ];
1769
+ var gpsSeconds = (week, tow) => week * SEC_PER_WEEK2 + tow;
1770
+ function maskPrn(i) {
1771
+ if (i >= 1 && i <= 37) return `G${two(i)}`;
1772
+ if (i >= 38 && i <= 61) return `R${two(i - 37)}`;
1773
+ if (i >= 120 && i <= 138) return `S${two(i - 100)}`;
1774
+ if (i >= 193 && i <= 202) return `J${two(i - 192)}`;
1775
+ return null;
1776
+ }
1777
+ function ionppp(latRad, lonRad, azRad, elRad, re, hion) {
1778
+ const rp = re / (re + hion) * Math.cos(elRad);
1779
+ const ap = Math.PI / 2 - elRad - Math.asin(rp);
1780
+ const sinap = Math.sin(ap);
1781
+ const tanap = Math.tan(ap);
1782
+ const cosaz = Math.cos(azRad);
1783
+ const latP = Math.asin(
1784
+ Math.sin(latRad) * Math.cos(ap) + Math.cos(latRad) * sinap * cosaz
1785
+ );
1786
+ let lonP;
1787
+ if (latRad > 70 * D2R && tanap * cosaz > Math.tan(Math.PI / 2 - latRad) || latRad < -70 * D2R && -tanap * cosaz > Math.tan(Math.PI / 2 + latRad)) {
1788
+ lonP = lonRad + Math.PI - Math.asin(sinap * Math.sin(azRad) / Math.cos(latP));
1789
+ } else {
1790
+ lonP = lonRad + Math.asin(sinap * Math.sin(azRad) / Math.cos(latP));
1791
+ }
1792
+ return { fp: 1 / Math.sqrt(1 - rp * rp), latP, lonP };
1793
+ }
1794
+ var SbasProcessor = class {
1795
+ sats = [];
1796
+ satIdx = /* @__PURE__ */ new Map();
1797
+ iodp = -1;
1798
+ tlat = 0;
1799
+ ion = [];
1800
+ /** GEO PRN(s) whose messages have been ingested. */
1801
+ geoPrns = /* @__PURE__ */ new Set();
1802
+ /**
1803
+ * Ingest one decoded SBAS L1 message (250-bit, MSB-first) received at the
1804
+ * given GPS week / time-of-week. Returns the message type, or -1 if it was
1805
+ * not a recognised/applicable correction message.
1806
+ */
1807
+ update(msg, week, tow, geoPrn) {
1808
+ if (week === 0) return -1;
1809
+ const type = sbasMessageType(msg);
1810
+ if (geoPrn != null && geoPrn >= 120 && geoPrn <= 158)
1811
+ this.geoPrns.add(`S${two(geoPrn - 100)}`);
1812
+ switch (type) {
1813
+ case 1:
1814
+ return this.decodeMask(msg) ? type : -1;
1815
+ case 0:
1816
+ case 2:
1817
+ case 3:
1818
+ case 4:
1819
+ case 5:
1820
+ return this.decodeFast(msg, type, week, tow) ? type : -1;
1821
+ case 6:
1822
+ return this.decodeIntegrity(msg) ? type : -1;
1823
+ case 7:
1824
+ return this.decodeDegradation(msg) ? type : -1;
1825
+ case 18:
1826
+ return this.decodeIgpMask(msg) ? type : -1;
1827
+ case 24:
1828
+ return this.decodeMixed(msg, week, tow) ? type : -1;
1829
+ case 25:
1830
+ return this.decodeLongCorrHalf(msg, 14, week, tow) && this.decodeLongCorrHalf(msg, 120, week, tow) ? type : -1;
1831
+ case 26:
1832
+ return this.decodeIgpDelay(msg, week, tow) ? type : -1;
1833
+ case 9:
1834
+ // GEO nav — handled by decodeSbasGeoNav elsewhere
1835
+ case 63:
1836
+ return type;
1837
+ default:
1838
+ return -1;
1839
+ }
1840
+ }
1841
+ decodeMask(msg) {
1842
+ const sats = [];
1843
+ for (let i = 1; i <= 210; i++) {
1844
+ if (getBitU(msg, 13 + i, 1)) sats.push({ prn: maskPrn(i) });
1845
+ }
1846
+ this.iodp = getBitU(msg, 224, 2);
1847
+ this.sats = sats;
1848
+ this.satIdx.clear();
1849
+ sats.forEach((s, k) => {
1850
+ if (s.prn) this.satIdx.set(s.prn, k);
1851
+ });
1852
+ return true;
1853
+ }
1854
+ decodeFast(msg, type, week, tow) {
1855
+ if (this.iodp !== getBitU(msg, 16, 2)) return false;
1856
+ const iodf = getBitU(msg, 14, 2);
1857
+ const t0s = gpsSeconds(week, tow);
1858
+ for (let i = 0; i < 13; i++) {
1859
+ const j = 13 * ((type === 0 ? 2 : type) - 2) + i;
1860
+ if (j >= this.sats.length) break;
1861
+ const udre = getBitU(msg, 174 + 4 * i, 4);
1862
+ const prc = getBitS(msg, 18 + i * 12, 12) * 0.125;
1863
+ const prev = this.sats[j].fcorr;
1864
+ this.sats[j].fcorr = {
1865
+ prc,
1866
+ udre: udre + 1,
1867
+ ai: prev?.ai ?? 0,
1868
+ iodf,
1869
+ t0s
1870
+ };
1871
+ }
1872
+ return true;
1873
+ }
1874
+ decodeIntegrity(msg) {
1875
+ const iodf = [0, 1, 2, 3].map((i) => getBitU(msg, 14 + i * 2, 2));
1876
+ for (let i = 0; i < this.sats.length; i++) {
1877
+ const f = this.sats[i].fcorr;
1878
+ if (!f || f.iodf !== iodf[Math.floor(i / 13)]) continue;
1879
+ f.udre = getBitU(msg, 22 + i * 4, 4) + 1;
1880
+ }
1881
+ return true;
1882
+ }
1883
+ decodeDegradation(msg) {
1884
+ if (this.iodp !== getBitU(msg, 18, 2)) return false;
1885
+ this.tlat = getBitU(msg, 14, 4);
1886
+ for (let i = 0; i < this.sats.length; i++) {
1887
+ const ai = getBitU(msg, 22 + i * 4, 4);
1888
+ if (this.sats[i].fcorr) this.sats[i].fcorr.ai = ai;
1889
+ else this.sats[i].fcorr = { prc: 0, udre: 0, ai, iodf: -1, t0s: 0 };
1890
+ }
1891
+ return true;
1892
+ }
1893
+ decodeMixed(msg, week, tow) {
1894
+ if (this.iodp !== getBitU(msg, 110, 2)) return false;
1895
+ const blk = getBitU(msg, 112, 2);
1896
+ const iodf = getBitU(msg, 114, 2);
1897
+ const t0s = gpsSeconds(week, tow);
1898
+ for (let i = 0; i < 6; i++) {
1899
+ const j = 13 * blk + i;
1900
+ if (j >= this.sats.length) break;
1901
+ const udre = getBitU(msg, 86 + 4 * i, 4);
1902
+ const prc = getBitS(msg, 14 + i * 12, 12) * 0.125;
1903
+ const prev = this.sats[j].fcorr;
1904
+ this.sats[j].fcorr = {
1905
+ prc,
1906
+ udre: udre + 1,
1907
+ ai: prev?.ai ?? 0,
1908
+ iodf,
1909
+ t0s
1910
+ };
1911
+ }
1912
+ return this.decodeLongCorrHalf(msg, 120, week, tow);
1913
+ }
1914
+ decodeLongCorrHalf(msg, p, week, tow) {
1915
+ if (getBitU(msg, p, 1) === 0) {
1916
+ if (this.iodp === getBitU(msg, p + 103, 2)) {
1917
+ const a = this.decodeLong0(msg, p + 1, week, tow);
1918
+ const b = this.decodeLong0(msg, p + 52, week, tow);
1919
+ return a || b;
1920
+ }
1921
+ } else if (this.iodp === getBitU(msg, p + 104, 2)) {
1922
+ return this.decodeLong1(msg, p + 1, week, tow);
1923
+ }
1924
+ return false;
1925
+ }
1926
+ decodeLong0(msg, p, week, tow) {
1927
+ const n = getBitU(msg, p, 6);
1928
+ if (n === 0 || n > this.sats.length) return false;
1929
+ this.sats[n - 1].lcorr = {
1930
+ iode: getBitU(msg, p + 6, 8),
1931
+ dpos: [
1932
+ getBitS(msg, p + 14, 9) * 0.125,
1933
+ getBitS(msg, p + 23, 9) * 0.125,
1934
+ getBitS(msg, p + 32, 9) * 0.125
1935
+ ],
1936
+ dvel: [0, 0, 0],
1937
+ daf0: getBitS(msg, p + 41, 10) * P2_31,
1938
+ daf1: 0,
1939
+ t0s: gpsSeconds(week, tow)
1940
+ };
1941
+ return true;
1942
+ }
1943
+ decodeLong1(msg, p, week, tow) {
1944
+ const n = getBitU(msg, p, 6);
1945
+ if (n === 0 || n > this.sats.length) return false;
1946
+ let t = getBitU(msg, p + 90, 13) * 16 - tow % 86400;
1947
+ if (t <= -43200) t += 86400;
1948
+ else if (t > 43200) t -= 86400;
1949
+ this.sats[n - 1].lcorr = {
1950
+ iode: getBitU(msg, p + 6, 8),
1951
+ dpos: [
1952
+ getBitS(msg, p + 14, 11) * 0.125,
1953
+ getBitS(msg, p + 25, 11) * 0.125,
1954
+ getBitS(msg, p + 36, 11) * 0.125
1955
+ ],
1956
+ dvel: [
1957
+ getBitS(msg, p + 58, 8) * P2_11,
1958
+ getBitS(msg, p + 66, 8) * P2_11,
1959
+ getBitS(msg, p + 74, 8) * P2_11
1960
+ ],
1961
+ daf0: getBitS(msg, p + 47, 11) * P2_31,
1962
+ daf1: getBitS(msg, p + 82, 8) * P2_39,
1963
+ t0s: gpsSeconds(week, tow + t)
1964
+ };
1965
+ return true;
1966
+ }
1967
+ decodeIgpMask(msg) {
1968
+ const band = getBitU(msg, 18, 4);
1969
+ let p;
1970
+ let m;
1971
+ if (band <= 8) {
1972
+ p = igpband1[band];
1973
+ m = 8;
1974
+ } else if (band <= 10) {
1975
+ p = igpband2[band - 9];
1976
+ m = 5;
1977
+ } else return false;
1978
+ const igp = [];
1979
+ for (let i = 1; i <= 201; i++) {
1980
+ if (!getBitU(msg, 23 + i, 1)) continue;
1981
+ for (let j = 0; j < m; j++) {
1982
+ const b = p[j];
1983
+ if (i < b.bits || b.bite < i) continue;
1984
+ const varying = b.arr[i - b.bits];
1985
+ igp.push({
1986
+ lat: band <= 8 ? varying : b.coord,
1987
+ lon: band <= 8 ? b.coord : varying,
1988
+ delay: 0,
1989
+ give: 0,
1990
+ t0s: 0
1991
+ });
1992
+ break;
1993
+ }
1994
+ }
1995
+ this.ion[band] = { iodi: getBitU(msg, 22, 2), igp };
1996
+ return true;
1997
+ }
1998
+ decodeIgpDelay(msg, week, tow) {
1999
+ const band = getBitU(msg, 14, 4);
2000
+ const b = this.ion[band];
2001
+ if (band > MAXBAND || !b || b.iodi !== getBitU(msg, 217, 2)) return false;
2002
+ const block = getBitU(msg, 18, 4);
2003
+ const t0s = gpsSeconds(week, tow);
2004
+ for (let i = 0; i < 15; i++) {
2005
+ const j = block * 15 + i;
2006
+ if (j >= b.igp.length) continue;
2007
+ const give = getBitU(msg, 22 + i * 13 + 9, 4);
2008
+ const delay = getBitU(msg, 22 + i * 13, 9);
2009
+ b.igp[j].delay = delay === 511 ? 0 : delay * 0.125;
2010
+ b.igp[j].give = give + 1 >= 16 ? 0 : give + 1;
2011
+ b.igp[j].t0s = t0s;
2012
+ }
2013
+ return true;
2014
+ }
2015
+ /** PRNs currently in the correction mask (in mask order). */
2016
+ activeSats() {
2017
+ return this.sats.map((s) => s.prn).filter((p) => !!p);
2018
+ }
2019
+ /** Number of ionospheric grid points with a valid delay across all bands. */
2020
+ ionoGridPoints() {
2021
+ let n = 0;
2022
+ for (const b of this.ion) if (b) {
2023
+ for (const g of b.igp) if (g.give > 0) n++;
2024
+ }
2025
+ return n;
2026
+ }
2027
+ /**
2028
+ * Satellite range/clock correction for a PRN at a GPS week/tow, or null if
2029
+ * no valid (unexpired) long-term + fast correction is available. Add `dPos`
2030
+ * to the satellite ECEF position and `dClkS` to its clock bias.
2031
+ */
2032
+ satCorrection(prn, week, tow) {
2033
+ const idx = this.satIdx.get(prn);
2034
+ if (idx === void 0) return null;
2035
+ const s = this.sats[idx];
2036
+ const now = gpsSeconds(week, tow);
2037
+ const drs = [0, 0, 0];
2038
+ let dclk = 0;
2039
+ let iode = -1;
2040
+ if (s.lcorr && s.lcorr.t0s !== 0) {
2041
+ const t = now - s.lcorr.t0s;
2042
+ if (Math.abs(t) > MAXSBSAGEL) return null;
2043
+ for (let i = 0; i < 3; i++)
2044
+ drs[i] = s.lcorr.dpos[i] + s.lcorr.dvel[i] * t;
2045
+ dclk = s.lcorr.daf0 + s.lcorr.daf1 * t;
2046
+ iode = s.lcorr.iode;
2047
+ } else if (prn[0] !== "S") {
2048
+ return null;
2049
+ }
2050
+ if (!s.fcorr || s.fcorr.t0s === 0) return null;
2051
+ const tf = now - s.fcorr.t0s + this.tlat;
2052
+ if (Math.abs(tf) > MAXSBSAGEF || s.fcorr.udre >= 15) return null;
2053
+ const prc = s.fcorr.prc;
2054
+ const varM2 = varfcorr(s.fcorr.udre) + degfcorr(s.fcorr.ai) * tf * tf / 2;
2055
+ return { dPos: drs, dClkS: dclk + prc / C_LIGHT, prcM: prc, varM2, iode };
2056
+ }
2057
+ /**
2058
+ * Slant L1 ionospheric delay (m) at the pierce point for a receiver geodetic
2059
+ * position (lat/lon rad, height m) and a satellite az/el (rad), interpolated
2060
+ * from the SBAS grid — or null if the pierce point isn't covered. RTKLIB
2061
+ * `sbsioncorr`.
2062
+ */
2063
+ ionoDelay(week, tow, latRad, lonRad, heightM, azRad, elRad) {
2064
+ if (heightM < -100 || elRad <= 0) return { delayM: 0, varM2: 0 };
2065
+ const { fp, latP, lonP } = ionppp(
2066
+ latRad,
2067
+ lonRad,
2068
+ azRad,
2069
+ elRad,
2070
+ 6378.1363,
2071
+ 350
2072
+ );
2073
+ const igp = this.searchIgp(latP, lonP);
2074
+ if (!igp) return null;
2075
+ const { pts, x, y } = igp;
2076
+ const w = [0, 0, 0, 0];
2077
+ if (pts[0] && pts[1] && pts[2] && pts[3]) {
2078
+ w[0] = (1 - x) * (1 - y);
2079
+ w[1] = (1 - x) * y;
2080
+ w[2] = x * (1 - y);
2081
+ w[3] = x * y;
2082
+ } else if (pts[0] && pts[1] && pts[2]) {
2083
+ w[1] = y;
2084
+ w[2] = x;
2085
+ w[0] = 1 - w[1] - w[2];
2086
+ if (w[0] < 0) return null;
2087
+ } else if (pts[0] && pts[2] && pts[3]) {
2088
+ w[0] = 1 - x;
2089
+ w[3] = y;
2090
+ w[2] = 1 - w[0] - w[3];
2091
+ if (w[2] < 0) return null;
2092
+ } else if (pts[0] && pts[1] && pts[3]) {
2093
+ w[0] = 1 - y;
2094
+ w[3] = x;
2095
+ w[1] = 1 - w[0] - w[3];
2096
+ if (w[1] < 0) return null;
2097
+ } else if (pts[1] && pts[2] && pts[3]) {
2098
+ w[1] = 1 - x;
2099
+ w[2] = 1 - y;
2100
+ w[3] = 1 - w[1] - w[2];
2101
+ if (w[3] < 0) return null;
2102
+ } else return null;
2103
+ const now = gpsSeconds(week, tow);
2104
+ let delay = 0;
2105
+ let varM2 = 0;
2106
+ for (let i = 0; i < 4; i++) {
2107
+ const g = pts[i];
2108
+ if (!g) continue;
2109
+ delay += w[i] * g.delay;
2110
+ varM2 += w[i] * varicorr(g.give) * 9e-8 * Math.abs(now - g.t0s);
2111
+ }
2112
+ return { delayM: delay * fp, varM2: varM2 * fp * fp };
2113
+ }
2114
+ /** Find the four IGPs bracketing a pierce point (RTKLIB `searchigp`). */
2115
+ searchIgp(latP, lonP) {
2116
+ const lat = latP * R2D;
2117
+ let lon = lonP * R2D;
2118
+ if (lon >= 180) lon -= 360;
2119
+ const latp = [0, 0];
2120
+ const lonp = [0, 0, 0, 0];
2121
+ let x;
2122
+ let y;
2123
+ if (lat >= -55 && lat < 55) {
2124
+ latp[0] = Math.floor(lat / 5) * 5;
2125
+ latp[1] = latp[0] + 5;
2126
+ lonp[0] = lonp[1] = Math.floor(lon / 5) * 5;
2127
+ lonp[2] = lonp[3] = lonp[0] + 5;
2128
+ x = (lon - lonp[0]) / 5;
2129
+ y = (lat - latp[0]) / 5;
2130
+ } else {
2131
+ latp[0] = Math.floor((lat - 5) / 10) * 10 + 5;
2132
+ latp[1] = latp[0] + 10;
2133
+ lonp[0] = lonp[1] = Math.floor(lon / 10) * 10;
2134
+ lonp[2] = lonp[3] = lonp[0] + 10;
2135
+ x = (lon - lonp[0]) / 10;
2136
+ y = (lat - latp[0]) / 10;
2137
+ if (lat >= 75 && lat < 85) {
2138
+ lonp[1] = Math.floor(lon / 90) * 90;
2139
+ lonp[3] = lonp[1] + 90;
2140
+ } else if (lat >= -85 && lat < -75) {
2141
+ lonp[0] = Math.floor((lon - 50) / 90) * 90 + 40;
2142
+ lonp[2] = lonp[0] + 90;
2143
+ } else if (lat >= 85) {
2144
+ for (let i = 0; i < 4; i++) lonp[i] = Math.floor(lon / 90) * 90;
2145
+ } else if (lat < -85) {
2146
+ for (let i = 0; i < 4; i++)
2147
+ lonp[i] = Math.floor((lon - 50) / 90) * 90 + 40;
2148
+ }
2149
+ }
2150
+ for (let i = 0; i < 4; i++) if (lonp[i] === 180) lonp[i] = -180;
2151
+ const pts = [null, null, null, null];
2152
+ for (const band of this.ion) {
2153
+ if (!band) continue;
2154
+ for (const g of band.igp) {
2155
+ if (g.t0s === 0 || g.give <= 0) continue;
2156
+ if (g.lat === latp[0] && g.lon === lonp[0]) pts[0] = g;
2157
+ else if (g.lat === latp[1] && g.lon === lonp[1]) pts[1] = g;
2158
+ else if (g.lat === latp[0] && g.lon === lonp[2]) pts[2] = g;
2159
+ else if (g.lat === latp[1] && g.lon === lonp[3]) pts[3] = g;
2160
+ }
2161
+ }
2162
+ if (!pts[0] && !pts[1] && !pts[2] && !pts[3]) return null;
2163
+ return { pts, x, y };
2164
+ }
2165
+ };
2166
+
1657
2167
  // src/rinex/sp3.ts
1658
2168
  function sp3Position(sp3, prn, tMs, order = 9) {
1659
2169
  const samples = sp3.satellites[prn];
@@ -1705,7 +2215,7 @@ function sp3Position(sp3, prn, tMs, order = 9) {
1705
2215
  }
1706
2216
 
1707
2217
  // src/rinex/clk.ts
1708
- var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
2218
+ var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
1709
2219
  function clkBias(clk, prn, tMs) {
1710
2220
  const e = clk.sats[prn];
1711
2221
  if (!e || e.t.length === 0) return null;
@@ -3119,7 +3629,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
3119
3629
  const systems = [...new Set(prns.map((p) => p[0]))].sort();
3120
3630
  const dim = 3 + systems.length;
3121
3631
  const sysIndex = new Map(systems.map((s, i) => [s, 3 + i]));
3122
- let x2 = 0;
3632
+ let x9 = 0;
3123
3633
  let y2 = 0;
3124
3634
  let z2 = 0;
3125
3635
  const clock2 = new Map(systems.map((s) => [s, 0]));
@@ -3135,8 +3645,8 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
3135
3645
  const Htv = new Array(dim).fill(0);
3136
3646
  let rows = 0;
3137
3647
  for (const k of Object.keys(residuals2)) delete residuals2[k];
3138
- const positionSaneIter = x2 * x2 + y2 * y2 + z2 * z2 > 1e12;
3139
- const [rxLat, rxLon, rxHgt] = positionSaneIter ? ecefToGeodetic(x2, y2, z2) : [0, 0, 0];
3648
+ const positionSaneIter = x9 * x9 + y2 * y2 + z2 * z2 > 1e12;
3649
+ const [rxLat, rxLon, rxHgt] = positionSaneIter ? ecefToGeodetic(x9, y2, z2) : [0, 0, 0];
3140
3650
  for (const prn of prns) {
3141
3651
  const psr = pseudoranges.get(prn);
3142
3652
  const eph = ephemerides.get(prn);
@@ -3148,10 +3658,10 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
3148
3658
  if (!Number.isFinite(sat.x)) continue;
3149
3659
  const isKepler = eph.system !== "R" && eph.system !== "S";
3150
3660
  const dts = dtsClock - (tgd && isKepler ? eph.tgd : 0);
3151
- const travel = Math.hypot(sat.x - x2, sat.y - y2, sat.z - z2) / C_LIGHT;
3661
+ const travel = Math.hypot(sat.x - x9, sat.y - y2, sat.z - z2) / C_LIGHT;
3152
3662
  const [sx, sy, sz] = sagnac2(sat, travel);
3153
- const rho = Math.hypot(sx - x2, sy - y2, sz - z2);
3154
- const ux = (x2 - sx) / rho;
3663
+ const rho = Math.hypot(sx - x9, sy - y2, sz - z2);
3664
+ const ux = (x9 - sx) / rho;
3155
3665
  const uy = (y2 - sy) / rho;
3156
3666
  const uz = (z2 - sz) / rho;
3157
3667
  let elev = Math.PI / 2;
@@ -3159,7 +3669,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
3159
3669
  let weight = 1;
3160
3670
  const positionSane = positionSaneIter;
3161
3671
  if (positionSane) {
3162
- const azel = ecefToAzEl(x2, y2, z2, sx, sy, sz);
3672
+ const azel = ecefToAzEl(x9, y2, z2, sx, sy, sz);
3163
3673
  elev = azel.el;
3164
3674
  azim = azel.az;
3165
3675
  if (iter >= 2 && elev < elevationMaskDeg * Math.PI / 180) continue;
@@ -3197,7 +3707,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
3197
3707
  if (rows < dim) return null;
3198
3708
  const dx = solveLinear(HtH, Htv);
3199
3709
  if (!dx) return null;
3200
- x2 += dx[0];
3710
+ x9 += dx[0];
3201
3711
  y2 += dx[1];
3202
3712
  z2 += dx[2];
3203
3713
  for (const s of systems)
@@ -3207,7 +3717,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
3207
3717
  break;
3208
3718
  }
3209
3719
  }
3210
- return { x: x2, y: y2, z: z2, clock: clock2, residuals: residuals2, iterations: iterations2, converged: converged2 };
3720
+ return { x: x9, y: y2, z: z2, clock: clock2, residuals: residuals2, iterations: iterations2, converged: converged2 };
3211
3721
  };
3212
3722
  const REJECT_THRESHOLD_M = 50;
3213
3723
  let candidates = all;
@@ -3261,6 +3771,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
3261
3771
  0 && (module.exports = {
3262
3772
  IONO_L1_M_PER_TECU,
3263
3773
  RtkFloatEngine,
3774
+ SbasProcessor,
3264
3775
  buildPppAntenna,
3265
3776
  createPppCorrections,
3266
3777
  estimateNarrowlaneFcb,