gnss-js 1.11.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/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,
@@ -216,6 +217,7 @@ __export(src_exports, {
216
217
  parseRinexStream: () => parseRinexStream,
217
218
  parseSinexBiasDcb: () => parseSinexBiasDcb,
218
219
  parseSourcetable: () => parseSourcetable,
220
+ parseSp3: () => parseSp3,
219
221
  phiAltBOC: () => phiAltBOC,
220
222
  phiBOCc: () => phiBOCc,
221
223
  phiBOCs: () => phiBOCs,
@@ -232,6 +234,8 @@ __export(src_exports, {
232
234
  setGloFreqNumber: () => setGloFreqNumber,
233
235
  setRtcm3DebugHandler: () => setRtcm3DebugHandler,
234
236
  solveSpp: () => solveSpp,
237
+ sp3Position: () => sp3Position,
238
+ stationHeaderLines: () => stationHeaderLines,
235
239
  systemCmp: () => systemCmp,
236
240
  systemName: () => systemName,
237
241
  transformFrame: () => transformFrame,
@@ -239,7 +243,11 @@ __export(src_exports, {
239
243
  updateStreamStats: () => updateStreamStats,
240
244
  verifyChecksum: () => verifyChecksum,
241
245
  vincenty: () => vincenty,
242
- writeRinexNav: () => writeRinexNav
246
+ writeModernObsBlob: () => writeModernObsBlob,
247
+ writeRinex2ObsBlob: () => writeRinex2ObsBlob,
248
+ writeRinex4ObsBlob: () => writeRinex4ObsBlob,
249
+ writeRinexNav: () => writeRinexNav,
250
+ writeRinexObsBlob: () => writeRinexObsBlob
243
251
  });
244
252
  module.exports = __toCommonJS(src_exports);
245
253
 
@@ -2665,6 +2673,496 @@ function parseIonex(text) {
2665
2673
  return { epochs, lats, lons, maps };
2666
2674
  }
2667
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
+
2668
3166
  // src/rtcm3/decoder.ts
2669
3167
  var debugHandler = null;
2670
3168
  function setRtcm3DebugHandler(fn) {
@@ -7488,6 +7986,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
7488
7986
  computeStats,
7489
7987
  computeVisibility,
7490
7988
  connectToMountpoint,
7989
+ createGzipLineSink,
7491
7990
  createStationMeta,
7492
7991
  createStreamStats,
7493
7992
  crxDecompress,
@@ -7586,6 +8085,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
7586
8085
  parseRinexStream,
7587
8086
  parseSinexBiasDcb,
7588
8087
  parseSourcetable,
8088
+ parseSp3,
7589
8089
  phiAltBOC,
7590
8090
  phiBOCc,
7591
8091
  phiBOCs,
@@ -7602,6 +8102,8 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
7602
8102
  setGloFreqNumber,
7603
8103
  setRtcm3DebugHandler,
7604
8104
  solveSpp,
8105
+ sp3Position,
8106
+ stationHeaderLines,
7605
8107
  systemCmp,
7606
8108
  systemName,
7607
8109
  transformFrame,
@@ -7609,5 +8111,9 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
7609
8111
  updateStreamStats,
7610
8112
  verifyChecksum,
7611
8113
  vincenty,
7612
- writeRinexNav
8114
+ writeModernObsBlob,
8115
+ writeRinex2ObsBlob,
8116
+ writeRinex4ObsBlob,
8117
+ writeRinexNav,
8118
+ writeRinexObsBlob
7613
8119
  });
package/dist/index.d.cts CHANGED
@@ -4,7 +4,7 @@ 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';
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ 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';
package/dist/index.js CHANGED
@@ -172,14 +172,22 @@ import {
172
172
  import {
173
173
  EMPTY_WARNINGS,
174
174
  WarningAccumulator,
175
+ createGzipLineSink,
175
176
  fmtF,
176
177
  hdrLine,
177
178
  padL,
178
179
  padR,
179
180
  parseIonex,
180
181
  parseNavFile,
181
- writeRinexNav
182
- } from "./chunk-77VUSDNI.js";
182
+ parseSp3,
183
+ sp3Position,
184
+ stationHeaderLines,
185
+ writeModernObsBlob,
186
+ writeRinex2ObsBlob,
187
+ writeRinex4ObsBlob,
188
+ writeRinexNav,
189
+ writeRinexObsBlob
190
+ } from "./chunk-HXF7XVW7.js";
183
191
  import {
184
192
  SYSTEM_ORDER,
185
193
  crxDecompress,
@@ -354,6 +362,7 @@ export {
354
362
  computeStats,
355
363
  computeVisibility,
356
364
  connectToMountpoint,
365
+ createGzipLineSink,
357
366
  createStationMeta,
358
367
  createStreamStats,
359
368
  crxDecompress,
@@ -452,6 +461,7 @@ export {
452
461
  parseRinexStream,
453
462
  parseSinexBiasDcb,
454
463
  parseSourcetable,
464
+ parseSp3,
455
465
  phiAltBOC,
456
466
  phiBOCc,
457
467
  phiBOCs,
@@ -468,6 +478,8 @@ export {
468
478
  setGloFreqNumber,
469
479
  setRtcm3DebugHandler,
470
480
  solveSpp,
481
+ sp3Position,
482
+ stationHeaderLines,
471
483
  systemCmp,
472
484
  systemName,
473
485
  transformFrame,
@@ -475,5 +487,9 @@ export {
475
487
  updateStreamStats,
476
488
  verifyChecksum,
477
489
  vincenty,
478
- writeRinexNav
490
+ writeModernObsBlob,
491
+ writeRinex2ObsBlob,
492
+ writeRinex4ObsBlob,
493
+ writeRinexNav,
494
+ writeRinexObsBlob
479
495
  };