gnss-js 1.55.0 → 1.57.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.
@@ -1551,6 +1551,36 @@ var SbasProcessor = class {
1551
1551
  }
1552
1552
  return n;
1553
1553
  }
1554
+ /**
1555
+ * Correction-coverage census at a GPS week/time — a diagnostic funnel over
1556
+ * the current state, explaining how many masked satellites are actually
1557
+ * correctable. Each stage subsumes the requirement of the previous one for a
1558
+ * full range/clock correction: a satellite is `corrected` only when it has
1559
+ * both a fresh fast correction and (for non-SBAS satellites) a fresh
1560
+ * long-term correction (exactly {@link satCorrection}'s gate). `ionoGrid` is
1561
+ * the total number of valid grid points — the additional requirement for the
1562
+ * *iono*-corrected subset a solver forms per pierce point.
1563
+ *
1564
+ * Use it to tell "no corrections applied" (mask empty / products stale) apart
1565
+ * from "corrections applied but the pierce points aren't grid-covered yet".
1566
+ */
1567
+ coverage(week, tow) {
1568
+ const now = gpsSeconds(week, tow);
1569
+ let masked = 0;
1570
+ let fast = 0;
1571
+ let long = 0;
1572
+ let corrected = 0;
1573
+ for (const s of this.sats) {
1574
+ if (!s.prn) continue;
1575
+ masked++;
1576
+ if (s.fcorr && s.fcorr.t0s !== 0 && s.fcorr.udre < 15 && Math.abs(now - s.fcorr.t0s + this.tlat) <= MAXSBSAGEF)
1577
+ fast++;
1578
+ if (s.prn[0] === "S" || s.lcorr && s.lcorr.t0s !== 0 && Math.abs(now - s.lcorr.t0s) <= MAXSBSAGEL)
1579
+ long++;
1580
+ if (this.satCorrection(s.prn, week, tow)) corrected++;
1581
+ }
1582
+ return { masked, fast, long, corrected, ionoGrid: this.ionoGridPoints() };
1583
+ }
1554
1584
  /**
1555
1585
  * Satellite range/clock correction for a PRN at a GPS week/tow, or null if
1556
1586
  * no valid (unexpired) long-term + fast correction is available. Add `dPos`
@@ -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 feedGeoBlock(view, b, onSbasMessage) {
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 svid = view.getUint8(b + 14);
764
- const prnStr = svidToPrn(svid);
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
- if (!sbasCrcOk(msg)) return { badCrc: true };
775
- const prn = Number(prnStr.slice(1)) + 100;
776
- onSbasMessage?.(msg, prn, wnc, tow / 1e3);
777
- const eph = decodeSbasGeoNav(msg, prn, wnc, tow / 1e3);
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
- return { ephemerides, cnav, ionoCorrections, leapSeconds, counts };
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
package/dist/index.cjs CHANGED
@@ -84,6 +84,8 @@ __export(src_exports, {
84
84
  RTCM3_MESSAGE_NAMES: () => RTCM3_MESSAGE_NAMES,
85
85
  Rtcm3Decoder: () => Rtcm3Decoder,
86
86
  RtkFloatEngine: () => RtkFloatEngine,
87
+ SBAS_L5_MT_NAMES: () => SBAS_L5_MT_NAMES,
88
+ SBAS_L5_PREAMBLE_UW: () => SBAS_L5_PREAMBLE_UW,
87
89
  SECONDS_IN_DAY: () => SECONDS_IN_DAY,
88
90
  SECONDS_IN_HOUR: () => SECONDS_IN_HOUR,
89
91
  SECONDS_IN_MINUTE: () => SECONDS_IN_MINUTE,
@@ -157,6 +159,7 @@ __export(src_exports, {
157
159
  euclidean3D: () => euclidean3D,
158
160
  extractWidelaneArcs: () => extractWidelaneArcs,
159
161
  feedGeoBlock: () => feedGeoBlock,
162
+ feedGeoL5Block: () => feedGeoL5Block,
160
163
  fetchSourcetable: () => fetchSourcetable,
161
164
  findSatBias: () => findSatBias,
162
165
  fixPppPosition: () => fixPppPosition,
@@ -233,6 +236,8 @@ __export(src_exports, {
233
236
  hdrLine: () => hdrLine,
234
237
  horizonDistance: () => horizonDistance,
235
238
  ionoFree: () => ionoFree,
239
+ isSbasL1Preamble: () => isSbasL1Preamble,
240
+ isSbasL5Correction: () => isSbasL5Correction,
236
241
  keplerPosition: () => keplerPosition,
237
242
  klobucharDelay: () => klobucharDelay,
238
243
  lambdaReduction: () => lambdaReduction,
@@ -263,6 +268,7 @@ __export(src_exports, {
263
268
  parseSbfBdsNav: () => parseSbfBdsNav,
264
269
  parseSbfCnav: () => parseSbfCnav,
265
270
  parseSbfGalNav: () => parseSbfGalNav,
271
+ parseSbfGeoL5: () => parseSbfGeoL5,
266
272
  parseSbfGeoNav: () => parseSbfGeoNav,
267
273
  parseSbfGloNav: () => parseSbfGloNav,
268
274
  parseSbfGpsNav: () => parseSbfGpsNav,
@@ -297,6 +303,8 @@ __export(src_exports, {
297
303
  rhumbLine: () => rhumbLine,
298
304
  rtcm3Constellation: () => rtcm3Constellation,
299
305
  satClockCorrection: () => satClockCorrection,
306
+ sbasL5MessageName: () => sbasL5MessageName,
307
+ sbasL5MessageType: () => sbasL5MessageType,
300
308
  sbasProtectionLevels: () => sbasProtectionLevels,
301
309
  sbfCrc16: () => crc16,
302
310
  scanSbfFrames: () => scanSbfFrames,
@@ -7833,13 +7841,42 @@ function parseSbfGloNav(data) {
7833
7841
  return { ephemerides, badCrc, messages };
7834
7842
  }
7835
7843
 
7844
+ // src/navbits/sbas-l5.ts
7845
+ var SBAS_L5_PREAMBLE_UW = 6056250;
7846
+ function isSbasL1Preamble(msg) {
7847
+ return msg[0] === 83 || msg[0] === 154 || msg[0] === 198;
7848
+ }
7849
+ function sbasL5MessageType(msg) {
7850
+ return getBitU(msg, 4, 6);
7851
+ }
7852
+ var SBAS_L5_MT_NAMES = {
7853
+ 0: "Do Not Use (test)",
7854
+ 31: "SBAS satellite mask",
7855
+ 32: "Satellite clock-ephemeris corrections + covariance",
7856
+ 34: "Integrity (DFREI/DFRECI)",
7857
+ 35: "Integrity (DFREI/DFRECI)",
7858
+ 36: "Integrity (DFREI/DFRECI)",
7859
+ 37: "Degradation parameters + DFREI scale table",
7860
+ 39: "SBAS satellite clock/ephemeris/covariance-1",
7861
+ 40: "SBAS satellite clock/ephemeris/covariance-2",
7862
+ 42: "SNT-to-UTC offset",
7863
+ 47: "SBAS satellite almanacs",
7864
+ 62: "Reserved",
7865
+ 63: "Null message"
7866
+ };
7867
+ function sbasL5MessageName(type) {
7868
+ return SBAS_L5_MT_NAMES[type] ?? (type >= 1 && type <= 61 ? "Spare" : `Type ${type}`);
7869
+ }
7870
+ function isSbasL5Correction(type) {
7871
+ return type === 31 || type === 32 || type >= 34 && type <= 37 || type === 39 || type === 40 || type === 42 || type === 47;
7872
+ }
7873
+
7836
7874
  // src/sbf/rawnav-sbas.ts
7837
- function feedGeoBlock(view, b, onSbasMessage) {
7875
+ function readGeoMessage(view, b) {
7838
7876
  const tow = view.getUint32(b + 8, true);
7839
7877
  const wnc = view.getUint16(b + 12, true);
7840
- const svid = view.getUint8(b + 14);
7841
- const prnStr = svidToPrn(svid);
7842
- if (!prnStr || prnStr[0] !== "S") return {};
7878
+ const prnStr = svidToPrn(view.getUint8(b + 14));
7879
+ if (!prnStr || prnStr[0] !== "S") return null;
7843
7880
  const msg = new Uint8Array(32);
7844
7881
  for (let k = 0; k < 8; k++) {
7845
7882
  const w = view.getUint32(b + 20 + 4 * k, true);
@@ -7848,12 +7885,29 @@ function feedGeoBlock(view, b, onSbasMessage) {
7848
7885
  msg[4 * k + 2] = w >>> 8 & 255;
7849
7886
  msg[4 * k + 3] = w & 255;
7850
7887
  }
7851
- if (!sbasCrcOk(msg)) return { badCrc: true };
7852
- const prn = Number(prnStr.slice(1)) + 100;
7853
- onSbasMessage?.(msg, prn, wnc, tow / 1e3);
7854
- const eph = decodeSbasGeoNav(msg, prn, wnc, tow / 1e3);
7888
+ return { msg, prn: Number(prnStr.slice(1)) + 100, wnc, towSec: tow / 1e3 };
7889
+ }
7890
+ function feedGeoBlock(view, b, onSbasMessage) {
7891
+ const g = readGeoMessage(view, b);
7892
+ if (!g) return {};
7893
+ if (!sbasCrcOk(g.msg)) return { badCrc: true };
7894
+ onSbasMessage?.(g.msg, g.prn, g.wnc, g.towSec);
7895
+ const eph = decodeSbasGeoNav(g.msg, g.prn, g.wnc, g.towSec);
7855
7896
  return eph ? { eph } : {};
7856
7897
  }
7898
+ function feedGeoL5Block(view, b, onSbasMessage, onDfmcMessage) {
7899
+ const g = readGeoMessage(view, b);
7900
+ if (!g) return {};
7901
+ if (!sbasCrcOk(g.msg)) return { badCrc: true };
7902
+ if (isSbasL1Preamble(g.msg)) {
7903
+ onSbasMessage?.(g.msg, g.prn, g.wnc, g.towSec);
7904
+ const eph = decodeSbasGeoNav(g.msg, g.prn, g.wnc, g.towSec);
7905
+ return eph ? { kind: "l1", eph } : { kind: "l1" };
7906
+ }
7907
+ const dfmcType = sbasL5MessageType(g.msg);
7908
+ onDfmcMessage?.(g.msg, g.prn, g.wnc, g.towSec, dfmcType);
7909
+ return { kind: "l5", dfmcType };
7910
+ }
7857
7911
  function parseSbfGeoNav(data, opts = {}) {
7858
7912
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
7859
7913
  const ephemerides = [];
@@ -7876,6 +7930,47 @@ function parseSbfGeoNav(data, opts = {}) {
7876
7930
  });
7877
7931
  return { ephemerides, badCrc, messages };
7878
7932
  }
7933
+ function parseSbfGeoL5(data, opts = {}) {
7934
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
7935
+ const ephemerides = [];
7936
+ const seen = /* @__PURE__ */ new Set();
7937
+ const byType = {};
7938
+ const dfmcPrns = /* @__PURE__ */ new Set();
7939
+ let legacyMessages = 0;
7940
+ let dfmcMessages = 0;
7941
+ let badCrc = 0;
7942
+ let messages = 0;
7943
+ scanSbfFrames(data, view, (id, b, len) => {
7944
+ if (id !== 4021 || len < 52) return;
7945
+ messages++;
7946
+ const r = feedGeoL5Block(view, b, opts.onSbasMessage, opts.onDfmcMessage);
7947
+ if (r.badCrc) {
7948
+ badCrc++;
7949
+ } else if (r.kind === "l1") {
7950
+ legacyMessages++;
7951
+ if (r.eph) {
7952
+ const key = `${r.eph.prn}|${r.eph.tocDate.getTime()}`;
7953
+ if (!seen.has(key)) {
7954
+ seen.add(key);
7955
+ ephemerides.push(r.eph);
7956
+ }
7957
+ }
7958
+ } else if (r.kind === "l5" && r.dfmcType !== void 0) {
7959
+ dfmcMessages++;
7960
+ byType[r.dfmcType] = (byType[r.dfmcType] ?? 0) + 1;
7961
+ const prn = view.getUint8(b + 14);
7962
+ const s = svidToPrn(prn);
7963
+ if (s) dfmcPrns.add(s);
7964
+ }
7965
+ });
7966
+ return {
7967
+ ephemerides,
7968
+ legacyMessages,
7969
+ dfmc: { byType, prns: [...dfmcPrns].sort(), messages: dfmcMessages },
7970
+ badCrc,
7971
+ messages
7972
+ };
7973
+ }
7879
7974
 
7880
7975
  // src/sbf/navigation.ts
7881
7976
  var F4_DNU4 = -2e10;
@@ -7898,8 +7993,11 @@ function decodeSbfNavigation(data, opts = {}) {
7898
7993
  gloRaw: 0,
7899
7994
  bdsRaw: 0,
7900
7995
  sbasRaw: 0,
7996
+ sbasL5Raw: 0,
7901
7997
  badFrames: 0
7902
7998
  };
7999
+ const dfmcByType = {};
8000
+ const dfmcPrns = /* @__PURE__ */ new Set();
7903
8001
  const cnavAsm = newCnavAssemblers();
7904
8002
  const galAsm = newGalAssemblers();
7905
8003
  const gloAsm = new GloStringAssembler();
@@ -8009,6 +8107,25 @@ function decodeSbfNavigation(data, opts = {}) {
8009
8107
  else if (r.badCrc) counts.badFrames++;
8010
8108
  return;
8011
8109
  }
8110
+ case 4021: {
8111
+ if (len < 52) return;
8112
+ counts.sbasL5Raw++;
8113
+ const r = feedGeoL5Block(
8114
+ view,
8115
+ b,
8116
+ opts.onSbasMessage,
8117
+ opts.onDfmcMessage
8118
+ );
8119
+ if (r.badCrc) counts.badFrames++;
8120
+ else if (r.kind === "l1") {
8121
+ if (r.eph) addEph(r.eph);
8122
+ } else if (r.kind === "l5" && r.dfmcType !== void 0) {
8123
+ dfmcByType[r.dfmcType] = (dfmcByType[r.dfmcType] ?? 0) + 1;
8124
+ const s = svidToPrn(view.getUint8(b + 14));
8125
+ if (s) dfmcPrns.add(s);
8126
+ }
8127
+ return;
8128
+ }
8012
8129
  /* ---- iono / UTC ---- */
8013
8130
  case 5893:
8014
8131
  // GPSIon
@@ -8033,7 +8150,12 @@ function decodeSbfNavigation(data, opts = {}) {
8033
8150
  return;
8034
8151
  }
8035
8152
  });
8036
- return { ephemerides, cnav, ionoCorrections, leapSeconds, counts };
8153
+ const dfmc = {
8154
+ byType: dfmcByType,
8155
+ prns: [...dfmcPrns].sort(),
8156
+ messages: Object.values(dfmcByType).reduce((a, v) => a + v, 0)
8157
+ };
8158
+ return { ephemerides, cnav, ionoCorrections, leapSeconds, dfmc, counts };
8037
8159
  }
8038
8160
 
8039
8161
  // src/navbits/rs255.ts
@@ -13637,6 +13759,36 @@ var SbasProcessor = class {
13637
13759
  }
13638
13760
  return n;
13639
13761
  }
13762
+ /**
13763
+ * Correction-coverage census at a GPS week/time — a diagnostic funnel over
13764
+ * the current state, explaining how many masked satellites are actually
13765
+ * correctable. Each stage subsumes the requirement of the previous one for a
13766
+ * full range/clock correction: a satellite is `corrected` only when it has
13767
+ * both a fresh fast correction and (for non-SBAS satellites) a fresh
13768
+ * long-term correction (exactly {@link satCorrection}'s gate). `ionoGrid` is
13769
+ * the total number of valid grid points — the additional requirement for the
13770
+ * *iono*-corrected subset a solver forms per pierce point.
13771
+ *
13772
+ * Use it to tell "no corrections applied" (mask empty / products stale) apart
13773
+ * from "corrections applied but the pierce points aren't grid-covered yet".
13774
+ */
13775
+ coverage(week, tow) {
13776
+ const now = gpsSeconds(week, tow);
13777
+ let masked = 0;
13778
+ let fast = 0;
13779
+ let long = 0;
13780
+ let corrected = 0;
13781
+ for (const s of this.sats) {
13782
+ if (!s.prn) continue;
13783
+ masked++;
13784
+ if (s.fcorr && s.fcorr.t0s !== 0 && s.fcorr.udre < 15 && Math.abs(now - s.fcorr.t0s + this.tlat) <= MAXSBSAGEF)
13785
+ fast++;
13786
+ if (s.prn[0] === "S" || s.lcorr && s.lcorr.t0s !== 0 && Math.abs(now - s.lcorr.t0s) <= MAXSBSAGEL)
13787
+ long++;
13788
+ if (this.satCorrection(s.prn, week, tow)) corrected++;
13789
+ }
13790
+ return { masked, fast, long, corrected, ionoGrid: this.ionoGridPoints() };
13791
+ }
13640
13792
  /**
13641
13793
  * Satellite range/clock correction for a PRN at a GPS week/tow, or null if
13642
13794
  * no valid (unexpired) long-term + fast correction is available. Add `dPos`
@@ -17751,6 +17903,8 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
17751
17903
  RTCM3_MESSAGE_NAMES,
17752
17904
  Rtcm3Decoder,
17753
17905
  RtkFloatEngine,
17906
+ SBAS_L5_MT_NAMES,
17907
+ SBAS_L5_PREAMBLE_UW,
17754
17908
  SECONDS_IN_DAY,
17755
17909
  SECONDS_IN_HOUR,
17756
17910
  SECONDS_IN_MINUTE,
@@ -17824,6 +17978,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
17824
17978
  euclidean3D,
17825
17979
  extractWidelaneArcs,
17826
17980
  feedGeoBlock,
17981
+ feedGeoL5Block,
17827
17982
  fetchSourcetable,
17828
17983
  findSatBias,
17829
17984
  fixPppPosition,
@@ -17900,6 +18055,8 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
17900
18055
  hdrLine,
17901
18056
  horizonDistance,
17902
18057
  ionoFree,
18058
+ isSbasL1Preamble,
18059
+ isSbasL5Correction,
17903
18060
  keplerPosition,
17904
18061
  klobucharDelay,
17905
18062
  lambdaReduction,
@@ -17930,6 +18087,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
17930
18087
  parseSbfBdsNav,
17931
18088
  parseSbfCnav,
17932
18089
  parseSbfGalNav,
18090
+ parseSbfGeoL5,
17933
18091
  parseSbfGeoNav,
17934
18092
  parseSbfGloNav,
17935
18093
  parseSbfGpsNav,
@@ -17964,6 +18122,8 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
17964
18122
  rhumbLine,
17965
18123
  rtcm3Constellation,
17966
18124
  satClockCorrection,
18125
+ sbasL5MessageName,
18126
+ sbasL5MessageType,
17967
18127
  sbasProtectionLevels,
17968
18128
  sbfCrc16,
17969
18129
  scanSbfFrames,
package/dist/index.d.cts CHANGED
@@ -12,7 +12,7 @@ export { C as ClkFile, I as IonexGrid, S as Sp3File, a as Sp3Sample, c as clkBia
12
12
  export { B as BitReader, E as EphemerisInfo, R as Rtcm3DebugHandler, a as Rtcm3Decoder, b as Rtcm3Frame, d as decodeEphemeris, r as readString, c as reportDecodeError, s as setRtcm3DebugHandler } from './ephemeris-Ohl6NAfw.cjs';
13
13
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.cjs';
14
14
  export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxPvtResult, UbxRawNavOptions, UbxRawNavResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxPvt, parseUbxRawNav, parseUbxRawx, ubxFrames } from './ubx.cjs';
15
- export { HasMessage, SbfBdsNavResult, SbfCnavEphemeris, SbfCnavResult, SbfGalEphemeris, SbfGalNavResult, SbfGeoNavResult, SbfGloNavResult, SbfGpsNavResult, SbfHasMessage, SbfHasResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfNavCounts, SbfNavigation, SbfParseResult, SbfPvt, SbfPvtResult, SbfReceiverSetup, decodeSbfNavigation, feedGeoBlock, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGeoNav, parseSbfGloNav, parseSbfGpsNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, parseSbfPvt, parseSbfReceiverSetup, sbfCrc16, scanSbfFrames } from './sbf.cjs';
15
+ export { DfmcCensus, DfmcMessageCb, GeoL5Result, HasMessage, SBAS_L5_MT_NAMES, SBAS_L5_PREAMBLE_UW, SbasMessageCb, SbfBdsNavResult, SbfCnavEphemeris, SbfCnavResult, SbfGalEphemeris, SbfGalNavResult, SbfGeoL5Result, SbfGeoNavResult, SbfGloNavResult, SbfGpsNavResult, SbfHasMessage, SbfHasResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfNavCounts, SbfNavigation, SbfParseResult, SbfPvt, SbfPvtResult, SbfReceiverSetup, decodeSbfNavigation, feedGeoBlock, feedGeoL5Block, isSbasL1Preamble, isSbasL5Correction, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGeoL5, parseSbfGeoNav, parseSbfGloNav, parseSbfGpsNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, parseSbfPvt, parseSbfReceiverSetup, sbasL5MessageName, sbasL5MessageType, sbfCrc16, scanSbfFrames } from './sbf.cjs';
16
16
  export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, NovatelPvtResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelPvt, parseNovatelRange } from './novatel.cjs';
17
17
  export { TrimbleEpoch, TrimbleFrame, TrimbleMeasurement, TrimbleNavResult, TrimbleParseResult, parseTrimble, parseTrimbleNav, trimbleFrames } from './trimble.cjs';
18
18
  export { BinexEpoch, BinexMeasurement, BinexParseResult, BinexRecord, binexCrc16, binexCrc32, binexCsum8, binexRecords, decodeBinexEph, getBnxi, parseBinex } from './binex.cjs';
package/dist/index.d.ts CHANGED
@@ -12,7 +12,7 @@ export { C as ClkFile, I as IonexGrid, S as Sp3File, a as Sp3Sample, c as clkBia
12
12
  export { B as BitReader, E as EphemerisInfo, R as Rtcm3DebugHandler, a as Rtcm3Decoder, b as Rtcm3Frame, d as decodeEphemeris, r as readString, c as reportDecodeError, s as setRtcm3DebugHandler } from './ephemeris-Ohl6NAfw.js';
13
13
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.js';
14
14
  export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxPvtResult, UbxRawNavOptions, UbxRawNavResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxPvt, parseUbxRawNav, parseUbxRawx, ubxFrames } from './ubx.js';
15
- export { HasMessage, SbfBdsNavResult, SbfCnavEphemeris, SbfCnavResult, SbfGalEphemeris, SbfGalNavResult, SbfGeoNavResult, SbfGloNavResult, SbfGpsNavResult, SbfHasMessage, SbfHasResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfNavCounts, SbfNavigation, SbfParseResult, SbfPvt, SbfPvtResult, SbfReceiverSetup, decodeSbfNavigation, feedGeoBlock, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGeoNav, parseSbfGloNav, parseSbfGpsNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, parseSbfPvt, parseSbfReceiverSetup, sbfCrc16, scanSbfFrames } from './sbf.js';
15
+ export { DfmcCensus, DfmcMessageCb, GeoL5Result, HasMessage, SBAS_L5_MT_NAMES, SBAS_L5_PREAMBLE_UW, SbasMessageCb, SbfBdsNavResult, SbfCnavEphemeris, SbfCnavResult, SbfGalEphemeris, SbfGalNavResult, SbfGeoL5Result, SbfGeoNavResult, SbfGloNavResult, SbfGpsNavResult, SbfHasMessage, SbfHasResult, SbfIonoUtcResult, SbfMeasEpoch, SbfMeasurement, SbfNavCounts, SbfNavigation, SbfParseResult, SbfPvt, SbfPvtResult, SbfReceiverSetup, decodeSbfNavigation, feedGeoBlock, feedGeoL5Block, isSbasL1Preamble, isSbasL5Correction, parseSbfBdsNav, parseSbfCnav, parseSbfGalNav, parseSbfGeoL5, parseSbfGeoNav, parseSbfGloNav, parseSbfGpsNav, parseSbfHas, parseSbfIonoUtc, parseSbfMeas, parseSbfPvt, parseSbfReceiverSetup, sbasL5MessageName, sbasL5MessageType, sbfCrc16, scanSbfFrames } from './sbf.js';
16
16
  export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, NovatelPvtResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelPvt, parseNovatelRange } from './novatel.js';
17
17
  export { TrimbleEpoch, TrimbleFrame, TrimbleMeasurement, TrimbleNavResult, TrimbleParseResult, parseTrimble, parseTrimbleNav, trimbleFrames } from './trimble.js';
18
18
  export { BinexEpoch, BinexMeasurement, BinexParseResult, BinexRecord, binexCrc16, binexCrc32, binexCsum8, binexRecords, decodeBinexEph, getBnxi, parseBinex } from './binex.js';
package/dist/index.js CHANGED
@@ -53,13 +53,19 @@ import {
53
53
  ubxFrames
54
54
  } from "./chunk-MRC6LIPM.js";
55
55
  import {
56
+ SBAS_L5_MT_NAMES,
57
+ SBAS_L5_PREAMBLE_UW,
56
58
  crc16,
57
59
  decodeSbfNavigation,
58
60
  feedGeoBlock,
61
+ feedGeoL5Block,
62
+ isSbasL1Preamble,
63
+ isSbasL5Correction,
59
64
  parseSbfAlmanac,
60
65
  parseSbfBdsNav,
61
66
  parseSbfCnav,
62
67
  parseSbfGalNav,
68
+ parseSbfGeoL5,
63
69
  parseSbfGeoNav,
64
70
  parseSbfGloNav,
65
71
  parseSbfGpsNav,
@@ -69,8 +75,10 @@ import {
69
75
  parseSbfNav,
70
76
  parseSbfPvt,
71
77
  parseSbfReceiverSetup,
78
+ sbasL5MessageName,
79
+ sbasL5MessageType,
72
80
  scanSbfFrames
73
- } from "./chunk-ZPNMIUNZ.js";
81
+ } from "./chunk-UHLUAU6H.js";
74
82
  import "./chunk-FA2UTLEQ.js";
75
83
  import {
76
84
  OEM4_HLEN,
@@ -168,7 +176,7 @@ import {
168
176
  sunEcef,
169
177
  toRtkEpoch,
170
178
  wlWavelength
171
- } from "./chunk-U32IU7RO.js";
179
+ } from "./chunk-BU6YC6VK.js";
172
180
  import "./chunk-WQX354KD.js";
173
181
  import {
174
182
  almanacEpochMs,
@@ -424,6 +432,8 @@ export {
424
432
  RTCM3_MESSAGE_NAMES,
425
433
  Rtcm3Decoder,
426
434
  RtkFloatEngine,
435
+ SBAS_L5_MT_NAMES,
436
+ SBAS_L5_PREAMBLE_UW,
427
437
  SECONDS_IN_DAY,
428
438
  SECONDS_IN_HOUR,
429
439
  SECONDS_IN_MINUTE,
@@ -497,6 +507,7 @@ export {
497
507
  euclidean3D,
498
508
  extractWidelaneArcs,
499
509
  feedGeoBlock,
510
+ feedGeoL5Block,
500
511
  fetchSourcetable,
501
512
  findSatBias,
502
513
  fixPppPosition,
@@ -573,6 +584,8 @@ export {
573
584
  hdrLine,
574
585
  horizonDistance,
575
586
  ionoFree,
587
+ isSbasL1Preamble,
588
+ isSbasL5Correction,
576
589
  keplerPosition,
577
590
  klobucharDelay,
578
591
  lambdaReduction,
@@ -603,6 +616,7 @@ export {
603
616
  parseSbfBdsNav,
604
617
  parseSbfCnav,
605
618
  parseSbfGalNav,
619
+ parseSbfGeoL5,
606
620
  parseSbfGeoNav,
607
621
  parseSbfGloNav,
608
622
  parseSbfGpsNav,
@@ -637,6 +651,8 @@ export {
637
651
  rhumbLine,
638
652
  rtcm3Constellation,
639
653
  satClockCorrection,
654
+ sbasL5MessageName,
655
+ sbasL5MessageType,
640
656
  sbasProtectionLevels,
641
657
  crc16 as sbfCrc16,
642
658
  scanSbfFrames,
@@ -2025,6 +2025,36 @@ var SbasProcessor = class {
2025
2025
  }
2026
2026
  return n;
2027
2027
  }
2028
+ /**
2029
+ * Correction-coverage census at a GPS week/time — a diagnostic funnel over
2030
+ * the current state, explaining how many masked satellites are actually
2031
+ * correctable. Each stage subsumes the requirement of the previous one for a
2032
+ * full range/clock correction: a satellite is `corrected` only when it has
2033
+ * both a fresh fast correction and (for non-SBAS satellites) a fresh
2034
+ * long-term correction (exactly {@link satCorrection}'s gate). `ionoGrid` is
2035
+ * the total number of valid grid points — the additional requirement for the
2036
+ * *iono*-corrected subset a solver forms per pierce point.
2037
+ *
2038
+ * Use it to tell "no corrections applied" (mask empty / products stale) apart
2039
+ * from "corrections applied but the pierce points aren't grid-covered yet".
2040
+ */
2041
+ coverage(week, tow) {
2042
+ const now = gpsSeconds(week, tow);
2043
+ let masked = 0;
2044
+ let fast = 0;
2045
+ let long = 0;
2046
+ let corrected = 0;
2047
+ for (const s of this.sats) {
2048
+ if (!s.prn) continue;
2049
+ masked++;
2050
+ if (s.fcorr && s.fcorr.t0s !== 0 && s.fcorr.udre < 15 && Math.abs(now - s.fcorr.t0s + this.tlat) <= MAXSBSAGEF)
2051
+ fast++;
2052
+ if (s.prn[0] === "S" || s.lcorr && s.lcorr.t0s !== 0 && Math.abs(now - s.lcorr.t0s) <= MAXSBSAGEL)
2053
+ long++;
2054
+ if (this.satCorrection(s.prn, week, tow)) corrected++;
2055
+ }
2056
+ return { masked, fast, long, corrected, ionoGrid: this.ionoGridPoints() };
2057
+ }
2028
2058
  /**
2029
2059
  * Satellite range/clock correction for a PRN at a GPS week/tow, or null if
2030
2060
  * no valid (unexpired) long-term + fast correction is available. Add `dPos`