gnss-js 1.47.0 → 1.49.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-ROVSSEGZ.js → chunk-2IM5JYKP.js} +1 -1
- package/dist/{chunk-EQNC24OB.js → chunk-DEVUKH6A.js} +2 -1
- package/dist/{chunk-75OYCNTY.js → chunk-DWLVCXA6.js} +516 -11
- package/dist/{chunk-ZIGMN3E5.js → chunk-WQX354KD.js} +1 -0
- package/dist/{chunk-MEDAWNWM.js → chunk-XFPDTGSV.js} +1 -1
- package/dist/index.cjs +522 -22
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +9 -7
- package/dist/novatel.js +2 -2
- package/dist/positioning.cjs +536 -14
- package/dist/positioning.d.cts +74 -1
- package/dist/positioning.d.ts +74 -1
- package/dist/positioning.js +6 -1
- package/dist/rinex.js +2 -2
- package/dist/sbf.js +2 -2
- package/dist/ubx.cjs +1 -0
- package/dist/ubx.d.cts +7 -0
- package/dist/ubx.d.ts +7 -0
- package/dist/ubx.js +2 -2
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
decodeSbasGeoNav,
|
|
11
11
|
sbasCrcOk
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-WQX354KD.js";
|
|
13
13
|
import {
|
|
14
14
|
CnavAssembler,
|
|
15
15
|
cnavCrcOk
|
|
@@ -292,6 +292,7 @@ function parseUbxRawNav(data, opts = {}) {
|
|
|
292
292
|
continue;
|
|
293
293
|
}
|
|
294
294
|
if (refWeek === 0) continue;
|
|
295
|
+
opts.onSbasMessage?.(msg, svId, refWeek, refTow);
|
|
295
296
|
const eph = decodeSbasGeoNav(msg, svId, refWeek, refTow);
|
|
296
297
|
if (eph) {
|
|
297
298
|
const key = `${eph.prn}@${eph.tocDate.getTime()}`;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sbasMessageType
|
|
3
|
+
} from "./chunk-WQX354KD.js";
|
|
1
4
|
import {
|
|
2
5
|
computeDop,
|
|
3
6
|
computeSatPosition,
|
|
@@ -13,6 +16,10 @@ import {
|
|
|
13
16
|
clkBias,
|
|
14
17
|
sp3Position
|
|
15
18
|
} from "./chunk-GPEP67TG.js";
|
|
19
|
+
import {
|
|
20
|
+
getBitS,
|
|
21
|
+
getBitU
|
|
22
|
+
} from "./chunk-V2D5KUKH.js";
|
|
16
23
|
import {
|
|
17
24
|
C_LIGHT,
|
|
18
25
|
OMEGA_E
|
|
@@ -45,8 +52,8 @@ function klobucharDelay(coeffs, latRad, lonRad, azRad, elRad, gpsTowSec) {
|
|
|
45
52
|
const F = 1 + 16 * Math.pow(0.53 - E, 3);
|
|
46
53
|
const x = 2 * Math.PI * (t - 50400) / per;
|
|
47
54
|
if (Math.abs(x) >= 1.57) return F * 5e-9;
|
|
48
|
-
const
|
|
49
|
-
return F * (5e-9 + amp * (1 -
|
|
55
|
+
const x22 = x * x;
|
|
56
|
+
return F * (5e-9 + amp * (1 - x22 / 2 + x22 * x22 / 24));
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
// src/positioning/gim.ts
|
|
@@ -1198,6 +1205,492 @@ function postProcessRtk(base, rover, ephemerides, baseEcef, opts = {}) {
|
|
|
1198
1205
|
return { track, solved, unmatched, fixRate: solved ? fixed / solved : 0 };
|
|
1199
1206
|
}
|
|
1200
1207
|
|
|
1208
|
+
// src/positioning/sbas.ts
|
|
1209
|
+
var P2_11 = 2 ** -11;
|
|
1210
|
+
var P2_31 = 2 ** -31;
|
|
1211
|
+
var P2_39 = 2 ** -39;
|
|
1212
|
+
var D2R = Math.PI / 180;
|
|
1213
|
+
var R2D = 180 / Math.PI;
|
|
1214
|
+
var SEC_PER_WEEK = 604800;
|
|
1215
|
+
var MAXSBSAGEF = 30;
|
|
1216
|
+
var MAXSBSAGEL = 1800;
|
|
1217
|
+
var MAXBAND = 10;
|
|
1218
|
+
var two = (n) => String(n).padStart(2, "0");
|
|
1219
|
+
var VAR_FCORR = [
|
|
1220
|
+
0.052,
|
|
1221
|
+
0.0924,
|
|
1222
|
+
0.1444,
|
|
1223
|
+
0.283,
|
|
1224
|
+
0.4678,
|
|
1225
|
+
0.8315,
|
|
1226
|
+
1.2992,
|
|
1227
|
+
1.8709,
|
|
1228
|
+
2.5465,
|
|
1229
|
+
3.326,
|
|
1230
|
+
5.1968,
|
|
1231
|
+
20.787,
|
|
1232
|
+
230.9661,
|
|
1233
|
+
2078.695
|
|
1234
|
+
];
|
|
1235
|
+
var varfcorr = (udre) => udre > 0 && udre <= 14 ? VAR_FCORR[udre - 1] : 0;
|
|
1236
|
+
var VAR_ICORR = [
|
|
1237
|
+
84e-4,
|
|
1238
|
+
0.0333,
|
|
1239
|
+
0.0749,
|
|
1240
|
+
0.1331,
|
|
1241
|
+
0.2079,
|
|
1242
|
+
0.2994,
|
|
1243
|
+
0.4075,
|
|
1244
|
+
0.5322,
|
|
1245
|
+
0.6735,
|
|
1246
|
+
0.8315,
|
|
1247
|
+
1.1974,
|
|
1248
|
+
1.8709,
|
|
1249
|
+
3.326,
|
|
1250
|
+
20.787,
|
|
1251
|
+
187.0826
|
|
1252
|
+
];
|
|
1253
|
+
var varicorr = (give) => give > 0 && give <= 15 ? VAR_ICORR[give - 1] : 0;
|
|
1254
|
+
var DEGF = [
|
|
1255
|
+
0,
|
|
1256
|
+
5e-5,
|
|
1257
|
+
9e-5,
|
|
1258
|
+
12e-5,
|
|
1259
|
+
15e-5,
|
|
1260
|
+
2e-4,
|
|
1261
|
+
3e-4,
|
|
1262
|
+
45e-5,
|
|
1263
|
+
6e-4,
|
|
1264
|
+
9e-4,
|
|
1265
|
+
15e-4,
|
|
1266
|
+
21e-4,
|
|
1267
|
+
27e-4,
|
|
1268
|
+
33e-4,
|
|
1269
|
+
46e-4,
|
|
1270
|
+
58e-4
|
|
1271
|
+
];
|
|
1272
|
+
var degfcorr = (ai) => ai > 0 && ai <= 15 ? DEGF[ai] : 58e-4;
|
|
1273
|
+
var x1 = [-75, -65, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 65, 75, 85];
|
|
1274
|
+
var x2 = [-55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55];
|
|
1275
|
+
var x3 = [-75, -65, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 65, 75];
|
|
1276
|
+
var x4 = [-85, -75, -65, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 65, 75];
|
|
1277
|
+
var x5 = [-180, -175, -170, -165, -160, -155, -150, -145, -140, -135, -130, -125, -120, -115, -110, -105, -100, -95, -90, -85, -80, -75, -70, -65, -60, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170, 175];
|
|
1278
|
+
var x6 = [-180, -170, -160, -150, -140, -130, -120, -110, -100, -90, -80, -70, -60, -50, -40, -30, -20, -10, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170];
|
|
1279
|
+
var x7 = [-180, -150, -120, -90, -60, -30, 0, 30, 60, 90, 120, 150];
|
|
1280
|
+
var x8 = [-170, -140, -110, -80, -50, -20, 10, 40, 70, 100, 130, 160];
|
|
1281
|
+
var igpband1 = [
|
|
1282
|
+
[{ coord: -180, arr: x1, bits: 1, bite: 28 }, { coord: -175, arr: x2, bits: 29, bite: 51 }, { coord: -170, arr: x3, bits: 52, bite: 78 }, { coord: -165, arr: x2, bits: 79, bite: 101 }, { coord: -160, arr: x3, bits: 102, bite: 128 }, { coord: -155, arr: x2, bits: 129, bite: 151 }, { coord: -150, arr: x3, bits: 152, bite: 178 }, { coord: -145, arr: x2, bits: 179, bite: 201 }],
|
|
1283
|
+
[{ coord: -140, arr: x4, bits: 1, bite: 28 }, { coord: -135, arr: x2, bits: 29, bite: 51 }, { coord: -130, arr: x3, bits: 52, bite: 78 }, { coord: -125, arr: x2, bits: 79, bite: 101 }, { coord: -120, arr: x3, bits: 102, bite: 128 }, { coord: -115, arr: x2, bits: 129, bite: 151 }, { coord: -110, arr: x3, bits: 152, bite: 178 }, { coord: -105, arr: x2, bits: 179, bite: 201 }],
|
|
1284
|
+
[{ coord: -100, arr: x3, bits: 1, bite: 27 }, { coord: -95, arr: x2, bits: 28, bite: 50 }, { coord: -90, arr: x1, bits: 51, bite: 78 }, { coord: -85, arr: x2, bits: 79, bite: 101 }, { coord: -80, arr: x3, bits: 102, bite: 128 }, { coord: -75, arr: x2, bits: 129, bite: 151 }, { coord: -70, arr: x3, bits: 152, bite: 178 }, { coord: -65, arr: x2, bits: 179, bite: 201 }],
|
|
1285
|
+
[{ coord: -60, arr: x3, bits: 1, bite: 27 }, { coord: -55, arr: x2, bits: 28, bite: 50 }, { coord: -50, arr: x4, bits: 51, bite: 78 }, { coord: -45, arr: x2, bits: 79, bite: 101 }, { coord: -40, arr: x3, bits: 102, bite: 128 }, { coord: -35, arr: x2, bits: 129, bite: 151 }, { coord: -30, arr: x3, bits: 152, bite: 178 }, { coord: -25, arr: x2, bits: 179, bite: 201 }],
|
|
1286
|
+
[{ coord: -20, arr: x3, bits: 1, bite: 27 }, { coord: -15, arr: x2, bits: 28, bite: 50 }, { coord: -10, arr: x3, bits: 51, bite: 77 }, { coord: -5, arr: x2, bits: 78, bite: 100 }, { coord: 0, arr: x1, bits: 101, bite: 128 }, { coord: 5, arr: x2, bits: 129, bite: 151 }, { coord: 10, arr: x3, bits: 152, bite: 178 }, { coord: 15, arr: x2, bits: 179, bite: 201 }],
|
|
1287
|
+
[{ coord: 20, arr: x3, bits: 1, bite: 27 }, { coord: 25, arr: x2, bits: 28, bite: 50 }, { coord: 30, arr: x3, bits: 51, bite: 77 }, { coord: 35, arr: x2, bits: 78, bite: 100 }, { coord: 40, arr: x4, bits: 101, bite: 128 }, { coord: 45, arr: x2, bits: 129, bite: 151 }, { coord: 50, arr: x3, bits: 152, bite: 178 }, { coord: 55, arr: x2, bits: 179, bite: 201 }],
|
|
1288
|
+
[{ coord: 60, arr: x3, bits: 1, bite: 27 }, { coord: 65, arr: x2, bits: 28, bite: 50 }, { coord: 70, arr: x3, bits: 51, bite: 77 }, { coord: 75, arr: x2, bits: 78, bite: 100 }, { coord: 80, arr: x3, bits: 101, bite: 127 }, { coord: 85, arr: x2, bits: 128, bite: 150 }, { coord: 90, arr: x1, bits: 151, bite: 178 }, { coord: 95, arr: x2, bits: 179, bite: 201 }],
|
|
1289
|
+
[{ coord: 100, arr: x3, bits: 1, bite: 27 }, { coord: 105, arr: x2, bits: 28, bite: 50 }, { coord: 110, arr: x3, bits: 51, bite: 77 }, { coord: 115, arr: x2, bits: 78, bite: 100 }, { coord: 120, arr: x3, bits: 101, bite: 127 }, { coord: 125, arr: x2, bits: 128, bite: 150 }, { coord: 130, arr: x4, bits: 151, bite: 178 }, { coord: 135, arr: x2, bits: 179, bite: 201 }],
|
|
1290
|
+
[{ coord: 140, arr: x3, bits: 1, bite: 27 }, { coord: 145, arr: x2, bits: 28, bite: 50 }, { coord: 150, arr: x3, bits: 51, bite: 77 }, { coord: 155, arr: x2, bits: 78, bite: 100 }, { coord: 160, arr: x3, bits: 101, bite: 127 }, { coord: 165, arr: x2, bits: 128, bite: 150 }, { coord: 170, arr: x3, bits: 151, bite: 177 }, { coord: 175, arr: x2, bits: 178, bite: 200 }]
|
|
1291
|
+
];
|
|
1292
|
+
var igpband2 = [
|
|
1293
|
+
[{ coord: 60, arr: x5, bits: 1, bite: 72 }, { coord: 65, arr: x6, bits: 73, bite: 108 }, { coord: 70, arr: x6, bits: 109, bite: 144 }, { coord: 75, arr: x6, bits: 145, bite: 180 }, { coord: 85, arr: x7, bits: 181, bite: 192 }],
|
|
1294
|
+
[{ coord: -60, arr: x5, bits: 1, bite: 72 }, { coord: -65, arr: x6, bits: 73, bite: 108 }, { coord: -70, arr: x6, bits: 109, bite: 144 }, { coord: -75, arr: x6, bits: 145, bite: 180 }, { coord: -85, arr: x8, bits: 181, bite: 192 }]
|
|
1295
|
+
];
|
|
1296
|
+
var gpsSeconds = (week, tow) => week * SEC_PER_WEEK + tow;
|
|
1297
|
+
function maskPrn(i) {
|
|
1298
|
+
if (i >= 1 && i <= 37) return `G${two(i)}`;
|
|
1299
|
+
if (i >= 38 && i <= 61) return `R${two(i - 37)}`;
|
|
1300
|
+
if (i >= 120 && i <= 138) return `S${two(i - 100)}`;
|
|
1301
|
+
if (i >= 193 && i <= 202) return `J${two(i - 192)}`;
|
|
1302
|
+
return null;
|
|
1303
|
+
}
|
|
1304
|
+
function ionppp(latRad, lonRad, azRad, elRad, re, hion) {
|
|
1305
|
+
const rp = re / (re + hion) * Math.cos(elRad);
|
|
1306
|
+
const ap = Math.PI / 2 - elRad - Math.asin(rp);
|
|
1307
|
+
const sinap = Math.sin(ap);
|
|
1308
|
+
const tanap = Math.tan(ap);
|
|
1309
|
+
const cosaz = Math.cos(azRad);
|
|
1310
|
+
const latP = Math.asin(
|
|
1311
|
+
Math.sin(latRad) * Math.cos(ap) + Math.cos(latRad) * sinap * cosaz
|
|
1312
|
+
);
|
|
1313
|
+
let lonP;
|
|
1314
|
+
if (latRad > 70 * D2R && tanap * cosaz > Math.tan(Math.PI / 2 - latRad) || latRad < -70 * D2R && -tanap * cosaz > Math.tan(Math.PI / 2 + latRad)) {
|
|
1315
|
+
lonP = lonRad + Math.PI - Math.asin(sinap * Math.sin(azRad) / Math.cos(latP));
|
|
1316
|
+
} else {
|
|
1317
|
+
lonP = lonRad + Math.asin(sinap * Math.sin(azRad) / Math.cos(latP));
|
|
1318
|
+
}
|
|
1319
|
+
return { fp: 1 / Math.sqrt(1 - rp * rp), latP, lonP };
|
|
1320
|
+
}
|
|
1321
|
+
var SbasProcessor = class {
|
|
1322
|
+
sats = [];
|
|
1323
|
+
satIdx = /* @__PURE__ */ new Map();
|
|
1324
|
+
iodp = -1;
|
|
1325
|
+
tlat = 0;
|
|
1326
|
+
ion = [];
|
|
1327
|
+
/** GEO PRN(s) whose messages have been ingested. */
|
|
1328
|
+
geoPrns = /* @__PURE__ */ new Set();
|
|
1329
|
+
/**
|
|
1330
|
+
* Ingest one decoded SBAS L1 message (250-bit, MSB-first) received at the
|
|
1331
|
+
* given GPS week / time-of-week. Returns the message type, or -1 if it was
|
|
1332
|
+
* not a recognised/applicable correction message.
|
|
1333
|
+
*/
|
|
1334
|
+
update(msg, week, tow, geoPrn) {
|
|
1335
|
+
if (week === 0) return -1;
|
|
1336
|
+
const type = sbasMessageType(msg);
|
|
1337
|
+
if (geoPrn != null && geoPrn >= 120 && geoPrn <= 158)
|
|
1338
|
+
this.geoPrns.add(`S${two(geoPrn - 100)}`);
|
|
1339
|
+
switch (type) {
|
|
1340
|
+
case 1:
|
|
1341
|
+
return this.decodeMask(msg) ? type : -1;
|
|
1342
|
+
case 0:
|
|
1343
|
+
case 2:
|
|
1344
|
+
case 3:
|
|
1345
|
+
case 4:
|
|
1346
|
+
case 5:
|
|
1347
|
+
return this.decodeFast(msg, type, week, tow) ? type : -1;
|
|
1348
|
+
case 6:
|
|
1349
|
+
return this.decodeIntegrity(msg) ? type : -1;
|
|
1350
|
+
case 7:
|
|
1351
|
+
return this.decodeDegradation(msg) ? type : -1;
|
|
1352
|
+
case 18:
|
|
1353
|
+
return this.decodeIgpMask(msg) ? type : -1;
|
|
1354
|
+
case 24:
|
|
1355
|
+
return this.decodeMixed(msg, week, tow) ? type : -1;
|
|
1356
|
+
case 25:
|
|
1357
|
+
return this.decodeLongCorrHalf(msg, 14, week, tow) && this.decodeLongCorrHalf(msg, 120, week, tow) ? type : -1;
|
|
1358
|
+
case 26:
|
|
1359
|
+
return this.decodeIgpDelay(msg, week, tow) ? type : -1;
|
|
1360
|
+
case 9:
|
|
1361
|
+
// GEO nav — handled by decodeSbasGeoNav elsewhere
|
|
1362
|
+
case 63:
|
|
1363
|
+
return type;
|
|
1364
|
+
default:
|
|
1365
|
+
return -1;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
decodeMask(msg) {
|
|
1369
|
+
const sats = [];
|
|
1370
|
+
for (let i = 1; i <= 210; i++) {
|
|
1371
|
+
if (getBitU(msg, 13 + i, 1)) sats.push({ prn: maskPrn(i) });
|
|
1372
|
+
}
|
|
1373
|
+
this.iodp = getBitU(msg, 224, 2);
|
|
1374
|
+
this.sats = sats;
|
|
1375
|
+
this.satIdx.clear();
|
|
1376
|
+
sats.forEach((s, k) => {
|
|
1377
|
+
if (s.prn) this.satIdx.set(s.prn, k);
|
|
1378
|
+
});
|
|
1379
|
+
return true;
|
|
1380
|
+
}
|
|
1381
|
+
decodeFast(msg, type, week, tow) {
|
|
1382
|
+
if (this.iodp !== getBitU(msg, 16, 2)) return false;
|
|
1383
|
+
const iodf = getBitU(msg, 14, 2);
|
|
1384
|
+
const t0s = gpsSeconds(week, tow);
|
|
1385
|
+
for (let i = 0; i < 13; i++) {
|
|
1386
|
+
const j = 13 * ((type === 0 ? 2 : type) - 2) + i;
|
|
1387
|
+
if (j >= this.sats.length) break;
|
|
1388
|
+
const udre = getBitU(msg, 174 + 4 * i, 4);
|
|
1389
|
+
const prc = getBitS(msg, 18 + i * 12, 12) * 0.125;
|
|
1390
|
+
const prev = this.sats[j].fcorr;
|
|
1391
|
+
this.sats[j].fcorr = {
|
|
1392
|
+
prc,
|
|
1393
|
+
udre: udre + 1,
|
|
1394
|
+
ai: prev?.ai ?? 0,
|
|
1395
|
+
iodf,
|
|
1396
|
+
t0s
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
return true;
|
|
1400
|
+
}
|
|
1401
|
+
decodeIntegrity(msg) {
|
|
1402
|
+
const iodf = [0, 1, 2, 3].map((i) => getBitU(msg, 14 + i * 2, 2));
|
|
1403
|
+
for (let i = 0; i < this.sats.length; i++) {
|
|
1404
|
+
const f = this.sats[i].fcorr;
|
|
1405
|
+
if (!f || f.iodf !== iodf[Math.floor(i / 13)]) continue;
|
|
1406
|
+
f.udre = getBitU(msg, 22 + i * 4, 4) + 1;
|
|
1407
|
+
}
|
|
1408
|
+
return true;
|
|
1409
|
+
}
|
|
1410
|
+
decodeDegradation(msg) {
|
|
1411
|
+
if (this.iodp !== getBitU(msg, 18, 2)) return false;
|
|
1412
|
+
this.tlat = getBitU(msg, 14, 4);
|
|
1413
|
+
for (let i = 0; i < this.sats.length; i++) {
|
|
1414
|
+
const ai = getBitU(msg, 22 + i * 4, 4);
|
|
1415
|
+
if (this.sats[i].fcorr) this.sats[i].fcorr.ai = ai;
|
|
1416
|
+
else this.sats[i].fcorr = { prc: 0, udre: 0, ai, iodf: -1, t0s: 0 };
|
|
1417
|
+
}
|
|
1418
|
+
return true;
|
|
1419
|
+
}
|
|
1420
|
+
decodeMixed(msg, week, tow) {
|
|
1421
|
+
if (this.iodp !== getBitU(msg, 110, 2)) return false;
|
|
1422
|
+
const blk = getBitU(msg, 112, 2);
|
|
1423
|
+
const iodf = getBitU(msg, 114, 2);
|
|
1424
|
+
const t0s = gpsSeconds(week, tow);
|
|
1425
|
+
for (let i = 0; i < 6; i++) {
|
|
1426
|
+
const j = 13 * blk + i;
|
|
1427
|
+
if (j >= this.sats.length) break;
|
|
1428
|
+
const udre = getBitU(msg, 86 + 4 * i, 4);
|
|
1429
|
+
const prc = getBitS(msg, 14 + i * 12, 12) * 0.125;
|
|
1430
|
+
const prev = this.sats[j].fcorr;
|
|
1431
|
+
this.sats[j].fcorr = {
|
|
1432
|
+
prc,
|
|
1433
|
+
udre: udre + 1,
|
|
1434
|
+
ai: prev?.ai ?? 0,
|
|
1435
|
+
iodf,
|
|
1436
|
+
t0s
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
return this.decodeLongCorrHalf(msg, 120, week, tow);
|
|
1440
|
+
}
|
|
1441
|
+
decodeLongCorrHalf(msg, p, week, tow) {
|
|
1442
|
+
if (getBitU(msg, p, 1) === 0) {
|
|
1443
|
+
if (this.iodp === getBitU(msg, p + 103, 2)) {
|
|
1444
|
+
const a = this.decodeLong0(msg, p + 1, week, tow);
|
|
1445
|
+
const b = this.decodeLong0(msg, p + 52, week, tow);
|
|
1446
|
+
return a || b;
|
|
1447
|
+
}
|
|
1448
|
+
} else if (this.iodp === getBitU(msg, p + 104, 2)) {
|
|
1449
|
+
return this.decodeLong1(msg, p + 1, week, tow);
|
|
1450
|
+
}
|
|
1451
|
+
return false;
|
|
1452
|
+
}
|
|
1453
|
+
decodeLong0(msg, p, week, tow) {
|
|
1454
|
+
const n = getBitU(msg, p, 6);
|
|
1455
|
+
if (n === 0 || n > this.sats.length) return false;
|
|
1456
|
+
this.sats[n - 1].lcorr = {
|
|
1457
|
+
iode: getBitU(msg, p + 6, 8),
|
|
1458
|
+
dpos: [
|
|
1459
|
+
getBitS(msg, p + 14, 9) * 0.125,
|
|
1460
|
+
getBitS(msg, p + 23, 9) * 0.125,
|
|
1461
|
+
getBitS(msg, p + 32, 9) * 0.125
|
|
1462
|
+
],
|
|
1463
|
+
dvel: [0, 0, 0],
|
|
1464
|
+
daf0: getBitS(msg, p + 41, 10) * P2_31,
|
|
1465
|
+
daf1: 0,
|
|
1466
|
+
t0s: gpsSeconds(week, tow)
|
|
1467
|
+
};
|
|
1468
|
+
return true;
|
|
1469
|
+
}
|
|
1470
|
+
decodeLong1(msg, p, week, tow) {
|
|
1471
|
+
const n = getBitU(msg, p, 6);
|
|
1472
|
+
if (n === 0 || n > this.sats.length) return false;
|
|
1473
|
+
let t = getBitU(msg, p + 90, 13) * 16 - tow % 86400;
|
|
1474
|
+
if (t <= -43200) t += 86400;
|
|
1475
|
+
else if (t > 43200) t -= 86400;
|
|
1476
|
+
this.sats[n - 1].lcorr = {
|
|
1477
|
+
iode: getBitU(msg, p + 6, 8),
|
|
1478
|
+
dpos: [
|
|
1479
|
+
getBitS(msg, p + 14, 11) * 0.125,
|
|
1480
|
+
getBitS(msg, p + 25, 11) * 0.125,
|
|
1481
|
+
getBitS(msg, p + 36, 11) * 0.125
|
|
1482
|
+
],
|
|
1483
|
+
dvel: [
|
|
1484
|
+
getBitS(msg, p + 58, 8) * P2_11,
|
|
1485
|
+
getBitS(msg, p + 66, 8) * P2_11,
|
|
1486
|
+
getBitS(msg, p + 74, 8) * P2_11
|
|
1487
|
+
],
|
|
1488
|
+
daf0: getBitS(msg, p + 47, 11) * P2_31,
|
|
1489
|
+
daf1: getBitS(msg, p + 82, 8) * P2_39,
|
|
1490
|
+
t0s: gpsSeconds(week, tow + t)
|
|
1491
|
+
};
|
|
1492
|
+
return true;
|
|
1493
|
+
}
|
|
1494
|
+
decodeIgpMask(msg) {
|
|
1495
|
+
const band = getBitU(msg, 18, 4);
|
|
1496
|
+
let p;
|
|
1497
|
+
let m;
|
|
1498
|
+
if (band <= 8) {
|
|
1499
|
+
p = igpband1[band];
|
|
1500
|
+
m = 8;
|
|
1501
|
+
} else if (band <= 10) {
|
|
1502
|
+
p = igpband2[band - 9];
|
|
1503
|
+
m = 5;
|
|
1504
|
+
} else return false;
|
|
1505
|
+
const igp = [];
|
|
1506
|
+
for (let i = 1; i <= 201; i++) {
|
|
1507
|
+
if (!getBitU(msg, 23 + i, 1)) continue;
|
|
1508
|
+
for (let j = 0; j < m; j++) {
|
|
1509
|
+
const b = p[j];
|
|
1510
|
+
if (i < b.bits || b.bite < i) continue;
|
|
1511
|
+
const varying = b.arr[i - b.bits];
|
|
1512
|
+
igp.push({
|
|
1513
|
+
lat: band <= 8 ? varying : b.coord,
|
|
1514
|
+
lon: band <= 8 ? b.coord : varying,
|
|
1515
|
+
delay: 0,
|
|
1516
|
+
give: 0,
|
|
1517
|
+
t0s: 0
|
|
1518
|
+
});
|
|
1519
|
+
break;
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
this.ion[band] = { iodi: getBitU(msg, 22, 2), igp };
|
|
1523
|
+
return true;
|
|
1524
|
+
}
|
|
1525
|
+
decodeIgpDelay(msg, week, tow) {
|
|
1526
|
+
const band = getBitU(msg, 14, 4);
|
|
1527
|
+
const b = this.ion[band];
|
|
1528
|
+
if (band > MAXBAND || !b || b.iodi !== getBitU(msg, 217, 2)) return false;
|
|
1529
|
+
const block = getBitU(msg, 18, 4);
|
|
1530
|
+
const t0s = gpsSeconds(week, tow);
|
|
1531
|
+
for (let i = 0; i < 15; i++) {
|
|
1532
|
+
const j = block * 15 + i;
|
|
1533
|
+
if (j >= b.igp.length) continue;
|
|
1534
|
+
const give = getBitU(msg, 22 + i * 13 + 9, 4);
|
|
1535
|
+
const delay = getBitU(msg, 22 + i * 13, 9);
|
|
1536
|
+
b.igp[j].delay = delay === 511 ? 0 : delay * 0.125;
|
|
1537
|
+
b.igp[j].give = give + 1 >= 16 ? 0 : give + 1;
|
|
1538
|
+
b.igp[j].t0s = t0s;
|
|
1539
|
+
}
|
|
1540
|
+
return true;
|
|
1541
|
+
}
|
|
1542
|
+
/** PRNs currently in the correction mask (in mask order). */
|
|
1543
|
+
activeSats() {
|
|
1544
|
+
return this.sats.map((s) => s.prn).filter((p) => !!p);
|
|
1545
|
+
}
|
|
1546
|
+
/** Number of ionospheric grid points with a valid delay across all bands. */
|
|
1547
|
+
ionoGridPoints() {
|
|
1548
|
+
let n = 0;
|
|
1549
|
+
for (const b of this.ion) if (b) {
|
|
1550
|
+
for (const g of b.igp) if (g.give > 0) n++;
|
|
1551
|
+
}
|
|
1552
|
+
return n;
|
|
1553
|
+
}
|
|
1554
|
+
/**
|
|
1555
|
+
* Satellite range/clock correction for a PRN at a GPS week/tow, or null if
|
|
1556
|
+
* no valid (unexpired) long-term + fast correction is available. Add `dPos`
|
|
1557
|
+
* to the satellite ECEF position and `dClkS` to its clock bias.
|
|
1558
|
+
*/
|
|
1559
|
+
satCorrection(prn, week, tow) {
|
|
1560
|
+
const idx = this.satIdx.get(prn);
|
|
1561
|
+
if (idx === void 0) return null;
|
|
1562
|
+
const s = this.sats[idx];
|
|
1563
|
+
const now = gpsSeconds(week, tow);
|
|
1564
|
+
const drs = [0, 0, 0];
|
|
1565
|
+
let dclk = 0;
|
|
1566
|
+
let iode = -1;
|
|
1567
|
+
if (s.lcorr && s.lcorr.t0s !== 0) {
|
|
1568
|
+
const t = now - s.lcorr.t0s;
|
|
1569
|
+
if (Math.abs(t) > MAXSBSAGEL) return null;
|
|
1570
|
+
for (let i = 0; i < 3; i++)
|
|
1571
|
+
drs[i] = s.lcorr.dpos[i] + s.lcorr.dvel[i] * t;
|
|
1572
|
+
dclk = s.lcorr.daf0 + s.lcorr.daf1 * t;
|
|
1573
|
+
iode = s.lcorr.iode;
|
|
1574
|
+
} else if (prn[0] !== "S") {
|
|
1575
|
+
return null;
|
|
1576
|
+
}
|
|
1577
|
+
if (!s.fcorr || s.fcorr.t0s === 0) return null;
|
|
1578
|
+
const tf = now - s.fcorr.t0s + this.tlat;
|
|
1579
|
+
if (Math.abs(tf) > MAXSBSAGEF || s.fcorr.udre >= 15) return null;
|
|
1580
|
+
const prc = s.fcorr.prc;
|
|
1581
|
+
const varM2 = varfcorr(s.fcorr.udre) + degfcorr(s.fcorr.ai) * tf * tf / 2;
|
|
1582
|
+
return { dPos: drs, dClkS: dclk + prc / C_LIGHT, prcM: prc, varM2, iode };
|
|
1583
|
+
}
|
|
1584
|
+
/**
|
|
1585
|
+
* Slant L1 ionospheric delay (m) at the pierce point for a receiver geodetic
|
|
1586
|
+
* position (lat/lon rad, height m) and a satellite az/el (rad), interpolated
|
|
1587
|
+
* from the SBAS grid — or null if the pierce point isn't covered. RTKLIB
|
|
1588
|
+
* `sbsioncorr`.
|
|
1589
|
+
*/
|
|
1590
|
+
ionoDelay(week, tow, latRad, lonRad, heightM, azRad, elRad) {
|
|
1591
|
+
if (heightM < -100 || elRad <= 0) return { delayM: 0, varM2: 0 };
|
|
1592
|
+
const { fp, latP, lonP } = ionppp(
|
|
1593
|
+
latRad,
|
|
1594
|
+
lonRad,
|
|
1595
|
+
azRad,
|
|
1596
|
+
elRad,
|
|
1597
|
+
6378.1363,
|
|
1598
|
+
350
|
|
1599
|
+
);
|
|
1600
|
+
const igp = this.searchIgp(latP, lonP);
|
|
1601
|
+
if (!igp) return null;
|
|
1602
|
+
const { pts, x, y } = igp;
|
|
1603
|
+
const w = [0, 0, 0, 0];
|
|
1604
|
+
if (pts[0] && pts[1] && pts[2] && pts[3]) {
|
|
1605
|
+
w[0] = (1 - x) * (1 - y);
|
|
1606
|
+
w[1] = (1 - x) * y;
|
|
1607
|
+
w[2] = x * (1 - y);
|
|
1608
|
+
w[3] = x * y;
|
|
1609
|
+
} else if (pts[0] && pts[1] && pts[2]) {
|
|
1610
|
+
w[1] = y;
|
|
1611
|
+
w[2] = x;
|
|
1612
|
+
w[0] = 1 - w[1] - w[2];
|
|
1613
|
+
if (w[0] < 0) return null;
|
|
1614
|
+
} else if (pts[0] && pts[2] && pts[3]) {
|
|
1615
|
+
w[0] = 1 - x;
|
|
1616
|
+
w[3] = y;
|
|
1617
|
+
w[2] = 1 - w[0] - w[3];
|
|
1618
|
+
if (w[2] < 0) return null;
|
|
1619
|
+
} else if (pts[0] && pts[1] && pts[3]) {
|
|
1620
|
+
w[0] = 1 - y;
|
|
1621
|
+
w[3] = x;
|
|
1622
|
+
w[1] = 1 - w[0] - w[3];
|
|
1623
|
+
if (w[1] < 0) return null;
|
|
1624
|
+
} else if (pts[1] && pts[2] && pts[3]) {
|
|
1625
|
+
w[1] = 1 - x;
|
|
1626
|
+
w[2] = 1 - y;
|
|
1627
|
+
w[3] = 1 - w[1] - w[2];
|
|
1628
|
+
if (w[3] < 0) return null;
|
|
1629
|
+
} else return null;
|
|
1630
|
+
const now = gpsSeconds(week, tow);
|
|
1631
|
+
let delay = 0;
|
|
1632
|
+
let varM2 = 0;
|
|
1633
|
+
for (let i = 0; i < 4; i++) {
|
|
1634
|
+
const g = pts[i];
|
|
1635
|
+
if (!g) continue;
|
|
1636
|
+
delay += w[i] * g.delay;
|
|
1637
|
+
varM2 += w[i] * varicorr(g.give) * 9e-8 * Math.abs(now - g.t0s);
|
|
1638
|
+
}
|
|
1639
|
+
return { delayM: delay * fp, varM2: varM2 * fp * fp };
|
|
1640
|
+
}
|
|
1641
|
+
/** Find the four IGPs bracketing a pierce point (RTKLIB `searchigp`). */
|
|
1642
|
+
searchIgp(latP, lonP) {
|
|
1643
|
+
const lat = latP * R2D;
|
|
1644
|
+
let lon = lonP * R2D;
|
|
1645
|
+
if (lon >= 180) lon -= 360;
|
|
1646
|
+
const latp = [0, 0];
|
|
1647
|
+
const lonp = [0, 0, 0, 0];
|
|
1648
|
+
let x;
|
|
1649
|
+
let y;
|
|
1650
|
+
if (lat >= -55 && lat < 55) {
|
|
1651
|
+
latp[0] = Math.floor(lat / 5) * 5;
|
|
1652
|
+
latp[1] = latp[0] + 5;
|
|
1653
|
+
lonp[0] = lonp[1] = Math.floor(lon / 5) * 5;
|
|
1654
|
+
lonp[2] = lonp[3] = lonp[0] + 5;
|
|
1655
|
+
x = (lon - lonp[0]) / 5;
|
|
1656
|
+
y = (lat - latp[0]) / 5;
|
|
1657
|
+
} else {
|
|
1658
|
+
latp[0] = Math.floor((lat - 5) / 10) * 10 + 5;
|
|
1659
|
+
latp[1] = latp[0] + 10;
|
|
1660
|
+
lonp[0] = lonp[1] = Math.floor(lon / 10) * 10;
|
|
1661
|
+
lonp[2] = lonp[3] = lonp[0] + 10;
|
|
1662
|
+
x = (lon - lonp[0]) / 10;
|
|
1663
|
+
y = (lat - latp[0]) / 10;
|
|
1664
|
+
if (lat >= 75 && lat < 85) {
|
|
1665
|
+
lonp[1] = Math.floor(lon / 90) * 90;
|
|
1666
|
+
lonp[3] = lonp[1] + 90;
|
|
1667
|
+
} else if (lat >= -85 && lat < -75) {
|
|
1668
|
+
lonp[0] = Math.floor((lon - 50) / 90) * 90 + 40;
|
|
1669
|
+
lonp[2] = lonp[0] + 90;
|
|
1670
|
+
} else if (lat >= 85) {
|
|
1671
|
+
for (let i = 0; i < 4; i++) lonp[i] = Math.floor(lon / 90) * 90;
|
|
1672
|
+
} else if (lat < -85) {
|
|
1673
|
+
for (let i = 0; i < 4; i++)
|
|
1674
|
+
lonp[i] = Math.floor((lon - 50) / 90) * 90 + 40;
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
for (let i = 0; i < 4; i++) if (lonp[i] === 180) lonp[i] = -180;
|
|
1678
|
+
const pts = [null, null, null, null];
|
|
1679
|
+
for (const band of this.ion) {
|
|
1680
|
+
if (!band) continue;
|
|
1681
|
+
for (const g of band.igp) {
|
|
1682
|
+
if (g.t0s === 0 || g.give <= 0) continue;
|
|
1683
|
+
if (g.lat === latp[0] && g.lon === lonp[0]) pts[0] = g;
|
|
1684
|
+
else if (g.lat === latp[1] && g.lon === lonp[1]) pts[1] = g;
|
|
1685
|
+
else if (g.lat === latp[0] && g.lon === lonp[2]) pts[2] = g;
|
|
1686
|
+
else if (g.lat === latp[1] && g.lon === lonp[3]) pts[3] = g;
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
if (!pts[0] && !pts[1] && !pts[2] && !pts[3]) return null;
|
|
1690
|
+
return { pts, x, y };
|
|
1691
|
+
}
|
|
1692
|
+
};
|
|
1693
|
+
|
|
1201
1694
|
// src/positioning/ppp-tropo.ts
|
|
1202
1695
|
var HYD_AVG_A = [
|
|
1203
1696
|
0.0012769934,
|
|
@@ -1722,11 +2215,13 @@ var IDX_Z = 2;
|
|
|
1722
2215
|
var IDX_ZWD = 3;
|
|
1723
2216
|
var NBASE = 4;
|
|
1724
2217
|
var CLK_VAR = 1e10;
|
|
2218
|
+
var POS_VAR = 60 * 60;
|
|
1725
2219
|
function solvePpp(epochs, sp3, opts) {
|
|
1726
2220
|
const elevMask = (opts.elevationMaskDeg ?? 10) * Math.PI / 180;
|
|
1727
2221
|
const codeSigma = opts.codeSigma ?? 3;
|
|
1728
2222
|
const phaseSigma = opts.phaseSigma ?? 0.01;
|
|
1729
2223
|
const ztdQ = opts.ztdProcessNoise ?? 1e-8;
|
|
2224
|
+
const kinematic = opts.mode === "kinematic";
|
|
1730
2225
|
const corrections = opts.corrections;
|
|
1731
2226
|
const x = [
|
|
1732
2227
|
opts.aprioriPos[0],
|
|
@@ -1822,6 +2317,15 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
1822
2317
|
let convergedStreak = 0;
|
|
1823
2318
|
for (let ei = 0; ei < epochs.length; ei++) {
|
|
1824
2319
|
const epoch = epochs[ei];
|
|
2320
|
+
if (kinematic && ei > 0) {
|
|
2321
|
+
for (const p of [IDX_X, IDX_Y, IDX_Z]) {
|
|
2322
|
+
for (let j = 0; j < x.length; j++) {
|
|
2323
|
+
P[p][j] = 0;
|
|
2324
|
+
P[j][p] = 0;
|
|
2325
|
+
}
|
|
2326
|
+
P[p][p] = POS_VAR;
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
1825
2329
|
for (const ci of clkIdx.values()) P[ci][ci] = CLK_VAR;
|
|
1826
2330
|
P[IDX_ZWD][IDX_ZWD] += ztdQ * (ei > 0 ? 1 : 0);
|
|
1827
2331
|
const rcv = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
|
|
@@ -2580,7 +3084,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
2580
3084
|
const systems = [...new Set(prns.map((p) => p[0]))].sort();
|
|
2581
3085
|
const dim = 3 + systems.length;
|
|
2582
3086
|
const sysIndex = new Map(systems.map((s, i) => [s, 3 + i]));
|
|
2583
|
-
let
|
|
3087
|
+
let x9 = 0;
|
|
2584
3088
|
let y2 = 0;
|
|
2585
3089
|
let z2 = 0;
|
|
2586
3090
|
const clock2 = new Map(systems.map((s) => [s, 0]));
|
|
@@ -2596,8 +3100,8 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
2596
3100
|
const Htv = new Array(dim).fill(0);
|
|
2597
3101
|
let rows = 0;
|
|
2598
3102
|
for (const k of Object.keys(residuals2)) delete residuals2[k];
|
|
2599
|
-
const positionSaneIter =
|
|
2600
|
-
const [rxLat, rxLon, rxHgt] = positionSaneIter ? ecefToGeodetic(
|
|
3103
|
+
const positionSaneIter = x9 * x9 + y2 * y2 + z2 * z2 > 1e12;
|
|
3104
|
+
const [rxLat, rxLon, rxHgt] = positionSaneIter ? ecefToGeodetic(x9, y2, z2) : [0, 0, 0];
|
|
2601
3105
|
for (const prn of prns) {
|
|
2602
3106
|
const psr = pseudoranges.get(prn);
|
|
2603
3107
|
const eph = ephemerides.get(prn);
|
|
@@ -2609,10 +3113,10 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
2609
3113
|
if (!Number.isFinite(sat.x)) continue;
|
|
2610
3114
|
const isKepler = eph.system !== "R" && eph.system !== "S";
|
|
2611
3115
|
const dts = dtsClock - (tgd && isKepler ? eph.tgd : 0);
|
|
2612
|
-
const travel = Math.hypot(sat.x -
|
|
3116
|
+
const travel = Math.hypot(sat.x - x9, sat.y - y2, sat.z - z2) / C_LIGHT;
|
|
2613
3117
|
const [sx, sy, sz] = sagnac2(sat, travel);
|
|
2614
|
-
const rho = Math.hypot(sx -
|
|
2615
|
-
const ux = (
|
|
3118
|
+
const rho = Math.hypot(sx - x9, sy - y2, sz - z2);
|
|
3119
|
+
const ux = (x9 - sx) / rho;
|
|
2616
3120
|
const uy = (y2 - sy) / rho;
|
|
2617
3121
|
const uz = (z2 - sz) / rho;
|
|
2618
3122
|
let elev = Math.PI / 2;
|
|
@@ -2620,7 +3124,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
2620
3124
|
let weight = 1;
|
|
2621
3125
|
const positionSane = positionSaneIter;
|
|
2622
3126
|
if (positionSane) {
|
|
2623
|
-
const azel = ecefToAzEl(
|
|
3127
|
+
const azel = ecefToAzEl(x9, y2, z2, sx, sy, sz);
|
|
2624
3128
|
elev = azel.el;
|
|
2625
3129
|
azim = azel.az;
|
|
2626
3130
|
if (iter >= 2 && elev < elevationMaskDeg * Math.PI / 180) continue;
|
|
@@ -2658,7 +3162,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
2658
3162
|
if (rows < dim) return null;
|
|
2659
3163
|
const dx = solveLinear(HtH, Htv);
|
|
2660
3164
|
if (!dx) return null;
|
|
2661
|
-
|
|
3165
|
+
x9 += dx[0];
|
|
2662
3166
|
y2 += dx[1];
|
|
2663
3167
|
z2 += dx[2];
|
|
2664
3168
|
for (const s of systems)
|
|
@@ -2668,7 +3172,7 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
2668
3172
|
break;
|
|
2669
3173
|
}
|
|
2670
3174
|
}
|
|
2671
|
-
return { x:
|
|
3175
|
+
return { x: x9, y: y2, z: z2, clock: clock2, residuals: residuals2, iterations: iterations2, converged: converged2 };
|
|
2672
3176
|
};
|
|
2673
3177
|
const REJECT_THRESHOLD_M = 50;
|
|
2674
3178
|
let candidates = all;
|
|
@@ -2730,6 +3234,7 @@ export {
|
|
|
2730
3234
|
solveDgnss,
|
|
2731
3235
|
RtkFloatEngine,
|
|
2732
3236
|
postProcessRtk,
|
|
3237
|
+
SbasProcessor,
|
|
2733
3238
|
niellMapping,
|
|
2734
3239
|
gmst,
|
|
2735
3240
|
sunEcef,
|