gnss-js 1.10.0 → 1.12.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-AK6LNWZX.js → chunk-DMNFB7Q6.js} +57 -7
- package/dist/{chunk-77VUSDNI.js → chunk-HXF7XVW7.js} +499 -1
- package/dist/{chunk-ZTFKRZMM.js → chunk-LKFSXVIZ.js} +60 -4
- package/dist/index.cjs +623 -12
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +27 -5
- package/dist/orbit.cjs +59 -7
- package/dist/orbit.d.cts +12 -2
- package/dist/orbit.d.ts +12 -2
- package/dist/orbit.js +5 -1
- package/dist/positioning.cjs +101 -10
- package/dist/positioning.d.cts +44 -4
- package/dist/positioning.d.ts +44 -4
- package/dist/positioning.js +4 -2
- package/dist/rinex.cjs +508 -2
- package/dist/rinex.d.cts +129 -1
- package/dist/rinex.d.ts +129 -1
- package/dist/rinex.js +19 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -118,6 +118,7 @@ __export(src_exports, {
|
|
|
118
118
|
computeStats: () => computeStats2,
|
|
119
119
|
computeVisibility: () => computeVisibility,
|
|
120
120
|
connectToMountpoint: () => connectToMountpoint,
|
|
121
|
+
createGzipLineSink: () => createGzipLineSink,
|
|
121
122
|
createStationMeta: () => createStationMeta,
|
|
122
123
|
createStreamStats: () => createStreamStats,
|
|
123
124
|
crxDecompress: () => crxDecompress,
|
|
@@ -128,6 +129,7 @@ __export(src_exports, {
|
|
|
128
129
|
deg2dms: () => deg2dms,
|
|
129
130
|
deg2rad: () => deg2rad,
|
|
130
131
|
detrendIonoArcs: () => detrendIonoArcs,
|
|
132
|
+
dopplerHz: () => dopplerHz,
|
|
131
133
|
ecefToAzEl: () => ecefToAzEl,
|
|
132
134
|
ecefToGeodetic: () => ecefToGeodetic,
|
|
133
135
|
ephInfoToEphemeris: () => ephInfoToEphemeris,
|
|
@@ -200,6 +202,7 @@ __export(src_exports, {
|
|
|
200
202
|
horizonDistance: () => horizonDistance,
|
|
201
203
|
ionoFree: () => ionoFree,
|
|
202
204
|
keplerPosition: () => keplerPosition,
|
|
205
|
+
klobucharDelay: () => klobucharDelay,
|
|
203
206
|
maskRadForAzimuth: () => maskRadForAzimuth,
|
|
204
207
|
msmEpochToDate: () => msmEpochToDate,
|
|
205
208
|
navTimesFromEph: () => navTimesFromEph,
|
|
@@ -214,11 +217,13 @@ __export(src_exports, {
|
|
|
214
217
|
parseRinexStream: () => parseRinexStream,
|
|
215
218
|
parseSinexBiasDcb: () => parseSinexBiasDcb,
|
|
216
219
|
parseSourcetable: () => parseSourcetable,
|
|
220
|
+
parseSp3: () => parseSp3,
|
|
217
221
|
phiAltBOC: () => phiAltBOC,
|
|
218
222
|
phiBOCc: () => phiBOCc,
|
|
219
223
|
phiBOCs: () => phiBOCs,
|
|
220
224
|
phiBPSK: () => phiBPSK,
|
|
221
225
|
rad2deg: () => rad2deg,
|
|
226
|
+
rangeRate: () => rangeRate,
|
|
222
227
|
readString: () => readString,
|
|
223
228
|
reportDecodeError: () => reportDecodeError,
|
|
224
229
|
resetGloFreqCache: () => resetGloFreqCache,
|
|
@@ -229,6 +234,8 @@ __export(src_exports, {
|
|
|
229
234
|
setGloFreqNumber: () => setGloFreqNumber,
|
|
230
235
|
setRtcm3DebugHandler: () => setRtcm3DebugHandler,
|
|
231
236
|
solveSpp: () => solveSpp,
|
|
237
|
+
sp3Position: () => sp3Position,
|
|
238
|
+
stationHeaderLines: () => stationHeaderLines,
|
|
232
239
|
systemCmp: () => systemCmp,
|
|
233
240
|
systemName: () => systemName,
|
|
234
241
|
transformFrame: () => transformFrame,
|
|
@@ -236,7 +243,11 @@ __export(src_exports, {
|
|
|
236
243
|
updateStreamStats: () => updateStreamStats,
|
|
237
244
|
verifyChecksum: () => verifyChecksum,
|
|
238
245
|
vincenty: () => vincenty,
|
|
239
|
-
|
|
246
|
+
writeModernObsBlob: () => writeModernObsBlob,
|
|
247
|
+
writeRinex2ObsBlob: () => writeRinex2ObsBlob,
|
|
248
|
+
writeRinex4ObsBlob: () => writeRinex4ObsBlob,
|
|
249
|
+
writeRinexNav: () => writeRinexNav,
|
|
250
|
+
writeRinexObsBlob: () => writeRinexObsBlob
|
|
240
251
|
});
|
|
241
252
|
module.exports = __toCommonJS(src_exports);
|
|
242
253
|
|
|
@@ -2662,6 +2673,496 @@ function parseIonex(text) {
|
|
|
2662
2673
|
return { epochs, lats, lons, maps };
|
|
2663
2674
|
}
|
|
2664
2675
|
|
|
2676
|
+
// src/rinex/sp3.ts
|
|
2677
|
+
var BAD_CLOCK = 999999.999999;
|
|
2678
|
+
function parseSp3(text) {
|
|
2679
|
+
const lines = text.split("\n");
|
|
2680
|
+
const epochs = [];
|
|
2681
|
+
const satellites = {};
|
|
2682
|
+
let version = "";
|
|
2683
|
+
let intervalSec = 0;
|
|
2684
|
+
let timeSystem = "GPS";
|
|
2685
|
+
let timeSystemSet = false;
|
|
2686
|
+
let epochIdx = -1;
|
|
2687
|
+
for (const line of lines) {
|
|
2688
|
+
if (!version && line.startsWith("#") && line.charAt(1) !== "#") {
|
|
2689
|
+
version = line.charAt(1);
|
|
2690
|
+
}
|
|
2691
|
+
if (line.startsWith("##")) {
|
|
2692
|
+
const f = line.slice(2).trim().split(/\s+/);
|
|
2693
|
+
intervalSec = Number(f[2]) || 0;
|
|
2694
|
+
} else if (line.startsWith("%c") && !timeSystemSet) {
|
|
2695
|
+
const sys = line.slice(9, 12).trim();
|
|
2696
|
+
if (sys && !/^c+$/.test(sys)) {
|
|
2697
|
+
timeSystem = sys;
|
|
2698
|
+
timeSystemSet = true;
|
|
2699
|
+
}
|
|
2700
|
+
} else if (line.startsWith("*")) {
|
|
2701
|
+
const f = line.slice(1).trim().split(/\s+/).map(Number);
|
|
2702
|
+
if (f.length >= 6 && f.every(Number.isFinite)) {
|
|
2703
|
+
const sec = f[5];
|
|
2704
|
+
epochs.push(
|
|
2705
|
+
Date.UTC(
|
|
2706
|
+
f[0],
|
|
2707
|
+
f[1] - 1,
|
|
2708
|
+
f[2],
|
|
2709
|
+
f[3],
|
|
2710
|
+
f[4],
|
|
2711
|
+
Math.floor(sec),
|
|
2712
|
+
Math.round(sec % 1 * 1e3)
|
|
2713
|
+
)
|
|
2714
|
+
);
|
|
2715
|
+
epochIdx++;
|
|
2716
|
+
}
|
|
2717
|
+
} else if (line.startsWith("P") && epochIdx >= 0) {
|
|
2718
|
+
const prn = line.slice(1, 4).replace(/\s/g, "0");
|
|
2719
|
+
const f = line.slice(4).trim().split(/\s+/).map(Number);
|
|
2720
|
+
if (f.length < 3) continue;
|
|
2721
|
+
const [xKm, yKm, zKm] = f;
|
|
2722
|
+
let arr = satellites[prn];
|
|
2723
|
+
if (!arr) satellites[prn] = arr = [];
|
|
2724
|
+
while (arr.length < epochIdx) arr.push(null);
|
|
2725
|
+
if (xKm === 0 && yKm === 0 && zKm === 0) {
|
|
2726
|
+
arr.push(null);
|
|
2727
|
+
continue;
|
|
2728
|
+
}
|
|
2729
|
+
const clkUs = f[3];
|
|
2730
|
+
arr.push({
|
|
2731
|
+
x: xKm * 1e3,
|
|
2732
|
+
y: yKm * 1e3,
|
|
2733
|
+
z: zKm * 1e3,
|
|
2734
|
+
clk: clkUs !== void 0 && Math.abs(clkUs) < BAD_CLOCK ? clkUs * 1e-6 : null
|
|
2735
|
+
});
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
for (const arr of Object.values(satellites)) {
|
|
2739
|
+
while (arr.length < epochs.length) arr.push(null);
|
|
2740
|
+
}
|
|
2741
|
+
return { version, epochs, intervalSec, timeSystem, satellites };
|
|
2742
|
+
}
|
|
2743
|
+
function sp3Position(sp3, prn, tMs, order = 9) {
|
|
2744
|
+
const samples = sp3.satellites[prn];
|
|
2745
|
+
const { epochs } = sp3;
|
|
2746
|
+
const n = epochs.length;
|
|
2747
|
+
if (!samples || n < order) return null;
|
|
2748
|
+
if (tMs < epochs[0] || tMs > epochs[n - 1]) return null;
|
|
2749
|
+
let lo = 0;
|
|
2750
|
+
let hi = n - 1;
|
|
2751
|
+
while (lo < hi) {
|
|
2752
|
+
const mid = lo + hi + 1 >> 1;
|
|
2753
|
+
if (epochs[mid] <= tMs) lo = mid;
|
|
2754
|
+
else hi = mid - 1;
|
|
2755
|
+
}
|
|
2756
|
+
let start = lo - (order >> 1) + (order % 2 === 0 ? 1 : 0);
|
|
2757
|
+
start = Math.max(0, Math.min(n - order, start));
|
|
2758
|
+
for (let i = start; i < start + order; i++) {
|
|
2759
|
+
if (!samples[i]) return null;
|
|
2760
|
+
}
|
|
2761
|
+
const t0 = epochs[start];
|
|
2762
|
+
const t = (tMs - t0) / 1e3;
|
|
2763
|
+
let x = 0;
|
|
2764
|
+
let y = 0;
|
|
2765
|
+
let z = 0;
|
|
2766
|
+
for (let i = 0; i < order; i++) {
|
|
2767
|
+
const ti = (epochs[start + i] - t0) / 1e3;
|
|
2768
|
+
let w = 1;
|
|
2769
|
+
for (let j = 0; j < order; j++) {
|
|
2770
|
+
if (j === i) continue;
|
|
2771
|
+
const tj = (epochs[start + j] - t0) / 1e3;
|
|
2772
|
+
w *= (t - tj) / (ti - tj);
|
|
2773
|
+
}
|
|
2774
|
+
const s = samples[start + i];
|
|
2775
|
+
x += w * s.x;
|
|
2776
|
+
y += w * s.y;
|
|
2777
|
+
z += w * s.z;
|
|
2778
|
+
}
|
|
2779
|
+
let clk = null;
|
|
2780
|
+
const a = samples[lo];
|
|
2781
|
+
const b = samples[Math.min(lo + 1, n - 1)];
|
|
2782
|
+
if (a?.clk != null && b?.clk != null) {
|
|
2783
|
+
const span = epochs[Math.min(lo + 1, n - 1)] - epochs[lo];
|
|
2784
|
+
const f = span > 0 ? (tMs - epochs[lo]) / span : 0;
|
|
2785
|
+
clk = a.clk * (1 - f) + b.clk * f;
|
|
2786
|
+
} else if (a?.clk != null) {
|
|
2787
|
+
clk = a.clk;
|
|
2788
|
+
}
|
|
2789
|
+
return { x, y, z, clk };
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
// src/rinex/obs-writer-common.ts
|
|
2793
|
+
function createGzipLineSink() {
|
|
2794
|
+
const encoder = new TextEncoder();
|
|
2795
|
+
const compressor = new CompressionStream("gzip");
|
|
2796
|
+
const writer = compressor.writable.getWriter();
|
|
2797
|
+
const compressedChunks = [];
|
|
2798
|
+
const readerDone = (async () => {
|
|
2799
|
+
const reader = compressor.readable.getReader();
|
|
2800
|
+
for (; ; ) {
|
|
2801
|
+
const { done, value } = await reader.read();
|
|
2802
|
+
if (done) break;
|
|
2803
|
+
compressedChunks.push(value);
|
|
2804
|
+
}
|
|
2805
|
+
})();
|
|
2806
|
+
let batch = [];
|
|
2807
|
+
async function flush() {
|
|
2808
|
+
if (batch.length === 0) return;
|
|
2809
|
+
await writer.write(encoder.encode(batch.join("\n") + "\n"));
|
|
2810
|
+
batch = [];
|
|
2811
|
+
}
|
|
2812
|
+
return {
|
|
2813
|
+
push(line) {
|
|
2814
|
+
batch.push(line);
|
|
2815
|
+
},
|
|
2816
|
+
flush,
|
|
2817
|
+
async finish() {
|
|
2818
|
+
await flush();
|
|
2819
|
+
await writer.close();
|
|
2820
|
+
await readerDone;
|
|
2821
|
+
return new Blob(compressedChunks, {
|
|
2822
|
+
type: "application/gzip"
|
|
2823
|
+
});
|
|
2824
|
+
}
|
|
2825
|
+
};
|
|
2826
|
+
}
|
|
2827
|
+
function stationHeaderLines(header) {
|
|
2828
|
+
const pos = header.approxPosition ?? [0, 0, 0];
|
|
2829
|
+
const delta = header.antDelta ?? [0, 0, 0];
|
|
2830
|
+
return [
|
|
2831
|
+
hdrLine(header.markerName || "UNKNOWN", "MARKER NAME"),
|
|
2832
|
+
hdrLine("", "MARKER NUMBER"),
|
|
2833
|
+
hdrLine(
|
|
2834
|
+
`${padL(header.observer || "", 20)}${padL(header.agency || "", 40)}`,
|
|
2835
|
+
"OBSERVER / AGENCY"
|
|
2836
|
+
),
|
|
2837
|
+
hdrLine(
|
|
2838
|
+
`${padL(header.receiverNumber || "", 20)}${padL(header.receiverType || "", 20)}${padL(header.receiverVersion || "", 20)}`,
|
|
2839
|
+
"REC # / TYPE / VERS"
|
|
2840
|
+
),
|
|
2841
|
+
hdrLine(
|
|
2842
|
+
`${padL(header.antNumber || "", 20)}${padL(header.antType || "", 20)}`,
|
|
2843
|
+
"ANT # / TYPE"
|
|
2844
|
+
),
|
|
2845
|
+
hdrLine(
|
|
2846
|
+
`${fmtF(pos[0], 14, 4)}${fmtF(pos[1], 14, 4)}${fmtF(pos[2], 14, 4)}`,
|
|
2847
|
+
"APPROX POSITION XYZ"
|
|
2848
|
+
),
|
|
2849
|
+
hdrLine(
|
|
2850
|
+
`${fmtF(delta[0], 14, 4)}${fmtF(delta[1], 14, 4)}${fmtF(delta[2], 14, 4)}`,
|
|
2851
|
+
"ANTENNA: DELTA H/E/N"
|
|
2852
|
+
)
|
|
2853
|
+
];
|
|
2854
|
+
}
|
|
2855
|
+
|
|
2856
|
+
// src/rinex/obs-writer.ts
|
|
2857
|
+
function writeRinexObsBlob(header, epochs, obsTypes) {
|
|
2858
|
+
return writeModernObsBlob(header, epochs, obsTypes, {
|
|
2859
|
+
version: "3.04",
|
|
2860
|
+
comment: "Merged from multiple RINEX files"
|
|
2861
|
+
});
|
|
2862
|
+
}
|
|
2863
|
+
async function writeModernObsBlob(header, epochs, obsTypes, opts) {
|
|
2864
|
+
if (epochs.length === 0) return new Blob([], { type: "application/gzip" });
|
|
2865
|
+
const sink = createGzipLineSink();
|
|
2866
|
+
const BATCH = 200;
|
|
2867
|
+
const systems = [...obsTypes.keys()];
|
|
2868
|
+
const sysChar = systems.length === 1 ? systems[0] : "M";
|
|
2869
|
+
sink.push(
|
|
2870
|
+
hdrLine(
|
|
2871
|
+
` ${opts.version} OBSERVATION DATA ${sysChar}`,
|
|
2872
|
+
"RINEX VERSION / TYPE"
|
|
2873
|
+
)
|
|
2874
|
+
);
|
|
2875
|
+
const now = /* @__PURE__ */ new Date();
|
|
2876
|
+
const dateStr = `${now.getUTCFullYear()}${String(now.getUTCMonth() + 1).padStart(2, "0")}${String(now.getUTCDate()).padStart(2, "0")} ${String(now.getUTCHours()).padStart(2, "0")}${String(now.getUTCMinutes()).padStart(2, "0")}${String(now.getUTCSeconds()).padStart(2, "0")} UTC`;
|
|
2877
|
+
sink.push(
|
|
2878
|
+
hdrLine(
|
|
2879
|
+
`${padL("GNSSCalc", 20)}${padL("", 20)}${dateStr}`,
|
|
2880
|
+
"PGM / RUN BY / DATE"
|
|
2881
|
+
)
|
|
2882
|
+
);
|
|
2883
|
+
sink.push(hdrLine(opts.comment, "COMMENT"));
|
|
2884
|
+
for (const line of stationHeaderLines(header)) sink.push(line);
|
|
2885
|
+
for (const [sys, types] of obsTypes) {
|
|
2886
|
+
for (let i = 0; i < types.length; i += 13) {
|
|
2887
|
+
const chunk = types.slice(i, i + 13);
|
|
2888
|
+
let content;
|
|
2889
|
+
if (i === 0) {
|
|
2890
|
+
content = `${sys} ${padR(String(types.length), 3)}`;
|
|
2891
|
+
} else {
|
|
2892
|
+
content = " ";
|
|
2893
|
+
}
|
|
2894
|
+
content += chunk.map((t) => ` ${padL(t, 3)}`).join("");
|
|
2895
|
+
sink.push(hdrLine(content, "SYS / # / OBS TYPES"));
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
const timeSys = systems.includes("R") && systems.length === 1 ? "GLO" : "GPS";
|
|
2899
|
+
const obsTimeLine = (d) => ` ${d.getUTCFullYear()} ${String(d.getUTCMonth() + 1).padStart(2)} ${String(d.getUTCDate()).padStart(2)} ${String(d.getUTCHours()).padStart(2)} ${String(d.getUTCMinutes()).padStart(2)} ${(d.getUTCSeconds() + d.getUTCMilliseconds() / 1e3).toFixed(7).padStart(10)} ${timeSys}`;
|
|
2900
|
+
sink.push(
|
|
2901
|
+
hdrLine(obsTimeLine(new Date(epochs[0].time)), "TIME OF FIRST OBS")
|
|
2902
|
+
);
|
|
2903
|
+
sink.push(
|
|
2904
|
+
hdrLine(
|
|
2905
|
+
obsTimeLine(new Date(epochs[epochs.length - 1].time)),
|
|
2906
|
+
"TIME OF LAST OBS"
|
|
2907
|
+
)
|
|
2908
|
+
);
|
|
2909
|
+
if (epochs.length >= 2) {
|
|
2910
|
+
const interval = (epochs[1].time - epochs[0].time) / 1e3;
|
|
2911
|
+
if (interval > 0 && interval < 3600) {
|
|
2912
|
+
sink.push(hdrLine(fmtF(interval, 10, 3), "INTERVAL"));
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2915
|
+
if (header.glonassSlots && Object.keys(header.glonassSlots).length > 0) {
|
|
2916
|
+
const entries = Object.entries(header.glonassSlots).sort(
|
|
2917
|
+
([a], [b]) => Number(a) - Number(b)
|
|
2918
|
+
);
|
|
2919
|
+
for (let i = 0; i < entries.length; i += 8) {
|
|
2920
|
+
const chunk = entries.slice(i, i + 8);
|
|
2921
|
+
let content = i === 0 ? padR(String(entries.length), 3) + " " : " ";
|
|
2922
|
+
for (const [slot, freq] of chunk) {
|
|
2923
|
+
content += `R${padR(slot, 2)} ${padR(String(freq), 2)} `;
|
|
2924
|
+
}
|
|
2925
|
+
sink.push(hdrLine(content, "GLONASS SLOT / FRQ #"));
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
sink.push(hdrLine("", "END OF HEADER"));
|
|
2929
|
+
await sink.flush();
|
|
2930
|
+
let epochCount = 0;
|
|
2931
|
+
for (const epoch of epochs) {
|
|
2932
|
+
const t = new Date(epoch.time);
|
|
2933
|
+
const sec = t.getUTCSeconds() + t.getUTCMilliseconds() / 1e3;
|
|
2934
|
+
const prns = [...epoch.sats.keys()].sort();
|
|
2935
|
+
sink.push(
|
|
2936
|
+
`> ${t.getUTCFullYear()} ${String(t.getUTCMonth() + 1).padStart(2, "0")} ${String(t.getUTCDate()).padStart(2, "0")} ${String(t.getUTCHours()).padStart(2, "0")} ${String(t.getUTCMinutes()).padStart(2, "0")}${fmtF(sec, 11, 7)} 0${padR(String(prns.length), 3)}`
|
|
2937
|
+
);
|
|
2938
|
+
for (const prn of prns) {
|
|
2939
|
+
const sys = prn[0];
|
|
2940
|
+
const sysTypes = obsTypes.get(sys);
|
|
2941
|
+
if (!sysTypes) continue;
|
|
2942
|
+
const valArr = epoch.sats.get(prn);
|
|
2943
|
+
let line = prn;
|
|
2944
|
+
for (let i = 0; i < sysTypes.length; i++) {
|
|
2945
|
+
const val = i < valArr.length ? valArr[i] : NaN;
|
|
2946
|
+
if (!isNaN(val)) {
|
|
2947
|
+
line += fmtF(val, 14, 3) + " ";
|
|
2948
|
+
} else {
|
|
2949
|
+
line += " ".repeat(16);
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
sink.push(line);
|
|
2953
|
+
}
|
|
2954
|
+
epochCount++;
|
|
2955
|
+
if (epochCount % BATCH === 0) await sink.flush();
|
|
2956
|
+
}
|
|
2957
|
+
return sink.finish();
|
|
2958
|
+
}
|
|
2959
|
+
|
|
2960
|
+
// src/rinex/obs-writer-v2.ts
|
|
2961
|
+
var V3_TO_V2 = {
|
|
2962
|
+
// GPS
|
|
2963
|
+
C1C: "C1",
|
|
2964
|
+
C1S: "C1",
|
|
2965
|
+
C1L: "C1",
|
|
2966
|
+
C1X: "C1",
|
|
2967
|
+
C1W: "P1",
|
|
2968
|
+
C1P: "P1",
|
|
2969
|
+
C2C: "C2",
|
|
2970
|
+
C2S: "P2",
|
|
2971
|
+
C2L: "P2",
|
|
2972
|
+
C2X: "P2",
|
|
2973
|
+
C2W: "P2",
|
|
2974
|
+
C2P: "P2",
|
|
2975
|
+
C5I: "C5",
|
|
2976
|
+
C5Q: "C5",
|
|
2977
|
+
C5X: "C5",
|
|
2978
|
+
L1C: "L1",
|
|
2979
|
+
L1S: "L1",
|
|
2980
|
+
L1L: "L1",
|
|
2981
|
+
L1X: "L1",
|
|
2982
|
+
L1W: "L1",
|
|
2983
|
+
L1P: "L1",
|
|
2984
|
+
L2C: "L2",
|
|
2985
|
+
L2S: "L2",
|
|
2986
|
+
L2L: "L2",
|
|
2987
|
+
L2X: "L2",
|
|
2988
|
+
L2W: "L2",
|
|
2989
|
+
L2P: "L2",
|
|
2990
|
+
L5I: "L5",
|
|
2991
|
+
L5Q: "L5",
|
|
2992
|
+
L5X: "L5",
|
|
2993
|
+
D1C: "D1",
|
|
2994
|
+
D1S: "D1",
|
|
2995
|
+
D1L: "D1",
|
|
2996
|
+
D1X: "D1",
|
|
2997
|
+
D1W: "D1",
|
|
2998
|
+
D1P: "D1",
|
|
2999
|
+
D2C: "D2",
|
|
3000
|
+
D2S: "D2",
|
|
3001
|
+
D2L: "D2",
|
|
3002
|
+
D2X: "D2",
|
|
3003
|
+
D2W: "D2",
|
|
3004
|
+
D2P: "D2",
|
|
3005
|
+
D5I: "D5",
|
|
3006
|
+
D5Q: "D5",
|
|
3007
|
+
D5X: "D5",
|
|
3008
|
+
S1C: "S1",
|
|
3009
|
+
S1S: "S1",
|
|
3010
|
+
S1L: "S1",
|
|
3011
|
+
S1X: "S1",
|
|
3012
|
+
S1W: "S1",
|
|
3013
|
+
S1P: "S1",
|
|
3014
|
+
S2C: "S2",
|
|
3015
|
+
S2S: "S2",
|
|
3016
|
+
S2L: "S2",
|
|
3017
|
+
S2X: "S2",
|
|
3018
|
+
S2W: "S2",
|
|
3019
|
+
S2P: "S2",
|
|
3020
|
+
S5I: "S5",
|
|
3021
|
+
S5Q: "S5",
|
|
3022
|
+
S5X: "S5"
|
|
3023
|
+
};
|
|
3024
|
+
function v3ToV2Code(code3) {
|
|
3025
|
+
return V3_TO_V2[code3] ?? null;
|
|
3026
|
+
}
|
|
3027
|
+
async function writeRinex2ObsBlob(header, epochs, obsTypes) {
|
|
3028
|
+
if (epochs.length === 0) return new Blob([], { type: "application/gzip" });
|
|
3029
|
+
const gpsCodes = obsTypes.get("G") ?? obsTypes.get("R") ?? [];
|
|
3030
|
+
const v2Codes = [];
|
|
3031
|
+
const v2CodeSet = /* @__PURE__ */ new Set();
|
|
3032
|
+
const v3ToV2Map = /* @__PURE__ */ new Map();
|
|
3033
|
+
for (const code3 of gpsCodes) {
|
|
3034
|
+
const code2 = v3ToV2Code(code3);
|
|
3035
|
+
if (!code2) continue;
|
|
3036
|
+
if (!v2CodeSet.has(code2)) {
|
|
3037
|
+
v2CodeSet.add(code2);
|
|
3038
|
+
v3ToV2Map.set(code3, v2Codes.length);
|
|
3039
|
+
v2Codes.push(code2);
|
|
3040
|
+
} else {
|
|
3041
|
+
v3ToV2Map.set(code3, v2Codes.indexOf(code2));
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
const gloCodes = obsTypes.get("R") ?? [];
|
|
3045
|
+
for (const code3 of gloCodes) {
|
|
3046
|
+
const code2 = v3ToV2Code(code3);
|
|
3047
|
+
if (!code2) continue;
|
|
3048
|
+
if (!v2CodeSet.has(code2)) {
|
|
3049
|
+
v2CodeSet.add(code2);
|
|
3050
|
+
v3ToV2Map.set(code3, v2Codes.length);
|
|
3051
|
+
v2Codes.push(code2);
|
|
3052
|
+
} else if (!v3ToV2Map.has(code3)) {
|
|
3053
|
+
v3ToV2Map.set(code3, v2Codes.indexOf(code2));
|
|
3054
|
+
}
|
|
3055
|
+
}
|
|
3056
|
+
const sink = createGzipLineSink();
|
|
3057
|
+
const BATCH = 200;
|
|
3058
|
+
const hasSystems = /* @__PURE__ */ new Set();
|
|
3059
|
+
for (const epoch of epochs) {
|
|
3060
|
+
for (const prn of epoch.sats.keys()) {
|
|
3061
|
+
const sys = prn[0];
|
|
3062
|
+
if (sys === "G" || sys === "R") hasSystems.add(sys);
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
const sysChar = hasSystems.has("G") && hasSystems.has("R") ? "M" : hasSystems.has("R") ? "R" : "G";
|
|
3066
|
+
sink.push(
|
|
3067
|
+
hdrLine(
|
|
3068
|
+
` 2.11 OBSERVATION DATA ${sysChar}`,
|
|
3069
|
+
"RINEX VERSION / TYPE"
|
|
3070
|
+
)
|
|
3071
|
+
);
|
|
3072
|
+
const now = /* @__PURE__ */ new Date();
|
|
3073
|
+
const dateStr = `${now.getUTCFullYear()}-${String(now.getUTCMonth() + 1).padStart(2, "0")}-${String(now.getUTCDate()).padStart(2, "0")} ${String(now.getUTCHours()).padStart(2, "0")}:${String(now.getUTCMinutes()).padStart(2, "0")}:${String(now.getUTCSeconds()).padStart(2, "0")}`;
|
|
3074
|
+
sink.push(
|
|
3075
|
+
hdrLine(
|
|
3076
|
+
`${padL("GNSSCalc", 20)}${padL("", 20)}${dateStr}`,
|
|
3077
|
+
"PGM / RUN BY / DATE"
|
|
3078
|
+
)
|
|
3079
|
+
);
|
|
3080
|
+
sink.push(hdrLine("Converted from RINEX 3 by GNSSCalc", "COMMENT"));
|
|
3081
|
+
for (const line of stationHeaderLines(header)) sink.push(line);
|
|
3082
|
+
sink.push(hdrLine(" 1 1", "WAVELENGTH FACT L1/2"));
|
|
3083
|
+
for (let i = 0; i < v2Codes.length; i += 9) {
|
|
3084
|
+
const chunk = v2Codes.slice(i, i + 9);
|
|
3085
|
+
let content;
|
|
3086
|
+
if (i === 0) {
|
|
3087
|
+
content = padR(String(v2Codes.length), 6);
|
|
3088
|
+
} else {
|
|
3089
|
+
content = " ";
|
|
3090
|
+
}
|
|
3091
|
+
content += chunk.map((c) => padR(c, 6)).join("");
|
|
3092
|
+
sink.push(hdrLine(content, "# / TYPES OF OBSERV"));
|
|
3093
|
+
}
|
|
3094
|
+
const first = new Date(epochs[0].time);
|
|
3095
|
+
const timeSys = sysChar === "R" ? "GLO" : "GPS";
|
|
3096
|
+
sink.push(
|
|
3097
|
+
hdrLine(
|
|
3098
|
+
` ${first.getUTCFullYear()} ${String(first.getUTCMonth() + 1).padStart(2)} ${String(first.getUTCDate()).padStart(2)} ${String(first.getUTCHours()).padStart(2)} ${String(first.getUTCMinutes()).padStart(2)} ${(first.getUTCSeconds() + first.getUTCMilliseconds() / 1e3).toFixed(7).padStart(10)} ${timeSys}`,
|
|
3099
|
+
"TIME OF FIRST OBS"
|
|
3100
|
+
)
|
|
3101
|
+
);
|
|
3102
|
+
sink.push(hdrLine("", "END OF HEADER"));
|
|
3103
|
+
await sink.flush();
|
|
3104
|
+
let epochCount = 0;
|
|
3105
|
+
for (const epoch of epochs) {
|
|
3106
|
+
const t = new Date(epoch.time);
|
|
3107
|
+
const sec = t.getUTCSeconds() + t.getUTCMilliseconds() / 1e3;
|
|
3108
|
+
const prns = [...epoch.sats.keys()].filter((p) => p[0] === "G" || p[0] === "R").sort();
|
|
3109
|
+
if (prns.length === 0) continue;
|
|
3110
|
+
const yy = t.getUTCFullYear() % 100;
|
|
3111
|
+
const yyS = padR(String(yy), 2);
|
|
3112
|
+
const moS = padR(String(t.getUTCMonth() + 1), 2);
|
|
3113
|
+
const ddS = padR(String(t.getUTCDate()), 2);
|
|
3114
|
+
const hhS = padR(String(t.getUTCHours()), 2);
|
|
3115
|
+
const mmS = padR(String(t.getUTCMinutes()), 2);
|
|
3116
|
+
const secS = fmtF(sec, 11, 7);
|
|
3117
|
+
const nSats = padR(String(prns.length), 3);
|
|
3118
|
+
let epochLine = ` ${yyS} ${moS} ${ddS} ${hhS} ${mmS}${secS} 0${nSats}`;
|
|
3119
|
+
for (let i = 0; i < prns.length; i++) {
|
|
3120
|
+
if (i > 0 && i % 12 === 0) {
|
|
3121
|
+
sink.push(epochLine);
|
|
3122
|
+
epochLine = " ".repeat(32);
|
|
3123
|
+
}
|
|
3124
|
+
epochLine += prns[i];
|
|
3125
|
+
}
|
|
3126
|
+
sink.push(epochLine);
|
|
3127
|
+
for (const prn of prns) {
|
|
3128
|
+
const sys = prn[0];
|
|
3129
|
+
const sysCodes3 = obsTypes.get(sys) ?? [];
|
|
3130
|
+
const valArr = epoch.sats.get(prn);
|
|
3131
|
+
const v2Vals = new Array(v2Codes.length).fill(NaN);
|
|
3132
|
+
for (let j = 0; j < sysCodes3.length; j++) {
|
|
3133
|
+
const v2Idx = v3ToV2Map.get(sysCodes3[j]);
|
|
3134
|
+
if (v2Idx != null && j < valArr.length && !isNaN(valArr[j])) {
|
|
3135
|
+
v2Vals[v2Idx] = valArr[j];
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
let line = "";
|
|
3139
|
+
for (let j = 0; j < v2Codes.length; j++) {
|
|
3140
|
+
const val = v2Vals[j];
|
|
3141
|
+
if (!isNaN(val)) {
|
|
3142
|
+
line += fmtF(val, 14, 3) + " ";
|
|
3143
|
+
} else {
|
|
3144
|
+
line += " ".repeat(16);
|
|
3145
|
+
}
|
|
3146
|
+
if ((j + 1) % 5 === 0 || j === v2Codes.length - 1) {
|
|
3147
|
+
sink.push(line);
|
|
3148
|
+
line = "";
|
|
3149
|
+
}
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3152
|
+
epochCount++;
|
|
3153
|
+
if (epochCount % BATCH === 0) await sink.flush();
|
|
3154
|
+
}
|
|
3155
|
+
return sink.finish();
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
// src/rinex/obs-writer-v4.ts
|
|
3159
|
+
function writeRinex4ObsBlob(header, epochs, obsTypes) {
|
|
3160
|
+
return writeModernObsBlob(header, epochs, obsTypes, {
|
|
3161
|
+
version: "4.01",
|
|
3162
|
+
comment: "Converted to RINEX 4 by GNSSCalc"
|
|
3163
|
+
});
|
|
3164
|
+
}
|
|
3165
|
+
|
|
2665
3166
|
// src/rtcm3/decoder.ts
|
|
2666
3167
|
var debugHandler = null;
|
|
2667
3168
|
function setRtcm3DebugHandler(fn) {
|
|
@@ -4104,6 +4605,7 @@ function gmForSystem(sys) {
|
|
|
4104
4605
|
if (sys === "C") return GM_BDS;
|
|
4105
4606
|
return GM_GPS;
|
|
4106
4607
|
}
|
|
4608
|
+
var geoVelocityPass = false;
|
|
4107
4609
|
function keplerPosition(eph, t) {
|
|
4108
4610
|
const GM = gmForSystem(eph.system);
|
|
4109
4611
|
const a = eph.sqrtA * eph.sqrtA;
|
|
@@ -4131,8 +4633,16 @@ function keplerPosition(eph, t) {
|
|
|
4131
4633
|
const uk = phik + duk;
|
|
4132
4634
|
const rk = a * (1 - eph.e * cosE) + drk;
|
|
4133
4635
|
const ik = eph.i0 + dik + eph.idot * tk;
|
|
4636
|
+
const EkDot = n / (1 - eph.e * cosE);
|
|
4637
|
+
const vkDot = EkDot * Math.sqrt(1 - eph.e * eph.e) / (1 - eph.e * cosE);
|
|
4638
|
+
const dukDot = 2 * vkDot * (eph.cus * cos2phi - eph.cuc * sin2phi);
|
|
4639
|
+
const drkDot = a * eph.e * sinE * EkDot + 2 * vkDot * (eph.crs * cos2phi - eph.crc * sin2phi);
|
|
4640
|
+
const dikDot = eph.idot + 2 * vkDot * (eph.cis * cos2phi - eph.cic * sin2phi);
|
|
4641
|
+
const ukDot = vkDot + dukDot;
|
|
4134
4642
|
const xp = rk * Math.cos(uk);
|
|
4135
4643
|
const yp = rk * Math.sin(uk);
|
|
4644
|
+
const xpDot = drkDot * Math.cos(uk) - rk * ukDot * Math.sin(uk);
|
|
4645
|
+
const ypDot = drkDot * Math.sin(uk) + rk * ukDot * Math.cos(uk);
|
|
4136
4646
|
const isBdsGeo = eph.system === "C" && Math.abs(eph.i0) < BDS_GEO_MAX_INCLINATION_RAD && a > BDS_GEO_MIN_SEMIMAJOR_AXIS_M;
|
|
4137
4647
|
if (isBdsGeo) {
|
|
4138
4648
|
const omegak2 = eph.omega0 + eph.omegaDot * tk - OMEGA_E * eph.toe;
|
|
@@ -4148,23 +4658,43 @@ function keplerPosition(eph, t) {
|
|
|
4148
4658
|
const sinPhi = Math.sin(phi);
|
|
4149
4659
|
const COS5 = Math.cos(-5 * Math.PI / 180);
|
|
4150
4660
|
const SIN5 = Math.sin(-5 * Math.PI / 180);
|
|
4661
|
+
const px = xg * cosPhi + yg * sinPhi * COS5 + zg * sinPhi * SIN5;
|
|
4662
|
+
const py = -xg * sinPhi + yg * cosPhi * COS5 + zg * cosPhi * SIN5;
|
|
4663
|
+
const pz = -yg * SIN5 + zg * COS5;
|
|
4664
|
+
if (geoVelocityPass) {
|
|
4665
|
+
return { prn: eph.prn, x: px, y: py, z: pz, vx: 0, vy: 0, vz: 0 };
|
|
4666
|
+
}
|
|
4667
|
+
geoVelocityPass = true;
|
|
4668
|
+
const h = 0.5;
|
|
4669
|
+
const pm = keplerPosition(eph, t - h);
|
|
4670
|
+
const pp = keplerPosition(eph, t + h);
|
|
4671
|
+
geoVelocityPass = false;
|
|
4151
4672
|
return {
|
|
4152
4673
|
prn: eph.prn,
|
|
4153
|
-
x:
|
|
4154
|
-
y:
|
|
4155
|
-
z:
|
|
4674
|
+
x: px,
|
|
4675
|
+
y: py,
|
|
4676
|
+
z: pz,
|
|
4677
|
+
vx: (pp.x - pm.x) / (2 * h),
|
|
4678
|
+
vy: (pp.y - pm.y) / (2 * h),
|
|
4679
|
+
vz: (pp.z - pm.z) / (2 * h)
|
|
4156
4680
|
};
|
|
4157
4681
|
}
|
|
4158
4682
|
const omegak = eph.omega0 + (eph.omegaDot - OMEGA_E) * tk - OMEGA_E * eph.toe;
|
|
4683
|
+
const omegakDot = eph.omegaDot - OMEGA_E;
|
|
4159
4684
|
const cosO = Math.cos(omegak);
|
|
4160
4685
|
const sinO = Math.sin(omegak);
|
|
4161
4686
|
const cosI = Math.cos(ik);
|
|
4162
4687
|
const sinI = Math.sin(ik);
|
|
4688
|
+
const x = xp * cosO - yp * cosI * sinO;
|
|
4689
|
+
const y = xp * sinO + yp * cosI * cosO;
|
|
4163
4690
|
return {
|
|
4164
4691
|
prn: eph.prn,
|
|
4165
|
-
x
|
|
4166
|
-
y
|
|
4167
|
-
z: yp * sinI
|
|
4692
|
+
x,
|
|
4693
|
+
y,
|
|
4694
|
+
z: yp * sinI,
|
|
4695
|
+
vx: xpDot * cosO - ypDot * cosI * sinO + yp * sinI * sinO * dikDot - omegakDot * y,
|
|
4696
|
+
vy: xpDot * sinO + ypDot * cosI * cosO - yp * sinI * cosO * dikDot + omegakDot * x,
|
|
4697
|
+
vz: ypDot * sinI + yp * cosI * dikDot
|
|
4168
4698
|
};
|
|
4169
4699
|
}
|
|
4170
4700
|
function gloDerivatives(state, acc) {
|
|
@@ -4218,7 +4748,25 @@ function glonassPosition(eph, tUtc) {
|
|
|
4218
4748
|
if (Math.abs(remainder) > 1e-3) {
|
|
4219
4749
|
state = rk4Step(state, acc, remainder);
|
|
4220
4750
|
}
|
|
4221
|
-
return {
|
|
4751
|
+
return {
|
|
4752
|
+
prn: eph.prn,
|
|
4753
|
+
x: state[0],
|
|
4754
|
+
y: state[1],
|
|
4755
|
+
z: state[2],
|
|
4756
|
+
vx: state[3],
|
|
4757
|
+
vy: state[4],
|
|
4758
|
+
vz: state[5]
|
|
4759
|
+
};
|
|
4760
|
+
}
|
|
4761
|
+
function rangeRate(sat, rx, rxVel = [0, 0, 0]) {
|
|
4762
|
+
const dx = sat.x - rx[0];
|
|
4763
|
+
const dy = sat.y - rx[1];
|
|
4764
|
+
const dz = sat.z - rx[2];
|
|
4765
|
+
const rho = Math.hypot(dx, dy, dz);
|
|
4766
|
+
return ((sat.vx - rxVel[0]) * dx + (sat.vy - rxVel[1]) * dy + (sat.vz - rxVel[2]) * dz) / rho;
|
|
4767
|
+
}
|
|
4768
|
+
function dopplerHz(rangeRateMs, freqHz) {
|
|
4769
|
+
return -rangeRateMs * freqHz / C_LIGHT;
|
|
4222
4770
|
}
|
|
4223
4771
|
function ecefToAzEl(rxX, rxY, rxZ, satX, satY, satZ) {
|
|
4224
4772
|
const [lat, lon] = ecefToGeodetic(rxX, rxY, rxZ);
|
|
@@ -4837,6 +5385,37 @@ function dateToEpoch(date) {
|
|
|
4837
5385
|
return year + (date.getTime() - start) / (end - start);
|
|
4838
5386
|
}
|
|
4839
5387
|
|
|
5388
|
+
// src/positioning/klobuchar.ts
|
|
5389
|
+
function klobucharDelay(coeffs, latRad, lonRad, azRad, elRad, gpsTowSec) {
|
|
5390
|
+
const { alpha, beta } = coeffs;
|
|
5391
|
+
if (alpha.length < 4 || beta.length < 4) return 0;
|
|
5392
|
+
const E = elRad / Math.PI;
|
|
5393
|
+
const phiU = latRad / Math.PI;
|
|
5394
|
+
const lambdaU = lonRad / Math.PI;
|
|
5395
|
+
const psi = 0.0137 / (E + 0.11) - 0.022;
|
|
5396
|
+
let phiI = phiU + psi * Math.cos(azRad);
|
|
5397
|
+
if (phiI > 0.416) phiI = 0.416;
|
|
5398
|
+
else if (phiI < -0.416) phiI = -0.416;
|
|
5399
|
+
const lambdaI = lambdaU + psi * Math.sin(azRad) / Math.cos(phiI * Math.PI);
|
|
5400
|
+
const phiM = phiI + 0.064 * Math.cos((lambdaI - 1.617) * Math.PI);
|
|
5401
|
+
let t = 43200 * lambdaI + gpsTowSec;
|
|
5402
|
+
t %= 86400;
|
|
5403
|
+
if (t < 0) t += 86400;
|
|
5404
|
+
let amp = 0;
|
|
5405
|
+
let per = 0;
|
|
5406
|
+
for (let n = 3; n >= 0; n--) {
|
|
5407
|
+
amp = amp * phiM + alpha[n];
|
|
5408
|
+
per = per * phiM + beta[n];
|
|
5409
|
+
}
|
|
5410
|
+
if (amp < 0) amp = 0;
|
|
5411
|
+
if (per < 72e3) per = 72e3;
|
|
5412
|
+
const F = 1 + 16 * Math.pow(0.53 - E, 3);
|
|
5413
|
+
const x = 2 * Math.PI * (t - 50400) / per;
|
|
5414
|
+
if (Math.abs(x) >= 1.57) return F * 5e-9;
|
|
5415
|
+
const x2 = x * x;
|
|
5416
|
+
return F * (5e-9 + amp * (1 - x2 / 2 + x2 * x2 / 24));
|
|
5417
|
+
}
|
|
5418
|
+
|
|
4840
5419
|
// src/positioning/index.ts
|
|
4841
5420
|
var GM_GPS2 = 3986005e8;
|
|
4842
5421
|
var F_REL = -4442807633e-19;
|
|
@@ -4863,6 +5442,16 @@ function ionoFree(p1, p2, f1, f2) {
|
|
|
4863
5442
|
const g = f1 * f1 / (f1 * f1 - f2 * f2);
|
|
4864
5443
|
return g * p1 - (g - 1) * p2;
|
|
4865
5444
|
}
|
|
5445
|
+
var GPS_EPOCH_MS_SPP = Date.UTC(1980, 0, 6);
|
|
5446
|
+
var PRIMARY_FREQ_HZ = {
|
|
5447
|
+
G: 157542e4,
|
|
5448
|
+
E: 157542e4,
|
|
5449
|
+
J: 157542e4,
|
|
5450
|
+
S: 157542e4,
|
|
5451
|
+
C: 1561098e3,
|
|
5452
|
+
R: 1602e6
|
|
5453
|
+
};
|
|
5454
|
+
var F_L1 = 157542e4;
|
|
4866
5455
|
function tropoDelay(elevationRad) {
|
|
4867
5456
|
const sinEl = Math.sin(elevationRad);
|
|
4868
5457
|
return 2.47 / (sinEl + 0.0121);
|
|
@@ -4897,8 +5486,10 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
4897
5486
|
troposphere = true,
|
|
4898
5487
|
maxIterations = 15,
|
|
4899
5488
|
convergenceM = 1e-4,
|
|
4900
|
-
tgd = true
|
|
5489
|
+
tgd = true,
|
|
5490
|
+
iono
|
|
4901
5491
|
} = opts;
|
|
5492
|
+
const gpsTow = (timeMs - GPS_EPOCH_MS_SPP) / 1e3 % 604800;
|
|
4902
5493
|
const all = [...pseudoranges.keys()].filter((p) => ephemerides.has(p));
|
|
4903
5494
|
const minSats = (list) => 3 + new Set(list.map((p) => p[0])).size;
|
|
4904
5495
|
if (all.length < minSats(all)) return null;
|
|
@@ -4922,6 +5513,8 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
4922
5513
|
const Htv = new Array(dim).fill(0);
|
|
4923
5514
|
let rows = 0;
|
|
4924
5515
|
for (const k of Object.keys(residuals2)) delete residuals2[k];
|
|
5516
|
+
const positionSaneIter = x2 * x2 + y2 * y2 + z2 * z2 > 1e12;
|
|
5517
|
+
const [rxLat, rxLon] = positionSaneIter ? ecefToGeodetic(x2, y2, z2) : [0, 0];
|
|
4925
5518
|
for (const prn of prns) {
|
|
4926
5519
|
const psr = pseudoranges.get(prn);
|
|
4927
5520
|
const eph = ephemerides.get(prn);
|
|
@@ -4940,17 +5533,24 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
4940
5533
|
const uy = (y2 - sy) / rho;
|
|
4941
5534
|
const uz = (z2 - sz) / rho;
|
|
4942
5535
|
let elev = Math.PI / 2;
|
|
5536
|
+
let azim = 0;
|
|
4943
5537
|
let weight = 1;
|
|
4944
|
-
const positionSane =
|
|
5538
|
+
const positionSane = positionSaneIter;
|
|
4945
5539
|
if (positionSane) {
|
|
4946
5540
|
const azel = ecefToAzEl(x2, y2, z2, sx, sy, sz);
|
|
4947
5541
|
elev = azel.el;
|
|
5542
|
+
azim = azel.az;
|
|
4948
5543
|
if (iter >= 2 && elev < elevationMaskDeg * Math.PI / 180) continue;
|
|
4949
5544
|
const sinEl = Math.max(Math.sin(elev), 0.1);
|
|
4950
5545
|
weight = sinEl * sinEl;
|
|
4951
5546
|
}
|
|
4952
5547
|
const tropo = troposphere && positionSane ? tropoDelay(elev) : 0;
|
|
4953
|
-
|
|
5548
|
+
let ionoM = 0;
|
|
5549
|
+
if (iono && positionSane) {
|
|
5550
|
+
const f = PRIMARY_FREQ_HZ[sys] ?? F_L1;
|
|
5551
|
+
ionoM = C_LIGHT * klobucharDelay(iono, rxLat, rxLon, azim, elev, gpsTow) * (F_L1 / f * (F_L1 / f));
|
|
5552
|
+
}
|
|
5553
|
+
const predicted = rho + clk - C_LIGHT * dts + tropo + ionoM;
|
|
4954
5554
|
const v = psr - predicted;
|
|
4955
5555
|
const h = new Array(dim).fill(0);
|
|
4956
5556
|
h[0] = ux;
|
|
@@ -7386,6 +7986,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
7386
7986
|
computeStats,
|
|
7387
7987
|
computeVisibility,
|
|
7388
7988
|
connectToMountpoint,
|
|
7989
|
+
createGzipLineSink,
|
|
7389
7990
|
createStationMeta,
|
|
7390
7991
|
createStreamStats,
|
|
7391
7992
|
crxDecompress,
|
|
@@ -7396,6 +7997,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
7396
7997
|
deg2dms,
|
|
7397
7998
|
deg2rad,
|
|
7398
7999
|
detrendIonoArcs,
|
|
8000
|
+
dopplerHz,
|
|
7399
8001
|
ecefToAzEl,
|
|
7400
8002
|
ecefToGeodetic,
|
|
7401
8003
|
ephInfoToEphemeris,
|
|
@@ -7468,6 +8070,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
7468
8070
|
horizonDistance,
|
|
7469
8071
|
ionoFree,
|
|
7470
8072
|
keplerPosition,
|
|
8073
|
+
klobucharDelay,
|
|
7471
8074
|
maskRadForAzimuth,
|
|
7472
8075
|
msmEpochToDate,
|
|
7473
8076
|
navTimesFromEph,
|
|
@@ -7482,11 +8085,13 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
7482
8085
|
parseRinexStream,
|
|
7483
8086
|
parseSinexBiasDcb,
|
|
7484
8087
|
parseSourcetable,
|
|
8088
|
+
parseSp3,
|
|
7485
8089
|
phiAltBOC,
|
|
7486
8090
|
phiBOCc,
|
|
7487
8091
|
phiBOCs,
|
|
7488
8092
|
phiBPSK,
|
|
7489
8093
|
rad2deg,
|
|
8094
|
+
rangeRate,
|
|
7490
8095
|
readString,
|
|
7491
8096
|
reportDecodeError,
|
|
7492
8097
|
resetGloFreqCache,
|
|
@@ -7497,6 +8102,8 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
7497
8102
|
setGloFreqNumber,
|
|
7498
8103
|
setRtcm3DebugHandler,
|
|
7499
8104
|
solveSpp,
|
|
8105
|
+
sp3Position,
|
|
8106
|
+
stationHeaderLines,
|
|
7500
8107
|
systemCmp,
|
|
7501
8108
|
systemName,
|
|
7502
8109
|
transformFrame,
|
|
@@ -7504,5 +8111,9 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
7504
8111
|
updateStreamStats,
|
|
7505
8112
|
verifyChecksum,
|
|
7506
8113
|
vincenty,
|
|
7507
|
-
|
|
8114
|
+
writeModernObsBlob,
|
|
8115
|
+
writeRinex2ObsBlob,
|
|
8116
|
+
writeRinex4ObsBlob,
|
|
8117
|
+
writeRinexNav,
|
|
8118
|
+
writeRinexObsBlob
|
|
7508
8119
|
});
|