gnss-js 1.66.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -79,6 +79,7 @@ __export(src_exports, {
79
79
  MultipathAccumulator: () => MultipathAccumulator,
80
80
  OEM4_HLEN: () => OEM4_HLEN,
81
81
  OMEGA_E: () => OMEGA_E,
82
+ PppEngine: () => PppEngine,
82
83
  REFERENCE_FRAMES: () => REFERENCE_FRAMES,
83
84
  RINEX_CODES: () => RINEX_CODES,
84
85
  RTCM2_MESSAGE_NAMES: () => RTCM2_MESSAGE_NAMES,
@@ -106,6 +107,7 @@ __export(src_exports, {
106
107
  SYS_SHORT: () => SYS_SHORT,
107
108
  SbasProcessor: () => SbasProcessor,
108
109
  Scale: () => Scale,
110
+ Sp3EphemerisSource: () => Sp3EphemerisSource,
109
111
  WGS84_ECCENTRICITY_SQUARED: () => WGS84_ECCENTRICITY_SQUARED,
110
112
  WGS84_FLATTENING: () => WGS84_FLATTENING,
111
113
  WGS84_SEMI_MAJOR_AXIS: () => WGS84_SEMI_MAJOR_AXIS,
@@ -116,6 +118,7 @@ __export(src_exports, {
116
118
  analyzeQuality: () => analyzeQuality,
117
119
  applyHelmert: () => applyHelmert,
118
120
  applyIonoDcb: () => applyIonoDcb,
121
+ applyOrbitClock: () => applyOrbitClock,
119
122
  biasMetres: () => biasMetres,
120
123
  binexCrc16: () => binexCrc16,
121
124
  binexCrc32: () => binexCrc32,
@@ -149,6 +152,7 @@ __export(src_exports, {
149
152
  decodeIgsSsr: () => decodeIgsSsr,
150
153
  decodeLegacyObs: () => decodeLegacyObs,
151
154
  decodeMsmFull: () => decodeMsmFull,
155
+ decodeObs: () => decodeObs,
152
156
  decodeSbfNavigation: () => decodeSbfNavigation,
153
157
  decodeSsr: () => decodeSsr,
154
158
  decodeSystemParams: () => decodeSystemParams,
@@ -239,6 +243,7 @@ __export(src_exports, {
239
243
  glonassPosition: () => glonassPosition,
240
244
  gmst: () => gmst,
241
245
  greatCircleMidpoint: () => greatCircleMidpoint,
246
+ hasToOrbitClock: () => hasToOrbitClock,
242
247
  hdrLine: () => hdrLine,
243
248
  horizonDistance: () => horizonDistance,
244
249
  ionoFree: () => ionoFree,
@@ -252,11 +257,11 @@ __export(src_exports, {
252
257
  looksLikeRtcm2: () => looksLikeRtcm2,
253
258
  maskRadForAzimuth: () => maskRadForAzimuth,
254
259
  moonEcef: () => moonEcef,
255
- msmEpochToDate: () => msmEpochToDate,
256
260
  navTimesFromEph: () => navTimesFromEph,
257
261
  niellMapping: () => niellMapping,
258
262
  nlWavelength: () => nlWavelength,
259
263
  nmeaCoordToDecimal: () => nmeaCoordToDecimal,
264
+ obsEpochToDate: () => obsEpochToDate,
260
265
  oem4Frames: () => oem4Frames,
261
266
  padL: () => padL,
262
267
  padR: () => padR,
@@ -4068,7 +4073,7 @@ function parseBiasSinex(text) {
4068
4073
  const endMs = parseEpoch(line.slice(50, 64), Infinity);
4069
4074
  const tail = line.slice(65).trim().split(/\s+/);
4070
4075
  if (tail.length < 2) continue;
4071
- const unit = tail[0];
4076
+ const unit2 = tail[0];
4072
4077
  const value = Number(tail[1]);
4073
4078
  if (!Number.isFinite(value)) continue;
4074
4079
  records.push({
@@ -4080,7 +4085,7 @@ function parseBiasSinex(text) {
4080
4085
  startMs,
4081
4086
  endMs,
4082
4087
  value,
4083
- unit
4088
+ unit: unit2
4084
4089
  });
4085
4090
  }
4086
4091
  const bySat = /* @__PURE__ */ new Map();
@@ -4787,9 +4792,6 @@ var BitReader = class {
4787
4792
  skip(n) {
4788
4793
  this.bitPos += n;
4789
4794
  }
4790
- get bitsLeft() {
4791
- return this.data.length * 8 - this.bitPos;
4792
- }
4793
4795
  };
4794
4796
  function crc24q2(data, length) {
4795
4797
  let crc = 0;
@@ -5291,7 +5293,7 @@ function decodeEphemeris(frame) {
5291
5293
  }
5292
5294
  }
5293
5295
 
5294
- // src/rtcm3/igs-ssr.ts
5296
+ // src/rtcm3/ssr-common.ts
5295
5297
  var UPDATE_INTERVAL_S = [
5296
5298
  1,
5297
5299
  2,
@@ -5310,6 +5312,28 @@ var UPDATE_INTERVAL_S = [
5310
5312
  7200,
5311
5313
  10800
5312
5314
  ];
5315
+ function ssrUraMm(v) {
5316
+ if (v === 0) return null;
5317
+ const cls = v >> 3 & 7;
5318
+ const val = v & 7;
5319
+ return 3 ** cls * (1 + val / 4) - 1;
5320
+ }
5321
+ function readSsrOrbit(r, sat) {
5322
+ sat.iode = r.readU(8);
5323
+ sat.deltaRadial = r.readS(22) * 1e-4;
5324
+ sat.deltaAlongTrack = r.readS(20) * 4e-4;
5325
+ sat.deltaCrossTrack = r.readS(20) * 4e-4;
5326
+ sat.dotRadial = r.readS(21) * 1e-6;
5327
+ sat.dotAlongTrack = r.readS(19) * 4e-6;
5328
+ sat.dotCrossTrack = r.readS(19) * 4e-6;
5329
+ }
5330
+ function readSsrClock(r, sat) {
5331
+ sat.c0 = r.readS(22) * 1e-4;
5332
+ sat.c1 = r.readS(21) * 1e-6;
5333
+ sat.c2 = r.readS(27) * 2e-8;
5334
+ }
5335
+
5336
+ // src/rtcm3/igs-ssr.ts
5313
5337
  var SYSTEM_BY_BASE = {
5314
5338
  20: "G",
5315
5339
  40: "R",
@@ -5333,12 +5357,6 @@ function prnFor(system, id) {
5333
5357
  if (system === "S") return `S${two(19 + id)}`;
5334
5358
  return `${system}${two(id)}`;
5335
5359
  }
5336
- function ssrUraMm(v) {
5337
- if (v === 0) return null;
5338
- const cls = v >> 3 & 7;
5339
- const val = v & 7;
5340
- return 3 ** cls * (1 + val / 4) - 1;
5341
- }
5342
5360
  function decodeIgsSsr(frame) {
5343
5361
  if (frame.messageType !== 4076) return null;
5344
5362
  const r = new BitReader(frame.payload);
@@ -5365,26 +5383,12 @@ function decodeIgsSsr(frame) {
5365
5383
  mwConsistency = r.readU(1) === 1;
5366
5384
  }
5367
5385
  const nsat = r.readU(6);
5368
- const readOrbit = (s) => {
5369
- s.iode = r.readU(8);
5370
- s.deltaRadial = r.readS(22) * 1e-4;
5371
- s.deltaAlongTrack = r.readS(20) * 4e-4;
5372
- s.deltaCrossTrack = r.readS(20) * 4e-4;
5373
- s.dotRadial = r.readS(21) * 1e-6;
5374
- s.dotAlongTrack = r.readS(19) * 4e-6;
5375
- s.dotCrossTrack = r.readS(19) * 4e-6;
5376
- };
5377
- const readClock2 = (s) => {
5378
- s.c0 = r.readS(22) * 1e-4;
5379
- s.c1 = r.readS(21) * 1e-6;
5380
- s.c2 = r.readS(27) * 2e-8;
5381
- };
5382
5386
  const satellites = [];
5383
5387
  for (let i = 0; i < nsat; i++) {
5384
5388
  const id = r.readU(6);
5385
5389
  const sat = { prn: prnFor(system, id) };
5386
- if (kind === "orbit" || kind === "combined") readOrbit(sat);
5387
- if (kind === "clock" || kind === "combined") readClock2(sat);
5390
+ if (kind === "orbit" || kind === "combined") readSsrOrbit(r, sat);
5391
+ if (kind === "clock" || kind === "combined") readSsrClock(r, sat);
5388
5392
  else if (kind === "ura")
5389
5393
  sat.uraMm = ssrUraMm(r.readU(6));
5390
5394
  else if (kind === "highRateClock")
@@ -5477,116 +5481,6 @@ function decodeIono(r, version, im) {
5477
5481
  };
5478
5482
  }
5479
5483
 
5480
- // src/rtcm3/legacy-obs.ts
5481
- var PRUNIT_GPS = 299792.458;
5482
- var PRUNIT_GLO = 599584.916;
5483
- var LAM_GPS_L1 = C_LIGHT / 157542e4;
5484
- var LAM_GPS_L2 = C_LIGHT / 12276e5;
5485
- var PPR_INVALID = -(2 ** 19);
5486
- var PR21_INVALID = -(2 ** 13);
5487
- function legacyLockSec(i) {
5488
- if (i < 24) return i;
5489
- if (i < 48) return 2 * i - 24;
5490
- if (i < 72) return 4 * i - 120;
5491
- if (i < 96) return 8 * i - 408;
5492
- if (i < 120) return 16 * i - 1176;
5493
- if (i < 127) return 32 * i - 3096;
5494
- return 937;
5495
- }
5496
- var two2 = (n) => n.toString().padStart(2, "0");
5497
- function decodeLegacyObs(frame) {
5498
- const type = frame.messageType;
5499
- const gps = type >= 1001 && type <= 1004;
5500
- const glo = type >= 1009 && type <= 1012;
5501
- if (!gps && !glo) return null;
5502
- const ext = type === 1002 || type === 1004 || type === 1010 || type === 1012;
5503
- const dual = type === 1003 || type === 1004 || type === 1011 || type === 1012;
5504
- const system = gps ? "G" : "R";
5505
- const r = new BitReader(frame.payload);
5506
- r.readU(12);
5507
- r.readU(12);
5508
- let epochMs;
5509
- let nsat;
5510
- if (gps) {
5511
- epochMs = r.readU(30);
5512
- r.readU(1);
5513
- nsat = r.readU(5);
5514
- r.readU(1);
5515
- r.readU(3);
5516
- } else {
5517
- const tk = r.readU(27);
5518
- r.readU(1);
5519
- nsat = r.readU(5);
5520
- r.readU(1);
5521
- r.readU(3);
5522
- const gloDow = new Date(Date.now() + 3 * 36e5).getUTCDay();
5523
- epochMs = (gloDow << 27 | tk) >>> 0;
5524
- }
5525
- const observations = [];
5526
- for (let s = 0; s < nsat; s++) {
5527
- const satId = r.readU(6);
5528
- const code1 = r.readU(1);
5529
- const freqCh = glo ? r.readU(5) : 0;
5530
- const pr1raw = r.readU(gps ? 24 : 25);
5531
- const ppr1 = r.readS(20);
5532
- const lock1 = r.readU(7);
5533
- let amb = 0;
5534
- let cnr1 = 0;
5535
- if (ext) {
5536
- amb = r.readU(gps ? 8 : 7);
5537
- cnr1 = r.readU(8);
5538
- }
5539
- let code2 = 0;
5540
- let pr21 = 0;
5541
- let ppr2 = 0;
5542
- let lock2 = 0;
5543
- let cnr2 = 0;
5544
- if (dual) {
5545
- code2 = r.readU(2);
5546
- pr21 = r.readS(14);
5547
- ppr2 = r.readS(20);
5548
- lock2 = r.readU(7);
5549
- if (ext) cnr2 = r.readU(8);
5550
- }
5551
- if (gps && (satId < 1 || satId > 32)) continue;
5552
- if (glo && (satId < 1 || satId > 24)) continue;
5553
- const prunit = gps ? PRUNIT_GPS : PRUNIT_GLO;
5554
- const pr1 = pr1raw * 0.02 + amb * prunit;
5555
- const k = freqCh - 7;
5556
- const lamL1 = gps ? LAM_GPS_L1 : C_LIGHT / (GLO_F1_BASE + k * GLO_F1_STEP);
5557
- const lamL2 = gps ? LAM_GPS_L2 : C_LIGHT / (GLO_F2_BASE + k * GLO_F2_STEP);
5558
- const signals = [];
5559
- {
5560
- const sig = {
5561
- rinexCode: gps ? code1 ? "1W" : "1C" : code1 ? "1P" : "1C",
5562
- pseudorange: pr1,
5563
- wavelength: lamL1,
5564
- lockTime: legacyLockSec(lock1)
5565
- };
5566
- if (ppr1 !== PPR_INVALID) sig.phase = (pr1 + ppr1 * 5e-4) / lamL1;
5567
- if (ext && cnr1 > 0) sig.cn0 = cnr1 * 0.25;
5568
- signals.push(sig);
5569
- }
5570
- if (dual) {
5571
- const sig = {
5572
- rinexCode: gps ? code2 === 0 ? "2X" : "2W" : code2 === 0 ? "2C" : "2P",
5573
- wavelength: lamL2,
5574
- lockTime: legacyLockSec(lock2)
5575
- };
5576
- if (pr21 !== PR21_INVALID) sig.pseudorange = pr1 + pr21 * 0.02;
5577
- if (ppr2 !== PPR_INVALID) sig.phase = (pr1 + ppr2 * 5e-4) / lamL2;
5578
- if (ext && cnr2 > 0) sig.cn0 = cnr2 * 0.25;
5579
- signals.push(sig);
5580
- }
5581
- observations.push({
5582
- prn: `${system}${two2(satId)}`,
5583
- system,
5584
- signals
5585
- });
5586
- }
5587
- return { messageType: type, epochMs, system, observations };
5588
- }
5589
-
5590
5484
  // src/rtcm3/msm.ts
5591
5485
  var GPS_L1 = FREQ.G["1"];
5592
5486
  var GPS_L2 = FREQ.G["2"];
@@ -6085,7 +5979,7 @@ function decodeMsmFull(frame) {
6085
5979
  }
6086
5980
  var GPS_EPOCH = START_GPS_TIME.getTime();
6087
5981
  var MS_PER_WEEK = MILLISECONDS_IN_WEEK;
6088
- function msmEpochToDate(sys, epochMs, refTime = /* @__PURE__ */ new Date()) {
5982
+ function obsEpochToDate(sys, epochMs, refTime = /* @__PURE__ */ new Date()) {
6089
5983
  const refMs = refTime.getTime();
6090
5984
  if (sys === "R") {
6091
5985
  const dayOfWeek = epochMs >>> 27 & 7;
@@ -6121,25 +6015,120 @@ function resetGloFreqCache() {
6121
6015
  gloFreqNum.fill(-128);
6122
6016
  }
6123
6017
 
6018
+ // src/rtcm3/legacy-obs.ts
6019
+ var PRUNIT_GPS = 299792.458;
6020
+ var PRUNIT_GLO = 599584.916;
6021
+ var LAM_GPS_L1 = C_LIGHT / 157542e4;
6022
+ var LAM_GPS_L2 = C_LIGHT / 12276e5;
6023
+ var PPR_INVALID = -(2 ** 19);
6024
+ var PR21_INVALID = -(2 ** 13);
6025
+ function legacyLockSec(i) {
6026
+ if (i < 24) return i;
6027
+ if (i < 48) return 2 * i - 24;
6028
+ if (i < 72) return 4 * i - 120;
6029
+ if (i < 96) return 8 * i - 408;
6030
+ if (i < 120) return 16 * i - 1176;
6031
+ if (i < 127) return 32 * i - 3096;
6032
+ return 937;
6033
+ }
6034
+ var two2 = (n) => n.toString().padStart(2, "0");
6035
+ function decodeLegacyObs(frame) {
6036
+ const type = frame.messageType;
6037
+ const gps = type >= 1001 && type <= 1004;
6038
+ const glo = type >= 1009 && type <= 1012;
6039
+ if (!gps && !glo) return null;
6040
+ const ext = type === 1002 || type === 1004 || type === 1010 || type === 1012;
6041
+ const dual = type === 1003 || type === 1004 || type === 1011 || type === 1012;
6042
+ const system = gps ? "G" : "R";
6043
+ const r = new BitReader(frame.payload);
6044
+ r.readU(12);
6045
+ r.readU(12);
6046
+ let epochMs;
6047
+ let nsat;
6048
+ if (gps) {
6049
+ epochMs = r.readU(30);
6050
+ r.readU(1);
6051
+ nsat = r.readU(5);
6052
+ r.readU(1);
6053
+ r.readU(3);
6054
+ } else {
6055
+ const tk = r.readU(27);
6056
+ r.readU(1);
6057
+ nsat = r.readU(5);
6058
+ r.readU(1);
6059
+ r.readU(3);
6060
+ const gloDow = new Date(Date.now() + 3 * 36e5).getUTCDay();
6061
+ epochMs = (gloDow << 27 | tk) >>> 0;
6062
+ }
6063
+ const observations = [];
6064
+ for (let s = 0; s < nsat; s++) {
6065
+ const satId = r.readU(6);
6066
+ const code1 = r.readU(1);
6067
+ const freqCh = glo ? r.readU(5) : 0;
6068
+ const pr1raw = r.readU(gps ? 24 : 25);
6069
+ const ppr1 = r.readS(20);
6070
+ const lock1 = r.readU(7);
6071
+ let amb = 0;
6072
+ let cnr1 = 0;
6073
+ if (ext) {
6074
+ amb = r.readU(gps ? 8 : 7);
6075
+ cnr1 = r.readU(8);
6076
+ }
6077
+ let code2 = 0;
6078
+ let pr21 = 0;
6079
+ let ppr2 = 0;
6080
+ let lock2 = 0;
6081
+ let cnr2 = 0;
6082
+ if (dual) {
6083
+ code2 = r.readU(2);
6084
+ pr21 = r.readS(14);
6085
+ ppr2 = r.readS(20);
6086
+ lock2 = r.readU(7);
6087
+ if (ext) cnr2 = r.readU(8);
6088
+ }
6089
+ if (gps && (satId < 1 || satId > 32)) continue;
6090
+ if (glo && (satId < 1 || satId > 24)) continue;
6091
+ const prunit = gps ? PRUNIT_GPS : PRUNIT_GLO;
6092
+ const pr1 = pr1raw * 0.02 + amb * prunit;
6093
+ const k = freqCh - 7;
6094
+ const lamL1 = gps ? LAM_GPS_L1 : C_LIGHT / (GLO_F1_BASE + k * GLO_F1_STEP);
6095
+ const lamL2 = gps ? LAM_GPS_L2 : C_LIGHT / (GLO_F2_BASE + k * GLO_F2_STEP);
6096
+ const signals = [];
6097
+ {
6098
+ const sig = {
6099
+ rinexCode: gps ? code1 ? "1W" : "1C" : code1 ? "1P" : "1C",
6100
+ pseudorange: pr1,
6101
+ wavelength: lamL1,
6102
+ lockTime: legacyLockSec(lock1)
6103
+ };
6104
+ if (ppr1 !== PPR_INVALID) sig.phase = (pr1 + ppr1 * 5e-4) / lamL1;
6105
+ if (ext && cnr1 > 0) sig.cn0 = cnr1 * 0.25;
6106
+ signals.push(sig);
6107
+ }
6108
+ if (dual) {
6109
+ const sig = {
6110
+ rinexCode: gps ? code2 === 0 ? "2X" : "2W" : code2 === 0 ? "2C" : "2P",
6111
+ wavelength: lamL2,
6112
+ lockTime: legacyLockSec(lock2)
6113
+ };
6114
+ if (pr21 !== PR21_INVALID) sig.pseudorange = pr1 + pr21 * 0.02;
6115
+ if (ppr2 !== PPR_INVALID) sig.phase = (pr1 + ppr2 * 5e-4) / lamL2;
6116
+ if (ext && cnr2 > 0) sig.cn0 = cnr2 * 0.25;
6117
+ signals.push(sig);
6118
+ }
6119
+ observations.push({
6120
+ prn: `${system}${two2(satId)}`,
6121
+ system,
6122
+ signals
6123
+ });
6124
+ }
6125
+ return { messageType: type, epochMs, system, observations };
6126
+ }
6127
+ function decodeObs(frame) {
6128
+ return decodeMsmFull(frame) ?? decodeLegacyObs(frame);
6129
+ }
6130
+
6124
6131
  // src/rtcm3/ssr.ts
6125
- var UPDATE_INTERVAL_S2 = [
6126
- 1,
6127
- 2,
6128
- 5,
6129
- 10,
6130
- 15,
6131
- 30,
6132
- 60,
6133
- 120,
6134
- 240,
6135
- 300,
6136
- 600,
6137
- 900,
6138
- 1800,
6139
- 3600,
6140
- 7200,
6141
- 10800
6142
- ];
6143
6132
  var GPS_SIGNAL = {
6144
6133
  0: "L1 C/A",
6145
6134
  1: "L1 P",
@@ -6174,12 +6163,6 @@ var SSR_KIND = {
6174
6163
  1067: { system: "R", kind: "ura" },
6175
6164
  1068: { system: "R", kind: "highRateClock" }
6176
6165
  };
6177
- function ssrUraMm2(v) {
6178
- if (v === 0) return null;
6179
- const cls = v >> 3 & 7;
6180
- const val = v & 7;
6181
- return 3 ** cls * (1 + val / 4) - 1;
6182
- }
6183
6166
  var two3 = (n) => n.toString().padStart(2, "0");
6184
6167
  function decodeSsr(frame) {
6185
6168
  const spec = SSR_KIND[frame.messageType];
@@ -6189,7 +6172,7 @@ function decodeSsr(frame) {
6189
6172
  const r = new BitReader(frame.payload);
6190
6173
  r.readU(12);
6191
6174
  const epochS = r.readU(gps ? 20 : 17);
6192
- const updateIntervalS = UPDATE_INTERVAL_S2[r.readU(4)];
6175
+ const updateIntervalS = UPDATE_INTERVAL_S[r.readU(4)];
6193
6176
  const multipleMessage = r.readU(1) === 1;
6194
6177
  const hasDatum = kind === "orbit" || kind === "combined";
6195
6178
  const referenceDatum = hasDatum ? r.readU(1) : void 0;
@@ -6199,30 +6182,14 @@ function decodeSsr(frame) {
6199
6182
  const nsat = r.readU(6);
6200
6183
  const sigName = gps ? GPS_SIGNAL : GLO_SIGNAL;
6201
6184
  const satellites = [];
6202
- const readOrbit = (sat) => {
6203
- sat.deltaRadial = r.readS(22) * 1e-4;
6204
- sat.deltaAlongTrack = r.readS(20) * 4e-4;
6205
- sat.deltaCrossTrack = r.readS(20) * 4e-4;
6206
- sat.dotRadial = r.readS(21) * 1e-6;
6207
- sat.dotAlongTrack = r.readS(19) * 4e-6;
6208
- sat.dotCrossTrack = r.readS(19) * 4e-6;
6209
- };
6210
- const readClock2 = (sat) => {
6211
- sat.c0 = r.readS(22) * 1e-4;
6212
- sat.c1 = r.readS(21) * 1e-6;
6213
- sat.c2 = r.readS(27) * 2e-8;
6214
- };
6215
6185
  for (let i = 0; i < nsat; i++) {
6216
6186
  const satId = gps ? r.readU(6) : r.readU(5);
6217
6187
  const sat = { prn: `${system}${two3(satId)}` };
6218
- if (kind === "orbit" || kind === "combined") {
6219
- sat.iode = r.readU(8);
6220
- readOrbit(sat);
6221
- }
6222
- if (kind === "combined") readClock2(sat);
6223
- else if (kind === "clock") readClock2(sat);
6188
+ if (kind === "orbit" || kind === "combined") readSsrOrbit(r, sat);
6189
+ if (kind === "combined") readSsrClock(r, sat);
6190
+ else if (kind === "clock") readSsrClock(r, sat);
6224
6191
  else if (kind === "ura")
6225
- sat.uraMm = ssrUraMm2(r.readU(6));
6192
+ sat.uraMm = ssrUraMm(r.readU(6));
6226
6193
  else if (kind === "highRateClock")
6227
6194
  sat.highRateClock = r.readS(22) * 1e-4;
6228
6195
  else if (kind === "codeBias") {
@@ -6590,9 +6557,9 @@ function updateStreamStats(stats, frames, rawBytes) {
6590
6557
  entry.count++;
6591
6558
  entry.lastSeen = now;
6592
6559
  entry.totalBytes += frame.length + 6;
6593
- const msmEpoch = decodeMsmFull(frame);
6594
- if (msmEpoch) {
6595
- for (const obs of msmEpoch.observations) {
6560
+ const obsEpoch = decodeObs(frame);
6561
+ if (obsEpoch) {
6562
+ for (const obs of obsEpoch.observations) {
6596
6563
  const signals = [];
6597
6564
  let bestCn0 = 0;
6598
6565
  for (const sig of obs.signals) {
@@ -6601,7 +6568,7 @@ function updateStreamStats(stats, frames, rawBytes) {
6601
6568
  if (sig.cn0 > bestCn0) bestCn0 = sig.cn0;
6602
6569
  }
6603
6570
  }
6604
- if (signals.length > 0) {
6571
+ if (obs.signals.length > 0) {
6605
6572
  stats.satellites.set(obs.prn, {
6606
6573
  prn: obs.prn,
6607
6574
  system: obs.system,
@@ -9152,14 +9119,14 @@ function parseOrbitBlock(c, masks) {
9152
9119
  const gnssIod = c.u(IOD_BITS[sys.system]);
9153
9120
  const rad = c.s(13);
9154
9121
  const inT = c.s(12);
9155
- const cross2 = c.s(12);
9122
+ const cross3 = c.s(12);
9156
9123
  corrections.push({
9157
9124
  system: sys.system,
9158
9125
  prn,
9159
9126
  gnssIod,
9160
9127
  deltaRadial: rad === -4096 ? null : rad * 25e-4,
9161
9128
  deltaInTrack: inT === -2048 ? null : inT * 8e-3,
9162
- deltaCrossTrack: cross2 === -2048 ? null : cross2 * 8e-3
9129
+ deltaCrossTrack: cross3 === -2048 ? null : cross3 * 8e-3
9163
9130
  });
9164
9131
  }
9165
9132
  }
@@ -14874,6 +14841,55 @@ var SbasProcessor = class {
14874
14841
  }
14875
14842
  };
14876
14843
 
14844
+ // src/positioning/ssr-apply.ts
14845
+ var cross = (a, b) => [
14846
+ a[1] * b[2] - a[2] * b[1],
14847
+ a[2] * b[0] - a[0] * b[2],
14848
+ a[0] * b[1] - a[1] * b[0]
14849
+ ];
14850
+ var norm = (a) => Math.hypot(a[0], a[1], a[2]);
14851
+ var unit = (a) => {
14852
+ const n = norm(a);
14853
+ return n > 0 ? [a[0] / n, a[1] / n, a[2] / n] : [0, 0, 0];
14854
+ };
14855
+ function applyOrbitClock(eph, corr, timeMs) {
14856
+ if (eph.system === "R" || eph.system === "S") return null;
14857
+ if (eph.iode !== corr.iod) return null;
14858
+ const age = (timeMs - corr.refTimeMs) / 1e3;
14859
+ if (corr.validitySeconds != null && (age < -1 || age > corr.validitySeconds))
14860
+ return null;
14861
+ const s = computeSatPosition(eph, timeMs);
14862
+ if (!Number.isFinite(s.x)) return null;
14863
+ const p = [s.x, s.y, s.z];
14864
+ const v = [s.vx, s.vy, s.vz];
14865
+ const er = unit(p);
14866
+ const en = unit(cross(p, v));
14867
+ const ea = cross(en, er);
14868
+ const dr = corr.radial + (corr.dotRadial ?? 0) * age;
14869
+ const da = corr.along + (corr.dotAlong ?? 0) * age;
14870
+ const dc = corr.cross + (corr.dotCross ?? 0) * age;
14871
+ const x = s.x + dr * er[0] + da * ea[0] + dc * en[0];
14872
+ const y = s.y + dr * er[1] + da * ea[1] + dc * en[1];
14873
+ const z = s.z + dr * er[2] + da * ea[2] + dc * en[2];
14874
+ const clockM = corr.clockC0 + (corr.clockC1 ?? 0) * age + (corr.clockC2 ?? 0) * age * age + (corr.highRateClock ?? 0);
14875
+ return { x, y, z, clockOffsetS: clockM / C_LIGHT };
14876
+ }
14877
+ function hasToOrbitClock(orbit, clock, refTimeMs, validitySeconds) {
14878
+ if (orbit.deltaRadial == null || orbit.deltaInTrack == null || orbit.deltaCrossTrack == null)
14879
+ return null;
14880
+ const clockC0 = clock && clock.deltaClock != null && !clock.notUsable ? clock.deltaClock : 0;
14881
+ return {
14882
+ prn: orbit.prn,
14883
+ iod: orbit.gnssIod,
14884
+ refTimeMs,
14885
+ radial: orbit.deltaRadial,
14886
+ along: orbit.deltaInTrack,
14887
+ cross: orbit.deltaCrossTrack,
14888
+ clockC0,
14889
+ validitySeconds
14890
+ };
14891
+ }
14892
+
14877
14893
  // src/positioning/ppp-tropo.ts
14878
14894
  var HYD_AVG_A = [
14879
14895
  0.0012769934,
@@ -15131,14 +15147,14 @@ function buildPppAntenna(antex) {
15131
15147
  }
15132
15148
  };
15133
15149
  }
15134
- function cross(a, b) {
15150
+ function cross2(a, b) {
15135
15151
  return [
15136
15152
  a[1] * b[2] - a[2] * b[1],
15137
15153
  a[2] * b[0] - a[0] * b[2],
15138
15154
  a[0] * b[1] - a[1] * b[0]
15139
15155
  ];
15140
15156
  }
15141
- function norm(a) {
15157
+ function norm2(a) {
15142
15158
  const n = Math.hypot(a[0], a[1], a[2]) || 1;
15143
15159
  return [a[0] / n, a[1] / n, a[2] / n];
15144
15160
  }
@@ -15146,14 +15162,14 @@ function dot(a, b) {
15146
15162
  return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
15147
15163
  }
15148
15164
  function satBodyFrame(satEcef, sunEcef2) {
15149
- const z = norm([-satEcef[0], -satEcef[1], -satEcef[2]]);
15150
- const eSun = norm([
15165
+ const z = norm2([-satEcef[0], -satEcef[1], -satEcef[2]]);
15166
+ const eSun = norm2([
15151
15167
  sunEcef2[0] - satEcef[0],
15152
15168
  sunEcef2[1] - satEcef[1],
15153
15169
  sunEcef2[2] - satEcef[2]
15154
15170
  ]);
15155
- const y = norm(cross(z, eSun));
15156
- const x = norm(cross(y, z));
15171
+ const y = norm2(cross2(z, eSun));
15172
+ const x = norm2(cross2(y, z));
15157
15173
  return { x, y, z };
15158
15174
  }
15159
15175
  function satPcoToEcef(pcoBody, frame) {
@@ -15194,7 +15210,7 @@ function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
15194
15210
  const kx = satFrame.x;
15195
15211
  const ky = satFrame.y;
15196
15212
  const kdotx = dot(k, kx);
15197
- const kcrossY = cross(k, ky);
15213
+ const kcrossY = cross2(k, ky);
15198
15214
  const dS = [
15199
15215
  kx[0] - k[0] * kdotx - kcrossY[0],
15200
15216
  kx[1] - k[1] * kdotx - kcrossY[1],
@@ -15203,7 +15219,7 @@ function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
15203
15219
  const north = enuToEcef([0, 1, 0], latRad, lonRad);
15204
15220
  const east = enuToEcef([1, 0, 0], latRad, lonRad);
15205
15221
  const kdotn = dot(k, north);
15206
- const kcrossE = cross(k, east);
15222
+ const kcrossE = cross2(k, east);
15207
15223
  const dR = [
15208
15224
  north[0] - k[0] * kdotn + kcrossE[0],
15209
15225
  north[1] - k[1] * kdotn + kcrossE[1],
@@ -15213,7 +15229,7 @@ function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
15213
15229
  const nR = Math.hypot(dR[0], dR[1], dR[2]) || 1;
15214
15230
  let cosPhi = dot(dS, dR) / (nS * nR);
15215
15231
  cosPhi = Math.max(-1, Math.min(1, cosPhi));
15216
- const zeta = cross(dS, dR);
15232
+ const zeta = cross2(dS, dR);
15217
15233
  const sign = dot(k, zeta) >= 0 ? 1 : -1;
15218
15234
  const dphi = sign * Math.acos(cosPhi) / (2 * Math.PI);
15219
15235
  const prev = state.get(prn);
@@ -15351,13 +15367,35 @@ function ifCoeffs(f1, f2) {
15351
15367
  const lambdaIf = C_LIGHT / (f1 + f2);
15352
15368
  return { g, lambdaIf };
15353
15369
  }
15370
+ var Sp3EphemerisSource = class {
15371
+ constructor(sp3, clk) {
15372
+ this.sp3 = sp3;
15373
+ this.clk = clk;
15374
+ }
15375
+ satState(prn, tEmitMs) {
15376
+ const p = sp3Position(this.sp3, prn, tEmitMs);
15377
+ if (!p || p.clk == null) return null;
15378
+ const pPlus = sp3Position(this.sp3, prn, tEmitMs + 500);
15379
+ const pMinus = sp3Position(this.sp3, prn, tEmitMs - 500);
15380
+ let vx = 0;
15381
+ let vy = 0;
15382
+ let vz = 0;
15383
+ if (pPlus && pMinus) {
15384
+ vx = pPlus.x - pMinus.x;
15385
+ vy = pPlus.y - pMinus.y;
15386
+ vz = pPlus.z - pMinus.z;
15387
+ }
15388
+ const clkS = (this.clk ? clkBias(this.clk, prn, tEmitMs) : null) ?? p.clk;
15389
+ return { x: p.x, y: p.y, z: p.z, vx, vy, vz, clkS };
15390
+ }
15391
+ };
15354
15392
  function sagnacRotate(x, y, z, travelS) {
15355
15393
  const theta = OMEGA_E * travelS;
15356
15394
  const c = Math.cos(theta);
15357
15395
  const s = Math.sin(theta);
15358
15396
  return [x * c + y * s, -x * s + y * c, z];
15359
15397
  }
15360
- function satStateAtEmission(sp3, prn, recvTimeMs, rcv, clk) {
15398
+ function satStateAtEmission(source, prn, recvTimeMs, rcv) {
15361
15399
  let travelS = 0.075;
15362
15400
  let sx = 0;
15363
15401
  let sy = 0;
@@ -15366,18 +15404,11 @@ function satStateAtEmission(sp3, prn, recvTimeMs, rcv, clk) {
15366
15404
  let velDotPos = 0;
15367
15405
  for (let iter = 0; iter < 3; iter++) {
15368
15406
  const tEmit = recvTimeMs - travelS * 1e3;
15369
- const p = sp3Position(sp3, prn, tEmit);
15370
- if (!p || p.clk == null) return null;
15371
- const pPlus = sp3Position(sp3, prn, tEmit + 500);
15372
- const pMinus = sp3Position(sp3, prn, tEmit - 500);
15373
- if (pPlus && pMinus) {
15374
- const vx = (pPlus.x - pMinus.x) / 1;
15375
- const vy = (pPlus.y - pMinus.y) / 1;
15376
- const vz = (pPlus.z - pMinus.z) / 1;
15377
- velDotPos = p.x * vx + p.y * vy + p.z * vz;
15378
- }
15379
- clkS = (clk && clkBias(clk, prn, tEmit)) ?? p.clk;
15380
- const [rx, ry, rz] = sagnacRotate(p.x, p.y, p.z, travelS);
15407
+ const s = source.satState(prn, tEmit);
15408
+ if (!s) return null;
15409
+ velDotPos = s.x * s.vx + s.y * s.vy + s.z * s.vz;
15410
+ clkS = s.clkS;
15411
+ const [rx, ry, rz] = sagnacRotate(s.x, s.y, s.z, travelS);
15381
15412
  sx = rx;
15382
15413
  sy = ry;
15383
15414
  sz = rz;
@@ -15399,39 +15430,72 @@ var IDX_ZWD = 3;
15399
15430
  var NBASE = 4;
15400
15431
  var CLK_VAR = 1e10;
15401
15432
  var POS_VAR = 60 * 60;
15402
- function solvePpp(epochs, sp3, opts) {
15403
- const elevMask = (opts.elevationMaskDeg ?? 10) * Math.PI / 180;
15404
- const codeSigma = opts.codeSigma ?? 3;
15405
- const phaseSigma = opts.phaseSigma ?? 0.01;
15406
- const ztdQ = opts.ztdProcessNoise ?? 1e-8;
15407
- const kinematic = opts.mode === "kinematic";
15408
- const corrections = opts.corrections;
15409
- const x = [
15410
- opts.aprioriPos[0],
15411
- opts.aprioriPos[1],
15412
- opts.aprioriPos[2],
15413
- 0.1
15414
- // zenith wet delay (m) a priori
15415
- ];
15416
- const P = [];
15417
- for (let i = 0; i < NBASE; i++) {
15418
- P.push(new Array(NBASE).fill(0));
15419
- }
15420
- P[IDX_X][IDX_X] = 100 * 100;
15421
- P[IDX_Y][IDX_Y] = 100 * 100;
15422
- P[IDX_Z][IDX_Z] = 100 * 100;
15423
- P[IDX_ZWD][IDX_ZWD] = 0.5 * 0.5;
15424
- const clkIdx = /* @__PURE__ */ new Map();
15425
- const clockSeeded = /* @__PURE__ */ new Set();
15426
- const ambIdx = /* @__PURE__ */ new Map();
15427
- const lastSeen = /* @__PURE__ */ new Map();
15428
- const arcs = [];
15429
- const arcSnap = /* @__PURE__ */ new Map();
15430
- const flushArc = (prn, minEpochs = 10) => {
15431
- const s = arcSnap.get(prn);
15432
- arcSnap.delete(prn);
15433
+ var PppEngine = class {
15434
+ source;
15435
+ opts;
15436
+ elevMask;
15437
+ codeSigma;
15438
+ phaseSigma;
15439
+ ztdQ;
15440
+ kinematic;
15441
+ corrections;
15442
+ truth;
15443
+ // Filter state (reset() initialises; mutated in place across epochs).
15444
+ x;
15445
+ P;
15446
+ clkIdx;
15447
+ clockSeeded;
15448
+ ambIdx;
15449
+ lastSeen;
15450
+ arcs;
15451
+ arcSnap;
15452
+ mwState;
15453
+ series;
15454
+ ei = 0;
15455
+ t0 = 0;
15456
+ convergenceSec = null;
15457
+ convergedStreak = 0;
15458
+ constructor(opts, source) {
15459
+ this.opts = opts;
15460
+ this.source = source;
15461
+ this.elevMask = (opts.elevationMaskDeg ?? 10) * Math.PI / 180;
15462
+ this.codeSigma = opts.codeSigma ?? 3;
15463
+ this.phaseSigma = opts.phaseSigma ?? 0.01;
15464
+ this.ztdQ = opts.ztdProcessNoise ?? 1e-8;
15465
+ this.kinematic = opts.mode === "kinematic";
15466
+ this.corrections = opts.corrections;
15467
+ this.truth = opts.groundTruth;
15468
+ this.reset();
15469
+ }
15470
+ /** Reinitialise the filter (fresh session). */
15471
+ reset() {
15472
+ const { opts } = this;
15473
+ this.x = [opts.aprioriPos[0], opts.aprioriPos[1], opts.aprioriPos[2], 0.1];
15474
+ const P = [];
15475
+ for (let i = 0; i < NBASE; i++) P.push(new Array(NBASE).fill(0));
15476
+ P[IDX_X][IDX_X] = 100 * 100;
15477
+ P[IDX_Y][IDX_Y] = 100 * 100;
15478
+ P[IDX_Z][IDX_Z] = 100 * 100;
15479
+ P[IDX_ZWD][IDX_ZWD] = 0.5 * 0.5;
15480
+ this.P = P;
15481
+ this.clkIdx = /* @__PURE__ */ new Map();
15482
+ this.clockSeeded = /* @__PURE__ */ new Set();
15483
+ this.ambIdx = /* @__PURE__ */ new Map();
15484
+ this.lastSeen = /* @__PURE__ */ new Map();
15485
+ this.arcs = [];
15486
+ this.arcSnap = /* @__PURE__ */ new Map();
15487
+ this.mwState = /* @__PURE__ */ new Map();
15488
+ this.series = [];
15489
+ this.ei = 0;
15490
+ this.t0 = 0;
15491
+ this.convergenceSec = null;
15492
+ this.convergedStreak = 0;
15493
+ }
15494
+ flushArc(prn, minEpochs = 10) {
15495
+ const s = this.arcSnap.get(prn);
15496
+ this.arcSnap.delete(prn);
15433
15497
  if (!s || s.nEpochs < minEpochs) return;
15434
- arcs.push({
15498
+ this.arcs.push({
15435
15499
  prn,
15436
15500
  aIF: s.aIF,
15437
15501
  mwCyc: s.mwCyc,
@@ -15442,64 +15506,88 @@ function solvePpp(epochs, sp3, opts) {
15442
15506
  startMs: s.startMs,
15443
15507
  endMs: s.endMs
15444
15508
  });
15445
- };
15446
- const mwState = /* @__PURE__ */ new Map();
15447
- const detectSlip = (o, ei) => {
15509
+ }
15510
+ /** Detect a cycle slip via the Melbourne–Wübbena wide-lane ambiguity. */
15511
+ detectSlip(o, ei) {
15448
15512
  const lamW = C_LIGHT / (o.f1 - o.f2);
15449
15513
  const lw = o.l1 - o.l2;
15450
15514
  const pn = (o.f1 * o.c1 + o.f2 * o.c2) / (o.f1 + o.f2);
15451
15515
  const mw = lw - pn / lamW;
15452
- const st = mwState.get(o.prn);
15516
+ const st = this.mwState.get(o.prn);
15453
15517
  let slip = o.slip;
15454
15518
  if (!st || ei - st.lastEi > 2)
15455
15519
  slip = true;
15456
15520
  else if (Math.abs(mw - st.mean) > 4) slip = true;
15457
- if (slip) mwState.set(o.prn, { mean: mw, n: 1, lastEi: ei });
15521
+ if (slip) this.mwState.set(o.prn, { mean: mw, n: 1, lastEi: ei });
15458
15522
  else {
15459
15523
  const n = st.n + 1;
15460
- mwState.set(o.prn, {
15524
+ this.mwState.set(o.prn, {
15461
15525
  mean: st.mean + (mw - st.mean) / Math.min(n, 100),
15462
15526
  n,
15463
15527
  lastEi: ei
15464
15528
  });
15465
15529
  }
15466
15530
  return slip;
15467
- };
15468
- const growState = (initVal, initVar) => {
15469
- const idx = x.length;
15470
- x.push(initVal);
15471
- for (const row of P) row.push(0);
15472
- P.push(new Array(x.length).fill(0));
15473
- P[idx][idx] = initVar;
15531
+ }
15532
+ growState(initVal, initVar) {
15533
+ const idx = this.x.length;
15534
+ this.x.push(initVal);
15535
+ for (const row of this.P) row.push(0);
15536
+ this.P.push(new Array(this.x.length).fill(0));
15537
+ this.P[idx][idx] = initVar;
15474
15538
  return idx;
15475
- };
15476
- const dropState = (idx) => {
15477
- x.splice(idx, 1);
15478
- P.splice(idx, 1);
15479
- for (const row of P) row.splice(idx, 1);
15480
- for (const [prn, i] of ambIdx) {
15481
- if (i === idx) ambIdx.delete(prn);
15482
- else if (i > idx) ambIdx.set(prn, i - 1);
15539
+ }
15540
+ dropState(idx) {
15541
+ this.x.splice(idx, 1);
15542
+ this.P.splice(idx, 1);
15543
+ for (const row of this.P) row.splice(idx, 1);
15544
+ for (const [prn, i] of this.ambIdx) {
15545
+ if (i === idx) this.ambIdx.delete(prn);
15546
+ else if (i > idx) this.ambIdx.set(prn, i - 1);
15483
15547
  }
15484
- for (const [sys, i] of clkIdx) {
15485
- if (i > idx) clkIdx.set(sys, i - 1);
15548
+ for (const [sys, i] of this.clkIdx) {
15549
+ if (i > idx) this.clkIdx.set(sys, i - 1);
15486
15550
  }
15487
- };
15488
- const clockOf = (sys) => {
15489
- let i = clkIdx.get(sys);
15551
+ }
15552
+ /** State index of a constellation's receiver clock, creating it lazily. */
15553
+ clockOf(sys) {
15554
+ let i = this.clkIdx.get(sys);
15490
15555
  if (i === void 0) {
15491
- i = growState(0, CLK_VAR);
15492
- clkIdx.set(sys, i);
15556
+ i = this.growState(0, CLK_VAR);
15557
+ this.clkIdx.set(sys, i);
15493
15558
  }
15494
15559
  return i;
15495
- };
15496
- const series = [];
15497
- const truth = opts.groundTruth;
15498
- const t0 = epochs[0]?.timeMs ?? 0;
15499
- let convergenceSec = null;
15500
- let convergedStreak = 0;
15501
- for (let ei = 0; ei < epochs.length; ei++) {
15502
- const epoch = epochs[ei];
15560
+ }
15561
+ /** Process one epoch, carrying the filter forward; returns its result. */
15562
+ process(epoch) {
15563
+ const {
15564
+ source,
15565
+ opts,
15566
+ elevMask,
15567
+ codeSigma,
15568
+ phaseSigma,
15569
+ ztdQ,
15570
+ kinematic,
15571
+ corrections,
15572
+ truth,
15573
+ x,
15574
+ P,
15575
+ clkIdx,
15576
+ clockSeeded,
15577
+ ambIdx,
15578
+ lastSeen,
15579
+ arcSnap,
15580
+ mwState,
15581
+ series
15582
+ } = this;
15583
+ const flushArc = this.flushArc.bind(this);
15584
+ const detectSlip = this.detectSlip.bind(this);
15585
+ const growState = this.growState.bind(this);
15586
+ const dropState = this.dropState.bind(this);
15587
+ const clockOf = this.clockOf.bind(this);
15588
+ const ei = this.ei;
15589
+ if (ei === 0) this.t0 = epoch.timeMs;
15590
+ const t0 = this.t0;
15503
15591
  if (kinematic && ei > 0) {
15504
15592
  for (const p of [IDX_X, IDX_Y, IDX_Z]) {
15505
15593
  for (let j = 0; j < x.length; j++) {
@@ -15520,7 +15608,7 @@ function solvePpp(epochs, sp3, opts) {
15520
15608
  for (const o of epoch.obs) {
15521
15609
  if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
15522
15610
  const slip = detectSlip(o, ei);
15523
- const sat = satStateAtEmission(sp3, o.prn, epoch.timeMs, rcv, opts.clk);
15611
+ const sat = satStateAtEmission(source, o.prn, epoch.timeMs, rcv);
15524
15612
  if (!sat) continue;
15525
15613
  const [elRad, azRad] = getAer(
15526
15614
  sat.state.x,
@@ -15540,7 +15628,9 @@ function solvePpp(epochs, sp3, opts) {
15540
15628
  const lam1 = C_LIGHT / o.f1;
15541
15629
  const lam2 = C_LIGHT / o.f2;
15542
15630
  if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
15543
- const pIf = g * o.c1 - (g - 1) * o.c2;
15631
+ const b1 = source.codeBias?.(o.prn, o.code1 ?? "", epoch.timeMs) ?? 0;
15632
+ const b2 = source.codeBias?.(o.prn, o.code2 ?? "", epoch.timeMs) ?? 0;
15633
+ const pIf = g * (o.c1 - b1) - (g - 1) * (o.c2 - b2);
15544
15634
  const lIf = g * (o.l1 * lam1) - (g - 1) * (o.l2 * lam2);
15545
15635
  if (!Number.isFinite(pIf) || !Number.isFinite(lIf)) continue;
15546
15636
  const trop = opts.troposphere ?? true ? niellMapping(elRad, latRad, heightM, epoch.timeMs) : { zhd: 0, mh: 0, mw: 0 };
@@ -15727,16 +15817,16 @@ function solvePpp(epochs, sp3, opts) {
15727
15817
  pos[2] - truth[2]
15728
15818
  );
15729
15819
  if (error3d < 0.1) {
15730
- convergedStreak++;
15731
- if (convergedStreak >= 10 && convergenceSec == null) {
15732
- convergenceSec = (epoch.timeMs - t0) / 1e3;
15820
+ this.convergedStreak++;
15821
+ if (this.convergedStreak >= 10 && this.convergenceSec == null) {
15822
+ this.convergenceSec = (epoch.timeMs - t0) / 1e3;
15733
15823
  }
15734
15824
  } else {
15735
- convergedStreak = 0;
15736
- convergenceSec = null;
15825
+ this.convergedStreak = 0;
15826
+ this.convergenceSec = null;
15737
15827
  }
15738
15828
  }
15739
- series.push({
15829
+ const result = {
15740
15830
  timeMs: epoch.timeMs,
15741
15831
  enu,
15742
15832
  error3d,
@@ -15745,50 +15835,68 @@ function solvePpp(epochs, sp3, opts) {
15745
15835
  ztdWet: x[IDX_ZWD],
15746
15836
  ztdHydrostatic: epochZhd,
15747
15837
  phaseResRms: nPhaseRes > 0 ? Math.sqrt(sumPhaseResSq / nPhaseRes) : 0
15748
- });
15749
- }
15750
- let finalState;
15751
- if (opts.exposeState) {
15752
- const ambs = [];
15753
- for (const [prn, index] of ambIdx) {
15754
- const s = arcSnap.get(prn);
15755
- if (!s || s.nEpochs < 10) continue;
15756
- ambs.push({
15757
- prn,
15758
- index,
15759
- aIF: x[index],
15760
- mwCyc: mwState.get(prn)?.mean ?? s.mwCyc,
15761
- f1: s.f1,
15762
- f2: s.f2,
15763
- elevDeg: s.elevSum / s.nEpochs
15764
- });
15838
+ };
15839
+ series.push(result);
15840
+ this.ei = ei + 1;
15841
+ return result;
15842
+ }
15843
+ /** Finalise the session: capture the AR state, flush open arcs, assemble. */
15844
+ solution() {
15845
+ const { opts, x, P, ambIdx, arcSnap, mwState, arcs, series, truth } = this;
15846
+ const flushArc = this.flushArc.bind(this);
15847
+ let finalState;
15848
+ if (opts.exposeState) {
15849
+ const ambs = [];
15850
+ for (const [prn, index] of ambIdx) {
15851
+ const s = arcSnap.get(prn);
15852
+ if (!s || s.nEpochs < 10) continue;
15853
+ ambs.push({
15854
+ prn,
15855
+ index,
15856
+ aIF: x[index],
15857
+ mwCyc: mwState.get(prn)?.mean ?? s.mwCyc,
15858
+ f1: s.f1,
15859
+ f2: s.f2,
15860
+ elevDeg: s.elevSum / s.nEpochs
15861
+ });
15862
+ }
15863
+ finalState = {
15864
+ position: [x[IDX_X], x[IDX_Y], x[IDX_Z]],
15865
+ covariance: P.map((row) => row.slice()),
15866
+ ambiguities: ambs
15867
+ };
15765
15868
  }
15766
- finalState = {
15767
- position: [x[IDX_X], x[IDX_Y], x[IDX_Z]],
15768
- covariance: P.map((row) => row.slice()),
15769
- ambiguities: ambs
15869
+ for (const prn of [...arcSnap.keys()]) flushArc(prn);
15870
+ const finalPos = [
15871
+ x[IDX_X],
15872
+ x[IDX_Y],
15873
+ x[IDX_Z]
15874
+ ];
15875
+ const llh = ecefToGeodetic(finalPos[0], finalPos[1], finalPos[2]);
15876
+ const finalError3d = truth ? Math.hypot(
15877
+ finalPos[0] - truth[0],
15878
+ finalPos[1] - truth[1],
15879
+ finalPos[2] - truth[2]
15880
+ ) : null;
15881
+ return {
15882
+ position: finalPos,
15883
+ llh,
15884
+ series,
15885
+ ztdWet: x[IDX_ZWD],
15886
+ ztdHydrostatic: series.length ? series[series.length - 1].ztdHydrostatic : 0,
15887
+ epochsUsed: series.length,
15888
+ convergenceSec: this.convergenceSec,
15889
+ finalError3d,
15890
+ arcs,
15891
+ finalState
15770
15892
  };
15771
15893
  }
15772
- for (const prn of [...arcSnap.keys()]) flushArc(prn);
15773
- const finalPos = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
15774
- const llh = ecefToGeodetic(finalPos[0], finalPos[1], finalPos[2]);
15775
- const finalError3d = truth ? Math.hypot(
15776
- finalPos[0] - truth[0],
15777
- finalPos[1] - truth[1],
15778
- finalPos[2] - truth[2]
15779
- ) : null;
15780
- return {
15781
- position: finalPos,
15782
- llh,
15783
- series,
15784
- ztdWet: x[IDX_ZWD],
15785
- ztdHydrostatic: series.length ? series[series.length - 1].ztdHydrostatic : 0,
15786
- epochsUsed: epochs.length,
15787
- convergenceSec,
15788
- finalError3d,
15789
- arcs,
15790
- finalState
15791
- };
15894
+ };
15895
+ function solvePpp(epochs, sp3OrSource, opts) {
15896
+ const source = "satState" in sp3OrSource ? sp3OrSource : new Sp3EphemerisSource(sp3OrSource, opts.clk);
15897
+ const eng = new PppEngine(opts, source);
15898
+ for (const epoch of epochs) eng.process(epoch);
15899
+ return eng.solution();
15792
15900
  }
15793
15901
 
15794
15902
  // src/positioning/ppp-ar.ts
@@ -18843,6 +18951,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
18843
18951
  MultipathAccumulator,
18844
18952
  OEM4_HLEN,
18845
18953
  OMEGA_E,
18954
+ PppEngine,
18846
18955
  REFERENCE_FRAMES,
18847
18956
  RINEX_CODES,
18848
18957
  RTCM2_MESSAGE_NAMES,
@@ -18870,6 +18979,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
18870
18979
  SYS_SHORT,
18871
18980
  SbasProcessor,
18872
18981
  Scale,
18982
+ Sp3EphemerisSource,
18873
18983
  WGS84_ECCENTRICITY_SQUARED,
18874
18984
  WGS84_FLATTENING,
18875
18985
  WGS84_SEMI_MAJOR_AXIS,
@@ -18880,6 +18990,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
18880
18990
  analyzeQuality,
18881
18991
  applyHelmert,
18882
18992
  applyIonoDcb,
18993
+ applyOrbitClock,
18883
18994
  biasMetres,
18884
18995
  binexCrc16,
18885
18996
  binexCrc32,
@@ -18913,6 +19024,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
18913
19024
  decodeIgsSsr,
18914
19025
  decodeLegacyObs,
18915
19026
  decodeMsmFull,
19027
+ decodeObs,
18916
19028
  decodeSbfNavigation,
18917
19029
  decodeSsr,
18918
19030
  decodeSystemParams,
@@ -19003,6 +19115,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
19003
19115
  glonassPosition,
19004
19116
  gmst,
19005
19117
  greatCircleMidpoint,
19118
+ hasToOrbitClock,
19006
19119
  hdrLine,
19007
19120
  horizonDistance,
19008
19121
  ionoFree,
@@ -19016,11 +19129,11 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
19016
19129
  looksLikeRtcm2,
19017
19130
  maskRadForAzimuth,
19018
19131
  moonEcef,
19019
- msmEpochToDate,
19020
19132
  navTimesFromEph,
19021
19133
  niellMapping,
19022
19134
  nlWavelength,
19023
19135
  nmeaCoordToDecimal,
19136
+ obsEpochToDate,
19024
19137
  oem4Frames,
19025
19138
  padL,
19026
19139
  padR,