gnss-js 1.23.0 → 1.25.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-4XGKCVE3.js} +384 -13
- package/dist/index.cjs +389 -13
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +11 -1
- package/dist/ionex-DaW5x9nq.d.cts +23 -0
- package/dist/ionex-DaW5x9nq.d.ts +23 -0
- package/dist/positioning.cjs +389 -13
- package/dist/positioning.d.cts +225 -7
- package/dist/positioning.d.ts +225 -7
- package/dist/positioning.js +11 -1
- package/dist/rinex.d.cts +2 -23
- package/dist/rinex.d.ts +2 -23
- package/package.json +1 -1
|
@@ -43,6 +43,252 @@ 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/gim.ts
|
|
47
|
+
var R_E = 6371e3;
|
|
48
|
+
var H_ION = 45e4;
|
|
49
|
+
var F_L1 = 157542e4;
|
|
50
|
+
var IONO_L1_M_PER_TECU = 403e15 / (F_L1 * F_L1);
|
|
51
|
+
function tecAtMap(grid, mapIdx, latDeg, lonDeg) {
|
|
52
|
+
const m = grid.maps[mapIdx];
|
|
53
|
+
const { lats, lons } = grid;
|
|
54
|
+
const w = lons.length;
|
|
55
|
+
const fi = (latDeg - lats[0]) / (lats[lats.length - 1] - lats[0]) * (lats.length - 1);
|
|
56
|
+
const fj = (lonDeg - lons[0]) / (lons[w - 1] - lons[0]) * (w - 1);
|
|
57
|
+
const i0 = Math.max(0, Math.min(lats.length - 2, Math.floor(fi)));
|
|
58
|
+
const j0 = Math.max(0, Math.min(w - 2, Math.floor(fj)));
|
|
59
|
+
const di = Math.max(0, Math.min(1, fi - i0));
|
|
60
|
+
const dj = Math.max(0, Math.min(1, fj - j0));
|
|
61
|
+
return m[i0 * w + j0] * (1 - di) * (1 - dj) + m[i0 * w + j0 + 1] * (1 - di) * dj + m[(i0 + 1) * w + j0] * di * (1 - dj) + m[(i0 + 1) * w + j0 + 1] * di * dj;
|
|
62
|
+
}
|
|
63
|
+
function gimVerticalTec(grid, timeMs, latDeg, lonDeg) {
|
|
64
|
+
const e = grid.epochs;
|
|
65
|
+
if (e.length === 0 || timeMs < e[0] || timeMs > e[e.length - 1]) return null;
|
|
66
|
+
let i = 0;
|
|
67
|
+
while (i < e.length - 2 && e[i + 1] <= timeMs) i++;
|
|
68
|
+
const span = e[i + 1] - e[i];
|
|
69
|
+
const f = span > 0 ? (timeMs - e[i]) / span : 0;
|
|
70
|
+
const a = tecAtMap(grid, i, latDeg, lonDeg);
|
|
71
|
+
const b = tecAtMap(grid, i + 1, latDeg, lonDeg);
|
|
72
|
+
if (!Number.isFinite(a) || !Number.isFinite(b)) return null;
|
|
73
|
+
return a * (1 - f) + b * f;
|
|
74
|
+
}
|
|
75
|
+
function gimSlantIonoDelayL1(grid, latRad, lonRad, azRad, elRad, timeMs) {
|
|
76
|
+
if (elRad <= 0) return null;
|
|
77
|
+
const sinZp = R_E / (R_E + H_ION) * Math.cos(elRad);
|
|
78
|
+
const mapping = 1 / Math.sqrt(1 - sinZp * sinZp);
|
|
79
|
+
const psi = Math.PI / 2 - elRad - Math.asin(sinZp);
|
|
80
|
+
const latI = Math.asin(
|
|
81
|
+
Math.sin(latRad) * Math.cos(psi) + Math.cos(latRad) * Math.sin(psi) * Math.cos(azRad)
|
|
82
|
+
);
|
|
83
|
+
const lonI = lonRad + Math.asin(Math.sin(psi) * Math.sin(azRad) / Math.cos(latI));
|
|
84
|
+
const latDeg = latI * 180 / Math.PI;
|
|
85
|
+
const lonDeg = ((lonI * 180 / Math.PI + 540) % 360 + 360) % 360 - 180;
|
|
86
|
+
const vtec = gimVerticalTec(grid, timeMs, latDeg, lonDeg);
|
|
87
|
+
if (vtec === null) return null;
|
|
88
|
+
return IONO_L1_M_PER_TECU * vtec * mapping;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/positioning/lambda.ts
|
|
92
|
+
var LOOPMAX = 1e4;
|
|
93
|
+
var ROUND = (x) => Math.floor(x + 0.5);
|
|
94
|
+
var SGN = (x) => x <= 0 ? -1 : 1;
|
|
95
|
+
function ldFactor(n, Q, L, D) {
|
|
96
|
+
const A = Float64Array.from(Q);
|
|
97
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
98
|
+
D[i] = A[i + i * n];
|
|
99
|
+
if (D[i] <= 0) return false;
|
|
100
|
+
const a = Math.sqrt(D[i]);
|
|
101
|
+
for (let j = 0; j <= i; j++) L[i + j * n] = A[i + j * n] / a;
|
|
102
|
+
for (let j = 0; j <= i - 1; j++)
|
|
103
|
+
for (let k = 0; k <= j; k++) A[j + k * n] -= L[i + k * n] * L[i + j * n];
|
|
104
|
+
for (let j = 0; j <= i; j++) L[i + j * n] /= L[i + i * n];
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
function gauss(n, L, Z, i, j) {
|
|
109
|
+
const mu = ROUND(L[i + j * n]);
|
|
110
|
+
if (mu !== 0) {
|
|
111
|
+
for (let k = i; k < n; k++) L[k + n * j] -= mu * L[k + i * n];
|
|
112
|
+
for (let k = 0; k < n; k++) Z[k + n * j] -= mu * Z[k + i * n];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function perm(n, L, D, j, del, Z) {
|
|
116
|
+
const eta = D[j] / del;
|
|
117
|
+
const lam = D[j + 1] * L[j + 1 + j * n] / del;
|
|
118
|
+
D[j] = eta * D[j + 1];
|
|
119
|
+
D[j + 1] = del;
|
|
120
|
+
for (let k = 0; k <= j - 1; k++) {
|
|
121
|
+
const a0 = L[j + k * n];
|
|
122
|
+
const a1 = L[j + 1 + k * n];
|
|
123
|
+
L[j + k * n] = -L[j + 1 + j * n] * a0 + a1;
|
|
124
|
+
L[j + 1 + k * n] = eta * a0 + lam * a1;
|
|
125
|
+
}
|
|
126
|
+
L[j + 1 + j * n] = lam;
|
|
127
|
+
for (let k = j + 2; k < n; k++) {
|
|
128
|
+
const t = L[k + j * n];
|
|
129
|
+
L[k + j * n] = L[k + (j + 1) * n];
|
|
130
|
+
L[k + (j + 1) * n] = t;
|
|
131
|
+
}
|
|
132
|
+
for (let k = 0; k < n; k++) {
|
|
133
|
+
const t = Z[k + j * n];
|
|
134
|
+
Z[k + j * n] = Z[k + (j + 1) * n];
|
|
135
|
+
Z[k + (j + 1) * n] = t;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function reduction(n, L, D, Z) {
|
|
139
|
+
let j = n - 2;
|
|
140
|
+
let k = n - 2;
|
|
141
|
+
while (j >= 0) {
|
|
142
|
+
if (j <= k) for (let i = j + 1; i < n; i++) gauss(n, L, Z, i, j);
|
|
143
|
+
const del = D[j] + L[j + 1 + j * n] * L[j + 1 + j * n] * D[j + 1];
|
|
144
|
+
if (del + 1e-6 < D[j + 1]) {
|
|
145
|
+
perm(n, L, D, j, del, Z);
|
|
146
|
+
k = j;
|
|
147
|
+
j = n - 2;
|
|
148
|
+
} else j--;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function search(n, m, L, D, zs, zn, s) {
|
|
152
|
+
let nn = 0;
|
|
153
|
+
let imax = 0;
|
|
154
|
+
let maxdist = 1e99;
|
|
155
|
+
const S = new Float64Array(n * n);
|
|
156
|
+
const dist = new Float64Array(n);
|
|
157
|
+
const zb = new Float64Array(n);
|
|
158
|
+
const z = new Float64Array(n);
|
|
159
|
+
const step = new Float64Array(n);
|
|
160
|
+
let k = n - 1;
|
|
161
|
+
dist[k] = 0;
|
|
162
|
+
zb[k] = zs[k];
|
|
163
|
+
z[k] = ROUND(zb[k]);
|
|
164
|
+
let y = zb[k] - z[k];
|
|
165
|
+
step[k] = SGN(y);
|
|
166
|
+
let c = 0;
|
|
167
|
+
for (; c < LOOPMAX; c++) {
|
|
168
|
+
const newdist = dist[k] + y * y / D[k];
|
|
169
|
+
if (newdist < maxdist) {
|
|
170
|
+
if (k !== 0) {
|
|
171
|
+
dist[--k] = newdist;
|
|
172
|
+
for (let i = 0; i <= k; i++)
|
|
173
|
+
S[k + i * n] = S[k + 1 + i * n] + (z[k + 1] - zb[k + 1]) * L[k + 1 + i * n];
|
|
174
|
+
zb[k] = zs[k] + S[k + k * n];
|
|
175
|
+
z[k] = ROUND(zb[k]);
|
|
176
|
+
y = zb[k] - z[k];
|
|
177
|
+
step[k] = SGN(y);
|
|
178
|
+
} else {
|
|
179
|
+
if (nn < m) {
|
|
180
|
+
if (nn === 0 || newdist > s[imax]) imax = nn;
|
|
181
|
+
for (let i = 0; i < n; i++) zn[i + nn * n] = z[i];
|
|
182
|
+
s[nn++] = newdist;
|
|
183
|
+
} else {
|
|
184
|
+
if (newdist < s[imax]) {
|
|
185
|
+
for (let i = 0; i < n; i++) zn[i + imax * n] = z[i];
|
|
186
|
+
s[imax] = newdist;
|
|
187
|
+
imax = 0;
|
|
188
|
+
for (let i = 0; i < m; i++) if (s[imax] < s[i]) imax = i;
|
|
189
|
+
}
|
|
190
|
+
maxdist = s[imax];
|
|
191
|
+
}
|
|
192
|
+
z[0] += step[0];
|
|
193
|
+
y = zb[0] - z[0];
|
|
194
|
+
step[0] = -step[0] - SGN(step[0]);
|
|
195
|
+
}
|
|
196
|
+
} else {
|
|
197
|
+
if (k === n - 1) break;
|
|
198
|
+
k++;
|
|
199
|
+
z[k] += step[k];
|
|
200
|
+
y = zb[k] - z[k];
|
|
201
|
+
step[k] = -step[k] - SGN(step[k]);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
for (let i = 0; i < m - 1; i++) {
|
|
205
|
+
for (let j = i + 1; j < m; j++) {
|
|
206
|
+
if (s[i] < s[j]) continue;
|
|
207
|
+
const t = s[i];
|
|
208
|
+
s[i] = s[j];
|
|
209
|
+
s[j] = t;
|
|
210
|
+
for (let l = 0; l < n; l++) {
|
|
211
|
+
const u = zn[l + i * n];
|
|
212
|
+
zn[l + i * n] = zn[l + j * n];
|
|
213
|
+
zn[l + j * n] = u;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return c < LOOPMAX;
|
|
218
|
+
}
|
|
219
|
+
function solveZt(n, m, Z, E) {
|
|
220
|
+
const w = n + m;
|
|
221
|
+
const M = new Float64Array(n * w);
|
|
222
|
+
for (let r = 0; r < n; r++) {
|
|
223
|
+
for (let cIdx = 0; cIdx < n; cIdx++) M[r * w + cIdx] = Z[cIdx + r * n];
|
|
224
|
+
for (let cIdx = 0; cIdx < m; cIdx++) M[r * w + n + cIdx] = E[r + cIdx * n];
|
|
225
|
+
}
|
|
226
|
+
for (let col = 0; col < n; col++) {
|
|
227
|
+
let piv = col;
|
|
228
|
+
for (let r = col + 1; r < n; r++)
|
|
229
|
+
if (Math.abs(M[r * w + col]) > Math.abs(M[piv * w + col])) piv = r;
|
|
230
|
+
if (Math.abs(M[piv * w + col]) < 1e-12) return null;
|
|
231
|
+
if (piv !== col) {
|
|
232
|
+
for (let cIdx = col; cIdx < w; cIdx++) {
|
|
233
|
+
const t = M[col * w + cIdx];
|
|
234
|
+
M[col * w + cIdx] = M[piv * w + cIdx];
|
|
235
|
+
M[piv * w + cIdx] = t;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
const d = M[col * w + col];
|
|
239
|
+
for (let cIdx = col; cIdx < w; cIdx++) M[col * w + cIdx] /= d;
|
|
240
|
+
for (let r = 0; r < n; r++) {
|
|
241
|
+
if (r === col) continue;
|
|
242
|
+
const f = M[r * w + col];
|
|
243
|
+
if (f === 0) continue;
|
|
244
|
+
for (let cIdx = col; cIdx < w; cIdx++)
|
|
245
|
+
M[r * w + cIdx] -= f * M[col * w + cIdx];
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const X = new Float64Array(n * m);
|
|
249
|
+
for (let r = 0; r < n; r++)
|
|
250
|
+
for (let cIdx = 0; cIdx < m; cIdx++) X[r + cIdx * n] = M[r * w + n + cIdx];
|
|
251
|
+
return X;
|
|
252
|
+
}
|
|
253
|
+
function lambdaSearch(a, Q, n, m = 2) {
|
|
254
|
+
if (n <= 0 || m <= 0 || a.length < n || Q.length < n * n) return null;
|
|
255
|
+
const L = new Float64Array(n * n);
|
|
256
|
+
const D = new Float64Array(n);
|
|
257
|
+
if (!ldFactor(n, Q, L, D)) return null;
|
|
258
|
+
const Z = new Float64Array(n * n);
|
|
259
|
+
for (let i = 0; i < n; i++) Z[i + i * n] = 1;
|
|
260
|
+
reduction(n, L, D, Z);
|
|
261
|
+
const z = new Float64Array(n);
|
|
262
|
+
for (let j = 0; j < n; j++) {
|
|
263
|
+
let sum = 0;
|
|
264
|
+
for (let k = 0; k < n; k++) sum += Z[k + j * n] * a[k];
|
|
265
|
+
z[j] = sum;
|
|
266
|
+
}
|
|
267
|
+
const E = new Float64Array(n * m);
|
|
268
|
+
const s = new Float64Array(m);
|
|
269
|
+
if (!search(n, m, L, D, z, E, s)) return null;
|
|
270
|
+
const F = solveZt(n, m, Z, E);
|
|
271
|
+
if (!F) return null;
|
|
272
|
+
const candidates = [];
|
|
273
|
+
for (let c = 0; c < m; c++) {
|
|
274
|
+
const v = new Float64Array(n);
|
|
275
|
+
for (let i = 0; i < n; i++) v[i] = ROUND(F[i + c * n]);
|
|
276
|
+
candidates.push(v);
|
|
277
|
+
}
|
|
278
|
+
const ratio = m >= 2 && s[0] > 0 ? s[1] / s[0] : Infinity;
|
|
279
|
+
return { candidates, residuals: s, ratio };
|
|
280
|
+
}
|
|
281
|
+
function lambdaReduction(Q, n) {
|
|
282
|
+
if (n <= 0 || Q.length < n * n) return null;
|
|
283
|
+
const L = new Float64Array(n * n);
|
|
284
|
+
const D = new Float64Array(n);
|
|
285
|
+
if (!ldFactor(n, Q, L, D)) return null;
|
|
286
|
+
const Z = new Float64Array(n * n);
|
|
287
|
+
for (let i = 0; i < n; i++) Z[i + i * n] = 1;
|
|
288
|
+
reduction(n, L, D, Z);
|
|
289
|
+
return Z;
|
|
290
|
+
}
|
|
291
|
+
|
|
46
292
|
// src/positioning/rtk.ts
|
|
47
293
|
var L1_CODES = {
|
|
48
294
|
G: ["1C"],
|
|
@@ -403,7 +649,13 @@ var RtkFloatEngine = class {
|
|
|
403
649
|
maxGapMs: opts.maxGapMs ?? 1e4,
|
|
404
650
|
codeGateM: opts.codeGateM ?? 30,
|
|
405
651
|
slipGateM: opts.slipGateM ?? 5,
|
|
406
|
-
updateIterations: opts.updateIterations ?? 2
|
|
652
|
+
updateIterations: opts.updateIterations ?? 2,
|
|
653
|
+
ambiguityResolution: opts.ambiguityResolution ?? "off",
|
|
654
|
+
ratioThreshold: opts.ratioThreshold ?? 3,
|
|
655
|
+
arElevationMaskDeg: opts.arElevationMaskDeg ?? 0,
|
|
656
|
+
glonassAr: opts.glonassAr ?? false,
|
|
657
|
+
partialFixing: opts.partialFixing ?? true,
|
|
658
|
+
minFixAmbiguities: opts.minFixAmbiguities ?? 4
|
|
407
659
|
};
|
|
408
660
|
}
|
|
409
661
|
/** Clear all filter state (position, ambiguities, lock history). */
|
|
@@ -461,6 +713,56 @@ var RtkFloatEngine = class {
|
|
|
461
713
|
const entry = this.amb[newRefIdx];
|
|
462
714
|
entry.prn = oldRef;
|
|
463
715
|
}
|
|
716
|
+
/**
|
|
717
|
+
* Try to fix the ambiguity subset `idxs` (indices into `this.amb`):
|
|
718
|
+
* extract the float subvector b and covariance Q_b from the filter,
|
|
719
|
+
* run MLAMBDA and, without touching the filter state, condition the
|
|
720
|
+
* position on the best integer candidate,
|
|
721
|
+
* xa = x − P_xb·Q_b⁻¹·(b − ǎ)
|
|
722
|
+
* (RTKLIB rtkpos.c `resamb_LAMBDA`). Returns null when Q_b is not
|
|
723
|
+
* positive definite / invertible or the search fails; ratio
|
|
724
|
+
* validation is the caller's job.
|
|
725
|
+
*/
|
|
726
|
+
tryFix(idxs) {
|
|
727
|
+
const k = idxs.length;
|
|
728
|
+
const b = new Float64Array(k);
|
|
729
|
+
const Qb = new Float64Array(k * k);
|
|
730
|
+
const QbRows = [];
|
|
731
|
+
for (let i = 0; i < k; i++) {
|
|
732
|
+
const si = 3 + idxs[i];
|
|
733
|
+
b[i] = this.x[si];
|
|
734
|
+
const row = [];
|
|
735
|
+
for (let j = 0; j < k; j++) {
|
|
736
|
+
const sj = 3 + idxs[j];
|
|
737
|
+
const q = (this.P[si][sj] + this.P[sj][si]) / 2;
|
|
738
|
+
Qb[i + j * k] = q;
|
|
739
|
+
row.push(q);
|
|
740
|
+
}
|
|
741
|
+
QbRows.push(row);
|
|
742
|
+
}
|
|
743
|
+
const res = lambdaSearch(b, Qb, k, 2);
|
|
744
|
+
if (!res) return null;
|
|
745
|
+
const best = res.candidates[0];
|
|
746
|
+
const QbInv = matInv(QbRows);
|
|
747
|
+
if (!QbInv) return null;
|
|
748
|
+
const db = [];
|
|
749
|
+
for (let i = 0; i < k; i++) db.push(b[i] - best[i]);
|
|
750
|
+
const position = [
|
|
751
|
+
this.x[0],
|
|
752
|
+
this.x[1],
|
|
753
|
+
this.x[2]
|
|
754
|
+
];
|
|
755
|
+
for (let r = 0; r < 3; r++) {
|
|
756
|
+
let dx = 0;
|
|
757
|
+
for (let i = 0; i < k; i++) {
|
|
758
|
+
let yi = 0;
|
|
759
|
+
for (let j = 0; j < k; j++) yi += QbInv[i][j] * db[j];
|
|
760
|
+
dx += this.P[r][3 + idxs[i]] * yi;
|
|
761
|
+
}
|
|
762
|
+
position[r] -= dx;
|
|
763
|
+
}
|
|
764
|
+
return { ratio: res.ratio, position, intAmb: [...best] };
|
|
765
|
+
}
|
|
464
766
|
/**
|
|
465
767
|
* Process one synchronized epoch (same nominal `timeMs` for both
|
|
466
768
|
* receivers). Returns null until a first position can be
|
|
@@ -711,6 +1013,47 @@ var RtkFloatEngine = class {
|
|
|
711
1013
|
Pnew[j][i] = s;
|
|
712
1014
|
}
|
|
713
1015
|
this.P = Pnew;
|
|
1016
|
+
let status = rows.some(
|
|
1017
|
+
(r) => r.kind === "phase"
|
|
1018
|
+
) ? "float" : "dgnss";
|
|
1019
|
+
let ratio;
|
|
1020
|
+
let nFixed;
|
|
1021
|
+
let fixedPos = null;
|
|
1022
|
+
let fixedAmbiguities;
|
|
1023
|
+
if (o.ambiguityResolution === "instant") {
|
|
1024
|
+
const cands = [];
|
|
1025
|
+
for (const row of rows) {
|
|
1026
|
+
if (row.kind !== "phase") continue;
|
|
1027
|
+
if (row.g.prn[0] === "R" && !o.glonassAr) continue;
|
|
1028
|
+
if (row.g.elB < o.arElevationMaskDeg * Math.PI / 180) continue;
|
|
1029
|
+
cands.push({ idx: row.ambIdx, el: row.g.elB });
|
|
1030
|
+
}
|
|
1031
|
+
cands.sort((a, b) => b.el - a.el);
|
|
1032
|
+
const floor = Math.max(
|
|
1033
|
+
o.minFixAmbiguities,
|
|
1034
|
+
Math.ceil(cands.length / 2),
|
|
1035
|
+
1
|
|
1036
|
+
);
|
|
1037
|
+
while (cands.length >= floor) {
|
|
1038
|
+
const fix = this.tryFix(cands.map((c) => c.idx));
|
|
1039
|
+
if (!fix) break;
|
|
1040
|
+
const capped = Math.min(fix.ratio, 999.9);
|
|
1041
|
+
ratio ??= capped;
|
|
1042
|
+
if (fix.ratio >= o.ratioThreshold) {
|
|
1043
|
+
ratio = capped;
|
|
1044
|
+
status = "fixed";
|
|
1045
|
+
nFixed = cands.length;
|
|
1046
|
+
fixedPos = fix.position;
|
|
1047
|
+
fixedAmbiguities = {};
|
|
1048
|
+
cands.forEach((c, i) => {
|
|
1049
|
+
fixedAmbiguities[this.amb[c.idx].prn] = fix.intAmb[i];
|
|
1050
|
+
});
|
|
1051
|
+
break;
|
|
1052
|
+
}
|
|
1053
|
+
if (!o.partialFixing) break;
|
|
1054
|
+
cands.pop();
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
714
1057
|
for (const g of geom) {
|
|
715
1058
|
if (g.cpR === null || g.cpB === null) continue;
|
|
716
1059
|
this.track.set(g.prn, { lockR: g.lockR, lockB: g.lockB, lastMs: timeMs });
|
|
@@ -724,14 +1067,22 @@ var RtkFloatEngine = class {
|
|
|
724
1067
|
const nSats = new Set(rows.flatMap((r) => [r.g.prn, r.ref.prn])).size;
|
|
725
1068
|
return {
|
|
726
1069
|
timeMs,
|
|
727
|
-
position: [this.x[0], this.x[1], this.x[2]],
|
|
1070
|
+
position: fixedPos ?? [this.x[0], this.x[1], this.x[2]],
|
|
728
1071
|
floatBaseline: [
|
|
729
1072
|
this.x[0] - this.basePos[0],
|
|
730
1073
|
this.x[1] - this.basePos[1],
|
|
731
1074
|
this.x[2] - this.basePos[2]
|
|
732
1075
|
],
|
|
1076
|
+
status,
|
|
733
1077
|
nSats,
|
|
734
|
-
ratio
|
|
1078
|
+
ratio,
|
|
1079
|
+
nFixed,
|
|
1080
|
+
fixedBaseline: fixedPos ? [
|
|
1081
|
+
fixedPos[0] - this.basePos[0],
|
|
1082
|
+
fixedPos[1] - this.basePos[1],
|
|
1083
|
+
fixedPos[2] - this.basePos[2]
|
|
1084
|
+
] : void 0,
|
|
1085
|
+
fixedAmbiguities,
|
|
735
1086
|
sigmas: [
|
|
736
1087
|
Math.sqrt(Math.max(this.P[0][0], 0)),
|
|
737
1088
|
Math.sqrt(Math.max(this.P[1][1], 0)),
|
|
@@ -778,10 +1129,17 @@ var PRIMARY_FREQ_HZ = {
|
|
|
778
1129
|
C: 1561098e3,
|
|
779
1130
|
R: 1602e6
|
|
780
1131
|
};
|
|
781
|
-
var
|
|
782
|
-
function tropoDelay2(elevationRad) {
|
|
783
|
-
|
|
784
|
-
|
|
1132
|
+
var F_L12 = 157542e4;
|
|
1133
|
+
function tropoDelay2(elevationRad, latRad, heightM) {
|
|
1134
|
+
if (elevationRad <= 0) return 0;
|
|
1135
|
+
const h = heightM < 0 ? 0 : heightM > 1e4 ? 1e4 : heightM;
|
|
1136
|
+
const humi = 0.7;
|
|
1137
|
+
const pres = 1013.25 * Math.pow(1 - 22557e-9 * h, 5.2568);
|
|
1138
|
+
const temp = 15 - 65e-4 * h + 273.16;
|
|
1139
|
+
const e = 6.108 * humi * Math.exp((17.15 * temp - 4684) / (temp - 38.45));
|
|
1140
|
+
const zhd = 22768e-7 * pres / (1 - 266e-5 * Math.cos(2 * latRad) - 28e-5 * (h / 1e3));
|
|
1141
|
+
const zwd = 2277e-6 * (1255 / temp + 0.05) * e;
|
|
1142
|
+
return (zhd + zwd) / Math.sin(elevationRad);
|
|
785
1143
|
}
|
|
786
1144
|
function sagnac2(pos, travelTimeS) {
|
|
787
1145
|
const theta = OMEGA_E * travelTimeS;
|
|
@@ -814,7 +1172,8 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
814
1172
|
maxIterations = 15,
|
|
815
1173
|
convergenceM = 1e-4,
|
|
816
1174
|
tgd = true,
|
|
817
|
-
iono
|
|
1175
|
+
iono,
|
|
1176
|
+
gim
|
|
818
1177
|
} = opts;
|
|
819
1178
|
const gpsTow = (timeMs - GPS_EPOCH_MS_SPP) / 1e3 % 604800;
|
|
820
1179
|
const all = [...pseudoranges.keys()].filter((p) => ephemerides.has(p));
|
|
@@ -841,7 +1200,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
841
1200
|
let rows = 0;
|
|
842
1201
|
for (const k of Object.keys(residuals2)) delete residuals2[k];
|
|
843
1202
|
const positionSaneIter = x2 * x2 + y2 * y2 + z2 * z2 > 1e12;
|
|
844
|
-
const [rxLat, rxLon] = positionSaneIter ? ecefToGeodetic(x2, y2, z2) : [0, 0];
|
|
1203
|
+
const [rxLat, rxLon, rxHgt] = positionSaneIter ? ecefToGeodetic(x2, y2, z2) : [0, 0, 0];
|
|
845
1204
|
for (const prn of prns) {
|
|
846
1205
|
const psr = pseudoranges.get(prn);
|
|
847
1206
|
const eph = ephemerides.get(prn);
|
|
@@ -871,11 +1230,18 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
871
1230
|
const sinEl = Math.max(Math.sin(elev), 0.1);
|
|
872
1231
|
weight = sinEl * sinEl;
|
|
873
1232
|
}
|
|
874
|
-
const tropo = troposphere && positionSane ? tropoDelay2(elev) : 0;
|
|
1233
|
+
const tropo = troposphere && positionSane ? tropoDelay2(elev, rxLat, rxHgt) : 0;
|
|
875
1234
|
let ionoM = 0;
|
|
876
|
-
if (iono && positionSane) {
|
|
877
|
-
|
|
878
|
-
|
|
1235
|
+
if ((gim || iono) && positionSane) {
|
|
1236
|
+
let l1M = null;
|
|
1237
|
+
if (gim) l1M = gimSlantIonoDelayL1(gim, rxLat, rxLon, azim, elev, timeMs);
|
|
1238
|
+
if (l1M === null && iono) {
|
|
1239
|
+
l1M = C_LIGHT * klobucharDelay(iono, rxLat, rxLon, azim, elev, gpsTow);
|
|
1240
|
+
}
|
|
1241
|
+
if (l1M !== null) {
|
|
1242
|
+
const f = PRIMARY_FREQ_HZ[sys] ?? F_L12;
|
|
1243
|
+
ionoM = l1M * (F_L12 / f * (F_L12 / f));
|
|
1244
|
+
}
|
|
879
1245
|
}
|
|
880
1246
|
const predicted = rho + clk - C_LIGHT * dts + tropo + ionoM;
|
|
881
1247
|
const v = psr - predicted;
|
|
@@ -957,6 +1323,11 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
957
1323
|
|
|
958
1324
|
export {
|
|
959
1325
|
klobucharDelay,
|
|
1326
|
+
IONO_L1_M_PER_TECU,
|
|
1327
|
+
gimVerticalTec,
|
|
1328
|
+
gimSlantIonoDelayL1,
|
|
1329
|
+
lambdaSearch,
|
|
1330
|
+
lambdaReduction,
|
|
960
1331
|
toRtkEpoch,
|
|
961
1332
|
solveDgnss,
|
|
962
1333
|
RtkFloatEngine,
|