gnss-js 1.44.0 → 1.45.1

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.
@@ -1100,6 +1100,85 @@ var RtkFloatEngine = class {
1100
1100
  }
1101
1101
  };
1102
1102
 
1103
+ // src/positioning/rtk-postprocess.ts
1104
+ var epochsOf = (o) => Array.isArray(o) ? o : o.epochs;
1105
+ function medianIntervalMs(epochs) {
1106
+ const times = [...new Set(epochs.map((e) => e.timeMs))].sort((a, b) => a - b);
1107
+ if (times.length < 2) return null;
1108
+ const gaps = [];
1109
+ for (let i = 1; i < times.length; i++) gaps.push(times[i] - times[i - 1]);
1110
+ gaps.sort((a, b) => a - b);
1111
+ return gaps[Math.floor(gaps.length / 2)];
1112
+ }
1113
+ function postProcessRtk(base, rover, ephemerides, baseEcef, opts = {}) {
1114
+ const tol = opts.pairToleranceMs ?? 500;
1115
+ const round = (ms) => Math.round(ms / 1e3) * 1e3;
1116
+ const roverEpochs = epochsOf(rover);
1117
+ const interval = medianIntervalMs(roverEpochs);
1118
+ const engineOpts = opts.maxGapMs != null || interval == null ? opts : { ...opts, maxGapMs: Math.max(1e4, Math.round(interval * 2.5)) };
1119
+ const baseByT = /* @__PURE__ */ new Map();
1120
+ for (const e of epochsOf(base)) baseByT.set(round(e.timeMs), e);
1121
+ const engine = new RtkFloatEngine(baseEcef, ephemerides, engineOpts);
1122
+ const [bLat, bLon] = ecefToGeodetic(baseEcef[0], baseEcef[1], baseEcef[2]);
1123
+ const [sLat, cLat, sLon, cLon] = [
1124
+ Math.sin(bLat),
1125
+ Math.cos(bLat),
1126
+ Math.sin(bLon),
1127
+ Math.cos(bLon)
1128
+ ];
1129
+ const enuOf = (p) => {
1130
+ const dx = p[0] - baseEcef[0];
1131
+ const dy = p[1] - baseEcef[1];
1132
+ const dz = p[2] - baseEcef[2];
1133
+ return [
1134
+ -sLon * dx + cLon * dy,
1135
+ -sLat * cLon * dx - sLat * sLon * dy + cLat * dz,
1136
+ cLat * cLon * dx + cLat * sLon * dy + sLat * dz
1137
+ ];
1138
+ };
1139
+ const track = [];
1140
+ const seen = /* @__PURE__ */ new Set();
1141
+ let solved = 0;
1142
+ let unmatched = 0;
1143
+ let fixed = 0;
1144
+ const sorted = [...roverEpochs].sort((a, b) => a.timeMs - b.timeMs);
1145
+ for (const rEp of sorted) {
1146
+ if (seen.has(rEp.timeMs)) continue;
1147
+ seen.add(rEp.timeMs);
1148
+ const bEp = baseByT.get(round(rEp.timeMs));
1149
+ if (!bEp || Math.abs(bEp.timeMs - rEp.timeMs) > tol) {
1150
+ unmatched++;
1151
+ continue;
1152
+ }
1153
+ const sol = engine.process(
1154
+ toRtkEpoch(rEp.meas),
1155
+ toRtkEpoch(bEp.meas),
1156
+ rEp.timeMs
1157
+ );
1158
+ if (!sol) continue;
1159
+ solved++;
1160
+ if (sol.status === "fixed") fixed++;
1161
+ const [lat, lon, height] = ecefToGeodetic(
1162
+ sol.position[0],
1163
+ sol.position[1],
1164
+ sol.position[2]
1165
+ );
1166
+ track.push({
1167
+ timeMs: rEp.timeMs,
1168
+ position: sol.position,
1169
+ lat,
1170
+ lon,
1171
+ height,
1172
+ enu: enuOf(sol.position),
1173
+ status: sol.status,
1174
+ ratio: sol.ratio,
1175
+ nSats: sol.nSats,
1176
+ nFixed: sol.nFixed
1177
+ });
1178
+ }
1179
+ return { track, solved, unmatched, fixRate: solved ? fixed / solved : 0 };
1180
+ }
1181
+
1103
1182
  // src/positioning/ppp-tropo.ts
1104
1183
  var HYD_AVG_A = [
1105
1184
  0.0012769934,
@@ -2627,6 +2706,7 @@ export {
2627
2706
  toRtkEpoch,
2628
2707
  solveDgnss,
2629
2708
  RtkFloatEngine,
2709
+ postProcessRtk,
2630
2710
  niellMapping,
2631
2711
  gmst,
2632
2712
  sunEcef,
package/dist/index.cjs CHANGED
@@ -283,6 +283,7 @@ __export(src_exports, {
283
283
  phiBOCc: () => phiBOCc,
284
284
  phiBOCs: () => phiBOCs,
285
285
  phiBPSK: () => phiBPSK,
286
+ postProcessRtk: () => postProcessRtk,
286
287
  rad2deg: () => rad2deg,
287
288
  rangeRate: () => rangeRate,
288
289
  readString: () => readString,
@@ -13032,6 +13033,85 @@ var RtkFloatEngine = class {
13032
13033
  }
13033
13034
  };
13034
13035
 
13036
+ // src/positioning/rtk-postprocess.ts
13037
+ var epochsOf = (o) => Array.isArray(o) ? o : o.epochs;
13038
+ function medianIntervalMs(epochs) {
13039
+ const times = [...new Set(epochs.map((e) => e.timeMs))].sort((a, b) => a - b);
13040
+ if (times.length < 2) return null;
13041
+ const gaps = [];
13042
+ for (let i = 1; i < times.length; i++) gaps.push(times[i] - times[i - 1]);
13043
+ gaps.sort((a, b) => a - b);
13044
+ return gaps[Math.floor(gaps.length / 2)];
13045
+ }
13046
+ function postProcessRtk(base, rover, ephemerides, baseEcef, opts = {}) {
13047
+ const tol = opts.pairToleranceMs ?? 500;
13048
+ const round = (ms) => Math.round(ms / 1e3) * 1e3;
13049
+ const roverEpochs = epochsOf(rover);
13050
+ const interval = medianIntervalMs(roverEpochs);
13051
+ const engineOpts = opts.maxGapMs != null || interval == null ? opts : { ...opts, maxGapMs: Math.max(1e4, Math.round(interval * 2.5)) };
13052
+ const baseByT = /* @__PURE__ */ new Map();
13053
+ for (const e of epochsOf(base)) baseByT.set(round(e.timeMs), e);
13054
+ const engine = new RtkFloatEngine(baseEcef, ephemerides, engineOpts);
13055
+ const [bLat, bLon] = ecefToGeodetic(baseEcef[0], baseEcef[1], baseEcef[2]);
13056
+ const [sLat, cLat, sLon, cLon] = [
13057
+ Math.sin(bLat),
13058
+ Math.cos(bLat),
13059
+ Math.sin(bLon),
13060
+ Math.cos(bLon)
13061
+ ];
13062
+ const enuOf = (p) => {
13063
+ const dx = p[0] - baseEcef[0];
13064
+ const dy = p[1] - baseEcef[1];
13065
+ const dz = p[2] - baseEcef[2];
13066
+ return [
13067
+ -sLon * dx + cLon * dy,
13068
+ -sLat * cLon * dx - sLat * sLon * dy + cLat * dz,
13069
+ cLat * cLon * dx + cLat * sLon * dy + sLat * dz
13070
+ ];
13071
+ };
13072
+ const track = [];
13073
+ const seen = /* @__PURE__ */ new Set();
13074
+ let solved = 0;
13075
+ let unmatched = 0;
13076
+ let fixed = 0;
13077
+ const sorted = [...roverEpochs].sort((a, b) => a.timeMs - b.timeMs);
13078
+ for (const rEp of sorted) {
13079
+ if (seen.has(rEp.timeMs)) continue;
13080
+ seen.add(rEp.timeMs);
13081
+ const bEp = baseByT.get(round(rEp.timeMs));
13082
+ if (!bEp || Math.abs(bEp.timeMs - rEp.timeMs) > tol) {
13083
+ unmatched++;
13084
+ continue;
13085
+ }
13086
+ const sol = engine.process(
13087
+ toRtkEpoch(rEp.meas),
13088
+ toRtkEpoch(bEp.meas),
13089
+ rEp.timeMs
13090
+ );
13091
+ if (!sol) continue;
13092
+ solved++;
13093
+ if (sol.status === "fixed") fixed++;
13094
+ const [lat, lon, height] = ecefToGeodetic(
13095
+ sol.position[0],
13096
+ sol.position[1],
13097
+ sol.position[2]
13098
+ );
13099
+ track.push({
13100
+ timeMs: rEp.timeMs,
13101
+ position: sol.position,
13102
+ lat,
13103
+ lon,
13104
+ height,
13105
+ enu: enuOf(sol.position),
13106
+ status: sol.status,
13107
+ ratio: sol.ratio,
13108
+ nSats: sol.nSats,
13109
+ nFixed: sol.nFixed
13110
+ });
13111
+ }
13112
+ return { track, solved, unmatched, fixRate: solved ? fixed / solved : 0 };
13113
+ }
13114
+
13035
13115
  // src/positioning/ppp-tropo.ts
13036
13116
  var HYD_AVG_A = [
13037
13117
  0.0012769934,
@@ -17072,6 +17152,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
17072
17152
  phiBOCc,
17073
17153
  phiBOCs,
17074
17154
  phiBPSK,
17155
+ postProcessRtk,
17075
17156
  rad2deg,
17076
17157
  rangeRate,
17077
17158
  readString,
package/dist/index.d.cts CHANGED
@@ -17,7 +17,7 @@ export { TrimbleEpoch, TrimbleFrame, TrimbleMeasurement, TrimbleNavResult, Trimb
17
17
  export { BinexEpoch, BinexMeasurement, BinexParseResult, BinexRecord, binexCrc16, binexCrc32, binexCsum8, binexRecords, decodeBinexEph, getBnxi, parseBinex } from './binex.cjs';
18
18
  export { AllPositionsData, AlmanacPosition, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, almanacEpochMs, almanacSatPosition, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassAlmanacEpochMs, glonassAlmanacPosition, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.cjs';
19
19
  export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.cjs';
20
- export { AntennaOffset, ArFixedSat, ArOptions, ArResult, ArSat, CorrectionResult, DgnssOptions, DgnssSolution, EphemerisSource, FixedPositionResult, IONO_L1_M_PER_TECU, KlobucharCoeffs, LambdaResult, NetworkFcbResult, NetworkFcbSummary, NlArc, NlFcbResult, PppAntennaModel, PppArc, PppCorrectionConfig, PppCorrections, PppEpoch, PppEpochContext, PppEpochResult, PppFixState, PppOptions, PppSatObs, PppSolution, RawObservation, RtkEpochMeasurements, RtkFloatEngine, RtkFloatOptions, RtkFloatSolution, RtkMeasurement, SatGeom, SppOptions, SppSolution, TropoMapping, WlArc, WlFcbOptions, WlFcbResult, WlObs, buildPppAntenna, createPppCorrections, estimateNarrowlaneFcb, estimateNetworkFcbs, estimateWidelaneFcb, extractWidelaneArcs, fixPppPosition, gimSlantIonoDelayL1, gimVerticalTec, gmst, ionoFree, klobucharDelay, lambdaReduction, lambdaSearch, moonEcef, niellMapping, nlWavelength, resolvePppAmbiguities, satClockCorrection, solidEarthTide, solveDgnss, solvePpp, solveSpp, sunEcef, toRtkEpoch, wlWavelength } from './positioning.cjs';
20
+ export { AntennaOffset, ArFixedSat, ArOptions, ArResult, ArSat, CorrectionResult, DgnssOptions, DgnssSolution, EphemerisSource, FixedPositionResult, IONO_L1_M_PER_TECU, KlobucharCoeffs, LambdaResult, NetworkFcbResult, NetworkFcbSummary, NlArc, NlFcbResult, PppAntennaModel, PppArc, PppCorrectionConfig, PppCorrections, PppEpoch, PppEpochContext, PppEpochResult, PppFixState, PppOptions, PppSatObs, PppSolution, RawObservation, RtkEpochMeasurements, RtkFloatEngine, RtkFloatOptions, RtkFloatSolution, RtkMeasurement, RtkObsEpoch, RtkObsInput, RtkPostProcessOptions, RtkPostProcessResult, RtkTrackPoint, SatGeom, SppOptions, SppSolution, TropoMapping, WlArc, WlFcbOptions, WlFcbResult, WlObs, buildPppAntenna, createPppCorrections, estimateNarrowlaneFcb, estimateNetworkFcbs, estimateWidelaneFcb, extractWidelaneArcs, fixPppPosition, gimSlantIonoDelayL1, gimVerticalTec, gmst, ionoFree, klobucharDelay, lambdaReduction, lambdaSearch, moonEcef, niellMapping, nlWavelength, postProcessRtk, resolvePppAmbiguities, satClockCorrection, solidEarthTide, solveDgnss, solvePpp, solveSpp, sunEcef, toRtkEpoch, wlWavelength } from './positioning.cjs';
21
21
  export { NtripCaster, NtripConnectionInfo, NtripNetwork, NtripStream, NtripStreamConnection, NtripVersion, Sourcetable, SourcetableEntry, connectToMountpoint, fetchSourcetable, parseSourcetable } from './ntrip.cjs';
22
22
  export { CompleteSatSignal, CompleteSignalStats, CompletenessAccumulator, CompletenessResult, CycleSlipAccumulator, CycleSlipEvent, CycleSlipResult, CycleSlipSignalStats, IonoAccumulator, IonoDcbResult, IonoPoint, IonoRatePoint, IonoRateSeries, IonoResult, IonoSeries, MultipathAccumulator, MultipathPoint, MultipathResult, MultipathSeries, MultipathSignalStat, QualityResult, SatDcbMap, analyzeQuality, applyIonoDcb, computeIonoRate, detrendIonoArcs, parseSinexBiasDcb } from './analysis.cjs';
23
23
  export { AntennaEntry, AntexFile, FrequencyData, frequencyLabel, parseAntex } from './antex.cjs';
package/dist/index.d.ts CHANGED
@@ -17,7 +17,7 @@ export { TrimbleEpoch, TrimbleFrame, TrimbleMeasurement, TrimbleNavResult, Trimb
17
17
  export { BinexEpoch, BinexMeasurement, BinexParseResult, BinexRecord, binexCrc16, binexCrc32, binexCsum8, binexRecords, decodeBinexEph, getBnxi, parseBinex } from './binex.js';
18
18
  export { AllPositionsData, AlmanacPosition, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, almanacEpochMs, almanacSatPosition, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassAlmanacEpochMs, glonassAlmanacPosition, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.js';
19
19
  export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.js';
20
- export { AntennaOffset, ArFixedSat, ArOptions, ArResult, ArSat, CorrectionResult, DgnssOptions, DgnssSolution, EphemerisSource, FixedPositionResult, IONO_L1_M_PER_TECU, KlobucharCoeffs, LambdaResult, NetworkFcbResult, NetworkFcbSummary, NlArc, NlFcbResult, PppAntennaModel, PppArc, PppCorrectionConfig, PppCorrections, PppEpoch, PppEpochContext, PppEpochResult, PppFixState, PppOptions, PppSatObs, PppSolution, RawObservation, RtkEpochMeasurements, RtkFloatEngine, RtkFloatOptions, RtkFloatSolution, RtkMeasurement, SatGeom, SppOptions, SppSolution, TropoMapping, WlArc, WlFcbOptions, WlFcbResult, WlObs, buildPppAntenna, createPppCorrections, estimateNarrowlaneFcb, estimateNetworkFcbs, estimateWidelaneFcb, extractWidelaneArcs, fixPppPosition, gimSlantIonoDelayL1, gimVerticalTec, gmst, ionoFree, klobucharDelay, lambdaReduction, lambdaSearch, moonEcef, niellMapping, nlWavelength, resolvePppAmbiguities, satClockCorrection, solidEarthTide, solveDgnss, solvePpp, solveSpp, sunEcef, toRtkEpoch, wlWavelength } from './positioning.js';
20
+ export { AntennaOffset, ArFixedSat, ArOptions, ArResult, ArSat, CorrectionResult, DgnssOptions, DgnssSolution, EphemerisSource, FixedPositionResult, IONO_L1_M_PER_TECU, KlobucharCoeffs, LambdaResult, NetworkFcbResult, NetworkFcbSummary, NlArc, NlFcbResult, PppAntennaModel, PppArc, PppCorrectionConfig, PppCorrections, PppEpoch, PppEpochContext, PppEpochResult, PppFixState, PppOptions, PppSatObs, PppSolution, RawObservation, RtkEpochMeasurements, RtkFloatEngine, RtkFloatOptions, RtkFloatSolution, RtkMeasurement, RtkObsEpoch, RtkObsInput, RtkPostProcessOptions, RtkPostProcessResult, RtkTrackPoint, SatGeom, SppOptions, SppSolution, TropoMapping, WlArc, WlFcbOptions, WlFcbResult, WlObs, buildPppAntenna, createPppCorrections, estimateNarrowlaneFcb, estimateNetworkFcbs, estimateWidelaneFcb, extractWidelaneArcs, fixPppPosition, gimSlantIonoDelayL1, gimVerticalTec, gmst, ionoFree, klobucharDelay, lambdaReduction, lambdaSearch, moonEcef, niellMapping, nlWavelength, postProcessRtk, resolvePppAmbiguities, satClockCorrection, solidEarthTide, solveDgnss, solvePpp, solveSpp, sunEcef, toRtkEpoch, wlWavelength } from './positioning.js';
21
21
  export { NtripCaster, NtripConnectionInfo, NtripNetwork, NtripStream, NtripStreamConnection, NtripVersion, Sourcetable, SourcetableEntry, connectToMountpoint, fetchSourcetable, parseSourcetable } from './ntrip.js';
22
22
  export { CompleteSatSignal, CompleteSignalStats, CompletenessAccumulator, CompletenessResult, CycleSlipAccumulator, CycleSlipEvent, CycleSlipResult, CycleSlipSignalStats, IonoAccumulator, IonoDcbResult, IonoPoint, IonoRatePoint, IonoRateSeries, IonoResult, IonoSeries, MultipathAccumulator, MultipathPoint, MultipathResult, MultipathSeries, MultipathSignalStat, QualityResult, SatDcbMap, analyzeQuality, applyIonoDcb, computeIonoRate, detrendIonoArcs, parseSinexBiasDcb } from './analysis.js';
23
23
  export { AntennaEntry, AntexFile, FrequencyData, frequencyLabel, parseAntex } from './antex.js';
package/dist/index.js CHANGED
@@ -128,19 +128,6 @@ import {
128
128
  getTimeOfDay,
129
129
  getWeekOfYear
130
130
  } from "./chunk-L5OUUNLT.js";
131
- import {
132
- deg2dms,
133
- deg2rad,
134
- euclidean3D,
135
- geodeticToGeohash,
136
- geodeticToMaidenhead,
137
- geodeticToUtm,
138
- greatCircleMidpoint,
139
- horizonDistance,
140
- rad2deg,
141
- rhumbLine,
142
- vincenty
143
- } from "./chunk-MIIM4LDY.js";
144
131
  import {
145
132
  REFERENCE_FRAMES,
146
133
  applyHelmert,
@@ -167,6 +154,7 @@ import {
167
154
  moonEcef,
168
155
  niellMapping,
169
156
  nlWavelength,
157
+ postProcessRtk,
170
158
  resolvePppAmbiguities,
171
159
  satClockCorrection,
172
160
  solidEarthTide,
@@ -176,7 +164,7 @@ import {
176
164
  sunEcef,
177
165
  toRtkEpoch,
178
166
  wlWavelength
179
- } from "./chunk-3FG4XVCB.js";
167
+ } from "./chunk-ST22ULND.js";
180
168
  import {
181
169
  almanacEpochMs,
182
170
  almanacSatPosition,
@@ -198,6 +186,19 @@ import {
198
186
  rangeRate,
199
187
  selectEphemeris
200
188
  } from "./chunk-MHGNKSSH.js";
189
+ import {
190
+ deg2dms,
191
+ deg2rad,
192
+ euclidean3D,
193
+ geodeticToGeohash,
194
+ geodeticToMaidenhead,
195
+ geodeticToUtm,
196
+ greatCircleMidpoint,
197
+ horizonDistance,
198
+ rad2deg,
199
+ rhumbLine,
200
+ vincenty
201
+ } from "./chunk-MIIM4LDY.js";
201
202
  import {
202
203
  clampUnit,
203
204
  ecefToGeodetic,
@@ -617,6 +618,7 @@ export {
617
618
  phiBOCc,
618
619
  phiBOCs,
619
620
  phiBPSK,
621
+ postProcessRtk,
620
622
  rad2deg,
621
623
  rangeRate,
622
624
  readString,
@@ -39,6 +39,7 @@ __export(positioning_exports, {
39
39
  moonEcef: () => moonEcef,
40
40
  niellMapping: () => niellMapping,
41
41
  nlWavelength: () => nlWavelength,
42
+ postProcessRtk: () => postProcessRtk,
42
43
  resolvePppAmbiguities: () => resolvePppAmbiguities,
43
44
  satClockCorrection: () => satClockCorrection,
44
45
  solidEarthTide: () => solidEarthTide,
@@ -1555,6 +1556,85 @@ var RtkFloatEngine = class {
1555
1556
  }
1556
1557
  };
1557
1558
 
1559
+ // src/positioning/rtk-postprocess.ts
1560
+ var epochsOf = (o) => Array.isArray(o) ? o : o.epochs;
1561
+ function medianIntervalMs(epochs) {
1562
+ const times = [...new Set(epochs.map((e) => e.timeMs))].sort((a, b) => a - b);
1563
+ if (times.length < 2) return null;
1564
+ const gaps = [];
1565
+ for (let i = 1; i < times.length; i++) gaps.push(times[i] - times[i - 1]);
1566
+ gaps.sort((a, b) => a - b);
1567
+ return gaps[Math.floor(gaps.length / 2)];
1568
+ }
1569
+ function postProcessRtk(base, rover, ephemerides, baseEcef, opts = {}) {
1570
+ const tol = opts.pairToleranceMs ?? 500;
1571
+ const round = (ms) => Math.round(ms / 1e3) * 1e3;
1572
+ const roverEpochs = epochsOf(rover);
1573
+ const interval = medianIntervalMs(roverEpochs);
1574
+ const engineOpts = opts.maxGapMs != null || interval == null ? opts : { ...opts, maxGapMs: Math.max(1e4, Math.round(interval * 2.5)) };
1575
+ const baseByT = /* @__PURE__ */ new Map();
1576
+ for (const e of epochsOf(base)) baseByT.set(round(e.timeMs), e);
1577
+ const engine = new RtkFloatEngine(baseEcef, ephemerides, engineOpts);
1578
+ const [bLat, bLon] = ecefToGeodetic(baseEcef[0], baseEcef[1], baseEcef[2]);
1579
+ const [sLat, cLat, sLon, cLon] = [
1580
+ Math.sin(bLat),
1581
+ Math.cos(bLat),
1582
+ Math.sin(bLon),
1583
+ Math.cos(bLon)
1584
+ ];
1585
+ const enuOf = (p) => {
1586
+ const dx = p[0] - baseEcef[0];
1587
+ const dy = p[1] - baseEcef[1];
1588
+ const dz = p[2] - baseEcef[2];
1589
+ return [
1590
+ -sLon * dx + cLon * dy,
1591
+ -sLat * cLon * dx - sLat * sLon * dy + cLat * dz,
1592
+ cLat * cLon * dx + cLat * sLon * dy + sLat * dz
1593
+ ];
1594
+ };
1595
+ const track = [];
1596
+ const seen = /* @__PURE__ */ new Set();
1597
+ let solved = 0;
1598
+ let unmatched = 0;
1599
+ let fixed = 0;
1600
+ const sorted = [...roverEpochs].sort((a, b) => a.timeMs - b.timeMs);
1601
+ for (const rEp of sorted) {
1602
+ if (seen.has(rEp.timeMs)) continue;
1603
+ seen.add(rEp.timeMs);
1604
+ const bEp = baseByT.get(round(rEp.timeMs));
1605
+ if (!bEp || Math.abs(bEp.timeMs - rEp.timeMs) > tol) {
1606
+ unmatched++;
1607
+ continue;
1608
+ }
1609
+ const sol = engine.process(
1610
+ toRtkEpoch(rEp.meas),
1611
+ toRtkEpoch(bEp.meas),
1612
+ rEp.timeMs
1613
+ );
1614
+ if (!sol) continue;
1615
+ solved++;
1616
+ if (sol.status === "fixed") fixed++;
1617
+ const [lat, lon, height] = ecefToGeodetic(
1618
+ sol.position[0],
1619
+ sol.position[1],
1620
+ sol.position[2]
1621
+ );
1622
+ track.push({
1623
+ timeMs: rEp.timeMs,
1624
+ position: sol.position,
1625
+ lat,
1626
+ lon,
1627
+ height,
1628
+ enu: enuOf(sol.position),
1629
+ status: sol.status,
1630
+ ratio: sol.ratio,
1631
+ nSats: sol.nSats,
1632
+ nFixed: sol.nFixed
1633
+ });
1634
+ }
1635
+ return { track, solved, unmatched, fixRate: solved ? fixed / solved : 0 };
1636
+ }
1637
+
1558
1638
  // src/rinex/sp3.ts
1559
1639
  function sp3Position(sp3, prn, tMs, order = 9) {
1560
1640
  const samples = sp3.satellites[prn];
@@ -3164,6 +3244,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
3164
3244
  moonEcef,
3165
3245
  niellMapping,
3166
3246
  nlWavelength,
3247
+ postProcessRtk,
3167
3248
  resolvePppAmbiguities,
3168
3249
  satClockCorrection,
3169
3250
  solidEarthTide,
@@ -399,6 +399,67 @@ declare class RtkFloatEngine {
399
399
  process(rover: RtkEpochMeasurements, base: RtkEpochMeasurements, timeMs: number): RtkFloatSolution | null;
400
400
  }
401
401
 
402
+ /** One observation epoch (base or rover) — the shape the receiver/RINEX
403
+ * parsers already produce (`parseNovatelRange().epochs`, etc.). */
404
+ interface RtkObsEpoch {
405
+ /** Epoch, GPS-scale milliseconds. */
406
+ timeMs: number;
407
+ meas: readonly RawObservation[];
408
+ }
409
+ /** Either a bare epoch array or a `{ epochs }` parser result. */
410
+ type RtkObsInput = readonly RtkObsEpoch[] | {
411
+ readonly epochs: readonly RtkObsEpoch[];
412
+ };
413
+ interface RtkTrackPoint {
414
+ /** Epoch, GPS-scale milliseconds. */
415
+ timeMs: number;
416
+ /** Rover position ECEF (m) — ambiguity-fixed when `status === 'fixed'`. */
417
+ position: [number, number, number];
418
+ /** Geodetic latitude, longitude (radians) and ellipsoidal height (m). */
419
+ lat: number;
420
+ lon: number;
421
+ height: number;
422
+ /** Rover − base baseline in the base's local ENU frame (m). */
423
+ enu: [number, number, number];
424
+ /** 'fixed' (integer AR passed), 'float', or 'dgnss' (code-only). */
425
+ status: 'fixed' | 'float' | 'dgnss';
426
+ /** LAMBDA validation ratio, when a fix was attempted. */
427
+ ratio?: number;
428
+ /** Satellites contributing this epoch. */
429
+ nSats: number;
430
+ /** Integer-fixed ambiguities, when fixed. */
431
+ nFixed?: number;
432
+ }
433
+ interface RtkPostProcessOptions extends RtkFloatOptions {
434
+ /**
435
+ * Maximum |base − rover| epoch-time difference to accept a pair (ms).
436
+ * Default 500. Base and rover are matched by rounded second, so this
437
+ * mainly rejects a base gap rather than sub-second offsets.
438
+ */
439
+ pairToleranceMs?: number;
440
+ }
441
+ interface RtkPostProcessResult {
442
+ /** Solved rover epochs in time order. */
443
+ track: RtkTrackPoint[];
444
+ /** Rover epochs paired with a base epoch and solved. */
445
+ solved: number;
446
+ /** Rover epochs with no base epoch within tolerance. */
447
+ unmatched: number;
448
+ /** Fraction of solved epochs with an integer-fixed solution (0–1). */
449
+ fixRate: number;
450
+ }
451
+ /**
452
+ * Post-process a base/rover observation pair into an RTK track.
453
+ *
454
+ * @param base base-station observation epochs (needs a known position)
455
+ * @param rover rover observation epochs
456
+ * @param ephemerides broadcast (or precise) ephemerides covering the window
457
+ * @param baseEcef surveyed base position, ECEF metres
458
+ * @param opts engine options (`mode`, `elevationMaskDeg`,
459
+ * `ambiguityResolution`, …) plus `pairToleranceMs`
460
+ */
461
+ declare function postProcessRtk(base: RtkObsInput, rover: RtkObsInput, ephemerides: EphemerisSource, baseEcef: readonly [number, number, number], opts?: RtkPostProcessOptions): RtkPostProcessResult;
462
+
402
463
  /**
403
464
  * Integer ambiguity resolution: LAMBDA decorrelation + MLAMBDA
404
465
  * integer least-squares search.
@@ -1117,4 +1178,4 @@ declare function ionoFree(p1: number, p2: number, f1: number, f2: number): numbe
1117
1178
  */
1118
1179
  declare function solveSpp(pseudoranges: Map<string, number>, ephemerides: Map<string, Ephemeris>, timeMs: number, opts?: SppOptions): SppSolution | null;
1119
1180
 
1120
- export { type AntennaOffset, type ArFixedSat, type ArOptions, type ArResult, type ArSat, type CorrectionResult, type DgnssOptions, type DgnssSolution, type EphemerisSource, type FixedPositionResult, IONO_L1_M_PER_TECU, type KlobucharCoeffs, type LambdaResult, type NetworkFcbResult, type NetworkFcbSummary, type NlArc, type NlFcbResult, type PppAntennaModel, type PppArc, type PppCorrectionConfig, type PppCorrections, type PppEpoch, type PppEpochContext, type PppEpochResult, type PppFixState, type PppOptions, type PppSatObs, type PppSolution, type RawObservation, type RtkEpochMeasurements, RtkFloatEngine, type RtkFloatOptions, type RtkFloatSolution, type RtkMeasurement, type SatGeom, type SppOptions, type SppSolution, type TropoMapping, type WlArc, type WlFcbOptions, type WlFcbResult, type WlObs, buildPppAntenna, createPppCorrections, estimateNarrowlaneFcb, estimateNetworkFcbs, estimateWidelaneFcb, extractWidelaneArcs, fixPppPosition, gimSlantIonoDelayL1, gimVerticalTec, gmst, ionoFree, klobucharDelay, lambdaReduction, lambdaSearch, moonEcef, niellMapping, nlWavelength, resolvePppAmbiguities, satClockCorrection, solidEarthTide, solveDgnss, solvePpp, solveSpp, sunEcef, toRtkEpoch, wlWavelength };
1181
+ export { type AntennaOffset, type ArFixedSat, type ArOptions, type ArResult, type ArSat, type CorrectionResult, type DgnssOptions, type DgnssSolution, type EphemerisSource, type FixedPositionResult, IONO_L1_M_PER_TECU, type KlobucharCoeffs, type LambdaResult, type NetworkFcbResult, type NetworkFcbSummary, type NlArc, type NlFcbResult, type PppAntennaModel, type PppArc, type PppCorrectionConfig, type PppCorrections, type PppEpoch, type PppEpochContext, type PppEpochResult, type PppFixState, type PppOptions, type PppSatObs, type PppSolution, type RawObservation, type RtkEpochMeasurements, RtkFloatEngine, type RtkFloatOptions, type RtkFloatSolution, type RtkMeasurement, type RtkObsEpoch, type RtkObsInput, type RtkPostProcessOptions, type RtkPostProcessResult, type RtkTrackPoint, type SatGeom, type SppOptions, type SppSolution, type TropoMapping, type WlArc, type WlFcbOptions, type WlFcbResult, type WlObs, buildPppAntenna, createPppCorrections, estimateNarrowlaneFcb, estimateNetworkFcbs, estimateWidelaneFcb, extractWidelaneArcs, fixPppPosition, gimSlantIonoDelayL1, gimVerticalTec, gmst, ionoFree, klobucharDelay, lambdaReduction, lambdaSearch, moonEcef, niellMapping, nlWavelength, postProcessRtk, resolvePppAmbiguities, satClockCorrection, solidEarthTide, solveDgnss, solvePpp, solveSpp, sunEcef, toRtkEpoch, wlWavelength };
@@ -399,6 +399,67 @@ declare class RtkFloatEngine {
399
399
  process(rover: RtkEpochMeasurements, base: RtkEpochMeasurements, timeMs: number): RtkFloatSolution | null;
400
400
  }
401
401
 
402
+ /** One observation epoch (base or rover) — the shape the receiver/RINEX
403
+ * parsers already produce (`parseNovatelRange().epochs`, etc.). */
404
+ interface RtkObsEpoch {
405
+ /** Epoch, GPS-scale milliseconds. */
406
+ timeMs: number;
407
+ meas: readonly RawObservation[];
408
+ }
409
+ /** Either a bare epoch array or a `{ epochs }` parser result. */
410
+ type RtkObsInput = readonly RtkObsEpoch[] | {
411
+ readonly epochs: readonly RtkObsEpoch[];
412
+ };
413
+ interface RtkTrackPoint {
414
+ /** Epoch, GPS-scale milliseconds. */
415
+ timeMs: number;
416
+ /** Rover position ECEF (m) — ambiguity-fixed when `status === 'fixed'`. */
417
+ position: [number, number, number];
418
+ /** Geodetic latitude, longitude (radians) and ellipsoidal height (m). */
419
+ lat: number;
420
+ lon: number;
421
+ height: number;
422
+ /** Rover − base baseline in the base's local ENU frame (m). */
423
+ enu: [number, number, number];
424
+ /** 'fixed' (integer AR passed), 'float', or 'dgnss' (code-only). */
425
+ status: 'fixed' | 'float' | 'dgnss';
426
+ /** LAMBDA validation ratio, when a fix was attempted. */
427
+ ratio?: number;
428
+ /** Satellites contributing this epoch. */
429
+ nSats: number;
430
+ /** Integer-fixed ambiguities, when fixed. */
431
+ nFixed?: number;
432
+ }
433
+ interface RtkPostProcessOptions extends RtkFloatOptions {
434
+ /**
435
+ * Maximum |base − rover| epoch-time difference to accept a pair (ms).
436
+ * Default 500. Base and rover are matched by rounded second, so this
437
+ * mainly rejects a base gap rather than sub-second offsets.
438
+ */
439
+ pairToleranceMs?: number;
440
+ }
441
+ interface RtkPostProcessResult {
442
+ /** Solved rover epochs in time order. */
443
+ track: RtkTrackPoint[];
444
+ /** Rover epochs paired with a base epoch and solved. */
445
+ solved: number;
446
+ /** Rover epochs with no base epoch within tolerance. */
447
+ unmatched: number;
448
+ /** Fraction of solved epochs with an integer-fixed solution (0–1). */
449
+ fixRate: number;
450
+ }
451
+ /**
452
+ * Post-process a base/rover observation pair into an RTK track.
453
+ *
454
+ * @param base base-station observation epochs (needs a known position)
455
+ * @param rover rover observation epochs
456
+ * @param ephemerides broadcast (or precise) ephemerides covering the window
457
+ * @param baseEcef surveyed base position, ECEF metres
458
+ * @param opts engine options (`mode`, `elevationMaskDeg`,
459
+ * `ambiguityResolution`, …) plus `pairToleranceMs`
460
+ */
461
+ declare function postProcessRtk(base: RtkObsInput, rover: RtkObsInput, ephemerides: EphemerisSource, baseEcef: readonly [number, number, number], opts?: RtkPostProcessOptions): RtkPostProcessResult;
462
+
402
463
  /**
403
464
  * Integer ambiguity resolution: LAMBDA decorrelation + MLAMBDA
404
465
  * integer least-squares search.
@@ -1117,4 +1178,4 @@ declare function ionoFree(p1: number, p2: number, f1: number, f2: number): numbe
1117
1178
  */
1118
1179
  declare function solveSpp(pseudoranges: Map<string, number>, ephemerides: Map<string, Ephemeris>, timeMs: number, opts?: SppOptions): SppSolution | null;
1119
1180
 
1120
- export { type AntennaOffset, type ArFixedSat, type ArOptions, type ArResult, type ArSat, type CorrectionResult, type DgnssOptions, type DgnssSolution, type EphemerisSource, type FixedPositionResult, IONO_L1_M_PER_TECU, type KlobucharCoeffs, type LambdaResult, type NetworkFcbResult, type NetworkFcbSummary, type NlArc, type NlFcbResult, type PppAntennaModel, type PppArc, type PppCorrectionConfig, type PppCorrections, type PppEpoch, type PppEpochContext, type PppEpochResult, type PppFixState, type PppOptions, type PppSatObs, type PppSolution, type RawObservation, type RtkEpochMeasurements, RtkFloatEngine, type RtkFloatOptions, type RtkFloatSolution, type RtkMeasurement, type SatGeom, type SppOptions, type SppSolution, type TropoMapping, type WlArc, type WlFcbOptions, type WlFcbResult, type WlObs, buildPppAntenna, createPppCorrections, estimateNarrowlaneFcb, estimateNetworkFcbs, estimateWidelaneFcb, extractWidelaneArcs, fixPppPosition, gimSlantIonoDelayL1, gimVerticalTec, gmst, ionoFree, klobucharDelay, lambdaReduction, lambdaSearch, moonEcef, niellMapping, nlWavelength, resolvePppAmbiguities, satClockCorrection, solidEarthTide, solveDgnss, solvePpp, solveSpp, sunEcef, toRtkEpoch, wlWavelength };
1181
+ export { type AntennaOffset, type ArFixedSat, type ArOptions, type ArResult, type ArSat, type CorrectionResult, type DgnssOptions, type DgnssSolution, type EphemerisSource, type FixedPositionResult, IONO_L1_M_PER_TECU, type KlobucharCoeffs, type LambdaResult, type NetworkFcbResult, type NetworkFcbSummary, type NlArc, type NlFcbResult, type PppAntennaModel, type PppArc, type PppCorrectionConfig, type PppCorrections, type PppEpoch, type PppEpochContext, type PppEpochResult, type PppFixState, type PppOptions, type PppSatObs, type PppSolution, type RawObservation, type RtkEpochMeasurements, RtkFloatEngine, type RtkFloatOptions, type RtkFloatSolution, type RtkMeasurement, type RtkObsEpoch, type RtkObsInput, type RtkPostProcessOptions, type RtkPostProcessResult, type RtkTrackPoint, type SatGeom, type SppOptions, type SppSolution, type TropoMapping, type WlArc, type WlFcbOptions, type WlFcbResult, type WlObs, buildPppAntenna, createPppCorrections, estimateNarrowlaneFcb, estimateNetworkFcbs, estimateWidelaneFcb, extractWidelaneArcs, fixPppPosition, gimSlantIonoDelayL1, gimVerticalTec, gmst, ionoFree, klobucharDelay, lambdaReduction, lambdaSearch, moonEcef, niellMapping, nlWavelength, postProcessRtk, resolvePppAmbiguities, satClockCorrection, solidEarthTide, solveDgnss, solvePpp, solveSpp, sunEcef, toRtkEpoch, wlWavelength };
@@ -18,6 +18,7 @@ import {
18
18
  moonEcef,
19
19
  niellMapping,
20
20
  nlWavelength,
21
+ postProcessRtk,
21
22
  resolvePppAmbiguities,
22
23
  satClockCorrection,
23
24
  solidEarthTide,
@@ -27,8 +28,9 @@ import {
27
28
  sunEcef,
28
29
  toRtkEpoch,
29
30
  wlWavelength
30
- } from "./chunk-3FG4XVCB.js";
31
+ } from "./chunk-ST22ULND.js";
31
32
  import "./chunk-MHGNKSSH.js";
33
+ import "./chunk-MIIM4LDY.js";
32
34
  import "./chunk-37QNKGTC.js";
33
35
  import "./chunk-6FAL6P4G.js";
34
36
  import "./chunk-GPEP67TG.js";
@@ -55,6 +57,7 @@ export {
55
57
  moonEcef,
56
58
  niellMapping,
57
59
  nlWavelength,
60
+ postProcessRtk,
58
61
  resolvePppAmbiguities,
59
62
  satClockCorrection,
60
63
  solidEarthTide,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gnss-js",
3
- "version": "1.44.0",
3
+ "version": "1.45.1",
4
4
  "description": "Comprehensive GNSS library for JavaScript — time scales, coordinates, RINEX parsing, RTCM3 decoding, orbit computation, and signal analysis",
5
5
  "type": "module",
6
6
  "sideEffects": false,