gnss-js 1.27.0 → 1.29.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/chunk-4KMWWCUR.js +120 -0
- package/dist/{chunk-4XGKCVE3.js → chunk-5WHKMKIB.js} +827 -2
- package/dist/{chunk-QVNNHACQ.js → chunk-6GTS5MVI.js} +0 -118
- package/dist/index.cjs +847 -19
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +22 -4
- package/dist/positioning.cjs +900 -1
- package/dist/positioning.d.cts +231 -2
- package/dist/positioning.d.ts +231 -2
- package/dist/positioning.js +18 -1
- package/dist/rinex.d.cts +2 -49
- package/dist/rinex.d.ts +2 -49
- package/dist/rinex.js +5 -3
- package/dist/sp3-BAq8l39b.d.cts +70 -0
- package/dist/sp3-BAq8l39b.d.ts +70 -0
- package/package.json +1 -1
- package/dist/ionex-DaW5x9nq.d.cts +0 -23
- package/dist/ionex-DaW5x9nq.d.ts +0 -23
package/dist/index.cjs
CHANGED
|
@@ -117,6 +117,7 @@ __export(src_exports, {
|
|
|
117
117
|
binexRecords: () => binexRecords,
|
|
118
118
|
buildGloChannelMap: () => buildGloChannelMap,
|
|
119
119
|
buildObsIndices: () => buildObsIndices,
|
|
120
|
+
buildPppAntenna: () => buildPppAntenna,
|
|
120
121
|
clampUnit: () => clampUnit,
|
|
121
122
|
computeAllPositions: () => computeAllPositions,
|
|
122
123
|
computeDop: () => computeDop,
|
|
@@ -130,6 +131,7 @@ __export(src_exports, {
|
|
|
130
131
|
connectToMountpoint: () => connectToMountpoint,
|
|
131
132
|
crc32: () => crc32,
|
|
132
133
|
createGzipLineSink: () => createGzipLineSink,
|
|
134
|
+
createPppCorrections: () => createPppCorrections,
|
|
133
135
|
createStationMeta: () => createStationMeta,
|
|
134
136
|
createStreamStats: () => createStreamStats,
|
|
135
137
|
crxDecompress: () => crxDecompress,
|
|
@@ -215,6 +217,7 @@ __export(src_exports, {
|
|
|
215
217
|
glonassAlmanacEpochMs: () => glonassAlmanacEpochMs,
|
|
216
218
|
glonassAlmanacPosition: () => glonassAlmanacPosition,
|
|
217
219
|
glonassPosition: () => glonassPosition,
|
|
220
|
+
gmst: () => gmst,
|
|
218
221
|
greatCircleMidpoint: () => greatCircleMidpoint,
|
|
219
222
|
hdrLine: () => hdrLine,
|
|
220
223
|
horizonDistance: () => horizonDistance,
|
|
@@ -224,8 +227,10 @@ __export(src_exports, {
|
|
|
224
227
|
lambdaReduction: () => lambdaReduction,
|
|
225
228
|
lambdaSearch: () => lambdaSearch,
|
|
226
229
|
maskRadForAzimuth: () => maskRadForAzimuth,
|
|
230
|
+
moonEcef: () => moonEcef,
|
|
227
231
|
msmEpochToDate: () => msmEpochToDate,
|
|
228
232
|
navTimesFromEph: () => navTimesFromEph,
|
|
233
|
+
niellMapping: () => niellMapping,
|
|
229
234
|
nmeaCoordToDecimal: () => nmeaCoordToDecimal,
|
|
230
235
|
oem4Frames: () => oem4Frames,
|
|
231
236
|
padL: () => padL,
|
|
@@ -275,10 +280,13 @@ __export(src_exports, {
|
|
|
275
280
|
selectEphemeris: () => selectEphemeris,
|
|
276
281
|
setGloFreqNumber: () => setGloFreqNumber,
|
|
277
282
|
setRtcm3DebugHandler: () => setRtcm3DebugHandler,
|
|
283
|
+
solidEarthTide: () => solidEarthTide,
|
|
278
284
|
solveDgnss: () => solveDgnss,
|
|
285
|
+
solvePpp: () => solvePpp,
|
|
279
286
|
solveSpp: () => solveSpp,
|
|
280
287
|
sp3Position: () => sp3Position,
|
|
281
288
|
stationHeaderLines: () => stationHeaderLines,
|
|
289
|
+
sunEcef: () => sunEcef,
|
|
282
290
|
systemCmp: () => systemCmp,
|
|
283
291
|
systemName: () => systemName,
|
|
284
292
|
toRtkEpoch: () => toRtkEpoch,
|
|
@@ -640,7 +648,7 @@ function getDayOfYear(date) {
|
|
|
640
648
|
(date.getTime() - Date.UTC(date.getUTCFullYear())) / MILLISECONDS_IN_DAY
|
|
641
649
|
) + 1;
|
|
642
650
|
}
|
|
643
|
-
function getDateFromDayOfYear(
|
|
651
|
+
function getDateFromDayOfYear(dayOfYear2, date) {
|
|
644
652
|
return new Date(
|
|
645
653
|
Date.UTC(
|
|
646
654
|
date.getUTCFullYear(),
|
|
@@ -650,7 +658,7 @@ function getDateFromDayOfYear(dayOfYear, date) {
|
|
|
650
658
|
date.getUTCMinutes(),
|
|
651
659
|
date.getUTCSeconds(),
|
|
652
660
|
date.getUTCMilliseconds()
|
|
653
|
-
) + (
|
|
661
|
+
) + (dayOfYear2 - 1) * MILLISECONDS_IN_DAY
|
|
654
662
|
);
|
|
655
663
|
}
|
|
656
664
|
function getDayOfWeek(date) {
|
|
@@ -7623,14 +7631,14 @@ function parseOrbitBlock(c, masks) {
|
|
|
7623
7631
|
const gnssIod = c.u(IOD_BITS[sys.system]);
|
|
7624
7632
|
const rad = c.s(13);
|
|
7625
7633
|
const inT = c.s(12);
|
|
7626
|
-
const
|
|
7634
|
+
const cross2 = c.s(12);
|
|
7627
7635
|
corrections.push({
|
|
7628
7636
|
system: sys.system,
|
|
7629
7637
|
prn,
|
|
7630
7638
|
gnssIod,
|
|
7631
7639
|
deltaRadial: rad === -4096 ? null : rad * 25e-4,
|
|
7632
7640
|
deltaInTrack: inT === -2048 ? null : inT * 8e-3,
|
|
7633
|
-
deltaCrossTrack:
|
|
7641
|
+
deltaCrossTrack: cross2 === -2048 ? null : cross2 * 8e-3
|
|
7634
7642
|
});
|
|
7635
7643
|
}
|
|
7636
7644
|
}
|
|
@@ -10657,17 +10665,17 @@ function ecefToAzEl(rxX, rxY, rxZ, satX, satY, satZ) {
|
|
|
10657
10665
|
function computeDop(satAzEls) {
|
|
10658
10666
|
const n = satAzEls.length;
|
|
10659
10667
|
if (n < 4) return null;
|
|
10660
|
-
const
|
|
10668
|
+
const H3 = [];
|
|
10661
10669
|
for (const { az, el } of satAzEls) {
|
|
10662
10670
|
const cosEl = Math.cos(el);
|
|
10663
|
-
|
|
10671
|
+
H3.push([cosEl * Math.sin(az), cosEl * Math.cos(az), Math.sin(el), 1]);
|
|
10664
10672
|
}
|
|
10665
10673
|
const HtH = Array.from({ length: 4 }, () => new Array(4).fill(0));
|
|
10666
10674
|
for (let i = 0; i < 4; i++) {
|
|
10667
10675
|
for (let j = 0; j < 4; j++) {
|
|
10668
10676
|
let sum = 0;
|
|
10669
10677
|
for (let k = 0; k < n; k++) {
|
|
10670
|
-
sum +=
|
|
10678
|
+
sum += H3[k][i] * H3[k][j];
|
|
10671
10679
|
}
|
|
10672
10680
|
HtH[i][j] = sum;
|
|
10673
10681
|
}
|
|
@@ -11794,7 +11802,7 @@ function solveDgnss(rover, base, basePos, ephemerides, timeMs, opts = {}) {
|
|
|
11794
11802
|
let cov = null;
|
|
11795
11803
|
for (let iter = 0; iter < maxIterations; iter++) {
|
|
11796
11804
|
iterations = iter + 1;
|
|
11797
|
-
const
|
|
11805
|
+
const H3 = [];
|
|
11798
11806
|
const v = [];
|
|
11799
11807
|
const terms = /* @__PURE__ */ new Map();
|
|
11800
11808
|
const termOf = (g) => {
|
|
@@ -11810,11 +11818,11 @@ function solveDgnss(rover, base, basePos, ephemerides, timeMs, opts = {}) {
|
|
|
11810
11818
|
const tr = termOf(row.ref);
|
|
11811
11819
|
const pred = ts.rho - row.g.rhoB + ts.dTropo - (tr.rho - row.ref.rhoB + tr.dTropo);
|
|
11812
11820
|
v.push(row.z - pred);
|
|
11813
|
-
|
|
11821
|
+
H3.push([ts.u[0] - tr.u[0], ts.u[1] - tr.u[1], ts.u[2] - tr.u[2]]);
|
|
11814
11822
|
}
|
|
11815
|
-
const Ht = transpose(
|
|
11823
|
+
const Ht = transpose(H3);
|
|
11816
11824
|
const HtW = matMul(Ht, W);
|
|
11817
|
-
const N = matMul(HtW,
|
|
11825
|
+
const N = matMul(HtW, H3);
|
|
11818
11826
|
const b = matMul(
|
|
11819
11827
|
HtW,
|
|
11820
11828
|
v.map((s) => [s])
|
|
@@ -11830,7 +11838,7 @@ function solveDgnss(rover, base, basePos, ephemerides, timeMs, opts = {}) {
|
|
|
11830
11838
|
z += dx[2][0];
|
|
11831
11839
|
cov = Ninv;
|
|
11832
11840
|
rows.forEach((row, i) => {
|
|
11833
|
-
residuals[row.g.prn] = v[i] - (
|
|
11841
|
+
residuals[row.g.prn] = v[i] - (H3[i][0] * dx[0][0] + H3[i][1] * dx[1][0] + H3[i][2] * dx[2][0]);
|
|
11834
11842
|
});
|
|
11835
11843
|
if (Math.hypot(dx[0][0], dx[1][0], dx[2][0]) < convergenceM) {
|
|
11836
11844
|
converged = true;
|
|
@@ -12222,19 +12230,19 @@ var RtkFloatEngine = class {
|
|
|
12222
12230
|
const PPrior = this.P;
|
|
12223
12231
|
let xi = [...this.x];
|
|
12224
12232
|
let K = [];
|
|
12225
|
-
let
|
|
12233
|
+
let H3 = [];
|
|
12226
12234
|
for (let it = 0; it < Math.max(o.updateIterations, 1); it++) {
|
|
12227
|
-
|
|
12235
|
+
H3 = [];
|
|
12228
12236
|
const v = [];
|
|
12229
12237
|
for (const row of rows) {
|
|
12230
12238
|
const { pred, h } = predict(row, xi);
|
|
12231
12239
|
let corr = 0;
|
|
12232
12240
|
for (let j = 0; j < n; j++) corr += h[j] * (xPrior[j] - xi[j]);
|
|
12233
12241
|
v.push(row.z - pred - corr);
|
|
12234
|
-
|
|
12242
|
+
H3.push(h);
|
|
12235
12243
|
}
|
|
12236
|
-
const Ht = transpose(
|
|
12237
|
-
const S = matMul(matMul(
|
|
12244
|
+
const Ht = transpose(H3);
|
|
12245
|
+
const S = matMul(matMul(H3, PPrior), Ht);
|
|
12238
12246
|
for (let i = 0; i < rows.length; i++)
|
|
12239
12247
|
for (let j = 0; j < rows.length; j++) S[i][j] += R[i][j];
|
|
12240
12248
|
const Sinv = matInv(S);
|
|
@@ -12250,7 +12258,7 @@ var RtkFloatEngine = class {
|
|
|
12250
12258
|
xi = xPrior.map((s, i) => s + dx[i][0]);
|
|
12251
12259
|
}
|
|
12252
12260
|
this.x = xi;
|
|
12253
|
-
const KH = matMul(K,
|
|
12261
|
+
const KH = matMul(K, H3);
|
|
12254
12262
|
const IKH = zeros(n, n);
|
|
12255
12263
|
for (let i = 0; i < n; i++)
|
|
12256
12264
|
for (let j = 0; j < n; j++) IKH[i][j] = (i === j ? 1 : 0) - KH[i][j];
|
|
@@ -12343,6 +12351,817 @@ var RtkFloatEngine = class {
|
|
|
12343
12351
|
}
|
|
12344
12352
|
};
|
|
12345
12353
|
|
|
12354
|
+
// src/positioning/ppp-tropo.ts
|
|
12355
|
+
var HYD_AVG_A = [
|
|
12356
|
+
0.0012769934,
|
|
12357
|
+
1268323e-9,
|
|
12358
|
+
0.0012465397,
|
|
12359
|
+
0.0012196049,
|
|
12360
|
+
0.0012045996
|
|
12361
|
+
];
|
|
12362
|
+
var HYD_AVG_B = [
|
|
12363
|
+
0.0029153695,
|
|
12364
|
+
0.0029152299,
|
|
12365
|
+
0.0029288445,
|
|
12366
|
+
0.0029022565,
|
|
12367
|
+
0.0029024912
|
|
12368
|
+
];
|
|
12369
|
+
var HYD_AVG_C = [
|
|
12370
|
+
0.062610505,
|
|
12371
|
+
0.062837393,
|
|
12372
|
+
0.063721774,
|
|
12373
|
+
0.063824265,
|
|
12374
|
+
0.064258455
|
|
12375
|
+
];
|
|
12376
|
+
var HYD_AMP_A = [0, 12709626e-12, 26523662e-12, 34000452e-12, 41202191e-12];
|
|
12377
|
+
var HYD_AMP_B = [0, 21414979e-12, 30160779e-12, 72562722e-12, 11723375e-11];
|
|
12378
|
+
var HYD_AMP_C = [0, 901284e-10, 43497037e-12, 84795348e-11, 0.0017037206];
|
|
12379
|
+
var HT_A = 253e-7;
|
|
12380
|
+
var HT_B = 549e-5;
|
|
12381
|
+
var HT_C = 114e-5;
|
|
12382
|
+
var WET_A = [
|
|
12383
|
+
58021897e-11,
|
|
12384
|
+
56794847e-11,
|
|
12385
|
+
58118019e-11,
|
|
12386
|
+
59727542e-11,
|
|
12387
|
+
61641693e-11
|
|
12388
|
+
];
|
|
12389
|
+
var WET_B = [
|
|
12390
|
+
0.0014275268,
|
|
12391
|
+
0.0015138625,
|
|
12392
|
+
0.0014572752,
|
|
12393
|
+
0.0015007428,
|
|
12394
|
+
0.0017599082
|
|
12395
|
+
];
|
|
12396
|
+
var WET_C = [
|
|
12397
|
+
0.043472961,
|
|
12398
|
+
0.04672951,
|
|
12399
|
+
0.043908931,
|
|
12400
|
+
0.044626982,
|
|
12401
|
+
0.054736038
|
|
12402
|
+
];
|
|
12403
|
+
var LATS = [15, 30, 45, 60, 75];
|
|
12404
|
+
function interpLat(table, absLatDeg) {
|
|
12405
|
+
if (absLatDeg <= 15) return table[0];
|
|
12406
|
+
if (absLatDeg >= 75) return table[4];
|
|
12407
|
+
let i = 0;
|
|
12408
|
+
while (i < 4 && absLatDeg > LATS[i + 1]) i++;
|
|
12409
|
+
const t = (absLatDeg - LATS[i]) / (LATS[i + 1] - LATS[i]);
|
|
12410
|
+
return table[i] + t * (table[i + 1] - table[i]);
|
|
12411
|
+
}
|
|
12412
|
+
function marini(sinEl, a, b, c) {
|
|
12413
|
+
const num = 1 + a / (1 + b / (1 + c));
|
|
12414
|
+
const den = sinEl + a / (sinEl + b / (sinEl + c));
|
|
12415
|
+
return num / den;
|
|
12416
|
+
}
|
|
12417
|
+
function dayOfYear(timeMs) {
|
|
12418
|
+
const d = new Date(timeMs);
|
|
12419
|
+
const start = Date.UTC(d.getUTCFullYear(), 0, 1);
|
|
12420
|
+
return Math.floor((timeMs - start) / 864e5) + 1;
|
|
12421
|
+
}
|
|
12422
|
+
function niellMapping(elRad, latRad, heightM, timeMs) {
|
|
12423
|
+
const sinEl = Math.sin(Math.max(elRad, 1e-3));
|
|
12424
|
+
const absLat = Math.abs(latRad * 180 / Math.PI);
|
|
12425
|
+
const hKm = heightM / 1e3;
|
|
12426
|
+
let doy = dayOfYear(timeMs);
|
|
12427
|
+
if (latRad < 0) doy += 365.25 / 2;
|
|
12428
|
+
const yfrac = Math.cos(2 * Math.PI * (doy - 28) / 365.25);
|
|
12429
|
+
const ah = interpLat(HYD_AVG_A, absLat) - interpLat(HYD_AMP_A, absLat) * yfrac;
|
|
12430
|
+
const bh = interpLat(HYD_AVG_B, absLat) - interpLat(HYD_AMP_B, absLat) * yfrac;
|
|
12431
|
+
const ch = interpLat(HYD_AVG_C, absLat) - interpLat(HYD_AMP_C, absLat) * yfrac;
|
|
12432
|
+
const mHt = marini(sinEl, HT_A, HT_B, HT_C);
|
|
12433
|
+
const dmdh = 1 / sinEl - mHt;
|
|
12434
|
+
const mh = marini(sinEl, ah, bh, ch) + dmdh * hKm;
|
|
12435
|
+
const aw = interpLat(WET_A, absLat);
|
|
12436
|
+
const bw = interpLat(WET_B, absLat);
|
|
12437
|
+
const cw = interpLat(WET_C, absLat);
|
|
12438
|
+
const mw = marini(sinEl, aw, bw, cw);
|
|
12439
|
+
const h = heightM < 0 ? 0 : heightM > 1e4 ? 1e4 : heightM;
|
|
12440
|
+
const pres = 1013.25 * Math.pow(1 - 22557e-9 * h, 5.2568);
|
|
12441
|
+
const zhd = 22768e-7 * pres / (1 - 266e-5 * Math.cos(2 * latRad) - 28e-5 * (h / 1e3));
|
|
12442
|
+
return { zhd, mh, mw };
|
|
12443
|
+
}
|
|
12444
|
+
|
|
12445
|
+
// src/positioning/ppp-astro.ts
|
|
12446
|
+
var AU = 149597870700;
|
|
12447
|
+
var GPS_UTC_LEAP = 18;
|
|
12448
|
+
var J2000_MS = Date.UTC(2e3, 0, 1, 12, 0, 0);
|
|
12449
|
+
var DEG = Math.PI / 180;
|
|
12450
|
+
function daysSinceJ2000(timeMs) {
|
|
12451
|
+
return (timeMs - GPS_UTC_LEAP * 1e3 - J2000_MS) / 864e5;
|
|
12452
|
+
}
|
|
12453
|
+
function gmst(timeMs) {
|
|
12454
|
+
const d = daysSinceJ2000(timeMs);
|
|
12455
|
+
let deg = 280.46061837 + 360.98564736629 * d;
|
|
12456
|
+
deg %= 360;
|
|
12457
|
+
if (deg < 0) deg += 360;
|
|
12458
|
+
return deg * DEG;
|
|
12459
|
+
}
|
|
12460
|
+
function eciToEcef(v, theta) {
|
|
12461
|
+
const c = Math.cos(theta);
|
|
12462
|
+
const s = Math.sin(theta);
|
|
12463
|
+
return [v[0] * c + v[1] * s, -v[0] * s + v[1] * c, v[2]];
|
|
12464
|
+
}
|
|
12465
|
+
function sunEcef(timeMs) {
|
|
12466
|
+
const n = daysSinceJ2000(timeMs);
|
|
12467
|
+
const L = (280.46 + 0.9856474 * n) * DEG;
|
|
12468
|
+
const g = (357.528 + 0.9856003 * n) * DEG;
|
|
12469
|
+
const lambda = L + (1.915 * Math.sin(g) + 0.02 * Math.sin(2 * g)) * DEG;
|
|
12470
|
+
const eps = (23.439 - 4e-7 * n) * DEG;
|
|
12471
|
+
const R = (1.00014 - 0.01671 * Math.cos(g) - 14e-5 * Math.cos(2 * g)) * AU;
|
|
12472
|
+
const eci = [
|
|
12473
|
+
R * Math.cos(lambda),
|
|
12474
|
+
R * Math.cos(eps) * Math.sin(lambda),
|
|
12475
|
+
R * Math.sin(eps) * Math.sin(lambda)
|
|
12476
|
+
];
|
|
12477
|
+
return eciToEcef(eci, gmst(timeMs));
|
|
12478
|
+
}
|
|
12479
|
+
function moonEcef(timeMs) {
|
|
12480
|
+
const T = daysSinceJ2000(timeMs) / 36525;
|
|
12481
|
+
const L0 = 218.31617 + 481267.88088 * T - 1.3972 * T;
|
|
12482
|
+
const l = 134.96292 + 477198.86753 * T;
|
|
12483
|
+
const lp = 357.52543 + 35999.04944 * T;
|
|
12484
|
+
const F = 93.27283 + 483202.01873 * T;
|
|
12485
|
+
const D = 297.85027 + 445267.11135 * T;
|
|
12486
|
+
const s = (x) => Math.sin(x * DEG);
|
|
12487
|
+
const c = (x) => Math.cos(x * DEG);
|
|
12488
|
+
const lon = L0 + 6.28875 * s(l) + 1.274018 * s(2 * D - l) + 0.658309 * s(2 * D) + 0.213616 * s(2 * l) - 0.185596 * s(lp) - 0.114336 * s(2 * F) + 0.058793 * s(2 * D - 2 * l) + 0.057212 * s(2 * D - lp - l) + 0.05332 * s(2 * D + l);
|
|
12489
|
+
const lat = 5.128189 * s(F) + 0.280606 * s(l + F) + 0.277693 * s(l - F) + 0.173238 * s(2 * D - F) + 0.055413 * s(2 * D + F - l) + 0.046272 * s(2 * D - F - l);
|
|
12490
|
+
const r = (385e3 - 20905 * c(l) - 3699 * c(2 * D - l) - 2956 * c(2 * D) - 570 * c(2 * l)) * 1e3;
|
|
12491
|
+
const eps = (23.4393 - 4e-7 * daysSinceJ2000(timeMs)) * DEG;
|
|
12492
|
+
const lonR = lon * DEG;
|
|
12493
|
+
const latR = lat * DEG;
|
|
12494
|
+
const xe = r * Math.cos(latR) * Math.cos(lonR);
|
|
12495
|
+
const ye = r * Math.cos(latR) * Math.sin(lonR);
|
|
12496
|
+
const ze = r * Math.sin(latR);
|
|
12497
|
+
const eci = [
|
|
12498
|
+
xe,
|
|
12499
|
+
ye * Math.cos(eps) - ze * Math.sin(eps),
|
|
12500
|
+
ye * Math.sin(eps) + ze * Math.cos(eps)
|
|
12501
|
+
];
|
|
12502
|
+
return eciToEcef(eci, gmst(timeMs));
|
|
12503
|
+
}
|
|
12504
|
+
var H2 = 0.6078;
|
|
12505
|
+
var L2 = 0.0847;
|
|
12506
|
+
var RE = 6378137;
|
|
12507
|
+
var GM_SUN_RATIO = 332946.0482;
|
|
12508
|
+
var GM_MOON_RATIO = 0.0123000371;
|
|
12509
|
+
function solidEarthTide(rcv, sun, moon) {
|
|
12510
|
+
const rNorm = Math.hypot(rcv[0], rcv[1], rcv[2]);
|
|
12511
|
+
const rHat = [
|
|
12512
|
+
rcv[0] / rNorm,
|
|
12513
|
+
rcv[1] / rNorm,
|
|
12514
|
+
rcv[2] / rNorm
|
|
12515
|
+
];
|
|
12516
|
+
const disp = [0, 0, 0];
|
|
12517
|
+
for (const [body, ratio] of [
|
|
12518
|
+
[sun, GM_SUN_RATIO],
|
|
12519
|
+
[moon, GM_MOON_RATIO]
|
|
12520
|
+
]) {
|
|
12521
|
+
const rj = Math.hypot(body[0], body[1], body[2]);
|
|
12522
|
+
const jHat = [
|
|
12523
|
+
body[0] / rj,
|
|
12524
|
+
body[1] / rj,
|
|
12525
|
+
body[2] / rj
|
|
12526
|
+
];
|
|
12527
|
+
const dot2 = rHat[0] * jHat[0] + rHat[1] * jHat[1] + rHat[2] * jHat[2];
|
|
12528
|
+
const factor = ratio * RE * RE * RE * RE / (rj * rj * rj);
|
|
12529
|
+
const radialScale = H2 * (1.5 * dot2 * dot2 - 0.5);
|
|
12530
|
+
const tanScale = 3 * L2 * dot2;
|
|
12531
|
+
for (let k = 0; k < 3; k++) {
|
|
12532
|
+
disp[k] += factor * (radialScale * rHat[k] + tanScale * (jHat[k] - dot2 * rHat[k]));
|
|
12533
|
+
}
|
|
12534
|
+
}
|
|
12535
|
+
return disp;
|
|
12536
|
+
}
|
|
12537
|
+
|
|
12538
|
+
// src/positioning/ppp-antenna.ts
|
|
12539
|
+
function parseAntexTime(s) {
|
|
12540
|
+
const p = s.trim().split(/\s+/).map(Number);
|
|
12541
|
+
if (p.length < 3 || p.some((v) => Number.isNaN(v))) return null;
|
|
12542
|
+
return Date.UTC(
|
|
12543
|
+
p[0],
|
|
12544
|
+
(p[1] || 1) - 1,
|
|
12545
|
+
p[2] || 1,
|
|
12546
|
+
p[3] ?? 0,
|
|
12547
|
+
p[4] ?? 0,
|
|
12548
|
+
Math.floor(p[5] ?? 0)
|
|
12549
|
+
);
|
|
12550
|
+
}
|
|
12551
|
+
function freqOf(entry, code) {
|
|
12552
|
+
return entry.frequencies.find((f) => f.frequency === code);
|
|
12553
|
+
}
|
|
12554
|
+
function combineIf(fA, fB, f1, f2) {
|
|
12555
|
+
const g = f1 * f1 / (f1 * f1 - f2 * f2);
|
|
12556
|
+
const mm = 1e-3;
|
|
12557
|
+
const pco = [
|
|
12558
|
+
(g * fA.pcoN - (g - 1) * fB.pcoN) * mm,
|
|
12559
|
+
(g * fA.pcoE - (g - 1) * fB.pcoE) * mm,
|
|
12560
|
+
(g * fA.pcoU - (g - 1) * fB.pcoU) * mm
|
|
12561
|
+
];
|
|
12562
|
+
const nz = Math.min(fA.pcvNoazi.length, fB.pcvNoazi.length);
|
|
12563
|
+
const pcvNoazi = new Array(nz);
|
|
12564
|
+
for (let i = 0; i < nz; i++) {
|
|
12565
|
+
pcvNoazi[i] = (g * fA.pcvNoazi[i] - (g - 1) * fB.pcvNoazi[i]) * mm;
|
|
12566
|
+
}
|
|
12567
|
+
return { pco, pcvZen1Deg: 0, pcvDzenDeg: 0, pcvNoazi };
|
|
12568
|
+
}
|
|
12569
|
+
function buildPppAntenna(antex) {
|
|
12570
|
+
const sats = /* @__PURE__ */ new Map();
|
|
12571
|
+
const rcvs = /* @__PURE__ */ new Map();
|
|
12572
|
+
for (const a of antex.antennas) {
|
|
12573
|
+
if (a.isSatellite) {
|
|
12574
|
+
const list = sats.get(a.serialNo) ?? [];
|
|
12575
|
+
list.push(a);
|
|
12576
|
+
sats.set(a.serialNo, list);
|
|
12577
|
+
} else if (!rcvs.has(a.type)) {
|
|
12578
|
+
rcvs.set(a.type, a);
|
|
12579
|
+
}
|
|
12580
|
+
}
|
|
12581
|
+
const withZen = (entry, off) => ({
|
|
12582
|
+
...off,
|
|
12583
|
+
pcvZen1Deg: entry.zen1,
|
|
12584
|
+
pcvDzenDeg: entry.dzen
|
|
12585
|
+
});
|
|
12586
|
+
return {
|
|
12587
|
+
satOffset(prn, dateMs, band1, band2, f1, f2) {
|
|
12588
|
+
const list = sats.get(prn);
|
|
12589
|
+
if (!list) return null;
|
|
12590
|
+
const entry = list.find((e) => {
|
|
12591
|
+
const from = parseAntexTime(e.validFrom);
|
|
12592
|
+
const until = parseAntexTime(e.validUntil);
|
|
12593
|
+
return (from == null || dateMs >= from) && (until == null || dateMs <= until);
|
|
12594
|
+
});
|
|
12595
|
+
if (!entry) return null;
|
|
12596
|
+
const a = freqOf(entry, band1);
|
|
12597
|
+
const b = freqOf(entry, band2);
|
|
12598
|
+
if (!a || !b) return null;
|
|
12599
|
+
return withZen(entry, combineIf(a, b, f1, f2));
|
|
12600
|
+
},
|
|
12601
|
+
rcvOffset(antType, band1, band2, f1, f2) {
|
|
12602
|
+
const entry = rcvs.get(antType);
|
|
12603
|
+
if (!entry) return null;
|
|
12604
|
+
const a = freqOf(entry, band1);
|
|
12605
|
+
const b = freqOf(entry, band2);
|
|
12606
|
+
if (!a || !b) return null;
|
|
12607
|
+
return withZen(entry, combineIf(a, b, f1, f2));
|
|
12608
|
+
}
|
|
12609
|
+
};
|
|
12610
|
+
}
|
|
12611
|
+
function cross(a, b) {
|
|
12612
|
+
return [
|
|
12613
|
+
a[1] * b[2] - a[2] * b[1],
|
|
12614
|
+
a[2] * b[0] - a[0] * b[2],
|
|
12615
|
+
a[0] * b[1] - a[1] * b[0]
|
|
12616
|
+
];
|
|
12617
|
+
}
|
|
12618
|
+
function norm(a) {
|
|
12619
|
+
const n = Math.hypot(a[0], a[1], a[2]) || 1;
|
|
12620
|
+
return [a[0] / n, a[1] / n, a[2] / n];
|
|
12621
|
+
}
|
|
12622
|
+
function dot(a, b) {
|
|
12623
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
12624
|
+
}
|
|
12625
|
+
function satBodyFrame(satEcef, sunEcef2) {
|
|
12626
|
+
const z = norm([-satEcef[0], -satEcef[1], -satEcef[2]]);
|
|
12627
|
+
const eSun = norm([
|
|
12628
|
+
sunEcef2[0] - satEcef[0],
|
|
12629
|
+
sunEcef2[1] - satEcef[1],
|
|
12630
|
+
sunEcef2[2] - satEcef[2]
|
|
12631
|
+
]);
|
|
12632
|
+
const y = norm(cross(z, eSun));
|
|
12633
|
+
const x = norm(cross(y, z));
|
|
12634
|
+
return { x, y, z };
|
|
12635
|
+
}
|
|
12636
|
+
function satPcoToEcef(pcoBody, frame) {
|
|
12637
|
+
return [
|
|
12638
|
+
pcoBody[0] * frame.x[0] + pcoBody[1] * frame.y[0] + pcoBody[2] * frame.z[0],
|
|
12639
|
+
pcoBody[0] * frame.x[1] + pcoBody[1] * frame.y[1] + pcoBody[2] * frame.z[1],
|
|
12640
|
+
pcoBody[0] * frame.x[2] + pcoBody[1] * frame.y[2] + pcoBody[2] * frame.z[2]
|
|
12641
|
+
];
|
|
12642
|
+
}
|
|
12643
|
+
function enuToEcef(enu, latRad, lonRad) {
|
|
12644
|
+
const sl = Math.sin(latRad);
|
|
12645
|
+
const cl = Math.cos(latRad);
|
|
12646
|
+
const so = Math.sin(lonRad);
|
|
12647
|
+
const co = Math.cos(lonRad);
|
|
12648
|
+
const [e, n, u] = enu;
|
|
12649
|
+
return [
|
|
12650
|
+
-so * e - sl * co * n + cl * co * u,
|
|
12651
|
+
co * e - sl * so * n + cl * so * u,
|
|
12652
|
+
cl * n + sl * u
|
|
12653
|
+
];
|
|
12654
|
+
}
|
|
12655
|
+
function interpPcv(off, angleDeg) {
|
|
12656
|
+
const { pcvZen1Deg, pcvDzenDeg, pcvNoazi } = off;
|
|
12657
|
+
if (pcvDzenDeg <= 0 || pcvNoazi.length < 2) return 0;
|
|
12658
|
+
const x = (angleDeg - pcvZen1Deg) / pcvDzenDeg;
|
|
12659
|
+
if (x <= 0) return pcvNoazi[0];
|
|
12660
|
+
if (x >= pcvNoazi.length - 1) return pcvNoazi[pcvNoazi.length - 1];
|
|
12661
|
+
const i = Math.floor(x);
|
|
12662
|
+
const t = x - i;
|
|
12663
|
+
return pcvNoazi[i] * (1 - t) + pcvNoazi[i + 1] * t;
|
|
12664
|
+
}
|
|
12665
|
+
function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
|
|
12666
|
+
const k = [
|
|
12667
|
+
-losRcvToSat[0],
|
|
12668
|
+
-losRcvToSat[1],
|
|
12669
|
+
-losRcvToSat[2]
|
|
12670
|
+
];
|
|
12671
|
+
const kx = satFrame.x;
|
|
12672
|
+
const ky = satFrame.y;
|
|
12673
|
+
const kdotx = dot(k, kx);
|
|
12674
|
+
const kcrossY = cross(k, ky);
|
|
12675
|
+
const dS = [
|
|
12676
|
+
kx[0] - k[0] * kdotx - kcrossY[0],
|
|
12677
|
+
kx[1] - k[1] * kdotx - kcrossY[1],
|
|
12678
|
+
kx[2] - k[2] * kdotx - kcrossY[2]
|
|
12679
|
+
];
|
|
12680
|
+
const north = enuToEcef([0, 1, 0], latRad, lonRad);
|
|
12681
|
+
const east = enuToEcef([1, 0, 0], latRad, lonRad);
|
|
12682
|
+
const kdotn = dot(k, north);
|
|
12683
|
+
const kcrossE = cross(k, east);
|
|
12684
|
+
const dR = [
|
|
12685
|
+
north[0] - k[0] * kdotn + kcrossE[0],
|
|
12686
|
+
north[1] - k[1] * kdotn + kcrossE[1],
|
|
12687
|
+
north[2] - k[2] * kdotn + kcrossE[2]
|
|
12688
|
+
];
|
|
12689
|
+
const nS = Math.hypot(dS[0], dS[1], dS[2]) || 1;
|
|
12690
|
+
const nR = Math.hypot(dR[0], dR[1], dR[2]) || 1;
|
|
12691
|
+
let cosPhi = dot(dS, dR) / (nS * nR);
|
|
12692
|
+
cosPhi = Math.max(-1, Math.min(1, cosPhi));
|
|
12693
|
+
const zeta = cross(dS, dR);
|
|
12694
|
+
const sign = dot(k, zeta) >= 0 ? 1 : -1;
|
|
12695
|
+
const dphi = sign * Math.acos(cosPhi) / (2 * Math.PI);
|
|
12696
|
+
const prev = state.get(prn);
|
|
12697
|
+
const wu = prev == null ? dphi : dphi + Math.round(prev - dphi);
|
|
12698
|
+
state.set(prn, wu);
|
|
12699
|
+
return wu;
|
|
12700
|
+
}
|
|
12701
|
+
|
|
12702
|
+
// src/positioning/ppp-corrections.ts
|
|
12703
|
+
function applyCorrections(corrections, geom, ctx) {
|
|
12704
|
+
if (corrections.evaluate) return corrections.evaluate(geom, ctx);
|
|
12705
|
+
return { rangeM: 0, phaseWindupM: 0 };
|
|
12706
|
+
}
|
|
12707
|
+
function createPppCorrections(cfg) {
|
|
12708
|
+
const useSat = cfg.satPco ?? false;
|
|
12709
|
+
const useRcv = cfg.rcvPco ?? true;
|
|
12710
|
+
const useTides = cfg.tides ?? true;
|
|
12711
|
+
const useWindup = cfg.windup ?? true;
|
|
12712
|
+
const antDelta = cfg.antDeltaEnu ?? [0, 0, 0];
|
|
12713
|
+
const windupState = /* @__PURE__ */ new Map();
|
|
12714
|
+
return {
|
|
12715
|
+
epochContext(timeMs, rcvEcef) {
|
|
12716
|
+
const sun = sunEcef(timeMs);
|
|
12717
|
+
const moon = moonEcef(timeMs);
|
|
12718
|
+
const tideDisp = useTides ? solidEarthTide(rcvEcef, sun, moon) : [0, 0, 0];
|
|
12719
|
+
return { timeMs, sun, moon, tideDisp };
|
|
12720
|
+
},
|
|
12721
|
+
evaluate(geom, ctx) {
|
|
12722
|
+
let rangeM = 0;
|
|
12723
|
+
let phaseWindupM = 0;
|
|
12724
|
+
const e = geom.los;
|
|
12725
|
+
const [latDeg, lonDeg] = ecefToGeodetic(
|
|
12726
|
+
geom.rcvEcef[0],
|
|
12727
|
+
geom.rcvEcef[1],
|
|
12728
|
+
geom.rcvEcef[2]
|
|
12729
|
+
);
|
|
12730
|
+
const latRad = latDeg * Math.PI / 180;
|
|
12731
|
+
const lonRad = lonDeg * Math.PI / 180;
|
|
12732
|
+
const frame = ctx ? satBodyFrame(geom.satEcef, ctx.sun) : null;
|
|
12733
|
+
if (useSat && frame && geom.band1 && geom.band2) {
|
|
12734
|
+
const off = cfg.antenna.satOffset(
|
|
12735
|
+
geom.prn,
|
|
12736
|
+
ctx.timeMs,
|
|
12737
|
+
geom.band1,
|
|
12738
|
+
geom.band2,
|
|
12739
|
+
geom.f1,
|
|
12740
|
+
geom.f2
|
|
12741
|
+
);
|
|
12742
|
+
if (off) {
|
|
12743
|
+
const pcoEcef = satPcoToEcef(off.pco, frame);
|
|
12744
|
+
rangeM += dot(e, pcoEcef);
|
|
12745
|
+
const satR = Math.hypot(
|
|
12746
|
+
geom.satEcef[0],
|
|
12747
|
+
geom.satEcef[1],
|
|
12748
|
+
geom.satEcef[2]
|
|
12749
|
+
);
|
|
12750
|
+
const cosNadir = (e[0] * geom.satEcef[0] + e[1] * geom.satEcef[1] + e[2] * geom.satEcef[2]) / satR;
|
|
12751
|
+
const nadirDeg = Math.acos(Math.max(-1, Math.min(1, cosNadir))) * 180 / Math.PI;
|
|
12752
|
+
rangeM += interpPcv(off, nadirDeg);
|
|
12753
|
+
}
|
|
12754
|
+
}
|
|
12755
|
+
if (useRcv && geom.band1 && geom.band2) {
|
|
12756
|
+
const off = cfg.antenna.rcvOffset(
|
|
12757
|
+
cfg.rcvAntType,
|
|
12758
|
+
geom.band1,
|
|
12759
|
+
geom.band2,
|
|
12760
|
+
geom.f1,
|
|
12761
|
+
geom.f2
|
|
12762
|
+
);
|
|
12763
|
+
if (off) {
|
|
12764
|
+
const total = [
|
|
12765
|
+
off.pco[0] + antDelta[0],
|
|
12766
|
+
off.pco[1] + antDelta[1],
|
|
12767
|
+
off.pco[2] + antDelta[2]
|
|
12768
|
+
];
|
|
12769
|
+
const ecef = enuToEcef(total, latRad, lonRad);
|
|
12770
|
+
rangeM -= dot(e, ecef);
|
|
12771
|
+
const zenithDeg = 90 - geom.elRad * 180 / Math.PI;
|
|
12772
|
+
rangeM += interpPcv(off, zenithDeg);
|
|
12773
|
+
}
|
|
12774
|
+
}
|
|
12775
|
+
if (useTides && ctx) {
|
|
12776
|
+
rangeM -= dot(e, ctx.tideDisp);
|
|
12777
|
+
}
|
|
12778
|
+
if (useWindup && frame) {
|
|
12779
|
+
const wu = phaseWindup(geom.prn, e, frame, latRad, lonRad, windupState);
|
|
12780
|
+
const lambdaIf = 299792458 / (geom.f1 + geom.f2);
|
|
12781
|
+
phaseWindupM = wu * lambdaIf;
|
|
12782
|
+
}
|
|
12783
|
+
return { rangeM, phaseWindupM };
|
|
12784
|
+
}
|
|
12785
|
+
};
|
|
12786
|
+
}
|
|
12787
|
+
|
|
12788
|
+
// src/positioning/ppp.ts
|
|
12789
|
+
function matVec(P, h) {
|
|
12790
|
+
const n = P.length;
|
|
12791
|
+
const out = new Array(n).fill(0);
|
|
12792
|
+
for (let i = 0; i < n; i++) {
|
|
12793
|
+
let s = 0;
|
|
12794
|
+
const Pi = P[i];
|
|
12795
|
+
for (let j = 0; j < n; j++) s += Pi[j] * h[j];
|
|
12796
|
+
out[i] = s;
|
|
12797
|
+
}
|
|
12798
|
+
return out;
|
|
12799
|
+
}
|
|
12800
|
+
function ekfUpdateScalar(x, P, h, innovation, r, rejectK = 0) {
|
|
12801
|
+
const n = x.length;
|
|
12802
|
+
const Ph = matVec(P, h);
|
|
12803
|
+
let hPh = 0;
|
|
12804
|
+
for (let i = 0; i < n; i++) hPh += h[i] * Ph[i];
|
|
12805
|
+
const s = hPh + r;
|
|
12806
|
+
if (s <= 0) return false;
|
|
12807
|
+
if (rejectK > 0 && innovation * innovation > rejectK * rejectK * s) {
|
|
12808
|
+
return false;
|
|
12809
|
+
}
|
|
12810
|
+
const K = Ph.map((v) => v / s);
|
|
12811
|
+
for (let i = 0; i < n; i++) x[i] += K[i] * innovation;
|
|
12812
|
+
for (let i = 0; i < n; i++) {
|
|
12813
|
+
for (let j = 0; j < n; j++) {
|
|
12814
|
+
P[i][j] -= K[i] * Ph[j];
|
|
12815
|
+
}
|
|
12816
|
+
}
|
|
12817
|
+
for (let i = 0; i < n; i++) {
|
|
12818
|
+
for (let j = i + 1; j < n; j++) {
|
|
12819
|
+
const m = 0.5 * (P[i][j] + P[j][i]);
|
|
12820
|
+
P[i][j] = m;
|
|
12821
|
+
P[j][i] = m;
|
|
12822
|
+
}
|
|
12823
|
+
}
|
|
12824
|
+
return true;
|
|
12825
|
+
}
|
|
12826
|
+
function ifCoeffs(f1, f2) {
|
|
12827
|
+
const g = f1 * f1 / (f1 * f1 - f2 * f2);
|
|
12828
|
+
const lambdaIf = C_LIGHT / (f1 + f2);
|
|
12829
|
+
return { g, lambdaIf };
|
|
12830
|
+
}
|
|
12831
|
+
function sagnacRotate(x, y, z, travelS) {
|
|
12832
|
+
const theta = OMEGA_E * travelS;
|
|
12833
|
+
const c = Math.cos(theta);
|
|
12834
|
+
const s = Math.sin(theta);
|
|
12835
|
+
return [x * c + y * s, -x * s + y * c, z];
|
|
12836
|
+
}
|
|
12837
|
+
function satStateAtEmission(sp3, prn, recvTimeMs, rcv) {
|
|
12838
|
+
let travelS = 0.075;
|
|
12839
|
+
let sx = 0;
|
|
12840
|
+
let sy = 0;
|
|
12841
|
+
let sz = 0;
|
|
12842
|
+
let clkS = null;
|
|
12843
|
+
let velDotPos = 0;
|
|
12844
|
+
for (let iter = 0; iter < 3; iter++) {
|
|
12845
|
+
const tEmit = recvTimeMs - travelS * 1e3;
|
|
12846
|
+
const p = sp3Position(sp3, prn, tEmit);
|
|
12847
|
+
if (!p || p.clk == null) return null;
|
|
12848
|
+
const pPlus = sp3Position(sp3, prn, tEmit + 500);
|
|
12849
|
+
const pMinus = sp3Position(sp3, prn, tEmit - 500);
|
|
12850
|
+
if (pPlus && pMinus) {
|
|
12851
|
+
const vx = (pPlus.x - pMinus.x) / 1;
|
|
12852
|
+
const vy = (pPlus.y - pMinus.y) / 1;
|
|
12853
|
+
const vz = (pPlus.z - pMinus.z) / 1;
|
|
12854
|
+
velDotPos = p.x * vx + p.y * vy + p.z * vz;
|
|
12855
|
+
}
|
|
12856
|
+
clkS = p.clk;
|
|
12857
|
+
const [rx, ry, rz] = sagnacRotate(p.x, p.y, p.z, travelS);
|
|
12858
|
+
sx = rx;
|
|
12859
|
+
sy = ry;
|
|
12860
|
+
sz = rz;
|
|
12861
|
+
const dx = sx - rcv[0];
|
|
12862
|
+
const dy = sy - rcv[1];
|
|
12863
|
+
const dz = sz - rcv[2];
|
|
12864
|
+
const range = Math.hypot(dx, dy, dz);
|
|
12865
|
+
travelS = range / C_LIGHT;
|
|
12866
|
+
}
|
|
12867
|
+
if (clkS == null) return null;
|
|
12868
|
+
const relS = -2 * velDotPos / (C_LIGHT * C_LIGHT);
|
|
12869
|
+
const clkM = C_LIGHT * (clkS + relS);
|
|
12870
|
+
return { state: { x: sx, y: sy, z: sz, clkM }, travelS };
|
|
12871
|
+
}
|
|
12872
|
+
var IDX_X = 0;
|
|
12873
|
+
var IDX_Y = 1;
|
|
12874
|
+
var IDX_Z = 2;
|
|
12875
|
+
var IDX_ZWD = 3;
|
|
12876
|
+
var NBASE = 4;
|
|
12877
|
+
var CLK_VAR = 1e10;
|
|
12878
|
+
function solvePpp(epochs, sp3, opts) {
|
|
12879
|
+
const elevMask = (opts.elevationMaskDeg ?? 10) * Math.PI / 180;
|
|
12880
|
+
const codeSigma = opts.codeSigma ?? 3;
|
|
12881
|
+
const phaseSigma = opts.phaseSigma ?? 0.01;
|
|
12882
|
+
const ztdQ = opts.ztdProcessNoise ?? 1e-8;
|
|
12883
|
+
const corrections = opts.corrections;
|
|
12884
|
+
const x = [
|
|
12885
|
+
opts.aprioriPos[0],
|
|
12886
|
+
opts.aprioriPos[1],
|
|
12887
|
+
opts.aprioriPos[2],
|
|
12888
|
+
0.1
|
|
12889
|
+
// zenith wet delay (m) a priori
|
|
12890
|
+
];
|
|
12891
|
+
const P = [];
|
|
12892
|
+
for (let i = 0; i < NBASE; i++) {
|
|
12893
|
+
P.push(new Array(NBASE).fill(0));
|
|
12894
|
+
}
|
|
12895
|
+
P[IDX_X][IDX_X] = 100 * 100;
|
|
12896
|
+
P[IDX_Y][IDX_Y] = 100 * 100;
|
|
12897
|
+
P[IDX_Z][IDX_Z] = 100 * 100;
|
|
12898
|
+
P[IDX_ZWD][IDX_ZWD] = 0.5 * 0.5;
|
|
12899
|
+
const clkIdx = /* @__PURE__ */ new Map();
|
|
12900
|
+
const clockSeeded = /* @__PURE__ */ new Set();
|
|
12901
|
+
const ambIdx = /* @__PURE__ */ new Map();
|
|
12902
|
+
const lastSeen = /* @__PURE__ */ new Map();
|
|
12903
|
+
const mwState = /* @__PURE__ */ new Map();
|
|
12904
|
+
const detectSlip = (o, ei) => {
|
|
12905
|
+
const lamW = C_LIGHT / (o.f1 - o.f2);
|
|
12906
|
+
const lw = o.l1 - o.l2;
|
|
12907
|
+
const pn = (o.f1 * o.c1 + o.f2 * o.c2) / (o.f1 + o.f2);
|
|
12908
|
+
const mw = lw - pn / lamW;
|
|
12909
|
+
const st = mwState.get(o.prn);
|
|
12910
|
+
let slip = o.slip;
|
|
12911
|
+
if (!st || ei - st.lastEi > 2)
|
|
12912
|
+
slip = true;
|
|
12913
|
+
else if (Math.abs(mw - st.mean) > 4) slip = true;
|
|
12914
|
+
if (slip) mwState.set(o.prn, { mean: mw, n: 1, lastEi: ei });
|
|
12915
|
+
else {
|
|
12916
|
+
const n = st.n + 1;
|
|
12917
|
+
mwState.set(o.prn, {
|
|
12918
|
+
mean: st.mean + (mw - st.mean) / Math.min(n, 100),
|
|
12919
|
+
n,
|
|
12920
|
+
lastEi: ei
|
|
12921
|
+
});
|
|
12922
|
+
}
|
|
12923
|
+
return slip;
|
|
12924
|
+
};
|
|
12925
|
+
const growState = (initVal, initVar) => {
|
|
12926
|
+
const idx = x.length;
|
|
12927
|
+
x.push(initVal);
|
|
12928
|
+
for (const row of P) row.push(0);
|
|
12929
|
+
P.push(new Array(x.length).fill(0));
|
|
12930
|
+
P[idx][idx] = initVar;
|
|
12931
|
+
return idx;
|
|
12932
|
+
};
|
|
12933
|
+
const dropState = (idx) => {
|
|
12934
|
+
x.splice(idx, 1);
|
|
12935
|
+
P.splice(idx, 1);
|
|
12936
|
+
for (const row of P) row.splice(idx, 1);
|
|
12937
|
+
for (const [prn, i] of ambIdx) {
|
|
12938
|
+
if (i === idx) ambIdx.delete(prn);
|
|
12939
|
+
else if (i > idx) ambIdx.set(prn, i - 1);
|
|
12940
|
+
}
|
|
12941
|
+
for (const [sys, i] of clkIdx) {
|
|
12942
|
+
if (i > idx) clkIdx.set(sys, i - 1);
|
|
12943
|
+
}
|
|
12944
|
+
};
|
|
12945
|
+
const clockOf = (sys) => {
|
|
12946
|
+
let i = clkIdx.get(sys);
|
|
12947
|
+
if (i === void 0) {
|
|
12948
|
+
i = growState(0, CLK_VAR);
|
|
12949
|
+
clkIdx.set(sys, i);
|
|
12950
|
+
}
|
|
12951
|
+
return i;
|
|
12952
|
+
};
|
|
12953
|
+
const series = [];
|
|
12954
|
+
const truth = opts.groundTruth;
|
|
12955
|
+
const t0 = epochs[0]?.timeMs ?? 0;
|
|
12956
|
+
let convergenceSec = null;
|
|
12957
|
+
let convergedStreak = 0;
|
|
12958
|
+
for (let ei = 0; ei < epochs.length; ei++) {
|
|
12959
|
+
const epoch = epochs[ei];
|
|
12960
|
+
for (const ci of clkIdx.values()) P[ci][ci] = CLK_VAR;
|
|
12961
|
+
P[IDX_ZWD][IDX_ZWD] += ztdQ * (ei > 0 ? 1 : 0);
|
|
12962
|
+
const rcv = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
|
|
12963
|
+
const [latDeg, , heightM] = ecefToGeodetic(rcv[0], rcv[1], rcv[2]);
|
|
12964
|
+
const latRad = latDeg * Math.PI / 180;
|
|
12965
|
+
const epochCtx = corrections?.epochContext?.(epoch.timeMs, rcv) ?? null;
|
|
12966
|
+
const vis = [];
|
|
12967
|
+
for (const o of epoch.obs) {
|
|
12968
|
+
if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
|
|
12969
|
+
const slip = detectSlip(o, ei);
|
|
12970
|
+
const sat = satStateAtEmission(sp3, o.prn, epoch.timeMs, rcv);
|
|
12971
|
+
if (!sat) continue;
|
|
12972
|
+
const [elRad, azRad] = getAer(
|
|
12973
|
+
sat.state.x,
|
|
12974
|
+
sat.state.y,
|
|
12975
|
+
sat.state.z,
|
|
12976
|
+
rcv[0],
|
|
12977
|
+
rcv[1],
|
|
12978
|
+
rcv[2]
|
|
12979
|
+
);
|
|
12980
|
+
if (elRad < elevMask) continue;
|
|
12981
|
+
const dx = sat.state.x - rcv[0];
|
|
12982
|
+
const dy = sat.state.y - rcv[1];
|
|
12983
|
+
const dz = sat.state.z - rcv[2];
|
|
12984
|
+
const range = Math.hypot(dx, dy, dz);
|
|
12985
|
+
const e = [dx / range, dy / range, dz / range];
|
|
12986
|
+
const { g } = ifCoeffs(o.f1, o.f2);
|
|
12987
|
+
const lam1 = C_LIGHT / o.f1;
|
|
12988
|
+
const lam2 = C_LIGHT / o.f2;
|
|
12989
|
+
if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
|
|
12990
|
+
const pIf = g * o.c1 - (g - 1) * o.c2;
|
|
12991
|
+
const lIf = g * (o.l1 * lam1) - (g - 1) * (o.l2 * lam2);
|
|
12992
|
+
if (!Number.isFinite(pIf) || !Number.isFinite(lIf)) continue;
|
|
12993
|
+
const trop = opts.troposphere ?? true ? niellMapping(elRad, latRad, heightM, epoch.timeMs) : { zhd: 0, mh: 0, mw: 0 };
|
|
12994
|
+
const { zhd, mh, mw } = trop;
|
|
12995
|
+
const geom = {
|
|
12996
|
+
prn: o.prn,
|
|
12997
|
+
satEcef: [sat.state.x, sat.state.y, sat.state.z],
|
|
12998
|
+
rcvEcef: rcv,
|
|
12999
|
+
los: e,
|
|
13000
|
+
elRad,
|
|
13001
|
+
azRad,
|
|
13002
|
+
f1: o.f1,
|
|
13003
|
+
f2: o.f2,
|
|
13004
|
+
band1: o.band1,
|
|
13005
|
+
band2: o.band2,
|
|
13006
|
+
g
|
|
13007
|
+
};
|
|
13008
|
+
const corr = corrections ? applyCorrections(corrections, geom, epochCtx) : { rangeM: 0, phaseWindupM: 0 };
|
|
13009
|
+
vis.push({
|
|
13010
|
+
prn: o.prn,
|
|
13011
|
+
e,
|
|
13012
|
+
elRad,
|
|
13013
|
+
pIf,
|
|
13014
|
+
lIf,
|
|
13015
|
+
satClkM: sat.state.clkM,
|
|
13016
|
+
range,
|
|
13017
|
+
tropoFixed: zhd * mh + corr.rangeM,
|
|
13018
|
+
mw,
|
|
13019
|
+
windupM: corr.phaseWindupM,
|
|
13020
|
+
slip
|
|
13021
|
+
});
|
|
13022
|
+
}
|
|
13023
|
+
const zwd0 = x[IDX_ZWD];
|
|
13024
|
+
const bySys = /* @__PURE__ */ new Map();
|
|
13025
|
+
for (const v of vis) {
|
|
13026
|
+
const sys = v.prn[0];
|
|
13027
|
+
const r = v.pIf - (v.range - v.satClkM + v.tropoFixed + zwd0 * v.mw);
|
|
13028
|
+
const arr = bySys.get(sys);
|
|
13029
|
+
if (arr) arr.push(r);
|
|
13030
|
+
else bySys.set(sys, [r]);
|
|
13031
|
+
}
|
|
13032
|
+
for (const [sys, res] of bySys) {
|
|
13033
|
+
const ci = clockOf(sys);
|
|
13034
|
+
if (!clockSeeded.has(sys)) {
|
|
13035
|
+
res.sort((a, b) => a - b);
|
|
13036
|
+
x[ci] = res[Math.floor(res.length / 2)];
|
|
13037
|
+
clockSeeded.add(sys);
|
|
13038
|
+
}
|
|
13039
|
+
P[ci][ci] = CLK_VAR;
|
|
13040
|
+
}
|
|
13041
|
+
let nSats = 0;
|
|
13042
|
+
let sumPhaseResSq = 0;
|
|
13043
|
+
let nPhaseRes = 0;
|
|
13044
|
+
for (const v of vis) {
|
|
13045
|
+
const ci = clockOf(v.prn[0]);
|
|
13046
|
+
const common = v.range + x[ci] - v.satClkM + v.tropoFixed + zwd0 * v.mw;
|
|
13047
|
+
let ai = ambIdx.get(v.prn);
|
|
13048
|
+
if (ai === void 0 || v.slip) {
|
|
13049
|
+
const bInit = v.lIf - (common + v.windupM);
|
|
13050
|
+
if (ai === void 0) {
|
|
13051
|
+
ai = growState(bInit, 100 * 100);
|
|
13052
|
+
} else {
|
|
13053
|
+
x[ai] = bInit;
|
|
13054
|
+
for (let j = 0; j < P.length; j++) {
|
|
13055
|
+
P[ai][j] = 0;
|
|
13056
|
+
P[j][ai] = 0;
|
|
13057
|
+
}
|
|
13058
|
+
P[ai][ai] = 100 * 100;
|
|
13059
|
+
}
|
|
13060
|
+
ambIdx.set(v.prn, ai);
|
|
13061
|
+
}
|
|
13062
|
+
const n = x.length;
|
|
13063
|
+
const sinEl = Math.max(Math.sin(v.elRad), 0.1);
|
|
13064
|
+
const rCode = (codeSigma / sinEl) ** 2;
|
|
13065
|
+
const rPhase = (phaseSigma / sinEl) ** 2;
|
|
13066
|
+
{
|
|
13067
|
+
const h = new Array(n).fill(0);
|
|
13068
|
+
h[IDX_X] = -v.e[0];
|
|
13069
|
+
h[IDX_Y] = -v.e[1];
|
|
13070
|
+
h[IDX_Z] = -v.e[2];
|
|
13071
|
+
h[ci] = 1;
|
|
13072
|
+
h[IDX_ZWD] = v.mw;
|
|
13073
|
+
const innov = v.pIf - common;
|
|
13074
|
+
if (Math.abs(innov) < 1e6) ekfUpdateScalar(x, P, h, innov, rCode, 4);
|
|
13075
|
+
}
|
|
13076
|
+
{
|
|
13077
|
+
const commonPh = v.range + x[ci] - v.satClkM + v.tropoFixed + x[IDX_ZWD] * v.mw;
|
|
13078
|
+
const innov = v.lIf - (commonPh + v.windupM + x[ai]);
|
|
13079
|
+
if (Math.abs(innov) > 0.15) {
|
|
13080
|
+
x[ai] = v.lIf - (commonPh + v.windupM);
|
|
13081
|
+
for (let j = 0; j < P.length; j++) {
|
|
13082
|
+
P[ai][j] = 0;
|
|
13083
|
+
P[j][ai] = 0;
|
|
13084
|
+
}
|
|
13085
|
+
P[ai][ai] = 100 * 100;
|
|
13086
|
+
} else {
|
|
13087
|
+
const h = new Array(n).fill(0);
|
|
13088
|
+
h[IDX_X] = -v.e[0];
|
|
13089
|
+
h[IDX_Y] = -v.e[1];
|
|
13090
|
+
h[IDX_Z] = -v.e[2];
|
|
13091
|
+
h[ci] = 1;
|
|
13092
|
+
h[IDX_ZWD] = v.mw;
|
|
13093
|
+
h[ai] = 1;
|
|
13094
|
+
if (ekfUpdateScalar(x, P, h, innov, rPhase, 4)) {
|
|
13095
|
+
sumPhaseResSq += innov * innov;
|
|
13096
|
+
nPhaseRes++;
|
|
13097
|
+
}
|
|
13098
|
+
}
|
|
13099
|
+
}
|
|
13100
|
+
lastSeen.set(v.prn, ei);
|
|
13101
|
+
nSats++;
|
|
13102
|
+
}
|
|
13103
|
+
for (const [prn, seen] of [...lastSeen]) {
|
|
13104
|
+
if (ei - seen > 20) {
|
|
13105
|
+
const idx = ambIdx.get(prn);
|
|
13106
|
+
if (idx !== void 0) dropState(idx);
|
|
13107
|
+
lastSeen.delete(prn);
|
|
13108
|
+
}
|
|
13109
|
+
}
|
|
13110
|
+
const pos = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
|
|
13111
|
+
let enu = null;
|
|
13112
|
+
let error3d = null;
|
|
13113
|
+
if (truth) {
|
|
13114
|
+
enu = getEnuDifference(
|
|
13115
|
+
pos[0],
|
|
13116
|
+
pos[1],
|
|
13117
|
+
pos[2],
|
|
13118
|
+
truth[0],
|
|
13119
|
+
truth[1],
|
|
13120
|
+
truth[2]
|
|
13121
|
+
);
|
|
13122
|
+
error3d = Math.hypot(
|
|
13123
|
+
pos[0] - truth[0],
|
|
13124
|
+
pos[1] - truth[1],
|
|
13125
|
+
pos[2] - truth[2]
|
|
13126
|
+
);
|
|
13127
|
+
if (error3d < 0.1) {
|
|
13128
|
+
convergedStreak++;
|
|
13129
|
+
if (convergedStreak >= 10 && convergenceSec == null) {
|
|
13130
|
+
convergenceSec = (epoch.timeMs - t0) / 1e3;
|
|
13131
|
+
}
|
|
13132
|
+
} else {
|
|
13133
|
+
convergedStreak = 0;
|
|
13134
|
+
convergenceSec = null;
|
|
13135
|
+
}
|
|
13136
|
+
}
|
|
13137
|
+
series.push({
|
|
13138
|
+
timeMs: epoch.timeMs,
|
|
13139
|
+
enu,
|
|
13140
|
+
error3d,
|
|
13141
|
+
position: pos,
|
|
13142
|
+
nSats,
|
|
13143
|
+
ztdWet: x[IDX_ZWD],
|
|
13144
|
+
phaseResRms: nPhaseRes > 0 ? Math.sqrt(sumPhaseResSq / nPhaseRes) : 0
|
|
13145
|
+
});
|
|
13146
|
+
}
|
|
13147
|
+
const finalPos = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
|
|
13148
|
+
const llh = ecefToGeodetic(finalPos[0], finalPos[1], finalPos[2]);
|
|
13149
|
+
const finalError3d = truth ? Math.hypot(
|
|
13150
|
+
finalPos[0] - truth[0],
|
|
13151
|
+
finalPos[1] - truth[1],
|
|
13152
|
+
finalPos[2] - truth[2]
|
|
13153
|
+
) : null;
|
|
13154
|
+
return {
|
|
13155
|
+
position: finalPos,
|
|
13156
|
+
llh,
|
|
13157
|
+
series,
|
|
13158
|
+
ztdWet: x[IDX_ZWD],
|
|
13159
|
+
epochsUsed: epochs.length,
|
|
13160
|
+
convergenceSec,
|
|
13161
|
+
finalError3d
|
|
13162
|
+
};
|
|
13163
|
+
}
|
|
13164
|
+
|
|
12346
13165
|
// src/positioning/index.ts
|
|
12347
13166
|
var GM_GPS3 = 3986005e8;
|
|
12348
13167
|
var F_REL = -4442807633e-19;
|
|
@@ -12483,7 +13302,8 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
12483
13302
|
let ionoM = 0;
|
|
12484
13303
|
if ((gim || iono) && positionSane) {
|
|
12485
13304
|
let l1M = null;
|
|
12486
|
-
if (gim)
|
|
13305
|
+
if (gim)
|
|
13306
|
+
l1M = gimSlantIonoDelayL1(gim, rxLat, rxLon, azim, elev, timeMs);
|
|
12487
13307
|
if (l1M === null && iono) {
|
|
12488
13308
|
l1M = C_LIGHT * klobucharDelay(iono, rxLat, rxLon, azim, elev, gpsTow);
|
|
12489
13309
|
}
|
|
@@ -14927,6 +15747,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
14927
15747
|
binexRecords,
|
|
14928
15748
|
buildGloChannelMap,
|
|
14929
15749
|
buildObsIndices,
|
|
15750
|
+
buildPppAntenna,
|
|
14930
15751
|
clampUnit,
|
|
14931
15752
|
computeAllPositions,
|
|
14932
15753
|
computeDop,
|
|
@@ -14940,6 +15761,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
14940
15761
|
connectToMountpoint,
|
|
14941
15762
|
crc32,
|
|
14942
15763
|
createGzipLineSink,
|
|
15764
|
+
createPppCorrections,
|
|
14943
15765
|
createStationMeta,
|
|
14944
15766
|
createStreamStats,
|
|
14945
15767
|
crxDecompress,
|
|
@@ -15025,6 +15847,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
15025
15847
|
glonassAlmanacEpochMs,
|
|
15026
15848
|
glonassAlmanacPosition,
|
|
15027
15849
|
glonassPosition,
|
|
15850
|
+
gmst,
|
|
15028
15851
|
greatCircleMidpoint,
|
|
15029
15852
|
hdrLine,
|
|
15030
15853
|
horizonDistance,
|
|
@@ -15034,8 +15857,10 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
15034
15857
|
lambdaReduction,
|
|
15035
15858
|
lambdaSearch,
|
|
15036
15859
|
maskRadForAzimuth,
|
|
15860
|
+
moonEcef,
|
|
15037
15861
|
msmEpochToDate,
|
|
15038
15862
|
navTimesFromEph,
|
|
15863
|
+
niellMapping,
|
|
15039
15864
|
nmeaCoordToDecimal,
|
|
15040
15865
|
oem4Frames,
|
|
15041
15866
|
padL,
|
|
@@ -15085,10 +15910,13 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
15085
15910
|
selectEphemeris,
|
|
15086
15911
|
setGloFreqNumber,
|
|
15087
15912
|
setRtcm3DebugHandler,
|
|
15913
|
+
solidEarthTide,
|
|
15088
15914
|
solveDgnss,
|
|
15915
|
+
solvePpp,
|
|
15089
15916
|
solveSpp,
|
|
15090
15917
|
sp3Position,
|
|
15091
15918
|
stationHeaderLines,
|
|
15919
|
+
sunEcef,
|
|
15092
15920
|
systemCmp,
|
|
15093
15921
|
systemName,
|
|
15094
15922
|
toRtkEpoch,
|