gnss-js 2.1.0 → 2.3.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.
@@ -25,8 +25,10 @@ __export(positioning_exports, {
25
25
  RtkFloatEngine: () => RtkFloatEngine,
26
26
  SbasProcessor: () => SbasProcessor,
27
27
  Sp3EphemerisSource: () => Sp3EphemerisSource,
28
+ antexFreqOfGroup: () => antexFreqOfGroup,
28
29
  applyOrbitClock: () => applyOrbitClock,
29
30
  buildPppAntenna: () => buildPppAntenna,
31
+ buildRtkAntenna: () => buildRtkAntenna,
30
32
  createPppCorrections: () => createPppCorrections,
31
33
  estimateNarrowlaneFcb: () => estimateNarrowlaneFcb,
32
34
  estimateNetworkFcbs: () => estimateNetworkFcbs,
@@ -45,6 +47,7 @@ __export(positioning_exports, {
45
47
  niellMapping: () => niellMapping,
46
48
  nlWavelength: () => nlWavelength,
47
49
  postProcessRtk: () => postProcessRtk,
50
+ rcvAntennaRangeM: () => rcvAntennaRangeM,
48
51
  resolvePppAmbiguities: () => resolvePppAmbiguities,
49
52
  satClockCorrection: () => satClockCorrection,
50
53
  sbasIonoDeg: () => sbasIonoDeg,
@@ -759,6 +762,211 @@ function lambdaReduction(Q, n) {
759
762
  return Z;
760
763
  }
761
764
 
765
+ // src/positioning/ppp-antenna.ts
766
+ function parseAntexTime(s) {
767
+ const p = s.trim().split(/\s+/).map(Number);
768
+ if (p.length < 3 || p.some((v) => Number.isNaN(v))) return null;
769
+ return Date.UTC(
770
+ p[0],
771
+ (p[1] || 1) - 1,
772
+ p[2] || 1,
773
+ p[3] ?? 0,
774
+ p[4] ?? 0,
775
+ Math.floor(p[5] ?? 0)
776
+ );
777
+ }
778
+ function freqOf(entry, code) {
779
+ return entry.frequencies.find((f) => f.frequency === code);
780
+ }
781
+ function combineIf(fA, fB, f1, f2) {
782
+ const g = f1 * f1 / (f1 * f1 - f2 * f2);
783
+ const mm = 1e-3;
784
+ const pco = [
785
+ (g * fA.pcoN - (g - 1) * fB.pcoN) * mm,
786
+ (g * fA.pcoE - (g - 1) * fB.pcoE) * mm,
787
+ (g * fA.pcoU - (g - 1) * fB.pcoU) * mm
788
+ ];
789
+ const nz = Math.min(fA.pcvNoazi.length, fB.pcvNoazi.length);
790
+ const pcvNoazi = new Array(nz);
791
+ for (let i = 0; i < nz; i++) {
792
+ pcvNoazi[i] = (g * fA.pcvNoazi[i] - (g - 1) * fB.pcvNoazi[i]) * mm;
793
+ }
794
+ return { pco, pcvZen1Deg: 0, pcvDzenDeg: 0, pcvNoazi };
795
+ }
796
+ function buildPppAntenna(antex) {
797
+ const sats = /* @__PURE__ */ new Map();
798
+ const rcvs = /* @__PURE__ */ new Map();
799
+ for (const a of antex.antennas) {
800
+ if (a.isSatellite) {
801
+ const list = sats.get(a.serialNo) ?? [];
802
+ list.push(a);
803
+ sats.set(a.serialNo, list);
804
+ } else if (!rcvs.has(a.type)) {
805
+ rcvs.set(a.type, a);
806
+ }
807
+ }
808
+ const withZen = (entry, off) => ({
809
+ ...off,
810
+ pcvZen1Deg: entry.zen1,
811
+ pcvDzenDeg: entry.dzen
812
+ });
813
+ return {
814
+ satOffset(prn, dateMs, band1, band2, f1, f2) {
815
+ const list = sats.get(prn);
816
+ if (!list) return null;
817
+ const entry = list.find((e) => {
818
+ const from = parseAntexTime(e.validFrom);
819
+ const until = parseAntexTime(e.validUntil);
820
+ return (from == null || dateMs >= from) && (until == null || dateMs <= until);
821
+ });
822
+ if (!entry) return null;
823
+ const a = freqOf(entry, band1);
824
+ const b = freqOf(entry, band2);
825
+ if (!a || !b) return null;
826
+ return withZen(entry, combineIf(a, b, f1, f2));
827
+ },
828
+ rcvOffset(antType, band1, band2, f1, f2) {
829
+ const entry = rcvs.get(antType);
830
+ if (!entry) return null;
831
+ const a = freqOf(entry, band1);
832
+ const b = freqOf(entry, band2);
833
+ if (!a || !b) return null;
834
+ return withZen(entry, combineIf(a, b, f1, f2));
835
+ }
836
+ };
837
+ }
838
+ function cross(a, b) {
839
+ return [
840
+ a[1] * b[2] - a[2] * b[1],
841
+ a[2] * b[0] - a[0] * b[2],
842
+ a[0] * b[1] - a[1] * b[0]
843
+ ];
844
+ }
845
+ function norm(a) {
846
+ const n = Math.hypot(a[0], a[1], a[2]) || 1;
847
+ return [a[0] / n, a[1] / n, a[2] / n];
848
+ }
849
+ function dot(a, b) {
850
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
851
+ }
852
+ function satBodyFrame(satEcef, sunEcef2) {
853
+ const z = norm([-satEcef[0], -satEcef[1], -satEcef[2]]);
854
+ const eSun = norm([
855
+ sunEcef2[0] - satEcef[0],
856
+ sunEcef2[1] - satEcef[1],
857
+ sunEcef2[2] - satEcef[2]
858
+ ]);
859
+ const y = norm(cross(z, eSun));
860
+ const x = norm(cross(y, z));
861
+ return { x, y, z };
862
+ }
863
+ function satPcoToEcef(pcoBody, frame) {
864
+ return [
865
+ pcoBody[0] * frame.x[0] + pcoBody[1] * frame.y[0] + pcoBody[2] * frame.z[0],
866
+ pcoBody[0] * frame.x[1] + pcoBody[1] * frame.y[1] + pcoBody[2] * frame.z[1],
867
+ pcoBody[0] * frame.x[2] + pcoBody[1] * frame.y[2] + pcoBody[2] * frame.z[2]
868
+ ];
869
+ }
870
+ function enuToEcef(enu, latRad, lonRad) {
871
+ const sl = Math.sin(latRad);
872
+ const cl = Math.cos(latRad);
873
+ const so = Math.sin(lonRad);
874
+ const co = Math.cos(lonRad);
875
+ const [e, n, u] = enu;
876
+ return [
877
+ -so * e - sl * co * n + cl * co * u,
878
+ co * e - sl * so * n + cl * so * u,
879
+ cl * n + sl * u
880
+ ];
881
+ }
882
+ function interpPcv(off, angleDeg) {
883
+ const { pcvZen1Deg, pcvDzenDeg, pcvNoazi } = off;
884
+ if (pcvDzenDeg <= 0 || pcvNoazi.length < 2) return 0;
885
+ const x = (angleDeg - pcvZen1Deg) / pcvDzenDeg;
886
+ if (x <= 0) return pcvNoazi[0];
887
+ if (x >= pcvNoazi.length - 1) return pcvNoazi[pcvNoazi.length - 1];
888
+ const i = Math.floor(x);
889
+ const t = x - i;
890
+ return pcvNoazi[i] * (1 - t) + pcvNoazi[i + 1] * t;
891
+ }
892
+ function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
893
+ const k = [
894
+ -losRcvToSat[0],
895
+ -losRcvToSat[1],
896
+ -losRcvToSat[2]
897
+ ];
898
+ const kx = satFrame.x;
899
+ const ky = satFrame.y;
900
+ const kdotx = dot(k, kx);
901
+ const kcrossY = cross(k, ky);
902
+ const dS = [
903
+ kx[0] - k[0] * kdotx - kcrossY[0],
904
+ kx[1] - k[1] * kdotx - kcrossY[1],
905
+ kx[2] - k[2] * kdotx - kcrossY[2]
906
+ ];
907
+ const north = enuToEcef([0, 1, 0], latRad, lonRad);
908
+ const east = enuToEcef([1, 0, 0], latRad, lonRad);
909
+ const kdotn = dot(k, north);
910
+ const kcrossE = cross(k, east);
911
+ const dR = [
912
+ north[0] - k[0] * kdotn + kcrossE[0],
913
+ north[1] - k[1] * kdotn + kcrossE[1],
914
+ north[2] - k[2] * kdotn + kcrossE[2]
915
+ ];
916
+ const nS = Math.hypot(dS[0], dS[1], dS[2]) || 1;
917
+ const nR = Math.hypot(dR[0], dR[1], dR[2]) || 1;
918
+ let cosPhi = dot(dS, dR) / (nS * nR);
919
+ cosPhi = Math.max(-1, Math.min(1, cosPhi));
920
+ const zeta = cross(dS, dR);
921
+ const sign = dot(k, zeta) >= 0 ? 1 : -1;
922
+ const dphi = sign * Math.acos(cosPhi) / (2 * Math.PI);
923
+ const prev = state.get(prn);
924
+ const wu = prev == null ? dphi : dphi + Math.round(prev - dphi);
925
+ state.set(prn, wu);
926
+ return wu;
927
+ }
928
+
929
+ // src/positioning/rtk-antenna.ts
930
+ function freqOf2(entry, code) {
931
+ return entry.frequencies.find((f) => f.frequency === code);
932
+ }
933
+ function buildRtkAntenna(antex) {
934
+ const rcvs = /* @__PURE__ */ new Map();
935
+ for (const a of antex.antennas) {
936
+ if (!a.isSatellite && !rcvs.has(a.type)) rcvs.set(a.type, a);
937
+ }
938
+ const mm = 1e-3;
939
+ return {
940
+ rcvOffset(antType, freq) {
941
+ const entry = rcvs.get(antType);
942
+ if (!entry) return null;
943
+ const f = freqOf2(entry, freq);
944
+ if (!f) return null;
945
+ return {
946
+ pco: [f.pcoN * mm, f.pcoE * mm, f.pcoU * mm],
947
+ pcvZen1Deg: entry.zen1,
948
+ pcvDzenDeg: entry.dzen,
949
+ pcvNoazi: f.pcvNoazi.map((v) => v * mm)
950
+ };
951
+ }
952
+ };
953
+ }
954
+ function rcvAntennaRangeM(off, losRcvToSat, latRad, lonRad, elRad, antDeltaEnu = [0, 0, 0]) {
955
+ const total = [
956
+ off.pco[0] + antDeltaEnu[0],
957
+ off.pco[1] + antDeltaEnu[1],
958
+ off.pco[2] + antDeltaEnu[2]
959
+ ];
960
+ const ecef = enuToEcef(total, latRad, lonRad);
961
+ let m = -dot(losRcvToSat, ecef);
962
+ const zenithDeg = 90 - elRad * 180 / Math.PI;
963
+ m += interpPcv(off, zenithDeg);
964
+ return m;
965
+ }
966
+ function antexFreqOfGroup(group) {
967
+ return `${group[0]}0${group[1]}`;
968
+ }
969
+
762
970
  // src/positioning/rtk.ts
763
971
  var L1_CODES = {
764
972
  G: ["1C"],
@@ -824,8 +1032,16 @@ function resolveEphemeris(src, prn, timeMs) {
824
1032
  return selectEphemeris(src, prn, timeMs);
825
1033
  return src.get(prn) ?? null;
826
1034
  }
827
- function buildGeometry(rover, base, basePos, ephemerides, timeMs, maskRad, troposphere) {
1035
+ var ZERO_DELTA = [0, 0, 0];
1036
+ function buildGeometry(rover, base, basePos, ephemerides, timeMs, maskRad, troposphere, antenna = null) {
828
1037
  const out = [];
1038
+ let baseLatRad = 0;
1039
+ let baseLonRad = 0;
1040
+ if (antenna?.base) {
1041
+ const [latDeg, lonDeg] = ecefToGeodetic(basePos[0], basePos[1], basePos[2]);
1042
+ baseLatRad = latDeg * Math.PI / 180;
1043
+ baseLonRad = lonDeg * Math.PI / 180;
1044
+ }
829
1045
  for (const [prn, mR] of rover) {
830
1046
  const sys = prn[0];
831
1047
  if (!"GERCJ".includes(sys)) continue;
@@ -850,14 +1066,43 @@ function buildGeometry(rover, base, basePos, ephemerides, timeMs, maskRad, tropo
850
1066
  satB.z - basePos[2]
851
1067
  ) / C_LIGHT;
852
1068
  const [bx, by, bz] = sagnac(satB, travelB);
853
- const rhoB = Math.hypot(bx - basePos[0], by - basePos[1], bz - basePos[2]);
1069
+ let rhoB = Math.hypot(bx - basePos[0], by - basePos[1], bz - basePos[2]);
854
1070
  const elB = ecefToAzEl(basePos[0], basePos[1], basePos[2], bx, by, bz).el;
855
1071
  if (elB < maskRad) continue;
1072
+ const group = sys + mR.code;
1073
+ let offR = null;
1074
+ let roverDelta = ZERO_DELTA;
1075
+ if (antenna) {
1076
+ const antexFreq = antexFreqOfGroup(group);
1077
+ if (antenna.base) {
1078
+ const offB = antenna.model.rcvOffset(antenna.base.type, antexFreq);
1079
+ if (offB) {
1080
+ const inv = 1 / rhoB;
1081
+ const losB = [
1082
+ (bx - basePos[0]) * inv,
1083
+ (by - basePos[1]) * inv,
1084
+ (bz - basePos[2]) * inv
1085
+ ];
1086
+ rhoB += rcvAntennaRangeM(
1087
+ offB,
1088
+ losB,
1089
+ baseLatRad,
1090
+ baseLonRad,
1091
+ elB,
1092
+ antenna.base.deltaEnu
1093
+ );
1094
+ }
1095
+ }
1096
+ if (antenna.rover) {
1097
+ offR = antenna.model.rcvOffset(antenna.rover.type, antexFreq);
1098
+ roverDelta = antenna.rover.deltaEnu ?? ZERO_DELTA;
1099
+ }
1100
+ }
856
1101
  const gloK = sys === "R" ? mR.gloChannel ?? mB.gloChannel ?? eph.freqNum ?? null : null;
857
1102
  const freq = carrierFreqHz(sys, mR.code, gloK);
858
1103
  out.push({
859
1104
  prn,
860
- group: sys + mR.code,
1105
+ group,
861
1106
  lambda: freq > 0 ? C_LIGHT / freq : 0,
862
1107
  satR,
863
1108
  rhoB,
@@ -868,7 +1113,9 @@ function buildGeometry(rover, base, basePos, ephemerides, timeMs, maskRad, tropo
868
1113
  cpR: mR.cp ?? null,
869
1114
  cpB: mB.cp ?? null,
870
1115
  lockR: mR.lockTimeMs,
871
- lockB: mB.lockTimeMs
1116
+ lockB: mB.lockTimeMs,
1117
+ offR,
1118
+ roverDelta
872
1119
  });
873
1120
  }
874
1121
  return out;
@@ -876,17 +1123,29 @@ function buildGeometry(rover, base, basePos, ephemerides, timeMs, maskRad, tropo
876
1123
  function roverTerms(g, x, y, z, troposphere) {
877
1124
  const travel = Math.hypot(g.satR.x - x, g.satR.y - y, g.satR.z - z) / C_LIGHT;
878
1125
  const [sx, sy, sz] = sagnac(g.satR, travel);
879
- const rho = Math.hypot(sx - x, sy - y, sz - z);
1126
+ let rho = Math.hypot(sx - x, sy - y, sz - z);
880
1127
  const u = [
881
1128
  (x - sx) / rho,
882
1129
  (y - sy) / rho,
883
1130
  (z - sz) / rho
884
1131
  ];
1132
+ const needEl = troposphere || g.offR != null;
1133
+ const elR = needEl ? ecefToAzEl(x, y, z, sx, sy, sz).el : 0;
885
1134
  let dTropo = 0;
886
1135
  if (troposphere) {
887
- const elR = ecefToAzEl(x, y, z, sx, sy, sz).el;
888
1136
  dTropo = tropoDelay(Math.max(elR, 0.05)) - g.tropoB;
889
1137
  }
1138
+ if (g.offR) {
1139
+ const [latDeg, lonDeg] = ecefToGeodetic(x, y, z);
1140
+ rho += rcvAntennaRangeM(
1141
+ g.offR,
1142
+ [-u[0], -u[1], -u[2]],
1143
+ latDeg * Math.PI / 180,
1144
+ lonDeg * Math.PI / 180,
1145
+ elR,
1146
+ g.roverDelta
1147
+ );
1148
+ }
890
1149
  return { rho, u, dTropo };
891
1150
  }
892
1151
  function sdVariance(sigmaM, elRad) {
@@ -1125,7 +1384,8 @@ var RtkFloatEngine = class {
1125
1384
  arElevationMaskDeg: opts.arElevationMaskDeg ?? 0,
1126
1385
  glonassAr: opts.glonassAr ?? false,
1127
1386
  partialFixing: opts.partialFixing ?? true,
1128
- minFixAmbiguities: opts.minFixAmbiguities ?? 4
1387
+ minFixAmbiguities: opts.minFixAmbiguities ?? 4,
1388
+ antenna: opts.antenna ?? null
1129
1389
  };
1130
1390
  }
1131
1391
  /** Clear all filter state (position, ambiguities, lock history). */
@@ -1248,7 +1508,8 @@ var RtkFloatEngine = class {
1248
1508
  this.ephemerides,
1249
1509
  timeMs,
1250
1510
  o.elevationMaskDeg * Math.PI / 180,
1251
- o.troposphere
1511
+ o.troposphere,
1512
+ o.antenna
1252
1513
  );
1253
1514
  const byPrn = new Map(geom.map((g) => [g.prn, g]));
1254
1515
  const dtS = this.lastMs !== null ? (timeMs - this.lastMs) / 1e3 : 0;
@@ -2399,14 +2660,14 @@ var SbasProcessor = class {
2399
2660
  };
2400
2661
 
2401
2662
  // src/positioning/ssr-apply.ts
2402
- var cross = (a, b) => [
2663
+ var cross2 = (a, b) => [
2403
2664
  a[1] * b[2] - a[2] * b[1],
2404
2665
  a[2] * b[0] - a[0] * b[2],
2405
2666
  a[0] * b[1] - a[1] * b[0]
2406
2667
  ];
2407
- var norm = (a) => Math.hypot(a[0], a[1], a[2]);
2668
+ var norm2 = (a) => Math.hypot(a[0], a[1], a[2]);
2408
2669
  var unit = (a) => {
2409
- const n = norm(a);
2670
+ const n = norm2(a);
2410
2671
  return n > 0 ? [a[0] / n, a[1] / n, a[2] / n] : [0, 0, 0];
2411
2672
  };
2412
2673
  function applyOrbitClock(eph, corr, timeMs) {
@@ -2420,8 +2681,8 @@ function applyOrbitClock(eph, corr, timeMs) {
2420
2681
  const p = [s.x, s.y, s.z];
2421
2682
  const v = [s.vx, s.vy, s.vz];
2422
2683
  const er = unit(p);
2423
- const en = unit(cross(p, v));
2424
- const ea = cross(en, er);
2684
+ const en = unit(cross2(p, v));
2685
+ const ea = cross2(en, er);
2425
2686
  const dr = corr.radial + (corr.dotRadial ?? 0) * age;
2426
2687
  const da = corr.along + (corr.dotAlong ?? 0) * age;
2427
2688
  const dc = corr.cross + (corr.dotCross ?? 0) * age;
@@ -2703,170 +2964,6 @@ function solidEarthTide(rcv, sun, moon) {
2703
2964
  return disp;
2704
2965
  }
2705
2966
 
2706
- // src/positioning/ppp-antenna.ts
2707
- function parseAntexTime(s) {
2708
- const p = s.trim().split(/\s+/).map(Number);
2709
- if (p.length < 3 || p.some((v) => Number.isNaN(v))) return null;
2710
- return Date.UTC(
2711
- p[0],
2712
- (p[1] || 1) - 1,
2713
- p[2] || 1,
2714
- p[3] ?? 0,
2715
- p[4] ?? 0,
2716
- Math.floor(p[5] ?? 0)
2717
- );
2718
- }
2719
- function freqOf(entry, code) {
2720
- return entry.frequencies.find((f) => f.frequency === code);
2721
- }
2722
- function combineIf(fA, fB, f1, f2) {
2723
- const g = f1 * f1 / (f1 * f1 - f2 * f2);
2724
- const mm = 1e-3;
2725
- const pco = [
2726
- (g * fA.pcoN - (g - 1) * fB.pcoN) * mm,
2727
- (g * fA.pcoE - (g - 1) * fB.pcoE) * mm,
2728
- (g * fA.pcoU - (g - 1) * fB.pcoU) * mm
2729
- ];
2730
- const nz = Math.min(fA.pcvNoazi.length, fB.pcvNoazi.length);
2731
- const pcvNoazi = new Array(nz);
2732
- for (let i = 0; i < nz; i++) {
2733
- pcvNoazi[i] = (g * fA.pcvNoazi[i] - (g - 1) * fB.pcvNoazi[i]) * mm;
2734
- }
2735
- return { pco, pcvZen1Deg: 0, pcvDzenDeg: 0, pcvNoazi };
2736
- }
2737
- function buildPppAntenna(antex) {
2738
- const sats = /* @__PURE__ */ new Map();
2739
- const rcvs = /* @__PURE__ */ new Map();
2740
- for (const a of antex.antennas) {
2741
- if (a.isSatellite) {
2742
- const list = sats.get(a.serialNo) ?? [];
2743
- list.push(a);
2744
- sats.set(a.serialNo, list);
2745
- } else if (!rcvs.has(a.type)) {
2746
- rcvs.set(a.type, a);
2747
- }
2748
- }
2749
- const withZen = (entry, off) => ({
2750
- ...off,
2751
- pcvZen1Deg: entry.zen1,
2752
- pcvDzenDeg: entry.dzen
2753
- });
2754
- return {
2755
- satOffset(prn, dateMs, band1, band2, f1, f2) {
2756
- const list = sats.get(prn);
2757
- if (!list) return null;
2758
- const entry = list.find((e) => {
2759
- const from = parseAntexTime(e.validFrom);
2760
- const until = parseAntexTime(e.validUntil);
2761
- return (from == null || dateMs >= from) && (until == null || dateMs <= until);
2762
- });
2763
- if (!entry) return null;
2764
- const a = freqOf(entry, band1);
2765
- const b = freqOf(entry, band2);
2766
- if (!a || !b) return null;
2767
- return withZen(entry, combineIf(a, b, f1, f2));
2768
- },
2769
- rcvOffset(antType, band1, band2, f1, f2) {
2770
- const entry = rcvs.get(antType);
2771
- if (!entry) return null;
2772
- const a = freqOf(entry, band1);
2773
- const b = freqOf(entry, band2);
2774
- if (!a || !b) return null;
2775
- return withZen(entry, combineIf(a, b, f1, f2));
2776
- }
2777
- };
2778
- }
2779
- function cross2(a, b) {
2780
- return [
2781
- a[1] * b[2] - a[2] * b[1],
2782
- a[2] * b[0] - a[0] * b[2],
2783
- a[0] * b[1] - a[1] * b[0]
2784
- ];
2785
- }
2786
- function norm2(a) {
2787
- const n = Math.hypot(a[0], a[1], a[2]) || 1;
2788
- return [a[0] / n, a[1] / n, a[2] / n];
2789
- }
2790
- function dot(a, b) {
2791
- return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
2792
- }
2793
- function satBodyFrame(satEcef, sunEcef2) {
2794
- const z = norm2([-satEcef[0], -satEcef[1], -satEcef[2]]);
2795
- const eSun = norm2([
2796
- sunEcef2[0] - satEcef[0],
2797
- sunEcef2[1] - satEcef[1],
2798
- sunEcef2[2] - satEcef[2]
2799
- ]);
2800
- const y = norm2(cross2(z, eSun));
2801
- const x = norm2(cross2(y, z));
2802
- return { x, y, z };
2803
- }
2804
- function satPcoToEcef(pcoBody, frame) {
2805
- return [
2806
- pcoBody[0] * frame.x[0] + pcoBody[1] * frame.y[0] + pcoBody[2] * frame.z[0],
2807
- pcoBody[0] * frame.x[1] + pcoBody[1] * frame.y[1] + pcoBody[2] * frame.z[1],
2808
- pcoBody[0] * frame.x[2] + pcoBody[1] * frame.y[2] + pcoBody[2] * frame.z[2]
2809
- ];
2810
- }
2811
- function enuToEcef(enu, latRad, lonRad) {
2812
- const sl = Math.sin(latRad);
2813
- const cl = Math.cos(latRad);
2814
- const so = Math.sin(lonRad);
2815
- const co = Math.cos(lonRad);
2816
- const [e, n, u] = enu;
2817
- return [
2818
- -so * e - sl * co * n + cl * co * u,
2819
- co * e - sl * so * n + cl * so * u,
2820
- cl * n + sl * u
2821
- ];
2822
- }
2823
- function interpPcv(off, angleDeg) {
2824
- const { pcvZen1Deg, pcvDzenDeg, pcvNoazi } = off;
2825
- if (pcvDzenDeg <= 0 || pcvNoazi.length < 2) return 0;
2826
- const x = (angleDeg - pcvZen1Deg) / pcvDzenDeg;
2827
- if (x <= 0) return pcvNoazi[0];
2828
- if (x >= pcvNoazi.length - 1) return pcvNoazi[pcvNoazi.length - 1];
2829
- const i = Math.floor(x);
2830
- const t = x - i;
2831
- return pcvNoazi[i] * (1 - t) + pcvNoazi[i + 1] * t;
2832
- }
2833
- function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
2834
- const k = [
2835
- -losRcvToSat[0],
2836
- -losRcvToSat[1],
2837
- -losRcvToSat[2]
2838
- ];
2839
- const kx = satFrame.x;
2840
- const ky = satFrame.y;
2841
- const kdotx = dot(k, kx);
2842
- const kcrossY = cross2(k, ky);
2843
- const dS = [
2844
- kx[0] - k[0] * kdotx - kcrossY[0],
2845
- kx[1] - k[1] * kdotx - kcrossY[1],
2846
- kx[2] - k[2] * kdotx - kcrossY[2]
2847
- ];
2848
- const north = enuToEcef([0, 1, 0], latRad, lonRad);
2849
- const east = enuToEcef([1, 0, 0], latRad, lonRad);
2850
- const kdotn = dot(k, north);
2851
- const kcrossE = cross2(k, east);
2852
- const dR = [
2853
- north[0] - k[0] * kdotn + kcrossE[0],
2854
- north[1] - k[1] * kdotn + kcrossE[1],
2855
- north[2] - k[2] * kdotn + kcrossE[2]
2856
- ];
2857
- const nS = Math.hypot(dS[0], dS[1], dS[2]) || 1;
2858
- const nR = Math.hypot(dR[0], dR[1], dR[2]) || 1;
2859
- let cosPhi = dot(dS, dR) / (nS * nR);
2860
- cosPhi = Math.max(-1, Math.min(1, cosPhi));
2861
- const zeta = cross2(dS, dR);
2862
- const sign = dot(k, zeta) >= 0 ? 1 : -1;
2863
- const dphi = sign * Math.acos(cosPhi) / (2 * Math.PI);
2864
- const prev = state.get(prn);
2865
- const wu = prev == null ? dphi : dphi + Math.round(prev - dphi);
2866
- state.set(prn, wu);
2867
- return wu;
2868
- }
2869
-
2870
2967
  // src/positioning/ppp-corrections.ts
2871
2968
  function applyCorrections(corrections, geom, ctx) {
2872
2969
  if (corrections.evaluate) return corrections.evaluate(geom, ctx);
@@ -4265,8 +4362,10 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
4265
4362
  RtkFloatEngine,
4266
4363
  SbasProcessor,
4267
4364
  Sp3EphemerisSource,
4365
+ antexFreqOfGroup,
4268
4366
  applyOrbitClock,
4269
4367
  buildPppAntenna,
4368
+ buildRtkAntenna,
4270
4369
  createPppCorrections,
4271
4370
  estimateNarrowlaneFcb,
4272
4371
  estimateNetworkFcbs,
@@ -4285,6 +4384,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
4285
4384
  niellMapping,
4286
4385
  nlWavelength,
4287
4386
  postProcessRtk,
4387
+ rcvAntennaRangeM,
4288
4388
  resolvePppAmbiguities,
4289
4389
  satClockCorrection,
4290
4390
  sbasIonoDeg,