gnss-js 1.46.0 → 1.48.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.
@@ -1150,31 +1150,50 @@ function postProcessRtk(base, rover, ephemerides, baseEcef, opts = {}) {
1150
1150
  unmatched++;
1151
1151
  continue;
1152
1152
  }
1153
- const sol = engine.process(
1154
- toRtkEpoch(rEp.meas),
1155
- toRtkEpoch(bEp.meas),
1156
- rEp.timeMs
1157
- );
1158
- if (!sol) continue;
1153
+ let point;
1154
+ if (opts.codeOnly) {
1155
+ const dg = solveDgnss(
1156
+ toRtkEpoch(rEp.meas),
1157
+ toRtkEpoch(bEp.meas),
1158
+ baseEcef,
1159
+ ephemerides,
1160
+ rEp.timeMs,
1161
+ {
1162
+ elevationMaskDeg: opts.elevationMaskDeg,
1163
+ troposphere: opts.troposphere,
1164
+ codeSigmaM: opts.codeSigmaM
1165
+ }
1166
+ );
1167
+ point = dg ? {
1168
+ timeMs: rEp.timeMs,
1169
+ position: dg.position,
1170
+ status: "dgnss",
1171
+ nSats: dg.nSats
1172
+ } : null;
1173
+ } else {
1174
+ const sol = engine.process(
1175
+ toRtkEpoch(rEp.meas),
1176
+ toRtkEpoch(bEp.meas),
1177
+ rEp.timeMs
1178
+ );
1179
+ point = sol ? {
1180
+ timeMs: rEp.timeMs,
1181
+ position: sol.position,
1182
+ status: sol.status,
1183
+ ratio: sol.ratio,
1184
+ nSats: sol.nSats,
1185
+ nFixed: sol.nFixed
1186
+ } : null;
1187
+ }
1188
+ if (!point) continue;
1159
1189
  solved++;
1160
- if (sol.status === "fixed") fixed++;
1190
+ if (point.status === "fixed") fixed++;
1161
1191
  const [lat, lon, height] = ecefToGeodetic(
1162
- sol.position[0],
1163
- sol.position[1],
1164
- sol.position[2]
1192
+ point.position[0],
1193
+ point.position[1],
1194
+ point.position[2]
1165
1195
  );
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
- });
1196
+ track.push({ ...point, lat, lon, height, enu: enuOf(point.position) });
1178
1197
  }
1179
1198
  return { track, solved, unmatched, fixRate: solved ? fixed / solved : 0 };
1180
1199
  }
@@ -1703,11 +1722,13 @@ var IDX_Z = 2;
1703
1722
  var IDX_ZWD = 3;
1704
1723
  var NBASE = 4;
1705
1724
  var CLK_VAR = 1e10;
1725
+ var POS_VAR = 60 * 60;
1706
1726
  function solvePpp(epochs, sp3, opts) {
1707
1727
  const elevMask = (opts.elevationMaskDeg ?? 10) * Math.PI / 180;
1708
1728
  const codeSigma = opts.codeSigma ?? 3;
1709
1729
  const phaseSigma = opts.phaseSigma ?? 0.01;
1710
1730
  const ztdQ = opts.ztdProcessNoise ?? 1e-8;
1731
+ const kinematic = opts.mode === "kinematic";
1711
1732
  const corrections = opts.corrections;
1712
1733
  const x = [
1713
1734
  opts.aprioriPos[0],
@@ -1803,6 +1824,15 @@ function solvePpp(epochs, sp3, opts) {
1803
1824
  let convergedStreak = 0;
1804
1825
  for (let ei = 0; ei < epochs.length; ei++) {
1805
1826
  const epoch = epochs[ei];
1827
+ if (kinematic && ei > 0) {
1828
+ for (const p of [IDX_X, IDX_Y, IDX_Z]) {
1829
+ for (let j = 0; j < x.length; j++) {
1830
+ P[p][j] = 0;
1831
+ P[j][p] = 0;
1832
+ }
1833
+ P[p][p] = POS_VAR;
1834
+ }
1835
+ }
1806
1836
  for (const ci of clkIdx.values()) P[ci][ci] = CLK_VAR;
1807
1837
  P[IDX_ZWD][IDX_ZWD] += ztdQ * (ei > 0 ? 1 : 0);
1808
1838
  const rcv = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
package/dist/index.cjs CHANGED
@@ -13083,31 +13083,50 @@ function postProcessRtk(base, rover, ephemerides, baseEcef, opts = {}) {
13083
13083
  unmatched++;
13084
13084
  continue;
13085
13085
  }
13086
- const sol = engine.process(
13087
- toRtkEpoch(rEp.meas),
13088
- toRtkEpoch(bEp.meas),
13089
- rEp.timeMs
13090
- );
13091
- if (!sol) continue;
13086
+ let point;
13087
+ if (opts.codeOnly) {
13088
+ const dg = solveDgnss(
13089
+ toRtkEpoch(rEp.meas),
13090
+ toRtkEpoch(bEp.meas),
13091
+ baseEcef,
13092
+ ephemerides,
13093
+ rEp.timeMs,
13094
+ {
13095
+ elevationMaskDeg: opts.elevationMaskDeg,
13096
+ troposphere: opts.troposphere,
13097
+ codeSigmaM: opts.codeSigmaM
13098
+ }
13099
+ );
13100
+ point = dg ? {
13101
+ timeMs: rEp.timeMs,
13102
+ position: dg.position,
13103
+ status: "dgnss",
13104
+ nSats: dg.nSats
13105
+ } : null;
13106
+ } else {
13107
+ const sol = engine.process(
13108
+ toRtkEpoch(rEp.meas),
13109
+ toRtkEpoch(bEp.meas),
13110
+ rEp.timeMs
13111
+ );
13112
+ point = sol ? {
13113
+ timeMs: rEp.timeMs,
13114
+ position: sol.position,
13115
+ status: sol.status,
13116
+ ratio: sol.ratio,
13117
+ nSats: sol.nSats,
13118
+ nFixed: sol.nFixed
13119
+ } : null;
13120
+ }
13121
+ if (!point) continue;
13092
13122
  solved++;
13093
- if (sol.status === "fixed") fixed++;
13123
+ if (point.status === "fixed") fixed++;
13094
13124
  const [lat, lon, height] = ecefToGeodetic(
13095
- sol.position[0],
13096
- sol.position[1],
13097
- sol.position[2]
13125
+ point.position[0],
13126
+ point.position[1],
13127
+ point.position[2]
13098
13128
  );
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
- });
13129
+ track.push({ ...point, lat, lon, height, enu: enuOf(point.position) });
13111
13130
  }
13112
13131
  return { track, solved, unmatched, fixRate: solved ? fixed / solved : 0 };
13113
13132
  }
@@ -13636,11 +13655,13 @@ var IDX_Z = 2;
13636
13655
  var IDX_ZWD = 3;
13637
13656
  var NBASE = 4;
13638
13657
  var CLK_VAR = 1e10;
13658
+ var POS_VAR = 60 * 60;
13639
13659
  function solvePpp(epochs, sp3, opts) {
13640
13660
  const elevMask = (opts.elevationMaskDeg ?? 10) * Math.PI / 180;
13641
13661
  const codeSigma = opts.codeSigma ?? 3;
13642
13662
  const phaseSigma = opts.phaseSigma ?? 0.01;
13643
13663
  const ztdQ = opts.ztdProcessNoise ?? 1e-8;
13664
+ const kinematic = opts.mode === "kinematic";
13644
13665
  const corrections = opts.corrections;
13645
13666
  const x = [
13646
13667
  opts.aprioriPos[0],
@@ -13736,6 +13757,15 @@ function solvePpp(epochs, sp3, opts) {
13736
13757
  let convergedStreak = 0;
13737
13758
  for (let ei = 0; ei < epochs.length; ei++) {
13738
13759
  const epoch = epochs[ei];
13760
+ if (kinematic && ei > 0) {
13761
+ for (const p of [IDX_X, IDX_Y, IDX_Z]) {
13762
+ for (let j = 0; j < x.length; j++) {
13763
+ P[p][j] = 0;
13764
+ P[j][p] = 0;
13765
+ }
13766
+ P[p][p] = POS_VAR;
13767
+ }
13768
+ }
13739
13769
  for (const ci of clkIdx.values()) P[ci][ci] = CLK_VAR;
13740
13770
  P[IDX_ZWD][IDX_ZWD] += ztdQ * (ei > 0 ? 1 : 0);
13741
13771
  const rcv = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
package/dist/index.js CHANGED
@@ -164,7 +164,7 @@ import {
164
164
  sunEcef,
165
165
  toRtkEpoch,
166
166
  wlWavelength
167
- } from "./chunk-VNDMPBKK.js";
167
+ } from "./chunk-KRXX4UGR.js";
168
168
  import {
169
169
  almanacEpochMs,
170
170
  almanacSatPosition,
@@ -1606,31 +1606,50 @@ function postProcessRtk(base, rover, ephemerides, baseEcef, opts = {}) {
1606
1606
  unmatched++;
1607
1607
  continue;
1608
1608
  }
1609
- const sol = engine.process(
1610
- toRtkEpoch(rEp.meas),
1611
- toRtkEpoch(bEp.meas),
1612
- rEp.timeMs
1613
- );
1614
- if (!sol) continue;
1609
+ let point;
1610
+ if (opts.codeOnly) {
1611
+ const dg = solveDgnss(
1612
+ toRtkEpoch(rEp.meas),
1613
+ toRtkEpoch(bEp.meas),
1614
+ baseEcef,
1615
+ ephemerides,
1616
+ rEp.timeMs,
1617
+ {
1618
+ elevationMaskDeg: opts.elevationMaskDeg,
1619
+ troposphere: opts.troposphere,
1620
+ codeSigmaM: opts.codeSigmaM
1621
+ }
1622
+ );
1623
+ point = dg ? {
1624
+ timeMs: rEp.timeMs,
1625
+ position: dg.position,
1626
+ status: "dgnss",
1627
+ nSats: dg.nSats
1628
+ } : null;
1629
+ } else {
1630
+ const sol = engine.process(
1631
+ toRtkEpoch(rEp.meas),
1632
+ toRtkEpoch(bEp.meas),
1633
+ rEp.timeMs
1634
+ );
1635
+ point = sol ? {
1636
+ timeMs: rEp.timeMs,
1637
+ position: sol.position,
1638
+ status: sol.status,
1639
+ ratio: sol.ratio,
1640
+ nSats: sol.nSats,
1641
+ nFixed: sol.nFixed
1642
+ } : null;
1643
+ }
1644
+ if (!point) continue;
1615
1645
  solved++;
1616
- if (sol.status === "fixed") fixed++;
1646
+ if (point.status === "fixed") fixed++;
1617
1647
  const [lat, lon, height] = ecefToGeodetic(
1618
- sol.position[0],
1619
- sol.position[1],
1620
- sol.position[2]
1648
+ point.position[0],
1649
+ point.position[1],
1650
+ point.position[2]
1621
1651
  );
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
- });
1652
+ track.push({ ...point, lat, lon, height, enu: enuOf(point.position) });
1634
1653
  }
1635
1654
  return { track, solved, unmatched, fixRate: solved ? fixed / solved : 0 };
1636
1655
  }
@@ -2231,11 +2250,13 @@ var IDX_Z = 2;
2231
2250
  var IDX_ZWD = 3;
2232
2251
  var NBASE = 4;
2233
2252
  var CLK_VAR = 1e10;
2253
+ var POS_VAR = 60 * 60;
2234
2254
  function solvePpp(epochs, sp3, opts) {
2235
2255
  const elevMask = (opts.elevationMaskDeg ?? 10) * Math.PI / 180;
2236
2256
  const codeSigma = opts.codeSigma ?? 3;
2237
2257
  const phaseSigma = opts.phaseSigma ?? 0.01;
2238
2258
  const ztdQ = opts.ztdProcessNoise ?? 1e-8;
2259
+ const kinematic = opts.mode === "kinematic";
2239
2260
  const corrections = opts.corrections;
2240
2261
  const x = [
2241
2262
  opts.aprioriPos[0],
@@ -2331,6 +2352,15 @@ function solvePpp(epochs, sp3, opts) {
2331
2352
  let convergedStreak = 0;
2332
2353
  for (let ei = 0; ei < epochs.length; ei++) {
2333
2354
  const epoch = epochs[ei];
2355
+ if (kinematic && ei > 0) {
2356
+ for (const p of [IDX_X, IDX_Y, IDX_Z]) {
2357
+ for (let j = 0; j < x.length; j++) {
2358
+ P[p][j] = 0;
2359
+ P[j][p] = 0;
2360
+ }
2361
+ P[p][p] = POS_VAR;
2362
+ }
2363
+ }
2334
2364
  for (const ci of clkIdx.values()) P[ci][ci] = CLK_VAR;
2335
2365
  P[IDX_ZWD][IDX_ZWD] += ztdQ * (ei > 0 ? 1 : 0);
2336
2366
  const rcv = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
@@ -437,6 +437,14 @@ interface RtkPostProcessOptions extends RtkFloatOptions {
437
437
  * mainly rejects a base gap rather than sub-second offsets.
438
438
  */
439
439
  pairToleranceMs?: number;
440
+ /**
441
+ * Code-only differential (DGNSS): solve each epoch from double-differenced
442
+ * pseudoranges via {@link solveDgnss} instead of the carrier-phase float
443
+ * engine. Every epoch is independent (no filter), so there is no ambiguity
444
+ * fixing — a robust metre→sub-metre fallback that needs no carrier phase.
445
+ * Track points come back with `status: 'dgnss'`. Default false.
446
+ */
447
+ codeOnly?: boolean;
440
448
  }
441
449
  interface RtkPostProcessResult {
442
450
  /** Solved rover epochs in time order. */
@@ -678,6 +686,14 @@ interface PppOptions {
678
686
  /** A priori receiver ECEF position (m). Required — from the RINEX header
679
687
  * approx position or an SPP solution. */
680
688
  aprioriPos: [number, number, number];
689
+ /**
690
+ * Rover dynamics. 'static' (default): the position is a single constant
691
+ * state, so all epochs average into one converged coordinate. 'kinematic':
692
+ * the position is white noise (RTKLIB `PMODE_PPP_KINEMA`) — re-estimated
693
+ * each epoch from that epoch's measurements while the carrier ambiguities
694
+ * (and troposphere) persist, so a moving receiver is tracked epoch by epoch.
695
+ */
696
+ mode?: 'static' | 'kinematic';
681
697
  /** Ground-truth ECEF (m) for reporting ENU error in the series. */
682
698
  groundTruth?: [number, number, number];
683
699
  /** Elevation cutoff (deg). Default 10. */
@@ -437,6 +437,14 @@ interface RtkPostProcessOptions extends RtkFloatOptions {
437
437
  * mainly rejects a base gap rather than sub-second offsets.
438
438
  */
439
439
  pairToleranceMs?: number;
440
+ /**
441
+ * Code-only differential (DGNSS): solve each epoch from double-differenced
442
+ * pseudoranges via {@link solveDgnss} instead of the carrier-phase float
443
+ * engine. Every epoch is independent (no filter), so there is no ambiguity
444
+ * fixing — a robust metre→sub-metre fallback that needs no carrier phase.
445
+ * Track points come back with `status: 'dgnss'`. Default false.
446
+ */
447
+ codeOnly?: boolean;
440
448
  }
441
449
  interface RtkPostProcessResult {
442
450
  /** Solved rover epochs in time order. */
@@ -678,6 +686,14 @@ interface PppOptions {
678
686
  /** A priori receiver ECEF position (m). Required — from the RINEX header
679
687
  * approx position or an SPP solution. */
680
688
  aprioriPos: [number, number, number];
689
+ /**
690
+ * Rover dynamics. 'static' (default): the position is a single constant
691
+ * state, so all epochs average into one converged coordinate. 'kinematic':
692
+ * the position is white noise (RTKLIB `PMODE_PPP_KINEMA`) — re-estimated
693
+ * each epoch from that epoch's measurements while the carrier ambiguities
694
+ * (and troposphere) persist, so a moving receiver is tracked epoch by epoch.
695
+ */
696
+ mode?: 'static' | 'kinematic';
681
697
  /** Ground-truth ECEF (m) for reporting ENU error in the series. */
682
698
  groundTruth?: [number, number, number];
683
699
  /** Elevation cutoff (deg). Default 10. */
@@ -28,7 +28,7 @@ import {
28
28
  sunEcef,
29
29
  toRtkEpoch,
30
30
  wlWavelength
31
- } from "./chunk-VNDMPBKK.js";
31
+ } from "./chunk-KRXX4UGR.js";
32
32
  import "./chunk-MHGNKSSH.js";
33
33
  import "./chunk-MIIM4LDY.js";
34
34
  import "./chunk-37QNKGTC.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gnss-js",
3
- "version": "1.46.0",
3
+ "version": "1.48.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,