gnss-js 1.18.0 → 1.20.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.
Files changed (43) hide show
  1. package/dist/{chunk-2IM5VXNI.js → chunk-7RKLWE6R.js} +23 -2
  2. package/dist/{chunk-QXZZNXE3.js → chunk-B5LU4746.js} +1 -1
  3. package/dist/{chunk-FEGLXNWA.js → chunk-DLXTTHRK.js} +2 -4
  4. package/dist/{chunk-OMVL3X7V.js → chunk-JNFV5BYB.js} +186 -8
  5. package/dist/{chunk-HXF7XVW7.js → chunk-NOQAAUGY.js} +297 -11
  6. package/dist/{chunk-CG7SF45F.js → chunk-VJEPOC76.js} +908 -14
  7. package/dist/{chunk-Y5IWUPJQ.js → chunk-WZDFZ76K.js} +151 -8
  8. package/dist/index.cjs +3283 -1908
  9. package/dist/index.d.cts +5 -5
  10. package/dist/index.d.ts +5 -5
  11. package/dist/index.js +25 -8
  12. package/dist/nav-BYmYoh9A.d.cts +137 -0
  13. package/dist/nav-CN8rxL4h.d.ts +137 -0
  14. package/dist/nav-DImXUdbp.d.cts +223 -0
  15. package/dist/nav-DImXUdbp.d.ts +223 -0
  16. package/dist/novatel.cjs +230 -15
  17. package/dist/novatel.d.cts +8 -1
  18. package/dist/novatel.d.ts +8 -1
  19. package/dist/novatel.js +2 -2
  20. package/dist/orbit.cjs +190 -8
  21. package/dist/orbit.d.cts +91 -2
  22. package/dist/orbit.d.ts +91 -2
  23. package/dist/orbit.js +9 -1
  24. package/dist/positioning.d.cts +2 -1
  25. package/dist/positioning.d.ts +2 -1
  26. package/dist/positioning.js +2 -2
  27. package/dist/rinex.cjs +304 -11
  28. package/dist/rinex.d.cts +45 -3
  29. package/dist/rinex.d.ts +45 -3
  30. package/dist/rinex.js +6 -1
  31. package/dist/sbf.cjs +908 -11
  32. package/dist/sbf.d.cts +114 -137
  33. package/dist/sbf.d.ts +114 -137
  34. package/dist/sbf.js +8 -3
  35. package/dist/ubx.d.cts +1 -2
  36. package/dist/ubx.d.ts +1 -2
  37. package/dist/ubx.js +2 -3
  38. package/package.json +1 -1
  39. package/dist/chunk-IQ5OIMQD.js +0 -148
  40. package/dist/cnav-CRns0ECn.d.cts +0 -96
  41. package/dist/cnav-CRns0ECn.d.ts +0 -96
  42. package/dist/nav-BAI1a9vK.d.cts +0 -108
  43. package/dist/nav-BAI1a9vK.d.ts +0 -108
package/dist/novatel.cjs CHANGED
@@ -202,6 +202,202 @@ function decodeGpsLnavFrame(subframes, opts = {}) {
202
202
  };
203
203
  }
204
204
 
205
+ // src/navbits/cnav.ts
206
+ var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
207
+ var SEC_PER_WEEK2 = 7 * 86400;
208
+ var HALF_WEEK = 302400;
209
+ var CNAV_PREAMBLE = 139;
210
+ var CNAV_A_REF = 26559710;
211
+ var CNAV_OMEGA_DOT_REF = -26e-10;
212
+ function crc24q(buff, bitLen) {
213
+ let crc = 0;
214
+ for (let i = 0; i < bitLen; i++) {
215
+ crc ^= (buff[i >> 3] >> 7 - (i & 7) & 1) << 23;
216
+ const msb = crc & 8388608;
217
+ crc = crc << 1 & 16777215;
218
+ if (msb) crc ^= 8801531;
219
+ }
220
+ return crc;
221
+ }
222
+ function cnavCrcOk(msg) {
223
+ if (msg.length < 38) return false;
224
+ return crc24q(msg, 276) === getBitU(msg, 276, 24);
225
+ }
226
+ function getBitU33(b, pos) {
227
+ return getBitU(b, pos, 1) * 2 ** 32 + getBitU(b, pos + 1, 32);
228
+ }
229
+ function getBitS33(b, pos) {
230
+ const u = getBitU33(b, pos);
231
+ return u < 2 ** 32 ? u : u - 2 ** 33;
232
+ }
233
+ function decodeType10(b, tow) {
234
+ return {
235
+ tow,
236
+ week: getBitU(b, 38, 13),
237
+ health: getBitU(b, 51, 3),
238
+ top: getBitU(b, 54, 11) * 300,
239
+ uraEd: getBitS(b, 65, 5),
240
+ toe: getBitU(b, 70, 11) * 300,
241
+ deltaA: getBitS(b, 81, 26) * 2 ** -9,
242
+ aDot: getBitS(b, 107, 25) * 2 ** -21,
243
+ deltaN0: getBitS(b, 132, 17) * 2 ** -44 * GPS_PI,
244
+ deltaN0Dot: getBitS(b, 149, 23) * 2 ** -57 * GPS_PI,
245
+ m0: getBitS33(b, 172) * 2 ** -32 * GPS_PI,
246
+ e: getBitU33(b, 205) * 2 ** -34,
247
+ omega: getBitS33(b, 238) * 2 ** -32 * GPS_PI,
248
+ integrityFlag: getBitU(b, 271, 1) === 1,
249
+ l2cPhasing: getBitU(b, 272, 1) === 1
250
+ };
251
+ }
252
+ function decodeType11(b) {
253
+ return {
254
+ toe: getBitU(b, 38, 11) * 300,
255
+ omega0: getBitS33(b, 49) * 2 ** -32 * GPS_PI,
256
+ i0: getBitS33(b, 82) * 2 ** -32 * GPS_PI,
257
+ deltaOmegaDot: getBitS(b, 115, 17) * 2 ** -44 * GPS_PI,
258
+ i0Dot: getBitS(b, 132, 15) * 2 ** -44 * GPS_PI,
259
+ cis: getBitS(b, 147, 16) * 2 ** -30,
260
+ cic: getBitS(b, 163, 16) * 2 ** -30,
261
+ crs: getBitS(b, 179, 24) * 2 ** -8,
262
+ crc: getBitS(b, 203, 24) * 2 ** -8,
263
+ cus: getBitS(b, 227, 21) * 2 ** -30,
264
+ cuc: getBitS(b, 248, 21) * 2 ** -30
265
+ };
266
+ }
267
+ var isc = (b, pos) => {
268
+ const raw = getBitS(b, pos, 13);
269
+ return raw === -4096 ? null : raw * 2 ** -35;
270
+ };
271
+ function decodeClock(b, msgType) {
272
+ const clock = {
273
+ msgType,
274
+ top: getBitU(b, 38, 11) * 300,
275
+ uraNed0: getBitS(b, 49, 5),
276
+ uraNed1: getBitU(b, 54, 3),
277
+ uraNed2: getBitU(b, 57, 3),
278
+ toc: getBitU(b, 60, 11) * 300,
279
+ af0: getBitS(b, 71, 26) * 2 ** -35,
280
+ af1: getBitS(b, 97, 20) * 2 ** -48,
281
+ af2: getBitS(b, 117, 10) * 2 ** -60
282
+ };
283
+ if (msgType === 30) {
284
+ clock.tgd = isc(b, 127);
285
+ clock.iscL1ca = isc(b, 140);
286
+ clock.iscL2c = isc(b, 153);
287
+ clock.iscL5i5 = isc(b, 166);
288
+ clock.iscL5q5 = isc(b, 179);
289
+ clock.ionoAlpha = [
290
+ getBitS(b, 192, 8) * 2 ** -30,
291
+ getBitS(b, 200, 8) * 2 ** -27,
292
+ getBitS(b, 208, 8) * 2 ** -24,
293
+ getBitS(b, 216, 8) * 2 ** -24
294
+ ];
295
+ clock.ionoBeta = [
296
+ getBitS(b, 224, 8) * 2 ** 11,
297
+ getBitS(b, 232, 8) * 2 ** 14,
298
+ getBitS(b, 240, 8) * 2 ** 16,
299
+ getBitS(b, 248, 8) * 2 ** 16
300
+ ];
301
+ clock.wnOp = getBitU(b, 256, 8);
302
+ }
303
+ return clock;
304
+ }
305
+ function resolveWeek(week, towSec, sec) {
306
+ if (sec < towSec - HALF_WEEK) return week + 1;
307
+ if (sec > towSec + HALF_WEEK) return week - 1;
308
+ return week;
309
+ }
310
+ function gpsDate(week, sec) {
311
+ return new Date(GPS_EPOCH_MS2 + (week * SEC_PER_WEEK2 + sec) * 1e3);
312
+ }
313
+ var CnavAssembler = class {
314
+ sats = /* @__PURE__ */ new Map();
315
+ /**
316
+ * Push one 300-bit CNAV message (38+ bytes, bit 0 = first bit of
317
+ * the preamble). Returns the newly completed ephemeris, or null.
318
+ * Messages that are not MT10/MT11/MT30-37, or whose preamble/PRN
319
+ * are out of range, are ignored.
320
+ */
321
+ push(msg) {
322
+ if (msg.length < 38 || getBitU(msg, 0, 8) !== CNAV_PREAMBLE) return null;
323
+ const prn = getBitU(msg, 8, 6);
324
+ if (prn < 1 || prn > 32) return null;
325
+ const type = getBitU(msg, 14, 6);
326
+ const tow = getBitU(msg, 20, 17) * 6;
327
+ let sat = this.sats.get(prn);
328
+ if (!sat) {
329
+ sat = {};
330
+ this.sats.set(prn, sat);
331
+ }
332
+ if (type === 10) sat.t10 = decodeType10(msg, tow);
333
+ else if (type === 11) sat.t11 = decodeType11(msg);
334
+ else if (type >= 30 && type <= 37) {
335
+ sat.clock = decodeClock(msg, type);
336
+ if (type === 30) sat.extras = sat.clock;
337
+ } else return null;
338
+ return this.tryEmit(prn, sat);
339
+ }
340
+ tryEmit(prn, sat) {
341
+ const { t10, t11, clock, extras } = sat;
342
+ if (!t10 || !t11 || !clock) return null;
343
+ if (t10.toe !== t11.toe || clock.toc !== t10.toe) return null;
344
+ const key = `${t10.week}:${t10.toe}:${clock.af0}:${clock.af1}`;
345
+ if (key === sat.lastKey) return null;
346
+ sat.lastKey = key;
347
+ const weekToe = resolveWeek(t10.week, t10.tow, t10.toe);
348
+ const a = CNAV_A_REF + t10.deltaA;
349
+ return {
350
+ system: "G",
351
+ prn: `G${String(prn).padStart(2, "0")}`,
352
+ week: t10.week,
353
+ health: t10.health,
354
+ uraEd: t10.uraEd,
355
+ uraNed0: clock.uraNed0,
356
+ uraNed1: clock.uraNed1,
357
+ uraNed2: clock.uraNed2,
358
+ top: t10.top,
359
+ toe: t10.toe,
360
+ toeDate: gpsDate(weekToe, t10.toe),
361
+ a,
362
+ deltaA: t10.deltaA,
363
+ aDot: t10.aDot,
364
+ deltaN0: t10.deltaN0,
365
+ deltaN0Dot: t10.deltaN0Dot,
366
+ m0: t10.m0,
367
+ e: t10.e,
368
+ omega: t10.omega,
369
+ omega0: t11.omega0,
370
+ i0: t11.i0,
371
+ omegaDot: CNAV_OMEGA_DOT_REF * GPS_PI + t11.deltaOmegaDot,
372
+ deltaOmegaDot: t11.deltaOmegaDot,
373
+ i0Dot: t11.i0Dot,
374
+ cis: t11.cis,
375
+ cic: t11.cic,
376
+ crs: t11.crs,
377
+ crc: t11.crc,
378
+ cus: t11.cus,
379
+ cuc: t11.cuc,
380
+ toc: clock.toc,
381
+ tocDate: gpsDate(weekToe, clock.toc),
382
+ af0: clock.af0,
383
+ af1: clock.af1,
384
+ af2: clock.af2,
385
+ clockMsgType: clock.msgType,
386
+ tgd: extras?.tgd ?? null,
387
+ iscL1ca: extras?.iscL1ca ?? null,
388
+ iscL2c: extras?.iscL2c ?? null,
389
+ iscL5i5: extras?.iscL5i5 ?? null,
390
+ iscL5q5: extras?.iscL5q5 ?? null,
391
+ ...extras?.ionoAlpha && { ionoAlpha: extras.ionoAlpha },
392
+ ...extras?.ionoBeta && { ionoBeta: extras.ionoBeta },
393
+ ...extras?.wnOp !== void 0 && { wnOp: extras.wnOp },
394
+ integrityFlag: t10.integrityFlag,
395
+ l2cPhasing: t10.l2cPhasing,
396
+ tow: t10.tow
397
+ };
398
+ }
399
+ };
400
+
205
401
  // src/constants/time.ts
206
402
  var MILLISECONDS_IN_SECOND = 1e3;
207
403
  var MILLISECONDS_GPS_TAI = 19e3;
@@ -291,21 +487,22 @@ function getUtcDate(date) {
291
487
 
292
488
  // src/novatel/nav.ts
293
489
  var ID_IONUTC = 8;
490
+ var ID_RAWCNAVFRAME = 1066;
294
491
  var ID_RAWEPHEM = 41;
295
492
  var ID_GLOEPHEMERIS = 723;
296
493
  var ID_GALEPHEMERIS = 1122;
297
494
  var ID_QZSSEPHEMERIS = 1336;
298
495
  var ID_GPSEPHEM = 7;
299
496
  var ID_BDSEPHEMERIS = 1696;
300
- var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
497
+ var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
301
498
  var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
302
- var SEC_PER_WEEK2 = 7 * 86400;
499
+ var SEC_PER_WEEK3 = 7 * 86400;
303
500
  var SEC_PER_DAY = 86400;
304
- var MS_PER_WEEK = SEC_PER_WEEK2 * 1e3;
305
- var gpsMs = (week, sec) => GPS_EPOCH_MS2 + week * MS_PER_WEEK + sec * 1e3;
306
- var sowOf = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK2;
501
+ var MS_PER_WEEK = SEC_PER_WEEK3 * 1e3;
502
+ var gpsMs = (week, sec) => GPS_EPOCH_MS3 + week * MS_PER_WEEK + sec * 1e3;
503
+ var sowOf = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK3;
307
504
  function nearWeekMs(refMs, sow) {
308
- const refWeek = Math.floor((refMs - GPS_EPOCH_MS2) / MS_PER_WEEK);
505
+ const refWeek = Math.floor((refMs - GPS_EPOCH_MS3) / MS_PER_WEEK);
309
506
  let ms = gpsMs(refWeek, sow);
310
507
  if (ms < refMs - MS_PER_WEEK / 2) ms += MS_PER_WEEK;
311
508
  else if (ms > refMs + MS_PER_WEEK / 2) ms -= MS_PER_WEEK;
@@ -332,9 +529,9 @@ function decodeGloEphemeris(view, p) {
332
529
  tof += Math.floor(tow / SEC_PER_DAY) * SEC_PER_DAY;
333
530
  if (tof < tow - 43200) tof += SEC_PER_DAY;
334
531
  else if (tof > tow + 43200) tof -= SEC_PER_DAY;
335
- const toeGpsMs = GPS_EPOCH_MS2 + (week * SEC_PER_WEEK2 + tow) * 1e3;
336
- const tofGpsMs = GPS_EPOCH_MS2 + (week * SEC_PER_WEEK2 + tof) * 1e3;
337
- const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS2) / 1e3;
532
+ const toeGpsMs = GPS_EPOCH_MS3 + (week * SEC_PER_WEEK3 + tow) * 1e3;
533
+ const tofGpsMs = GPS_EPOCH_MS3 + (week * SEC_PER_WEEK3 + tof) * 1e3;
534
+ const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS3) / 1e3;
338
535
  return {
339
536
  system: "R",
340
537
  prn: `R${String(slot).padStart(2, "0")}`,
@@ -342,7 +539,7 @@ function decodeGloEphemeris(view, p) {
342
539
  tauN: -view.getFloat64(p + 100, true),
343
540
  // RINEX stores −τ_n
344
541
  gammaN: view.getFloat64(p + 116, true),
345
- messageFrameTime: (tofUtcSec % SEC_PER_WEEK2 + SEC_PER_WEEK2) % SEC_PER_WEEK2,
542
+ messageFrameTime: (tofUtcSec % SEC_PER_WEEK3 + SEC_PER_WEEK3) % SEC_PER_WEEK3,
346
543
  x: view.getFloat64(p + 28, true) / 1e3,
347
544
  y: view.getFloat64(p + 36, true) / 1e3,
348
545
  z: view.getFloat64(p + 44, true) / 1e3,
@@ -399,7 +596,7 @@ function decodeGalEphemeris(view, p, headerMs) {
399
596
  omega: view.getFloat64(p + 60, true),
400
597
  omegaDot: view.getFloat64(p + 140, true),
401
598
  idot: view.getFloat64(p + 124, true),
402
- week: Math.floor((toeMs - GPS_EPOCH_MS2) / MS_PER_WEEK),
599
+ week: Math.floor((toeMs - GPS_EPOCH_MS3) / MS_PER_WEEK),
403
600
  // RINEX Galileo SVH bit layout (E1B DVS/HS in bits 0-2, E5a in
404
601
  // 3-5, E5b in 6-8) — same packing as RTKLIB.
405
602
  svHealth: svhE5b << 7 | dvsE5b << 6 | svhE5a << 4 | dvsE5a << 3 | svhE1b << 1 | dvsE1b,
@@ -497,6 +694,9 @@ function parseNovatelNav(data) {
497
694
  const ephemerides = [];
498
695
  const ionoCorrections = {};
499
696
  let leapSeconds = null;
697
+ const cnav = [];
698
+ const cnavAssembler = new CnavAssembler();
699
+ let cnavBadCrc = 0;
500
700
  const lastKep = /* @__PURE__ */ new Map();
501
701
  const lastGlo = /* @__PURE__ */ new Map();
502
702
  const pushKepler = (key, eph) => {
@@ -527,6 +727,14 @@ function parseNovatelNav(data) {
527
727
  } else if (frame.id === ID_QZSSEPHEMERIS && frame.msgLen >= 204) {
528
728
  const eph = decodeGpsQzssEphemeris(view, frame.payload, "J");
529
729
  if (eph) pushKepler(eph.prn, eph);
730
+ } else if (frame.id === ID_RAWCNAVFRAME && frame.msgLen >= 50) {
731
+ const msg = data.subarray(frame.payload + 12, frame.payload + 50);
732
+ if (!cnavCrcOk(msg)) {
733
+ cnavBadCrc++;
734
+ } else {
735
+ const eph = cnavAssembler.push(msg);
736
+ if (eph) cnav.push(eph);
737
+ }
530
738
  } else if (frame.id === ID_IONUTC && frame.msgLen >= 108) {
531
739
  const p = frame.payload;
532
740
  const alpha = [];
@@ -549,11 +757,18 @@ function parseNovatelNav(data) {
549
757
  ephemerides.push(eph);
550
758
  }
551
759
  }
552
- return { ephemerides, ionoCorrections, leapSeconds, badCrc: stats.badCrc };
760
+ return {
761
+ ephemerides,
762
+ ionoCorrections,
763
+ leapSeconds,
764
+ cnav,
765
+ cnavBadCrc,
766
+ badCrc: stats.badCrc
767
+ };
553
768
  }
554
769
 
555
770
  // src/novatel/index.ts
556
- var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
771
+ var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
557
772
  var MS_PER_WEEK2 = 7 * 864e5;
558
773
  var HDR = 28;
559
774
  var ID_RANGE = 43;
@@ -723,7 +938,7 @@ function parseNovatelRange(data) {
723
938
  if (!codes.includes(code)) codes.push(code);
724
939
  }
725
940
  epochs.push({
726
- timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK2 + towMs,
941
+ timeMs: GPS_EPOCH_MS4 + week * MS_PER_WEEK2 + towMs,
727
942
  meas
728
943
  });
729
944
  }
@@ -775,7 +990,7 @@ function parseNovatelRange(data) {
775
990
  if (!codes.includes(code)) codes.push(code);
776
991
  }
777
992
  epochs.push({
778
- timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK2 + towMs,
993
+ timeMs: GPS_EPOCH_MS4 + week * MS_PER_WEEK2 + towMs,
779
994
  meas
780
995
  });
781
996
  }
@@ -1,4 +1,4 @@
1
- import { E as Ephemeris } from './nav-BAI1a9vK.cjs';
1
+ import { E as Ephemeris, C as CnavEphemeris } from './nav-DImXUdbp.cjs';
2
2
 
3
3
  /**
4
4
  * NovAtel OEM4/6/7 binary framing shared by the measurement and
@@ -75,6 +75,13 @@ interface NovatelNavResult {
75
75
  ionoCorrections: Record<string, number[]>;
76
76
  /** GPS−UTC leap seconds (Δt_LS) from IONUTC, null when unseen. */
77
77
  leapSeconds: number | null;
78
+ /**
79
+ * GPS CNAV ephemerides assembled from RAWCNAVFRAME (1066) raw
80
+ * L2C/L5 messages, repeats suppressed by the shared assembler.
81
+ */
82
+ cnav: CnavEphemeris[];
83
+ /** RAWCNAVFRAME messages whose CRC-24Q check failed (dropped). */
84
+ cnavBadCrc: number;
78
85
  /** Frames whose CRC failed (corruption indicator). */
79
86
  badCrc: number;
80
87
  }
package/dist/novatel.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { E as Ephemeris } from './nav-BAI1a9vK.js';
1
+ import { E as Ephemeris, C as CnavEphemeris } from './nav-DImXUdbp.js';
2
2
 
3
3
  /**
4
4
  * NovAtel OEM4/6/7 binary framing shared by the measurement and
@@ -75,6 +75,13 @@ interface NovatelNavResult {
75
75
  ionoCorrections: Record<string, number[]>;
76
76
  /** GPS−UTC leap seconds (Δt_LS) from IONUTC, null when unseen. */
77
77
  leapSeconds: number | null;
78
+ /**
79
+ * GPS CNAV ephemerides assembled from RAWCNAVFRAME (1066) raw
80
+ * L2C/L5 messages, repeats suppressed by the shared assembler.
81
+ */
82
+ cnav: CnavEphemeris[];
83
+ /** RAWCNAVFRAME messages whose CRC-24Q check failed (dropped). */
84
+ cnavBadCrc: number;
78
85
  /** Frames whose CRC failed (corruption indicator). */
79
86
  badCrc: number;
80
87
  }
package/dist/novatel.js CHANGED
@@ -4,8 +4,8 @@ import {
4
4
  oem4Frames,
5
5
  parseNovatelNav,
6
6
  parseNovatelRange
7
- } from "./chunk-2IM5VXNI.js";
8
- import "./chunk-IQ5OIMQD.js";
7
+ } from "./chunk-7RKLWE6R.js";
8
+ import "./chunk-WZDFZ76K.js";
9
9
  import "./chunk-HVXYFUCB.js";
10
10
  import "./chunk-LEEU5OIO.js";
11
11
  export {
package/dist/orbit.cjs CHANGED
@@ -20,6 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/orbit/index.ts
21
21
  var orbit_exports = {};
22
22
  __export(orbit_exports, {
23
+ almanacEpochMs: () => almanacEpochMs,
24
+ almanacSatPosition: () => almanacSatPosition,
23
25
  computeAllPositions: () => computeAllPositions,
24
26
  computeDop: () => computeDop,
25
27
  computeLiveSkyPositions: () => computeLiveSkyPositions,
@@ -31,6 +33,8 @@ __export(orbit_exports, {
31
33
  ecefToGeodetic: () => ecefToGeodetic,
32
34
  ephInfoToEphemeris: () => ephInfoToEphemeris,
33
35
  geodeticToEcef: () => geodeticToEcef,
36
+ glonassAlmanacEpochMs: () => glonassAlmanacEpochMs,
37
+ glonassAlmanacPosition: () => glonassAlmanacPosition,
34
38
  glonassPosition: () => glonassPosition,
35
39
  keplerPosition: () => keplerPosition,
36
40
  maskRadForAzimuth: () => maskRadForAzimuth,
@@ -170,10 +174,184 @@ function getGpsLeap(date) {
170
174
  return leap_seconds - 19;
171
175
  }
172
176
 
173
- // src/orbit/index.ts
177
+ // src/orbit/almanac.ts
174
178
  var GM_GPS = 3986005e8;
175
179
  var GM_GAL = 3986004418e5;
176
180
  var GM_BDS = 3986004418e5;
181
+ var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
182
+ var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
183
+ var WEEK_MS = 6048e5;
184
+ var BDT_MINUS_GPST_MS = 14e3;
185
+ var BDS_GEO_PRNS = /* @__PURE__ */ new Set([1, 2, 3, 4, 5, 59, 60, 61, 62, 63]);
186
+ function almanacEpochMs(alm) {
187
+ if (alm.system === "C") {
188
+ return BDT_EPOCH_MS + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3 + BDT_MINUS_GPST_MS;
189
+ }
190
+ return GPS_EPOCH_MS + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3;
191
+ }
192
+ function almanacSatPosition(alm, timeMs) {
193
+ const GM = alm.system === "E" ? GM_GAL : alm.system === "C" ? GM_BDS : GM_GPS;
194
+ const a = alm.sqrtA * alm.sqrtA;
195
+ const n0 = Math.sqrt(GM / (a * a * a));
196
+ const tk = (timeMs - almanacEpochMs(alm)) / 1e3;
197
+ const Mk = alm.m0 + n0 * tk;
198
+ let Ek = Mk;
199
+ for (let i = 0; i < 12; i++) {
200
+ const dE = (Mk - (Ek - alm.e * Math.sin(Ek))) / (1 - alm.e * Math.cos(Ek));
201
+ Ek += dE;
202
+ if (Math.abs(dE) < 1e-12) break;
203
+ }
204
+ const sinE = Math.sin(Ek);
205
+ const cosE = Math.cos(Ek);
206
+ const vk = Math.atan2(Math.sqrt(1 - alm.e * alm.e) * sinE, cosE - alm.e);
207
+ const uk = vk + alm.omega;
208
+ const rk = a * (1 - alm.e * cosE);
209
+ const ik = alm.i0OrDeltaI;
210
+ const xp = rk * Math.cos(uk);
211
+ const yp = rk * Math.sin(uk);
212
+ const clockBias = alm.af0 + alm.af1 * tk;
213
+ const isGeo = alm.system === "C" && BDS_GEO_PRNS.has(Number(alm.prn.slice(1)));
214
+ if (isGeo) {
215
+ const omegak2 = alm.omega0 + alm.omegaDot * tk - OMEGA_E * alm.toaSec;
216
+ const cosO2 = Math.cos(omegak2);
217
+ const sinO2 = Math.sin(omegak2);
218
+ const cosI2 = Math.cos(ik);
219
+ const sinI2 = Math.sin(ik);
220
+ const xg = xp * cosO2 - yp * cosI2 * sinO2;
221
+ const yg = xp * sinO2 + yp * cosI2 * cosO2;
222
+ const zg = yp * sinI2;
223
+ const phi = OMEGA_E * tk;
224
+ const cosPhi = Math.cos(phi);
225
+ const sinPhi = Math.sin(phi);
226
+ const COS5 = Math.cos(-5 * Math.PI / 180);
227
+ const SIN5 = Math.sin(-5 * Math.PI / 180);
228
+ return {
229
+ prn: alm.prn,
230
+ x: xg * cosPhi + yg * sinPhi * COS5 + zg * sinPhi * SIN5,
231
+ y: -xg * sinPhi + yg * cosPhi * COS5 + zg * cosPhi * SIN5,
232
+ z: -yg * SIN5 + zg * COS5,
233
+ clockBias
234
+ };
235
+ }
236
+ const omegak = alm.omega0 + (alm.omegaDot - OMEGA_E) * tk - OMEGA_E * alm.toaSec;
237
+ const cosO = Math.cos(omegak);
238
+ const sinO = Math.sin(omegak);
239
+ const cosI = Math.cos(ik);
240
+ const sinI = Math.sin(ik);
241
+ return {
242
+ prn: alm.prn,
243
+ x: xp * cosO - yp * cosI * sinO,
244
+ y: xp * sinO + yp * cosI * cosO,
245
+ z: yp * sinI,
246
+ clockBias
247
+ };
248
+ }
249
+
250
+ // src/orbit/almanac-glo.ts
251
+ var C20 = -108263e-8;
252
+ var J = -1.5 * C20;
253
+ var AE = 6378.136;
254
+ var MU = 398600.44;
255
+ var OMEGA_Z = 7292115e-11;
256
+ var I_MEAN = 63 * Math.PI / 180;
257
+ var T_MEAN = 43200;
258
+ var GLO_1996_UTC_MS = Date.UTC(1996, 0, 1) - 108e5;
259
+ var DAY_MS = 864e5;
260
+ var FOUR_YEARS_DAYS = 1461;
261
+ function glonassAlmanacEpochMs(alm) {
262
+ const utcMs = GLO_1996_UTC_MS + ((alm.n4 - 1) * FOUR_YEARS_DAYS + (alm.nDay - 1)) * DAY_MS + alm.tLambda * 1e3;
263
+ return utcMs + getGpsLeap(new Date(utcMs)) * 1e3;
264
+ }
265
+ function c20Deltas(lam, tau, B, h, l, n, sinI, cosI) {
266
+ const sin2i = sinI * sinI;
267
+ const cos2i = cosI * cosI;
268
+ const s1 = Math.sin(lam);
269
+ const c1 = Math.cos(lam);
270
+ const s2 = Math.sin(2 * lam);
271
+ const c2 = Math.cos(2 * lam);
272
+ const s3 = Math.sin(3 * lam);
273
+ const c3 = Math.cos(3 * lam);
274
+ const s4 = Math.sin(4 * lam);
275
+ const c4 = Math.cos(4 * lam);
276
+ const daOverA = 2 * B * (1 - 1.5 * sin2i) * (l * c1 + h * s1) + B * sin2i * (0.5 * h * s1 - 0.5 * l * c1 + c2 + 3.5 * l * c3 + 3.5 * h * s3);
277
+ const dh = B * (1 - 1.5 * sin2i) * (l * n * tau + s1 + 1.5 * l * s2 - 1.5 * h * c2) - 0.25 * B * sin2i * (s1 - 7 / 3 * s3 + 5 * l * s2 - 8.5 * l * s4 + 8.5 * h * c4 + h * c2) + B * cos2i * (l * n * tau - 0.5 * l * s2);
278
+ const dl = B * (1 - 1.5 * sin2i) * (-h * n * tau + c1 + 1.5 * l * c2 + 1.5 * h * s2) - 0.25 * B * sin2i * (-c1 - 7 / 3 * c3 - 5 * h * s2 - 8.5 * l * c4 - 8.5 * h * s4 + l * c2) + B * cos2i * (-h * n * tau + 0.5 * h * s2);
279
+ const nodeBracket = n * tau + 3.5 * l * s1 - 2.5 * h * c1 - 0.5 * s2 - 7 / 6 * l * s3 + 7 / 6 * h * c3;
280
+ const dOmega = -B * cosI * nodeBracket;
281
+ const di = 0.5 * B * sinI * cosI * (-l * c1 + h * s1 + c2 + 7 / 3 * l * c3 + 7 / 3 * h * s3);
282
+ const dLambda = 2 * B * (1 - 1.5 * sin2i) * (n * tau + 1.75 * l * s1 - 1.75 * h * c1) + 3 * B * sin2i * (-(7 / 24) * h * c1 - 7 / 24 * l * s1 - 49 / 72 * h * c3 + 49 / 72 * l * s3 + 0.25 * s2) + B * cos2i * nodeBracket;
283
+ return { daOverA, dh, dl, dOmega, di, dLambda };
284
+ }
285
+ function glonassAlmanacPosition(alm, timeMs) {
286
+ const i = I_MEAN + alm.deltaI;
287
+ const sinI = Math.sin(i);
288
+ const cosI = Math.cos(i);
289
+ const sin2i = sinI * sinI;
290
+ const e = alm.epsilon;
291
+ const oneMinusE2 = 1 - e * e;
292
+ const Tdr = T_MEAN + alm.deltaT;
293
+ const n = 2 * Math.PI / Tdr;
294
+ const cosW = Math.cos(alm.omega);
295
+ let a = Math.cbrt((Tdr / (2 * Math.PI)) ** 2 * MU);
296
+ for (let k = 0; k < 10; k++) {
297
+ const p = a * oneMinusE2;
298
+ const tOsc = Tdr / (1 + 1.5 * C20 * (AE / p) ** 2 * ((2 - 2.5 * sin2i) * (Math.pow(oneMinusE2, 1.5) / (1 + e * cosW) ** 2) + (1 + e * cosW) ** 3 / oneMinusE2));
299
+ const aNext = Math.cbrt((tOsc / (2 * Math.PI)) ** 2 * MU);
300
+ const converged = Math.abs(aNext - a) < 1e-3;
301
+ a = aNext;
302
+ if (converged) break;
303
+ }
304
+ const tStar = (timeMs - glonassAlmanacEpochMs(alm)) / 1e3;
305
+ const W = Math.floor(tStar / Tdr);
306
+ const nodeShift = Tdr * W + alm.deltaTDot * W * W;
307
+ const omegaDot = 1.5 * C20 * n * (AE / a) ** 2 * cosI * oneMinusE2 ** -2;
308
+ const lambdaK = alm.lambda + (omegaDot - OMEGA_Z) * nodeShift;
309
+ const tau = tStar - nodeShift;
310
+ const h = e * Math.sin(alm.omega);
311
+ const l = e * cosW;
312
+ const E0 = 2 * Math.atan(Math.sqrt((1 - e) / (1 + e)) * Math.tan(-alm.omega / 2));
313
+ const M = E0 - e * Math.sin(E0);
314
+ const B = J * (AE / a) ** 2;
315
+ const d1 = c20Deltas(M + alm.omega, 0, B, h, l, n, sinI, cosI);
316
+ const d2 = c20Deltas(M + alm.omega + n * tau, tau, B, h, l, n, sinI, cosI);
317
+ const hi = h + (d2.dh - d1.dh);
318
+ const li = l + (d2.dl - d1.dl);
319
+ const epsI = Math.hypot(hi, li);
320
+ const omegaI = epsI === 0 ? 0 : Math.atan2(hi, li);
321
+ const aI = a + a * (d2.daOverA - d1.daOverA);
322
+ const iI = i + (d2.di - d1.di);
323
+ const omegaG = lambdaK + (d2.dOmega - d1.dOmega) - OMEGA_Z * tau;
324
+ const lambdaStar = M + alm.omega + n * tau + (d2.dLambda - d1.dLambda);
325
+ const Mi = lambdaStar - omegaI;
326
+ let E = Mi;
327
+ for (let k = 0; k < 30; k++) {
328
+ const next = Mi + epsI * Math.sin(E);
329
+ const converged = Math.abs(next - E) < 1e-12;
330
+ E = next;
331
+ if (converged) break;
332
+ }
333
+ const v = 2 * Math.atan(Math.sqrt((1 + epsI) / (1 - epsI)) * Math.tan(E / 2));
334
+ const u = v + omegaI;
335
+ const rKm = aI * (1 - epsI * Math.cos(E));
336
+ const cosU = Math.cos(u);
337
+ const sinU = Math.sin(u);
338
+ const cosO = Math.cos(omegaG);
339
+ const sinO = Math.sin(omegaG);
340
+ const cosIi = Math.cos(iI);
341
+ const sinIi = Math.sin(iI);
342
+ return {
343
+ prn: alm.prn,
344
+ x: 1e3 * rKm * (cosU * cosO - sinU * sinO * cosIi),
345
+ y: 1e3 * rKm * (cosU * sinO + sinU * cosO * cosIi),
346
+ z: 1e3 * rKm * sinU * sinIi,
347
+ clockBias: -alm.tau
348
+ };
349
+ }
350
+
351
+ // src/orbit/index.ts
352
+ var GM_GPS2 = 3986005e8;
353
+ var GM_GAL2 = 3986004418e5;
354
+ var GM_BDS2 = 3986004418e5;
177
355
  var GM_GLO = 39860044e7;
178
356
  var BDS_GEO_MAX_INCLINATION_RAD = 0.1;
179
357
  var BDS_GEO_MIN_SEMIMAJOR_AXIS_M = 4e7;
@@ -181,9 +359,9 @@ var AE_GLO = 6378136;
181
359
  var J2_GLO = 108263e-8;
182
360
  var TWO_PI = 2 * Math.PI;
183
361
  function gmForSystem(sys) {
184
- if (sys === "E") return GM_GAL;
185
- if (sys === "C") return GM_BDS;
186
- return GM_GPS;
362
+ if (sys === "E") return GM_GAL2;
363
+ if (sys === "C") return GM_BDS2;
364
+ return GM_GPS2;
187
365
  }
188
366
  var geoVelocityPass = false;
189
367
  function keplerPosition(eph, t) {
@@ -519,10 +697,10 @@ function selectBest(ephs, timeMs) {
519
697
  }
520
698
  return best;
521
699
  }
522
- var GPS_EPOCH_MS = START_GPS_TIME.getTime();
700
+ var GPS_EPOCH_MS2 = START_GPS_TIME.getTime();
523
701
  var MS_PER_WEEK = 7 * 864e5;
524
702
  var BDS_EPOCH_MS = START_BDS_TIME.getTime();
525
- var GAL_EPOCH_MS = GPS_EPOCH_MS + 1024 * MS_PER_WEEK;
703
+ var GAL_EPOCH_MS = GPS_EPOCH_MS2 + 1024 * MS_PER_WEEK;
526
704
  function ephInfoToEphemeris(info) {
527
705
  const sys = info.prn.charAt(0);
528
706
  if (sys === "R") {
@@ -573,8 +751,8 @@ function ephInfoToEphemeris(info) {
573
751
  } else if (sys === "E") {
574
752
  epochMs = GAL_EPOCH_MS;
575
753
  } else {
576
- epochMs = GPS_EPOCH_MS;
577
- const weeksNow = (info.lastReceived - GPS_EPOCH_MS) / MS_PER_WEEK;
754
+ epochMs = GPS_EPOCH_MS2;
755
+ const weeksNow = (info.lastReceived - GPS_EPOCH_MS2) / MS_PER_WEEK;
578
756
  week += 1024 * Math.round((weeksNow - week) / 1024);
579
757
  }
580
758
  const tocDate = new Date(epochMs + week * MS_PER_WEEK + tocSec * 1e3);
@@ -755,6 +933,8 @@ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
755
933
  }
756
934
  // Annotate the CommonJS export names for ESM import in node:
757
935
  0 && (module.exports = {
936
+ almanacEpochMs,
937
+ almanacSatPosition,
758
938
  computeAllPositions,
759
939
  computeDop,
760
940
  computeLiveSkyPositions,
@@ -766,6 +946,8 @@ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
766
946
  ecefToGeodetic,
767
947
  ephInfoToEphemeris,
768
948
  geodeticToEcef,
949
+ glonassAlmanacEpochMs,
950
+ glonassAlmanacPosition,
769
951
  glonassPosition,
770
952
  keplerPosition,
771
953
  maskRadForAzimuth,