gnss-js 1.11.0 → 1.13.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,7 +117,9 @@ __export(src_exports, {
117
117
  computeSatPosition: () => computeSatPosition,
118
118
  computeStats: () => computeStats2,
119
119
  computeVisibility: () => computeVisibility,
120
+ computeVisibilityFromPositions: () => computeVisibilityFromPositions,
120
121
  connectToMountpoint: () => connectToMountpoint,
122
+ createGzipLineSink: () => createGzipLineSink,
121
123
  createStationMeta: () => createStationMeta,
122
124
  createStreamStats: () => createStreamStats,
123
125
  crxDecompress: () => crxDecompress,
@@ -216,6 +218,7 @@ __export(src_exports, {
216
218
  parseRinexStream: () => parseRinexStream,
217
219
  parseSinexBiasDcb: () => parseSinexBiasDcb,
218
220
  parseSourcetable: () => parseSourcetable,
221
+ parseSp3: () => parseSp3,
219
222
  phiAltBOC: () => phiAltBOC,
220
223
  phiBOCc: () => phiBOCc,
221
224
  phiBOCs: () => phiBOCs,
@@ -232,6 +235,8 @@ __export(src_exports, {
232
235
  setGloFreqNumber: () => setGloFreqNumber,
233
236
  setRtcm3DebugHandler: () => setRtcm3DebugHandler,
234
237
  solveSpp: () => solveSpp,
238
+ sp3Position: () => sp3Position,
239
+ stationHeaderLines: () => stationHeaderLines,
235
240
  systemCmp: () => systemCmp,
236
241
  systemName: () => systemName,
237
242
  transformFrame: () => transformFrame,
@@ -239,7 +244,11 @@ __export(src_exports, {
239
244
  updateStreamStats: () => updateStreamStats,
240
245
  verifyChecksum: () => verifyChecksum,
241
246
  vincenty: () => vincenty,
242
- writeRinexNav: () => writeRinexNav
247
+ writeModernObsBlob: () => writeModernObsBlob,
248
+ writeRinex2ObsBlob: () => writeRinex2ObsBlob,
249
+ writeRinex4ObsBlob: () => writeRinex4ObsBlob,
250
+ writeRinexNav: () => writeRinexNav,
251
+ writeRinexObsBlob: () => writeRinexObsBlob
243
252
  });
244
253
  module.exports = __toCommonJS(src_exports);
245
254
 
@@ -2665,6 +2674,496 @@ function parseIonex(text) {
2665
2674
  return { epochs, lats, lons, maps };
2666
2675
  }
2667
2676
 
2677
+ // src/rinex/sp3.ts
2678
+ var BAD_CLOCK = 999999.999999;
2679
+ function parseSp3(text) {
2680
+ const lines = text.split("\n");
2681
+ const epochs = [];
2682
+ const satellites = {};
2683
+ let version = "";
2684
+ let intervalSec = 0;
2685
+ let timeSystem = "GPS";
2686
+ let timeSystemSet = false;
2687
+ let epochIdx = -1;
2688
+ for (const line of lines) {
2689
+ if (!version && line.startsWith("#") && line.charAt(1) !== "#") {
2690
+ version = line.charAt(1);
2691
+ }
2692
+ if (line.startsWith("##")) {
2693
+ const f = line.slice(2).trim().split(/\s+/);
2694
+ intervalSec = Number(f[2]) || 0;
2695
+ } else if (line.startsWith("%c") && !timeSystemSet) {
2696
+ const sys = line.slice(9, 12).trim();
2697
+ if (sys && !/^c+$/.test(sys)) {
2698
+ timeSystem = sys;
2699
+ timeSystemSet = true;
2700
+ }
2701
+ } else if (line.startsWith("*")) {
2702
+ const f = line.slice(1).trim().split(/\s+/).map(Number);
2703
+ if (f.length >= 6 && f.every(Number.isFinite)) {
2704
+ const sec = f[5];
2705
+ epochs.push(
2706
+ Date.UTC(
2707
+ f[0],
2708
+ f[1] - 1,
2709
+ f[2],
2710
+ f[3],
2711
+ f[4],
2712
+ Math.floor(sec),
2713
+ Math.round(sec % 1 * 1e3)
2714
+ )
2715
+ );
2716
+ epochIdx++;
2717
+ }
2718
+ } else if (line.startsWith("P") && epochIdx >= 0) {
2719
+ const prn = line.slice(1, 4).replace(/\s/g, "0");
2720
+ const f = line.slice(4).trim().split(/\s+/).map(Number);
2721
+ if (f.length < 3) continue;
2722
+ const [xKm, yKm, zKm] = f;
2723
+ let arr = satellites[prn];
2724
+ if (!arr) satellites[prn] = arr = [];
2725
+ while (arr.length < epochIdx) arr.push(null);
2726
+ if (xKm === 0 && yKm === 0 && zKm === 0) {
2727
+ arr.push(null);
2728
+ continue;
2729
+ }
2730
+ const clkUs = f[3];
2731
+ arr.push({
2732
+ x: xKm * 1e3,
2733
+ y: yKm * 1e3,
2734
+ z: zKm * 1e3,
2735
+ clk: clkUs !== void 0 && Math.abs(clkUs) < BAD_CLOCK ? clkUs * 1e-6 : null
2736
+ });
2737
+ }
2738
+ }
2739
+ for (const arr of Object.values(satellites)) {
2740
+ while (arr.length < epochs.length) arr.push(null);
2741
+ }
2742
+ return { version, epochs, intervalSec, timeSystem, satellites };
2743
+ }
2744
+ function sp3Position(sp3, prn, tMs, order = 9) {
2745
+ const samples = sp3.satellites[prn];
2746
+ const { epochs } = sp3;
2747
+ const n = epochs.length;
2748
+ if (!samples || n < order) return null;
2749
+ if (tMs < epochs[0] || tMs > epochs[n - 1]) return null;
2750
+ let lo = 0;
2751
+ let hi = n - 1;
2752
+ while (lo < hi) {
2753
+ const mid = lo + hi + 1 >> 1;
2754
+ if (epochs[mid] <= tMs) lo = mid;
2755
+ else hi = mid - 1;
2756
+ }
2757
+ let start = lo - (order >> 1) + (order % 2 === 0 ? 1 : 0);
2758
+ start = Math.max(0, Math.min(n - order, start));
2759
+ for (let i = start; i < start + order; i++) {
2760
+ if (!samples[i]) return null;
2761
+ }
2762
+ const t0 = epochs[start];
2763
+ const t = (tMs - t0) / 1e3;
2764
+ let x = 0;
2765
+ let y = 0;
2766
+ let z = 0;
2767
+ for (let i = 0; i < order; i++) {
2768
+ const ti = (epochs[start + i] - t0) / 1e3;
2769
+ let w = 1;
2770
+ for (let j = 0; j < order; j++) {
2771
+ if (j === i) continue;
2772
+ const tj = (epochs[start + j] - t0) / 1e3;
2773
+ w *= (t - tj) / (ti - tj);
2774
+ }
2775
+ const s = samples[start + i];
2776
+ x += w * s.x;
2777
+ y += w * s.y;
2778
+ z += w * s.z;
2779
+ }
2780
+ let clk = null;
2781
+ const a = samples[lo];
2782
+ const b = samples[Math.min(lo + 1, n - 1)];
2783
+ if (a?.clk != null && b?.clk != null) {
2784
+ const span = epochs[Math.min(lo + 1, n - 1)] - epochs[lo];
2785
+ const f = span > 0 ? (tMs - epochs[lo]) / span : 0;
2786
+ clk = a.clk * (1 - f) + b.clk * f;
2787
+ } else if (a?.clk != null) {
2788
+ clk = a.clk;
2789
+ }
2790
+ return { x, y, z, clk };
2791
+ }
2792
+
2793
+ // src/rinex/obs-writer-common.ts
2794
+ function createGzipLineSink() {
2795
+ const encoder = new TextEncoder();
2796
+ const compressor = new CompressionStream("gzip");
2797
+ const writer = compressor.writable.getWriter();
2798
+ const compressedChunks = [];
2799
+ const readerDone = (async () => {
2800
+ const reader = compressor.readable.getReader();
2801
+ for (; ; ) {
2802
+ const { done, value } = await reader.read();
2803
+ if (done) break;
2804
+ compressedChunks.push(value);
2805
+ }
2806
+ })();
2807
+ let batch = [];
2808
+ async function flush() {
2809
+ if (batch.length === 0) return;
2810
+ await writer.write(encoder.encode(batch.join("\n") + "\n"));
2811
+ batch = [];
2812
+ }
2813
+ return {
2814
+ push(line) {
2815
+ batch.push(line);
2816
+ },
2817
+ flush,
2818
+ async finish() {
2819
+ await flush();
2820
+ await writer.close();
2821
+ await readerDone;
2822
+ return new Blob(compressedChunks, {
2823
+ type: "application/gzip"
2824
+ });
2825
+ }
2826
+ };
2827
+ }
2828
+ function stationHeaderLines(header) {
2829
+ const pos = header.approxPosition ?? [0, 0, 0];
2830
+ const delta = header.antDelta ?? [0, 0, 0];
2831
+ return [
2832
+ hdrLine(header.markerName || "UNKNOWN", "MARKER NAME"),
2833
+ hdrLine("", "MARKER NUMBER"),
2834
+ hdrLine(
2835
+ `${padL(header.observer || "", 20)}${padL(header.agency || "", 40)}`,
2836
+ "OBSERVER / AGENCY"
2837
+ ),
2838
+ hdrLine(
2839
+ `${padL(header.receiverNumber || "", 20)}${padL(header.receiverType || "", 20)}${padL(header.receiverVersion || "", 20)}`,
2840
+ "REC # / TYPE / VERS"
2841
+ ),
2842
+ hdrLine(
2843
+ `${padL(header.antNumber || "", 20)}${padL(header.antType || "", 20)}`,
2844
+ "ANT # / TYPE"
2845
+ ),
2846
+ hdrLine(
2847
+ `${fmtF(pos[0], 14, 4)}${fmtF(pos[1], 14, 4)}${fmtF(pos[2], 14, 4)}`,
2848
+ "APPROX POSITION XYZ"
2849
+ ),
2850
+ hdrLine(
2851
+ `${fmtF(delta[0], 14, 4)}${fmtF(delta[1], 14, 4)}${fmtF(delta[2], 14, 4)}`,
2852
+ "ANTENNA: DELTA H/E/N"
2853
+ )
2854
+ ];
2855
+ }
2856
+
2857
+ // src/rinex/obs-writer.ts
2858
+ function writeRinexObsBlob(header, epochs, obsTypes) {
2859
+ return writeModernObsBlob(header, epochs, obsTypes, {
2860
+ version: "3.04",
2861
+ comment: "Merged from multiple RINEX files"
2862
+ });
2863
+ }
2864
+ async function writeModernObsBlob(header, epochs, obsTypes, opts) {
2865
+ if (epochs.length === 0) return new Blob([], { type: "application/gzip" });
2866
+ const sink = createGzipLineSink();
2867
+ const BATCH = 200;
2868
+ const systems = [...obsTypes.keys()];
2869
+ const sysChar = systems.length === 1 ? systems[0] : "M";
2870
+ sink.push(
2871
+ hdrLine(
2872
+ ` ${opts.version} OBSERVATION DATA ${sysChar}`,
2873
+ "RINEX VERSION / TYPE"
2874
+ )
2875
+ );
2876
+ const now = /* @__PURE__ */ new Date();
2877
+ 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`;
2878
+ sink.push(
2879
+ hdrLine(
2880
+ `${padL("GNSSCalc", 20)}${padL("", 20)}${dateStr}`,
2881
+ "PGM / RUN BY / DATE"
2882
+ )
2883
+ );
2884
+ sink.push(hdrLine(opts.comment, "COMMENT"));
2885
+ for (const line of stationHeaderLines(header)) sink.push(line);
2886
+ for (const [sys, types] of obsTypes) {
2887
+ for (let i = 0; i < types.length; i += 13) {
2888
+ const chunk = types.slice(i, i + 13);
2889
+ let content;
2890
+ if (i === 0) {
2891
+ content = `${sys} ${padR(String(types.length), 3)}`;
2892
+ } else {
2893
+ content = " ";
2894
+ }
2895
+ content += chunk.map((t) => ` ${padL(t, 3)}`).join("");
2896
+ sink.push(hdrLine(content, "SYS / # / OBS TYPES"));
2897
+ }
2898
+ }
2899
+ const timeSys = systems.includes("R") && systems.length === 1 ? "GLO" : "GPS";
2900
+ 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}`;
2901
+ sink.push(
2902
+ hdrLine(obsTimeLine(new Date(epochs[0].time)), "TIME OF FIRST OBS")
2903
+ );
2904
+ sink.push(
2905
+ hdrLine(
2906
+ obsTimeLine(new Date(epochs[epochs.length - 1].time)),
2907
+ "TIME OF LAST OBS"
2908
+ )
2909
+ );
2910
+ if (epochs.length >= 2) {
2911
+ const interval = (epochs[1].time - epochs[0].time) / 1e3;
2912
+ if (interval > 0 && interval < 3600) {
2913
+ sink.push(hdrLine(fmtF(interval, 10, 3), "INTERVAL"));
2914
+ }
2915
+ }
2916
+ if (header.glonassSlots && Object.keys(header.glonassSlots).length > 0) {
2917
+ const entries = Object.entries(header.glonassSlots).sort(
2918
+ ([a], [b]) => Number(a) - Number(b)
2919
+ );
2920
+ for (let i = 0; i < entries.length; i += 8) {
2921
+ const chunk = entries.slice(i, i + 8);
2922
+ let content = i === 0 ? padR(String(entries.length), 3) + " " : " ";
2923
+ for (const [slot, freq] of chunk) {
2924
+ content += `R${padR(slot, 2)} ${padR(String(freq), 2)} `;
2925
+ }
2926
+ sink.push(hdrLine(content, "GLONASS SLOT / FRQ #"));
2927
+ }
2928
+ }
2929
+ sink.push(hdrLine("", "END OF HEADER"));
2930
+ await sink.flush();
2931
+ let epochCount = 0;
2932
+ for (const epoch of epochs) {
2933
+ const t = new Date(epoch.time);
2934
+ const sec = t.getUTCSeconds() + t.getUTCMilliseconds() / 1e3;
2935
+ const prns = [...epoch.sats.keys()].sort();
2936
+ sink.push(
2937
+ `> ${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)}`
2938
+ );
2939
+ for (const prn of prns) {
2940
+ const sys = prn[0];
2941
+ const sysTypes = obsTypes.get(sys);
2942
+ if (!sysTypes) continue;
2943
+ const valArr = epoch.sats.get(prn);
2944
+ let line = prn;
2945
+ for (let i = 0; i < sysTypes.length; i++) {
2946
+ const val = i < valArr.length ? valArr[i] : NaN;
2947
+ if (!isNaN(val)) {
2948
+ line += fmtF(val, 14, 3) + " ";
2949
+ } else {
2950
+ line += " ".repeat(16);
2951
+ }
2952
+ }
2953
+ sink.push(line);
2954
+ }
2955
+ epochCount++;
2956
+ if (epochCount % BATCH === 0) await sink.flush();
2957
+ }
2958
+ return sink.finish();
2959
+ }
2960
+
2961
+ // src/rinex/obs-writer-v2.ts
2962
+ var V3_TO_V2 = {
2963
+ // GPS
2964
+ C1C: "C1",
2965
+ C1S: "C1",
2966
+ C1L: "C1",
2967
+ C1X: "C1",
2968
+ C1W: "P1",
2969
+ C1P: "P1",
2970
+ C2C: "C2",
2971
+ C2S: "P2",
2972
+ C2L: "P2",
2973
+ C2X: "P2",
2974
+ C2W: "P2",
2975
+ C2P: "P2",
2976
+ C5I: "C5",
2977
+ C5Q: "C5",
2978
+ C5X: "C5",
2979
+ L1C: "L1",
2980
+ L1S: "L1",
2981
+ L1L: "L1",
2982
+ L1X: "L1",
2983
+ L1W: "L1",
2984
+ L1P: "L1",
2985
+ L2C: "L2",
2986
+ L2S: "L2",
2987
+ L2L: "L2",
2988
+ L2X: "L2",
2989
+ L2W: "L2",
2990
+ L2P: "L2",
2991
+ L5I: "L5",
2992
+ L5Q: "L5",
2993
+ L5X: "L5",
2994
+ D1C: "D1",
2995
+ D1S: "D1",
2996
+ D1L: "D1",
2997
+ D1X: "D1",
2998
+ D1W: "D1",
2999
+ D1P: "D1",
3000
+ D2C: "D2",
3001
+ D2S: "D2",
3002
+ D2L: "D2",
3003
+ D2X: "D2",
3004
+ D2W: "D2",
3005
+ D2P: "D2",
3006
+ D5I: "D5",
3007
+ D5Q: "D5",
3008
+ D5X: "D5",
3009
+ S1C: "S1",
3010
+ S1S: "S1",
3011
+ S1L: "S1",
3012
+ S1X: "S1",
3013
+ S1W: "S1",
3014
+ S1P: "S1",
3015
+ S2C: "S2",
3016
+ S2S: "S2",
3017
+ S2L: "S2",
3018
+ S2X: "S2",
3019
+ S2W: "S2",
3020
+ S2P: "S2",
3021
+ S5I: "S5",
3022
+ S5Q: "S5",
3023
+ S5X: "S5"
3024
+ };
3025
+ function v3ToV2Code(code3) {
3026
+ return V3_TO_V2[code3] ?? null;
3027
+ }
3028
+ async function writeRinex2ObsBlob(header, epochs, obsTypes) {
3029
+ if (epochs.length === 0) return new Blob([], { type: "application/gzip" });
3030
+ const gpsCodes = obsTypes.get("G") ?? obsTypes.get("R") ?? [];
3031
+ const v2Codes = [];
3032
+ const v2CodeSet = /* @__PURE__ */ new Set();
3033
+ const v3ToV2Map = /* @__PURE__ */ new Map();
3034
+ for (const code3 of gpsCodes) {
3035
+ const code2 = v3ToV2Code(code3);
3036
+ if (!code2) continue;
3037
+ if (!v2CodeSet.has(code2)) {
3038
+ v2CodeSet.add(code2);
3039
+ v3ToV2Map.set(code3, v2Codes.length);
3040
+ v2Codes.push(code2);
3041
+ } else {
3042
+ v3ToV2Map.set(code3, v2Codes.indexOf(code2));
3043
+ }
3044
+ }
3045
+ const gloCodes = obsTypes.get("R") ?? [];
3046
+ for (const code3 of gloCodes) {
3047
+ const code2 = v3ToV2Code(code3);
3048
+ if (!code2) continue;
3049
+ if (!v2CodeSet.has(code2)) {
3050
+ v2CodeSet.add(code2);
3051
+ v3ToV2Map.set(code3, v2Codes.length);
3052
+ v2Codes.push(code2);
3053
+ } else if (!v3ToV2Map.has(code3)) {
3054
+ v3ToV2Map.set(code3, v2Codes.indexOf(code2));
3055
+ }
3056
+ }
3057
+ const sink = createGzipLineSink();
3058
+ const BATCH = 200;
3059
+ const hasSystems = /* @__PURE__ */ new Set();
3060
+ for (const epoch of epochs) {
3061
+ for (const prn of epoch.sats.keys()) {
3062
+ const sys = prn[0];
3063
+ if (sys === "G" || sys === "R") hasSystems.add(sys);
3064
+ }
3065
+ }
3066
+ const sysChar = hasSystems.has("G") && hasSystems.has("R") ? "M" : hasSystems.has("R") ? "R" : "G";
3067
+ sink.push(
3068
+ hdrLine(
3069
+ ` 2.11 OBSERVATION DATA ${sysChar}`,
3070
+ "RINEX VERSION / TYPE"
3071
+ )
3072
+ );
3073
+ const now = /* @__PURE__ */ new Date();
3074
+ 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")}`;
3075
+ sink.push(
3076
+ hdrLine(
3077
+ `${padL("GNSSCalc", 20)}${padL("", 20)}${dateStr}`,
3078
+ "PGM / RUN BY / DATE"
3079
+ )
3080
+ );
3081
+ sink.push(hdrLine("Converted from RINEX 3 by GNSSCalc", "COMMENT"));
3082
+ for (const line of stationHeaderLines(header)) sink.push(line);
3083
+ sink.push(hdrLine(" 1 1", "WAVELENGTH FACT L1/2"));
3084
+ for (let i = 0; i < v2Codes.length; i += 9) {
3085
+ const chunk = v2Codes.slice(i, i + 9);
3086
+ let content;
3087
+ if (i === 0) {
3088
+ content = padR(String(v2Codes.length), 6);
3089
+ } else {
3090
+ content = " ";
3091
+ }
3092
+ content += chunk.map((c) => padR(c, 6)).join("");
3093
+ sink.push(hdrLine(content, "# / TYPES OF OBSERV"));
3094
+ }
3095
+ const first = new Date(epochs[0].time);
3096
+ const timeSys = sysChar === "R" ? "GLO" : "GPS";
3097
+ sink.push(
3098
+ hdrLine(
3099
+ ` ${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}`,
3100
+ "TIME OF FIRST OBS"
3101
+ )
3102
+ );
3103
+ sink.push(hdrLine("", "END OF HEADER"));
3104
+ await sink.flush();
3105
+ let epochCount = 0;
3106
+ for (const epoch of epochs) {
3107
+ const t = new Date(epoch.time);
3108
+ const sec = t.getUTCSeconds() + t.getUTCMilliseconds() / 1e3;
3109
+ const prns = [...epoch.sats.keys()].filter((p) => p[0] === "G" || p[0] === "R").sort();
3110
+ if (prns.length === 0) continue;
3111
+ const yy = t.getUTCFullYear() % 100;
3112
+ const yyS = padR(String(yy), 2);
3113
+ const moS = padR(String(t.getUTCMonth() + 1), 2);
3114
+ const ddS = padR(String(t.getUTCDate()), 2);
3115
+ const hhS = padR(String(t.getUTCHours()), 2);
3116
+ const mmS = padR(String(t.getUTCMinutes()), 2);
3117
+ const secS = fmtF(sec, 11, 7);
3118
+ const nSats = padR(String(prns.length), 3);
3119
+ let epochLine = ` ${yyS} ${moS} ${ddS} ${hhS} ${mmS}${secS} 0${nSats}`;
3120
+ for (let i = 0; i < prns.length; i++) {
3121
+ if (i > 0 && i % 12 === 0) {
3122
+ sink.push(epochLine);
3123
+ epochLine = " ".repeat(32);
3124
+ }
3125
+ epochLine += prns[i];
3126
+ }
3127
+ sink.push(epochLine);
3128
+ for (const prn of prns) {
3129
+ const sys = prn[0];
3130
+ const sysCodes3 = obsTypes.get(sys) ?? [];
3131
+ const valArr = epoch.sats.get(prn);
3132
+ const v2Vals = new Array(v2Codes.length).fill(NaN);
3133
+ for (let j = 0; j < sysCodes3.length; j++) {
3134
+ const v2Idx = v3ToV2Map.get(sysCodes3[j]);
3135
+ if (v2Idx != null && j < valArr.length && !isNaN(valArr[j])) {
3136
+ v2Vals[v2Idx] = valArr[j];
3137
+ }
3138
+ }
3139
+ let line = "";
3140
+ for (let j = 0; j < v2Codes.length; j++) {
3141
+ const val = v2Vals[j];
3142
+ if (!isNaN(val)) {
3143
+ line += fmtF(val, 14, 3) + " ";
3144
+ } else {
3145
+ line += " ".repeat(16);
3146
+ }
3147
+ if ((j + 1) % 5 === 0 || j === v2Codes.length - 1) {
3148
+ sink.push(line);
3149
+ line = "";
3150
+ }
3151
+ }
3152
+ }
3153
+ epochCount++;
3154
+ if (epochCount % BATCH === 0) await sink.flush();
3155
+ }
3156
+ return sink.finish();
3157
+ }
3158
+
3159
+ // src/rinex/obs-writer-v4.ts
3160
+ function writeRinex4ObsBlob(header, epochs, obsTypes) {
3161
+ return writeModernObsBlob(header, epochs, obsTypes, {
3162
+ version: "4.01",
3163
+ comment: "Converted to RINEX 4 by GNSSCalc"
3164
+ });
3165
+ }
3166
+
2668
3167
  // src/rtcm3/decoder.ts
2669
3168
  var debugHandler = null;
2670
3169
  function setRtcm3DebugHandler(fn) {
@@ -4585,8 +5084,14 @@ function computeVisibility(ephemerides, rxPos, startMs, endMs, stepSec = 300, el
4585
5084
  const stepMs = stepSec * 1e3;
4586
5085
  const times = [];
4587
5086
  for (let t = startMs; t <= endMs; t += stepMs) times.push(t);
5087
+ return computeVisibilityFromPositions(
5088
+ computeAllPositions(ephemerides, times, rxPos),
5089
+ elevationMaskDeg
5090
+ );
5091
+ }
5092
+ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
5093
+ const times = all.times;
4588
5094
  const maskRadFor = maskRadForAzimuth(elevationMaskDeg);
4589
- const all = computeAllPositions(ephemerides, times, rxPos);
4590
5095
  const elevation = {};
4591
5096
  const azimuth = {};
4592
5097
  const subLat = {};
@@ -7487,7 +7992,9 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
7487
7992
  computeSatPosition,
7488
7993
  computeStats,
7489
7994
  computeVisibility,
7995
+ computeVisibilityFromPositions,
7490
7996
  connectToMountpoint,
7997
+ createGzipLineSink,
7491
7998
  createStationMeta,
7492
7999
  createStreamStats,
7493
8000
  crxDecompress,
@@ -7586,6 +8093,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
7586
8093
  parseRinexStream,
7587
8094
  parseSinexBiasDcb,
7588
8095
  parseSourcetable,
8096
+ parseSp3,
7589
8097
  phiAltBOC,
7590
8098
  phiBOCc,
7591
8099
  phiBOCs,
@@ -7602,6 +8110,8 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
7602
8110
  setGloFreqNumber,
7603
8111
  setRtcm3DebugHandler,
7604
8112
  solveSpp,
8113
+ sp3Position,
8114
+ stationHeaderLines,
7605
8115
  systemCmp,
7606
8116
  systemName,
7607
8117
  transformFrame,
@@ -7609,5 +8119,9 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
7609
8119
  updateStreamStats,
7610
8120
  verifyChecksum,
7611
8121
  vincenty,
7612
- writeRinexNav
8122
+ writeModernObsBlob,
8123
+ writeRinex2ObsBlob,
8124
+ writeRinex4ObsBlob,
8125
+ writeRinexNav,
8126
+ writeRinexObsBlob
7613
8127
  });
package/dist/index.d.cts CHANGED
@@ -4,12 +4,12 @@ export { A as ARC_GAP_FACTOR, B as BAND_LABELS, a as BDS_SATELLITES, b as BdsSat
4
4
  export { Scale, getBdsTime, getDateFromBdsTime, getDateFromDayOfWeek, getDateFromDayOfYear, getDateFromGalTime, getDateFromGloN, getDateFromGpsData, getDateFromGpsTime, getDateFromHourCode, getDateFromJulianDate, getDateFromMJD, getDateFromMJD2000, getDateFromRINEX, getDateFromTai, getDateFromTimeOfDay, getDateFromTt, getDateFromUnixTime, getDateFromUtc, getDayOfWeek, getDayOfYear, getGalTime, getGloN4, getGloNA, getGpsLeap, getGpsTime, getHourCode, getHoursFromTimeDifference, getJulianDate, getLeap, getMJD, getMJD2000, getMinutesFromTimeDifference, getNtpTime, getRINEX, getSecondsFromTimeDifference, getTaiDate, getTimeDifference, getTimeDifferenceFromDays, getTimeDifferenceFromHours, getTimeDifferenceFromMinutes, getTimeDifferenceFromObject, getTimeDifferenceFromSeconds, getTimeOfDay, getTimeOfWeek, getTotalDaysFromTimeDifference, getTtDate, getUnixTime, getUtcDate, getWeekNumber, getWeekOfYear } from './time.cjs';
5
5
  export { deg2dms, deg2rad, euclidean3D, geodeticToGeohash, geodeticToMaidenhead, geodeticToUtm, greatCircleMidpoint, horizonDistance, rad2deg, rhumbLine, vincenty } from './coordinates.cjs';
6
6
  export { c as clampUnit, e as ecefToGeodetic, g as geodeticToEcef, a as getAer, b as getEnuDifference } from './ecef-CF0uAysr.cjs';
7
- export { CrxField, DiffState, EMPTY_WARNINGS, IonexGrid, RinexWarning, RinexWarnings, WarningAccumulator, WarningSeverity, crxDecompress, crxRepair, fmtF, hdrLine, padL, padR, parseCrxDataLine, parseIonex, writeRinexNav } from './rinex.cjs';
7
+ export { CompactEpoch, CrxField, DiffState, EMPTY_WARNINGS, IonexGrid, RinexWarning, RinexWarnings, Sp3File, Sp3Sample, WarningAccumulator, WarningSeverity, createGzipLineSink, crxDecompress, crxRepair, fmtF, hdrLine, padL, padR, parseCrxDataLine, parseIonex, parseSp3, sp3Position, stationHeaderLines, writeModernObsBlob, writeRinex2ObsBlob, writeRinex4ObsBlob, writeRinexNav, writeRinexObsBlob } from './rinex.cjs';
8
8
  export { E as EpochSummary, P as ParseOptions, R as RinexHeader, a as RinexResult, b as RinexStats, S as SYSTEM_ORDER, c as SatObsCallback, p as parseRinexStream, s as systemCmp, d as systemName } from './parser-JPjjFgeP.cjs';
9
9
  export { E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHeader, a as NavResult, p as parseNavFile } from './nav-BAI1a9vK.cjs';
10
10
  export { B as BitReader, E as EphemerisInfo, R as Rtcm3DebugHandler, a as Rtcm3Decoder, b as Rtcm3Frame, d as decodeEphemeris, r as readString, c as reportDecodeError, s as setRtcm3DebugHandler } from './ephemeris-Ohl6NAfw.cjs';
11
11
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.cjs';
12
- export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.cjs';
12
+ export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.cjs';
13
13
  export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.cjs';
14
14
  export { KlobucharCoeffs, SppOptions, SppSolution, ionoFree, klobucharDelay, satClockCorrection, solveSpp } from './positioning.cjs';
15
15
  export { NtripCaster, NtripConnectionInfo, NtripNetwork, NtripStream, NtripStreamConnection, NtripVersion, Sourcetable, SourcetableEntry, connectToMountpoint, fetchSourcetable, parseSourcetable } from './ntrip.cjs';
package/dist/index.d.ts CHANGED
@@ -4,12 +4,12 @@ export { A as ARC_GAP_FACTOR, B as BAND_LABELS, a as BDS_SATELLITES, b as BdsSat
4
4
  export { Scale, getBdsTime, getDateFromBdsTime, getDateFromDayOfWeek, getDateFromDayOfYear, getDateFromGalTime, getDateFromGloN, getDateFromGpsData, getDateFromGpsTime, getDateFromHourCode, getDateFromJulianDate, getDateFromMJD, getDateFromMJD2000, getDateFromRINEX, getDateFromTai, getDateFromTimeOfDay, getDateFromTt, getDateFromUnixTime, getDateFromUtc, getDayOfWeek, getDayOfYear, getGalTime, getGloN4, getGloNA, getGpsLeap, getGpsTime, getHourCode, getHoursFromTimeDifference, getJulianDate, getLeap, getMJD, getMJD2000, getMinutesFromTimeDifference, getNtpTime, getRINEX, getSecondsFromTimeDifference, getTaiDate, getTimeDifference, getTimeDifferenceFromDays, getTimeDifferenceFromHours, getTimeDifferenceFromMinutes, getTimeDifferenceFromObject, getTimeDifferenceFromSeconds, getTimeOfDay, getTimeOfWeek, getTotalDaysFromTimeDifference, getTtDate, getUnixTime, getUtcDate, getWeekNumber, getWeekOfYear } from './time.js';
5
5
  export { deg2dms, deg2rad, euclidean3D, geodeticToGeohash, geodeticToMaidenhead, geodeticToUtm, greatCircleMidpoint, horizonDistance, rad2deg, rhumbLine, vincenty } from './coordinates.js';
6
6
  export { c as clampUnit, e as ecefToGeodetic, g as geodeticToEcef, a as getAer, b as getEnuDifference } from './ecef-CF0uAysr.js';
7
- export { CrxField, DiffState, EMPTY_WARNINGS, IonexGrid, RinexWarning, RinexWarnings, WarningAccumulator, WarningSeverity, crxDecompress, crxRepair, fmtF, hdrLine, padL, padR, parseCrxDataLine, parseIonex, writeRinexNav } from './rinex.js';
7
+ export { CompactEpoch, CrxField, DiffState, EMPTY_WARNINGS, IonexGrid, RinexWarning, RinexWarnings, Sp3File, Sp3Sample, WarningAccumulator, WarningSeverity, createGzipLineSink, crxDecompress, crxRepair, fmtF, hdrLine, padL, padR, parseCrxDataLine, parseIonex, parseSp3, sp3Position, stationHeaderLines, writeModernObsBlob, writeRinex2ObsBlob, writeRinex4ObsBlob, writeRinexNav, writeRinexObsBlob } from './rinex.js';
8
8
  export { E as EpochSummary, P as ParseOptions, R as RinexHeader, a as RinexResult, b as RinexStats, S as SYSTEM_ORDER, c as SatObsCallback, p as parseRinexStream, s as systemCmp, d as systemName } from './parser-JPjjFgeP.js';
9
9
  export { E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHeader, a as NavResult, p as parseNavFile } from './nav-BAI1a9vK.js';
10
10
  export { B as BitReader, E as EphemerisInfo, R as Rtcm3DebugHandler, a as Rtcm3Decoder, b as Rtcm3Frame, d as decodeEphemeris, r as readString, c as reportDecodeError, s as setRtcm3DebugHandler } from './ephemeris-Ohl6NAfw.js';
11
11
  export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.js';
12
- export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.js';
12
+ export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.js';
13
13
  export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.js';
14
14
  export { KlobucharCoeffs, SppOptions, SppSolution, ionoFree, klobucharDelay, satClockCorrection, solveSpp } from './positioning.js';
15
15
  export { NtripCaster, NtripConnectionInfo, NtripNetwork, NtripStream, NtripStreamConnection, NtripVersion, Sourcetable, SourcetableEntry, connectToMountpoint, fetchSourcetable, parseSourcetable } from './ntrip.js';