gnss-js 2.7.0 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-BWLLHLLS.js → chunk-F6KOFOXN.js} +3 -24
- package/dist/{chunk-JYWYQ7DW.js → chunk-T5M3LVBJ.js} +55 -46
- package/dist/index.cjs +56 -70
- package/dist/index.js +2 -2
- package/dist/orbit.cjs +54 -46
- package/dist/orbit.d.cts +24 -6
- package/dist/orbit.d.ts +24 -6
- package/dist/orbit.js +1 -1
- package/dist/positioning.cjs +52 -69
- package/dist/positioning.js +2 -2
- package/package.json +1 -1
|
@@ -5,8 +5,9 @@ import {
|
|
|
5
5
|
computeDop,
|
|
6
6
|
computeSatPosition,
|
|
7
7
|
ecefToAzEl,
|
|
8
|
+
invertMatrix,
|
|
8
9
|
selectEphemeris
|
|
9
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-T5M3LVBJ.js";
|
|
10
11
|
import {
|
|
11
12
|
ecefToGeodetic,
|
|
12
13
|
getAer,
|
|
@@ -3730,28 +3731,6 @@ function sbasAirTropoVar(elRad) {
|
|
|
3730
3731
|
const sigTropo = 0.12 * m;
|
|
3731
3732
|
return sigMp * sigMp + NOISE_DIVG_AADA * NOISE_DIVG_AADA + sigTropo * sigTropo;
|
|
3732
3733
|
}
|
|
3733
|
-
function invertMatrix(A) {
|
|
3734
|
-
const n = A.length;
|
|
3735
|
-
const M = A.map((row, i) => [
|
|
3736
|
-
...row,
|
|
3737
|
-
...Array.from({ length: n }, (_, j) => i === j ? 1 : 0)
|
|
3738
|
-
]);
|
|
3739
|
-
for (let col = 0; col < n; col++) {
|
|
3740
|
-
let piv = col;
|
|
3741
|
-
for (let r = col + 1; r < n; r++)
|
|
3742
|
-
if (Math.abs(M[r][col]) > Math.abs(M[piv][col])) piv = r;
|
|
3743
|
-
if (Math.abs(M[piv][col]) < 1e-12) return null;
|
|
3744
|
-
[M[col], M[piv]] = [M[piv], M[col]];
|
|
3745
|
-
const d = M[col][col];
|
|
3746
|
-
for (let j = 0; j < 2 * n; j++) M[col][j] /= d;
|
|
3747
|
-
for (let r = 0; r < n; r++) {
|
|
3748
|
-
if (r === col) continue;
|
|
3749
|
-
const f = M[r][col];
|
|
3750
|
-
for (let j = 0; j < 2 * n; j++) M[r][j] -= f * M[col][j];
|
|
3751
|
-
}
|
|
3752
|
-
}
|
|
3753
|
-
return M.map((row) => row.slice(n));
|
|
3754
|
-
}
|
|
3755
3734
|
function sbasProtectionLevels(sats, opts = {}) {
|
|
3756
3735
|
const kH = opts.kH ?? 6;
|
|
3757
3736
|
const kV = opts.kV ?? 5.33;
|
|
@@ -3978,7 +3957,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
3978
3957
|
const azel = ecefToAzEl(x, y, z, sat.x, sat.y, sat.z);
|
|
3979
3958
|
if (azel.el >= elevationMaskDeg * Math.PI / 180) {
|
|
3980
3959
|
used.push(prn);
|
|
3981
|
-
azels.push(azel);
|
|
3960
|
+
azels.push({ ...azel, prn });
|
|
3982
3961
|
if (sbas) {
|
|
3983
3962
|
const dx = sat.x - x, dy = sat.y - y, dz = sat.z - z;
|
|
3984
3963
|
const dr = Math.hypot(dx, dy, dz) || 1;
|
|
@@ -13,6 +13,30 @@ import {
|
|
|
13
13
|
OMEGA_E
|
|
14
14
|
} from "./chunk-FIEWO4J4.js";
|
|
15
15
|
|
|
16
|
+
// src/orbit/matrix.ts
|
|
17
|
+
function invertMatrix(A) {
|
|
18
|
+
const n = A.length;
|
|
19
|
+
const M = A.map((row, i) => [
|
|
20
|
+
...row,
|
|
21
|
+
...Array.from({ length: n }, (_, j) => i === j ? 1 : 0)
|
|
22
|
+
]);
|
|
23
|
+
for (let col = 0; col < n; col++) {
|
|
24
|
+
let piv = col;
|
|
25
|
+
for (let r = col + 1; r < n; r++)
|
|
26
|
+
if (Math.abs(M[r][col]) > Math.abs(M[piv][col])) piv = r;
|
|
27
|
+
if (Math.abs(M[piv][col]) < 1e-12) return null;
|
|
28
|
+
[M[col], M[piv]] = [M[piv], M[col]];
|
|
29
|
+
const d = M[col][col];
|
|
30
|
+
for (let j = 0; j < 2 * n; j++) M[col][j] /= d;
|
|
31
|
+
for (let r = 0; r < n; r++) {
|
|
32
|
+
if (r === col) continue;
|
|
33
|
+
const f = M[r][col];
|
|
34
|
+
for (let j = 0; j < 2 * n; j++) M[r][j] -= f * M[col][j];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return M.map((row) => row.slice(n));
|
|
38
|
+
}
|
|
39
|
+
|
|
16
40
|
// src/orbit/almanac.ts
|
|
17
41
|
var GM_GPS = 3986005e8;
|
|
18
42
|
var GM_GAL = 3986004418e5;
|
|
@@ -380,17 +404,26 @@ function ecefToAzEl(rxX, rxY, rxZ, satX, satY, satZ) {
|
|
|
380
404
|
const el = Math.atan2(up, Math.sqrt(east * east + north * north));
|
|
381
405
|
return { az: (az + TWO_PI) % TWO_PI, el };
|
|
382
406
|
}
|
|
407
|
+
function dopClock(prn) {
|
|
408
|
+
const sys = prn?.[0] ?? "";
|
|
409
|
+
return sys === "J" || sys === "S" ? "G" : sys;
|
|
410
|
+
}
|
|
383
411
|
function computeDop(satAzEls) {
|
|
384
412
|
const n = satAzEls.length;
|
|
385
|
-
|
|
413
|
+
const clocks = [...new Set(satAzEls.map((s) => dopClock(s.prn)))];
|
|
414
|
+
const m = 3 + clocks.length;
|
|
415
|
+
if (n < Math.max(4, m)) return null;
|
|
386
416
|
const H = [];
|
|
387
|
-
for (const { az, el } of satAzEls) {
|
|
417
|
+
for (const { az, el, prn } of satAzEls) {
|
|
388
418
|
const cosEl = Math.cos(el);
|
|
389
|
-
|
|
419
|
+
const row = [cosEl * Math.sin(az), cosEl * Math.cos(az), Math.sin(el)];
|
|
420
|
+
const clock = dopClock(prn);
|
|
421
|
+
for (const c of clocks) row.push(c === clock ? 1 : 0);
|
|
422
|
+
H.push(row);
|
|
390
423
|
}
|
|
391
|
-
const HtH = Array.from({ length:
|
|
392
|
-
for (let i = 0; i <
|
|
393
|
-
for (let j = 0; j <
|
|
424
|
+
const HtH = Array.from({ length: m }, () => new Array(m).fill(0));
|
|
425
|
+
for (let i = 0; i < m; i++) {
|
|
426
|
+
for (let j = 0; j < m; j++) {
|
|
394
427
|
let sum = 0;
|
|
395
428
|
for (let k = 0; k < n; k++) {
|
|
396
429
|
sum += H[k][i] * H[k][j];
|
|
@@ -398,46 +431,18 @@ function computeDop(satAzEls) {
|
|
|
398
431
|
HtH[i][j] = sum;
|
|
399
432
|
}
|
|
400
433
|
}
|
|
401
|
-
const Q =
|
|
434
|
+
const Q = invertMatrix(HtH);
|
|
402
435
|
if (!Q) return null;
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
inv[4] = -a[4] * a[10] * a[15] + a[4] * a[11] * a[14] + a[8] * a[6] * a[15] - a[8] * a[7] * a[14] - a[12] * a[6] * a[11] + a[12] * a[7] * a[10];
|
|
414
|
-
inv[8] = a[4] * a[9] * a[15] - a[4] * a[11] * a[13] - a[8] * a[5] * a[15] + a[8] * a[7] * a[13] + a[12] * a[5] * a[11] - a[12] * a[7] * a[9];
|
|
415
|
-
inv[12] = -a[4] * a[9] * a[14] + a[4] * a[10] * a[13] + a[8] * a[5] * a[14] - a[8] * a[6] * a[13] - a[12] * a[5] * a[10] + a[12] * a[6] * a[9];
|
|
416
|
-
inv[1] = -a[1] * a[10] * a[15] + a[1] * a[11] * a[14] + a[9] * a[2] * a[15] - a[9] * a[3] * a[14] - a[13] * a[2] * a[11] + a[13] * a[3] * a[10];
|
|
417
|
-
inv[5] = a[0] * a[10] * a[15] - a[0] * a[11] * a[14] - a[8] * a[2] * a[15] + a[8] * a[3] * a[14] + a[12] * a[2] * a[11] - a[12] * a[3] * a[10];
|
|
418
|
-
inv[9] = -a[0] * a[9] * a[15] + a[0] * a[11] * a[13] + a[8] * a[1] * a[15] - a[8] * a[3] * a[13] - a[12] * a[1] * a[11] + a[12] * a[3] * a[9];
|
|
419
|
-
inv[13] = a[0] * a[9] * a[14] - a[0] * a[10] * a[13] - a[8] * a[1] * a[14] + a[8] * a[2] * a[13] + a[12] * a[1] * a[10] - a[12] * a[2] * a[9];
|
|
420
|
-
inv[2] = a[1] * a[6] * a[15] - a[1] * a[7] * a[14] - a[5] * a[2] * a[15] + a[5] * a[3] * a[14] + a[13] * a[2] * a[7] - a[13] * a[3] * a[6];
|
|
421
|
-
inv[6] = -a[0] * a[6] * a[15] + a[0] * a[7] * a[14] + a[4] * a[2] * a[15] - a[4] * a[3] * a[14] - a[12] * a[2] * a[7] + a[12] * a[3] * a[6];
|
|
422
|
-
inv[10] = a[0] * a[5] * a[15] - a[0] * a[7] * a[13] - a[4] * a[1] * a[15] + a[4] * a[3] * a[13] + a[12] * a[1] * a[7] - a[12] * a[3] * a[5];
|
|
423
|
-
inv[14] = -a[0] * a[5] * a[14] + a[0] * a[6] * a[13] + a[4] * a[1] * a[14] - a[4] * a[2] * a[13] - a[12] * a[1] * a[6] + a[12] * a[2] * a[5];
|
|
424
|
-
inv[3] = -a[1] * a[6] * a[11] + a[1] * a[7] * a[10] + a[5] * a[2] * a[11] - a[5] * a[3] * a[10] - a[9] * a[2] * a[7] + a[9] * a[3] * a[6];
|
|
425
|
-
inv[7] = a[0] * a[6] * a[11] - a[0] * a[7] * a[10] - a[4] * a[2] * a[11] + a[4] * a[3] * a[10] + a[8] * a[2] * a[7] - a[8] * a[3] * a[6];
|
|
426
|
-
inv[11] = -a[0] * a[5] * a[11] + a[0] * a[7] * a[9] + a[4] * a[1] * a[11] - a[4] * a[3] * a[9] - a[8] * a[1] * a[7] + a[8] * a[3] * a[5];
|
|
427
|
-
inv[15] = a[0] * a[5] * a[10] - a[0] * a[6] * a[9] - a[4] * a[1] * a[10] + a[4] * a[2] * a[9] + a[8] * a[1] * a[6] - a[8] * a[2] * a[5];
|
|
428
|
-
let det = a[0] * inv[0] + a[1] * inv[4] + a[2] * inv[8] + a[3] * inv[12];
|
|
429
|
-
if (Math.abs(det) < 1e-20) return null;
|
|
430
|
-
det = 1 / det;
|
|
431
|
-
const result = Array.from(
|
|
432
|
-
{ length: 4 },
|
|
433
|
-
() => new Array(4).fill(0)
|
|
434
|
-
);
|
|
435
|
-
for (let i = 0; i < 4; i++) {
|
|
436
|
-
for (let j = 0; j < 4; j++) {
|
|
437
|
-
result[i][j] = inv[i * 4 + j] * det;
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
return result;
|
|
436
|
+
let clockVar = 0;
|
|
437
|
+
for (let i = 3; i < m; i++) clockVar += Q[i][i];
|
|
438
|
+
const posVar = Q[0][0] + Q[1][1] + Q[2][2];
|
|
439
|
+
return {
|
|
440
|
+
gdop: Math.sqrt(posVar + clockVar),
|
|
441
|
+
pdop: Math.sqrt(posVar),
|
|
442
|
+
hdop: Math.sqrt(Q[0][0] + Q[1][1]),
|
|
443
|
+
vdop: Math.sqrt(Q[2][2]),
|
|
444
|
+
tdop: Math.sqrt(clockVar)
|
|
445
|
+
};
|
|
441
446
|
}
|
|
442
447
|
function selectEphemeris(ephemerides, prn, timeMs) {
|
|
443
448
|
return selectBest(
|
|
@@ -697,6 +702,7 @@ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
|
|
|
697
702
|
const gdop = new Array(times.length).fill(null);
|
|
698
703
|
const hdop = new Array(times.length).fill(null);
|
|
699
704
|
const vdop = new Array(times.length).fill(null);
|
|
705
|
+
const tdop = new Array(times.length).fill(null);
|
|
700
706
|
const visiblePerEpoch = times.map(() => []);
|
|
701
707
|
for (const prn of all.prns) {
|
|
702
708
|
const series = all.positions[prn];
|
|
@@ -710,7 +716,7 @@ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
|
|
|
710
716
|
visibleCount[i]++;
|
|
711
717
|
const sys = prn[0];
|
|
712
718
|
(visibleBySystem[sys] ??= new Array(times.length).fill(0))[i]++;
|
|
713
|
-
visiblePerEpoch[i].push({ az: p.az, el: p.el });
|
|
719
|
+
visiblePerEpoch[i].push({ az: p.az, el: p.el, prn });
|
|
714
720
|
}
|
|
715
721
|
}
|
|
716
722
|
}
|
|
@@ -720,6 +726,7 @@ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
|
|
|
720
726
|
gdop[i] = dop ? dop.gdop : null;
|
|
721
727
|
hdop[i] = dop ? dop.hdop : null;
|
|
722
728
|
vdop[i] = dop ? dop.vdop : null;
|
|
729
|
+
tdop[i] = dop ? dop.tdop : null;
|
|
723
730
|
}
|
|
724
731
|
const passes = [];
|
|
725
732
|
for (const prn of all.prns) {
|
|
@@ -766,11 +773,13 @@ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
|
|
|
766
773
|
gdop,
|
|
767
774
|
hdop,
|
|
768
775
|
vdop,
|
|
776
|
+
tdop,
|
|
769
777
|
passes
|
|
770
778
|
};
|
|
771
779
|
}
|
|
772
780
|
|
|
773
781
|
export {
|
|
782
|
+
invertMatrix,
|
|
774
783
|
almanacEpochMs,
|
|
775
784
|
almanacSatPosition,
|
|
776
785
|
glonassAlmanacEpochMs,
|
package/dist/index.cjs
CHANGED
|
@@ -12288,6 +12288,30 @@ function parseBinex(data) {
|
|
|
12288
12288
|
return { epochs, ephemerides, messageCounts, obsCodes, badCrc: stats.badCrc };
|
|
12289
12289
|
}
|
|
12290
12290
|
|
|
12291
|
+
// src/orbit/matrix.ts
|
|
12292
|
+
function invertMatrix(A) {
|
|
12293
|
+
const n = A.length;
|
|
12294
|
+
const M = A.map((row, i) => [
|
|
12295
|
+
...row,
|
|
12296
|
+
...Array.from({ length: n }, (_, j) => i === j ? 1 : 0)
|
|
12297
|
+
]);
|
|
12298
|
+
for (let col = 0; col < n; col++) {
|
|
12299
|
+
let piv = col;
|
|
12300
|
+
for (let r = col + 1; r < n; r++)
|
|
12301
|
+
if (Math.abs(M[r][col]) > Math.abs(M[piv][col])) piv = r;
|
|
12302
|
+
if (Math.abs(M[piv][col]) < 1e-12) return null;
|
|
12303
|
+
[M[col], M[piv]] = [M[piv], M[col]];
|
|
12304
|
+
const d = M[col][col];
|
|
12305
|
+
for (let j = 0; j < 2 * n; j++) M[col][j] /= d;
|
|
12306
|
+
for (let r = 0; r < n; r++) {
|
|
12307
|
+
if (r === col) continue;
|
|
12308
|
+
const f = M[r][col];
|
|
12309
|
+
for (let j = 0; j < 2 * n; j++) M[r][j] -= f * M[col][j];
|
|
12310
|
+
}
|
|
12311
|
+
}
|
|
12312
|
+
return M.map((row) => row.slice(n));
|
|
12313
|
+
}
|
|
12314
|
+
|
|
12291
12315
|
// src/orbit/almanac.ts
|
|
12292
12316
|
var GM_GPS = 3986005e8;
|
|
12293
12317
|
var GM_GAL = 3986004418e5;
|
|
@@ -12655,17 +12679,26 @@ function ecefToAzEl(rxX, rxY, rxZ, satX, satY, satZ) {
|
|
|
12655
12679
|
const el = Math.atan2(up, Math.sqrt(east * east + north * north));
|
|
12656
12680
|
return { az: (az + TWO_PI) % TWO_PI, el };
|
|
12657
12681
|
}
|
|
12682
|
+
function dopClock(prn) {
|
|
12683
|
+
const sys = prn?.[0] ?? "";
|
|
12684
|
+
return sys === "J" || sys === "S" ? "G" : sys;
|
|
12685
|
+
}
|
|
12658
12686
|
function computeDop(satAzEls) {
|
|
12659
12687
|
const n = satAzEls.length;
|
|
12660
|
-
|
|
12688
|
+
const clocks = [...new Set(satAzEls.map((s) => dopClock(s.prn)))];
|
|
12689
|
+
const m = 3 + clocks.length;
|
|
12690
|
+
if (n < Math.max(4, m)) return null;
|
|
12661
12691
|
const H3 = [];
|
|
12662
|
-
for (const { az, el } of satAzEls) {
|
|
12692
|
+
for (const { az, el, prn } of satAzEls) {
|
|
12663
12693
|
const cosEl = Math.cos(el);
|
|
12664
|
-
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12694
|
+
const row = [cosEl * Math.sin(az), cosEl * Math.cos(az), Math.sin(el)];
|
|
12695
|
+
const clock = dopClock(prn);
|
|
12696
|
+
for (const c of clocks) row.push(c === clock ? 1 : 0);
|
|
12697
|
+
H3.push(row);
|
|
12698
|
+
}
|
|
12699
|
+
const HtH = Array.from({ length: m }, () => new Array(m).fill(0));
|
|
12700
|
+
for (let i = 0; i < m; i++) {
|
|
12701
|
+
for (let j = 0; j < m; j++) {
|
|
12669
12702
|
let sum = 0;
|
|
12670
12703
|
for (let k = 0; k < n; k++) {
|
|
12671
12704
|
sum += H3[k][i] * H3[k][j];
|
|
@@ -12673,46 +12706,18 @@ function computeDop(satAzEls) {
|
|
|
12673
12706
|
HtH[i][j] = sum;
|
|
12674
12707
|
}
|
|
12675
12708
|
}
|
|
12676
|
-
const Q =
|
|
12709
|
+
const Q = invertMatrix(HtH);
|
|
12677
12710
|
if (!Q) return null;
|
|
12678
|
-
|
|
12679
|
-
|
|
12680
|
-
const
|
|
12681
|
-
|
|
12682
|
-
|
|
12683
|
-
|
|
12684
|
-
|
|
12685
|
-
|
|
12686
|
-
|
|
12687
|
-
|
|
12688
|
-
inv[4] = -a[4] * a[10] * a[15] + a[4] * a[11] * a[14] + a[8] * a[6] * a[15] - a[8] * a[7] * a[14] - a[12] * a[6] * a[11] + a[12] * a[7] * a[10];
|
|
12689
|
-
inv[8] = a[4] * a[9] * a[15] - a[4] * a[11] * a[13] - a[8] * a[5] * a[15] + a[8] * a[7] * a[13] + a[12] * a[5] * a[11] - a[12] * a[7] * a[9];
|
|
12690
|
-
inv[12] = -a[4] * a[9] * a[14] + a[4] * a[10] * a[13] + a[8] * a[5] * a[14] - a[8] * a[6] * a[13] - a[12] * a[5] * a[10] + a[12] * a[6] * a[9];
|
|
12691
|
-
inv[1] = -a[1] * a[10] * a[15] + a[1] * a[11] * a[14] + a[9] * a[2] * a[15] - a[9] * a[3] * a[14] - a[13] * a[2] * a[11] + a[13] * a[3] * a[10];
|
|
12692
|
-
inv[5] = a[0] * a[10] * a[15] - a[0] * a[11] * a[14] - a[8] * a[2] * a[15] + a[8] * a[3] * a[14] + a[12] * a[2] * a[11] - a[12] * a[3] * a[10];
|
|
12693
|
-
inv[9] = -a[0] * a[9] * a[15] + a[0] * a[11] * a[13] + a[8] * a[1] * a[15] - a[8] * a[3] * a[13] - a[12] * a[1] * a[11] + a[12] * a[3] * a[9];
|
|
12694
|
-
inv[13] = a[0] * a[9] * a[14] - a[0] * a[10] * a[13] - a[8] * a[1] * a[14] + a[8] * a[2] * a[13] + a[12] * a[1] * a[10] - a[12] * a[2] * a[9];
|
|
12695
|
-
inv[2] = a[1] * a[6] * a[15] - a[1] * a[7] * a[14] - a[5] * a[2] * a[15] + a[5] * a[3] * a[14] + a[13] * a[2] * a[7] - a[13] * a[3] * a[6];
|
|
12696
|
-
inv[6] = -a[0] * a[6] * a[15] + a[0] * a[7] * a[14] + a[4] * a[2] * a[15] - a[4] * a[3] * a[14] - a[12] * a[2] * a[7] + a[12] * a[3] * a[6];
|
|
12697
|
-
inv[10] = a[0] * a[5] * a[15] - a[0] * a[7] * a[13] - a[4] * a[1] * a[15] + a[4] * a[3] * a[13] + a[12] * a[1] * a[7] - a[12] * a[3] * a[5];
|
|
12698
|
-
inv[14] = -a[0] * a[5] * a[14] + a[0] * a[6] * a[13] + a[4] * a[1] * a[14] - a[4] * a[2] * a[13] - a[12] * a[1] * a[6] + a[12] * a[2] * a[5];
|
|
12699
|
-
inv[3] = -a[1] * a[6] * a[11] + a[1] * a[7] * a[10] + a[5] * a[2] * a[11] - a[5] * a[3] * a[10] - a[9] * a[2] * a[7] + a[9] * a[3] * a[6];
|
|
12700
|
-
inv[7] = a[0] * a[6] * a[11] - a[0] * a[7] * a[10] - a[4] * a[2] * a[11] + a[4] * a[3] * a[10] + a[8] * a[2] * a[7] - a[8] * a[3] * a[6];
|
|
12701
|
-
inv[11] = -a[0] * a[5] * a[11] + a[0] * a[7] * a[9] + a[4] * a[1] * a[11] - a[4] * a[3] * a[9] - a[8] * a[1] * a[7] + a[8] * a[3] * a[5];
|
|
12702
|
-
inv[15] = a[0] * a[5] * a[10] - a[0] * a[6] * a[9] - a[4] * a[1] * a[10] + a[4] * a[2] * a[9] + a[8] * a[1] * a[6] - a[8] * a[2] * a[5];
|
|
12703
|
-
let det = a[0] * inv[0] + a[1] * inv[4] + a[2] * inv[8] + a[3] * inv[12];
|
|
12704
|
-
if (Math.abs(det) < 1e-20) return null;
|
|
12705
|
-
det = 1 / det;
|
|
12706
|
-
const result = Array.from(
|
|
12707
|
-
{ length: 4 },
|
|
12708
|
-
() => new Array(4).fill(0)
|
|
12709
|
-
);
|
|
12710
|
-
for (let i = 0; i < 4; i++) {
|
|
12711
|
-
for (let j = 0; j < 4; j++) {
|
|
12712
|
-
result[i][j] = inv[i * 4 + j] * det;
|
|
12713
|
-
}
|
|
12714
|
-
}
|
|
12715
|
-
return result;
|
|
12711
|
+
let clockVar = 0;
|
|
12712
|
+
for (let i = 3; i < m; i++) clockVar += Q[i][i];
|
|
12713
|
+
const posVar = Q[0][0] + Q[1][1] + Q[2][2];
|
|
12714
|
+
return {
|
|
12715
|
+
gdop: Math.sqrt(posVar + clockVar),
|
|
12716
|
+
pdop: Math.sqrt(posVar),
|
|
12717
|
+
hdop: Math.sqrt(Q[0][0] + Q[1][1]),
|
|
12718
|
+
vdop: Math.sqrt(Q[2][2]),
|
|
12719
|
+
tdop: Math.sqrt(clockVar)
|
|
12720
|
+
};
|
|
12716
12721
|
}
|
|
12717
12722
|
function selectEphemeris(ephemerides, prn, timeMs) {
|
|
12718
12723
|
return selectBest(
|
|
@@ -12972,6 +12977,7 @@ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
|
|
|
12972
12977
|
const gdop = new Array(times.length).fill(null);
|
|
12973
12978
|
const hdop = new Array(times.length).fill(null);
|
|
12974
12979
|
const vdop = new Array(times.length).fill(null);
|
|
12980
|
+
const tdop = new Array(times.length).fill(null);
|
|
12975
12981
|
const visiblePerEpoch = times.map(() => []);
|
|
12976
12982
|
for (const prn of all.prns) {
|
|
12977
12983
|
const series = all.positions[prn];
|
|
@@ -12985,7 +12991,7 @@ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
|
|
|
12985
12991
|
visibleCount[i]++;
|
|
12986
12992
|
const sys = prn[0];
|
|
12987
12993
|
(visibleBySystem[sys] ??= new Array(times.length).fill(0))[i]++;
|
|
12988
|
-
visiblePerEpoch[i].push({ az: p.az, el: p.el });
|
|
12994
|
+
visiblePerEpoch[i].push({ az: p.az, el: p.el, prn });
|
|
12989
12995
|
}
|
|
12990
12996
|
}
|
|
12991
12997
|
}
|
|
@@ -12995,6 +13001,7 @@ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
|
|
|
12995
13001
|
gdop[i] = dop ? dop.gdop : null;
|
|
12996
13002
|
hdop[i] = dop ? dop.hdop : null;
|
|
12997
13003
|
vdop[i] = dop ? dop.vdop : null;
|
|
13004
|
+
tdop[i] = dop ? dop.tdop : null;
|
|
12998
13005
|
}
|
|
12999
13006
|
const passes = [];
|
|
13000
13007
|
for (const prn of all.prns) {
|
|
@@ -13041,6 +13048,7 @@ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
|
|
|
13041
13048
|
gdop,
|
|
13042
13049
|
hdop,
|
|
13043
13050
|
vdop,
|
|
13051
|
+
tdop,
|
|
13044
13052
|
passes
|
|
13045
13053
|
};
|
|
13046
13054
|
}
|
|
@@ -16966,28 +16974,6 @@ function sbasAirTropoVar(elRad) {
|
|
|
16966
16974
|
const sigTropo = 0.12 * m;
|
|
16967
16975
|
return sigMp * sigMp + NOISE_DIVG_AADA * NOISE_DIVG_AADA + sigTropo * sigTropo;
|
|
16968
16976
|
}
|
|
16969
|
-
function invertMatrix(A) {
|
|
16970
|
-
const n = A.length;
|
|
16971
|
-
const M = A.map((row, i) => [
|
|
16972
|
-
...row,
|
|
16973
|
-
...Array.from({ length: n }, (_, j) => i === j ? 1 : 0)
|
|
16974
|
-
]);
|
|
16975
|
-
for (let col = 0; col < n; col++) {
|
|
16976
|
-
let piv = col;
|
|
16977
|
-
for (let r = col + 1; r < n; r++)
|
|
16978
|
-
if (Math.abs(M[r][col]) > Math.abs(M[piv][col])) piv = r;
|
|
16979
|
-
if (Math.abs(M[piv][col]) < 1e-12) return null;
|
|
16980
|
-
[M[col], M[piv]] = [M[piv], M[col]];
|
|
16981
|
-
const d = M[col][col];
|
|
16982
|
-
for (let j = 0; j < 2 * n; j++) M[col][j] /= d;
|
|
16983
|
-
for (let r = 0; r < n; r++) {
|
|
16984
|
-
if (r === col) continue;
|
|
16985
|
-
const f = M[r][col];
|
|
16986
|
-
for (let j = 0; j < 2 * n; j++) M[r][j] -= f * M[col][j];
|
|
16987
|
-
}
|
|
16988
|
-
}
|
|
16989
|
-
return M.map((row) => row.slice(n));
|
|
16990
|
-
}
|
|
16991
16977
|
function sbasProtectionLevels(sats, opts = {}) {
|
|
16992
16978
|
const kH = opts.kH ?? 6;
|
|
16993
16979
|
const kV = opts.kV ?? 5.33;
|
|
@@ -17214,7 +17200,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
17214
17200
|
const azel = ecefToAzEl(x, y, z, sat.x, sat.y, sat.z);
|
|
17215
17201
|
if (azel.el >= elevationMaskDeg * Math.PI / 180) {
|
|
17216
17202
|
used.push(prn);
|
|
17217
|
-
azels.push(azel);
|
|
17203
|
+
azels.push({ ...azel, prn });
|
|
17218
17204
|
if (sbas) {
|
|
17219
17205
|
const dx = sat.x - x, dy = sat.y - y, dz = sat.z - z;
|
|
17220
17206
|
const dr = Math.hypot(dx, dy, dz) || 1;
|
package/dist/index.js
CHANGED
|
@@ -213,7 +213,7 @@ import {
|
|
|
213
213
|
sunEcef,
|
|
214
214
|
toRtkEpoch,
|
|
215
215
|
wlWavelength
|
|
216
|
-
} from "./chunk-
|
|
216
|
+
} from "./chunk-F6KOFOXN.js";
|
|
217
217
|
import "./chunk-WQX354KD.js";
|
|
218
218
|
import {
|
|
219
219
|
almanacEpochMs,
|
|
@@ -235,7 +235,7 @@ import {
|
|
|
235
235
|
navTimesFromEph,
|
|
236
236
|
rangeRate,
|
|
237
237
|
selectEphemeris
|
|
238
|
-
} from "./chunk-
|
|
238
|
+
} from "./chunk-T5M3LVBJ.js";
|
|
239
239
|
import {
|
|
240
240
|
getBdsTime,
|
|
241
241
|
getDateFromBdsTime,
|
package/dist/orbit.cjs
CHANGED
|
@@ -174,6 +174,30 @@ function getGpsLeap(date) {
|
|
|
174
174
|
return leap_seconds - 19;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
// src/orbit/matrix.ts
|
|
178
|
+
function invertMatrix(A) {
|
|
179
|
+
const n = A.length;
|
|
180
|
+
const M = A.map((row, i) => [
|
|
181
|
+
...row,
|
|
182
|
+
...Array.from({ length: n }, (_, j) => i === j ? 1 : 0)
|
|
183
|
+
]);
|
|
184
|
+
for (let col = 0; col < n; col++) {
|
|
185
|
+
let piv = col;
|
|
186
|
+
for (let r = col + 1; r < n; r++)
|
|
187
|
+
if (Math.abs(M[r][col]) > Math.abs(M[piv][col])) piv = r;
|
|
188
|
+
if (Math.abs(M[piv][col]) < 1e-12) return null;
|
|
189
|
+
[M[col], M[piv]] = [M[piv], M[col]];
|
|
190
|
+
const d = M[col][col];
|
|
191
|
+
for (let j = 0; j < 2 * n; j++) M[col][j] /= d;
|
|
192
|
+
for (let r = 0; r < n; r++) {
|
|
193
|
+
if (r === col) continue;
|
|
194
|
+
const f = M[r][col];
|
|
195
|
+
for (let j = 0; j < 2 * n; j++) M[r][j] -= f * M[col][j];
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return M.map((row) => row.slice(n));
|
|
199
|
+
}
|
|
200
|
+
|
|
177
201
|
// src/orbit/almanac.ts
|
|
178
202
|
var GM_GPS = 3986005e8;
|
|
179
203
|
var GM_GAL = 3986004418e5;
|
|
@@ -541,17 +565,26 @@ function ecefToAzEl(rxX, rxY, rxZ, satX, satY, satZ) {
|
|
|
541
565
|
const el = Math.atan2(up, Math.sqrt(east * east + north * north));
|
|
542
566
|
return { az: (az + TWO_PI) % TWO_PI, el };
|
|
543
567
|
}
|
|
568
|
+
function dopClock(prn) {
|
|
569
|
+
const sys = prn?.[0] ?? "";
|
|
570
|
+
return sys === "J" || sys === "S" ? "G" : sys;
|
|
571
|
+
}
|
|
544
572
|
function computeDop(satAzEls) {
|
|
545
573
|
const n = satAzEls.length;
|
|
546
|
-
|
|
574
|
+
const clocks = [...new Set(satAzEls.map((s) => dopClock(s.prn)))];
|
|
575
|
+
const m = 3 + clocks.length;
|
|
576
|
+
if (n < Math.max(4, m)) return null;
|
|
547
577
|
const H = [];
|
|
548
|
-
for (const { az, el } of satAzEls) {
|
|
578
|
+
for (const { az, el, prn } of satAzEls) {
|
|
549
579
|
const cosEl = Math.cos(el);
|
|
550
|
-
|
|
580
|
+
const row = [cosEl * Math.sin(az), cosEl * Math.cos(az), Math.sin(el)];
|
|
581
|
+
const clock = dopClock(prn);
|
|
582
|
+
for (const c of clocks) row.push(c === clock ? 1 : 0);
|
|
583
|
+
H.push(row);
|
|
551
584
|
}
|
|
552
|
-
const HtH = Array.from({ length:
|
|
553
|
-
for (let i = 0; i <
|
|
554
|
-
for (let j = 0; j <
|
|
585
|
+
const HtH = Array.from({ length: m }, () => new Array(m).fill(0));
|
|
586
|
+
for (let i = 0; i < m; i++) {
|
|
587
|
+
for (let j = 0; j < m; j++) {
|
|
555
588
|
let sum = 0;
|
|
556
589
|
for (let k = 0; k < n; k++) {
|
|
557
590
|
sum += H[k][i] * H[k][j];
|
|
@@ -559,46 +592,18 @@ function computeDop(satAzEls) {
|
|
|
559
592
|
HtH[i][j] = sum;
|
|
560
593
|
}
|
|
561
594
|
}
|
|
562
|
-
const Q =
|
|
595
|
+
const Q = invertMatrix(HtH);
|
|
563
596
|
if (!Q) return null;
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
inv[4] = -a[4] * a[10] * a[15] + a[4] * a[11] * a[14] + a[8] * a[6] * a[15] - a[8] * a[7] * a[14] - a[12] * a[6] * a[11] + a[12] * a[7] * a[10];
|
|
575
|
-
inv[8] = a[4] * a[9] * a[15] - a[4] * a[11] * a[13] - a[8] * a[5] * a[15] + a[8] * a[7] * a[13] + a[12] * a[5] * a[11] - a[12] * a[7] * a[9];
|
|
576
|
-
inv[12] = -a[4] * a[9] * a[14] + a[4] * a[10] * a[13] + a[8] * a[5] * a[14] - a[8] * a[6] * a[13] - a[12] * a[5] * a[10] + a[12] * a[6] * a[9];
|
|
577
|
-
inv[1] = -a[1] * a[10] * a[15] + a[1] * a[11] * a[14] + a[9] * a[2] * a[15] - a[9] * a[3] * a[14] - a[13] * a[2] * a[11] + a[13] * a[3] * a[10];
|
|
578
|
-
inv[5] = a[0] * a[10] * a[15] - a[0] * a[11] * a[14] - a[8] * a[2] * a[15] + a[8] * a[3] * a[14] + a[12] * a[2] * a[11] - a[12] * a[3] * a[10];
|
|
579
|
-
inv[9] = -a[0] * a[9] * a[15] + a[0] * a[11] * a[13] + a[8] * a[1] * a[15] - a[8] * a[3] * a[13] - a[12] * a[1] * a[11] + a[12] * a[3] * a[9];
|
|
580
|
-
inv[13] = a[0] * a[9] * a[14] - a[0] * a[10] * a[13] - a[8] * a[1] * a[14] + a[8] * a[2] * a[13] + a[12] * a[1] * a[10] - a[12] * a[2] * a[9];
|
|
581
|
-
inv[2] = a[1] * a[6] * a[15] - a[1] * a[7] * a[14] - a[5] * a[2] * a[15] + a[5] * a[3] * a[14] + a[13] * a[2] * a[7] - a[13] * a[3] * a[6];
|
|
582
|
-
inv[6] = -a[0] * a[6] * a[15] + a[0] * a[7] * a[14] + a[4] * a[2] * a[15] - a[4] * a[3] * a[14] - a[12] * a[2] * a[7] + a[12] * a[3] * a[6];
|
|
583
|
-
inv[10] = a[0] * a[5] * a[15] - a[0] * a[7] * a[13] - a[4] * a[1] * a[15] + a[4] * a[3] * a[13] + a[12] * a[1] * a[7] - a[12] * a[3] * a[5];
|
|
584
|
-
inv[14] = -a[0] * a[5] * a[14] + a[0] * a[6] * a[13] + a[4] * a[1] * a[14] - a[4] * a[2] * a[13] - a[12] * a[1] * a[6] + a[12] * a[2] * a[5];
|
|
585
|
-
inv[3] = -a[1] * a[6] * a[11] + a[1] * a[7] * a[10] + a[5] * a[2] * a[11] - a[5] * a[3] * a[10] - a[9] * a[2] * a[7] + a[9] * a[3] * a[6];
|
|
586
|
-
inv[7] = a[0] * a[6] * a[11] - a[0] * a[7] * a[10] - a[4] * a[2] * a[11] + a[4] * a[3] * a[10] + a[8] * a[2] * a[7] - a[8] * a[3] * a[6];
|
|
587
|
-
inv[11] = -a[0] * a[5] * a[11] + a[0] * a[7] * a[9] + a[4] * a[1] * a[11] - a[4] * a[3] * a[9] - a[8] * a[1] * a[7] + a[8] * a[3] * a[5];
|
|
588
|
-
inv[15] = a[0] * a[5] * a[10] - a[0] * a[6] * a[9] - a[4] * a[1] * a[10] + a[4] * a[2] * a[9] + a[8] * a[1] * a[6] - a[8] * a[2] * a[5];
|
|
589
|
-
let det = a[0] * inv[0] + a[1] * inv[4] + a[2] * inv[8] + a[3] * inv[12];
|
|
590
|
-
if (Math.abs(det) < 1e-20) return null;
|
|
591
|
-
det = 1 / det;
|
|
592
|
-
const result = Array.from(
|
|
593
|
-
{ length: 4 },
|
|
594
|
-
() => new Array(4).fill(0)
|
|
595
|
-
);
|
|
596
|
-
for (let i = 0; i < 4; i++) {
|
|
597
|
-
for (let j = 0; j < 4; j++) {
|
|
598
|
-
result[i][j] = inv[i * 4 + j] * det;
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
return result;
|
|
597
|
+
let clockVar = 0;
|
|
598
|
+
for (let i = 3; i < m; i++) clockVar += Q[i][i];
|
|
599
|
+
const posVar = Q[0][0] + Q[1][1] + Q[2][2];
|
|
600
|
+
return {
|
|
601
|
+
gdop: Math.sqrt(posVar + clockVar),
|
|
602
|
+
pdop: Math.sqrt(posVar),
|
|
603
|
+
hdop: Math.sqrt(Q[0][0] + Q[1][1]),
|
|
604
|
+
vdop: Math.sqrt(Q[2][2]),
|
|
605
|
+
tdop: Math.sqrt(clockVar)
|
|
606
|
+
};
|
|
602
607
|
}
|
|
603
608
|
function selectEphemeris(ephemerides, prn, timeMs) {
|
|
604
609
|
return selectBest(
|
|
@@ -858,6 +863,7 @@ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
|
|
|
858
863
|
const gdop = new Array(times.length).fill(null);
|
|
859
864
|
const hdop = new Array(times.length).fill(null);
|
|
860
865
|
const vdop = new Array(times.length).fill(null);
|
|
866
|
+
const tdop = new Array(times.length).fill(null);
|
|
861
867
|
const visiblePerEpoch = times.map(() => []);
|
|
862
868
|
for (const prn of all.prns) {
|
|
863
869
|
const series = all.positions[prn];
|
|
@@ -871,7 +877,7 @@ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
|
|
|
871
877
|
visibleCount[i]++;
|
|
872
878
|
const sys = prn[0];
|
|
873
879
|
(visibleBySystem[sys] ??= new Array(times.length).fill(0))[i]++;
|
|
874
|
-
visiblePerEpoch[i].push({ az: p.az, el: p.el });
|
|
880
|
+
visiblePerEpoch[i].push({ az: p.az, el: p.el, prn });
|
|
875
881
|
}
|
|
876
882
|
}
|
|
877
883
|
}
|
|
@@ -881,6 +887,7 @@ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
|
|
|
881
887
|
gdop[i] = dop ? dop.gdop : null;
|
|
882
888
|
hdop[i] = dop ? dop.hdop : null;
|
|
883
889
|
vdop[i] = dop ? dop.vdop : null;
|
|
890
|
+
tdop[i] = dop ? dop.tdop : null;
|
|
884
891
|
}
|
|
885
892
|
const passes = [];
|
|
886
893
|
for (const prn of all.prns) {
|
|
@@ -927,6 +934,7 @@ function computeVisibilityFromPositions(all, elevationMaskDeg = 10) {
|
|
|
927
934
|
gdop,
|
|
928
935
|
hdop,
|
|
929
936
|
vdop,
|
|
937
|
+
tdop,
|
|
930
938
|
passes
|
|
931
939
|
};
|
|
932
940
|
}
|
package/dist/orbit.d.cts
CHANGED
|
@@ -118,6 +118,11 @@ interface DopValues {
|
|
|
118
118
|
pdop: number;
|
|
119
119
|
hdop: number;
|
|
120
120
|
vdop: number;
|
|
121
|
+
/**
|
|
122
|
+
* Time DOP: root of the summed receiver-clock variances (one clock per
|
|
123
|
+
* constellation in view), so GDOP² = PDOP² + TDOP².
|
|
124
|
+
*/
|
|
125
|
+
tdop: number;
|
|
121
126
|
}
|
|
122
127
|
/**
|
|
123
128
|
* Compute satellite ECEF position and velocity from Keplerian ephemeris.
|
|
@@ -154,12 +159,23 @@ declare function ecefToAzEl(rxX: number, rxY: number, rxZ: number, satX: number,
|
|
|
154
159
|
};
|
|
155
160
|
/**
|
|
156
161
|
* Compute DOP values from a set of satellite az/el.
|
|
157
|
-
*
|
|
158
|
-
*
|
|
162
|
+
*
|
|
163
|
+
* Satellites tagged with a `prn` get one receiver-clock unknown per
|
|
164
|
+
* constellation time scale, as a multi-GNSS receiver solves: every extra
|
|
165
|
+
* time scale costs one observation. QZSS and SBAS share the GPS clock —
|
|
166
|
+
* QZSST and SBAS network time are steered to GPST (RTKLIB pntpos does the
|
|
167
|
+
* same) — so a lone SBAS GEO doesn't inflate TDOP/GDOP. Untagged
|
|
168
|
+
* satellites share a single clock (the classic single-system model).
|
|
169
|
+
*
|
|
170
|
+
* @param satAzEls Satellite azimuth/elevation pairs (radians), optionally
|
|
171
|
+
* tagged with their PRN.
|
|
172
|
+
* @returns DOP values, or null when there are fewer satellites than
|
|
173
|
+
* unknowns (3 + one clock per constellation) or the geometry is singular.
|
|
159
174
|
*/
|
|
160
175
|
declare function computeDop(satAzEls: {
|
|
161
176
|
az: number;
|
|
162
177
|
el: number;
|
|
178
|
+
prn?: string;
|
|
163
179
|
}[]): DopValues | null;
|
|
164
180
|
/**
|
|
165
181
|
* Find the best ephemeris for a given PRN at a given time.
|
|
@@ -242,14 +258,16 @@ interface VisibilityResult {
|
|
|
242
258
|
visibleCount: number[];
|
|
243
259
|
/** Per-system visible counts per epoch (system letter → counts). */
|
|
244
260
|
visibleBySystem: Record<string, number[]>;
|
|
245
|
-
/** PDOP per epoch (null when
|
|
261
|
+
/** PDOP per epoch (null when fewer satellites than unknowns). */
|
|
246
262
|
pdop: (number | null)[];
|
|
247
|
-
/** GDOP per epoch (null when
|
|
263
|
+
/** GDOP per epoch (null when fewer satellites than unknowns). */
|
|
248
264
|
gdop: (number | null)[];
|
|
249
|
-
/** HDOP per epoch (null when
|
|
265
|
+
/** HDOP per epoch (null when fewer satellites than unknowns). */
|
|
250
266
|
hdop: (number | null)[];
|
|
251
|
-
/** VDOP per epoch (null when
|
|
267
|
+
/** VDOP per epoch (null when fewer satellites than unknowns). */
|
|
252
268
|
vdop: (number | null)[];
|
|
269
|
+
/** TDOP per epoch (all constellation clocks; null like the others). */
|
|
270
|
+
tdop: (number | null)[];
|
|
253
271
|
/** Discrete above-mask passes, sorted by rise time. */
|
|
254
272
|
passes: VisibilityPass[];
|
|
255
273
|
}
|
package/dist/orbit.d.ts
CHANGED
|
@@ -118,6 +118,11 @@ interface DopValues {
|
|
|
118
118
|
pdop: number;
|
|
119
119
|
hdop: number;
|
|
120
120
|
vdop: number;
|
|
121
|
+
/**
|
|
122
|
+
* Time DOP: root of the summed receiver-clock variances (one clock per
|
|
123
|
+
* constellation in view), so GDOP² = PDOP² + TDOP².
|
|
124
|
+
*/
|
|
125
|
+
tdop: number;
|
|
121
126
|
}
|
|
122
127
|
/**
|
|
123
128
|
* Compute satellite ECEF position and velocity from Keplerian ephemeris.
|
|
@@ -154,12 +159,23 @@ declare function ecefToAzEl(rxX: number, rxY: number, rxZ: number, satX: number,
|
|
|
154
159
|
};
|
|
155
160
|
/**
|
|
156
161
|
* Compute DOP values from a set of satellite az/el.
|
|
157
|
-
*
|
|
158
|
-
*
|
|
162
|
+
*
|
|
163
|
+
* Satellites tagged with a `prn` get one receiver-clock unknown per
|
|
164
|
+
* constellation time scale, as a multi-GNSS receiver solves: every extra
|
|
165
|
+
* time scale costs one observation. QZSS and SBAS share the GPS clock —
|
|
166
|
+
* QZSST and SBAS network time are steered to GPST (RTKLIB pntpos does the
|
|
167
|
+
* same) — so a lone SBAS GEO doesn't inflate TDOP/GDOP. Untagged
|
|
168
|
+
* satellites share a single clock (the classic single-system model).
|
|
169
|
+
*
|
|
170
|
+
* @param satAzEls Satellite azimuth/elevation pairs (radians), optionally
|
|
171
|
+
* tagged with their PRN.
|
|
172
|
+
* @returns DOP values, or null when there are fewer satellites than
|
|
173
|
+
* unknowns (3 + one clock per constellation) or the geometry is singular.
|
|
159
174
|
*/
|
|
160
175
|
declare function computeDop(satAzEls: {
|
|
161
176
|
az: number;
|
|
162
177
|
el: number;
|
|
178
|
+
prn?: string;
|
|
163
179
|
}[]): DopValues | null;
|
|
164
180
|
/**
|
|
165
181
|
* Find the best ephemeris for a given PRN at a given time.
|
|
@@ -242,14 +258,16 @@ interface VisibilityResult {
|
|
|
242
258
|
visibleCount: number[];
|
|
243
259
|
/** Per-system visible counts per epoch (system letter → counts). */
|
|
244
260
|
visibleBySystem: Record<string, number[]>;
|
|
245
|
-
/** PDOP per epoch (null when
|
|
261
|
+
/** PDOP per epoch (null when fewer satellites than unknowns). */
|
|
246
262
|
pdop: (number | null)[];
|
|
247
|
-
/** GDOP per epoch (null when
|
|
263
|
+
/** GDOP per epoch (null when fewer satellites than unknowns). */
|
|
248
264
|
gdop: (number | null)[];
|
|
249
|
-
/** HDOP per epoch (null when
|
|
265
|
+
/** HDOP per epoch (null when fewer satellites than unknowns). */
|
|
250
266
|
hdop: (number | null)[];
|
|
251
|
-
/** VDOP per epoch (null when
|
|
267
|
+
/** VDOP per epoch (null when fewer satellites than unknowns). */
|
|
252
268
|
vdop: (number | null)[];
|
|
269
|
+
/** TDOP per epoch (all constellation clocks; null like the others). */
|
|
270
|
+
tdop: (number | null)[];
|
|
253
271
|
/** Discrete above-mask passes, sorted by rise time. */
|
|
254
272
|
passes: VisibilityPass[];
|
|
255
273
|
}
|
package/dist/orbit.js
CHANGED
package/dist/positioning.cjs
CHANGED
|
@@ -230,6 +230,30 @@ function getGpsLeap(date) {
|
|
|
230
230
|
return leap_seconds - 19;
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
// src/orbit/matrix.ts
|
|
234
|
+
function invertMatrix(A) {
|
|
235
|
+
const n = A.length;
|
|
236
|
+
const M = A.map((row, i) => [
|
|
237
|
+
...row,
|
|
238
|
+
...Array.from({ length: n }, (_, j) => i === j ? 1 : 0)
|
|
239
|
+
]);
|
|
240
|
+
for (let col = 0; col < n; col++) {
|
|
241
|
+
let piv = col;
|
|
242
|
+
for (let r = col + 1; r < n; r++)
|
|
243
|
+
if (Math.abs(M[r][col]) > Math.abs(M[piv][col])) piv = r;
|
|
244
|
+
if (Math.abs(M[piv][col]) < 1e-12) return null;
|
|
245
|
+
[M[col], M[piv]] = [M[piv], M[col]];
|
|
246
|
+
const d = M[col][col];
|
|
247
|
+
for (let j = 0; j < 2 * n; j++) M[col][j] /= d;
|
|
248
|
+
for (let r = 0; r < n; r++) {
|
|
249
|
+
if (r === col) continue;
|
|
250
|
+
const f = M[r][col];
|
|
251
|
+
for (let j = 0; j < 2 * n; j++) M[r][j] -= f * M[col][j];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return M.map((row) => row.slice(n));
|
|
255
|
+
}
|
|
256
|
+
|
|
233
257
|
// src/orbit/index.ts
|
|
234
258
|
var GM_GPS = 3986005e8;
|
|
235
259
|
var GM_GAL = 3986004418e5;
|
|
@@ -413,17 +437,26 @@ function ecefToAzEl(rxX, rxY, rxZ, satX, satY, satZ) {
|
|
|
413
437
|
const el = Math.atan2(up, Math.sqrt(east * east + north * north));
|
|
414
438
|
return { az: (az + TWO_PI) % TWO_PI, el };
|
|
415
439
|
}
|
|
440
|
+
function dopClock(prn) {
|
|
441
|
+
const sys = prn?.[0] ?? "";
|
|
442
|
+
return sys === "J" || sys === "S" ? "G" : sys;
|
|
443
|
+
}
|
|
416
444
|
function computeDop(satAzEls) {
|
|
417
445
|
const n = satAzEls.length;
|
|
418
|
-
|
|
446
|
+
const clocks = [...new Set(satAzEls.map((s) => dopClock(s.prn)))];
|
|
447
|
+
const m = 3 + clocks.length;
|
|
448
|
+
if (n < Math.max(4, m)) return null;
|
|
419
449
|
const H = [];
|
|
420
|
-
for (const { az, el } of satAzEls) {
|
|
450
|
+
for (const { az, el, prn } of satAzEls) {
|
|
421
451
|
const cosEl = Math.cos(el);
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
452
|
+
const row = [cosEl * Math.sin(az), cosEl * Math.cos(az), Math.sin(el)];
|
|
453
|
+
const clock = dopClock(prn);
|
|
454
|
+
for (const c of clocks) row.push(c === clock ? 1 : 0);
|
|
455
|
+
H.push(row);
|
|
456
|
+
}
|
|
457
|
+
const HtH = Array.from({ length: m }, () => new Array(m).fill(0));
|
|
458
|
+
for (let i = 0; i < m; i++) {
|
|
459
|
+
for (let j = 0; j < m; j++) {
|
|
427
460
|
let sum = 0;
|
|
428
461
|
for (let k = 0; k < n; k++) {
|
|
429
462
|
sum += H[k][i] * H[k][j];
|
|
@@ -431,46 +464,18 @@ function computeDop(satAzEls) {
|
|
|
431
464
|
HtH[i][j] = sum;
|
|
432
465
|
}
|
|
433
466
|
}
|
|
434
|
-
const Q =
|
|
467
|
+
const Q = invertMatrix(HtH);
|
|
435
468
|
if (!Q) return null;
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
const
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
inv[4] = -a[4] * a[10] * a[15] + a[4] * a[11] * a[14] + a[8] * a[6] * a[15] - a[8] * a[7] * a[14] - a[12] * a[6] * a[11] + a[12] * a[7] * a[10];
|
|
447
|
-
inv[8] = a[4] * a[9] * a[15] - a[4] * a[11] * a[13] - a[8] * a[5] * a[15] + a[8] * a[7] * a[13] + a[12] * a[5] * a[11] - a[12] * a[7] * a[9];
|
|
448
|
-
inv[12] = -a[4] * a[9] * a[14] + a[4] * a[10] * a[13] + a[8] * a[5] * a[14] - a[8] * a[6] * a[13] - a[12] * a[5] * a[10] + a[12] * a[6] * a[9];
|
|
449
|
-
inv[1] = -a[1] * a[10] * a[15] + a[1] * a[11] * a[14] + a[9] * a[2] * a[15] - a[9] * a[3] * a[14] - a[13] * a[2] * a[11] + a[13] * a[3] * a[10];
|
|
450
|
-
inv[5] = a[0] * a[10] * a[15] - a[0] * a[11] * a[14] - a[8] * a[2] * a[15] + a[8] * a[3] * a[14] + a[12] * a[2] * a[11] - a[12] * a[3] * a[10];
|
|
451
|
-
inv[9] = -a[0] * a[9] * a[15] + a[0] * a[11] * a[13] + a[8] * a[1] * a[15] - a[8] * a[3] * a[13] - a[12] * a[1] * a[11] + a[12] * a[3] * a[9];
|
|
452
|
-
inv[13] = a[0] * a[9] * a[14] - a[0] * a[10] * a[13] - a[8] * a[1] * a[14] + a[8] * a[2] * a[13] + a[12] * a[1] * a[10] - a[12] * a[2] * a[9];
|
|
453
|
-
inv[2] = a[1] * a[6] * a[15] - a[1] * a[7] * a[14] - a[5] * a[2] * a[15] + a[5] * a[3] * a[14] + a[13] * a[2] * a[7] - a[13] * a[3] * a[6];
|
|
454
|
-
inv[6] = -a[0] * a[6] * a[15] + a[0] * a[7] * a[14] + a[4] * a[2] * a[15] - a[4] * a[3] * a[14] - a[12] * a[2] * a[7] + a[12] * a[3] * a[6];
|
|
455
|
-
inv[10] = a[0] * a[5] * a[15] - a[0] * a[7] * a[13] - a[4] * a[1] * a[15] + a[4] * a[3] * a[13] + a[12] * a[1] * a[7] - a[12] * a[3] * a[5];
|
|
456
|
-
inv[14] = -a[0] * a[5] * a[14] + a[0] * a[6] * a[13] + a[4] * a[1] * a[14] - a[4] * a[2] * a[13] - a[12] * a[1] * a[6] + a[12] * a[2] * a[5];
|
|
457
|
-
inv[3] = -a[1] * a[6] * a[11] + a[1] * a[7] * a[10] + a[5] * a[2] * a[11] - a[5] * a[3] * a[10] - a[9] * a[2] * a[7] + a[9] * a[3] * a[6];
|
|
458
|
-
inv[7] = a[0] * a[6] * a[11] - a[0] * a[7] * a[10] - a[4] * a[2] * a[11] + a[4] * a[3] * a[10] + a[8] * a[2] * a[7] - a[8] * a[3] * a[6];
|
|
459
|
-
inv[11] = -a[0] * a[5] * a[11] + a[0] * a[7] * a[9] + a[4] * a[1] * a[11] - a[4] * a[3] * a[9] - a[8] * a[1] * a[7] + a[8] * a[3] * a[5];
|
|
460
|
-
inv[15] = a[0] * a[5] * a[10] - a[0] * a[6] * a[9] - a[4] * a[1] * a[10] + a[4] * a[2] * a[9] + a[8] * a[1] * a[6] - a[8] * a[2] * a[5];
|
|
461
|
-
let det = a[0] * inv[0] + a[1] * inv[4] + a[2] * inv[8] + a[3] * inv[12];
|
|
462
|
-
if (Math.abs(det) < 1e-20) return null;
|
|
463
|
-
det = 1 / det;
|
|
464
|
-
const result = Array.from(
|
|
465
|
-
{ length: 4 },
|
|
466
|
-
() => new Array(4).fill(0)
|
|
467
|
-
);
|
|
468
|
-
for (let i = 0; i < 4; i++) {
|
|
469
|
-
for (let j = 0; j < 4; j++) {
|
|
470
|
-
result[i][j] = inv[i * 4 + j] * det;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
return result;
|
|
469
|
+
let clockVar = 0;
|
|
470
|
+
for (let i = 3; i < m; i++) clockVar += Q[i][i];
|
|
471
|
+
const posVar = Q[0][0] + Q[1][1] + Q[2][2];
|
|
472
|
+
return {
|
|
473
|
+
gdop: Math.sqrt(posVar + clockVar),
|
|
474
|
+
pdop: Math.sqrt(posVar),
|
|
475
|
+
hdop: Math.sqrt(Q[0][0] + Q[1][1]),
|
|
476
|
+
vdop: Math.sqrt(Q[2][2]),
|
|
477
|
+
tdop: Math.sqrt(clockVar)
|
|
478
|
+
};
|
|
474
479
|
}
|
|
475
480
|
function selectEphemeris(ephemerides, prn, timeMs) {
|
|
476
481
|
return selectBest(
|
|
@@ -4307,28 +4312,6 @@ function sbasAirTropoVar(elRad) {
|
|
|
4307
4312
|
const sigTropo = 0.12 * m;
|
|
4308
4313
|
return sigMp * sigMp + NOISE_DIVG_AADA * NOISE_DIVG_AADA + sigTropo * sigTropo;
|
|
4309
4314
|
}
|
|
4310
|
-
function invertMatrix(A) {
|
|
4311
|
-
const n = A.length;
|
|
4312
|
-
const M = A.map((row, i) => [
|
|
4313
|
-
...row,
|
|
4314
|
-
...Array.from({ length: n }, (_, j) => i === j ? 1 : 0)
|
|
4315
|
-
]);
|
|
4316
|
-
for (let col = 0; col < n; col++) {
|
|
4317
|
-
let piv = col;
|
|
4318
|
-
for (let r = col + 1; r < n; r++)
|
|
4319
|
-
if (Math.abs(M[r][col]) > Math.abs(M[piv][col])) piv = r;
|
|
4320
|
-
if (Math.abs(M[piv][col]) < 1e-12) return null;
|
|
4321
|
-
[M[col], M[piv]] = [M[piv], M[col]];
|
|
4322
|
-
const d = M[col][col];
|
|
4323
|
-
for (let j = 0; j < 2 * n; j++) M[col][j] /= d;
|
|
4324
|
-
for (let r = 0; r < n; r++) {
|
|
4325
|
-
if (r === col) continue;
|
|
4326
|
-
const f = M[r][col];
|
|
4327
|
-
for (let j = 0; j < 2 * n; j++) M[r][j] -= f * M[col][j];
|
|
4328
|
-
}
|
|
4329
|
-
}
|
|
4330
|
-
return M.map((row) => row.slice(n));
|
|
4331
|
-
}
|
|
4332
4315
|
function sbasProtectionLevels(sats, opts = {}) {
|
|
4333
4316
|
const kH = opts.kH ?? 6;
|
|
4334
4317
|
const kV = opts.kV ?? 5.33;
|
|
@@ -4555,7 +4538,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
4555
4538
|
const azel = ecefToAzEl(x, y, z, sat.x, sat.y, sat.z);
|
|
4556
4539
|
if (azel.el >= elevationMaskDeg * Math.PI / 180) {
|
|
4557
4540
|
used.push(prn);
|
|
4558
|
-
azels.push(azel);
|
|
4541
|
+
azels.push({ ...azel, prn });
|
|
4559
4542
|
if (sbas) {
|
|
4560
4543
|
const dx = sat.x - x, dy = sat.y - y, dz = sat.z - z;
|
|
4561
4544
|
const dr = Math.hypot(dx, dy, dz) || 1;
|
package/dist/positioning.js
CHANGED
|
@@ -40,9 +40,9 @@ import {
|
|
|
40
40
|
sunEcef,
|
|
41
41
|
toRtkEpoch,
|
|
42
42
|
wlWavelength
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-F6KOFOXN.js";
|
|
44
44
|
import "./chunk-WQX354KD.js";
|
|
45
|
-
import "./chunk-
|
|
45
|
+
import "./chunk-T5M3LVBJ.js";
|
|
46
46
|
import "./chunk-HVXYFUCB.js";
|
|
47
47
|
import "./chunk-CVCTRIWU.js";
|
|
48
48
|
import "./chunk-37QNKGTC.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gnss-js",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.1",
|
|
4
4
|
"description": "Comprehensive GNSS library for JavaScript — time scales, coordinates, RINEX parsing, RTCM3 decoding, orbit computation, and signal analysis",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|