gnss-js 2.4.0 → 2.6.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.
@@ -24,6 +24,7 @@ import {
24
24
  crc24q
25
25
  } from "./chunk-YUW33VXK.js";
26
26
  import {
27
+ GPS_PI,
27
28
  GpsLnavAssembler,
28
29
  getBitS,
29
30
  getBitU,
@@ -575,6 +576,173 @@ function parseSbfGpsNav(data) {
575
576
  return { ephemerides, badParity, messages };
576
577
  }
577
578
 
579
+ // src/navbits/navic.ts
580
+ var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
581
+ var SEC_PER_WEEK2 = 604800;
582
+ var DATA = 30;
583
+ function navicSubframeCrcOk(sf) {
584
+ return crc24q(sf, 262) === getBitU(sf, 262, 24);
585
+ }
586
+ function navicSubframeId(sf) {
587
+ return getBitU(sf, 27, 2) + 1;
588
+ }
589
+ function decodeNavicSubframes(sf1, sf2, opts = {}) {
590
+ let i = DATA;
591
+ getBitU(sf1, i, 10);
592
+ i += 10;
593
+ const af0 = getBitS(sf1, i, 22) * 2 ** -31;
594
+ i += 22;
595
+ const af1 = getBitS(sf1, i, 16) * 2 ** -43;
596
+ i += 16;
597
+ const af2 = getBitS(sf1, i, 8) * 2 ** -55;
598
+ i += 8;
599
+ i += 4;
600
+ const tocSec = getBitU(sf1, i, 16) * 16;
601
+ i += 16;
602
+ const tgd = getBitS(sf1, i, 8) * 2 ** -31;
603
+ i += 8;
604
+ const deltaN = getBitS(sf1, i, 22) * 2 ** -41 * GPS_PI;
605
+ i += 22;
606
+ const iode = getBitU(sf1, i, 8);
607
+ i += 8;
608
+ i += 10;
609
+ const l5Health = getBitU(sf1, i, 1);
610
+ i += 1;
611
+ const sHealth = getBitU(sf1, i, 1);
612
+ i += 1;
613
+ const cuc = getBitS(sf1, i, 15) * 2 ** -28;
614
+ i += 15;
615
+ const cus = getBitS(sf1, i, 15) * 2 ** -28;
616
+ i += 15;
617
+ const cic = getBitS(sf1, i, 15) * 2 ** -28;
618
+ i += 15;
619
+ const cis = getBitS(sf1, i, 15) * 2 ** -28;
620
+ i += 15;
621
+ const crc = getBitS(sf1, i, 15) * 2 ** -4;
622
+ i += 15;
623
+ const crs = getBitS(sf1, i, 15) * 2 ** -4;
624
+ i += 15;
625
+ const idot = getBitS(sf1, i, 14) * 2 ** -43 * GPS_PI;
626
+ let j = DATA;
627
+ const m0 = getBitS(sf2, j, 32) * 2 ** -31 * GPS_PI;
628
+ j += 32;
629
+ const toeSec = getBitU(sf2, j, 16) * 16;
630
+ j += 16;
631
+ const e = getBitU(sf2, j, 32) * 2 ** -33;
632
+ j += 32;
633
+ const sqrtA = getBitU(sf2, j, 32) * 2 ** -19;
634
+ j += 32;
635
+ const omega0 = getBitS(sf2, j, 32) * 2 ** -31 * GPS_PI;
636
+ j += 32;
637
+ const omega = getBitS(sf2, j, 32) * 2 ** -31 * GPS_PI;
638
+ j += 32;
639
+ const omegaDot = getBitS(sf2, j, 22) * 2 ** -41 * GPS_PI;
640
+ j += 22;
641
+ const i0 = getBitS(sf2, j, 32) * 2 ** -31 * GPS_PI;
642
+ if (sqrtA <= 0 || e >= 1) return null;
643
+ const week = opts.refWeek ?? Math.floor((Date.now() - GPS_EPOCH_MS3) / 1e3 / SEC_PER_WEEK2);
644
+ const prn = opts.prn ?? "I00";
645
+ const tocDate = new Date(
646
+ GPS_EPOCH_MS3 + (week * SEC_PER_WEEK2 + tocSec) * 1e3
647
+ );
648
+ return {
649
+ system: "I",
650
+ prn,
651
+ tocDate,
652
+ toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK2,
653
+ af0,
654
+ af1,
655
+ af2,
656
+ iode,
657
+ crs,
658
+ deltaN,
659
+ m0,
660
+ cuc,
661
+ e,
662
+ cus,
663
+ sqrtA,
664
+ toe: toeSec,
665
+ cic,
666
+ omega0,
667
+ cis,
668
+ i0,
669
+ crc,
670
+ omega,
671
+ omegaDot,
672
+ idot,
673
+ week,
674
+ svHealth: l5Health << 1 | sHealth,
675
+ tgd
676
+ };
677
+ }
678
+ var NavicAssembler = class {
679
+ sf1 = /* @__PURE__ */ new Map();
680
+ last = /* @__PURE__ */ new Map();
681
+ /**
682
+ * Push one CRC-valid subframe. Subframe 1 opens a master frame (subframe 2
683
+ * immediately follows it in the NavIC frame order), so an ephemeris is only
684
+ * emitted when a subframe 2 pairs with the subframe 1 that opened the *same*
685
+ * frame — never a stale subframe 1 left over across CRC drops.
686
+ */
687
+ push(prn, subframe, refWeek) {
688
+ if (getBitU(subframe, 25, 1)) return null;
689
+ const id = navicSubframeId(subframe);
690
+ if (id === 1) {
691
+ this.sf1.set(prn, subframe);
692
+ return null;
693
+ }
694
+ if (id !== 2) return null;
695
+ const a = this.sf1.get(prn);
696
+ if (!a) return null;
697
+ this.sf1.delete(prn);
698
+ const eph = decodeNavicSubframes(a, subframe, { prn, refWeek });
699
+ if (!eph) return null;
700
+ const key = `${eph.toc}|${eph.iode}`;
701
+ if (this.last.get(prn) === key) return null;
702
+ this.last.set(prn, key);
703
+ return eph;
704
+ }
705
+ };
706
+
707
+ // src/sbf/rawnav-navic.ts
708
+ var WNC_DNU2 = 65535;
709
+ function extractSbfNavicSubframe(view, b) {
710
+ const sf = new Uint8Array(40);
711
+ for (let k = 0; k < 10; k++) {
712
+ const w = view.getUint32(b + 20 + 4 * k, true);
713
+ sf[4 * k] = w >>> 24;
714
+ sf[4 * k + 1] = w >>> 16 & 255;
715
+ sf[4 * k + 2] = w >>> 8 & 255;
716
+ sf[4 * k + 3] = w & 255;
717
+ }
718
+ return sf;
719
+ }
720
+ function feedNavicBlock(view, b, assembler) {
721
+ const prn = svidToPrn(view.getUint8(b + 14));
722
+ if (!prn || prn[0] !== "I") return {};
723
+ const wnc = view.getUint16(b + 12, true);
724
+ if (wnc === WNC_DNU2) return {};
725
+ const sf = extractSbfNavicSubframe(view, b);
726
+ if (!navicSubframeCrcOk(sf)) return { badCrc: true };
727
+ const eph = assembler.push(prn, sf, wnc);
728
+ return eph ? { eph } : {};
729
+ }
730
+ function parseSbfNavic(data) {
731
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
732
+ const ephemerides = [];
733
+ const assembler = new NavicAssembler();
734
+ let badCrc = 0;
735
+ let messages = 0;
736
+ scanSbfFrames(data, view, (id, b, len) => {
737
+ if (id !== 4093 || len < 60) return;
738
+ messages++;
739
+ const r = feedNavicBlock(view, b, assembler);
740
+ if (r.eph) ephemerides.push(r.eph);
741
+ else if (r.badCrc) badCrc++;
742
+ });
743
+ return { ephemerides, badCrc, messages };
744
+ }
745
+
578
746
  // src/sbf/rawnav.ts
579
747
  var CNAV_SIGNAL_OF_BLOCK = {
580
748
  4018: "L2C",
@@ -673,10 +841,10 @@ function isFnavDummy(page) {
673
841
  }
674
842
 
675
843
  // src/sbf/rawnav-bds.ts
676
- var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
844
+ var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
677
845
  var MS_PER_WEEK2 = 7 * 86400 * 1e3;
678
846
  var TOW_DNU = 4294967295;
679
- var WNC_DNU2 = 65535;
847
+ var WNC_DNU3 = 65535;
680
848
  function feedBdsBlock(view, b, assembler) {
681
849
  const prn = svidToPrn(view.getUint8(b + 14));
682
850
  if (!prn || prn[0] !== "C") return {};
@@ -716,7 +884,7 @@ function feedGloBlock(view, b, assembler) {
716
884
  if (!prn || prn[0] !== "R") return {};
717
885
  const towMs = view.getUint32(b + 8, true);
718
886
  const wnc = view.getUint16(b + 12, true);
719
- if (towMs === TOW_DNU || wnc === WNC_DNU2) return {};
887
+ if (towMs === TOW_DNU || wnc === WNC_DNU3) return {};
720
888
  const str2 = new Uint8Array(11);
721
889
  for (let k = 0; k < 3; k++) {
722
890
  const w = view.getUint32(b + 20 + 4 * k, true);
@@ -734,7 +902,7 @@ function feedGloBlock(view, b, assembler) {
734
902
  const eph = assembler.push(
735
903
  prn,
736
904
  str2,
737
- new Date(GPS_EPOCH_MS3 + wnc * MS_PER_WEEK2 + towMs),
905
+ new Date(GPS_EPOCH_MS4 + wnc * MS_PER_WEEK2 + towMs),
738
906
  view.getUint8(b + 18) - 8
739
907
  // FreqNr, offset by 8
740
908
  );
@@ -909,6 +1077,7 @@ function decodeSbfNavigation(data, opts = {}) {
909
1077
  bdsRaw: 0,
910
1078
  sbasRaw: 0,
911
1079
  sbasL5Raw: 0,
1080
+ navicRaw: 0,
912
1081
  badFrames: 0
913
1082
  };
914
1083
  const dfmcByType = {};
@@ -918,6 +1087,7 @@ function decodeSbfNavigation(data, opts = {}) {
918
1087
  const gloAsm = new GloStringAssembler();
919
1088
  const bdsAsm = new BdsAssembler();
920
1089
  const lnavAsm = new GpsLnavAssembler();
1090
+ const navicAsm = new NavicAssembler();
921
1091
  const addEph = (e) => {
922
1092
  if (!e) return;
923
1093
  const key = ephKey(e);
@@ -978,6 +1148,14 @@ function decodeSbfNavigation(data, opts = {}) {
978
1148
  else if (r.badParity) counts.badFrames++;
979
1149
  return;
980
1150
  }
1151
+ case 4093: {
1152
+ if (len < 60) return;
1153
+ counts.navicRaw++;
1154
+ const r = feedNavicBlock(view, b, navicAsm);
1155
+ if (r.eph) addEph(r.eph);
1156
+ else if (r.badCrc) counts.badFrames++;
1157
+ return;
1158
+ }
981
1159
  case 4018:
982
1160
  // GPSRawL2C
983
1161
  case 4019: {
@@ -1598,7 +1776,7 @@ function parseSbfHas(data) {
1598
1776
 
1599
1777
  // src/sbf/index.ts
1600
1778
  var CLIGHT = 299792458;
1601
- var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
1779
+ var GPS_EPOCH_MS5 = Date.UTC(1980, 0, 6);
1602
1780
  var MS_PER_WEEK3 = 7 * 864e5;
1603
1781
  var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
1604
1782
  var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
@@ -2252,7 +2430,7 @@ function parseSbfMeas(data) {
2252
2430
  const tow = view.getUint32(i + 8, true);
2253
2431
  const wnc = view.getUint16(i + 12, true);
2254
2432
  if (tow !== 4294967295 && wnc !== 65535) {
2255
- ensureEpoch(GPS_EPOCH_MS4 + wnc * MS_PER_WEEK3 + tow);
2433
+ ensureEpoch(GPS_EPOCH_MS5 + wnc * MS_PER_WEEK3 + tow);
2256
2434
  if (id === 4109) decodeMeas3Ranges(i, tow);
2257
2435
  else if (id === 4110) decodeMeas3CN0(i, len);
2258
2436
  else if (id === 4111) decodeMeas3Doppler(i, len);
@@ -2273,6 +2451,9 @@ export {
2273
2451
  parseSbfReceiverSetup,
2274
2452
  parseSbfPvt,
2275
2453
  parseSbfGpsNav,
2454
+ extractSbfNavicSubframe,
2455
+ feedNavicBlock,
2456
+ parseSbfNavic,
2276
2457
  parseSbfCnav,
2277
2458
  parseSbfGalNav,
2278
2459
  parseSbfBdsNav,
@@ -534,6 +534,70 @@ function decodeQzssEphemeris(payload) {
534
534
  fitInterval
535
535
  };
536
536
  }
537
+ function decodeNavicEphemeris(payload) {
538
+ if (payload.length < 60) return null;
539
+ const r = new BitReader(payload);
540
+ r.skip(12);
541
+ const svId = r.readU(6);
542
+ const week = r.readU(10);
543
+ const af0 = r.readS(22) * 2 ** -31;
544
+ const af1 = r.readS(16) * 2 ** -43;
545
+ const af2 = r.readS(8) * 2 ** -55;
546
+ const ura = r.readU(4);
547
+ const toc = r.readU(16) * 16;
548
+ const tgd = r.readS(8) * 2 ** -31;
549
+ const deltaN = r.readS(22) * 2 ** -41 * PI;
550
+ const iode = r.readU(8);
551
+ r.skip(10);
552
+ const l5Health = r.readU(1);
553
+ const sHealth = r.readU(1);
554
+ const cuc = r.readS(15) * 2 ** -28;
555
+ const cus = r.readS(15) * 2 ** -28;
556
+ const cic = r.readS(15) * 2 ** -28;
557
+ const cis = r.readS(15) * 2 ** -28;
558
+ const crc = r.readS(15) * 2 ** -4;
559
+ const crs = r.readS(15) * 2 ** -4;
560
+ const idot = r.readS(14) * 2 ** -43 * PI;
561
+ const m0 = r.readS(32) * 2 ** -31 * PI;
562
+ const toe = r.readU(16) * 16;
563
+ const e = r.readU(32) * 2 ** -33;
564
+ const sqrtA = r.readU(32) * 2 ** -19;
565
+ const omega0 = r.readS(32) * 2 ** -31 * PI;
566
+ const argPerigee = r.readS(32) * 2 ** -31 * PI;
567
+ const omegaDot = r.readS(22) * 2 ** -41 * PI;
568
+ const i0 = r.readS(32) * 2 ** -31 * PI;
569
+ return {
570
+ prn: `I${String(svId).padStart(2, "0")}`,
571
+ constellation: "NavIC",
572
+ health: l5Health << 1 | sHealth,
573
+ lastReceived: Date.now(),
574
+ messageType: 1041,
575
+ week,
576
+ ura,
577
+ toc,
578
+ toe,
579
+ sqrtA,
580
+ eccentricity: e,
581
+ inclination: i0,
582
+ omega0,
583
+ omegaDot,
584
+ argPerigee,
585
+ meanAnomaly: m0,
586
+ deltaN,
587
+ idot,
588
+ crs,
589
+ crc,
590
+ cuc,
591
+ cus,
592
+ cic,
593
+ cis,
594
+ af0,
595
+ af1,
596
+ af2,
597
+ iode,
598
+ tgd
599
+ };
600
+ }
537
601
  function decodeEphemeris(frame) {
538
602
  try {
539
603
  switch (frame.messageType) {
@@ -541,6 +605,8 @@ function decodeEphemeris(frame) {
541
605
  return decodeGpsEphemeris(frame.payload);
542
606
  case 1020:
543
607
  return decodeGlonassEphemeris(frame.payload);
608
+ case 1041:
609
+ return decodeNavicEphemeris(frame.payload);
544
610
  case 1042:
545
611
  return decodeBdsEphemeris(frame.payload);
546
612
  case 1043:
@@ -22,6 +22,7 @@ import {
22
22
  } from "./chunk-V2D5KUKH.js";
23
23
  import {
24
24
  C_LIGHT,
25
+ FREQ,
25
26
  OMEGA_E
26
27
  } from "./chunk-FIEWO4J4.js";
27
28
 
@@ -1463,6 +1464,162 @@ function postProcessRtk(base, rover, ephemerides, baseEcef, opts = {}) {
1463
1464
  return { track, solved, unmatched, fixRate: solved ? fixed / solved : 0 };
1464
1465
  }
1465
1466
 
1467
+ // src/positioning/zero-baseline.ts
1468
+ function carrierFreqHz2(sys, band, gloChannel) {
1469
+ if (sys === "R") {
1470
+ if (band === "1") return 1602e6 + (gloChannel ?? 0) * 562500;
1471
+ if (band === "2") return 1246e6 + (gloChannel ?? 0) * 437500;
1472
+ return FREQ.R?.[band] ?? 0;
1473
+ }
1474
+ return FREQ[sys]?.[band] ?? 0;
1475
+ }
1476
+ function median(a) {
1477
+ if (a.length === 0) return 0;
1478
+ const s = [...a].sort((x, y) => x - y);
1479
+ const m = s.length >> 1;
1480
+ return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
1481
+ }
1482
+ var ZeroBaselineEngine = class {
1483
+ ref;
1484
+ refSys;
1485
+ slip;
1486
+ /** Per (receiver|prn|code) continuous phase-SD arc. */
1487
+ arcs = /* @__PURE__ */ new Map();
1488
+ /** Per receiver: integrated phase-smoothed clock (m). */
1489
+ phaseClock = /* @__PURE__ */ new Map();
1490
+ /** Per (receiver|system): accumulated ISB (m) + count. */
1491
+ isb = /* @__PURE__ */ new Map();
1492
+ constructor(opts) {
1493
+ this.ref = opts.reference;
1494
+ this.refSys = opts.referenceSystem ?? "G";
1495
+ this.slip = opts.slipThreshM ?? 0.05;
1496
+ }
1497
+ reset() {
1498
+ this.arcs.clear();
1499
+ this.phaseClock.clear();
1500
+ this.isb.clear();
1501
+ }
1502
+ /** ISB/IFB estimates accumulated so far, per receiver × system. */
1503
+ biases() {
1504
+ const out = [];
1505
+ for (const [key, { sum, n }] of this.isb) {
1506
+ const [receiver, system] = key.split("|");
1507
+ out.push({ receiver, system, biasM: sum / n, n });
1508
+ }
1509
+ return out;
1510
+ }
1511
+ /**
1512
+ * Ingest one time-aligned instant: observations per receiver id. Returns one
1513
+ * {@link ReceiverClockSample} per non-reference receiver present this epoch.
1514
+ */
1515
+ process(epoch) {
1516
+ const refObs = epoch.obs[this.ref];
1517
+ if (!refObs) return [];
1518
+ const refByKey = /* @__PURE__ */ new Map();
1519
+ for (const o of refObs)
1520
+ if (o.pr != null && Number.isFinite(o.pr))
1521
+ refByKey.set(`${o.prn}|${o.code}`, o);
1522
+ const out = [];
1523
+ for (const rx of Object.keys(epoch.obs)) {
1524
+ if (rx === this.ref) continue;
1525
+ out.push(
1526
+ this.processReceiver(rx, epoch.obs[rx], refByKey, epoch.timeMs)
1527
+ );
1528
+ }
1529
+ return out;
1530
+ }
1531
+ processReceiver(rx, obs, refByKey, t) {
1532
+ const codeBySys = /* @__PURE__ */ new Map();
1533
+ const phase = [];
1534
+ for (const o of obs) {
1535
+ if (o.pr == null || !Number.isFinite(o.pr)) continue;
1536
+ const r = refByKey.get(`${o.prn}|${o.code}`);
1537
+ if (!r || r.pr == null) continue;
1538
+ const sys = o.prn[0];
1539
+ (codeBySys.get(sys) ?? codeBySys.set(sys, []).get(sys)).push(
1540
+ o.pr - r.pr
1541
+ );
1542
+ if (o.cp != null && r.cp != null) {
1543
+ const f = carrierFreqHz2(
1544
+ sys,
1545
+ o.code[0],
1546
+ o.gloChannel ?? r.gloChannel ?? null
1547
+ );
1548
+ if (f > 0)
1549
+ phase.push({
1550
+ key: `${rx}|${o.prn}|${o.code}`,
1551
+ sdM: (o.cp - r.cp) * (C_LIGHT / f),
1552
+ lock: o.lockTimeS
1553
+ });
1554
+ }
1555
+ }
1556
+ if (codeBySys.size === 0)
1557
+ return {
1558
+ t,
1559
+ receiver: rx,
1560
+ clockOffsetM: null,
1561
+ clockOffsetPhaseM: this.phaseClock.get(rx) ?? null,
1562
+ used: 0,
1563
+ rejected: 0,
1564
+ residualRmsM: 0
1565
+ };
1566
+ const sysMedian = /* @__PURE__ */ new Map();
1567
+ for (const [sys, v] of codeBySys) sysMedian.set(sys, median(v));
1568
+ const allSd = [];
1569
+ for (const v of codeBySys.values()) allSd.push(...v);
1570
+ const clk = sysMedian.get(this.refSys) ?? median(allSd);
1571
+ for (const [sys, med] of sysMedian) {
1572
+ if (sys === this.refSys) continue;
1573
+ const cur = this.isb.get(`${rx}|${sys}`) ?? { sum: 0, n: 0 };
1574
+ cur.sum += med - clk;
1575
+ cur.n += 1;
1576
+ this.isb.set(`${rx}|${sys}`, cur);
1577
+ }
1578
+ let ss = 0, used = 0, rejected = 0;
1579
+ for (const [sys, v] of codeBySys) {
1580
+ const isb = sys === this.refSys ? 0 : sysMedian.get(sys) - clk;
1581
+ for (const sd of v) {
1582
+ const res = sd - clk - isb;
1583
+ if (Math.abs(res) > 5) {
1584
+ rejected++;
1585
+ continue;
1586
+ }
1587
+ ss += res * res;
1588
+ used++;
1589
+ }
1590
+ }
1591
+ const residualRmsM = used ? Math.sqrt(ss / used) : 0;
1592
+ const deltas = [];
1593
+ for (const p of phase) {
1594
+ const arc = this.arcs.get(p.key);
1595
+ this.arcs.set(p.key, { lastPhaseSdM: p.sdM, lastLock: p.lock });
1596
+ if (!arc) continue;
1597
+ const lockReset = p.lock != null && arc.lastLock != null && p.lock < arc.lastLock;
1598
+ if (lockReset) continue;
1599
+ deltas.push(p.sdM - arc.lastPhaseSdM);
1600
+ }
1601
+ let phaseClockM = this.phaseClock.get(rx) ?? null;
1602
+ if (phaseClockM == null) {
1603
+ phaseClockM = clk;
1604
+ } else if (deltas.length) {
1605
+ const md = median(deltas);
1606
+ const good = deltas.filter((d) => Math.abs(d - md) < this.slip);
1607
+ const step = good.length ? good.reduce((a, b) => a + b, 0) / good.length : md;
1608
+ phaseClockM += step;
1609
+ }
1610
+ this.phaseClock.set(rx, phaseClockM);
1611
+ return {
1612
+ t,
1613
+ receiver: rx,
1614
+ clockOffsetM: clk,
1615
+ clockOffsetPhaseM: phaseClockM,
1616
+ used,
1617
+ rejected,
1618
+ residualRmsM
1619
+ };
1620
+ }
1621
+ };
1622
+
1466
1623
  // src/positioning/sbas.ts
1467
1624
  var P2_11 = 2 ** -11;
1468
1625
  var P2_31 = 2 ** -31;
@@ -3874,6 +4031,7 @@ export {
3874
4031
  solveDgnss,
3875
4032
  RtkFloatEngine,
3876
4033
  postProcessRtk,
4034
+ ZeroBaselineEngine,
3877
4035
  sbasLongTermDeg,
3878
4036
  sbasIonoDeg,
3879
4037
  SbasProcessor,