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.
- package/dist/{chunk-DWUQRJ37.js → chunk-TYJNN77C.js} +275 -178
- package/dist/{chunk-WVTDVPKA.js → chunk-XPQ4BU6W.js} +2 -1
- package/dist/index.cjs +279 -178
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8 -2
- package/dist/positioning.cjs +277 -177
- package/dist/positioning.d.cts +91 -23
- package/dist/positioning.d.ts +91 -23
- package/dist/positioning.js +7 -1
- package/dist/rtcm3.cjs +2 -1
- package/dist/rtcm3.d.cts +4 -1
- package/dist/rtcm3.d.ts +4 -1
- package/dist/rtcm3.js +1 -1
- package/package.json +1 -1
package/dist/positioning.cjs
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
2668
|
+
var norm2 = (a) => Math.hypot(a[0], a[1], a[2]);
|
|
2408
2669
|
var unit = (a) => {
|
|
2409
|
-
const n =
|
|
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(
|
|
2424
|
-
const ea =
|
|
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,
|