gnss-js 1.29.0 → 1.30.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.
@@ -10,8 +10,9 @@ import {
10
10
  getEnuDifference
11
11
  } from "./chunk-37QNKGTC.js";
12
12
  import {
13
+ clkBias,
13
14
  sp3Position
14
- } from "./chunk-4KMWWCUR.js";
15
+ } from "./chunk-GPEP67TG.js";
15
16
  import {
16
17
  C_LIGHT,
17
18
  OMEGA_E
@@ -1582,7 +1583,7 @@ function sagnacRotate(x, y, z, travelS) {
1582
1583
  const s = Math.sin(theta);
1583
1584
  return [x * c + y * s, -x * s + y * c, z];
1584
1585
  }
1585
- function satStateAtEmission(sp3, prn, recvTimeMs, rcv) {
1586
+ function satStateAtEmission(sp3, prn, recvTimeMs, rcv, clk) {
1586
1587
  let travelS = 0.075;
1587
1588
  let sx = 0;
1588
1589
  let sy = 0;
@@ -1601,7 +1602,7 @@ function satStateAtEmission(sp3, prn, recvTimeMs, rcv) {
1601
1602
  const vz = (pPlus.z - pMinus.z) / 1;
1602
1603
  velDotPos = p.x * vx + p.y * vy + p.z * vz;
1603
1604
  }
1604
- clkS = p.clk;
1605
+ clkS = (clk && clkBias(clk, prn, tEmit)) ?? p.clk;
1605
1606
  const [rx, ry, rz] = sagnacRotate(p.x, p.y, p.z, travelS);
1606
1607
  sx = rx;
1607
1608
  sy = ry;
@@ -1715,7 +1716,7 @@ function solvePpp(epochs, sp3, opts) {
1715
1716
  for (const o of epoch.obs) {
1716
1717
  if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
1717
1718
  const slip = detectSlip(o, ei);
1718
- const sat = satStateAtEmission(sp3, o.prn, epoch.timeMs, rcv);
1719
+ const sat = satStateAtEmission(sp3, o.prn, epoch.timeMs, rcv, opts.clk);
1719
1720
  if (!sat) continue;
1720
1721
  const [elRad, azRad] = getAer(
1721
1722
  sat.state.x,
@@ -114,7 +114,69 @@ function sp3Position(sp3, prn, tMs, order = 9) {
114
114
  return { x, y, z, clk };
115
115
  }
116
116
 
117
+ // src/rinex/clk.ts
118
+ var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
119
+ function parseClk(text) {
120
+ const sats = {};
121
+ let inData = false;
122
+ for (const line of text.split("\n")) {
123
+ if (!inData) {
124
+ if (line.includes("END OF HEADER")) inData = true;
125
+ continue;
126
+ }
127
+ if (line.length < 3 || line[0] !== "A" || line[1] !== "S") continue;
128
+ const p = line.slice(2).trim().split(/\s+/);
129
+ if (p.length < 9) continue;
130
+ const prn = p[0];
131
+ const y = +p[1];
132
+ const mo = +p[2];
133
+ const d = +p[3];
134
+ const h = +p[4];
135
+ const mi = +p[5];
136
+ const s = +p[6];
137
+ const bias = +p[8];
138
+ if (!Number.isFinite(bias)) continue;
139
+ const t = Date.UTC(y, mo - 1, d, h, mi, Math.floor(s)) + s % 1 * 1e3;
140
+ let e = sats[prn];
141
+ if (!e) {
142
+ e = { t: [], c: [] };
143
+ sats[prn] = e;
144
+ }
145
+ e.t.push(t);
146
+ e.c.push(bias);
147
+ }
148
+ let intervalSec = 30;
149
+ for (const e of Object.values(sats)) {
150
+ if (e.t.length >= 2) {
151
+ intervalSec = Math.round((e.t[1] - e.t[0]) / 1e3);
152
+ break;
153
+ }
154
+ }
155
+ return { sats, intervalSec };
156
+ }
157
+ function clkBias(clk, prn, tMs) {
158
+ const e = clk.sats[prn];
159
+ if (!e || e.t.length === 0) return null;
160
+ const { t, c } = e;
161
+ let lo = 0;
162
+ let hi = t.length - 1;
163
+ if (tMs < t[0] || tMs > t[hi]) return null;
164
+ while (lo < hi) {
165
+ const mid = lo + hi + 1 >> 1;
166
+ if (t[mid] <= tMs) lo = mid;
167
+ else hi = mid - 1;
168
+ }
169
+ if (t[lo] === tMs || lo === t.length - 1) return c[lo];
170
+ const t0 = t[lo];
171
+ const t1 = t[lo + 1];
172
+ if (t1 - t0 > clk.intervalSec * 1e3 * 4) return null;
173
+ const f = (tMs - t0) / (t1 - t0);
174
+ return c[lo] + f * (c[lo + 1] - c[lo]);
175
+ }
176
+
117
177
  export {
118
178
  parseSp3,
119
- sp3Position
179
+ sp3Position,
180
+ parseClk,
181
+ clkBias
120
182
  };
@@ -67,4 +67,30 @@ declare function sp3Position(sp3: Sp3File, prn: string, tMs: number, order?: num
67
67
  clk: number | null;
68
68
  } | null;
69
69
 
70
- export { type IonexGrid as I, type Sp3File as S, type Sp3Sample as a, parseSp3 as b, parseIonex as p, sp3Position as s };
70
+ /**
71
+ * RINEX CLOCK (.CLK) parser — high-rate (typically 30 s) precise satellite
72
+ * clock corrections, the accuracy-limiting term for PPP that SP3's 5-minute
73
+ * (linearly interpolated) clocks cannot match.
74
+ *
75
+ * Only `AS` (satellite) records are kept; `AR` (station) records — the bulk
76
+ * of a combined file — are skipped. Clock bias is in seconds.
77
+ */
78
+ interface ClkFile {
79
+ /** prn → time-sorted samples { t: GPS-scale ms, c: clock bias (s) }. */
80
+ sats: Record<string, {
81
+ t: number[];
82
+ c: number[];
83
+ }>;
84
+ /** Nominal sampling interval (s), inferred from the first satellite. */
85
+ intervalSec: number;
86
+ }
87
+ /** Parse a RINEX CLOCK file. */
88
+ declare function parseClk(text: string): ClkFile;
89
+ /**
90
+ * Satellite clock bias (seconds) at an arbitrary time by linear
91
+ * interpolation between the bracketing samples. Returns null outside the
92
+ * span or across a gap larger than 4 sampling intervals.
93
+ */
94
+ declare function clkBias(clk: ClkFile, prn: string, tMs: number): number | null;
95
+
96
+ export { type ClkFile as C, type IonexGrid as I, type Sp3File as S, type Sp3Sample as a, parseIonex as b, clkBias as c, parseSp3 as d, parseClk as p, sp3Position as s };
@@ -67,4 +67,30 @@ declare function sp3Position(sp3: Sp3File, prn: string, tMs: number, order?: num
67
67
  clk: number | null;
68
68
  } | null;
69
69
 
70
- export { type IonexGrid as I, type Sp3File as S, type Sp3Sample as a, parseSp3 as b, parseIonex as p, sp3Position as s };
70
+ /**
71
+ * RINEX CLOCK (.CLK) parser — high-rate (typically 30 s) precise satellite
72
+ * clock corrections, the accuracy-limiting term for PPP that SP3's 5-minute
73
+ * (linearly interpolated) clocks cannot match.
74
+ *
75
+ * Only `AS` (satellite) records are kept; `AR` (station) records — the bulk
76
+ * of a combined file — are skipped. Clock bias is in seconds.
77
+ */
78
+ interface ClkFile {
79
+ /** prn → time-sorted samples { t: GPS-scale ms, c: clock bias (s) }. */
80
+ sats: Record<string, {
81
+ t: number[];
82
+ c: number[];
83
+ }>;
84
+ /** Nominal sampling interval (s), inferred from the first satellite. */
85
+ intervalSec: number;
86
+ }
87
+ /** Parse a RINEX CLOCK file. */
88
+ declare function parseClk(text: string): ClkFile;
89
+ /**
90
+ * Satellite clock bias (seconds) at an arbitrary time by linear
91
+ * interpolation between the bracketing samples. Returns null outside the
92
+ * span or across a gap larger than 4 sampling intervals.
93
+ */
94
+ declare function clkBias(clk: ClkFile, prn: string, tMs: number): number | null;
95
+
96
+ export { type ClkFile as C, type IonexGrid as I, type Sp3File as S, type Sp3Sample as a, parseIonex as b, clkBias as c, parseSp3 as d, parseClk as p, sp3Position as s };
package/dist/index.cjs CHANGED
@@ -119,6 +119,7 @@ __export(src_exports, {
119
119
  buildObsIndices: () => buildObsIndices,
120
120
  buildPppAntenna: () => buildPppAntenna,
121
121
  clampUnit: () => clampUnit,
122
+ clkBias: () => clkBias,
122
123
  computeAllPositions: () => computeAllPositions,
123
124
  computeDop: () => computeDop,
124
125
  computeIonoRate: () => computeIonoRate,
@@ -237,6 +238,7 @@ __export(src_exports, {
237
238
  padR: () => padR,
238
239
  parseAntex: () => parseAntex,
239
240
  parseBinex: () => parseBinex,
241
+ parseClk: () => parseClk,
240
242
  parseCrxDataLine: () => parseCrxDataLine,
241
243
  parseIonex: () => parseIonex,
242
244
  parseNavFile: () => parseNavFile,
@@ -3896,6 +3898,66 @@ function sp3Position(sp3, prn, tMs, order = 9) {
3896
3898
  return { x, y, z, clk };
3897
3899
  }
3898
3900
 
3901
+ // src/rinex/clk.ts
3902
+ var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
3903
+ function parseClk(text) {
3904
+ const sats = {};
3905
+ let inData = false;
3906
+ for (const line of text.split("\n")) {
3907
+ if (!inData) {
3908
+ if (line.includes("END OF HEADER")) inData = true;
3909
+ continue;
3910
+ }
3911
+ if (line.length < 3 || line[0] !== "A" || line[1] !== "S") continue;
3912
+ const p = line.slice(2).trim().split(/\s+/);
3913
+ if (p.length < 9) continue;
3914
+ const prn = p[0];
3915
+ const y = +p[1];
3916
+ const mo = +p[2];
3917
+ const d = +p[3];
3918
+ const h = +p[4];
3919
+ const mi = +p[5];
3920
+ const s = +p[6];
3921
+ const bias = +p[8];
3922
+ if (!Number.isFinite(bias)) continue;
3923
+ const t = Date.UTC(y, mo - 1, d, h, mi, Math.floor(s)) + s % 1 * 1e3;
3924
+ let e = sats[prn];
3925
+ if (!e) {
3926
+ e = { t: [], c: [] };
3927
+ sats[prn] = e;
3928
+ }
3929
+ e.t.push(t);
3930
+ e.c.push(bias);
3931
+ }
3932
+ let intervalSec = 30;
3933
+ for (const e of Object.values(sats)) {
3934
+ if (e.t.length >= 2) {
3935
+ intervalSec = Math.round((e.t[1] - e.t[0]) / 1e3);
3936
+ break;
3937
+ }
3938
+ }
3939
+ return { sats, intervalSec };
3940
+ }
3941
+ function clkBias(clk, prn, tMs) {
3942
+ const e = clk.sats[prn];
3943
+ if (!e || e.t.length === 0) return null;
3944
+ const { t, c } = e;
3945
+ let lo = 0;
3946
+ let hi = t.length - 1;
3947
+ if (tMs < t[0] || tMs > t[hi]) return null;
3948
+ while (lo < hi) {
3949
+ const mid = lo + hi + 1 >> 1;
3950
+ if (t[mid] <= tMs) lo = mid;
3951
+ else hi = mid - 1;
3952
+ }
3953
+ if (t[lo] === tMs || lo === t.length - 1) return c[lo];
3954
+ const t0 = t[lo];
3955
+ const t1 = t[lo + 1];
3956
+ if (t1 - t0 > clk.intervalSec * 1e3 * 4) return null;
3957
+ const f = (tMs - t0) / (t1 - t0);
3958
+ return c[lo] + f * (c[lo + 1] - c[lo]);
3959
+ }
3960
+
3899
3961
  // src/rinex/obs-writer-common.ts
3900
3962
  function createGzipLineSink() {
3901
3963
  const encoder = new TextEncoder();
@@ -6147,7 +6209,7 @@ var BdsAssembler = class {
6147
6209
  };
6148
6210
 
6149
6211
  // src/navbits/gal.ts
6150
- var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
6212
+ var GPS_EPOCH_MS5 = Date.UTC(1980, 0, 6);
6151
6213
  var SEC_PER_WEEK5 = 7 * 86400;
6152
6214
  var HALF_WEEK3 = 302400;
6153
6215
  var GST_GPS_WEEK_OFFSET = 1024;
@@ -6160,7 +6222,7 @@ function galFnavPageCrcOk(page) {
6160
6222
  return crc24q(page, 214) === getBitU(page, 214, 24);
6161
6223
  }
6162
6224
  function gpsDate2(week, sec) {
6163
- return new Date(GPS_EPOCH_MS4 + (week * SEC_PER_WEEK5 + sec) * 1e3);
6225
+ return new Date(GPS_EPOCH_MS5 + (week * SEC_PER_WEEK5 + sec) * 1e3);
6164
6226
  }
6165
6227
  function weekOfToe(week, tow, toe) {
6166
6228
  if (toe - tow > HALF_WEEK3) return week - 1;
@@ -6455,7 +6517,7 @@ var GalFnavAssembler = class {
6455
6517
  };
6456
6518
 
6457
6519
  // src/navbits/glo.ts
6458
- var GPS_EPOCH_MS5 = Date.UTC(1980, 0, 6);
6520
+ var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
6459
6521
  var SEC_PER_WEEK6 = 7 * 86400;
6460
6522
  var SEC_PER_DAY = 86400;
6461
6523
  var GLO_STRING_BYTES = 10;
@@ -6549,7 +6611,7 @@ function decodeGloStrings(strings, refDate, opts = {}) {
6549
6611
  const slot = getBitU(b, i, 5);
6550
6612
  if (frn1 !== 1 || frn2 !== 2 || frn3 !== 3 || frn4 !== 4) return null;
6551
6613
  if (slot < 1 || slot > 27) return null;
6552
- const utcSec = (getUtcDate(refDate).getTime() - GPS_EPOCH_MS5) / 1e3;
6614
+ const utcSec = (getUtcDate(refDate).getTime() - GPS_EPOCH_MS6) / 1e3;
6553
6615
  const week = Math.floor(utcSec / SEC_PER_WEEK6);
6554
6616
  let tow = utcSec - week * SEC_PER_WEEK6;
6555
6617
  const tod = tow % SEC_PER_DAY;
@@ -6564,7 +6626,7 @@ function decodeGloStrings(strings, refDate, opts = {}) {
6564
6626
  system: "R",
6565
6627
  prn: `R${String(slot).padStart(2, "0")}`,
6566
6628
  // RINEX GLONASS epochs are UTC: build the UTC toe Date directly.
6567
- tocDate: new Date(GPS_EPOCH_MS5 + (week * SEC_PER_WEEK6 + tow + toe) * 1e3),
6629
+ tocDate: new Date(GPS_EPOCH_MS6 + (week * SEC_PER_WEEK6 + tow + toe) * 1e3),
6568
6630
  tauN: -tauN,
6569
6631
  // RINEX stores −τn; the SIS carries τn (ICD sign)
6570
6632
  gammaN,
@@ -6618,7 +6680,7 @@ var GloStringAssembler = class {
6618
6680
  };
6619
6681
 
6620
6682
  // src/ubx/rawnav.ts
6621
- var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
6683
+ var GPS_EPOCH_MS7 = Date.UTC(1980, 0, 6);
6622
6684
  var SEC_PER_WEEK7 = 7 * 86400;
6623
6685
  var two2 = (n) => String(n).padStart(2, "0");
6624
6686
  function parseUbxRawNav(data, opts = {}) {
@@ -6638,7 +6700,7 @@ function parseUbxRawNav(data, opts = {}) {
6638
6700
  if (week === 0 && opts.refWeek !== void 0) week = opts.refWeek;
6639
6701
  if (week > 0) {
6640
6702
  refDate = new Date(
6641
- GPS_EPOCH_MS6 + (week * SEC_PER_WEEK7 + rcvTow) * 1e3
6703
+ GPS_EPOCH_MS7 + (week * SEC_PER_WEEK7 + rcvTow) * 1e3
6642
6704
  );
6643
6705
  }
6644
6706
  continue;
@@ -6718,7 +6780,7 @@ function parseUbxRawNav(data, opts = {}) {
6718
6780
  }
6719
6781
 
6720
6782
  // src/ubx/index.ts
6721
- var GPS_EPOCH_MS7 = Date.UTC(1980, 0, 6);
6783
+ var GPS_EPOCH_MS8 = Date.UTC(1980, 0, 6);
6722
6784
  var MS_PER_WEEK3 = 7 * 864e5;
6723
6785
  var SIGNALS = {
6724
6786
  0: { 0: ["G", "1C"], 3: ["G", "2X"], 4: ["G", "2X"] },
@@ -6801,7 +6863,7 @@ function parseUbxRawx(data) {
6801
6863
  if (!codes.includes(sig[1])) codes.push(sig[1]);
6802
6864
  }
6803
6865
  epochs.push({
6804
- timeMs: GPS_EPOCH_MS7 + week * MS_PER_WEEK3 + Math.round(rcvTow * 1e3),
6866
+ timeMs: GPS_EPOCH_MS8 + week * MS_PER_WEEK3 + Math.round(rcvTow * 1e3),
6805
6867
  leapS: leapValid ? leapS : null,
6806
6868
  meas
6807
6869
  });
@@ -6872,7 +6934,7 @@ function svidToPrn(svid) {
6872
6934
 
6873
6935
  // src/sbf/nav.ts
6874
6936
  var PI2 = Math.PI;
6875
- var GPS_EPOCH_MS8 = Date.UTC(1980, 0, 6);
6937
+ var GPS_EPOCH_MS9 = Date.UTC(1980, 0, 6);
6876
6938
  var BDT_EPOCH_MS2 = Date.UTC(2006, 0, 1);
6877
6939
  var SEC_PER_WEEK8 = 7 * 86400;
6878
6940
  var MS_PER_WEEK4 = SEC_PER_WEEK8 * 1e3;
@@ -6884,7 +6946,7 @@ function adjustWeek(refWeek, wn, mod) {
6884
6946
  if (offset < -(mod / 2 - 1)) offset += mod;
6885
6947
  return refWeek - offset;
6886
6948
  }
6887
- var gpsMs = (week, sec) => GPS_EPOCH_MS8 + week * MS_PER_WEEK4 + sec * 1e3;
6949
+ var gpsMs = (week, sec) => GPS_EPOCH_MS9 + week * MS_PER_WEEK4 + sec * 1e3;
6888
6950
  var sowOf2 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK8;
6889
6951
  function decodeGpsQzsNav(view, b, sys) {
6890
6952
  const svid = view.getUint8(b + 14);
@@ -7034,7 +7096,7 @@ function decodeGloNav(view, b) {
7034
7096
  const tocDate = new Date(toeGpsMs - leapMs);
7035
7097
  const tofGpsMs = gpsMs(wnc, 0) + view.getUint32(b + 8, true);
7036
7098
  const tofLeapMs = getGpsLeap(new Date(tofGpsMs)) * 1e3;
7037
- const messageFrameTime = (tofGpsMs - tofLeapMs - GPS_EPOCH_MS8) / 1e3 % SEC_PER_WEEK8;
7099
+ const messageFrameTime = (tofGpsMs - tofLeapMs - GPS_EPOCH_MS9) / 1e3 % SEC_PER_WEEK8;
7038
7100
  return {
7039
7101
  system: "R",
7040
7102
  prn,
@@ -7306,7 +7368,7 @@ function isFnavDummy(page) {
7306
7368
  }
7307
7369
 
7308
7370
  // src/sbf/rawnav-bds.ts
7309
- var GPS_EPOCH_MS9 = Date.UTC(1980, 0, 6);
7371
+ var GPS_EPOCH_MS10 = Date.UTC(1980, 0, 6);
7310
7372
  var MS_PER_WEEK5 = 7 * 86400 * 1e3;
7311
7373
  var TOW_DNU = 4294967295;
7312
7374
  var WNC_DNU = 65535;
@@ -7376,7 +7438,7 @@ function parseSbfGloNav(data) {
7376
7438
  const eph = assembler.push(
7377
7439
  prn,
7378
7440
  str,
7379
- new Date(GPS_EPOCH_MS9 + wnc * MS_PER_WEEK5 + towMs),
7441
+ new Date(GPS_EPOCH_MS10 + wnc * MS_PER_WEEK5 + towMs),
7380
7442
  view.getUint8(b + 18) - 8
7381
7443
  // FreqNr, offset by 8
7382
7444
  );
@@ -7910,7 +7972,7 @@ function parseSbfHas(data) {
7910
7972
 
7911
7973
  // src/sbf/index.ts
7912
7974
  var CLIGHT = 299792458;
7913
- var GPS_EPOCH_MS10 = Date.UTC(1980, 0, 6);
7975
+ var GPS_EPOCH_MS11 = Date.UTC(1980, 0, 6);
7914
7976
  var MS_PER_WEEK6 = 7 * 864e5;
7915
7977
  var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
7916
7978
  var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
@@ -8564,7 +8626,7 @@ function parseSbfMeas(data) {
8564
8626
  const tow = view.getUint32(i + 8, true);
8565
8627
  const wnc = view.getUint16(i + 12, true);
8566
8628
  if (tow !== 4294967295 && wnc !== 65535) {
8567
- ensureEpoch(GPS_EPOCH_MS10 + wnc * MS_PER_WEEK6 + tow);
8629
+ ensureEpoch(GPS_EPOCH_MS11 + wnc * MS_PER_WEEK6 + tow);
8568
8630
  if (id === 4109) decodeMeas3Ranges(i, tow);
8569
8631
  else if (id === 4110) decodeMeas3CN0(i, len);
8570
8632
  else if (id === 4111) decodeMeas3Doppler(i, len);
@@ -8629,15 +8691,15 @@ var ID_GALEPHEMERIS = 1122;
8629
8691
  var ID_QZSSEPHEMERIS = 1336;
8630
8692
  var ID_GPSEPHEM = 7;
8631
8693
  var ID_BDSEPHEMERIS = 1696;
8632
- var GPS_EPOCH_MS11 = Date.UTC(1980, 0, 6);
8694
+ var GPS_EPOCH_MS12 = Date.UTC(1980, 0, 6);
8633
8695
  var BDT_EPOCH_MS3 = Date.UTC(2006, 0, 1);
8634
8696
  var SEC_PER_WEEK9 = 7 * 86400;
8635
8697
  var SEC_PER_DAY2 = 86400;
8636
8698
  var MS_PER_WEEK7 = SEC_PER_WEEK9 * 1e3;
8637
- var gpsMs2 = (week, sec) => GPS_EPOCH_MS11 + week * MS_PER_WEEK7 + sec * 1e3;
8699
+ var gpsMs2 = (week, sec) => GPS_EPOCH_MS12 + week * MS_PER_WEEK7 + sec * 1e3;
8638
8700
  var sowOf3 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK9;
8639
8701
  function nearWeekMs(refMs, sow) {
8640
- const refWeek = Math.floor((refMs - GPS_EPOCH_MS11) / MS_PER_WEEK7);
8702
+ const refWeek = Math.floor((refMs - GPS_EPOCH_MS12) / MS_PER_WEEK7);
8641
8703
  let ms = gpsMs2(refWeek, sow);
8642
8704
  if (ms < refMs - MS_PER_WEEK7 / 2) ms += MS_PER_WEEK7;
8643
8705
  else if (ms > refMs + MS_PER_WEEK7 / 2) ms -= MS_PER_WEEK7;
@@ -8664,9 +8726,9 @@ function decodeGloEphemeris(view, p) {
8664
8726
  tof += Math.floor(tow / SEC_PER_DAY2) * SEC_PER_DAY2;
8665
8727
  if (tof < tow - 43200) tof += SEC_PER_DAY2;
8666
8728
  else if (tof > tow + 43200) tof -= SEC_PER_DAY2;
8667
- const toeGpsMs = GPS_EPOCH_MS11 + (week * SEC_PER_WEEK9 + tow) * 1e3;
8668
- const tofGpsMs = GPS_EPOCH_MS11 + (week * SEC_PER_WEEK9 + tof) * 1e3;
8669
- const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS11) / 1e3;
8729
+ const toeGpsMs = GPS_EPOCH_MS12 + (week * SEC_PER_WEEK9 + tow) * 1e3;
8730
+ const tofGpsMs = GPS_EPOCH_MS12 + (week * SEC_PER_WEEK9 + tof) * 1e3;
8731
+ const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS12) / 1e3;
8670
8732
  return {
8671
8733
  system: "R",
8672
8734
  prn: `R${String(slot).padStart(2, "0")}`,
@@ -8731,7 +8793,7 @@ function decodeGalEphemeris(view, p, headerMs) {
8731
8793
  omega: view.getFloat64(p + 60, true),
8732
8794
  omegaDot: view.getFloat64(p + 140, true),
8733
8795
  idot: view.getFloat64(p + 124, true),
8734
- week: Math.floor((toeMs - GPS_EPOCH_MS11) / MS_PER_WEEK7),
8796
+ week: Math.floor((toeMs - GPS_EPOCH_MS12) / MS_PER_WEEK7),
8735
8797
  // RINEX Galileo SVH bit layout (E1B DVS/HS in bits 0-2, E5a in
8736
8798
  // 3-5, E5b in 6-8) — same packing as RTKLIB.
8737
8799
  svHealth: svhE5b << 7 | dvsE5b << 6 | svhE5a << 4 | dvsE5a << 3 | svhE1b << 1 | dvsE1b,
@@ -8903,7 +8965,7 @@ function parseNovatelNav(data) {
8903
8965
  }
8904
8966
 
8905
8967
  // src/novatel/index.ts
8906
- var GPS_EPOCH_MS12 = Date.UTC(1980, 0, 6);
8968
+ var GPS_EPOCH_MS13 = Date.UTC(1980, 0, 6);
8907
8969
  var MS_PER_WEEK8 = 7 * 864e5;
8908
8970
  var HDR = 28;
8909
8971
  var ID_RANGE = 43;
@@ -9073,7 +9135,7 @@ function parseNovatelRange(data) {
9073
9135
  if (!codes.includes(code)) codes.push(code);
9074
9136
  }
9075
9137
  epochs.push({
9076
- timeMs: GPS_EPOCH_MS12 + week * MS_PER_WEEK8 + towMs,
9138
+ timeMs: GPS_EPOCH_MS13 + week * MS_PER_WEEK8 + towMs,
9077
9139
  meas
9078
9140
  });
9079
9141
  }
@@ -9125,7 +9187,7 @@ function parseNovatelRange(data) {
9125
9187
  if (!codes.includes(code)) codes.push(code);
9126
9188
  }
9127
9189
  epochs.push({
9128
- timeMs: GPS_EPOCH_MS12 + week * MS_PER_WEEK8 + towMs,
9190
+ timeMs: GPS_EPOCH_MS13 + week * MS_PER_WEEK8 + towMs,
9129
9191
  meas
9130
9192
  });
9131
9193
  }
@@ -9176,11 +9238,11 @@ function* trimbleFrames(data, stats) {
9176
9238
  }
9177
9239
 
9178
9240
  // src/trimble/nav.ts
9179
- var GPS_EPOCH_MS13 = Date.UTC(1980, 0, 6);
9241
+ var GPS_EPOCH_MS14 = Date.UTC(1980, 0, 6);
9180
9242
  var SEC_PER_WEEK10 = 7 * 86400;
9181
9243
  var MS_PER_WEEK9 = SEC_PER_WEEK10 * 1e3;
9182
9244
  var GPS_PI2 = 3.1415926535898;
9183
- var gpsMs3 = (week, sec) => GPS_EPOCH_MS13 + week * MS_PER_WEEK9 + sec * 1e3;
9245
+ var gpsMs3 = (week, sec) => GPS_EPOCH_MS14 + week * MS_PER_WEEK9 + sec * 1e3;
9184
9246
  var sowOf4 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK10;
9185
9247
  var SUB_GPS_EPHEMERIS = 1;
9186
9248
  var SUB_ION_UTC = 3;
@@ -9282,7 +9344,7 @@ function parseTrimbleNav(data) {
9282
9344
  }
9283
9345
 
9284
9346
  // src/trimble/index.ts
9285
- var GPS_EPOCH_MS14 = Date.UTC(1980, 0, 6);
9347
+ var GPS_EPOCH_MS15 = Date.UTC(1980, 0, 6);
9286
9348
  var MS_PER_WEEK10 = 7 * 864e5;
9287
9349
  var REC_TYPE_27 = 6;
9288
9350
  var SYS = {
@@ -9480,7 +9542,7 @@ function decodeEpoch(epoch, epochs, obsCodes) {
9480
9542
  o += c.length;
9481
9543
  }
9482
9544
  const dv = new DataView(M.buffer, M.byteOffset, M.byteLength);
9483
- const timeMs = GPS_EPOCH_MS14 + epoch.week * MS_PER_WEEK10 + epoch.towMs;
9545
+ const timeMs = GPS_EPOCH_MS15 + epoch.week * MS_PER_WEEK10 + epoch.towMs;
9484
9546
  const meas = [];
9485
9547
  let q = 0;
9486
9548
  for (let sv = 0; sv < epoch.nsv && q + 8 <= M.length; sv++) {
@@ -9661,13 +9723,13 @@ function* binexRecords(data, view, stats) {
9661
9723
  }
9662
9724
 
9663
9725
  // src/binex/nav.ts
9664
- var GPS_EPOCH_MS15 = Date.UTC(1980, 0, 6);
9726
+ var GPS_EPOCH_MS16 = Date.UTC(1980, 0, 6);
9665
9727
  var GLO_DAY0_MS = Date.UTC(1980, 0, 1);
9666
9728
  var BDT_EPOCH_MS4 = Date.UTC(2006, 0, 1);
9667
9729
  var SEC_PER_WEEK11 = 7 * 86400;
9668
9730
  var MS_PER_WEEK11 = SEC_PER_WEEK11 * 1e3;
9669
9731
  var SC2RAD = GPS_PI;
9670
- var gpsMs4 = (week, sec) => GPS_EPOCH_MS15 + week * MS_PER_WEEK11 + sec * 1e3;
9732
+ var gpsMs4 = (week, sec) => GPS_EPOCH_MS16 + week * MS_PER_WEEK11 + sec * 1e3;
9671
9733
  var sowOf5 = (dateMs) => (dateMs / 1e3 % SEC_PER_WEEK11 + SEC_PER_WEEK11) % SEC_PER_WEEK11;
9672
9734
  var two5 = (n) => String(n).padStart(2, "0");
9673
9735
  var Reader = class {
@@ -9955,7 +10017,7 @@ function decodeBinexEph(view, body, len, le) {
9955
10017
  }
9956
10018
 
9957
10019
  // src/binex/index.ts
9958
- var GPS_EPOCH_MS16 = Date.UTC(1980, 0, 6);
10020
+ var GPS_EPOCH_MS17 = Date.UTC(1980, 0, 6);
9959
10021
  var CLIGHT2 = 299792458;
9960
10022
  var OBS_CODES = {
9961
10023
  0: [
@@ -10213,7 +10275,7 @@ function decodeObsRecord(data, view, body, len, obsCodes) {
10213
10275
  p += 4;
10214
10276
  const msec = view.getUint16(p);
10215
10277
  p += 2;
10216
- const timeMs = GPS_EPOCH_MS16 + min * 6e4 + msec;
10278
+ const timeMs = GPS_EPOCH_MS17 + min * 6e4 + msec;
10217
10279
  const flag = data[p++];
10218
10280
  const nsat = (flag & 63) + 1;
10219
10281
  if (flag & 128) p += 3;
@@ -10299,7 +10361,7 @@ function parseBinex(data) {
10299
10361
  var GM_GPS = 3986005e8;
10300
10362
  var GM_GAL = 3986004418e5;
10301
10363
  var GM_BDS = 3986004418e5;
10302
- var GPS_EPOCH_MS17 = Date.UTC(1980, 0, 6);
10364
+ var GPS_EPOCH_MS18 = Date.UTC(1980, 0, 6);
10303
10365
  var BDT_EPOCH_MS5 = Date.UTC(2006, 0, 1);
10304
10366
  var WEEK_MS = 6048e5;
10305
10367
  var BDT_MINUS_GPST_MS = 14e3;
@@ -10308,7 +10370,7 @@ function almanacEpochMs(alm) {
10308
10370
  if (alm.system === "C") {
10309
10371
  return BDT_EPOCH_MS5 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3 + BDT_MINUS_GPST_MS;
10310
10372
  }
10311
- return GPS_EPOCH_MS17 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3;
10373
+ return GPS_EPOCH_MS18 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3;
10312
10374
  }
10313
10375
  function almanacSatPosition(alm, timeMs) {
10314
10376
  const GM = alm.system === "E" ? GM_GAL : alm.system === "C" ? GM_BDS : GM_GPS;
@@ -10817,10 +10879,10 @@ function selectBest(ephs, timeMs) {
10817
10879
  }
10818
10880
  return best;
10819
10881
  }
10820
- var GPS_EPOCH_MS18 = START_GPS_TIME.getTime();
10882
+ var GPS_EPOCH_MS19 = START_GPS_TIME.getTime();
10821
10883
  var MS_PER_WEEK12 = 7 * 864e5;
10822
10884
  var BDS_EPOCH_MS = START_BDS_TIME.getTime();
10823
- var GAL_EPOCH_MS = GPS_EPOCH_MS18 + 1024 * MS_PER_WEEK12;
10885
+ var GAL_EPOCH_MS = GPS_EPOCH_MS19 + 1024 * MS_PER_WEEK12;
10824
10886
  function ephInfoToEphemeris(info) {
10825
10887
  const sys = info.prn.charAt(0);
10826
10888
  if (sys === "R") {
@@ -10871,8 +10933,8 @@ function ephInfoToEphemeris(info) {
10871
10933
  } else if (sys === "E") {
10872
10934
  epochMs = GAL_EPOCH_MS;
10873
10935
  } else {
10874
- epochMs = GPS_EPOCH_MS18;
10875
- const weeksNow = (info.lastReceived - GPS_EPOCH_MS18) / MS_PER_WEEK12;
10936
+ epochMs = GPS_EPOCH_MS19;
10937
+ const weeksNow = (info.lastReceived - GPS_EPOCH_MS19) / MS_PER_WEEK12;
10876
10938
  week += 1024 * Math.round((weeksNow - week) / 1024);
10877
10939
  }
10878
10940
  const tocDate = new Date(epochMs + week * MS_PER_WEEK12 + tocSec * 1e3);
@@ -12834,7 +12896,7 @@ function sagnacRotate(x, y, z, travelS) {
12834
12896
  const s = Math.sin(theta);
12835
12897
  return [x * c + y * s, -x * s + y * c, z];
12836
12898
  }
12837
- function satStateAtEmission(sp3, prn, recvTimeMs, rcv) {
12899
+ function satStateAtEmission(sp3, prn, recvTimeMs, rcv, clk) {
12838
12900
  let travelS = 0.075;
12839
12901
  let sx = 0;
12840
12902
  let sy = 0;
@@ -12853,7 +12915,7 @@ function satStateAtEmission(sp3, prn, recvTimeMs, rcv) {
12853
12915
  const vz = (pPlus.z - pMinus.z) / 1;
12854
12916
  velDotPos = p.x * vx + p.y * vy + p.z * vz;
12855
12917
  }
12856
- clkS = p.clk;
12918
+ clkS = (clk && clkBias(clk, prn, tEmit)) ?? p.clk;
12857
12919
  const [rx, ry, rz] = sagnacRotate(p.x, p.y, p.z, travelS);
12858
12920
  sx = rx;
12859
12921
  sy = ry;
@@ -12967,7 +13029,7 @@ function solvePpp(epochs, sp3, opts) {
12967
13029
  for (const o of epoch.obs) {
12968
13030
  if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
12969
13031
  const slip = detectSlip(o, ei);
12970
- const sat = satStateAtEmission(sp3, o.prn, epoch.timeMs, rcv);
13032
+ const sat = satStateAtEmission(sp3, o.prn, epoch.timeMs, rcv, opts.clk);
12971
13033
  if (!sat) continue;
12972
13034
  const [elRad, azRad] = getAer(
12973
13035
  sat.state.x,
@@ -15749,6 +15811,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
15749
15811
  buildObsIndices,
15750
15812
  buildPppAntenna,
15751
15813
  clampUnit,
15814
+ clkBias,
15752
15815
  computeAllPositions,
15753
15816
  computeDop,
15754
15817
  computeIonoRate,
@@ -15867,6 +15930,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
15867
15930
  padR,
15868
15931
  parseAntex,
15869
15932
  parseBinex,
15933
+ parseClk,
15870
15934
  parseCrxDataLine,
15871
15935
  parseIonex,
15872
15936
  parseNavFile,
package/dist/index.d.cts CHANGED
@@ -7,7 +7,7 @@ export { c as clampUnit, e as ecefToGeodetic, g as geodeticToEcef, a as getAer,
7
7
  export { CompactEpoch, CrxField, DiffState, EMPTY_WARNINGS, Nav4Input, RinexWarning, RinexWarnings, WarningAccumulator, WarningSeverity, WriteCrxOptions, createGzipLineSink, crxDecompress, crxRepair, fmtD, fmtF, hdrLine, padL, padR, parseCrxDataLine, stationHeaderLines, writeCrx, writeModernObsBlob, writeRinex2ObsBlob, writeRinex4ObsBlob, writeRinexNav, writeRinexNav4, writeRinexObsBlob } from './rinex.cjs';
8
8
  export { E as EpochSummary, P as ParseOptions, R as RinexHeader, a as RinexResult, b as RinexStats, S as SYSTEM_ORDER, c as SatObsCallback, p as parseRinexStream, s as systemCmp, d as systemName } from './parser-JPjjFgeP.cjs';
9
9
  export { C as CnavEphemeris, E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHeader, a as NavResult, R as RinexCnavEphemeris, p as parseNavFile } from './nav-DImXUdbp.cjs';
10
- export { I as IonexGrid, S as Sp3File, a as Sp3Sample, p as parseIonex, b as parseSp3, s as sp3Position } from './sp3-BAq8l39b.cjs';
10
+ export { C as ClkFile, I as IonexGrid, S as Sp3File, a as Sp3Sample, c as clkBias, p as parseClk, b as parseIonex, d as parseSp3, s as sp3Position } from './clk-DGVBGRzA.cjs';
11
11
  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';
12
12
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.cjs';
13
13
  export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawNavOptions, UbxRawNavResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxRawNav, parseUbxRawx, ubxFrames } from './ubx.cjs';
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ export { c as clampUnit, e as ecefToGeodetic, g as geodeticToEcef, a as getAer,
7
7
  export { CompactEpoch, CrxField, DiffState, EMPTY_WARNINGS, Nav4Input, RinexWarning, RinexWarnings, WarningAccumulator, WarningSeverity, WriteCrxOptions, createGzipLineSink, crxDecompress, crxRepair, fmtD, fmtF, hdrLine, padL, padR, parseCrxDataLine, stationHeaderLines, writeCrx, writeModernObsBlob, writeRinex2ObsBlob, writeRinex4ObsBlob, writeRinexNav, writeRinexNav4, writeRinexObsBlob } from './rinex.js';
8
8
  export { E as EpochSummary, P as ParseOptions, R as RinexHeader, a as RinexResult, b as RinexStats, S as SYSTEM_ORDER, c as SatObsCallback, p as parseRinexStream, s as systemCmp, d as systemName } from './parser-JPjjFgeP.js';
9
9
  export { C as CnavEphemeris, E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHeader, a as NavResult, R as RinexCnavEphemeris, p as parseNavFile } from './nav-DImXUdbp.js';
10
- export { I as IonexGrid, S as Sp3File, a as Sp3Sample, p as parseIonex, b as parseSp3, s as sp3Position } from './sp3-BAq8l39b.js';
10
+ export { C as ClkFile, I as IonexGrid, S as Sp3File, a as Sp3Sample, c as clkBias, p as parseClk, b as parseIonex, d as parseSp3, s as sp3Position } from './clk-DGVBGRzA.js';
11
11
  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';
12
12
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.js';
13
13
  export { UbxCnavResult, UbxFrame, UbxIonoUtcResult, UbxMeasurement, UbxNavOptions, UbxNavResult, UbxParseResult, UbxRawNavOptions, UbxRawNavResult, UbxRawxEpoch, parseUbxCnav, parseUbxIonoUtc, parseUbxNav, parseUbxRawNav, parseUbxRawx, ubxFrames } from './ubx.js';
package/dist/index.js CHANGED
@@ -162,7 +162,7 @@ import {
162
162
  solveSpp,
163
163
  sunEcef,
164
164
  toRtkEpoch
165
- } from "./chunk-5WHKMKIB.js";
165
+ } from "./chunk-CRFFUU5Y.js";
166
166
  import {
167
167
  almanacEpochMs,
168
168
  almanacSatPosition,
@@ -217,7 +217,7 @@ import {
217
217
  writeRinexNav,
218
218
  writeRinexNav4,
219
219
  writeRinexObsBlob
220
- } from "./chunk-6GTS5MVI.js";
220
+ } from "./chunk-KDM2NVBO.js";
221
221
  import "./chunk-726LQBGM.js";
222
222
  import "./chunk-IQ5OIMQD.js";
223
223
  import {
@@ -230,9 +230,11 @@ import {
230
230
  systemName
231
231
  } from "./chunk-3U5AX7PY.js";
232
232
  import {
233
+ clkBias,
234
+ parseClk,
233
235
  parseSp3,
234
236
  sp3Position
235
- } from "./chunk-4KMWWCUR.js";
237
+ } from "./chunk-GPEP67TG.js";
236
238
  import {
237
239
  BitReader,
238
240
  RTCM3_MESSAGE_NAMES,
@@ -434,6 +436,7 @@ export {
434
436
  buildObsIndices,
435
437
  buildPppAntenna,
436
438
  clampUnit,
439
+ clkBias,
437
440
  computeAllPositions,
438
441
  computeDop,
439
442
  computeIonoRate,
@@ -552,6 +555,7 @@ export {
552
555
  padR,
553
556
  parseAntex,
554
557
  parseBinex,
558
+ parseClk,
555
559
  parseCrxDataLine,
556
560
  parseIonex,
557
561
  parseNavFile,
@@ -1597,6 +1597,28 @@ function sp3Position(sp3, prn, tMs, order = 9) {
1597
1597
  return { x, y, z, clk };
1598
1598
  }
1599
1599
 
1600
+ // src/rinex/clk.ts
1601
+ var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
1602
+ function clkBias(clk, prn, tMs) {
1603
+ const e = clk.sats[prn];
1604
+ if (!e || e.t.length === 0) return null;
1605
+ const { t, c } = e;
1606
+ let lo = 0;
1607
+ let hi = t.length - 1;
1608
+ if (tMs < t[0] || tMs > t[hi]) return null;
1609
+ while (lo < hi) {
1610
+ const mid = lo + hi + 1 >> 1;
1611
+ if (t[mid] <= tMs) lo = mid;
1612
+ else hi = mid - 1;
1613
+ }
1614
+ if (t[lo] === tMs || lo === t.length - 1) return c[lo];
1615
+ const t0 = t[lo];
1616
+ const t1 = t[lo + 1];
1617
+ if (t1 - t0 > clk.intervalSec * 1e3 * 4) return null;
1618
+ const f = (tMs - t0) / (t1 - t0);
1619
+ return c[lo] + f * (c[lo + 1] - c[lo]);
1620
+ }
1621
+
1600
1622
  // src/positioning/ppp-tropo.ts
1601
1623
  var HYD_AVG_A = [
1602
1624
  0.0012769934,
@@ -2080,7 +2102,7 @@ function sagnacRotate(x, y, z, travelS) {
2080
2102
  const s = Math.sin(theta);
2081
2103
  return [x * c + y * s, -x * s + y * c, z];
2082
2104
  }
2083
- function satStateAtEmission(sp3, prn, recvTimeMs, rcv) {
2105
+ function satStateAtEmission(sp3, prn, recvTimeMs, rcv, clk) {
2084
2106
  let travelS = 0.075;
2085
2107
  let sx = 0;
2086
2108
  let sy = 0;
@@ -2099,7 +2121,7 @@ function satStateAtEmission(sp3, prn, recvTimeMs, rcv) {
2099
2121
  const vz = (pPlus.z - pMinus.z) / 1;
2100
2122
  velDotPos = p.x * vx + p.y * vy + p.z * vz;
2101
2123
  }
2102
- clkS = p.clk;
2124
+ clkS = (clk && clkBias(clk, prn, tEmit)) ?? p.clk;
2103
2125
  const [rx, ry, rz] = sagnacRotate(p.x, p.y, p.z, travelS);
2104
2126
  sx = rx;
2105
2127
  sy = ry;
@@ -2213,7 +2235,7 @@ function solvePpp(epochs, sp3, opts) {
2213
2235
  for (const o of epoch.obs) {
2214
2236
  if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
2215
2237
  const slip = detectSlip(o, ei);
2216
- const sat = satStateAtEmission(sp3, o.prn, epoch.timeMs, rcv);
2238
+ const sat = satStateAtEmission(sp3, o.prn, epoch.timeMs, rcv, opts.clk);
2217
2239
  if (!sat) continue;
2218
2240
  const [elRad, azRad] = getAer(
2219
2241
  sat.state.x,
@@ -1,6 +1,6 @@
1
1
  import { E as Ephemeris } from './nav-DImXUdbp.cjs';
2
2
  import { DopValues } from './orbit.cjs';
3
- import { I as IonexGrid, S as Sp3File } from './sp3-BAq8l39b.cjs';
3
+ import { I as IonexGrid, C as ClkFile, S as Sp3File } from './clk-DGVBGRzA.cjs';
4
4
  import { AntexFile } from './antex.cjs';
5
5
  import './ephemeris-Ohl6NAfw.cjs';
6
6
  import './ecef-CF0uAysr.cjs';
@@ -631,6 +631,11 @@ interface PppOptions {
631
631
  ztdProcessNoise?: number;
632
632
  /** Model + estimate the troposphere. Default true. */
633
633
  troposphere?: boolean;
634
+ /** High-rate precise satellite clocks (RINEX CLOCK, typically 30 s). When
635
+ * given, satellite clock offsets come from this by linear interpolation
636
+ * instead of the SP3 5-minute clocks — the dominant PPP accuracy term.
637
+ * Satellites/epochs absent from the CLK fall back to the SP3 clock. */
638
+ clk?: ClkFile;
634
639
  }
635
640
  interface PppEpochResult {
636
641
  timeMs: number;
@@ -1,6 +1,6 @@
1
1
  import { E as Ephemeris } from './nav-DImXUdbp.js';
2
2
  import { DopValues } from './orbit.js';
3
- import { I as IonexGrid, S as Sp3File } from './sp3-BAq8l39b.js';
3
+ import { I as IonexGrid, C as ClkFile, S as Sp3File } from './clk-DGVBGRzA.js';
4
4
  import { AntexFile } from './antex.js';
5
5
  import './ephemeris-Ohl6NAfw.js';
6
6
  import './ecef-CF0uAysr.js';
@@ -631,6 +631,11 @@ interface PppOptions {
631
631
  ztdProcessNoise?: number;
632
632
  /** Model + estimate the troposphere. Default true. */
633
633
  troposphere?: boolean;
634
+ /** High-rate precise satellite clocks (RINEX CLOCK, typically 30 s). When
635
+ * given, satellite clock offsets come from this by linear interpolation
636
+ * instead of the SP3 5-minute clocks — the dominant PPP accuracy term.
637
+ * Satellites/epochs absent from the CLK fall back to the SP3 clock. */
638
+ clk?: ClkFile;
634
639
  }
635
640
  interface PppEpochResult {
636
641
  timeMs: number;
@@ -19,11 +19,11 @@ import {
19
19
  solveSpp,
20
20
  sunEcef,
21
21
  toRtkEpoch
22
- } from "./chunk-5WHKMKIB.js";
22
+ } from "./chunk-CRFFUU5Y.js";
23
23
  import "./chunk-MHGNKSSH.js";
24
24
  import "./chunk-37QNKGTC.js";
25
25
  import "./chunk-6FAL6P4G.js";
26
- import "./chunk-4KMWWCUR.js";
26
+ import "./chunk-GPEP67TG.js";
27
27
  import "./chunk-HVXYFUCB.js";
28
28
  import "./chunk-LEEU5OIO.js";
29
29
  import "./chunk-FIEWO4J4.js";
package/dist/rinex.cjs CHANGED
@@ -23,6 +23,7 @@ __export(rinex_exports, {
23
23
  EMPTY_WARNINGS: () => EMPTY_WARNINGS,
24
24
  SYSTEM_ORDER: () => SYSTEM_ORDER,
25
25
  WarningAccumulator: () => WarningAccumulator,
26
+ clkBias: () => clkBias,
26
27
  createGzipLineSink: () => createGzipLineSink,
27
28
  crxDecompress: () => crxDecompress,
28
29
  crxRepair: () => crxRepair,
@@ -31,6 +32,7 @@ __export(rinex_exports, {
31
32
  hdrLine: () => hdrLine,
32
33
  padL: () => padL,
33
34
  padR: () => padR,
35
+ parseClk: () => parseClk,
34
36
  parseCrxDataLine: () => parseCrxDataLine,
35
37
  parseIonex: () => parseIonex,
36
38
  parseNavFile: () => parseNavFile,
@@ -2388,6 +2390,66 @@ function sp3Position(sp3, prn, tMs, order = 9) {
2388
2390
  return { x, y, z, clk };
2389
2391
  }
2390
2392
 
2393
+ // src/rinex/clk.ts
2394
+ var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
2395
+ function parseClk(text) {
2396
+ const sats = {};
2397
+ let inData = false;
2398
+ for (const line of text.split("\n")) {
2399
+ if (!inData) {
2400
+ if (line.includes("END OF HEADER")) inData = true;
2401
+ continue;
2402
+ }
2403
+ if (line.length < 3 || line[0] !== "A" || line[1] !== "S") continue;
2404
+ const p = line.slice(2).trim().split(/\s+/);
2405
+ if (p.length < 9) continue;
2406
+ const prn = p[0];
2407
+ const y = +p[1];
2408
+ const mo = +p[2];
2409
+ const d = +p[3];
2410
+ const h = +p[4];
2411
+ const mi = +p[5];
2412
+ const s = +p[6];
2413
+ const bias = +p[8];
2414
+ if (!Number.isFinite(bias)) continue;
2415
+ const t = Date.UTC(y, mo - 1, d, h, mi, Math.floor(s)) + s % 1 * 1e3;
2416
+ let e = sats[prn];
2417
+ if (!e) {
2418
+ e = { t: [], c: [] };
2419
+ sats[prn] = e;
2420
+ }
2421
+ e.t.push(t);
2422
+ e.c.push(bias);
2423
+ }
2424
+ let intervalSec = 30;
2425
+ for (const e of Object.values(sats)) {
2426
+ if (e.t.length >= 2) {
2427
+ intervalSec = Math.round((e.t[1] - e.t[0]) / 1e3);
2428
+ break;
2429
+ }
2430
+ }
2431
+ return { sats, intervalSec };
2432
+ }
2433
+ function clkBias(clk, prn, tMs) {
2434
+ const e = clk.sats[prn];
2435
+ if (!e || e.t.length === 0) return null;
2436
+ const { t, c } = e;
2437
+ let lo = 0;
2438
+ let hi = t.length - 1;
2439
+ if (tMs < t[0] || tMs > t[hi]) return null;
2440
+ while (lo < hi) {
2441
+ const mid = lo + hi + 1 >> 1;
2442
+ if (t[mid] <= tMs) lo = mid;
2443
+ else hi = mid - 1;
2444
+ }
2445
+ if (t[lo] === tMs || lo === t.length - 1) return c[lo];
2446
+ const t0 = t[lo];
2447
+ const t1 = t[lo + 1];
2448
+ if (t1 - t0 > clk.intervalSec * 1e3 * 4) return null;
2449
+ const f = (tMs - t0) / (t1 - t0);
2450
+ return c[lo] + f * (c[lo + 1] - c[lo]);
2451
+ }
2452
+
2391
2453
  // src/rinex/obs-writer-common.ts
2392
2454
  function createGzipLineSink() {
2393
2455
  const encoder = new TextEncoder();
@@ -2766,6 +2828,7 @@ function writeRinex4ObsBlob(header, epochs, obsTypes) {
2766
2828
  EMPTY_WARNINGS,
2767
2829
  SYSTEM_ORDER,
2768
2830
  WarningAccumulator,
2831
+ clkBias,
2769
2832
  createGzipLineSink,
2770
2833
  crxDecompress,
2771
2834
  crxRepair,
@@ -2774,6 +2837,7 @@ function writeRinex4ObsBlob(header, epochs, obsTypes) {
2774
2837
  hdrLine,
2775
2838
  padL,
2776
2839
  padR,
2840
+ parseClk,
2777
2841
  parseCrxDataLine,
2778
2842
  parseIonex,
2779
2843
  parseNavFile,
package/dist/rinex.d.cts CHANGED
@@ -2,7 +2,7 @@ import { R as RinexHeader } from './parser-JPjjFgeP.cjs';
2
2
  export { E as EpochSummary, P as ParseOptions, a as RinexResult, b as RinexStats, S as SYSTEM_ORDER, c as SatObsCallback, p as parseRinexStream, s as systemCmp, d as systemName } from './parser-JPjjFgeP.cjs';
3
3
  import { a as NavResult, N as NavHeader, E as Ephemeris, R as RinexCnavEphemeris } from './nav-DImXUdbp.cjs';
4
4
  export { G as GlonassEphemeris, K as KeplerEphemeris, p as parseNavFile } from './nav-DImXUdbp.cjs';
5
- export { I as IonexGrid, S as Sp3File, a as Sp3Sample, p as parseIonex, b as parseSp3, s as sp3Position } from './sp3-BAq8l39b.cjs';
5
+ export { C as ClkFile, I as IonexGrid, S as Sp3File, a as Sp3Sample, c as clkBias, p as parseClk, b as parseIonex, d as parseSp3, s as sp3Position } from './clk-DGVBGRzA.cjs';
6
6
 
7
7
  /**
8
8
  * Compact RINEX (Hatanaka / CRX) decompression utilities.
package/dist/rinex.d.ts CHANGED
@@ -2,7 +2,7 @@ import { R as RinexHeader } from './parser-JPjjFgeP.js';
2
2
  export { E as EpochSummary, P as ParseOptions, a as RinexResult, b as RinexStats, S as SYSTEM_ORDER, c as SatObsCallback, p as parseRinexStream, s as systemCmp, d as systemName } from './parser-JPjjFgeP.js';
3
3
  import { a as NavResult, N as NavHeader, E as Ephemeris, R as RinexCnavEphemeris } from './nav-DImXUdbp.js';
4
4
  export { G as GlonassEphemeris, K as KeplerEphemeris, p as parseNavFile } from './nav-DImXUdbp.js';
5
- export { I as IonexGrid, S as Sp3File, a as Sp3Sample, p as parseIonex, b as parseSp3, s as sp3Position } from './sp3-BAq8l39b.js';
5
+ export { C as ClkFile, I as IonexGrid, S as Sp3File, a as Sp3Sample, c as clkBias, p as parseClk, b as parseIonex, d as parseSp3, s as sp3Position } from './clk-DGVBGRzA.js';
6
6
 
7
7
  /**
8
8
  * Compact RINEX (Hatanaka / CRX) decompression utilities.
package/dist/rinex.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  writeRinexNav,
18
18
  writeRinexNav4,
19
19
  writeRinexObsBlob
20
- } from "./chunk-6GTS5MVI.js";
20
+ } from "./chunk-KDM2NVBO.js";
21
21
  import "./chunk-726LQBGM.js";
22
22
  import "./chunk-IQ5OIMQD.js";
23
23
  import {
@@ -30,14 +30,17 @@ import {
30
30
  systemName
31
31
  } from "./chunk-3U5AX7PY.js";
32
32
  import {
33
+ clkBias,
34
+ parseClk,
33
35
  parseSp3,
34
36
  sp3Position
35
- } from "./chunk-4KMWWCUR.js";
37
+ } from "./chunk-GPEP67TG.js";
36
38
  import "./chunk-FIEWO4J4.js";
37
39
  export {
38
40
  EMPTY_WARNINGS,
39
41
  SYSTEM_ORDER,
40
42
  WarningAccumulator,
43
+ clkBias,
41
44
  createGzipLineSink,
42
45
  crxDecompress,
43
46
  crxRepair,
@@ -46,6 +49,7 @@ export {
46
49
  hdrLine,
47
50
  padL,
48
51
  padR,
52
+ parseClk,
49
53
  parseCrxDataLine,
50
54
  parseIonex,
51
55
  parseNavFile,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gnss-js",
3
- "version": "1.29.0",
3
+ "version": "1.30.0",
4
4
  "description": "Comprehensive GNSS library for JavaScript — time scales, coordinates, RINEX parsing, RTCM3 decoding, orbit computation, and signal analysis",
5
5
  "type": "module",
6
6
  "sideEffects": false,
File without changes