gnss-js 1.17.0 → 1.18.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.cjs CHANGED
@@ -222,12 +222,14 @@ __export(src_exports, {
222
222
  parseNovatelRange: () => parseNovatelRange,
223
223
  parseRinexStream: () => parseRinexStream,
224
224
  parseSbfAlmanac: () => parseSbfAlmanac,
225
+ parseSbfCnav: () => parseSbfCnav,
225
226
  parseSbfIonoUtc: () => parseSbfIonoUtc,
226
227
  parseSbfMeas: () => parseSbfMeas,
227
228
  parseSbfNav: () => parseSbfNav,
228
229
  parseSinexBiasDcb: () => parseSinexBiasDcb,
229
230
  parseSourcetable: () => parseSourcetable,
230
231
  parseSp3: () => parseSp3,
232
+ parseUbxCnav: () => parseUbxCnav,
231
233
  parseUbxIonoUtc: () => parseUbxIonoUtc,
232
234
  parseUbxNav: () => parseUbxNav,
233
235
  parseUbxRawx: () => parseUbxRawx,
@@ -4884,8 +4886,238 @@ function parseUbxIonoUtc(data) {
4884
4886
  return { ionoCorrections, leapSeconds };
4885
4887
  }
4886
4888
 
4887
- // src/ubx/index.ts
4889
+ // src/navbits/cnav.ts
4888
4890
  var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
4891
+ var SEC_PER_WEEK2 = 7 * 86400;
4892
+ var HALF_WEEK = 302400;
4893
+ var CNAV_PREAMBLE = 139;
4894
+ var CNAV_A_REF = 26559710;
4895
+ var CNAV_OMEGA_DOT_REF = -26e-10;
4896
+ function crc24q2(buff, bitLen) {
4897
+ let crc = 0;
4898
+ for (let i = 0; i < bitLen; i++) {
4899
+ crc ^= (buff[i >> 3] >> 7 - (i & 7) & 1) << 23;
4900
+ const msb = crc & 8388608;
4901
+ crc = crc << 1 & 16777215;
4902
+ if (msb) crc ^= 8801531;
4903
+ }
4904
+ return crc;
4905
+ }
4906
+ function cnavCrcOk(msg) {
4907
+ if (msg.length < 38) return false;
4908
+ return crc24q2(msg, 276) === getBitU(msg, 276, 24);
4909
+ }
4910
+ function getBitU33(b, pos) {
4911
+ return getBitU(b, pos, 1) * 2 ** 32 + getBitU(b, pos + 1, 32);
4912
+ }
4913
+ function getBitS33(b, pos) {
4914
+ const u = getBitU33(b, pos);
4915
+ return u < 2 ** 32 ? u : u - 2 ** 33;
4916
+ }
4917
+ function decodeType10(b, tow) {
4918
+ return {
4919
+ tow,
4920
+ week: getBitU(b, 38, 13),
4921
+ health: getBitU(b, 51, 3),
4922
+ top: getBitU(b, 54, 11) * 300,
4923
+ uraEd: getBitS(b, 65, 5),
4924
+ toe: getBitU(b, 70, 11) * 300,
4925
+ deltaA: getBitS(b, 81, 26) * 2 ** -9,
4926
+ aDot: getBitS(b, 107, 25) * 2 ** -21,
4927
+ deltaN0: getBitS(b, 132, 17) * 2 ** -44 * GPS_PI,
4928
+ deltaN0Dot: getBitS(b, 149, 23) * 2 ** -57 * GPS_PI,
4929
+ m0: getBitS33(b, 172) * 2 ** -32 * GPS_PI,
4930
+ e: getBitU33(b, 205) * 2 ** -34,
4931
+ omega: getBitS33(b, 238) * 2 ** -32 * GPS_PI,
4932
+ integrityFlag: getBitU(b, 271, 1) === 1,
4933
+ l2cPhasing: getBitU(b, 272, 1) === 1
4934
+ };
4935
+ }
4936
+ function decodeType11(b) {
4937
+ return {
4938
+ toe: getBitU(b, 38, 11) * 300,
4939
+ omega0: getBitS33(b, 49) * 2 ** -32 * GPS_PI,
4940
+ i0: getBitS33(b, 82) * 2 ** -32 * GPS_PI,
4941
+ deltaOmegaDot: getBitS(b, 115, 17) * 2 ** -44 * GPS_PI,
4942
+ i0Dot: getBitS(b, 132, 15) * 2 ** -44 * GPS_PI,
4943
+ cis: getBitS(b, 147, 16) * 2 ** -30,
4944
+ cic: getBitS(b, 163, 16) * 2 ** -30,
4945
+ crs: getBitS(b, 179, 24) * 2 ** -8,
4946
+ crc: getBitS(b, 203, 24) * 2 ** -8,
4947
+ cus: getBitS(b, 227, 21) * 2 ** -30,
4948
+ cuc: getBitS(b, 248, 21) * 2 ** -30
4949
+ };
4950
+ }
4951
+ var isc = (b, pos) => {
4952
+ const raw = getBitS(b, pos, 13);
4953
+ return raw === -4096 ? null : raw * 2 ** -35;
4954
+ };
4955
+ function decodeClock(b, msgType) {
4956
+ const clock = {
4957
+ msgType,
4958
+ top: getBitU(b, 38, 11) * 300,
4959
+ uraNed0: getBitS(b, 49, 5),
4960
+ uraNed1: getBitU(b, 54, 3),
4961
+ uraNed2: getBitU(b, 57, 3),
4962
+ toc: getBitU(b, 60, 11) * 300,
4963
+ af0: getBitS(b, 71, 26) * 2 ** -35,
4964
+ af1: getBitS(b, 97, 20) * 2 ** -48,
4965
+ af2: getBitS(b, 117, 10) * 2 ** -60
4966
+ };
4967
+ if (msgType === 30) {
4968
+ clock.tgd = isc(b, 127);
4969
+ clock.iscL1ca = isc(b, 140);
4970
+ clock.iscL2c = isc(b, 153);
4971
+ clock.iscL5i5 = isc(b, 166);
4972
+ clock.iscL5q5 = isc(b, 179);
4973
+ clock.ionoAlpha = [
4974
+ getBitS(b, 192, 8) * 2 ** -30,
4975
+ getBitS(b, 200, 8) * 2 ** -27,
4976
+ getBitS(b, 208, 8) * 2 ** -24,
4977
+ getBitS(b, 216, 8) * 2 ** -24
4978
+ ];
4979
+ clock.ionoBeta = [
4980
+ getBitS(b, 224, 8) * 2 ** 11,
4981
+ getBitS(b, 232, 8) * 2 ** 14,
4982
+ getBitS(b, 240, 8) * 2 ** 16,
4983
+ getBitS(b, 248, 8) * 2 ** 16
4984
+ ];
4985
+ clock.wnOp = getBitU(b, 256, 8);
4986
+ }
4987
+ return clock;
4988
+ }
4989
+ function resolveWeek(week, towSec, sec) {
4990
+ if (sec < towSec - HALF_WEEK) return week + 1;
4991
+ if (sec > towSec + HALF_WEEK) return week - 1;
4992
+ return week;
4993
+ }
4994
+ function gpsDate(week, sec) {
4995
+ return new Date(GPS_EPOCH_MS2 + (week * SEC_PER_WEEK2 + sec) * 1e3);
4996
+ }
4997
+ var CnavAssembler = class {
4998
+ sats = /* @__PURE__ */ new Map();
4999
+ /**
5000
+ * Push one 300-bit CNAV message (38+ bytes, bit 0 = first bit of
5001
+ * the preamble). Returns the newly completed ephemeris, or null.
5002
+ * Messages that are not MT10/MT11/MT30-37, or whose preamble/PRN
5003
+ * are out of range, are ignored.
5004
+ */
5005
+ push(msg) {
5006
+ if (msg.length < 38 || getBitU(msg, 0, 8) !== CNAV_PREAMBLE) return null;
5007
+ const prn = getBitU(msg, 8, 6);
5008
+ if (prn < 1 || prn > 32) return null;
5009
+ const type = getBitU(msg, 14, 6);
5010
+ const tow = getBitU(msg, 20, 17) * 6;
5011
+ let sat = this.sats.get(prn);
5012
+ if (!sat) {
5013
+ sat = {};
5014
+ this.sats.set(prn, sat);
5015
+ }
5016
+ if (type === 10) sat.t10 = decodeType10(msg, tow);
5017
+ else if (type === 11) sat.t11 = decodeType11(msg);
5018
+ else if (type >= 30 && type <= 37) {
5019
+ sat.clock = decodeClock(msg, type);
5020
+ if (type === 30) sat.extras = sat.clock;
5021
+ } else return null;
5022
+ return this.tryEmit(prn, sat);
5023
+ }
5024
+ tryEmit(prn, sat) {
5025
+ const { t10, t11, clock, extras } = sat;
5026
+ if (!t10 || !t11 || !clock) return null;
5027
+ if (t10.toe !== t11.toe || clock.toc !== t10.toe) return null;
5028
+ const key = `${t10.week}:${t10.toe}:${clock.af0}:${clock.af1}`;
5029
+ if (key === sat.lastKey) return null;
5030
+ sat.lastKey = key;
5031
+ const weekToe = resolveWeek(t10.week, t10.tow, t10.toe);
5032
+ const a = CNAV_A_REF + t10.deltaA;
5033
+ return {
5034
+ system: "G",
5035
+ prn: `G${String(prn).padStart(2, "0")}`,
5036
+ week: t10.week,
5037
+ health: t10.health,
5038
+ uraEd: t10.uraEd,
5039
+ uraNed0: clock.uraNed0,
5040
+ uraNed1: clock.uraNed1,
5041
+ uraNed2: clock.uraNed2,
5042
+ top: t10.top,
5043
+ toe: t10.toe,
5044
+ toeDate: gpsDate(weekToe, t10.toe),
5045
+ a,
5046
+ deltaA: t10.deltaA,
5047
+ aDot: t10.aDot,
5048
+ deltaN0: t10.deltaN0,
5049
+ deltaN0Dot: t10.deltaN0Dot,
5050
+ m0: t10.m0,
5051
+ e: t10.e,
5052
+ omega: t10.omega,
5053
+ omega0: t11.omega0,
5054
+ i0: t11.i0,
5055
+ omegaDot: CNAV_OMEGA_DOT_REF * GPS_PI + t11.deltaOmegaDot,
5056
+ deltaOmegaDot: t11.deltaOmegaDot,
5057
+ i0Dot: t11.i0Dot,
5058
+ cis: t11.cis,
5059
+ cic: t11.cic,
5060
+ crs: t11.crs,
5061
+ crc: t11.crc,
5062
+ cus: t11.cus,
5063
+ cuc: t11.cuc,
5064
+ toc: clock.toc,
5065
+ tocDate: gpsDate(weekToe, clock.toc),
5066
+ af0: clock.af0,
5067
+ af1: clock.af1,
5068
+ af2: clock.af2,
5069
+ clockMsgType: clock.msgType,
5070
+ tgd: extras?.tgd ?? null,
5071
+ iscL1ca: extras?.iscL1ca ?? null,
5072
+ iscL2c: extras?.iscL2c ?? null,
5073
+ iscL5i5: extras?.iscL5i5 ?? null,
5074
+ iscL5q5: extras?.iscL5q5 ?? null,
5075
+ ...extras?.ionoAlpha && { ionoAlpha: extras.ionoAlpha },
5076
+ ...extras?.ionoBeta && { ionoBeta: extras.ionoBeta },
5077
+ ...extras?.wnOp !== void 0 && { wnOp: extras.wnOp },
5078
+ integrityFlag: t10.integrityFlag,
5079
+ l2cPhasing: t10.l2cPhasing,
5080
+ tow: t10.tow
5081
+ };
5082
+ }
5083
+ };
5084
+
5085
+ // src/ubx/cnav.ts
5086
+ function parseUbxCnav(data) {
5087
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
5088
+ const assembler = new CnavAssembler();
5089
+ const ephemerides = [];
5090
+ let badCrc = 0;
5091
+ let messages = 0;
5092
+ for (const f of ubxFrames(data)) {
5093
+ if (f.msgClass !== 2 || f.msgId !== 19) continue;
5094
+ const p = f.payload;
5095
+ if (p.length < 8 + 40) continue;
5096
+ if (p[0] !== 0 || p[2] !== 3 && p[2] !== 4) continue;
5097
+ const svId = p[1];
5098
+ if (svId < 1 || svId > 32) continue;
5099
+ messages++;
5100
+ const msg = new Uint8Array(40);
5101
+ const base = f.payloadStart + 8;
5102
+ for (let k = 0; k < 10; k++) {
5103
+ const w = view.getUint32(base + 4 * k, true);
5104
+ msg[4 * k] = w >>> 24;
5105
+ msg[4 * k + 1] = w >>> 16 & 255;
5106
+ msg[4 * k + 2] = w >>> 8 & 255;
5107
+ msg[4 * k + 3] = w & 255;
5108
+ }
5109
+ if (!cnavCrcOk(msg)) {
5110
+ badCrc++;
5111
+ continue;
5112
+ }
5113
+ const eph = assembler.push(msg);
5114
+ if (eph) ephemerides.push(eph);
5115
+ }
5116
+ return { ephemerides, badCrc, messages };
5117
+ }
5118
+
5119
+ // src/ubx/index.ts
5120
+ var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
4889
5121
  var MS_PER_WEEK2 = 7 * 864e5;
4890
5122
  var SIGNALS = {
4891
5123
  0: { 0: ["G", "1C"], 3: ["G", "2X"], 4: ["G", "2X"] },
@@ -4968,7 +5200,7 @@ function parseUbxRawx(data) {
4968
5200
  if (!codes.includes(sig[1])) codes.push(sig[1]);
4969
5201
  }
4970
5202
  epochs.push({
4971
- timeMs: GPS_EPOCH_MS2 + week * MS_PER_WEEK2 + Math.round(rcvTow * 1e3),
5203
+ timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK2 + Math.round(rcvTow * 1e3),
4972
5204
  leapS: leapValid ? leapS : null,
4973
5205
  meas
4974
5206
  });
@@ -5039,10 +5271,10 @@ function svidToPrn(svid) {
5039
5271
 
5040
5272
  // src/sbf/nav.ts
5041
5273
  var PI2 = Math.PI;
5042
- var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
5274
+ var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
5043
5275
  var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
5044
- var SEC_PER_WEEK2 = 7 * 86400;
5045
- var MS_PER_WEEK3 = SEC_PER_WEEK2 * 1e3;
5276
+ var SEC_PER_WEEK3 = 7 * 86400;
5277
+ var MS_PER_WEEK3 = SEC_PER_WEEK3 * 1e3;
5046
5278
  var F4_DNU = -2e10;
5047
5279
  var U4_DNU = 4294967295;
5048
5280
  function adjustWeek(refWeek, wn, mod) {
@@ -5051,8 +5283,8 @@ function adjustWeek(refWeek, wn, mod) {
5051
5283
  if (offset < -(mod / 2 - 1)) offset += mod;
5052
5284
  return refWeek - offset;
5053
5285
  }
5054
- var gpsMs = (week, sec) => GPS_EPOCH_MS3 + week * MS_PER_WEEK3 + sec * 1e3;
5055
- var sowOf = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK2;
5286
+ var gpsMs = (week, sec) => GPS_EPOCH_MS4 + week * MS_PER_WEEK3 + sec * 1e3;
5287
+ var sowOf = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK3;
5056
5288
  function decodeGpsQzsNav(view, b, sys) {
5057
5289
  const svid = view.getUint8(b + 14);
5058
5290
  const prn = sys === "G" ? svid : svid - 180;
@@ -5201,7 +5433,7 @@ function decodeGloNav(view, b) {
5201
5433
  const tocDate = new Date(toeGpsMs - leapMs);
5202
5434
  const tofGpsMs = gpsMs(wnc, 0) + view.getUint32(b + 8, true);
5203
5435
  const tofLeapMs = getGpsLeap(new Date(tofGpsMs)) * 1e3;
5204
- const messageFrameTime = (tofGpsMs - tofLeapMs - GPS_EPOCH_MS3) / 1e3 % SEC_PER_WEEK2;
5436
+ const messageFrameTime = (tofGpsMs - tofLeapMs - GPS_EPOCH_MS4) / 1e3 % SEC_PER_WEEK3;
5205
5437
  return {
5206
5438
  system: "R",
5207
5439
  prn,
@@ -5379,9 +5611,45 @@ function parseSbfIonoUtc(data) {
5379
5611
  return { ionoCorrections, leapSeconds };
5380
5612
  }
5381
5613
 
5614
+ // src/sbf/rawnav.ts
5615
+ var SIGNAL_OF_BLOCK = {
5616
+ 4018: "L2C",
5617
+ 4019: "L5"
5618
+ };
5619
+ function parseSbfCnav(data) {
5620
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
5621
+ const ephemerides = [];
5622
+ const assemblers = {
5623
+ L2C: new CnavAssembler(),
5624
+ L5: new CnavAssembler()
5625
+ };
5626
+ let badCrc = 0;
5627
+ let messages = 0;
5628
+ scanSbfFrames(data, view, (id, b, len) => {
5629
+ const signal = SIGNAL_OF_BLOCK[id];
5630
+ if (!signal || len < 60) return;
5631
+ messages++;
5632
+ const msg = new Uint8Array(40);
5633
+ for (let k = 0; k < 10; k++) {
5634
+ const w = view.getUint32(b + 20 + 4 * k, true);
5635
+ msg[4 * k] = w >>> 24;
5636
+ msg[4 * k + 1] = w >>> 16 & 255;
5637
+ msg[4 * k + 2] = w >>> 8 & 255;
5638
+ msg[4 * k + 3] = w & 255;
5639
+ }
5640
+ if (!cnavCrcOk(msg)) {
5641
+ badCrc++;
5642
+ return;
5643
+ }
5644
+ const eph = assemblers[signal].push(msg);
5645
+ if (eph) ephemerides.push({ ...eph, signal });
5646
+ });
5647
+ return { ephemerides, badCrc, messages };
5648
+ }
5649
+
5382
5650
  // src/sbf/index.ts
5383
5651
  var CLIGHT = 299792458;
5384
- var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
5652
+ var GPS_EPOCH_MS5 = Date.UTC(1980, 0, 6);
5385
5653
  var MS_PER_WEEK4 = 7 * 864e5;
5386
5654
  var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
5387
5655
  var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
@@ -6035,7 +6303,7 @@ function parseSbfMeas(data) {
6035
6303
  const tow = view.getUint32(i + 8, true);
6036
6304
  const wnc = view.getUint16(i + 12, true);
6037
6305
  if (tow !== 4294967295 && wnc !== 65535) {
6038
- ensureEpoch(GPS_EPOCH_MS4 + wnc * MS_PER_WEEK4 + tow);
6306
+ ensureEpoch(GPS_EPOCH_MS5 + wnc * MS_PER_WEEK4 + tow);
6039
6307
  if (id === 4109) decodeMeas3Ranges(i, tow);
6040
6308
  else if (id === 4110) decodeMeas3CN0(i, len);
6041
6309
  else if (id === 4111) decodeMeas3Doppler(i, len);
@@ -6097,16 +6365,17 @@ var ID_RAWEPHEM = 41;
6097
6365
  var ID_GLOEPHEMERIS = 723;
6098
6366
  var ID_GALEPHEMERIS = 1122;
6099
6367
  var ID_QZSSEPHEMERIS = 1336;
6368
+ var ID_GPSEPHEM = 7;
6100
6369
  var ID_BDSEPHEMERIS = 1696;
6101
- var GPS_EPOCH_MS5 = Date.UTC(1980, 0, 6);
6370
+ var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
6102
6371
  var BDT_EPOCH_MS2 = Date.UTC(2006, 0, 1);
6103
- var SEC_PER_WEEK3 = 7 * 86400;
6372
+ var SEC_PER_WEEK4 = 7 * 86400;
6104
6373
  var SEC_PER_DAY = 86400;
6105
- var MS_PER_WEEK5 = SEC_PER_WEEK3 * 1e3;
6106
- var gpsMs2 = (week, sec) => GPS_EPOCH_MS5 + week * MS_PER_WEEK5 + sec * 1e3;
6107
- var sowOf2 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK3;
6374
+ var MS_PER_WEEK5 = SEC_PER_WEEK4 * 1e3;
6375
+ var gpsMs2 = (week, sec) => GPS_EPOCH_MS6 + week * MS_PER_WEEK5 + sec * 1e3;
6376
+ var sowOf2 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK4;
6108
6377
  function nearWeekMs(refMs, sow) {
6109
- const refWeek = Math.floor((refMs - GPS_EPOCH_MS5) / MS_PER_WEEK5);
6378
+ const refWeek = Math.floor((refMs - GPS_EPOCH_MS6) / MS_PER_WEEK5);
6110
6379
  let ms = gpsMs2(refWeek, sow);
6111
6380
  if (ms < refMs - MS_PER_WEEK5 / 2) ms += MS_PER_WEEK5;
6112
6381
  else if (ms > refMs + MS_PER_WEEK5 / 2) ms -= MS_PER_WEEK5;
@@ -6133,9 +6402,9 @@ function decodeGloEphemeris(view, p) {
6133
6402
  tof += Math.floor(tow / SEC_PER_DAY) * SEC_PER_DAY;
6134
6403
  if (tof < tow - 43200) tof += SEC_PER_DAY;
6135
6404
  else if (tof > tow + 43200) tof -= SEC_PER_DAY;
6136
- const toeGpsMs = GPS_EPOCH_MS5 + (week * SEC_PER_WEEK3 + tow) * 1e3;
6137
- const tofGpsMs = GPS_EPOCH_MS5 + (week * SEC_PER_WEEK3 + tof) * 1e3;
6138
- const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS5) / 1e3;
6405
+ const toeGpsMs = GPS_EPOCH_MS6 + (week * SEC_PER_WEEK4 + tow) * 1e3;
6406
+ const tofGpsMs = GPS_EPOCH_MS6 + (week * SEC_PER_WEEK4 + tof) * 1e3;
6407
+ const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS6) / 1e3;
6139
6408
  return {
6140
6409
  system: "R",
6141
6410
  prn: `R${String(slot).padStart(2, "0")}`,
@@ -6143,7 +6412,7 @@ function decodeGloEphemeris(view, p) {
6143
6412
  tauN: -view.getFloat64(p + 100, true),
6144
6413
  // RINEX stores −τ_n
6145
6414
  gammaN: view.getFloat64(p + 116, true),
6146
- messageFrameTime: (tofUtcSec % SEC_PER_WEEK3 + SEC_PER_WEEK3) % SEC_PER_WEEK3,
6415
+ messageFrameTime: (tofUtcSec % SEC_PER_WEEK4 + SEC_PER_WEEK4) % SEC_PER_WEEK4,
6147
6416
  x: view.getFloat64(p + 28, true) / 1e3,
6148
6417
  y: view.getFloat64(p + 36, true) / 1e3,
6149
6418
  z: view.getFloat64(p + 44, true) / 1e3,
@@ -6200,7 +6469,7 @@ function decodeGalEphemeris(view, p, headerMs) {
6200
6469
  omega: view.getFloat64(p + 60, true),
6201
6470
  omegaDot: view.getFloat64(p + 140, true),
6202
6471
  idot: view.getFloat64(p + 124, true),
6203
- week: Math.floor((toeMs - GPS_EPOCH_MS5) / MS_PER_WEEK5),
6472
+ week: Math.floor((toeMs - GPS_EPOCH_MS6) / MS_PER_WEEK5),
6204
6473
  // RINEX Galileo SVH bit layout (E1B DVS/HS in bits 0-2, E5a in
6205
6474
  // 3-5, E5b in 6-8) — same packing as RTKLIB.
6206
6475
  svHealth: svhE5b << 7 | dvsE5b << 6 | svhE5a << 4 | dvsE5a << 3 | svhE1b << 1 | dvsE1b,
@@ -6251,9 +6520,10 @@ function decodeBdsEphemeris2(view, p) {
6251
6520
  // TGD1 (B1) — RINEX slot
6252
6521
  };
6253
6522
  }
6254
- function decodeQzssEphemeris2(view, p) {
6523
+ function decodeGpsQzssEphemeris(view, p, sys) {
6255
6524
  const prn = view.getUint32(p, true);
6256
- if (prn < 193 || prn > 202) return null;
6525
+ if (sys === "G" && (prn < 1 || prn > 32)) return null;
6526
+ if (sys === "J" && (prn < 193 || prn > 202)) return null;
6257
6527
  const health = view.getUint32(p + 12, true) & 63;
6258
6528
  const iode1 = view.getUint32(p + 16, true);
6259
6529
  const week = view.getUint32(p + 24, true);
@@ -6262,8 +6532,8 @@ function decodeQzssEphemeris2(view, p) {
6262
6532
  const tocs = view.getFloat64(p + 164, true);
6263
6533
  const tocDate = new Date(nearWeekMs(toeMs, tocs));
6264
6534
  return {
6265
- system: "J",
6266
- prn: `J${String(prn - 192).padStart(2, "0")}`,
6535
+ system: sys,
6536
+ prn: `${sys}${String(sys === "J" ? prn - 192 : prn).padStart(2, "0")}`,
6267
6537
  toc: sowOf2(tocDate.getTime()),
6268
6538
  tocDate,
6269
6539
  af0: view.getFloat64(p + 180, true),
@@ -6321,8 +6591,11 @@ function parseNovatelNav(data) {
6321
6591
  } else if (frame.id === ID_BDSEPHEMERIS && frame.msgLen >= 196) {
6322
6592
  const eph = decodeBdsEphemeris2(view, frame.payload);
6323
6593
  if (eph) pushKepler(eph.prn, eph);
6594
+ } else if (frame.id === ID_GPSEPHEM && frame.msgLen >= 204) {
6595
+ const eph = decodeGpsQzssEphemeris(view, frame.payload, "G");
6596
+ if (eph) pushKepler(eph.prn, eph);
6324
6597
  } else if (frame.id === ID_QZSSEPHEMERIS && frame.msgLen >= 204) {
6325
- const eph = decodeQzssEphemeris2(view, frame.payload);
6598
+ const eph = decodeGpsQzssEphemeris(view, frame.payload, "J");
6326
6599
  if (eph) pushKepler(eph.prn, eph);
6327
6600
  } else if (frame.id === ID_IONUTC && frame.msgLen >= 108) {
6328
6601
  const p = frame.payload;
@@ -6350,7 +6623,7 @@ function parseNovatelNav(data) {
6350
6623
  }
6351
6624
 
6352
6625
  // src/novatel/index.ts
6353
- var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
6626
+ var GPS_EPOCH_MS7 = Date.UTC(1980, 0, 6);
6354
6627
  var MS_PER_WEEK6 = 7 * 864e5;
6355
6628
  var HDR = 28;
6356
6629
  var ID_RANGE = 43;
@@ -6520,7 +6793,7 @@ function parseNovatelRange(data) {
6520
6793
  if (!codes.includes(code)) codes.push(code);
6521
6794
  }
6522
6795
  epochs.push({
6523
- timeMs: GPS_EPOCH_MS6 + week * MS_PER_WEEK6 + towMs,
6796
+ timeMs: GPS_EPOCH_MS7 + week * MS_PER_WEEK6 + towMs,
6524
6797
  meas
6525
6798
  });
6526
6799
  }
@@ -6572,7 +6845,7 @@ function parseNovatelRange(data) {
6572
6845
  if (!codes.includes(code)) codes.push(code);
6573
6846
  }
6574
6847
  epochs.push({
6575
- timeMs: GPS_EPOCH_MS6 + week * MS_PER_WEEK6 + towMs,
6848
+ timeMs: GPS_EPOCH_MS7 + week * MS_PER_WEEK6 + towMs,
6576
6849
  meas
6577
6850
  });
6578
6851
  }
@@ -6931,10 +7204,10 @@ function selectBest(ephs, timeMs) {
6931
7204
  }
6932
7205
  return best;
6933
7206
  }
6934
- var GPS_EPOCH_MS7 = START_GPS_TIME.getTime();
7207
+ var GPS_EPOCH_MS8 = START_GPS_TIME.getTime();
6935
7208
  var MS_PER_WEEK7 = 7 * 864e5;
6936
7209
  var BDS_EPOCH_MS = START_BDS_TIME.getTime();
6937
- var GAL_EPOCH_MS = GPS_EPOCH_MS7 + 1024 * MS_PER_WEEK7;
7210
+ var GAL_EPOCH_MS = GPS_EPOCH_MS8 + 1024 * MS_PER_WEEK7;
6938
7211
  function ephInfoToEphemeris(info) {
6939
7212
  const sys = info.prn.charAt(0);
6940
7213
  if (sys === "R") {
@@ -6985,8 +7258,8 @@ function ephInfoToEphemeris(info) {
6985
7258
  } else if (sys === "E") {
6986
7259
  epochMs = GAL_EPOCH_MS;
6987
7260
  } else {
6988
- epochMs = GPS_EPOCH_MS7;
6989
- const weeksNow = (info.lastReceived - GPS_EPOCH_MS7) / MS_PER_WEEK7;
7261
+ epochMs = GPS_EPOCH_MS8;
7262
+ const weeksNow = (info.lastReceived - GPS_EPOCH_MS8) / MS_PER_WEEK7;
6990
7263
  week += 1024 * Math.round((weeksNow - week) / 1024);
6991
7264
  }
6992
7265
  const tocDate = new Date(epochMs + week * MS_PER_WEEK7 + tocSec * 1e3);
@@ -10088,12 +10361,14 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
10088
10361
  parseNovatelRange,
10089
10362
  parseRinexStream,
10090
10363
  parseSbfAlmanac,
10364
+ parseSbfCnav,
10091
10365
  parseSbfIonoUtc,
10092
10366
  parseSbfMeas,
10093
10367
  parseSbfNav,
10094
10368
  parseSinexBiasDcb,
10095
10369
  parseSourcetable,
10096
10370
  parseSp3,
10371
+ parseUbxCnav,
10097
10372
  parseUbxIonoUtc,
10098
10373
  parseUbxNav,
10099
10374
  parseUbxRawx,
package/dist/index.d.cts CHANGED
@@ -9,8 +9,8 @@ export { E as EpochSummary, P as ParseOptions, R as RinexHeader, a as RinexResul
9
9
  export { E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHeader, a as NavResult, p as parseNavFile } from './nav-BAI1a9vK.cjs';
10
10
  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';
11
11
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.cjs';
12
- export { UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawxEpoch, parseUbxIonoUtc, parseUbxNav, parseUbxRawx, ubxFrames } from './ubx.cjs';
13
- export { SbfAlmanac, SbfAlmanacResult, SbfGlonassAlmanac, SbfIonoUtcResult, SbfKeplerAlmanac, SbfMeasEpoch, SbfMeasurement, SbfNavResult, SbfParseResult, parseSbfAlmanac, parseSbfIonoUtc, parseSbfMeas, parseSbfNav, sbfCrc16, scanSbfFrames } from './sbf.cjs';
12
+ export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxRawx, ubxFrames } from './ubx.cjs';
13
+ export { SbfAlmanac, SbfAlmanacResult, SbfCnavEphemeris, SbfCnavResult, SbfGlonassAlmanac, SbfIonoUtcResult, SbfKeplerAlmanac, SbfMeasEpoch, SbfMeasurement, SbfNavResult, SbfParseResult, parseSbfAlmanac, parseSbfCnav, parseSbfIonoUtc, parseSbfMeas, parseSbfNav, sbfCrc16, scanSbfFrames } from './sbf.cjs';
14
14
  export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelRange } from './novatel.cjs';
15
15
  export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.cjs';
16
16
  export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.cjs';
@@ -20,3 +20,4 @@ export { CompleteSatSignal, CompleteSignalStats, CompletenessAccumulator, Comple
20
20
  export { AntennaEntry, AntexFile, FrequencyData, frequencyLabel, parseAntex } from './antex.cjs';
21
21
  export { NmeaFix, NmeaStats, NmeaTrack, computeStats, nmeaCoordToDecimal, parseNmeaFile, verifyChecksum } from './nmea.cjs';
22
22
  export { BAND_PRESETS, BandPreset, CONSTELLATIONS, ConstellationRow, DELTA_GLO_L1, DELTA_GLO_L2, FREQ_BDS_B1A, FREQ_BDS_B1C, FREQ_BDS_B1I, FREQ_BDS_B2I, FREQ_BDS_B3A, FREQ_BDS_B3I, FREQ_GAL_E1, FREQ_GAL_E5, FREQ_GAL_E5a, FREQ_GAL_E5b, FREQ_GAL_E6, FREQ_GLO_L1, FREQ_GLO_L1OC, FREQ_GLO_L2, FREQ_GLO_L2OC, FREQ_GLO_L3OC, FREQ_GPS_L1, FREQ_GPS_L2, FREQ_GPS_L5, FREQ_NAVIC_L5, FREQ_QZS_L1, FREQ_QZS_L2, FREQ_QZS_L5, FREQ_QZS_L6, Modulation, SignalDef, computePsdDb, phiAltBOC, phiBOCc, phiBOCs, phiBPSK } from './signals.cjs';
23
+ export { C as CnavEphemeris } from './cnav-CRns0ECn.cjs';
package/dist/index.d.ts CHANGED
@@ -9,8 +9,8 @@ export { E as EpochSummary, P as ParseOptions, R as RinexHeader, a as RinexResul
9
9
  export { E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHeader, a as NavResult, p as parseNavFile } from './nav-BAI1a9vK.js';
10
10
  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';
11
11
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.js';
12
- export { UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawxEpoch, parseUbxIonoUtc, parseUbxNav, parseUbxRawx, ubxFrames } from './ubx.js';
13
- export { SbfAlmanac, SbfAlmanacResult, SbfGlonassAlmanac, SbfIonoUtcResult, SbfKeplerAlmanac, SbfMeasEpoch, SbfMeasurement, SbfNavResult, SbfParseResult, parseSbfAlmanac, parseSbfIonoUtc, parseSbfMeas, parseSbfNav, sbfCrc16, scanSbfFrames } from './sbf.js';
12
+ export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxRawx, ubxFrames } from './ubx.js';
13
+ export { SbfAlmanac, SbfAlmanacResult, SbfCnavEphemeris, SbfCnavResult, SbfGlonassAlmanac, SbfIonoUtcResult, SbfKeplerAlmanac, SbfMeasEpoch, SbfMeasurement, SbfNavResult, SbfParseResult, parseSbfAlmanac, parseSbfCnav, parseSbfIonoUtc, parseSbfMeas, parseSbfNav, sbfCrc16, scanSbfFrames } from './sbf.js';
14
14
  export { NovatelEpoch, NovatelMeasurement, NovatelNavResult, NovatelParseResult, OEM4_HLEN, Oem4Frame, crc32, oem4Frames, parseNovatelNav, parseNovatelRange } from './novatel.js';
15
15
  export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.js';
16
16
  export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.js';
@@ -20,3 +20,4 @@ export { CompleteSatSignal, CompleteSignalStats, CompletenessAccumulator, Comple
20
20
  export { AntennaEntry, AntexFile, FrequencyData, frequencyLabel, parseAntex } from './antex.js';
21
21
  export { NmeaFix, NmeaStats, NmeaTrack, computeStats, nmeaCoordToDecimal, parseNmeaFile, verifyChecksum } from './nmea.js';
22
22
  export { BAND_PRESETS, BandPreset, CONSTELLATIONS, ConstellationRow, DELTA_GLO_L1, DELTA_GLO_L2, FREQ_BDS_B1A, FREQ_BDS_B1C, FREQ_BDS_B1I, FREQ_BDS_B2I, FREQ_BDS_B3A, FREQ_BDS_B3I, FREQ_GAL_E1, FREQ_GAL_E5, FREQ_GAL_E5a, FREQ_GAL_E5b, FREQ_GAL_E6, FREQ_GLO_L1, FREQ_GLO_L1OC, FREQ_GLO_L2, FREQ_GLO_L2OC, FREQ_GLO_L3OC, FREQ_GPS_L1, FREQ_GPS_L2, FREQ_GPS_L5, FREQ_NAVIC_L5, FREQ_QZS_L1, FREQ_QZS_L2, FREQ_QZS_L5, FREQ_QZS_L6, Modulation, SignalDef, computePsdDb, phiAltBOC, phiBOCc, phiBOCs, phiBPSK } from './signals.js';
23
+ export { C as CnavEphemeris } from './cnav-CRns0ECn.js';
package/dist/index.js CHANGED
@@ -34,27 +34,30 @@ import {
34
34
  phiBPSK
35
35
  } from "./chunk-2K3FCJBX.js";
36
36
  import {
37
+ parseUbxCnav,
37
38
  parseUbxIonoUtc,
38
39
  parseUbxNav,
39
40
  parseUbxRawx,
40
41
  ubxFrames
41
- } from "./chunk-IG5CDNDS.js";
42
+ } from "./chunk-FEGLXNWA.js";
42
43
  import {
43
44
  crc16,
44
45
  parseSbfAlmanac,
46
+ parseSbfCnav,
45
47
  parseSbfIonoUtc,
46
48
  parseSbfMeas,
47
49
  parseSbfNav,
48
50
  scanSbfFrames
49
- } from "./chunk-ZNCQNHNI.js";
51
+ } from "./chunk-CG7SF45F.js";
52
+ import "./chunk-Y5IWUPJQ.js";
50
53
  import {
51
54
  OEM4_HLEN,
52
55
  crc32,
53
56
  oem4Frames,
54
57
  parseNovatelNav,
55
58
  parseNovatelRange
56
- } from "./chunk-7QR2KPDU.js";
57
- import "./chunk-REYOYF7O.js";
59
+ } from "./chunk-2IM5VXNI.js";
60
+ import "./chunk-IQ5OIMQD.js";
58
61
  import {
59
62
  connectToMountpoint,
60
63
  fetchSourcetable,
@@ -489,12 +492,14 @@ export {
489
492
  parseNovatelRange,
490
493
  parseRinexStream,
491
494
  parseSbfAlmanac,
495
+ parseSbfCnav,
492
496
  parseSbfIonoUtc,
493
497
  parseSbfMeas,
494
498
  parseSbfNav,
495
499
  parseSinexBiasDcb,
496
500
  parseSourcetable,
497
501
  parseSp3,
502
+ parseUbxCnav,
498
503
  parseUbxIonoUtc,
499
504
  parseUbxNav,
500
505
  parseUbxRawx,
package/dist/novatel.cjs CHANGED
@@ -295,6 +295,7 @@ var ID_RAWEPHEM = 41;
295
295
  var ID_GLOEPHEMERIS = 723;
296
296
  var ID_GALEPHEMERIS = 1122;
297
297
  var ID_QZSSEPHEMERIS = 1336;
298
+ var ID_GPSEPHEM = 7;
298
299
  var ID_BDSEPHEMERIS = 1696;
299
300
  var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
300
301
  var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
@@ -449,9 +450,10 @@ function decodeBdsEphemeris(view, p) {
449
450
  // TGD1 (B1) — RINEX slot
450
451
  };
451
452
  }
452
- function decodeQzssEphemeris(view, p) {
453
+ function decodeGpsQzssEphemeris(view, p, sys) {
453
454
  const prn = view.getUint32(p, true);
454
- if (prn < 193 || prn > 202) return null;
455
+ if (sys === "G" && (prn < 1 || prn > 32)) return null;
456
+ if (sys === "J" && (prn < 193 || prn > 202)) return null;
455
457
  const health = view.getUint32(p + 12, true) & 63;
456
458
  const iode1 = view.getUint32(p + 16, true);
457
459
  const week = view.getUint32(p + 24, true);
@@ -460,8 +462,8 @@ function decodeQzssEphemeris(view, p) {
460
462
  const tocs = view.getFloat64(p + 164, true);
461
463
  const tocDate = new Date(nearWeekMs(toeMs, tocs));
462
464
  return {
463
- system: "J",
464
- prn: `J${String(prn - 192).padStart(2, "0")}`,
465
+ system: sys,
466
+ prn: `${sys}${String(sys === "J" ? prn - 192 : prn).padStart(2, "0")}`,
465
467
  toc: sowOf(tocDate.getTime()),
466
468
  tocDate,
467
469
  af0: view.getFloat64(p + 180, true),
@@ -519,8 +521,11 @@ function parseNovatelNav(data) {
519
521
  } else if (frame.id === ID_BDSEPHEMERIS && frame.msgLen >= 196) {
520
522
  const eph = decodeBdsEphemeris(view, frame.payload);
521
523
  if (eph) pushKepler(eph.prn, eph);
524
+ } else if (frame.id === ID_GPSEPHEM && frame.msgLen >= 204) {
525
+ const eph = decodeGpsQzssEphemeris(view, frame.payload, "G");
526
+ if (eph) pushKepler(eph.prn, eph);
522
527
  } else if (frame.id === ID_QZSSEPHEMERIS && frame.msgLen >= 204) {
523
- const eph = decodeQzssEphemeris(view, frame.payload);
528
+ const eph = decodeGpsQzssEphemeris(view, frame.payload, "J");
524
529
  if (eph) pushKepler(eph.prn, eph);
525
530
  } else if (frame.id === ID_IONUTC && frame.msgLen >= 108) {
526
531
  const p = frame.payload;
package/dist/novatel.js CHANGED
@@ -4,8 +4,8 @@ import {
4
4
  oem4Frames,
5
5
  parseNovatelNav,
6
6
  parseNovatelRange
7
- } from "./chunk-7QR2KPDU.js";
8
- import "./chunk-REYOYF7O.js";
7
+ } from "./chunk-2IM5VXNI.js";
8
+ import "./chunk-IQ5OIMQD.js";
9
9
  import "./chunk-HVXYFUCB.js";
10
10
  import "./chunk-LEEU5OIO.js";
11
11
  export {