gnss-js 1.23.0 → 1.24.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-CUWF56ST.js → chunk-T2ZMNRCY.js} +311 -3
- package/dist/index.cjs +313 -3
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -1
- package/dist/positioning.cjs +313 -3
- package/dist/positioning.d.cts +167 -5
- package/dist/positioning.d.ts +167 -5
- package/dist/positioning.js +5 -1
- package/package.json +1 -1
|
@@ -43,6 +43,207 @@ function klobucharDelay(coeffs, latRad, lonRad, azRad, elRad, gpsTowSec) {
|
|
|
43
43
|
return F * (5e-9 + amp * (1 - x2 / 2 + x2 * x2 / 24));
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
// src/positioning/lambda.ts
|
|
47
|
+
var LOOPMAX = 1e4;
|
|
48
|
+
var ROUND = (x) => Math.floor(x + 0.5);
|
|
49
|
+
var SGN = (x) => x <= 0 ? -1 : 1;
|
|
50
|
+
function ldFactor(n, Q, L, D) {
|
|
51
|
+
const A = Float64Array.from(Q);
|
|
52
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
53
|
+
D[i] = A[i + i * n];
|
|
54
|
+
if (D[i] <= 0) return false;
|
|
55
|
+
const a = Math.sqrt(D[i]);
|
|
56
|
+
for (let j = 0; j <= i; j++) L[i + j * n] = A[i + j * n] / a;
|
|
57
|
+
for (let j = 0; j <= i - 1; j++)
|
|
58
|
+
for (let k = 0; k <= j; k++) A[j + k * n] -= L[i + k * n] * L[i + j * n];
|
|
59
|
+
for (let j = 0; j <= i; j++) L[i + j * n] /= L[i + i * n];
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
function gauss(n, L, Z, i, j) {
|
|
64
|
+
const mu = ROUND(L[i + j * n]);
|
|
65
|
+
if (mu !== 0) {
|
|
66
|
+
for (let k = i; k < n; k++) L[k + n * j] -= mu * L[k + i * n];
|
|
67
|
+
for (let k = 0; k < n; k++) Z[k + n * j] -= mu * Z[k + i * n];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function perm(n, L, D, j, del, Z) {
|
|
71
|
+
const eta = D[j] / del;
|
|
72
|
+
const lam = D[j + 1] * L[j + 1 + j * n] / del;
|
|
73
|
+
D[j] = eta * D[j + 1];
|
|
74
|
+
D[j + 1] = del;
|
|
75
|
+
for (let k = 0; k <= j - 1; k++) {
|
|
76
|
+
const a0 = L[j + k * n];
|
|
77
|
+
const a1 = L[j + 1 + k * n];
|
|
78
|
+
L[j + k * n] = -L[j + 1 + j * n] * a0 + a1;
|
|
79
|
+
L[j + 1 + k * n] = eta * a0 + lam * a1;
|
|
80
|
+
}
|
|
81
|
+
L[j + 1 + j * n] = lam;
|
|
82
|
+
for (let k = j + 2; k < n; k++) {
|
|
83
|
+
const t = L[k + j * n];
|
|
84
|
+
L[k + j * n] = L[k + (j + 1) * n];
|
|
85
|
+
L[k + (j + 1) * n] = t;
|
|
86
|
+
}
|
|
87
|
+
for (let k = 0; k < n; k++) {
|
|
88
|
+
const t = Z[k + j * n];
|
|
89
|
+
Z[k + j * n] = Z[k + (j + 1) * n];
|
|
90
|
+
Z[k + (j + 1) * n] = t;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function reduction(n, L, D, Z) {
|
|
94
|
+
let j = n - 2;
|
|
95
|
+
let k = n - 2;
|
|
96
|
+
while (j >= 0) {
|
|
97
|
+
if (j <= k) for (let i = j + 1; i < n; i++) gauss(n, L, Z, i, j);
|
|
98
|
+
const del = D[j] + L[j + 1 + j * n] * L[j + 1 + j * n] * D[j + 1];
|
|
99
|
+
if (del + 1e-6 < D[j + 1]) {
|
|
100
|
+
perm(n, L, D, j, del, Z);
|
|
101
|
+
k = j;
|
|
102
|
+
j = n - 2;
|
|
103
|
+
} else j--;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function search(n, m, L, D, zs, zn, s) {
|
|
107
|
+
let nn = 0;
|
|
108
|
+
let imax = 0;
|
|
109
|
+
let maxdist = 1e99;
|
|
110
|
+
const S = new Float64Array(n * n);
|
|
111
|
+
const dist = new Float64Array(n);
|
|
112
|
+
const zb = new Float64Array(n);
|
|
113
|
+
const z = new Float64Array(n);
|
|
114
|
+
const step = new Float64Array(n);
|
|
115
|
+
let k = n - 1;
|
|
116
|
+
dist[k] = 0;
|
|
117
|
+
zb[k] = zs[k];
|
|
118
|
+
z[k] = ROUND(zb[k]);
|
|
119
|
+
let y = zb[k] - z[k];
|
|
120
|
+
step[k] = SGN(y);
|
|
121
|
+
let c = 0;
|
|
122
|
+
for (; c < LOOPMAX; c++) {
|
|
123
|
+
const newdist = dist[k] + y * y / D[k];
|
|
124
|
+
if (newdist < maxdist) {
|
|
125
|
+
if (k !== 0) {
|
|
126
|
+
dist[--k] = newdist;
|
|
127
|
+
for (let i = 0; i <= k; i++)
|
|
128
|
+
S[k + i * n] = S[k + 1 + i * n] + (z[k + 1] - zb[k + 1]) * L[k + 1 + i * n];
|
|
129
|
+
zb[k] = zs[k] + S[k + k * n];
|
|
130
|
+
z[k] = ROUND(zb[k]);
|
|
131
|
+
y = zb[k] - z[k];
|
|
132
|
+
step[k] = SGN(y);
|
|
133
|
+
} else {
|
|
134
|
+
if (nn < m) {
|
|
135
|
+
if (nn === 0 || newdist > s[imax]) imax = nn;
|
|
136
|
+
for (let i = 0; i < n; i++) zn[i + nn * n] = z[i];
|
|
137
|
+
s[nn++] = newdist;
|
|
138
|
+
} else {
|
|
139
|
+
if (newdist < s[imax]) {
|
|
140
|
+
for (let i = 0; i < n; i++) zn[i + imax * n] = z[i];
|
|
141
|
+
s[imax] = newdist;
|
|
142
|
+
imax = 0;
|
|
143
|
+
for (let i = 0; i < m; i++) if (s[imax] < s[i]) imax = i;
|
|
144
|
+
}
|
|
145
|
+
maxdist = s[imax];
|
|
146
|
+
}
|
|
147
|
+
z[0] += step[0];
|
|
148
|
+
y = zb[0] - z[0];
|
|
149
|
+
step[0] = -step[0] - SGN(step[0]);
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
if (k === n - 1) break;
|
|
153
|
+
k++;
|
|
154
|
+
z[k] += step[k];
|
|
155
|
+
y = zb[k] - z[k];
|
|
156
|
+
step[k] = -step[k] - SGN(step[k]);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
for (let i = 0; i < m - 1; i++) {
|
|
160
|
+
for (let j = i + 1; j < m; j++) {
|
|
161
|
+
if (s[i] < s[j]) continue;
|
|
162
|
+
const t = s[i];
|
|
163
|
+
s[i] = s[j];
|
|
164
|
+
s[j] = t;
|
|
165
|
+
for (let l = 0; l < n; l++) {
|
|
166
|
+
const u = zn[l + i * n];
|
|
167
|
+
zn[l + i * n] = zn[l + j * n];
|
|
168
|
+
zn[l + j * n] = u;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return c < LOOPMAX;
|
|
173
|
+
}
|
|
174
|
+
function solveZt(n, m, Z, E) {
|
|
175
|
+
const w = n + m;
|
|
176
|
+
const M = new Float64Array(n * w);
|
|
177
|
+
for (let r = 0; r < n; r++) {
|
|
178
|
+
for (let cIdx = 0; cIdx < n; cIdx++) M[r * w + cIdx] = Z[cIdx + r * n];
|
|
179
|
+
for (let cIdx = 0; cIdx < m; cIdx++) M[r * w + n + cIdx] = E[r + cIdx * n];
|
|
180
|
+
}
|
|
181
|
+
for (let col = 0; col < n; col++) {
|
|
182
|
+
let piv = col;
|
|
183
|
+
for (let r = col + 1; r < n; r++)
|
|
184
|
+
if (Math.abs(M[r * w + col]) > Math.abs(M[piv * w + col])) piv = r;
|
|
185
|
+
if (Math.abs(M[piv * w + col]) < 1e-12) return null;
|
|
186
|
+
if (piv !== col) {
|
|
187
|
+
for (let cIdx = col; cIdx < w; cIdx++) {
|
|
188
|
+
const t = M[col * w + cIdx];
|
|
189
|
+
M[col * w + cIdx] = M[piv * w + cIdx];
|
|
190
|
+
M[piv * w + cIdx] = t;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const d = M[col * w + col];
|
|
194
|
+
for (let cIdx = col; cIdx < w; cIdx++) M[col * w + cIdx] /= d;
|
|
195
|
+
for (let r = 0; r < n; r++) {
|
|
196
|
+
if (r === col) continue;
|
|
197
|
+
const f = M[r * w + col];
|
|
198
|
+
if (f === 0) continue;
|
|
199
|
+
for (let cIdx = col; cIdx < w; cIdx++)
|
|
200
|
+
M[r * w + cIdx] -= f * M[col * w + cIdx];
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const X = new Float64Array(n * m);
|
|
204
|
+
for (let r = 0; r < n; r++)
|
|
205
|
+
for (let cIdx = 0; cIdx < m; cIdx++) X[r + cIdx * n] = M[r * w + n + cIdx];
|
|
206
|
+
return X;
|
|
207
|
+
}
|
|
208
|
+
function lambdaSearch(a, Q, n, m = 2) {
|
|
209
|
+
if (n <= 0 || m <= 0 || a.length < n || Q.length < n * n) return null;
|
|
210
|
+
const L = new Float64Array(n * n);
|
|
211
|
+
const D = new Float64Array(n);
|
|
212
|
+
if (!ldFactor(n, Q, L, D)) return null;
|
|
213
|
+
const Z = new Float64Array(n * n);
|
|
214
|
+
for (let i = 0; i < n; i++) Z[i + i * n] = 1;
|
|
215
|
+
reduction(n, L, D, Z);
|
|
216
|
+
const z = new Float64Array(n);
|
|
217
|
+
for (let j = 0; j < n; j++) {
|
|
218
|
+
let sum = 0;
|
|
219
|
+
for (let k = 0; k < n; k++) sum += Z[k + j * n] * a[k];
|
|
220
|
+
z[j] = sum;
|
|
221
|
+
}
|
|
222
|
+
const E = new Float64Array(n * m);
|
|
223
|
+
const s = new Float64Array(m);
|
|
224
|
+
if (!search(n, m, L, D, z, E, s)) return null;
|
|
225
|
+
const F = solveZt(n, m, Z, E);
|
|
226
|
+
if (!F) return null;
|
|
227
|
+
const candidates = [];
|
|
228
|
+
for (let c = 0; c < m; c++) {
|
|
229
|
+
const v = new Float64Array(n);
|
|
230
|
+
for (let i = 0; i < n; i++) v[i] = ROUND(F[i + c * n]);
|
|
231
|
+
candidates.push(v);
|
|
232
|
+
}
|
|
233
|
+
const ratio = m >= 2 && s[0] > 0 ? s[1] / s[0] : Infinity;
|
|
234
|
+
return { candidates, residuals: s, ratio };
|
|
235
|
+
}
|
|
236
|
+
function lambdaReduction(Q, n) {
|
|
237
|
+
if (n <= 0 || Q.length < n * n) return null;
|
|
238
|
+
const L = new Float64Array(n * n);
|
|
239
|
+
const D = new Float64Array(n);
|
|
240
|
+
if (!ldFactor(n, Q, L, D)) return null;
|
|
241
|
+
const Z = new Float64Array(n * n);
|
|
242
|
+
for (let i = 0; i < n; i++) Z[i + i * n] = 1;
|
|
243
|
+
reduction(n, L, D, Z);
|
|
244
|
+
return Z;
|
|
245
|
+
}
|
|
246
|
+
|
|
46
247
|
// src/positioning/rtk.ts
|
|
47
248
|
var L1_CODES = {
|
|
48
249
|
G: ["1C"],
|
|
@@ -403,7 +604,13 @@ var RtkFloatEngine = class {
|
|
|
403
604
|
maxGapMs: opts.maxGapMs ?? 1e4,
|
|
404
605
|
codeGateM: opts.codeGateM ?? 30,
|
|
405
606
|
slipGateM: opts.slipGateM ?? 5,
|
|
406
|
-
updateIterations: opts.updateIterations ?? 2
|
|
607
|
+
updateIterations: opts.updateIterations ?? 2,
|
|
608
|
+
ambiguityResolution: opts.ambiguityResolution ?? "off",
|
|
609
|
+
ratioThreshold: opts.ratioThreshold ?? 3,
|
|
610
|
+
arElevationMaskDeg: opts.arElevationMaskDeg ?? 0,
|
|
611
|
+
glonassAr: opts.glonassAr ?? false,
|
|
612
|
+
partialFixing: opts.partialFixing ?? true,
|
|
613
|
+
minFixAmbiguities: opts.minFixAmbiguities ?? 4
|
|
407
614
|
};
|
|
408
615
|
}
|
|
409
616
|
/** Clear all filter state (position, ambiguities, lock history). */
|
|
@@ -461,6 +668,56 @@ var RtkFloatEngine = class {
|
|
|
461
668
|
const entry = this.amb[newRefIdx];
|
|
462
669
|
entry.prn = oldRef;
|
|
463
670
|
}
|
|
671
|
+
/**
|
|
672
|
+
* Try to fix the ambiguity subset `idxs` (indices into `this.amb`):
|
|
673
|
+
* extract the float subvector b and covariance Q_b from the filter,
|
|
674
|
+
* run MLAMBDA and, without touching the filter state, condition the
|
|
675
|
+
* position on the best integer candidate,
|
|
676
|
+
* xa = x − P_xb·Q_b⁻¹·(b − ǎ)
|
|
677
|
+
* (RTKLIB rtkpos.c `resamb_LAMBDA`). Returns null when Q_b is not
|
|
678
|
+
* positive definite / invertible or the search fails; ratio
|
|
679
|
+
* validation is the caller's job.
|
|
680
|
+
*/
|
|
681
|
+
tryFix(idxs) {
|
|
682
|
+
const k = idxs.length;
|
|
683
|
+
const b = new Float64Array(k);
|
|
684
|
+
const Qb = new Float64Array(k * k);
|
|
685
|
+
const QbRows = [];
|
|
686
|
+
for (let i = 0; i < k; i++) {
|
|
687
|
+
const si = 3 + idxs[i];
|
|
688
|
+
b[i] = this.x[si];
|
|
689
|
+
const row = [];
|
|
690
|
+
for (let j = 0; j < k; j++) {
|
|
691
|
+
const sj = 3 + idxs[j];
|
|
692
|
+
const q = (this.P[si][sj] + this.P[sj][si]) / 2;
|
|
693
|
+
Qb[i + j * k] = q;
|
|
694
|
+
row.push(q);
|
|
695
|
+
}
|
|
696
|
+
QbRows.push(row);
|
|
697
|
+
}
|
|
698
|
+
const res = lambdaSearch(b, Qb, k, 2);
|
|
699
|
+
if (!res) return null;
|
|
700
|
+
const best = res.candidates[0];
|
|
701
|
+
const QbInv = matInv(QbRows);
|
|
702
|
+
if (!QbInv) return null;
|
|
703
|
+
const db = [];
|
|
704
|
+
for (let i = 0; i < k; i++) db.push(b[i] - best[i]);
|
|
705
|
+
const position = [
|
|
706
|
+
this.x[0],
|
|
707
|
+
this.x[1],
|
|
708
|
+
this.x[2]
|
|
709
|
+
];
|
|
710
|
+
for (let r = 0; r < 3; r++) {
|
|
711
|
+
let dx = 0;
|
|
712
|
+
for (let i = 0; i < k; i++) {
|
|
713
|
+
let yi = 0;
|
|
714
|
+
for (let j = 0; j < k; j++) yi += QbInv[i][j] * db[j];
|
|
715
|
+
dx += this.P[r][3 + idxs[i]] * yi;
|
|
716
|
+
}
|
|
717
|
+
position[r] -= dx;
|
|
718
|
+
}
|
|
719
|
+
return { ratio: res.ratio, position, intAmb: [...best] };
|
|
720
|
+
}
|
|
464
721
|
/**
|
|
465
722
|
* Process one synchronized epoch (same nominal `timeMs` for both
|
|
466
723
|
* receivers). Returns null until a first position can be
|
|
@@ -711,6 +968,47 @@ var RtkFloatEngine = class {
|
|
|
711
968
|
Pnew[j][i] = s;
|
|
712
969
|
}
|
|
713
970
|
this.P = Pnew;
|
|
971
|
+
let status = rows.some(
|
|
972
|
+
(r) => r.kind === "phase"
|
|
973
|
+
) ? "float" : "dgnss";
|
|
974
|
+
let ratio;
|
|
975
|
+
let nFixed;
|
|
976
|
+
let fixedPos = null;
|
|
977
|
+
let fixedAmbiguities;
|
|
978
|
+
if (o.ambiguityResolution === "instant") {
|
|
979
|
+
const cands = [];
|
|
980
|
+
for (const row of rows) {
|
|
981
|
+
if (row.kind !== "phase") continue;
|
|
982
|
+
if (row.g.prn[0] === "R" && !o.glonassAr) continue;
|
|
983
|
+
if (row.g.elB < o.arElevationMaskDeg * Math.PI / 180) continue;
|
|
984
|
+
cands.push({ idx: row.ambIdx, el: row.g.elB });
|
|
985
|
+
}
|
|
986
|
+
cands.sort((a, b) => b.el - a.el);
|
|
987
|
+
const floor = Math.max(
|
|
988
|
+
o.minFixAmbiguities,
|
|
989
|
+
Math.ceil(cands.length / 2),
|
|
990
|
+
1
|
|
991
|
+
);
|
|
992
|
+
while (cands.length >= floor) {
|
|
993
|
+
const fix = this.tryFix(cands.map((c) => c.idx));
|
|
994
|
+
if (!fix) break;
|
|
995
|
+
const capped = Math.min(fix.ratio, 999.9);
|
|
996
|
+
ratio ??= capped;
|
|
997
|
+
if (fix.ratio >= o.ratioThreshold) {
|
|
998
|
+
ratio = capped;
|
|
999
|
+
status = "fixed";
|
|
1000
|
+
nFixed = cands.length;
|
|
1001
|
+
fixedPos = fix.position;
|
|
1002
|
+
fixedAmbiguities = {};
|
|
1003
|
+
cands.forEach((c, i) => {
|
|
1004
|
+
fixedAmbiguities[this.amb[c.idx].prn] = fix.intAmb[i];
|
|
1005
|
+
});
|
|
1006
|
+
break;
|
|
1007
|
+
}
|
|
1008
|
+
if (!o.partialFixing) break;
|
|
1009
|
+
cands.pop();
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
714
1012
|
for (const g of geom) {
|
|
715
1013
|
if (g.cpR === null || g.cpB === null) continue;
|
|
716
1014
|
this.track.set(g.prn, { lockR: g.lockR, lockB: g.lockB, lastMs: timeMs });
|
|
@@ -724,14 +1022,22 @@ var RtkFloatEngine = class {
|
|
|
724
1022
|
const nSats = new Set(rows.flatMap((r) => [r.g.prn, r.ref.prn])).size;
|
|
725
1023
|
return {
|
|
726
1024
|
timeMs,
|
|
727
|
-
position: [this.x[0], this.x[1], this.x[2]],
|
|
1025
|
+
position: fixedPos ?? [this.x[0], this.x[1], this.x[2]],
|
|
728
1026
|
floatBaseline: [
|
|
729
1027
|
this.x[0] - this.basePos[0],
|
|
730
1028
|
this.x[1] - this.basePos[1],
|
|
731
1029
|
this.x[2] - this.basePos[2]
|
|
732
1030
|
],
|
|
1031
|
+
status,
|
|
733
1032
|
nSats,
|
|
734
|
-
ratio
|
|
1033
|
+
ratio,
|
|
1034
|
+
nFixed,
|
|
1035
|
+
fixedBaseline: fixedPos ? [
|
|
1036
|
+
fixedPos[0] - this.basePos[0],
|
|
1037
|
+
fixedPos[1] - this.basePos[1],
|
|
1038
|
+
fixedPos[2] - this.basePos[2]
|
|
1039
|
+
] : void 0,
|
|
1040
|
+
fixedAmbiguities,
|
|
735
1041
|
sigmas: [
|
|
736
1042
|
Math.sqrt(Math.max(this.P[0][0], 0)),
|
|
737
1043
|
Math.sqrt(Math.max(this.P[1][1], 0)),
|
|
@@ -957,6 +1263,8 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
957
1263
|
|
|
958
1264
|
export {
|
|
959
1265
|
klobucharDelay,
|
|
1266
|
+
lambdaSearch,
|
|
1267
|
+
lambdaReduction,
|
|
960
1268
|
toRtkEpoch,
|
|
961
1269
|
solveDgnss,
|
|
962
1270
|
RtkFloatEngine,
|