gnss-js 1.43.0 → 1.45.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.
@@ -3,11 +3,13 @@ import {
3
3
  GalInavAssembler,
4
4
  GloStringAssembler,
5
5
  bdsSubframeParityOk,
6
- decodeSbasGeoNav,
7
6
  galInavPageCrcOk,
8
- sbasCrcOk,
9
7
  testGloString
10
- } from "./chunk-QV3XGDUU.js";
8
+ } from "./chunk-FA2UTLEQ.js";
9
+ import {
10
+ decodeSbasGeoNav,
11
+ sbasCrcOk
12
+ } from "./chunk-ZIGMN3E5.js";
11
13
  import {
12
14
  CnavAssembler,
13
15
  cnavCrcOk
@@ -759,49 +759,6 @@ var GloStringAssembler = class {
759
759
  }
760
760
  };
761
761
 
762
- // src/navbits/sbas.ts
763
- var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
764
- var MS_PER_WEEK2 = 7 * 86400 * 1e3;
765
- var two2 = (n) => String(n).padStart(2, "0");
766
- var SBAS_MT_GEO_NAV = 9;
767
- function sbasMessageType(msg) {
768
- return getBitU(msg, 8, 6);
769
- }
770
- function sbasCrcOk(msg) {
771
- if (msg.length < 32) return false;
772
- return crc24q(msg, 226) === getBitU(msg, 226, 24);
773
- }
774
- function decodeSbasGeoNav(msg, prn, week, tow) {
775
- if (prn < 120 || prn > 158) return null;
776
- if (sbasMessageType(msg) !== SBAS_MT_GEO_NAV) return null;
777
- let t = getBitU(msg, 22, 13) * 16 - tow % 86400;
778
- if (t <= -43200) t += 86400;
779
- else if (t > 43200) t -= 86400;
780
- const t0Sec = tow + t;
781
- const ura = getBitU(msg, 35, 4);
782
- return {
783
- system: "S",
784
- prn: `S${two2(prn - 100)}`,
785
- tocDate: new Date(GPS_EPOCH_MS3 + week * MS_PER_WEEK2 + t0Sec * 1e3),
786
- tauN: getBitS(msg, 206, 12) * 2 ** -31,
787
- // a_Gf0, clock offset (s)
788
- gammaN: getBitS(msg, 218, 8) * 2 ** -39 / 2,
789
- // a_Gf1, clock drift (s/s)
790
- messageFrameTime: (tow % 86400 + 86400) % 86400,
791
- x: getBitS(msg, 39, 30) * 0.08 / 1e3,
792
- y: getBitS(msg, 69, 30) * 0.08 / 1e3,
793
- z: getBitS(msg, 99, 25) * 0.4 / 1e3,
794
- xDot: getBitS(msg, 124, 17) * 625e-6 / 1e3,
795
- yDot: getBitS(msg, 141, 17) * 625e-6 / 1e3,
796
- zDot: getBitS(msg, 158, 18) * 4e-3 / 1e3,
797
- xAcc: getBitS(msg, 176, 10) * 125e-7 / 1e3,
798
- yAcc: getBitS(msg, 186, 10) * 125e-7 / 1e3,
799
- zAcc: getBitS(msg, 196, 10) * 625e-7 / 1e3,
800
- health: ura === 15 ? 1 : 0,
801
- freqNum: 0
802
- };
803
- }
804
-
805
762
  export {
806
763
  bdsSubframeParityOk,
807
764
  BdsAssembler,
@@ -810,7 +767,5 @@ export {
810
767
  GalInavAssembler,
811
768
  GalFnavAssembler,
812
769
  testGloString,
813
- GloStringAssembler,
814
- sbasCrcOk,
815
- decodeSbasGeoNav
770
+ GloStringAssembler
816
771
  };
@@ -4,12 +4,14 @@ import {
4
4
  GalInavAssembler,
5
5
  GloStringAssembler,
6
6
  bdsSubframeParityOk,
7
- decodeSbasGeoNav,
8
7
  galFnavPageCrcOk,
9
8
  galInavPageCrcOk,
10
- sbasCrcOk,
11
9
  testGloString
12
- } from "./chunk-QV3XGDUU.js";
10
+ } from "./chunk-FA2UTLEQ.js";
11
+ import {
12
+ decodeSbasGeoNav,
13
+ sbasCrcOk
14
+ } from "./chunk-ZIGMN3E5.js";
13
15
  import {
14
16
  geodeticToEcef
15
17
  } from "./chunk-37QNKGTC.js";
@@ -1,3 +1,6 @@
1
+ import {
2
+ decodeSbasGeoNav
3
+ } from "./chunk-ZIGMN3E5.js";
1
4
  import {
2
5
  CnavAssembler,
3
6
  cnavCrcOk
@@ -62,6 +65,8 @@ var ID_GALEPHEMERIS = 1122;
62
65
  var ID_QZSSEPHEMERIS = 1336;
63
66
  var ID_GPSEPHEM = 7;
64
67
  var ID_BDSEPHEMERIS = 1696;
68
+ var ID_RAWWAASFRAME = 287;
69
+ var ID_RAWSBASFRAME = 973;
65
70
  var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
66
71
  var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
67
72
  var SEC_PER_WEEK = 7 * 86400;
@@ -323,6 +328,20 @@ function parseNovatelNav(data) {
323
328
  }
324
329
  lastGlo.set(eph.prn, eph);
325
330
  ephemerides.push(eph);
331
+ } else if ((frame.id === ID_RAWSBASFRAME || frame.id === ID_RAWWAASFRAME) && frame.msgLen >= 41) {
332
+ if (frame.week === 0) continue;
333
+ const p = frame.payload;
334
+ const prn = view.getUint32(p + 4, true);
335
+ const msg = new Uint8Array(32);
336
+ msg.set(data.subarray(p + 12, p + 41));
337
+ const eph = decodeSbasGeoNav(msg, prn, frame.week, frame.towMs / 1e3);
338
+ if (!eph) continue;
339
+ const prev = lastGlo.get(eph.prn);
340
+ if (prev && Math.abs(prev.tocDate.getTime() - eph.tocDate.getTime()) < 1e3 && prev.health === eph.health) {
341
+ continue;
342
+ }
343
+ lastGlo.set(eph.prn, eph);
344
+ ephemerides.push(eph);
326
345
  }
327
346
  }
328
347
  return {
@@ -1100,6 +1100,74 @@ 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 postProcessRtk(base, rover, ephemerides, baseEcef, opts = {}) {
1106
+ const tol = opts.pairToleranceMs ?? 500;
1107
+ const round = (ms) => Math.round(ms / 1e3) * 1e3;
1108
+ const baseByT = /* @__PURE__ */ new Map();
1109
+ for (const e of epochsOf(base)) baseByT.set(round(e.timeMs), e);
1110
+ const engine = new RtkFloatEngine(baseEcef, ephemerides, opts);
1111
+ const [bLat, bLon] = ecefToGeodetic(baseEcef[0], baseEcef[1], baseEcef[2]);
1112
+ const [sLat, cLat, sLon, cLon] = [
1113
+ Math.sin(bLat),
1114
+ Math.cos(bLat),
1115
+ Math.sin(bLon),
1116
+ Math.cos(bLon)
1117
+ ];
1118
+ const enuOf = (p) => {
1119
+ const dx = p[0] - baseEcef[0];
1120
+ const dy = p[1] - baseEcef[1];
1121
+ const dz = p[2] - baseEcef[2];
1122
+ return [
1123
+ -sLon * dx + cLon * dy,
1124
+ -sLat * cLon * dx - sLat * sLon * dy + cLat * dz,
1125
+ cLat * cLon * dx + cLat * sLon * dy + sLat * dz
1126
+ ];
1127
+ };
1128
+ const track = [];
1129
+ const seen = /* @__PURE__ */ new Set();
1130
+ let solved = 0;
1131
+ let unmatched = 0;
1132
+ let fixed = 0;
1133
+ const sorted = [...epochsOf(rover)].sort((a, b) => a.timeMs - b.timeMs);
1134
+ for (const rEp of sorted) {
1135
+ if (seen.has(rEp.timeMs)) continue;
1136
+ seen.add(rEp.timeMs);
1137
+ const bEp = baseByT.get(round(rEp.timeMs));
1138
+ if (!bEp || Math.abs(bEp.timeMs - rEp.timeMs) > tol) {
1139
+ unmatched++;
1140
+ continue;
1141
+ }
1142
+ const sol = engine.process(
1143
+ toRtkEpoch(rEp.meas),
1144
+ toRtkEpoch(bEp.meas),
1145
+ rEp.timeMs
1146
+ );
1147
+ if (!sol) continue;
1148
+ solved++;
1149
+ if (sol.status === "fixed") fixed++;
1150
+ const [lat, lon, height] = ecefToGeodetic(
1151
+ sol.position[0],
1152
+ sol.position[1],
1153
+ sol.position[2]
1154
+ );
1155
+ track.push({
1156
+ timeMs: rEp.timeMs,
1157
+ position: sol.position,
1158
+ lat,
1159
+ lon,
1160
+ height,
1161
+ enu: enuOf(sol.position),
1162
+ status: sol.status,
1163
+ ratio: sol.ratio,
1164
+ nSats: sol.nSats,
1165
+ nFixed: sol.nFixed
1166
+ });
1167
+ }
1168
+ return { track, solved, unmatched, fixRate: solved ? fixed / solved : 0 };
1169
+ }
1170
+
1103
1171
  // src/positioning/ppp-tropo.ts
1104
1172
  var HYD_AVG_A = [
1105
1173
  0.0012769934,
@@ -2627,6 +2695,7 @@ export {
2627
2695
  toRtkEpoch,
2628
2696
  solveDgnss,
2629
2697
  RtkFloatEngine,
2698
+ postProcessRtk,
2630
2699
  niellMapping,
2631
2700
  gmst,
2632
2701
  sunEcef,
@@ -0,0 +1,55 @@
1
+ import {
2
+ crc24q
3
+ } from "./chunk-YUW33VXK.js";
4
+ import {
5
+ getBitS,
6
+ getBitU
7
+ } from "./chunk-V2D5KUKH.js";
8
+
9
+ // src/navbits/sbas.ts
10
+ var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
11
+ var MS_PER_WEEK = 7 * 86400 * 1e3;
12
+ var two = (n) => String(n).padStart(2, "0");
13
+ var SBAS_MT_GEO_NAV = 9;
14
+ function sbasMessageType(msg) {
15
+ return getBitU(msg, 8, 6);
16
+ }
17
+ function sbasCrcOk(msg) {
18
+ if (msg.length < 32) return false;
19
+ return crc24q(msg, 226) === getBitU(msg, 226, 24);
20
+ }
21
+ function decodeSbasGeoNav(msg, prn, week, tow) {
22
+ if (prn < 120 || prn > 158) return null;
23
+ if (sbasMessageType(msg) !== SBAS_MT_GEO_NAV) return null;
24
+ let t = getBitU(msg, 22, 13) * 16 - tow % 86400;
25
+ if (t <= -43200) t += 86400;
26
+ else if (t > 43200) t -= 86400;
27
+ const t0Sec = tow + t;
28
+ const ura = getBitU(msg, 35, 4);
29
+ return {
30
+ system: "S",
31
+ prn: `S${two(prn - 100)}`,
32
+ tocDate: new Date(GPS_EPOCH_MS + week * MS_PER_WEEK + t0Sec * 1e3),
33
+ tauN: getBitS(msg, 206, 12) * 2 ** -31,
34
+ // a_Gf0, clock offset (s)
35
+ gammaN: getBitS(msg, 218, 8) * 2 ** -39 / 2,
36
+ // a_Gf1, clock drift (s/s)
37
+ messageFrameTime: (tow % 86400 + 86400) % 86400,
38
+ x: getBitS(msg, 39, 30) * 0.08 / 1e3,
39
+ y: getBitS(msg, 69, 30) * 0.08 / 1e3,
40
+ z: getBitS(msg, 99, 25) * 0.4 / 1e3,
41
+ xDot: getBitS(msg, 124, 17) * 625e-6 / 1e3,
42
+ yDot: getBitS(msg, 141, 17) * 625e-6 / 1e3,
43
+ zDot: getBitS(msg, 158, 18) * 4e-3 / 1e3,
44
+ xAcc: getBitS(msg, 176, 10) * 125e-7 / 1e3,
45
+ yAcc: getBitS(msg, 186, 10) * 125e-7 / 1e3,
46
+ zAcc: getBitS(msg, 196, 10) * 625e-7 / 1e3,
47
+ health: ura === 15 ? 1 : 0,
48
+ freqNum: 0
49
+ };
50
+ }
51
+
52
+ export {
53
+ sbasCrcOk,
54
+ decodeSbasGeoNav
55
+ };
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,
@@ -9169,6 +9170,8 @@ var ID_GALEPHEMERIS = 1122;
9169
9170
  var ID_QZSSEPHEMERIS = 1336;
9170
9171
  var ID_GPSEPHEM = 7;
9171
9172
  var ID_BDSEPHEMERIS = 1696;
9173
+ var ID_RAWWAASFRAME = 287;
9174
+ var ID_RAWSBASFRAME = 973;
9172
9175
  var GPS_EPOCH_MS13 = Date.UTC(1980, 0, 6);
9173
9176
  var BDT_EPOCH_MS3 = Date.UTC(2006, 0, 1);
9174
9177
  var SEC_PER_WEEK9 = 7 * 86400;
@@ -9430,6 +9433,20 @@ function parseNovatelNav(data) {
9430
9433
  }
9431
9434
  lastGlo.set(eph.prn, eph);
9432
9435
  ephemerides.push(eph);
9436
+ } else if ((frame.id === ID_RAWSBASFRAME || frame.id === ID_RAWWAASFRAME) && frame.msgLen >= 41) {
9437
+ if (frame.week === 0) continue;
9438
+ const p = frame.payload;
9439
+ const prn = view.getUint32(p + 4, true);
9440
+ const msg = new Uint8Array(32);
9441
+ msg.set(data.subarray(p + 12, p + 41));
9442
+ const eph = decodeSbasGeoNav(msg, prn, frame.week, frame.towMs / 1e3);
9443
+ if (!eph) continue;
9444
+ const prev = lastGlo.get(eph.prn);
9445
+ if (prev && Math.abs(prev.tocDate.getTime() - eph.tocDate.getTime()) < 1e3 && prev.health === eph.health) {
9446
+ continue;
9447
+ }
9448
+ lastGlo.set(eph.prn, eph);
9449
+ ephemerides.push(eph);
9433
9450
  }
9434
9451
  }
9435
9452
  return {
@@ -13016,6 +13033,74 @@ var RtkFloatEngine = class {
13016
13033
  }
13017
13034
  };
13018
13035
 
13036
+ // src/positioning/rtk-postprocess.ts
13037
+ var epochsOf = (o) => Array.isArray(o) ? o : o.epochs;
13038
+ function postProcessRtk(base, rover, ephemerides, baseEcef, opts = {}) {
13039
+ const tol = opts.pairToleranceMs ?? 500;
13040
+ const round = (ms) => Math.round(ms / 1e3) * 1e3;
13041
+ const baseByT = /* @__PURE__ */ new Map();
13042
+ for (const e of epochsOf(base)) baseByT.set(round(e.timeMs), e);
13043
+ const engine = new RtkFloatEngine(baseEcef, ephemerides, opts);
13044
+ const [bLat, bLon] = ecefToGeodetic(baseEcef[0], baseEcef[1], baseEcef[2]);
13045
+ const [sLat, cLat, sLon, cLon] = [
13046
+ Math.sin(bLat),
13047
+ Math.cos(bLat),
13048
+ Math.sin(bLon),
13049
+ Math.cos(bLon)
13050
+ ];
13051
+ const enuOf = (p) => {
13052
+ const dx = p[0] - baseEcef[0];
13053
+ const dy = p[1] - baseEcef[1];
13054
+ const dz = p[2] - baseEcef[2];
13055
+ return [
13056
+ -sLon * dx + cLon * dy,
13057
+ -sLat * cLon * dx - sLat * sLon * dy + cLat * dz,
13058
+ cLat * cLon * dx + cLat * sLon * dy + sLat * dz
13059
+ ];
13060
+ };
13061
+ const track = [];
13062
+ const seen = /* @__PURE__ */ new Set();
13063
+ let solved = 0;
13064
+ let unmatched = 0;
13065
+ let fixed = 0;
13066
+ const sorted = [...epochsOf(rover)].sort((a, b) => a.timeMs - b.timeMs);
13067
+ for (const rEp of sorted) {
13068
+ if (seen.has(rEp.timeMs)) continue;
13069
+ seen.add(rEp.timeMs);
13070
+ const bEp = baseByT.get(round(rEp.timeMs));
13071
+ if (!bEp || Math.abs(bEp.timeMs - rEp.timeMs) > tol) {
13072
+ unmatched++;
13073
+ continue;
13074
+ }
13075
+ const sol = engine.process(
13076
+ toRtkEpoch(rEp.meas),
13077
+ toRtkEpoch(bEp.meas),
13078
+ rEp.timeMs
13079
+ );
13080
+ if (!sol) continue;
13081
+ solved++;
13082
+ if (sol.status === "fixed") fixed++;
13083
+ const [lat, lon, height] = ecefToGeodetic(
13084
+ sol.position[0],
13085
+ sol.position[1],
13086
+ sol.position[2]
13087
+ );
13088
+ track.push({
13089
+ timeMs: rEp.timeMs,
13090
+ position: sol.position,
13091
+ lat,
13092
+ lon,
13093
+ height,
13094
+ enu: enuOf(sol.position),
13095
+ status: sol.status,
13096
+ ratio: sol.ratio,
13097
+ nSats: sol.nSats,
13098
+ nFixed: sol.nFixed
13099
+ });
13100
+ }
13101
+ return { track, solved, unmatched, fixRate: solved ? fixed / solved : 0 };
13102
+ }
13103
+
13019
13104
  // src/positioning/ppp-tropo.ts
13020
13105
  var HYD_AVG_A = [
13021
13106
  0.0012769934,
@@ -17056,6 +17141,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
17056
17141
  phiBOCc,
17057
17142
  phiBOCs,
17058
17143
  phiBPSK,
17144
+ postProcessRtk,
17059
17145
  rad2deg,
17060
17146
  rangeRate,
17061
17147
  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
@@ -50,7 +50,7 @@ import {
50
50
  parseUbxRawNav,
51
51
  parseUbxRawx,
52
52
  ubxFrames
53
- } from "./chunk-Z5VLTH33.js";
53
+ } from "./chunk-EQNC24OB.js";
54
54
  import {
55
55
  crc16,
56
56
  decodeSbfNavigation,
@@ -68,15 +68,16 @@ import {
68
68
  parseSbfNav,
69
69
  parseSbfReceiverSetup,
70
70
  scanSbfFrames
71
- } from "./chunk-6EZUM2MB.js";
72
- import "./chunk-QV3XGDUU.js";
71
+ } from "./chunk-MEDAWNWM.js";
72
+ import "./chunk-FA2UTLEQ.js";
73
73
  import {
74
74
  OEM4_HLEN,
75
75
  crc32,
76
76
  oem4Frames,
77
77
  parseNovatelNav,
78
78
  parseNovatelRange
79
- } from "./chunk-5X4AG4MK.js";
79
+ } from "./chunk-ROVSSEGZ.js";
80
+ import "./chunk-ZIGMN3E5.js";
80
81
  import {
81
82
  parseTrimble,
82
83
  parseTrimbleNav,
@@ -127,19 +128,6 @@ import {
127
128
  getTimeOfDay,
128
129
  getWeekOfYear
129
130
  } from "./chunk-L5OUUNLT.js";
130
- import {
131
- deg2dms,
132
- deg2rad,
133
- euclidean3D,
134
- geodeticToGeohash,
135
- geodeticToMaidenhead,
136
- geodeticToUtm,
137
- greatCircleMidpoint,
138
- horizonDistance,
139
- rad2deg,
140
- rhumbLine,
141
- vincenty
142
- } from "./chunk-MIIM4LDY.js";
143
131
  import {
144
132
  REFERENCE_FRAMES,
145
133
  applyHelmert,
@@ -166,6 +154,7 @@ import {
166
154
  moonEcef,
167
155
  niellMapping,
168
156
  nlWavelength,
157
+ postProcessRtk,
169
158
  resolvePppAmbiguities,
170
159
  satClockCorrection,
171
160
  solidEarthTide,
@@ -175,7 +164,7 @@ import {
175
164
  sunEcef,
176
165
  toRtkEpoch,
177
166
  wlWavelength
178
- } from "./chunk-3FG4XVCB.js";
167
+ } from "./chunk-XYCECWWS.js";
179
168
  import {
180
169
  almanacEpochMs,
181
170
  almanacSatPosition,
@@ -197,6 +186,19 @@ import {
197
186
  rangeRate,
198
187
  selectEphemeris
199
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";
200
202
  import {
201
203
  clampUnit,
202
204
  ecefToGeodetic,
@@ -616,6 +618,7 @@ export {
616
618
  phiBOCc,
617
619
  phiBOCs,
618
620
  phiBPSK,
621
+ postProcessRtk,
619
622
  rad2deg,
620
623
  rangeRate,
621
624
  readString,
package/dist/novatel.cjs CHANGED
@@ -398,6 +398,45 @@ var CnavAssembler = class {
398
398
  }
399
399
  };
400
400
 
401
+ // src/navbits/sbas.ts
402
+ var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
403
+ var MS_PER_WEEK = 7 * 86400 * 1e3;
404
+ var two = (n) => String(n).padStart(2, "0");
405
+ var SBAS_MT_GEO_NAV = 9;
406
+ function sbasMessageType(msg) {
407
+ return getBitU(msg, 8, 6);
408
+ }
409
+ function decodeSbasGeoNav(msg, prn, week, tow) {
410
+ if (prn < 120 || prn > 158) return null;
411
+ if (sbasMessageType(msg) !== SBAS_MT_GEO_NAV) return null;
412
+ let t = getBitU(msg, 22, 13) * 16 - tow % 86400;
413
+ if (t <= -43200) t += 86400;
414
+ else if (t > 43200) t -= 86400;
415
+ const t0Sec = tow + t;
416
+ const ura = getBitU(msg, 35, 4);
417
+ return {
418
+ system: "S",
419
+ prn: `S${two(prn - 100)}`,
420
+ tocDate: new Date(GPS_EPOCH_MS3 + week * MS_PER_WEEK + t0Sec * 1e3),
421
+ tauN: getBitS(msg, 206, 12) * 2 ** -31,
422
+ // a_Gf0, clock offset (s)
423
+ gammaN: getBitS(msg, 218, 8) * 2 ** -39 / 2,
424
+ // a_Gf1, clock drift (s/s)
425
+ messageFrameTime: (tow % 86400 + 86400) % 86400,
426
+ x: getBitS(msg, 39, 30) * 0.08 / 1e3,
427
+ y: getBitS(msg, 69, 30) * 0.08 / 1e3,
428
+ z: getBitS(msg, 99, 25) * 0.4 / 1e3,
429
+ xDot: getBitS(msg, 124, 17) * 625e-6 / 1e3,
430
+ yDot: getBitS(msg, 141, 17) * 625e-6 / 1e3,
431
+ zDot: getBitS(msg, 158, 18) * 4e-3 / 1e3,
432
+ xAcc: getBitS(msg, 176, 10) * 125e-7 / 1e3,
433
+ yAcc: getBitS(msg, 186, 10) * 125e-7 / 1e3,
434
+ zAcc: getBitS(msg, 196, 10) * 625e-7 / 1e3,
435
+ health: ura === 15 ? 1 : 0,
436
+ freqNum: 0
437
+ };
438
+ }
439
+
401
440
  // src/constants/time.ts
402
441
  var MILLISECONDS_IN_SECOND = 1e3;
403
442
  var MILLISECONDS_GPS_TAI = 19e3;
@@ -494,18 +533,20 @@ var ID_GALEPHEMERIS = 1122;
494
533
  var ID_QZSSEPHEMERIS = 1336;
495
534
  var ID_GPSEPHEM = 7;
496
535
  var ID_BDSEPHEMERIS = 1696;
497
- var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
536
+ var ID_RAWWAASFRAME = 287;
537
+ var ID_RAWSBASFRAME = 973;
538
+ var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
498
539
  var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
499
540
  var SEC_PER_WEEK3 = 7 * 86400;
500
541
  var SEC_PER_DAY = 86400;
501
- var MS_PER_WEEK = SEC_PER_WEEK3 * 1e3;
502
- var gpsMs = (week, sec) => GPS_EPOCH_MS3 + week * MS_PER_WEEK + sec * 1e3;
542
+ var MS_PER_WEEK2 = SEC_PER_WEEK3 * 1e3;
543
+ var gpsMs = (week, sec) => GPS_EPOCH_MS4 + week * MS_PER_WEEK2 + sec * 1e3;
503
544
  var sowOf = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK3;
504
545
  function nearWeekMs(refMs, sow) {
505
- const refWeek = Math.floor((refMs - GPS_EPOCH_MS3) / MS_PER_WEEK);
546
+ const refWeek = Math.floor((refMs - GPS_EPOCH_MS4) / MS_PER_WEEK2);
506
547
  let ms = gpsMs(refWeek, sow);
507
- if (ms < refMs - MS_PER_WEEK / 2) ms += MS_PER_WEEK;
508
- else if (ms > refMs + MS_PER_WEEK / 2) ms -= MS_PER_WEEK;
548
+ if (ms < refMs - MS_PER_WEEK2 / 2) ms += MS_PER_WEEK2;
549
+ else if (ms > refMs + MS_PER_WEEK2 / 2) ms -= MS_PER_WEEK2;
509
550
  return ms;
510
551
  }
511
552
  function decodeRawEphem(data, view, p) {
@@ -529,9 +570,9 @@ function decodeGloEphemeris(view, p) {
529
570
  tof += Math.floor(tow / SEC_PER_DAY) * SEC_PER_DAY;
530
571
  if (tof < tow - 43200) tof += SEC_PER_DAY;
531
572
  else if (tof > tow + 43200) tof -= SEC_PER_DAY;
532
- const toeGpsMs = GPS_EPOCH_MS3 + (week * SEC_PER_WEEK3 + tow) * 1e3;
533
- const tofGpsMs = GPS_EPOCH_MS3 + (week * SEC_PER_WEEK3 + tof) * 1e3;
534
- const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS3) / 1e3;
573
+ const toeGpsMs = GPS_EPOCH_MS4 + (week * SEC_PER_WEEK3 + tow) * 1e3;
574
+ const tofGpsMs = GPS_EPOCH_MS4 + (week * SEC_PER_WEEK3 + tof) * 1e3;
575
+ const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS4) / 1e3;
535
576
  return {
536
577
  system: "R",
537
578
  prn: `R${String(slot).padStart(2, "0")}`,
@@ -596,7 +637,7 @@ function decodeGalEphemeris(view, p, headerMs) {
596
637
  omega: view.getFloat64(p + 60, true),
597
638
  omegaDot: view.getFloat64(p + 140, true),
598
639
  idot: view.getFloat64(p + 124, true),
599
- week: Math.floor((toeMs - GPS_EPOCH_MS3) / MS_PER_WEEK),
640
+ week: Math.floor((toeMs - GPS_EPOCH_MS4) / MS_PER_WEEK2),
600
641
  // RINEX Galileo SVH bit layout (E1B DVS/HS in bits 0-2, E5a in
601
642
  // 3-5, E5b in 6-8) — same packing as RTKLIB.
602
643
  svHealth: svhE5b << 7 | dvsE5b << 6 | svhE5a << 4 | dvsE5a << 3 | svhE1b << 1 | dvsE1b,
@@ -613,7 +654,7 @@ function decodeBdsEphemeris(view, p) {
613
654
  const tgd1 = view.getFloat64(p + 20, true);
614
655
  const tocs = view.getUint32(p + 40, true);
615
656
  const toes = view.getUint32(p + 72, true);
616
- const tocDate = new Date(BDT_EPOCH_MS + week * MS_PER_WEEK + tocs * 1e3);
657
+ const tocDate = new Date(BDT_EPOCH_MS + week * MS_PER_WEEK2 + tocs * 1e3);
617
658
  return {
618
659
  system: "C",
619
660
  prn: `C${String(prn).padStart(2, "0")}`,
@@ -755,6 +796,20 @@ function parseNovatelNav(data) {
755
796
  }
756
797
  lastGlo.set(eph.prn, eph);
757
798
  ephemerides.push(eph);
799
+ } else if ((frame.id === ID_RAWSBASFRAME || frame.id === ID_RAWWAASFRAME) && frame.msgLen >= 41) {
800
+ if (frame.week === 0) continue;
801
+ const p = frame.payload;
802
+ const prn = view.getUint32(p + 4, true);
803
+ const msg = new Uint8Array(32);
804
+ msg.set(data.subarray(p + 12, p + 41));
805
+ const eph = decodeSbasGeoNav(msg, prn, frame.week, frame.towMs / 1e3);
806
+ if (!eph) continue;
807
+ const prev = lastGlo.get(eph.prn);
808
+ if (prev && Math.abs(prev.tocDate.getTime() - eph.tocDate.getTime()) < 1e3 && prev.health === eph.health) {
809
+ continue;
810
+ }
811
+ lastGlo.set(eph.prn, eph);
812
+ ephemerides.push(eph);
758
813
  }
759
814
  }
760
815
  return {
@@ -768,8 +823,8 @@ function parseNovatelNav(data) {
768
823
  }
769
824
 
770
825
  // src/novatel/index.ts
771
- var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
772
- var MS_PER_WEEK2 = 7 * 864e5;
826
+ var GPS_EPOCH_MS5 = Date.UTC(1980, 0, 6);
827
+ var MS_PER_WEEK3 = 7 * 864e5;
773
828
  var HDR = 28;
774
829
  var ID_RANGE = 43;
775
830
  var ID_RANGECMP = 140;
@@ -938,7 +993,7 @@ function parseNovatelRange(data) {
938
993
  if (!codes.includes(code)) codes.push(code);
939
994
  }
940
995
  epochs.push({
941
- timeMs: GPS_EPOCH_MS4 + week * MS_PER_WEEK2 + towMs,
996
+ timeMs: GPS_EPOCH_MS5 + week * MS_PER_WEEK3 + towMs,
942
997
  meas
943
998
  });
944
999
  }
@@ -990,7 +1045,7 @@ function parseNovatelRange(data) {
990
1045
  if (!codes.includes(code)) codes.push(code);
991
1046
  }
992
1047
  epochs.push({
993
- timeMs: GPS_EPOCH_MS4 + week * MS_PER_WEEK2 + towMs,
1048
+ timeMs: GPS_EPOCH_MS5 + week * MS_PER_WEEK3 + towMs,
994
1049
  meas
995
1050
  });
996
1051
  }
@@ -39,16 +39,28 @@ declare function oem4Frames(data: Uint8Array, view: DataView, stats: {
39
39
  * NovAtel navigation-message decoding: RAWEPHEM (message 41, raw GPS
40
40
  * LNAV subframes 1–3), GLOEPHEMERIS (message 723, decoded GLONASS
41
41
  * L1 C/A ephemeris), GALEPHEMERIS (1122), BDSEPHEMERIS (1696),
42
- * QZSSEPHEMERIS (1336) and IONUTC (8, GPS Klobuchar + UTC parameters).
42
+ * QZSSEPHEMERIS (1336), RAWSBASFRAME (973) / RAWWAASFRAME (287, its
43
+ * OEMV-era twin — raw SBAS L1 GEO messages) and IONUTC (8, GPS
44
+ * Klobuchar + UTC parameters).
43
45
  *
44
46
  * Ported from RTKLIB demo5 (rtklibexplorer fork, src/rcv/novatel.c:
45
47
  * decode_rawephemb / decode_gloephemerisb / decode_galephemerisb /
46
- * decode_bdsephemerisb / decode_ionutcb, Copyright (c) 2007-2020
47
- * T. Takasu, BSD-2-Clause) and cross-checked against the OEM7
48
- * Commands and Logs Reference Manual. QZSSEPHEMERIS has no RTKLIB
49
- * decoder (RTKLIB only handles the raw-subframe QZSSRAWEPHEM 1331);
50
- * its layout is taken from the OEM7 manual §3.150 and is therefore
51
- * synthetic-tested only, like SBF's QZSNav.
48
+ * decode_bdsephemerisb / decode_rawsbasframeb / decode_ionutcb,
49
+ * Copyright (c) 2007-2020 T. Takasu, BSD-2-Clause) and cross-checked
50
+ * against the OEM7 Commands and Logs Reference Manual. QZSSEPHEMERIS
51
+ * has no RTKLIB decoder (RTKLIB only handles the raw-subframe
52
+ * QZSSRAWEPHEM 1331); its layout is taken from the OEM7 manual §3.150
53
+ * and is therefore synthetic-tested only, like SBF's QZSNav.
54
+ *
55
+ * RAWSBASFRAME/RAWWAASFRAME carry the 250-bit SBAS L1 message as a
56
+ * 29-byte field (OEM7 manual §3.169: after the header, frame-decoder
57
+ * u4, PRN u4, a u4, then 29 bytes of message). Message type 9 (GEO
58
+ * navigation) is decoded by the shared `decodeSbasGeoNav`, the same
59
+ * decoder the u-blox and SBF paths use; other message types (fast/long
60
+ * corrections, etc.) are skipped. Because only 29 bytes (232 bits) are
61
+ * carried — enough for every MT9 field but 18 bits short of the 24-bit
62
+ * SBAS CRC — the SBAS CRC is not re-checked; the OEM4 CRC-32 over the
63
+ * whole log already guarantees the transported bytes.
52
64
  *
53
65
  * Output records mirror what `parseNavFile` produces for the
54
66
  * equivalent RINEX 3 navigation file: Keplerian `tocDate` is a
package/dist/novatel.d.ts CHANGED
@@ -39,16 +39,28 @@ declare function oem4Frames(data: Uint8Array, view: DataView, stats: {
39
39
  * NovAtel navigation-message decoding: RAWEPHEM (message 41, raw GPS
40
40
  * LNAV subframes 1–3), GLOEPHEMERIS (message 723, decoded GLONASS
41
41
  * L1 C/A ephemeris), GALEPHEMERIS (1122), BDSEPHEMERIS (1696),
42
- * QZSSEPHEMERIS (1336) and IONUTC (8, GPS Klobuchar + UTC parameters).
42
+ * QZSSEPHEMERIS (1336), RAWSBASFRAME (973) / RAWWAASFRAME (287, its
43
+ * OEMV-era twin — raw SBAS L1 GEO messages) and IONUTC (8, GPS
44
+ * Klobuchar + UTC parameters).
43
45
  *
44
46
  * Ported from RTKLIB demo5 (rtklibexplorer fork, src/rcv/novatel.c:
45
47
  * decode_rawephemb / decode_gloephemerisb / decode_galephemerisb /
46
- * decode_bdsephemerisb / decode_ionutcb, Copyright (c) 2007-2020
47
- * T. Takasu, BSD-2-Clause) and cross-checked against the OEM7
48
- * Commands and Logs Reference Manual. QZSSEPHEMERIS has no RTKLIB
49
- * decoder (RTKLIB only handles the raw-subframe QZSSRAWEPHEM 1331);
50
- * its layout is taken from the OEM7 manual §3.150 and is therefore
51
- * synthetic-tested only, like SBF's QZSNav.
48
+ * decode_bdsephemerisb / decode_rawsbasframeb / decode_ionutcb,
49
+ * Copyright (c) 2007-2020 T. Takasu, BSD-2-Clause) and cross-checked
50
+ * against the OEM7 Commands and Logs Reference Manual. QZSSEPHEMERIS
51
+ * has no RTKLIB decoder (RTKLIB only handles the raw-subframe
52
+ * QZSSRAWEPHEM 1331); its layout is taken from the OEM7 manual §3.150
53
+ * and is therefore synthetic-tested only, like SBF's QZSNav.
54
+ *
55
+ * RAWSBASFRAME/RAWWAASFRAME carry the 250-bit SBAS L1 message as a
56
+ * 29-byte field (OEM7 manual §3.169: after the header, frame-decoder
57
+ * u4, PRN u4, a u4, then 29 bytes of message). Message type 9 (GEO
58
+ * navigation) is decoded by the shared `decodeSbasGeoNav`, the same
59
+ * decoder the u-blox and SBF paths use; other message types (fast/long
60
+ * corrections, etc.) are skipped. Because only 29 bytes (232 bits) are
61
+ * carried — enough for every MT9 field but 18 bits short of the 24-bit
62
+ * SBAS CRC — the SBAS CRC is not re-checked; the OEM4 CRC-32 over the
63
+ * whole log already guarantees the transported bytes.
52
64
  *
53
65
  * Output records mirror what `parseNavFile` produces for the
54
66
  * equivalent RINEX 3 navigation file: Keplerian `tocDate` is a
package/dist/novatel.js CHANGED
@@ -4,7 +4,8 @@ import {
4
4
  oem4Frames,
5
5
  parseNovatelNav,
6
6
  parseNovatelRange
7
- } from "./chunk-5X4AG4MK.js";
7
+ } from "./chunk-ROVSSEGZ.js";
8
+ import "./chunk-ZIGMN3E5.js";
8
9
  import "./chunk-YUW33VXK.js";
9
10
  import "./chunk-V2D5KUKH.js";
10
11
  import "./chunk-HVXYFUCB.js";
@@ -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,74 @@ 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 postProcessRtk(base, rover, ephemerides, baseEcef, opts = {}) {
1562
+ const tol = opts.pairToleranceMs ?? 500;
1563
+ const round = (ms) => Math.round(ms / 1e3) * 1e3;
1564
+ const baseByT = /* @__PURE__ */ new Map();
1565
+ for (const e of epochsOf(base)) baseByT.set(round(e.timeMs), e);
1566
+ const engine = new RtkFloatEngine(baseEcef, ephemerides, opts);
1567
+ const [bLat, bLon] = ecefToGeodetic(baseEcef[0], baseEcef[1], baseEcef[2]);
1568
+ const [sLat, cLat, sLon, cLon] = [
1569
+ Math.sin(bLat),
1570
+ Math.cos(bLat),
1571
+ Math.sin(bLon),
1572
+ Math.cos(bLon)
1573
+ ];
1574
+ const enuOf = (p) => {
1575
+ const dx = p[0] - baseEcef[0];
1576
+ const dy = p[1] - baseEcef[1];
1577
+ const dz = p[2] - baseEcef[2];
1578
+ return [
1579
+ -sLon * dx + cLon * dy,
1580
+ -sLat * cLon * dx - sLat * sLon * dy + cLat * dz,
1581
+ cLat * cLon * dx + cLat * sLon * dy + sLat * dz
1582
+ ];
1583
+ };
1584
+ const track = [];
1585
+ const seen = /* @__PURE__ */ new Set();
1586
+ let solved = 0;
1587
+ let unmatched = 0;
1588
+ let fixed = 0;
1589
+ const sorted = [...epochsOf(rover)].sort((a, b) => a.timeMs - b.timeMs);
1590
+ for (const rEp of sorted) {
1591
+ if (seen.has(rEp.timeMs)) continue;
1592
+ seen.add(rEp.timeMs);
1593
+ const bEp = baseByT.get(round(rEp.timeMs));
1594
+ if (!bEp || Math.abs(bEp.timeMs - rEp.timeMs) > tol) {
1595
+ unmatched++;
1596
+ continue;
1597
+ }
1598
+ const sol = engine.process(
1599
+ toRtkEpoch(rEp.meas),
1600
+ toRtkEpoch(bEp.meas),
1601
+ rEp.timeMs
1602
+ );
1603
+ if (!sol) continue;
1604
+ solved++;
1605
+ if (sol.status === "fixed") fixed++;
1606
+ const [lat, lon, height] = ecefToGeodetic(
1607
+ sol.position[0],
1608
+ sol.position[1],
1609
+ sol.position[2]
1610
+ );
1611
+ track.push({
1612
+ timeMs: rEp.timeMs,
1613
+ position: sol.position,
1614
+ lat,
1615
+ lon,
1616
+ height,
1617
+ enu: enuOf(sol.position),
1618
+ status: sol.status,
1619
+ ratio: sol.ratio,
1620
+ nSats: sol.nSats,
1621
+ nFixed: sol.nFixed
1622
+ });
1623
+ }
1624
+ return { track, solved, unmatched, fixRate: solved ? fixed / solved : 0 };
1625
+ }
1626
+
1558
1627
  // src/rinex/sp3.ts
1559
1628
  function sp3Position(sp3, prn, tMs, order = 9) {
1560
1629
  const samples = sp3.satellites[prn];
@@ -3164,6 +3233,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
3164
3233
  moonEcef,
3165
3234
  niellMapping,
3166
3235
  nlWavelength,
3236
+ postProcessRtk,
3167
3237
  resolvePppAmbiguities,
3168
3238
  satClockCorrection,
3169
3239
  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-XYCECWWS.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/dist/sbf.js CHANGED
@@ -15,8 +15,9 @@ import {
15
15
  parseSbfNav,
16
16
  parseSbfReceiverSetup,
17
17
  scanSbfFrames
18
- } from "./chunk-6EZUM2MB.js";
19
- import "./chunk-QV3XGDUU.js";
18
+ } from "./chunk-MEDAWNWM.js";
19
+ import "./chunk-FA2UTLEQ.js";
20
+ import "./chunk-ZIGMN3E5.js";
20
21
  import "./chunk-37QNKGTC.js";
21
22
  import "./chunk-6FAL6P4G.js";
22
23
  import "./chunk-YUW33VXK.js";
package/dist/ubx.js CHANGED
@@ -5,8 +5,9 @@ import {
5
5
  parseUbxRawNav,
6
6
  parseUbxRawx,
7
7
  ubxFrames
8
- } from "./chunk-Z5VLTH33.js";
9
- import "./chunk-QV3XGDUU.js";
8
+ } from "./chunk-EQNC24OB.js";
9
+ import "./chunk-FA2UTLEQ.js";
10
+ import "./chunk-ZIGMN3E5.js";
10
11
  import "./chunk-YUW33VXK.js";
11
12
  import "./chunk-V2D5KUKH.js";
12
13
  import "./chunk-HVXYFUCB.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gnss-js",
3
- "version": "1.43.0",
3
+ "version": "1.45.0",
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,