gnss-js 1.27.0 → 1.28.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
@@ -117,6 +117,7 @@ __export(src_exports, {
117
117
  binexRecords: () => binexRecords,
118
118
  buildGloChannelMap: () => buildGloChannelMap,
119
119
  buildObsIndices: () => buildObsIndices,
120
+ buildPppAntenna: () => buildPppAntenna,
120
121
  clampUnit: () => clampUnit,
121
122
  computeAllPositions: () => computeAllPositions,
122
123
  computeDop: () => computeDop,
@@ -130,6 +131,7 @@ __export(src_exports, {
130
131
  connectToMountpoint: () => connectToMountpoint,
131
132
  crc32: () => crc32,
132
133
  createGzipLineSink: () => createGzipLineSink,
134
+ createPppCorrections: () => createPppCorrections,
133
135
  createStationMeta: () => createStationMeta,
134
136
  createStreamStats: () => createStreamStats,
135
137
  crxDecompress: () => crxDecompress,
@@ -215,6 +217,7 @@ __export(src_exports, {
215
217
  glonassAlmanacEpochMs: () => glonassAlmanacEpochMs,
216
218
  glonassAlmanacPosition: () => glonassAlmanacPosition,
217
219
  glonassPosition: () => glonassPosition,
220
+ gmst: () => gmst,
218
221
  greatCircleMidpoint: () => greatCircleMidpoint,
219
222
  hdrLine: () => hdrLine,
220
223
  horizonDistance: () => horizonDistance,
@@ -224,8 +227,10 @@ __export(src_exports, {
224
227
  lambdaReduction: () => lambdaReduction,
225
228
  lambdaSearch: () => lambdaSearch,
226
229
  maskRadForAzimuth: () => maskRadForAzimuth,
230
+ moonEcef: () => moonEcef,
227
231
  msmEpochToDate: () => msmEpochToDate,
228
232
  navTimesFromEph: () => navTimesFromEph,
233
+ niellMapping: () => niellMapping,
229
234
  nmeaCoordToDecimal: () => nmeaCoordToDecimal,
230
235
  oem4Frames: () => oem4Frames,
231
236
  padL: () => padL,
@@ -275,10 +280,13 @@ __export(src_exports, {
275
280
  selectEphemeris: () => selectEphemeris,
276
281
  setGloFreqNumber: () => setGloFreqNumber,
277
282
  setRtcm3DebugHandler: () => setRtcm3DebugHandler,
283
+ solidEarthTide: () => solidEarthTide,
278
284
  solveDgnss: () => solveDgnss,
285
+ solvePpp: () => solvePpp,
279
286
  solveSpp: () => solveSpp,
280
287
  sp3Position: () => sp3Position,
281
288
  stationHeaderLines: () => stationHeaderLines,
289
+ sunEcef: () => sunEcef,
282
290
  systemCmp: () => systemCmp,
283
291
  systemName: () => systemName,
284
292
  toRtkEpoch: () => toRtkEpoch,
@@ -640,7 +648,7 @@ function getDayOfYear(date) {
640
648
  (date.getTime() - Date.UTC(date.getUTCFullYear())) / MILLISECONDS_IN_DAY
641
649
  ) + 1;
642
650
  }
643
- function getDateFromDayOfYear(dayOfYear, date) {
651
+ function getDateFromDayOfYear(dayOfYear2, date) {
644
652
  return new Date(
645
653
  Date.UTC(
646
654
  date.getUTCFullYear(),
@@ -650,7 +658,7 @@ function getDateFromDayOfYear(dayOfYear, date) {
650
658
  date.getUTCMinutes(),
651
659
  date.getUTCSeconds(),
652
660
  date.getUTCMilliseconds()
653
- ) + (dayOfYear - 1) * MILLISECONDS_IN_DAY
661
+ ) + (dayOfYear2 - 1) * MILLISECONDS_IN_DAY
654
662
  );
655
663
  }
656
664
  function getDayOfWeek(date) {
@@ -7623,14 +7631,14 @@ function parseOrbitBlock(c, masks) {
7623
7631
  const gnssIod = c.u(IOD_BITS[sys.system]);
7624
7632
  const rad = c.s(13);
7625
7633
  const inT = c.s(12);
7626
- const cross = c.s(12);
7634
+ const cross2 = c.s(12);
7627
7635
  corrections.push({
7628
7636
  system: sys.system,
7629
7637
  prn,
7630
7638
  gnssIod,
7631
7639
  deltaRadial: rad === -4096 ? null : rad * 25e-4,
7632
7640
  deltaInTrack: inT === -2048 ? null : inT * 8e-3,
7633
- deltaCrossTrack: cross === -2048 ? null : cross * 8e-3
7641
+ deltaCrossTrack: cross2 === -2048 ? null : cross2 * 8e-3
7634
7642
  });
7635
7643
  }
7636
7644
  }
@@ -10657,17 +10665,17 @@ function ecefToAzEl(rxX, rxY, rxZ, satX, satY, satZ) {
10657
10665
  function computeDop(satAzEls) {
10658
10666
  const n = satAzEls.length;
10659
10667
  if (n < 4) return null;
10660
- const H2 = [];
10668
+ const H3 = [];
10661
10669
  for (const { az, el } of satAzEls) {
10662
10670
  const cosEl = Math.cos(el);
10663
- H2.push([cosEl * Math.sin(az), cosEl * Math.cos(az), Math.sin(el), 1]);
10671
+ H3.push([cosEl * Math.sin(az), cosEl * Math.cos(az), Math.sin(el), 1]);
10664
10672
  }
10665
10673
  const HtH = Array.from({ length: 4 }, () => new Array(4).fill(0));
10666
10674
  for (let i = 0; i < 4; i++) {
10667
10675
  for (let j = 0; j < 4; j++) {
10668
10676
  let sum = 0;
10669
10677
  for (let k = 0; k < n; k++) {
10670
- sum += H2[k][i] * H2[k][j];
10678
+ sum += H3[k][i] * H3[k][j];
10671
10679
  }
10672
10680
  HtH[i][j] = sum;
10673
10681
  }
@@ -11794,7 +11802,7 @@ function solveDgnss(rover, base, basePos, ephemerides, timeMs, opts = {}) {
11794
11802
  let cov = null;
11795
11803
  for (let iter = 0; iter < maxIterations; iter++) {
11796
11804
  iterations = iter + 1;
11797
- const H2 = [];
11805
+ const H3 = [];
11798
11806
  const v = [];
11799
11807
  const terms = /* @__PURE__ */ new Map();
11800
11808
  const termOf = (g) => {
@@ -11810,11 +11818,11 @@ function solveDgnss(rover, base, basePos, ephemerides, timeMs, opts = {}) {
11810
11818
  const tr = termOf(row.ref);
11811
11819
  const pred = ts.rho - row.g.rhoB + ts.dTropo - (tr.rho - row.ref.rhoB + tr.dTropo);
11812
11820
  v.push(row.z - pred);
11813
- H2.push([ts.u[0] - tr.u[0], ts.u[1] - tr.u[1], ts.u[2] - tr.u[2]]);
11821
+ H3.push([ts.u[0] - tr.u[0], ts.u[1] - tr.u[1], ts.u[2] - tr.u[2]]);
11814
11822
  }
11815
- const Ht = transpose(H2);
11823
+ const Ht = transpose(H3);
11816
11824
  const HtW = matMul(Ht, W);
11817
- const N = matMul(HtW, H2);
11825
+ const N = matMul(HtW, H3);
11818
11826
  const b = matMul(
11819
11827
  HtW,
11820
11828
  v.map((s) => [s])
@@ -11830,7 +11838,7 @@ function solveDgnss(rover, base, basePos, ephemerides, timeMs, opts = {}) {
11830
11838
  z += dx[2][0];
11831
11839
  cov = Ninv;
11832
11840
  rows.forEach((row, i) => {
11833
- residuals[row.g.prn] = v[i] - (H2[i][0] * dx[0][0] + H2[i][1] * dx[1][0] + H2[i][2] * dx[2][0]);
11841
+ residuals[row.g.prn] = v[i] - (H3[i][0] * dx[0][0] + H3[i][1] * dx[1][0] + H3[i][2] * dx[2][0]);
11834
11842
  });
11835
11843
  if (Math.hypot(dx[0][0], dx[1][0], dx[2][0]) < convergenceM) {
11836
11844
  converged = true;
@@ -12222,19 +12230,19 @@ var RtkFloatEngine = class {
12222
12230
  const PPrior = this.P;
12223
12231
  let xi = [...this.x];
12224
12232
  let K = [];
12225
- let H2 = [];
12233
+ let H3 = [];
12226
12234
  for (let it = 0; it < Math.max(o.updateIterations, 1); it++) {
12227
- H2 = [];
12235
+ H3 = [];
12228
12236
  const v = [];
12229
12237
  for (const row of rows) {
12230
12238
  const { pred, h } = predict(row, xi);
12231
12239
  let corr = 0;
12232
12240
  for (let j = 0; j < n; j++) corr += h[j] * (xPrior[j] - xi[j]);
12233
12241
  v.push(row.z - pred - corr);
12234
- H2.push(h);
12242
+ H3.push(h);
12235
12243
  }
12236
- const Ht = transpose(H2);
12237
- const S = matMul(matMul(H2, PPrior), Ht);
12244
+ const Ht = transpose(H3);
12245
+ const S = matMul(matMul(H3, PPrior), Ht);
12238
12246
  for (let i = 0; i < rows.length; i++)
12239
12247
  for (let j = 0; j < rows.length; j++) S[i][j] += R[i][j];
12240
12248
  const Sinv = matInv(S);
@@ -12250,7 +12258,7 @@ var RtkFloatEngine = class {
12250
12258
  xi = xPrior.map((s, i) => s + dx[i][0]);
12251
12259
  }
12252
12260
  this.x = xi;
12253
- const KH = matMul(K, H2);
12261
+ const KH = matMul(K, H3);
12254
12262
  const IKH = zeros(n, n);
12255
12263
  for (let i = 0; i < n; i++)
12256
12264
  for (let j = 0; j < n; j++) IKH[i][j] = (i === j ? 1 : 0) - KH[i][j];
@@ -12343,6 +12351,800 @@ var RtkFloatEngine = class {
12343
12351
  }
12344
12352
  };
12345
12353
 
12354
+ // src/positioning/ppp-tropo.ts
12355
+ var HYD_AVG_A = [
12356
+ 0.0012769934,
12357
+ 1268323e-9,
12358
+ 0.0012465397,
12359
+ 0.0012196049,
12360
+ 0.0012045996
12361
+ ];
12362
+ var HYD_AVG_B = [
12363
+ 0.0029153695,
12364
+ 0.0029152299,
12365
+ 0.0029288445,
12366
+ 0.0029022565,
12367
+ 0.0029024912
12368
+ ];
12369
+ var HYD_AVG_C = [
12370
+ 0.062610505,
12371
+ 0.062837393,
12372
+ 0.063721774,
12373
+ 0.063824265,
12374
+ 0.064258455
12375
+ ];
12376
+ var HYD_AMP_A = [0, 12709626e-12, 26523662e-12, 34000452e-12, 41202191e-12];
12377
+ var HYD_AMP_B = [0, 21414979e-12, 30160779e-12, 72562722e-12, 11723375e-11];
12378
+ var HYD_AMP_C = [0, 901284e-10, 43497037e-12, 84795348e-11, 0.0017037206];
12379
+ var HT_A = 253e-7;
12380
+ var HT_B = 549e-5;
12381
+ var HT_C = 114e-5;
12382
+ var WET_A = [
12383
+ 58021897e-11,
12384
+ 56794847e-11,
12385
+ 58118019e-11,
12386
+ 59727542e-11,
12387
+ 61641693e-11
12388
+ ];
12389
+ var WET_B = [
12390
+ 0.0014275268,
12391
+ 0.0015138625,
12392
+ 0.0014572752,
12393
+ 0.0015007428,
12394
+ 0.0017599082
12395
+ ];
12396
+ var WET_C = [
12397
+ 0.043472961,
12398
+ 0.04672951,
12399
+ 0.043908931,
12400
+ 0.044626982,
12401
+ 0.054736038
12402
+ ];
12403
+ var LATS = [15, 30, 45, 60, 75];
12404
+ function interpLat(table, absLatDeg) {
12405
+ if (absLatDeg <= 15) return table[0];
12406
+ if (absLatDeg >= 75) return table[4];
12407
+ let i = 0;
12408
+ while (i < 4 && absLatDeg > LATS[i + 1]) i++;
12409
+ const t = (absLatDeg - LATS[i]) / (LATS[i + 1] - LATS[i]);
12410
+ return table[i] + t * (table[i + 1] - table[i]);
12411
+ }
12412
+ function marini(sinEl, a, b, c) {
12413
+ const num = 1 + a / (1 + b / (1 + c));
12414
+ const den = sinEl + a / (sinEl + b / (sinEl + c));
12415
+ return num / den;
12416
+ }
12417
+ function dayOfYear(timeMs) {
12418
+ const d = new Date(timeMs);
12419
+ const start = Date.UTC(d.getUTCFullYear(), 0, 1);
12420
+ return Math.floor((timeMs - start) / 864e5) + 1;
12421
+ }
12422
+ function niellMapping(elRad, latRad, heightM, timeMs) {
12423
+ const sinEl = Math.sin(Math.max(elRad, 1e-3));
12424
+ const absLat = Math.abs(latRad * 180 / Math.PI);
12425
+ const hKm = heightM / 1e3;
12426
+ let doy = dayOfYear(timeMs);
12427
+ if (latRad < 0) doy += 365.25 / 2;
12428
+ const yfrac = Math.cos(2 * Math.PI * (doy - 28) / 365.25);
12429
+ const ah = interpLat(HYD_AVG_A, absLat) - interpLat(HYD_AMP_A, absLat) * yfrac;
12430
+ const bh = interpLat(HYD_AVG_B, absLat) - interpLat(HYD_AMP_B, absLat) * yfrac;
12431
+ const ch = interpLat(HYD_AVG_C, absLat) - interpLat(HYD_AMP_C, absLat) * yfrac;
12432
+ const mHt = marini(sinEl, HT_A, HT_B, HT_C);
12433
+ const dmdh = 1 / sinEl - mHt;
12434
+ const mh = marini(sinEl, ah, bh, ch) + dmdh * hKm;
12435
+ const aw = interpLat(WET_A, absLat);
12436
+ const bw = interpLat(WET_B, absLat);
12437
+ const cw = interpLat(WET_C, absLat);
12438
+ const mw = marini(sinEl, aw, bw, cw);
12439
+ const h = heightM < 0 ? 0 : heightM > 1e4 ? 1e4 : heightM;
12440
+ const pres = 1013.25 * Math.pow(1 - 22557e-9 * h, 5.2568);
12441
+ const zhd = 22768e-7 * pres / (1 - 266e-5 * Math.cos(2 * latRad) - 28e-5 * (h / 1e3));
12442
+ return { zhd, mh, mw };
12443
+ }
12444
+
12445
+ // src/positioning/ppp-astro.ts
12446
+ var AU = 149597870700;
12447
+ var GPS_UTC_LEAP = 18;
12448
+ var J2000_MS = Date.UTC(2e3, 0, 1, 12, 0, 0);
12449
+ var DEG = Math.PI / 180;
12450
+ function daysSinceJ2000(timeMs) {
12451
+ return (timeMs - GPS_UTC_LEAP * 1e3 - J2000_MS) / 864e5;
12452
+ }
12453
+ function gmst(timeMs) {
12454
+ const d = daysSinceJ2000(timeMs);
12455
+ let deg = 280.46061837 + 360.98564736629 * d;
12456
+ deg %= 360;
12457
+ if (deg < 0) deg += 360;
12458
+ return deg * DEG;
12459
+ }
12460
+ function eciToEcef(v, theta) {
12461
+ const c = Math.cos(theta);
12462
+ const s = Math.sin(theta);
12463
+ return [v[0] * c + v[1] * s, -v[0] * s + v[1] * c, v[2]];
12464
+ }
12465
+ function sunEcef(timeMs) {
12466
+ const n = daysSinceJ2000(timeMs);
12467
+ const L = (280.46 + 0.9856474 * n) * DEG;
12468
+ const g = (357.528 + 0.9856003 * n) * DEG;
12469
+ const lambda = L + (1.915 * Math.sin(g) + 0.02 * Math.sin(2 * g)) * DEG;
12470
+ const eps = (23.439 - 4e-7 * n) * DEG;
12471
+ const R = (1.00014 - 0.01671 * Math.cos(g) - 14e-5 * Math.cos(2 * g)) * AU;
12472
+ const eci = [
12473
+ R * Math.cos(lambda),
12474
+ R * Math.cos(eps) * Math.sin(lambda),
12475
+ R * Math.sin(eps) * Math.sin(lambda)
12476
+ ];
12477
+ return eciToEcef(eci, gmst(timeMs));
12478
+ }
12479
+ function moonEcef(timeMs) {
12480
+ const T = daysSinceJ2000(timeMs) / 36525;
12481
+ const L0 = 218.31617 + 481267.88088 * T - 1.3972 * T;
12482
+ const l = 134.96292 + 477198.86753 * T;
12483
+ const lp = 357.52543 + 35999.04944 * T;
12484
+ const F = 93.27283 + 483202.01873 * T;
12485
+ const D = 297.85027 + 445267.11135 * T;
12486
+ const s = (x) => Math.sin(x * DEG);
12487
+ const c = (x) => Math.cos(x * DEG);
12488
+ const lon = L0 + 6.28875 * s(l) + 1.274018 * s(2 * D - l) + 0.658309 * s(2 * D) + 0.213616 * s(2 * l) - 0.185596 * s(lp) - 0.114336 * s(2 * F) + 0.058793 * s(2 * D - 2 * l) + 0.057212 * s(2 * D - lp - l) + 0.05332 * s(2 * D + l);
12489
+ const lat = 5.128189 * s(F) + 0.280606 * s(l + F) + 0.277693 * s(l - F) + 0.173238 * s(2 * D - F) + 0.055413 * s(2 * D + F - l) + 0.046272 * s(2 * D - F - l);
12490
+ const r = (385e3 - 20905 * c(l) - 3699 * c(2 * D - l) - 2956 * c(2 * D) - 570 * c(2 * l)) * 1e3;
12491
+ const eps = (23.4393 - 4e-7 * daysSinceJ2000(timeMs)) * DEG;
12492
+ const lonR = lon * DEG;
12493
+ const latR = lat * DEG;
12494
+ const xe = r * Math.cos(latR) * Math.cos(lonR);
12495
+ const ye = r * Math.cos(latR) * Math.sin(lonR);
12496
+ const ze = r * Math.sin(latR);
12497
+ const eci = [
12498
+ xe,
12499
+ ye * Math.cos(eps) - ze * Math.sin(eps),
12500
+ ye * Math.sin(eps) + ze * Math.cos(eps)
12501
+ ];
12502
+ return eciToEcef(eci, gmst(timeMs));
12503
+ }
12504
+ var H2 = 0.6078;
12505
+ var L2 = 0.0847;
12506
+ var RE = 6378137;
12507
+ var GM_SUN_RATIO = 332946.0482;
12508
+ var GM_MOON_RATIO = 0.0123000371;
12509
+ function solidEarthTide(rcv, sun, moon) {
12510
+ const rNorm = Math.hypot(rcv[0], rcv[1], rcv[2]);
12511
+ const rHat = [
12512
+ rcv[0] / rNorm,
12513
+ rcv[1] / rNorm,
12514
+ rcv[2] / rNorm
12515
+ ];
12516
+ const disp = [0, 0, 0];
12517
+ for (const [body, ratio] of [
12518
+ [sun, GM_SUN_RATIO],
12519
+ [moon, GM_MOON_RATIO]
12520
+ ]) {
12521
+ const rj = Math.hypot(body[0], body[1], body[2]);
12522
+ const jHat = [
12523
+ body[0] / rj,
12524
+ body[1] / rj,
12525
+ body[2] / rj
12526
+ ];
12527
+ const dot2 = rHat[0] * jHat[0] + rHat[1] * jHat[1] + rHat[2] * jHat[2];
12528
+ const factor = ratio * RE * RE * RE * RE / (rj * rj * rj);
12529
+ const radialScale = H2 * (1.5 * dot2 * dot2 - 0.5);
12530
+ const tanScale = 3 * L2 * dot2;
12531
+ for (let k = 0; k < 3; k++) {
12532
+ disp[k] += factor * (radialScale * rHat[k] + tanScale * (jHat[k] - dot2 * rHat[k]));
12533
+ }
12534
+ }
12535
+ return disp;
12536
+ }
12537
+
12538
+ // src/positioning/ppp-antenna.ts
12539
+ function parseAntexTime(s) {
12540
+ const p = s.trim().split(/\s+/).map(Number);
12541
+ if (p.length < 3 || p.some((v) => Number.isNaN(v))) return null;
12542
+ return Date.UTC(
12543
+ p[0],
12544
+ (p[1] || 1) - 1,
12545
+ p[2] || 1,
12546
+ p[3] ?? 0,
12547
+ p[4] ?? 0,
12548
+ Math.floor(p[5] ?? 0)
12549
+ );
12550
+ }
12551
+ function freqOf(entry, code) {
12552
+ return entry.frequencies.find((f) => f.frequency === code);
12553
+ }
12554
+ function combineIf(fA, fB, f1, f2) {
12555
+ const g = f1 * f1 / (f1 * f1 - f2 * f2);
12556
+ const mm = 1e-3;
12557
+ const pco = [
12558
+ (g * fA.pcoN - (g - 1) * fB.pcoN) * mm,
12559
+ (g * fA.pcoE - (g - 1) * fB.pcoE) * mm,
12560
+ (g * fA.pcoU - (g - 1) * fB.pcoU) * mm
12561
+ ];
12562
+ const nz = Math.min(fA.pcvNoazi.length, fB.pcvNoazi.length);
12563
+ const pcvNoazi = new Array(nz);
12564
+ for (let i = 0; i < nz; i++) {
12565
+ pcvNoazi[i] = (g * fA.pcvNoazi[i] - (g - 1) * fB.pcvNoazi[i]) * mm;
12566
+ }
12567
+ return { pco, pcvZen1Deg: 0, pcvDzenDeg: 0, pcvNoazi };
12568
+ }
12569
+ function buildPppAntenna(antex) {
12570
+ const sats = /* @__PURE__ */ new Map();
12571
+ const rcvs = /* @__PURE__ */ new Map();
12572
+ for (const a of antex.antennas) {
12573
+ if (a.isSatellite) {
12574
+ const list = sats.get(a.serialNo) ?? [];
12575
+ list.push(a);
12576
+ sats.set(a.serialNo, list);
12577
+ } else if (!rcvs.has(a.type)) {
12578
+ rcvs.set(a.type, a);
12579
+ }
12580
+ }
12581
+ const withZen = (entry, off) => ({
12582
+ ...off,
12583
+ pcvZen1Deg: entry.zen1,
12584
+ pcvDzenDeg: entry.dzen
12585
+ });
12586
+ return {
12587
+ satOffset(prn, dateMs, band1, band2, f1, f2) {
12588
+ const list = sats.get(prn);
12589
+ if (!list) return null;
12590
+ const entry = list.find((e) => {
12591
+ const from = parseAntexTime(e.validFrom);
12592
+ const until = parseAntexTime(e.validUntil);
12593
+ return (from == null || dateMs >= from) && (until == null || dateMs <= until);
12594
+ });
12595
+ if (!entry) return null;
12596
+ const a = freqOf(entry, band1);
12597
+ const b = freqOf(entry, band2);
12598
+ if (!a || !b) return null;
12599
+ return withZen(entry, combineIf(a, b, f1, f2));
12600
+ },
12601
+ rcvOffset(antType, band1, band2, f1, f2) {
12602
+ const entry = rcvs.get(antType);
12603
+ if (!entry) return null;
12604
+ const a = freqOf(entry, band1);
12605
+ const b = freqOf(entry, band2);
12606
+ if (!a || !b) return null;
12607
+ return withZen(entry, combineIf(a, b, f1, f2));
12608
+ }
12609
+ };
12610
+ }
12611
+ function cross(a, b) {
12612
+ return [
12613
+ a[1] * b[2] - a[2] * b[1],
12614
+ a[2] * b[0] - a[0] * b[2],
12615
+ a[0] * b[1] - a[1] * b[0]
12616
+ ];
12617
+ }
12618
+ function norm(a) {
12619
+ const n = Math.hypot(a[0], a[1], a[2]) || 1;
12620
+ return [a[0] / n, a[1] / n, a[2] / n];
12621
+ }
12622
+ function dot(a, b) {
12623
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
12624
+ }
12625
+ function satBodyFrame(satEcef, sunEcef2) {
12626
+ const z = norm([-satEcef[0], -satEcef[1], -satEcef[2]]);
12627
+ const eSun = norm([
12628
+ sunEcef2[0] - satEcef[0],
12629
+ sunEcef2[1] - satEcef[1],
12630
+ sunEcef2[2] - satEcef[2]
12631
+ ]);
12632
+ const y = norm(cross(z, eSun));
12633
+ const x = norm(cross(y, z));
12634
+ return { x, y, z };
12635
+ }
12636
+ function satPcoToEcef(pcoBody, frame) {
12637
+ return [
12638
+ pcoBody[0] * frame.x[0] + pcoBody[1] * frame.y[0] + pcoBody[2] * frame.z[0],
12639
+ pcoBody[0] * frame.x[1] + pcoBody[1] * frame.y[1] + pcoBody[2] * frame.z[1],
12640
+ pcoBody[0] * frame.x[2] + pcoBody[1] * frame.y[2] + pcoBody[2] * frame.z[2]
12641
+ ];
12642
+ }
12643
+ function enuToEcef(enu, latRad, lonRad) {
12644
+ const sl = Math.sin(latRad);
12645
+ const cl = Math.cos(latRad);
12646
+ const so = Math.sin(lonRad);
12647
+ const co = Math.cos(lonRad);
12648
+ const [e, n, u] = enu;
12649
+ return [
12650
+ -so * e - sl * co * n + cl * co * u,
12651
+ co * e - sl * so * n + cl * so * u,
12652
+ cl * n + sl * u
12653
+ ];
12654
+ }
12655
+ function interpPcv(off, angleDeg) {
12656
+ const { pcvZen1Deg, pcvDzenDeg, pcvNoazi } = off;
12657
+ if (pcvDzenDeg <= 0 || pcvNoazi.length < 2) return 0;
12658
+ const x = (angleDeg - pcvZen1Deg) / pcvDzenDeg;
12659
+ if (x <= 0) return pcvNoazi[0];
12660
+ if (x >= pcvNoazi.length - 1) return pcvNoazi[pcvNoazi.length - 1];
12661
+ const i = Math.floor(x);
12662
+ const t = x - i;
12663
+ return pcvNoazi[i] * (1 - t) + pcvNoazi[i + 1] * t;
12664
+ }
12665
+ function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
12666
+ const k = [
12667
+ -losRcvToSat[0],
12668
+ -losRcvToSat[1],
12669
+ -losRcvToSat[2]
12670
+ ];
12671
+ const kx = satFrame.x;
12672
+ const ky = satFrame.y;
12673
+ const kdotx = dot(k, kx);
12674
+ const kcrossY = cross(k, ky);
12675
+ const dS = [
12676
+ kx[0] - k[0] * kdotx - kcrossY[0],
12677
+ kx[1] - k[1] * kdotx - kcrossY[1],
12678
+ kx[2] - k[2] * kdotx - kcrossY[2]
12679
+ ];
12680
+ const north = enuToEcef([0, 1, 0], latRad, lonRad);
12681
+ const east = enuToEcef([1, 0, 0], latRad, lonRad);
12682
+ const kdotn = dot(k, north);
12683
+ const kcrossE = cross(k, east);
12684
+ const dR = [
12685
+ north[0] - k[0] * kdotn + kcrossE[0],
12686
+ north[1] - k[1] * kdotn + kcrossE[1],
12687
+ north[2] - k[2] * kdotn + kcrossE[2]
12688
+ ];
12689
+ const nS = Math.hypot(dS[0], dS[1], dS[2]) || 1;
12690
+ const nR = Math.hypot(dR[0], dR[1], dR[2]) || 1;
12691
+ let cosPhi = dot(dS, dR) / (nS * nR);
12692
+ cosPhi = Math.max(-1, Math.min(1, cosPhi));
12693
+ const zeta = cross(dS, dR);
12694
+ const sign = dot(k, zeta) >= 0 ? 1 : -1;
12695
+ const dphi = sign * Math.acos(cosPhi) / (2 * Math.PI);
12696
+ const prev = state.get(prn);
12697
+ const wu = prev == null ? dphi : dphi + Math.round(prev - dphi);
12698
+ state.set(prn, wu);
12699
+ return wu;
12700
+ }
12701
+
12702
+ // src/positioning/ppp-corrections.ts
12703
+ function applyCorrections(corrections, geom, ctx) {
12704
+ if (corrections.evaluate) return corrections.evaluate(geom, ctx);
12705
+ return { rangeM: 0, phaseWindupM: 0 };
12706
+ }
12707
+ function createPppCorrections(cfg) {
12708
+ const useSat = cfg.satPco ?? false;
12709
+ const useRcv = cfg.rcvPco ?? true;
12710
+ const useTides = cfg.tides ?? true;
12711
+ const useWindup = cfg.windup ?? true;
12712
+ const antDelta = cfg.antDeltaEnu ?? [0, 0, 0];
12713
+ const windupState = /* @__PURE__ */ new Map();
12714
+ return {
12715
+ epochContext(timeMs, rcvEcef) {
12716
+ const sun = sunEcef(timeMs);
12717
+ const moon = moonEcef(timeMs);
12718
+ const tideDisp = useTides ? solidEarthTide(rcvEcef, sun, moon) : [0, 0, 0];
12719
+ return { timeMs, sun, moon, tideDisp };
12720
+ },
12721
+ evaluate(geom, ctx) {
12722
+ let rangeM = 0;
12723
+ let phaseWindupM = 0;
12724
+ const e = geom.los;
12725
+ const [latDeg, lonDeg] = ecefToGeodetic(
12726
+ geom.rcvEcef[0],
12727
+ geom.rcvEcef[1],
12728
+ geom.rcvEcef[2]
12729
+ );
12730
+ const latRad = latDeg * Math.PI / 180;
12731
+ const lonRad = lonDeg * Math.PI / 180;
12732
+ const frame = ctx ? satBodyFrame(geom.satEcef, ctx.sun) : null;
12733
+ if (useSat && frame && geom.band1 && geom.band2) {
12734
+ const off = cfg.antenna.satOffset(
12735
+ geom.prn,
12736
+ ctx.timeMs,
12737
+ geom.band1,
12738
+ geom.band2,
12739
+ geom.f1,
12740
+ geom.f2
12741
+ );
12742
+ if (off) {
12743
+ const pcoEcef = satPcoToEcef(off.pco, frame);
12744
+ rangeM += dot(e, pcoEcef);
12745
+ const satR = Math.hypot(
12746
+ geom.satEcef[0],
12747
+ geom.satEcef[1],
12748
+ geom.satEcef[2]
12749
+ );
12750
+ const cosNadir = (e[0] * geom.satEcef[0] + e[1] * geom.satEcef[1] + e[2] * geom.satEcef[2]) / satR;
12751
+ const nadirDeg = Math.acos(Math.max(-1, Math.min(1, cosNadir))) * 180 / Math.PI;
12752
+ rangeM += interpPcv(off, nadirDeg);
12753
+ }
12754
+ }
12755
+ if (useRcv && geom.band1 && geom.band2) {
12756
+ const off = cfg.antenna.rcvOffset(
12757
+ cfg.rcvAntType,
12758
+ geom.band1,
12759
+ geom.band2,
12760
+ geom.f1,
12761
+ geom.f2
12762
+ );
12763
+ if (off) {
12764
+ const total = [
12765
+ off.pco[0] + antDelta[0],
12766
+ off.pco[1] + antDelta[1],
12767
+ off.pco[2] + antDelta[2]
12768
+ ];
12769
+ const ecef = enuToEcef(total, latRad, lonRad);
12770
+ rangeM -= dot(e, ecef);
12771
+ const zenithDeg = 90 - geom.elRad * 180 / Math.PI;
12772
+ rangeM += interpPcv(off, zenithDeg);
12773
+ }
12774
+ }
12775
+ if (useTides && ctx) {
12776
+ rangeM -= dot(e, ctx.tideDisp);
12777
+ }
12778
+ if (useWindup && frame) {
12779
+ const wu = phaseWindup(geom.prn, e, frame, latRad, lonRad, windupState);
12780
+ const lambdaIf = 299792458 / (geom.f1 + geom.f2);
12781
+ phaseWindupM = wu * lambdaIf;
12782
+ }
12783
+ return { rangeM, phaseWindupM };
12784
+ }
12785
+ };
12786
+ }
12787
+
12788
+ // src/positioning/ppp.ts
12789
+ function matVec(P, h) {
12790
+ const n = P.length;
12791
+ const out = new Array(n).fill(0);
12792
+ for (let i = 0; i < n; i++) {
12793
+ let s = 0;
12794
+ const Pi = P[i];
12795
+ for (let j = 0; j < n; j++) s += Pi[j] * h[j];
12796
+ out[i] = s;
12797
+ }
12798
+ return out;
12799
+ }
12800
+ function ekfUpdateScalar(x, P, h, innovation, r, rejectK = 0) {
12801
+ const n = x.length;
12802
+ const Ph = matVec(P, h);
12803
+ let hPh = 0;
12804
+ for (let i = 0; i < n; i++) hPh += h[i] * Ph[i];
12805
+ const s = hPh + r;
12806
+ if (s <= 0) return false;
12807
+ if (rejectK > 0 && innovation * innovation > rejectK * rejectK * s) {
12808
+ return false;
12809
+ }
12810
+ const K = Ph.map((v) => v / s);
12811
+ for (let i = 0; i < n; i++) x[i] += K[i] * innovation;
12812
+ for (let i = 0; i < n; i++) {
12813
+ for (let j = 0; j < n; j++) {
12814
+ P[i][j] -= K[i] * Ph[j];
12815
+ }
12816
+ }
12817
+ for (let i = 0; i < n; i++) {
12818
+ for (let j = i + 1; j < n; j++) {
12819
+ const m = 0.5 * (P[i][j] + P[j][i]);
12820
+ P[i][j] = m;
12821
+ P[j][i] = m;
12822
+ }
12823
+ }
12824
+ return true;
12825
+ }
12826
+ function ifCoeffs(f1, f2) {
12827
+ const g = f1 * f1 / (f1 * f1 - f2 * f2);
12828
+ const lambdaIf = C_LIGHT / (f1 + f2);
12829
+ return { g, lambdaIf };
12830
+ }
12831
+ function sagnacRotate(x, y, z, travelS) {
12832
+ const theta = OMEGA_E * travelS;
12833
+ const c = Math.cos(theta);
12834
+ const s = Math.sin(theta);
12835
+ return [x * c + y * s, -x * s + y * c, z];
12836
+ }
12837
+ function satStateAtEmission(sp3, prn, recvTimeMs, rcv) {
12838
+ let travelS = 0.075;
12839
+ let sx = 0;
12840
+ let sy = 0;
12841
+ let sz = 0;
12842
+ let clkS = null;
12843
+ let velDotPos = 0;
12844
+ for (let iter = 0; iter < 3; iter++) {
12845
+ const tEmit = recvTimeMs - travelS * 1e3;
12846
+ const p = sp3Position(sp3, prn, tEmit);
12847
+ if (!p || p.clk == null) return null;
12848
+ const pPlus = sp3Position(sp3, prn, tEmit + 500);
12849
+ const pMinus = sp3Position(sp3, prn, tEmit - 500);
12850
+ if (pPlus && pMinus) {
12851
+ const vx = (pPlus.x - pMinus.x) / 1;
12852
+ const vy = (pPlus.y - pMinus.y) / 1;
12853
+ const vz = (pPlus.z - pMinus.z) / 1;
12854
+ velDotPos = p.x * vx + p.y * vy + p.z * vz;
12855
+ }
12856
+ clkS = p.clk;
12857
+ const [rx, ry, rz] = sagnacRotate(p.x, p.y, p.z, travelS);
12858
+ sx = rx;
12859
+ sy = ry;
12860
+ sz = rz;
12861
+ const dx = sx - rcv[0];
12862
+ const dy = sy - rcv[1];
12863
+ const dz = sz - rcv[2];
12864
+ const range = Math.hypot(dx, dy, dz);
12865
+ travelS = range / C_LIGHT;
12866
+ }
12867
+ if (clkS == null) return null;
12868
+ const relS = -2 * velDotPos / (C_LIGHT * C_LIGHT);
12869
+ const clkM = C_LIGHT * (clkS + relS);
12870
+ return { state: { x: sx, y: sy, z: sz, clkM }, travelS };
12871
+ }
12872
+ var IDX_X = 0;
12873
+ var IDX_Y = 1;
12874
+ var IDX_Z = 2;
12875
+ var IDX_CLK = 3;
12876
+ var IDX_ZWD = 4;
12877
+ var NBASE = 5;
12878
+ function solvePpp(epochs, sp3, opts) {
12879
+ const elevMask = (opts.elevationMaskDeg ?? 10) * Math.PI / 180;
12880
+ const codeSigma = opts.codeSigma ?? 3;
12881
+ const phaseSigma = opts.phaseSigma ?? 0.01;
12882
+ const ztdQ = opts.ztdProcessNoise ?? 1e-8;
12883
+ const corrections = opts.corrections;
12884
+ const x = [
12885
+ opts.aprioriPos[0],
12886
+ opts.aprioriPos[1],
12887
+ opts.aprioriPos[2],
12888
+ 0,
12889
+ // receiver clock (m)
12890
+ 0.1
12891
+ // zenith wet delay (m) a priori
12892
+ ];
12893
+ const P = [];
12894
+ for (let i = 0; i < NBASE; i++) {
12895
+ P.push(new Array(NBASE).fill(0));
12896
+ }
12897
+ P[IDX_X][IDX_X] = 100 * 100;
12898
+ P[IDX_Y][IDX_Y] = 100 * 100;
12899
+ P[IDX_Z][IDX_Z] = 100 * 100;
12900
+ P[IDX_CLK][IDX_CLK] = 1e10;
12901
+ P[IDX_ZWD][IDX_ZWD] = 0.5 * 0.5;
12902
+ const ambIdx = /* @__PURE__ */ new Map();
12903
+ const lastSeen = /* @__PURE__ */ new Map();
12904
+ const mwState = /* @__PURE__ */ new Map();
12905
+ const detectSlip = (o, ei) => {
12906
+ const lamW = C_LIGHT / (o.f1 - o.f2);
12907
+ const lw = o.l1 - o.l2;
12908
+ const pn = (o.f1 * o.c1 + o.f2 * o.c2) / (o.f1 + o.f2);
12909
+ const mw = lw - pn / lamW;
12910
+ const st = mwState.get(o.prn);
12911
+ let slip = o.slip;
12912
+ if (!st || ei - st.lastEi > 2)
12913
+ slip = true;
12914
+ else if (Math.abs(mw - st.mean) > 4) slip = true;
12915
+ if (slip) mwState.set(o.prn, { mean: mw, n: 1, lastEi: ei });
12916
+ else {
12917
+ const n = st.n + 1;
12918
+ mwState.set(o.prn, {
12919
+ mean: st.mean + (mw - st.mean) / Math.min(n, 100),
12920
+ n,
12921
+ lastEi: ei
12922
+ });
12923
+ }
12924
+ return slip;
12925
+ };
12926
+ const growState = (initVal, initVar) => {
12927
+ const idx = x.length;
12928
+ x.push(initVal);
12929
+ for (const row of P) row.push(0);
12930
+ P.push(new Array(x.length).fill(0));
12931
+ P[idx][idx] = initVar;
12932
+ return idx;
12933
+ };
12934
+ const dropState = (idx) => {
12935
+ x.splice(idx, 1);
12936
+ P.splice(idx, 1);
12937
+ for (const row of P) row.splice(idx, 1);
12938
+ for (const [prn, i] of ambIdx) {
12939
+ if (i === idx) ambIdx.delete(prn);
12940
+ else if (i > idx) ambIdx.set(prn, i - 1);
12941
+ }
12942
+ };
12943
+ let clockSeeded = false;
12944
+ const series = [];
12945
+ const truth = opts.groundTruth;
12946
+ const t0 = epochs[0]?.timeMs ?? 0;
12947
+ let convergenceSec = null;
12948
+ let convergedStreak = 0;
12949
+ for (let ei = 0; ei < epochs.length; ei++) {
12950
+ const epoch = epochs[ei];
12951
+ P[IDX_CLK][IDX_CLK] = 1e10;
12952
+ P[IDX_ZWD][IDX_ZWD] += ztdQ * (ei > 0 ? 1 : 0);
12953
+ const rcv = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
12954
+ const [latDeg, , heightM] = ecefToGeodetic(rcv[0], rcv[1], rcv[2]);
12955
+ const latRad = latDeg * Math.PI / 180;
12956
+ const epochCtx = corrections?.epochContext?.(epoch.timeMs, rcv) ?? null;
12957
+ const vis = [];
12958
+ for (const o of epoch.obs) {
12959
+ if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
12960
+ const slip = detectSlip(o, ei);
12961
+ const sat = satStateAtEmission(sp3, o.prn, epoch.timeMs, rcv);
12962
+ if (!sat) continue;
12963
+ const [elRad, azRad] = getAer(
12964
+ sat.state.x,
12965
+ sat.state.y,
12966
+ sat.state.z,
12967
+ rcv[0],
12968
+ rcv[1],
12969
+ rcv[2]
12970
+ );
12971
+ if (elRad < elevMask) continue;
12972
+ const dx = sat.state.x - rcv[0];
12973
+ const dy = sat.state.y - rcv[1];
12974
+ const dz = sat.state.z - rcv[2];
12975
+ const range = Math.hypot(dx, dy, dz);
12976
+ const e = [dx / range, dy / range, dz / range];
12977
+ const { g } = ifCoeffs(o.f1, o.f2);
12978
+ const lam1 = C_LIGHT / o.f1;
12979
+ const lam2 = C_LIGHT / o.f2;
12980
+ if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
12981
+ const pIf = g * o.c1 - (g - 1) * o.c2;
12982
+ const lIf = g * (o.l1 * lam1) - (g - 1) * (o.l2 * lam2);
12983
+ if (!Number.isFinite(pIf) || !Number.isFinite(lIf)) continue;
12984
+ const trop = opts.troposphere ?? true ? niellMapping(elRad, latRad, heightM, epoch.timeMs) : { zhd: 0, mh: 0, mw: 0 };
12985
+ const { zhd, mh, mw } = trop;
12986
+ const geom = {
12987
+ prn: o.prn,
12988
+ satEcef: [sat.state.x, sat.state.y, sat.state.z],
12989
+ rcvEcef: rcv,
12990
+ los: e,
12991
+ elRad,
12992
+ azRad,
12993
+ f1: o.f1,
12994
+ f2: o.f2,
12995
+ band1: o.band1,
12996
+ band2: o.band2,
12997
+ g
12998
+ };
12999
+ const corr = corrections ? applyCorrections(corrections, geom, epochCtx) : { rangeM: 0, phaseWindupM: 0 };
13000
+ vis.push({
13001
+ prn: o.prn,
13002
+ e,
13003
+ elRad,
13004
+ pIf,
13005
+ lIf,
13006
+ satClkM: sat.state.clkM,
13007
+ range,
13008
+ tropoFixed: zhd * mh + corr.rangeM,
13009
+ mw,
13010
+ windupM: corr.phaseWindupM,
13011
+ slip
13012
+ });
13013
+ }
13014
+ const zwd0 = x[IDX_ZWD];
13015
+ if (vis.length > 0) {
13016
+ if (!clockSeeded) {
13017
+ const s = vis.map(
13018
+ (v) => v.pIf - (v.range - v.satClkM + v.tropoFixed + zwd0 * v.mw)
13019
+ ).sort((a, b) => a - b);
13020
+ x[IDX_CLK] = s[Math.floor(s.length / 2)];
13021
+ clockSeeded = true;
13022
+ }
13023
+ P[IDX_CLK][IDX_CLK] = 1e10;
13024
+ }
13025
+ let nSats = 0;
13026
+ let sumPhaseResSq = 0;
13027
+ let nPhaseRes = 0;
13028
+ for (const v of vis) {
13029
+ const common = v.range + x[IDX_CLK] - v.satClkM + v.tropoFixed + zwd0 * v.mw;
13030
+ let ai = ambIdx.get(v.prn);
13031
+ if (ai === void 0 || v.slip) {
13032
+ const bInit = v.lIf - (common + v.windupM);
13033
+ if (ai === void 0) {
13034
+ ai = growState(bInit, 100 * 100);
13035
+ } else {
13036
+ x[ai] = bInit;
13037
+ for (let j = 0; j < P.length; j++) {
13038
+ P[ai][j] = 0;
13039
+ P[j][ai] = 0;
13040
+ }
13041
+ P[ai][ai] = 100 * 100;
13042
+ }
13043
+ ambIdx.set(v.prn, ai);
13044
+ }
13045
+ const n = x.length;
13046
+ const sinEl = Math.max(Math.sin(v.elRad), 0.1);
13047
+ const rCode = (codeSigma / sinEl) ** 2;
13048
+ const rPhase = (phaseSigma / sinEl) ** 2;
13049
+ {
13050
+ const h = new Array(n).fill(0);
13051
+ h[IDX_X] = -v.e[0];
13052
+ h[IDX_Y] = -v.e[1];
13053
+ h[IDX_Z] = -v.e[2];
13054
+ h[IDX_CLK] = 1;
13055
+ h[IDX_ZWD] = v.mw;
13056
+ const innov = v.pIf - common;
13057
+ if (Math.abs(innov) < 1e6) ekfUpdateScalar(x, P, h, innov, rCode, 4);
13058
+ }
13059
+ {
13060
+ const commonPh = v.range + x[IDX_CLK] - v.satClkM + v.tropoFixed + x[IDX_ZWD] * v.mw;
13061
+ const innov = v.lIf - (commonPh + v.windupM + x[ai]);
13062
+ if (Math.abs(innov) > 0.15) {
13063
+ x[ai] = v.lIf - (commonPh + v.windupM);
13064
+ for (let j = 0; j < P.length; j++) {
13065
+ P[ai][j] = 0;
13066
+ P[j][ai] = 0;
13067
+ }
13068
+ P[ai][ai] = 100 * 100;
13069
+ } else {
13070
+ const h = new Array(n).fill(0);
13071
+ h[IDX_X] = -v.e[0];
13072
+ h[IDX_Y] = -v.e[1];
13073
+ h[IDX_Z] = -v.e[2];
13074
+ h[IDX_CLK] = 1;
13075
+ h[IDX_ZWD] = v.mw;
13076
+ h[ai] = 1;
13077
+ if (ekfUpdateScalar(x, P, h, innov, rPhase, 4)) {
13078
+ sumPhaseResSq += innov * innov;
13079
+ nPhaseRes++;
13080
+ }
13081
+ }
13082
+ }
13083
+ lastSeen.set(v.prn, ei);
13084
+ nSats++;
13085
+ }
13086
+ for (const [prn, seen] of [...lastSeen]) {
13087
+ if (ei - seen > 20) {
13088
+ const idx = ambIdx.get(prn);
13089
+ if (idx !== void 0) dropState(idx);
13090
+ lastSeen.delete(prn);
13091
+ }
13092
+ }
13093
+ const pos = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
13094
+ let enu = null;
13095
+ let error3d = null;
13096
+ if (truth) {
13097
+ enu = getEnuDifference(
13098
+ pos[0],
13099
+ pos[1],
13100
+ pos[2],
13101
+ truth[0],
13102
+ truth[1],
13103
+ truth[2]
13104
+ );
13105
+ error3d = Math.hypot(
13106
+ pos[0] - truth[0],
13107
+ pos[1] - truth[1],
13108
+ pos[2] - truth[2]
13109
+ );
13110
+ if (error3d < 0.1) {
13111
+ convergedStreak++;
13112
+ if (convergedStreak >= 10 && convergenceSec == null) {
13113
+ convergenceSec = (epoch.timeMs - t0) / 1e3;
13114
+ }
13115
+ } else {
13116
+ convergedStreak = 0;
13117
+ convergenceSec = null;
13118
+ }
13119
+ }
13120
+ series.push({
13121
+ timeMs: epoch.timeMs,
13122
+ enu,
13123
+ error3d,
13124
+ position: pos,
13125
+ nSats,
13126
+ ztdWet: x[IDX_ZWD],
13127
+ phaseResRms: nPhaseRes > 0 ? Math.sqrt(sumPhaseResSq / nPhaseRes) : 0
13128
+ });
13129
+ }
13130
+ const finalPos = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
13131
+ const llh = ecefToGeodetic(finalPos[0], finalPos[1], finalPos[2]);
13132
+ const finalError3d = truth ? Math.hypot(
13133
+ finalPos[0] - truth[0],
13134
+ finalPos[1] - truth[1],
13135
+ finalPos[2] - truth[2]
13136
+ ) : null;
13137
+ return {
13138
+ position: finalPos,
13139
+ llh,
13140
+ series,
13141
+ ztdWet: x[IDX_ZWD],
13142
+ epochsUsed: epochs.length,
13143
+ convergenceSec,
13144
+ finalError3d
13145
+ };
13146
+ }
13147
+
12346
13148
  // src/positioning/index.ts
12347
13149
  var GM_GPS3 = 3986005e8;
12348
13150
  var F_REL = -4442807633e-19;
@@ -12483,7 +13285,8 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
12483
13285
  let ionoM = 0;
12484
13286
  if ((gim || iono) && positionSane) {
12485
13287
  let l1M = null;
12486
- if (gim) l1M = gimSlantIonoDelayL1(gim, rxLat, rxLon, azim, elev, timeMs);
13288
+ if (gim)
13289
+ l1M = gimSlantIonoDelayL1(gim, rxLat, rxLon, azim, elev, timeMs);
12487
13290
  if (l1M === null && iono) {
12488
13291
  l1M = C_LIGHT * klobucharDelay(iono, rxLat, rxLon, azim, elev, gpsTow);
12489
13292
  }
@@ -14927,6 +15730,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
14927
15730
  binexRecords,
14928
15731
  buildGloChannelMap,
14929
15732
  buildObsIndices,
15733
+ buildPppAntenna,
14930
15734
  clampUnit,
14931
15735
  computeAllPositions,
14932
15736
  computeDop,
@@ -14940,6 +15744,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
14940
15744
  connectToMountpoint,
14941
15745
  crc32,
14942
15746
  createGzipLineSink,
15747
+ createPppCorrections,
14943
15748
  createStationMeta,
14944
15749
  createStreamStats,
14945
15750
  crxDecompress,
@@ -15025,6 +15830,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
15025
15830
  glonassAlmanacEpochMs,
15026
15831
  glonassAlmanacPosition,
15027
15832
  glonassPosition,
15833
+ gmst,
15028
15834
  greatCircleMidpoint,
15029
15835
  hdrLine,
15030
15836
  horizonDistance,
@@ -15034,8 +15840,10 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
15034
15840
  lambdaReduction,
15035
15841
  lambdaSearch,
15036
15842
  maskRadForAzimuth,
15843
+ moonEcef,
15037
15844
  msmEpochToDate,
15038
15845
  navTimesFromEph,
15846
+ niellMapping,
15039
15847
  nmeaCoordToDecimal,
15040
15848
  oem4Frames,
15041
15849
  padL,
@@ -15085,10 +15893,13 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
15085
15893
  selectEphemeris,
15086
15894
  setGloFreqNumber,
15087
15895
  setRtcm3DebugHandler,
15896
+ solidEarthTide,
15088
15897
  solveDgnss,
15898
+ solvePpp,
15089
15899
  solveSpp,
15090
15900
  sp3Position,
15091
15901
  stationHeaderLines,
15902
+ sunEcef,
15092
15903
  systemCmp,
15093
15904
  systemName,
15094
15905
  toRtkEpoch,