gnss-js 1.26.0 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-4KMWWCUR.js +120 -0
- package/dist/{chunk-WDUN4BWL.js → chunk-6GTS5MVI.js} +437 -118
- package/dist/{chunk-4XGKCVE3.js → chunk-O65WA6CM.js} +810 -2
- package/dist/index.cjs +1268 -19
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +24 -4
- package/dist/positioning.cjs +883 -1
- package/dist/positioning.d.cts +231 -2
- package/dist/positioning.d.ts +231 -2
- package/dist/positioning.js +18 -1
- package/dist/rinex.cjs +438 -0
- package/dist/rinex.d.cts +28 -49
- package/dist/rinex.d.ts +28 -49
- package/dist/rinex.js +7 -3
- package/dist/sp3-BAq8l39b.d.cts +70 -0
- package/dist/sp3-BAq8l39b.d.ts +70 -0
- package/package.json +1 -1
- package/dist/ionex-DaW5x9nq.d.cts +0 -23
- package/dist/ionex-DaW5x9nq.d.ts +0 -23
package/dist/index.cjs
CHANGED
|
@@ -117,6 +117,7 @@ __export(src_exports, {
|
|
|
117
117
|
binexRecords: () => binexRecords,
|
|
118
118
|
buildGloChannelMap: () => buildGloChannelMap,
|
|
119
119
|
buildObsIndices: () => buildObsIndices,
|
|
120
|
+
buildPppAntenna: () => buildPppAntenna,
|
|
120
121
|
clampUnit: () => clampUnit,
|
|
121
122
|
computeAllPositions: () => computeAllPositions,
|
|
122
123
|
computeDop: () => computeDop,
|
|
@@ -130,6 +131,7 @@ __export(src_exports, {
|
|
|
130
131
|
connectToMountpoint: () => connectToMountpoint,
|
|
131
132
|
crc32: () => crc32,
|
|
132
133
|
createGzipLineSink: () => createGzipLineSink,
|
|
134
|
+
createPppCorrections: () => createPppCorrections,
|
|
133
135
|
createStationMeta: () => createStationMeta,
|
|
134
136
|
createStreamStats: () => createStreamStats,
|
|
135
137
|
crxDecompress: () => crxDecompress,
|
|
@@ -215,6 +217,7 @@ __export(src_exports, {
|
|
|
215
217
|
glonassAlmanacEpochMs: () => glonassAlmanacEpochMs,
|
|
216
218
|
glonassAlmanacPosition: () => glonassAlmanacPosition,
|
|
217
219
|
glonassPosition: () => glonassPosition,
|
|
220
|
+
gmst: () => gmst,
|
|
218
221
|
greatCircleMidpoint: () => greatCircleMidpoint,
|
|
219
222
|
hdrLine: () => hdrLine,
|
|
220
223
|
horizonDistance: () => horizonDistance,
|
|
@@ -224,8 +227,10 @@ __export(src_exports, {
|
|
|
224
227
|
lambdaReduction: () => lambdaReduction,
|
|
225
228
|
lambdaSearch: () => lambdaSearch,
|
|
226
229
|
maskRadForAzimuth: () => maskRadForAzimuth,
|
|
230
|
+
moonEcef: () => moonEcef,
|
|
227
231
|
msmEpochToDate: () => msmEpochToDate,
|
|
228
232
|
navTimesFromEph: () => navTimesFromEph,
|
|
233
|
+
niellMapping: () => niellMapping,
|
|
229
234
|
nmeaCoordToDecimal: () => nmeaCoordToDecimal,
|
|
230
235
|
oem4Frames: () => oem4Frames,
|
|
231
236
|
padL: () => padL,
|
|
@@ -275,10 +280,13 @@ __export(src_exports, {
|
|
|
275
280
|
selectEphemeris: () => selectEphemeris,
|
|
276
281
|
setGloFreqNumber: () => setGloFreqNumber,
|
|
277
282
|
setRtcm3DebugHandler: () => setRtcm3DebugHandler,
|
|
283
|
+
solidEarthTide: () => solidEarthTide,
|
|
278
284
|
solveDgnss: () => solveDgnss,
|
|
285
|
+
solvePpp: () => solvePpp,
|
|
279
286
|
solveSpp: () => solveSpp,
|
|
280
287
|
sp3Position: () => sp3Position,
|
|
281
288
|
stationHeaderLines: () => stationHeaderLines,
|
|
289
|
+
sunEcef: () => sunEcef,
|
|
282
290
|
systemCmp: () => systemCmp,
|
|
283
291
|
systemName: () => systemName,
|
|
284
292
|
toRtkEpoch: () => toRtkEpoch,
|
|
@@ -289,6 +297,7 @@ __export(src_exports, {
|
|
|
289
297
|
updateStreamStats: () => updateStreamStats,
|
|
290
298
|
verifyChecksum: () => verifyChecksum,
|
|
291
299
|
vincenty: () => vincenty,
|
|
300
|
+
writeCrx: () => writeCrx,
|
|
292
301
|
writeModernObsBlob: () => writeModernObsBlob,
|
|
293
302
|
writeRinex2ObsBlob: () => writeRinex2ObsBlob,
|
|
294
303
|
writeRinex4ObsBlob: () => writeRinex4ObsBlob,
|
|
@@ -639,7 +648,7 @@ function getDayOfYear(date) {
|
|
|
639
648
|
(date.getTime() - Date.UTC(date.getUTCFullYear())) / MILLISECONDS_IN_DAY
|
|
640
649
|
) + 1;
|
|
641
650
|
}
|
|
642
|
-
function getDateFromDayOfYear(
|
|
651
|
+
function getDateFromDayOfYear(dayOfYear2, date) {
|
|
643
652
|
return new Date(
|
|
644
653
|
Date.UTC(
|
|
645
654
|
date.getUTCFullYear(),
|
|
@@ -649,7 +658,7 @@ function getDateFromDayOfYear(dayOfYear, date) {
|
|
|
649
658
|
date.getUTCMinutes(),
|
|
650
659
|
date.getUTCSeconds(),
|
|
651
660
|
date.getUTCMilliseconds()
|
|
652
|
-
) + (
|
|
661
|
+
) + (dayOfYear2 - 1) * MILLISECONDS_IN_DAY
|
|
653
662
|
);
|
|
654
663
|
}
|
|
655
664
|
function getDayOfWeek(date) {
|
|
@@ -1319,6 +1328,442 @@ function crxDecompress(prev, field) {
|
|
|
1319
1328
|
};
|
|
1320
1329
|
}
|
|
1321
1330
|
|
|
1331
|
+
// src/rinex/crx-writer.ts
|
|
1332
|
+
var ARC_ORDER = 3;
|
|
1333
|
+
function emptyData() {
|
|
1334
|
+
return { u: [0, 0, 0, 0], l: [0, 0, 0, 0], order: -1 };
|
|
1335
|
+
}
|
|
1336
|
+
function cAtol(s) {
|
|
1337
|
+
let i = 0;
|
|
1338
|
+
while (i < s.length && (s[i] === " " || s[i] === " ")) i++;
|
|
1339
|
+
let sign = 1;
|
|
1340
|
+
if (s[i] === "+" || s[i] === "-") {
|
|
1341
|
+
if (s[i] === "-") sign = -1;
|
|
1342
|
+
i++;
|
|
1343
|
+
}
|
|
1344
|
+
let n = 0;
|
|
1345
|
+
let any = false;
|
|
1346
|
+
while (i < s.length && s[i] >= "0" && s[i] <= "9") {
|
|
1347
|
+
n = n * 10 + (s.charCodeAt(i) - 48);
|
|
1348
|
+
i++;
|
|
1349
|
+
any = true;
|
|
1350
|
+
}
|
|
1351
|
+
return any ? sign * n : 0;
|
|
1352
|
+
}
|
|
1353
|
+
function strdiff(s1, s2) {
|
|
1354
|
+
let ds = "";
|
|
1355
|
+
const n = Math.min(s1.length, s2.length);
|
|
1356
|
+
let i = 0;
|
|
1357
|
+
for (; i < n; i++) {
|
|
1358
|
+
if (s2[i] === s1[i]) ds += " ";
|
|
1359
|
+
else if (s2[i] === " ") ds += "&";
|
|
1360
|
+
else ds += s2[i];
|
|
1361
|
+
}
|
|
1362
|
+
if (s1.length > s2.length) {
|
|
1363
|
+
for (let k = i; k < s1.length; k++) ds += s1[k] === " " ? " " : "&";
|
|
1364
|
+
} else if (s2.length > s1.length) {
|
|
1365
|
+
ds += s2.slice(i);
|
|
1366
|
+
}
|
|
1367
|
+
let end = ds.length;
|
|
1368
|
+
while (end > 0 && ds[end - 1] === " ") end--;
|
|
1369
|
+
return ds.slice(0, end);
|
|
1370
|
+
}
|
|
1371
|
+
function readValue(field14) {
|
|
1372
|
+
const c = field14.padEnd(14, " ").split("");
|
|
1373
|
+
const p7 = c[7];
|
|
1374
|
+
c[10] = c[9];
|
|
1375
|
+
c[9] = c[8];
|
|
1376
|
+
let l = cAtol(c.slice(9, 14).join(""));
|
|
1377
|
+
let u;
|
|
1378
|
+
if (p7 === " ") {
|
|
1379
|
+
u = 0;
|
|
1380
|
+
} else if (p7 === "-") {
|
|
1381
|
+
u = 0;
|
|
1382
|
+
l = -l;
|
|
1383
|
+
} else {
|
|
1384
|
+
c[8] = ".";
|
|
1385
|
+
u = cAtol(c.slice(0, 14).join(""));
|
|
1386
|
+
if (u < 0) l = -l;
|
|
1387
|
+
}
|
|
1388
|
+
return { u, l };
|
|
1389
|
+
}
|
|
1390
|
+
function putdiff(dddu, dddl) {
|
|
1391
|
+
dddu += Math.trunc(dddl / 1e5);
|
|
1392
|
+
dddl %= 1e5;
|
|
1393
|
+
if (dddu < 0 && dddl > 0) {
|
|
1394
|
+
dddu++;
|
|
1395
|
+
dddl -= 1e5;
|
|
1396
|
+
} else if (dddu > 0 && dddl < 0) {
|
|
1397
|
+
dddu--;
|
|
1398
|
+
dddl += 1e5;
|
|
1399
|
+
}
|
|
1400
|
+
if (dddu === 0) return String(dddl);
|
|
1401
|
+
return `${dddu}${String(Math.abs(dddl)).padStart(5, "0")}`;
|
|
1402
|
+
}
|
|
1403
|
+
function putClock(du, dl, cOrder) {
|
|
1404
|
+
du += Math.trunc(dl / 1e8);
|
|
1405
|
+
dl %= 1e8;
|
|
1406
|
+
if (du < 0 && dl > 0) {
|
|
1407
|
+
du++;
|
|
1408
|
+
dl -= 1e8;
|
|
1409
|
+
} else if (du > 0 && dl < 0) {
|
|
1410
|
+
du--;
|
|
1411
|
+
dl += 1e8;
|
|
1412
|
+
}
|
|
1413
|
+
let out = "";
|
|
1414
|
+
if (cOrder === 0) out += `${ARC_ORDER}&`;
|
|
1415
|
+
if (du === 0) out += String(dl);
|
|
1416
|
+
else out += `${du}${String(Math.abs(dl)).padStart(8, "0")}`;
|
|
1417
|
+
return out;
|
|
1418
|
+
}
|
|
1419
|
+
function chop(line) {
|
|
1420
|
+
let end = line.length;
|
|
1421
|
+
if (end > 0 && line[end - 1] === "\r") end--;
|
|
1422
|
+
while (end > 0 && line[end - 1] === " ") end--;
|
|
1423
|
+
return line.slice(0, end);
|
|
1424
|
+
}
|
|
1425
|
+
function readSat(lines, cursor, rinexVersion, ntype, ntypeGnss) {
|
|
1426
|
+
let line = chop(lines[cursor.li++] ?? "");
|
|
1427
|
+
let maxField;
|
|
1428
|
+
let ntypeRec;
|
|
1429
|
+
let firstRec;
|
|
1430
|
+
let satId = "";
|
|
1431
|
+
if (rinexVersion === 2) {
|
|
1432
|
+
maxField = 5;
|
|
1433
|
+
ntypeRec = ntype;
|
|
1434
|
+
firstRec = 0;
|
|
1435
|
+
} else {
|
|
1436
|
+
satId = line.slice(0, 3);
|
|
1437
|
+
const sys = line[0];
|
|
1438
|
+
maxField = ntypeRec = ntypeGnss[sys] ?? -1;
|
|
1439
|
+
if (maxField < 0) return null;
|
|
1440
|
+
firstRec = 3;
|
|
1441
|
+
}
|
|
1442
|
+
const data = [];
|
|
1443
|
+
let flag = "";
|
|
1444
|
+
for (let i = 0; i < ntypeRec; i += maxField) {
|
|
1445
|
+
const nfield = Math.min(ntypeRec - i, maxField);
|
|
1446
|
+
const need = firstRec + 16 * nfield;
|
|
1447
|
+
let body = line;
|
|
1448
|
+
if (body.length < need) body = body.padEnd(need, " ");
|
|
1449
|
+
for (let j = 0; j < nfield; j++) {
|
|
1450
|
+
const p = firstRec + j * 16;
|
|
1451
|
+
const rec = body.slice(p, p + 16);
|
|
1452
|
+
const d = emptyData();
|
|
1453
|
+
if (rec[10] === ".") {
|
|
1454
|
+
flag += rec[14] ?? " ";
|
|
1455
|
+
flag += rec[15] ?? " ";
|
|
1456
|
+
const v = readValue(rec.slice(0, 14));
|
|
1457
|
+
d.u[0] = v.u;
|
|
1458
|
+
d.l[0] = v.l;
|
|
1459
|
+
d.order = 0;
|
|
1460
|
+
} else if (rec.slice(0, 14).trim() === "") {
|
|
1461
|
+
flag += rec[14] ?? " ";
|
|
1462
|
+
flag += rec[15] ?? " ";
|
|
1463
|
+
d.order = -1;
|
|
1464
|
+
} else {
|
|
1465
|
+
return null;
|
|
1466
|
+
}
|
|
1467
|
+
data.push(d);
|
|
1468
|
+
}
|
|
1469
|
+
if (i + maxField < ntypeRec) {
|
|
1470
|
+
line = chop(lines[cursor.li++] ?? "");
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
return { sat: { data, flag, ntypeRec }, satId };
|
|
1474
|
+
}
|
|
1475
|
+
var MONTHS = [
|
|
1476
|
+
"Jan",
|
|
1477
|
+
"Feb",
|
|
1478
|
+
"Mar",
|
|
1479
|
+
"Apr",
|
|
1480
|
+
"May",
|
|
1481
|
+
"Jun",
|
|
1482
|
+
"Jul",
|
|
1483
|
+
"Aug",
|
|
1484
|
+
"Sep",
|
|
1485
|
+
"Oct",
|
|
1486
|
+
"Nov",
|
|
1487
|
+
"Dec"
|
|
1488
|
+
];
|
|
1489
|
+
function crinexDate() {
|
|
1490
|
+
const d = /* @__PURE__ */ new Date();
|
|
1491
|
+
const dd = String(d.getUTCDate()).padStart(2, "0");
|
|
1492
|
+
const mon = MONTHS[d.getUTCMonth()];
|
|
1493
|
+
const yy = String(d.getUTCFullYear() % 100).padStart(2, "0");
|
|
1494
|
+
const hh = String(d.getUTCHours()).padStart(2, "0");
|
|
1495
|
+
const mm = String(d.getUTCMinutes()).padStart(2, "0");
|
|
1496
|
+
return `${dd}-${mon}-${yy} ${hh}:${mm}`;
|
|
1497
|
+
}
|
|
1498
|
+
function writeCrx(rinexText, opts = {}) {
|
|
1499
|
+
const rawLines = rinexText.split("\n");
|
|
1500
|
+
const cursor = { li: 0 };
|
|
1501
|
+
const out = [];
|
|
1502
|
+
const firstLine = chop(rawLines[cursor.li++] ?? "");
|
|
1503
|
+
if (firstLine.slice(60, 80) !== "RINEX VERSION / TYPE" || firstLine[20] !== "O") {
|
|
1504
|
+
throw new Error("writeCrx: not a RINEX observation file");
|
|
1505
|
+
}
|
|
1506
|
+
const rinexVersion = parseInt(firstLine, 10);
|
|
1507
|
+
const rinexVersionFull = readVersionFull(firstLine);
|
|
1508
|
+
if (rinexVersionFull < 0) throw new Error("writeCrx: invalid RINEX version");
|
|
1509
|
+
const crxVersion = rinexVersionFull >= 402 ? "3.1" : rinexVersion === 2 ? "1.0" : "3.0";
|
|
1510
|
+
out.push(
|
|
1511
|
+
`${crxVersion.padEnd(20)}${"COMPACT RINEX FORMAT".padEnd(40)}${"CRINEX VERS / TYPE".padEnd(20)}`
|
|
1512
|
+
);
|
|
1513
|
+
const prog = (opts.prog ?? "gnss-js writeCrx").slice(0, 40);
|
|
1514
|
+
const date = opts.date ?? crinexDate();
|
|
1515
|
+
out.push(`${prog.padEnd(40)}${date.padEnd(20)}CRINEX PROG / DATE`);
|
|
1516
|
+
out.push(firstLine);
|
|
1517
|
+
let ntype = 0;
|
|
1518
|
+
const ntypeGnss = {};
|
|
1519
|
+
let line;
|
|
1520
|
+
do {
|
|
1521
|
+
line = chop(rawLines[cursor.li++] ?? "");
|
|
1522
|
+
out.push(line);
|
|
1523
|
+
const label2 = line.slice(60).trimStart();
|
|
1524
|
+
if (label2.startsWith("# / TYPES OF OBSERV") && line[5] !== " ") {
|
|
1525
|
+
ntype = parseInt(line, 10);
|
|
1526
|
+
} else if (label2.startsWith("SYS / # / OBS TYPES") && line[0] !== " ") {
|
|
1527
|
+
ntypeGnss[line[0]] = parseInt(line.slice(3), 10);
|
|
1528
|
+
}
|
|
1529
|
+
if (cursor.li >= rawLines.length) break;
|
|
1530
|
+
} while (!line.slice(60).trimStart().startsWith("END OF HEADER"));
|
|
1531
|
+
const v2 = rinexVersion === 2;
|
|
1532
|
+
const off = v2 ? { event: 28, nsat: 29, satlst: 32, clock: 68, satOld: 32, shiftClk: 1 } : {
|
|
1533
|
+
event: 31,
|
|
1534
|
+
nsat: 32,
|
|
1535
|
+
satlst: 41,
|
|
1536
|
+
clock: 41,
|
|
1537
|
+
satOld: 41,
|
|
1538
|
+
shiftClk: 4,
|
|
1539
|
+
psec: 57
|
|
1540
|
+
};
|
|
1541
|
+
let oldline = "&";
|
|
1542
|
+
let nsatOld = 0;
|
|
1543
|
+
let clk0 = { u: [0, 0, 0, 0], l: [0, 0, 0, 0] };
|
|
1544
|
+
let dy0 = [];
|
|
1545
|
+
let flag0 = [];
|
|
1546
|
+
let oldpsec = "";
|
|
1547
|
+
let clkOrderPrev = -1;
|
|
1548
|
+
const resetArcs = () => {
|
|
1549
|
+
oldline = "&";
|
|
1550
|
+
nsatOld = 0;
|
|
1551
|
+
clkOrderPrev = -1;
|
|
1552
|
+
};
|
|
1553
|
+
for (; ; ) {
|
|
1554
|
+
if (cursor.li >= rawLines.length) break;
|
|
1555
|
+
let epoch = rawLines[cursor.li];
|
|
1556
|
+
if (epoch === void 0) break;
|
|
1557
|
+
if (epoch === "" && cursor.li === rawLines.length - 1) break;
|
|
1558
|
+
cursor.li++;
|
|
1559
|
+
epoch = chop(epoch);
|
|
1560
|
+
if (epoch === "") continue;
|
|
1561
|
+
let newline;
|
|
1562
|
+
if (v2) {
|
|
1563
|
+
newline = epoch;
|
|
1564
|
+
} else {
|
|
1565
|
+
newline = epoch.length < 41 ? epoch.padEnd(41, " ") : epoch;
|
|
1566
|
+
}
|
|
1567
|
+
const eventFlag = parseInt(newline[off.event] ?? "0", 10) || 0;
|
|
1568
|
+
if (eventFlag > 1) {
|
|
1569
|
+
putEventData(rawLines, cursor, v2, newline, out, ntypeGnss, (n) => {
|
|
1570
|
+
ntype = n;
|
|
1571
|
+
});
|
|
1572
|
+
resetArcs();
|
|
1573
|
+
clk0 = { u: [0, 0, 0, 0], l: [0, 0, 0, 0] };
|
|
1574
|
+
dy0 = [];
|
|
1575
|
+
flag0 = [];
|
|
1576
|
+
continue;
|
|
1577
|
+
}
|
|
1578
|
+
let newpsec = "";
|
|
1579
|
+
if (rinexVersionFull >= 402 && newline.length === 62) {
|
|
1580
|
+
const psec = newline.slice(off.psec, off.psec + 5);
|
|
1581
|
+
if (/^\d{5}$/.test(psec)) newpsec = psec;
|
|
1582
|
+
newline = newline.slice(0, off.psec).replace(/\s+$/, "");
|
|
1583
|
+
}
|
|
1584
|
+
let clkOrder = -1;
|
|
1585
|
+
const clk1 = { u: [0, 0, 0, 0], l: [0, 0, 0, 0] };
|
|
1586
|
+
if (newline.length > off.clock) {
|
|
1587
|
+
clkOrder = readClock(
|
|
1588
|
+
newline.slice(off.clock),
|
|
1589
|
+
off.shiftClk,
|
|
1590
|
+
clk1,
|
|
1591
|
+
clkOrderPrev
|
|
1592
|
+
);
|
|
1593
|
+
if (clkOrder > -1) {
|
|
1594
|
+
newline = newline.slice(0, off.clock).replace(/\s+$/, "");
|
|
1595
|
+
if (!v2 && newline.length < 41) newline = newline.padEnd(41, " ");
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
clkOrderPrev = clkOrder;
|
|
1599
|
+
const nsat = parseInt((newline.slice(off.nsat) || "0").trim(), 10) || 0;
|
|
1600
|
+
if (v2 && nsat > 12) {
|
|
1601
|
+
newline = readMoreSat(rawLines, cursor, nsat, newline);
|
|
1602
|
+
}
|
|
1603
|
+
const sats = [];
|
|
1604
|
+
const satIds = [];
|
|
1605
|
+
let bad = false;
|
|
1606
|
+
let satlist = v2 ? newline.slice(off.satlst, off.satlst + nsat * 3) : "";
|
|
1607
|
+
for (let i = 0; i < nsat; i++) {
|
|
1608
|
+
const r = readSat(rawLines, cursor, rinexVersion, ntype, ntypeGnss);
|
|
1609
|
+
if (!r) {
|
|
1610
|
+
bad = true;
|
|
1611
|
+
break;
|
|
1612
|
+
}
|
|
1613
|
+
sats.push(r.sat);
|
|
1614
|
+
satIds.push(v2 ? satlist.slice(i * 3, i * 3 + 3) : r.satId);
|
|
1615
|
+
}
|
|
1616
|
+
if (bad) continue;
|
|
1617
|
+
if (!v2) satlist = satIds.join("");
|
|
1618
|
+
const fullNew = v2 ? newline : newline.slice(0, 41) + satlist;
|
|
1619
|
+
const oldSatList = v2 ? oldline.slice(off.satOld, off.satOld + nsatOld * 3) : oldline.slice(off.satOld);
|
|
1620
|
+
const sattbl = [];
|
|
1621
|
+
const dup = /* @__PURE__ */ new Set();
|
|
1622
|
+
for (let i = 0; i < nsat; i++) {
|
|
1623
|
+
const id = satIds[i];
|
|
1624
|
+
if (dup.has(id)) {
|
|
1625
|
+
bad = true;
|
|
1626
|
+
break;
|
|
1627
|
+
}
|
|
1628
|
+
dup.add(id);
|
|
1629
|
+
let found = -1;
|
|
1630
|
+
for (let j = 0; j < nsatOld; j++) {
|
|
1631
|
+
if (oldSatList.slice(j * 3, j * 3 + 3) === id) {
|
|
1632
|
+
found = j;
|
|
1633
|
+
break;
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
sattbl.push(found);
|
|
1637
|
+
}
|
|
1638
|
+
if (bad) continue;
|
|
1639
|
+
out.push(strdiff(oldline, fullNew));
|
|
1640
|
+
let clockLine = "";
|
|
1641
|
+
if (clkOrder > -1) {
|
|
1642
|
+
if (clkOrder > 0) processClock(clk1, clk0, clkOrder);
|
|
1643
|
+
clockLine += putClock(clk1.u[clkOrder], clk1.l[clkOrder], clkOrder);
|
|
1644
|
+
}
|
|
1645
|
+
if (newpsec.length === 5) {
|
|
1646
|
+
clockLine += " " + strdiff(oldpsec, newpsec);
|
|
1647
|
+
}
|
|
1648
|
+
out.push(clockLine);
|
|
1649
|
+
const dataLines = buildData(sats, sattbl, dy0, flag0, rinexVersion);
|
|
1650
|
+
for (const dl of dataLines) out.push(dl);
|
|
1651
|
+
oldline = fullNew;
|
|
1652
|
+
nsatOld = nsat;
|
|
1653
|
+
clk0 = clk1;
|
|
1654
|
+
oldpsec = newpsec;
|
|
1655
|
+
dy0 = sats.map((s) => s.data);
|
|
1656
|
+
flag0 = sats.map((s) => s.flag);
|
|
1657
|
+
}
|
|
1658
|
+
return out.join("\n") + "\n";
|
|
1659
|
+
}
|
|
1660
|
+
function readClock(field, shiftClk, clk1, prevOrder) {
|
|
1661
|
+
const c = field.split("");
|
|
1662
|
+
if (c[2] !== ".") return -1;
|
|
1663
|
+
for (let k = 0; k < shiftClk; k++) c[2 + k] = c[3 + k];
|
|
1664
|
+
c[2 + shiftClk] = ".";
|
|
1665
|
+
const s = c.join("");
|
|
1666
|
+
const m = /(-?\d+)\.(\d+)/.exec(s);
|
|
1667
|
+
if (!m) return -1;
|
|
1668
|
+
clk1.u[0] = parseInt(m[1], 10);
|
|
1669
|
+
clk1.l[0] = parseInt(m[2], 10);
|
|
1670
|
+
if (c[0] === "-" || c[1] === "-") clk1.l[0] = -clk1.l[0];
|
|
1671
|
+
return Math.min(prevOrder + 1, ARC_ORDER);
|
|
1672
|
+
}
|
|
1673
|
+
function processClock(clk1, clk0, clkOrder) {
|
|
1674
|
+
for (let i = 0; i < clkOrder; i++) {
|
|
1675
|
+
clk1.u[i + 1] = clk1.u[i] - clk0.u[i];
|
|
1676
|
+
clk1.l[i + 1] = clk1.l[i] - clk0.l[i];
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
function takeDiff(py1, py0) {
|
|
1680
|
+
py1.order = py0.order;
|
|
1681
|
+
if (py1.order < ARC_ORDER) py1.order++;
|
|
1682
|
+
for (let k = 0; k < py1.order; k++) {
|
|
1683
|
+
py1.u[k + 1] = py1.u[k] - py0.u[k];
|
|
1684
|
+
py1.l[k + 1] = py1.l[k] - py0.l[k];
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
function buildData(sats, sattbl, dy0, flag0, rinexVersion) {
|
|
1688
|
+
const lines = [];
|
|
1689
|
+
for (let i = 0; i < sats.length; i++) {
|
|
1690
|
+
const sat = sats[i];
|
|
1691
|
+
const i0 = sattbl[i];
|
|
1692
|
+
const prevFlag = (i0 >= 0 ? flag0[i0] ?? "" : "").split("");
|
|
1693
|
+
let line = "";
|
|
1694
|
+
for (let j = 0; j < sat.ntypeRec; j++) {
|
|
1695
|
+
const py1 = sat.data[j];
|
|
1696
|
+
if (py1.order >= 0) {
|
|
1697
|
+
if (i0 < 0 || dy0[i0]?.[j]?.order === -1) {
|
|
1698
|
+
py1.order = 0;
|
|
1699
|
+
line += `${ARC_ORDER}&`;
|
|
1700
|
+
} else {
|
|
1701
|
+
takeDiff(py1, dy0[i0][j]);
|
|
1702
|
+
if (Math.abs(py1.u[py1.order]) > 1e5) {
|
|
1703
|
+
py1.order = 0;
|
|
1704
|
+
line += `${ARC_ORDER}&`;
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
line += putdiff(py1.u[py1.order], py1.l[py1.order]);
|
|
1708
|
+
} else if (i0 >= 0 && rinexVersion === 2) {
|
|
1709
|
+
prevFlag[j * 2] = " ";
|
|
1710
|
+
prevFlag[j * 2 + 1] = " ";
|
|
1711
|
+
}
|
|
1712
|
+
line += " ";
|
|
1713
|
+
}
|
|
1714
|
+
if (i0 < 0 && rinexVersion !== 2) {
|
|
1715
|
+
for (const ch of sat.flag) line += ch === " " ? "&" : ch;
|
|
1716
|
+
} else {
|
|
1717
|
+
line += i0 < 0 ? strdiff("", sat.flag) : strdiff(prevFlag.join(""), sat.flag);
|
|
1718
|
+
line = line.replace(/ +$/, "");
|
|
1719
|
+
}
|
|
1720
|
+
lines.push(line);
|
|
1721
|
+
}
|
|
1722
|
+
return lines;
|
|
1723
|
+
}
|
|
1724
|
+
function putEventData(lines, cursor, v2, epochLine, out, ntypeGnss, setNtype) {
|
|
1725
|
+
if (v2) {
|
|
1726
|
+
out.push("&" + epochLine.slice(1));
|
|
1727
|
+
if (epochLine.length > 29) {
|
|
1728
|
+
const n = parseInt(epochLine.slice(29), 10) || 0;
|
|
1729
|
+
for (let i = 0; i < n; i++) {
|
|
1730
|
+
const l = chop(lines[cursor.li++] ?? "");
|
|
1731
|
+
out.push(l);
|
|
1732
|
+
if (l.slice(60).trimStart().startsWith("# / TYPES OF OBSERV") && l[5] !== " ") {
|
|
1733
|
+
setNtype(parseInt(l, 10));
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
} else {
|
|
1738
|
+
out.push(epochLine.replace(/\s+$/, ""));
|
|
1739
|
+
const n = parseInt(epochLine.slice(32), 10) || 0;
|
|
1740
|
+
for (let i = 0; i < n; i++) {
|
|
1741
|
+
const l = chop(lines[cursor.li++] ?? "");
|
|
1742
|
+
out.push(l);
|
|
1743
|
+
if (l.slice(60).trimStart().startsWith("SYS / # / OBS TYPES") && l[0] !== " ") {
|
|
1744
|
+
ntypeGnss[l[0]] = parseInt(l.slice(3), 10);
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
function readMoreSat(lines, cursor, n, epochLine) {
|
|
1750
|
+
let result = epochLine;
|
|
1751
|
+
let remaining = n;
|
|
1752
|
+
while (remaining > 12) {
|
|
1753
|
+
const l = lines[cursor.li++] ?? "";
|
|
1754
|
+
const chopped = chop(l);
|
|
1755
|
+
result += chopped[2] === " " ? chopped.slice(32) : chopped;
|
|
1756
|
+
remaining -= 12;
|
|
1757
|
+
}
|
|
1758
|
+
return result;
|
|
1759
|
+
}
|
|
1760
|
+
function readVersionFull(line) {
|
|
1761
|
+
if (line[5] === "2" && line[6] === " ") return 200;
|
|
1762
|
+
const d = (c) => c !== void 0 && c >= "0" && c <= "9";
|
|
1763
|
+
if (!d(line[5]) || line[6] !== "." || !d(line[7]) || !d(line[8])) return -1;
|
|
1764
|
+
return (line.charCodeAt(5) - 48) * 100 + (line.charCodeAt(7) - 48) * 10 + (line.charCodeAt(8) - 48);
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1322
1767
|
// src/rinex/format.ts
|
|
1323
1768
|
function padL(s, w) {
|
|
1324
1769
|
return s.length >= w ? s.slice(0, w) : s + " ".repeat(w - s.length);
|
|
@@ -7186,14 +7631,14 @@ function parseOrbitBlock(c, masks) {
|
|
|
7186
7631
|
const gnssIod = c.u(IOD_BITS[sys.system]);
|
|
7187
7632
|
const rad = c.s(13);
|
|
7188
7633
|
const inT = c.s(12);
|
|
7189
|
-
const
|
|
7634
|
+
const cross2 = c.s(12);
|
|
7190
7635
|
corrections.push({
|
|
7191
7636
|
system: sys.system,
|
|
7192
7637
|
prn,
|
|
7193
7638
|
gnssIod,
|
|
7194
7639
|
deltaRadial: rad === -4096 ? null : rad * 25e-4,
|
|
7195
7640
|
deltaInTrack: inT === -2048 ? null : inT * 8e-3,
|
|
7196
|
-
deltaCrossTrack:
|
|
7641
|
+
deltaCrossTrack: cross2 === -2048 ? null : cross2 * 8e-3
|
|
7197
7642
|
});
|
|
7198
7643
|
}
|
|
7199
7644
|
}
|
|
@@ -10220,17 +10665,17 @@ function ecefToAzEl(rxX, rxY, rxZ, satX, satY, satZ) {
|
|
|
10220
10665
|
function computeDop(satAzEls) {
|
|
10221
10666
|
const n = satAzEls.length;
|
|
10222
10667
|
if (n < 4) return null;
|
|
10223
|
-
const
|
|
10668
|
+
const H3 = [];
|
|
10224
10669
|
for (const { az, el } of satAzEls) {
|
|
10225
10670
|
const cosEl = Math.cos(el);
|
|
10226
|
-
|
|
10671
|
+
H3.push([cosEl * Math.sin(az), cosEl * Math.cos(az), Math.sin(el), 1]);
|
|
10227
10672
|
}
|
|
10228
10673
|
const HtH = Array.from({ length: 4 }, () => new Array(4).fill(0));
|
|
10229
10674
|
for (let i = 0; i < 4; i++) {
|
|
10230
10675
|
for (let j = 0; j < 4; j++) {
|
|
10231
10676
|
let sum = 0;
|
|
10232
10677
|
for (let k = 0; k < n; k++) {
|
|
10233
|
-
sum +=
|
|
10678
|
+
sum += H3[k][i] * H3[k][j];
|
|
10234
10679
|
}
|
|
10235
10680
|
HtH[i][j] = sum;
|
|
10236
10681
|
}
|
|
@@ -11357,7 +11802,7 @@ function solveDgnss(rover, base, basePos, ephemerides, timeMs, opts = {}) {
|
|
|
11357
11802
|
let cov = null;
|
|
11358
11803
|
for (let iter = 0; iter < maxIterations; iter++) {
|
|
11359
11804
|
iterations = iter + 1;
|
|
11360
|
-
const
|
|
11805
|
+
const H3 = [];
|
|
11361
11806
|
const v = [];
|
|
11362
11807
|
const terms = /* @__PURE__ */ new Map();
|
|
11363
11808
|
const termOf = (g) => {
|
|
@@ -11373,11 +11818,11 @@ function solveDgnss(rover, base, basePos, ephemerides, timeMs, opts = {}) {
|
|
|
11373
11818
|
const tr = termOf(row.ref);
|
|
11374
11819
|
const pred = ts.rho - row.g.rhoB + ts.dTropo - (tr.rho - row.ref.rhoB + tr.dTropo);
|
|
11375
11820
|
v.push(row.z - pred);
|
|
11376
|
-
|
|
11821
|
+
H3.push([ts.u[0] - tr.u[0], ts.u[1] - tr.u[1], ts.u[2] - tr.u[2]]);
|
|
11377
11822
|
}
|
|
11378
|
-
const Ht = transpose(
|
|
11823
|
+
const Ht = transpose(H3);
|
|
11379
11824
|
const HtW = matMul(Ht, W);
|
|
11380
|
-
const N = matMul(HtW,
|
|
11825
|
+
const N = matMul(HtW, H3);
|
|
11381
11826
|
const b = matMul(
|
|
11382
11827
|
HtW,
|
|
11383
11828
|
v.map((s) => [s])
|
|
@@ -11393,7 +11838,7 @@ function solveDgnss(rover, base, basePos, ephemerides, timeMs, opts = {}) {
|
|
|
11393
11838
|
z += dx[2][0];
|
|
11394
11839
|
cov = Ninv;
|
|
11395
11840
|
rows.forEach((row, i) => {
|
|
11396
|
-
residuals[row.g.prn] = v[i] - (
|
|
11841
|
+
residuals[row.g.prn] = v[i] - (H3[i][0] * dx[0][0] + H3[i][1] * dx[1][0] + H3[i][2] * dx[2][0]);
|
|
11397
11842
|
});
|
|
11398
11843
|
if (Math.hypot(dx[0][0], dx[1][0], dx[2][0]) < convergenceM) {
|
|
11399
11844
|
converged = true;
|
|
@@ -11785,19 +12230,19 @@ var RtkFloatEngine = class {
|
|
|
11785
12230
|
const PPrior = this.P;
|
|
11786
12231
|
let xi = [...this.x];
|
|
11787
12232
|
let K = [];
|
|
11788
|
-
let
|
|
12233
|
+
let H3 = [];
|
|
11789
12234
|
for (let it = 0; it < Math.max(o.updateIterations, 1); it++) {
|
|
11790
|
-
|
|
12235
|
+
H3 = [];
|
|
11791
12236
|
const v = [];
|
|
11792
12237
|
for (const row of rows) {
|
|
11793
12238
|
const { pred, h } = predict(row, xi);
|
|
11794
12239
|
let corr = 0;
|
|
11795
12240
|
for (let j = 0; j < n; j++) corr += h[j] * (xPrior[j] - xi[j]);
|
|
11796
12241
|
v.push(row.z - pred - corr);
|
|
11797
|
-
|
|
12242
|
+
H3.push(h);
|
|
11798
12243
|
}
|
|
11799
|
-
const Ht = transpose(
|
|
11800
|
-
const S = matMul(matMul(
|
|
12244
|
+
const Ht = transpose(H3);
|
|
12245
|
+
const S = matMul(matMul(H3, PPrior), Ht);
|
|
11801
12246
|
for (let i = 0; i < rows.length; i++)
|
|
11802
12247
|
for (let j = 0; j < rows.length; j++) S[i][j] += R[i][j];
|
|
11803
12248
|
const Sinv = matInv(S);
|
|
@@ -11813,7 +12258,7 @@ var RtkFloatEngine = class {
|
|
|
11813
12258
|
xi = xPrior.map((s, i) => s + dx[i][0]);
|
|
11814
12259
|
}
|
|
11815
12260
|
this.x = xi;
|
|
11816
|
-
const KH = matMul(K,
|
|
12261
|
+
const KH = matMul(K, H3);
|
|
11817
12262
|
const IKH = zeros(n, n);
|
|
11818
12263
|
for (let i = 0; i < n; i++)
|
|
11819
12264
|
for (let j = 0; j < n; j++) IKH[i][j] = (i === j ? 1 : 0) - KH[i][j];
|
|
@@ -11906,6 +12351,800 @@ var RtkFloatEngine = class {
|
|
|
11906
12351
|
}
|
|
11907
12352
|
};
|
|
11908
12353
|
|
|
12354
|
+
// src/positioning/ppp-tropo.ts
|
|
12355
|
+
var HYD_AVG_A = [
|
|
12356
|
+
0.0012769934,
|
|
12357
|
+
1268323e-9,
|
|
12358
|
+
0.0012465397,
|
|
12359
|
+
0.0012196049,
|
|
12360
|
+
0.0012045996
|
|
12361
|
+
];
|
|
12362
|
+
var HYD_AVG_B = [
|
|
12363
|
+
0.0029153695,
|
|
12364
|
+
0.0029152299,
|
|
12365
|
+
0.0029288445,
|
|
12366
|
+
0.0029022565,
|
|
12367
|
+
0.0029024912
|
|
12368
|
+
];
|
|
12369
|
+
var HYD_AVG_C = [
|
|
12370
|
+
0.062610505,
|
|
12371
|
+
0.062837393,
|
|
12372
|
+
0.063721774,
|
|
12373
|
+
0.063824265,
|
|
12374
|
+
0.064258455
|
|
12375
|
+
];
|
|
12376
|
+
var HYD_AMP_A = [0, 12709626e-12, 26523662e-12, 34000452e-12, 41202191e-12];
|
|
12377
|
+
var HYD_AMP_B = [0, 21414979e-12, 30160779e-12, 72562722e-12, 11723375e-11];
|
|
12378
|
+
var HYD_AMP_C = [0, 901284e-10, 43497037e-12, 84795348e-11, 0.0017037206];
|
|
12379
|
+
var HT_A = 253e-7;
|
|
12380
|
+
var HT_B = 549e-5;
|
|
12381
|
+
var HT_C = 114e-5;
|
|
12382
|
+
var WET_A = [
|
|
12383
|
+
58021897e-11,
|
|
12384
|
+
56794847e-11,
|
|
12385
|
+
58118019e-11,
|
|
12386
|
+
59727542e-11,
|
|
12387
|
+
61641693e-11
|
|
12388
|
+
];
|
|
12389
|
+
var WET_B = [
|
|
12390
|
+
0.0014275268,
|
|
12391
|
+
0.0015138625,
|
|
12392
|
+
0.0014572752,
|
|
12393
|
+
0.0015007428,
|
|
12394
|
+
0.0017599082
|
|
12395
|
+
];
|
|
12396
|
+
var WET_C = [
|
|
12397
|
+
0.043472961,
|
|
12398
|
+
0.04672951,
|
|
12399
|
+
0.043908931,
|
|
12400
|
+
0.044626982,
|
|
12401
|
+
0.054736038
|
|
12402
|
+
];
|
|
12403
|
+
var LATS = [15, 30, 45, 60, 75];
|
|
12404
|
+
function interpLat(table, absLatDeg) {
|
|
12405
|
+
if (absLatDeg <= 15) return table[0];
|
|
12406
|
+
if (absLatDeg >= 75) return table[4];
|
|
12407
|
+
let i = 0;
|
|
12408
|
+
while (i < 4 && absLatDeg > LATS[i + 1]) i++;
|
|
12409
|
+
const t = (absLatDeg - LATS[i]) / (LATS[i + 1] - LATS[i]);
|
|
12410
|
+
return table[i] + t * (table[i + 1] - table[i]);
|
|
12411
|
+
}
|
|
12412
|
+
function marini(sinEl, a, b, c) {
|
|
12413
|
+
const num = 1 + a / (1 + b / (1 + c));
|
|
12414
|
+
const den = sinEl + a / (sinEl + b / (sinEl + c));
|
|
12415
|
+
return num / den;
|
|
12416
|
+
}
|
|
12417
|
+
function dayOfYear(timeMs) {
|
|
12418
|
+
const d = new Date(timeMs);
|
|
12419
|
+
const start = Date.UTC(d.getUTCFullYear(), 0, 1);
|
|
12420
|
+
return Math.floor((timeMs - start) / 864e5) + 1;
|
|
12421
|
+
}
|
|
12422
|
+
function niellMapping(elRad, latRad, heightM, timeMs) {
|
|
12423
|
+
const sinEl = Math.sin(Math.max(elRad, 1e-3));
|
|
12424
|
+
const absLat = Math.abs(latRad * 180 / Math.PI);
|
|
12425
|
+
const hKm = heightM / 1e3;
|
|
12426
|
+
let doy = dayOfYear(timeMs);
|
|
12427
|
+
if (latRad < 0) doy += 365.25 / 2;
|
|
12428
|
+
const yfrac = Math.cos(2 * Math.PI * (doy - 28) / 365.25);
|
|
12429
|
+
const ah = interpLat(HYD_AVG_A, absLat) - interpLat(HYD_AMP_A, absLat) * yfrac;
|
|
12430
|
+
const bh = interpLat(HYD_AVG_B, absLat) - interpLat(HYD_AMP_B, absLat) * yfrac;
|
|
12431
|
+
const ch = interpLat(HYD_AVG_C, absLat) - interpLat(HYD_AMP_C, absLat) * yfrac;
|
|
12432
|
+
const mHt = marini(sinEl, HT_A, HT_B, HT_C);
|
|
12433
|
+
const dmdh = 1 / sinEl - mHt;
|
|
12434
|
+
const mh = marini(sinEl, ah, bh, ch) + dmdh * hKm;
|
|
12435
|
+
const aw = interpLat(WET_A, absLat);
|
|
12436
|
+
const bw = interpLat(WET_B, absLat);
|
|
12437
|
+
const cw = interpLat(WET_C, absLat);
|
|
12438
|
+
const mw = marini(sinEl, aw, bw, cw);
|
|
12439
|
+
const h = heightM < 0 ? 0 : heightM > 1e4 ? 1e4 : heightM;
|
|
12440
|
+
const pres = 1013.25 * Math.pow(1 - 22557e-9 * h, 5.2568);
|
|
12441
|
+
const zhd = 22768e-7 * pres / (1 - 266e-5 * Math.cos(2 * latRad) - 28e-5 * (h / 1e3));
|
|
12442
|
+
return { zhd, mh, mw };
|
|
12443
|
+
}
|
|
12444
|
+
|
|
12445
|
+
// src/positioning/ppp-astro.ts
|
|
12446
|
+
var AU = 149597870700;
|
|
12447
|
+
var GPS_UTC_LEAP = 18;
|
|
12448
|
+
var J2000_MS = Date.UTC(2e3, 0, 1, 12, 0, 0);
|
|
12449
|
+
var DEG = Math.PI / 180;
|
|
12450
|
+
function daysSinceJ2000(timeMs) {
|
|
12451
|
+
return (timeMs - GPS_UTC_LEAP * 1e3 - J2000_MS) / 864e5;
|
|
12452
|
+
}
|
|
12453
|
+
function gmst(timeMs) {
|
|
12454
|
+
const d = daysSinceJ2000(timeMs);
|
|
12455
|
+
let deg = 280.46061837 + 360.98564736629 * d;
|
|
12456
|
+
deg %= 360;
|
|
12457
|
+
if (deg < 0) deg += 360;
|
|
12458
|
+
return deg * DEG;
|
|
12459
|
+
}
|
|
12460
|
+
function eciToEcef(v, theta) {
|
|
12461
|
+
const c = Math.cos(theta);
|
|
12462
|
+
const s = Math.sin(theta);
|
|
12463
|
+
return [v[0] * c + v[1] * s, -v[0] * s + v[1] * c, v[2]];
|
|
12464
|
+
}
|
|
12465
|
+
function sunEcef(timeMs) {
|
|
12466
|
+
const n = daysSinceJ2000(timeMs);
|
|
12467
|
+
const L = (280.46 + 0.9856474 * n) * DEG;
|
|
12468
|
+
const g = (357.528 + 0.9856003 * n) * DEG;
|
|
12469
|
+
const lambda = L + (1.915 * Math.sin(g) + 0.02 * Math.sin(2 * g)) * DEG;
|
|
12470
|
+
const eps = (23.439 - 4e-7 * n) * DEG;
|
|
12471
|
+
const R = (1.00014 - 0.01671 * Math.cos(g) - 14e-5 * Math.cos(2 * g)) * AU;
|
|
12472
|
+
const eci = [
|
|
12473
|
+
R * Math.cos(lambda),
|
|
12474
|
+
R * Math.cos(eps) * Math.sin(lambda),
|
|
12475
|
+
R * Math.sin(eps) * Math.sin(lambda)
|
|
12476
|
+
];
|
|
12477
|
+
return eciToEcef(eci, gmst(timeMs));
|
|
12478
|
+
}
|
|
12479
|
+
function moonEcef(timeMs) {
|
|
12480
|
+
const T = daysSinceJ2000(timeMs) / 36525;
|
|
12481
|
+
const L0 = 218.31617 + 481267.88088 * T - 1.3972 * T;
|
|
12482
|
+
const l = 134.96292 + 477198.86753 * T;
|
|
12483
|
+
const lp = 357.52543 + 35999.04944 * T;
|
|
12484
|
+
const F = 93.27283 + 483202.01873 * T;
|
|
12485
|
+
const D = 297.85027 + 445267.11135 * T;
|
|
12486
|
+
const s = (x) => Math.sin(x * DEG);
|
|
12487
|
+
const c = (x) => Math.cos(x * DEG);
|
|
12488
|
+
const lon = L0 + 6.28875 * s(l) + 1.274018 * s(2 * D - l) + 0.658309 * s(2 * D) + 0.213616 * s(2 * l) - 0.185596 * s(lp) - 0.114336 * s(2 * F) + 0.058793 * s(2 * D - 2 * l) + 0.057212 * s(2 * D - lp - l) + 0.05332 * s(2 * D + l);
|
|
12489
|
+
const lat = 5.128189 * s(F) + 0.280606 * s(l + F) + 0.277693 * s(l - F) + 0.173238 * s(2 * D - F) + 0.055413 * s(2 * D + F - l) + 0.046272 * s(2 * D - F - l);
|
|
12490
|
+
const r = (385e3 - 20905 * c(l) - 3699 * c(2 * D - l) - 2956 * c(2 * D) - 570 * c(2 * l)) * 1e3;
|
|
12491
|
+
const eps = (23.4393 - 4e-7 * daysSinceJ2000(timeMs)) * DEG;
|
|
12492
|
+
const lonR = lon * DEG;
|
|
12493
|
+
const latR = lat * DEG;
|
|
12494
|
+
const xe = r * Math.cos(latR) * Math.cos(lonR);
|
|
12495
|
+
const ye = r * Math.cos(latR) * Math.sin(lonR);
|
|
12496
|
+
const ze = r * Math.sin(latR);
|
|
12497
|
+
const eci = [
|
|
12498
|
+
xe,
|
|
12499
|
+
ye * Math.cos(eps) - ze * Math.sin(eps),
|
|
12500
|
+
ye * Math.sin(eps) + ze * Math.cos(eps)
|
|
12501
|
+
];
|
|
12502
|
+
return eciToEcef(eci, gmst(timeMs));
|
|
12503
|
+
}
|
|
12504
|
+
var H2 = 0.6078;
|
|
12505
|
+
var L2 = 0.0847;
|
|
12506
|
+
var RE = 6378137;
|
|
12507
|
+
var GM_SUN_RATIO = 332946.0482;
|
|
12508
|
+
var GM_MOON_RATIO = 0.0123000371;
|
|
12509
|
+
function solidEarthTide(rcv, sun, moon) {
|
|
12510
|
+
const rNorm = Math.hypot(rcv[0], rcv[1], rcv[2]);
|
|
12511
|
+
const rHat = [
|
|
12512
|
+
rcv[0] / rNorm,
|
|
12513
|
+
rcv[1] / rNorm,
|
|
12514
|
+
rcv[2] / rNorm
|
|
12515
|
+
];
|
|
12516
|
+
const disp = [0, 0, 0];
|
|
12517
|
+
for (const [body, ratio] of [
|
|
12518
|
+
[sun, GM_SUN_RATIO],
|
|
12519
|
+
[moon, GM_MOON_RATIO]
|
|
12520
|
+
]) {
|
|
12521
|
+
const rj = Math.hypot(body[0], body[1], body[2]);
|
|
12522
|
+
const jHat = [
|
|
12523
|
+
body[0] / rj,
|
|
12524
|
+
body[1] / rj,
|
|
12525
|
+
body[2] / rj
|
|
12526
|
+
];
|
|
12527
|
+
const dot2 = rHat[0] * jHat[0] + rHat[1] * jHat[1] + rHat[2] * jHat[2];
|
|
12528
|
+
const factor = ratio * RE * RE * RE * RE / (rj * rj * rj);
|
|
12529
|
+
const radialScale = H2 * (1.5 * dot2 * dot2 - 0.5);
|
|
12530
|
+
const tanScale = 3 * L2 * dot2;
|
|
12531
|
+
for (let k = 0; k < 3; k++) {
|
|
12532
|
+
disp[k] += factor * (radialScale * rHat[k] + tanScale * (jHat[k] - dot2 * rHat[k]));
|
|
12533
|
+
}
|
|
12534
|
+
}
|
|
12535
|
+
return disp;
|
|
12536
|
+
}
|
|
12537
|
+
|
|
12538
|
+
// src/positioning/ppp-antenna.ts
|
|
12539
|
+
function parseAntexTime(s) {
|
|
12540
|
+
const p = s.trim().split(/\s+/).map(Number);
|
|
12541
|
+
if (p.length < 3 || p.some((v) => Number.isNaN(v))) return null;
|
|
12542
|
+
return Date.UTC(
|
|
12543
|
+
p[0],
|
|
12544
|
+
(p[1] || 1) - 1,
|
|
12545
|
+
p[2] || 1,
|
|
12546
|
+
p[3] ?? 0,
|
|
12547
|
+
p[4] ?? 0,
|
|
12548
|
+
Math.floor(p[5] ?? 0)
|
|
12549
|
+
);
|
|
12550
|
+
}
|
|
12551
|
+
function freqOf(entry, code) {
|
|
12552
|
+
return entry.frequencies.find((f) => f.frequency === code);
|
|
12553
|
+
}
|
|
12554
|
+
function combineIf(fA, fB, f1, f2) {
|
|
12555
|
+
const g = f1 * f1 / (f1 * f1 - f2 * f2);
|
|
12556
|
+
const mm = 1e-3;
|
|
12557
|
+
const pco = [
|
|
12558
|
+
(g * fA.pcoN - (g - 1) * fB.pcoN) * mm,
|
|
12559
|
+
(g * fA.pcoE - (g - 1) * fB.pcoE) * mm,
|
|
12560
|
+
(g * fA.pcoU - (g - 1) * fB.pcoU) * mm
|
|
12561
|
+
];
|
|
12562
|
+
const nz = Math.min(fA.pcvNoazi.length, fB.pcvNoazi.length);
|
|
12563
|
+
const pcvNoazi = new Array(nz);
|
|
12564
|
+
for (let i = 0; i < nz; i++) {
|
|
12565
|
+
pcvNoazi[i] = (g * fA.pcvNoazi[i] - (g - 1) * fB.pcvNoazi[i]) * mm;
|
|
12566
|
+
}
|
|
12567
|
+
return { pco, pcvZen1Deg: 0, pcvDzenDeg: 0, pcvNoazi };
|
|
12568
|
+
}
|
|
12569
|
+
function buildPppAntenna(antex) {
|
|
12570
|
+
const sats = /* @__PURE__ */ new Map();
|
|
12571
|
+
const rcvs = /* @__PURE__ */ new Map();
|
|
12572
|
+
for (const a of antex.antennas) {
|
|
12573
|
+
if (a.isSatellite) {
|
|
12574
|
+
const list = sats.get(a.serialNo) ?? [];
|
|
12575
|
+
list.push(a);
|
|
12576
|
+
sats.set(a.serialNo, list);
|
|
12577
|
+
} else if (!rcvs.has(a.type)) {
|
|
12578
|
+
rcvs.set(a.type, a);
|
|
12579
|
+
}
|
|
12580
|
+
}
|
|
12581
|
+
const withZen = (entry, off) => ({
|
|
12582
|
+
...off,
|
|
12583
|
+
pcvZen1Deg: entry.zen1,
|
|
12584
|
+
pcvDzenDeg: entry.dzen
|
|
12585
|
+
});
|
|
12586
|
+
return {
|
|
12587
|
+
satOffset(prn, dateMs, band1, band2, f1, f2) {
|
|
12588
|
+
const list = sats.get(prn);
|
|
12589
|
+
if (!list) return null;
|
|
12590
|
+
const entry = list.find((e) => {
|
|
12591
|
+
const from = parseAntexTime(e.validFrom);
|
|
12592
|
+
const until = parseAntexTime(e.validUntil);
|
|
12593
|
+
return (from == null || dateMs >= from) && (until == null || dateMs <= until);
|
|
12594
|
+
});
|
|
12595
|
+
if (!entry) return null;
|
|
12596
|
+
const a = freqOf(entry, band1);
|
|
12597
|
+
const b = freqOf(entry, band2);
|
|
12598
|
+
if (!a || !b) return null;
|
|
12599
|
+
return withZen(entry, combineIf(a, b, f1, f2));
|
|
12600
|
+
},
|
|
12601
|
+
rcvOffset(antType, band1, band2, f1, f2) {
|
|
12602
|
+
const entry = rcvs.get(antType);
|
|
12603
|
+
if (!entry) return null;
|
|
12604
|
+
const a = freqOf(entry, band1);
|
|
12605
|
+
const b = freqOf(entry, band2);
|
|
12606
|
+
if (!a || !b) return null;
|
|
12607
|
+
return withZen(entry, combineIf(a, b, f1, f2));
|
|
12608
|
+
}
|
|
12609
|
+
};
|
|
12610
|
+
}
|
|
12611
|
+
function cross(a, b) {
|
|
12612
|
+
return [
|
|
12613
|
+
a[1] * b[2] - a[2] * b[1],
|
|
12614
|
+
a[2] * b[0] - a[0] * b[2],
|
|
12615
|
+
a[0] * b[1] - a[1] * b[0]
|
|
12616
|
+
];
|
|
12617
|
+
}
|
|
12618
|
+
function norm(a) {
|
|
12619
|
+
const n = Math.hypot(a[0], a[1], a[2]) || 1;
|
|
12620
|
+
return [a[0] / n, a[1] / n, a[2] / n];
|
|
12621
|
+
}
|
|
12622
|
+
function dot(a, b) {
|
|
12623
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
12624
|
+
}
|
|
12625
|
+
function satBodyFrame(satEcef, sunEcef2) {
|
|
12626
|
+
const z = norm([-satEcef[0], -satEcef[1], -satEcef[2]]);
|
|
12627
|
+
const eSun = norm([
|
|
12628
|
+
sunEcef2[0] - satEcef[0],
|
|
12629
|
+
sunEcef2[1] - satEcef[1],
|
|
12630
|
+
sunEcef2[2] - satEcef[2]
|
|
12631
|
+
]);
|
|
12632
|
+
const y = norm(cross(z, eSun));
|
|
12633
|
+
const x = norm(cross(y, z));
|
|
12634
|
+
return { x, y, z };
|
|
12635
|
+
}
|
|
12636
|
+
function satPcoToEcef(pcoBody, frame) {
|
|
12637
|
+
return [
|
|
12638
|
+
pcoBody[0] * frame.x[0] + pcoBody[1] * frame.y[0] + pcoBody[2] * frame.z[0],
|
|
12639
|
+
pcoBody[0] * frame.x[1] + pcoBody[1] * frame.y[1] + pcoBody[2] * frame.z[1],
|
|
12640
|
+
pcoBody[0] * frame.x[2] + pcoBody[1] * frame.y[2] + pcoBody[2] * frame.z[2]
|
|
12641
|
+
];
|
|
12642
|
+
}
|
|
12643
|
+
function enuToEcef(enu, latRad, lonRad) {
|
|
12644
|
+
const sl = Math.sin(latRad);
|
|
12645
|
+
const cl = Math.cos(latRad);
|
|
12646
|
+
const so = Math.sin(lonRad);
|
|
12647
|
+
const co = Math.cos(lonRad);
|
|
12648
|
+
const [e, n, u] = enu;
|
|
12649
|
+
return [
|
|
12650
|
+
-so * e - sl * co * n + cl * co * u,
|
|
12651
|
+
co * e - sl * so * n + cl * so * u,
|
|
12652
|
+
cl * n + sl * u
|
|
12653
|
+
];
|
|
12654
|
+
}
|
|
12655
|
+
function interpPcv(off, angleDeg) {
|
|
12656
|
+
const { pcvZen1Deg, pcvDzenDeg, pcvNoazi } = off;
|
|
12657
|
+
if (pcvDzenDeg <= 0 || pcvNoazi.length < 2) return 0;
|
|
12658
|
+
const x = (angleDeg - pcvZen1Deg) / pcvDzenDeg;
|
|
12659
|
+
if (x <= 0) return pcvNoazi[0];
|
|
12660
|
+
if (x >= pcvNoazi.length - 1) return pcvNoazi[pcvNoazi.length - 1];
|
|
12661
|
+
const i = Math.floor(x);
|
|
12662
|
+
const t = x - i;
|
|
12663
|
+
return pcvNoazi[i] * (1 - t) + pcvNoazi[i + 1] * t;
|
|
12664
|
+
}
|
|
12665
|
+
function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
|
|
12666
|
+
const k = [
|
|
12667
|
+
-losRcvToSat[0],
|
|
12668
|
+
-losRcvToSat[1],
|
|
12669
|
+
-losRcvToSat[2]
|
|
12670
|
+
];
|
|
12671
|
+
const kx = satFrame.x;
|
|
12672
|
+
const ky = satFrame.y;
|
|
12673
|
+
const kdotx = dot(k, kx);
|
|
12674
|
+
const kcrossY = cross(k, ky);
|
|
12675
|
+
const dS = [
|
|
12676
|
+
kx[0] - k[0] * kdotx - kcrossY[0],
|
|
12677
|
+
kx[1] - k[1] * kdotx - kcrossY[1],
|
|
12678
|
+
kx[2] - k[2] * kdotx - kcrossY[2]
|
|
12679
|
+
];
|
|
12680
|
+
const north = enuToEcef([0, 1, 0], latRad, lonRad);
|
|
12681
|
+
const east = enuToEcef([1, 0, 0], latRad, lonRad);
|
|
12682
|
+
const kdotn = dot(k, north);
|
|
12683
|
+
const kcrossE = cross(k, east);
|
|
12684
|
+
const dR = [
|
|
12685
|
+
north[0] - k[0] * kdotn + kcrossE[0],
|
|
12686
|
+
north[1] - k[1] * kdotn + kcrossE[1],
|
|
12687
|
+
north[2] - k[2] * kdotn + kcrossE[2]
|
|
12688
|
+
];
|
|
12689
|
+
const nS = Math.hypot(dS[0], dS[1], dS[2]) || 1;
|
|
12690
|
+
const nR = Math.hypot(dR[0], dR[1], dR[2]) || 1;
|
|
12691
|
+
let cosPhi = dot(dS, dR) / (nS * nR);
|
|
12692
|
+
cosPhi = Math.max(-1, Math.min(1, cosPhi));
|
|
12693
|
+
const zeta = cross(dS, dR);
|
|
12694
|
+
const sign = dot(k, zeta) >= 0 ? 1 : -1;
|
|
12695
|
+
const dphi = sign * Math.acos(cosPhi) / (2 * Math.PI);
|
|
12696
|
+
const prev = state.get(prn);
|
|
12697
|
+
const wu = prev == null ? dphi : dphi + Math.round(prev - dphi);
|
|
12698
|
+
state.set(prn, wu);
|
|
12699
|
+
return wu;
|
|
12700
|
+
}
|
|
12701
|
+
|
|
12702
|
+
// src/positioning/ppp-corrections.ts
|
|
12703
|
+
function applyCorrections(corrections, geom, ctx) {
|
|
12704
|
+
if (corrections.evaluate) return corrections.evaluate(geom, ctx);
|
|
12705
|
+
return { rangeM: 0, phaseWindupM: 0 };
|
|
12706
|
+
}
|
|
12707
|
+
function createPppCorrections(cfg) {
|
|
12708
|
+
const useSat = cfg.satPco ?? false;
|
|
12709
|
+
const useRcv = cfg.rcvPco ?? true;
|
|
12710
|
+
const useTides = cfg.tides ?? true;
|
|
12711
|
+
const useWindup = cfg.windup ?? true;
|
|
12712
|
+
const antDelta = cfg.antDeltaEnu ?? [0, 0, 0];
|
|
12713
|
+
const windupState = /* @__PURE__ */ new Map();
|
|
12714
|
+
return {
|
|
12715
|
+
epochContext(timeMs, rcvEcef) {
|
|
12716
|
+
const sun = sunEcef(timeMs);
|
|
12717
|
+
const moon = moonEcef(timeMs);
|
|
12718
|
+
const tideDisp = useTides ? solidEarthTide(rcvEcef, sun, moon) : [0, 0, 0];
|
|
12719
|
+
return { timeMs, sun, moon, tideDisp };
|
|
12720
|
+
},
|
|
12721
|
+
evaluate(geom, ctx) {
|
|
12722
|
+
let rangeM = 0;
|
|
12723
|
+
let phaseWindupM = 0;
|
|
12724
|
+
const e = geom.los;
|
|
12725
|
+
const [latDeg, lonDeg] = ecefToGeodetic(
|
|
12726
|
+
geom.rcvEcef[0],
|
|
12727
|
+
geom.rcvEcef[1],
|
|
12728
|
+
geom.rcvEcef[2]
|
|
12729
|
+
);
|
|
12730
|
+
const latRad = latDeg * Math.PI / 180;
|
|
12731
|
+
const lonRad = lonDeg * Math.PI / 180;
|
|
12732
|
+
const frame = ctx ? satBodyFrame(geom.satEcef, ctx.sun) : null;
|
|
12733
|
+
if (useSat && frame && geom.band1 && geom.band2) {
|
|
12734
|
+
const off = cfg.antenna.satOffset(
|
|
12735
|
+
geom.prn,
|
|
12736
|
+
ctx.timeMs,
|
|
12737
|
+
geom.band1,
|
|
12738
|
+
geom.band2,
|
|
12739
|
+
geom.f1,
|
|
12740
|
+
geom.f2
|
|
12741
|
+
);
|
|
12742
|
+
if (off) {
|
|
12743
|
+
const pcoEcef = satPcoToEcef(off.pco, frame);
|
|
12744
|
+
rangeM += dot(e, pcoEcef);
|
|
12745
|
+
const satR = Math.hypot(
|
|
12746
|
+
geom.satEcef[0],
|
|
12747
|
+
geom.satEcef[1],
|
|
12748
|
+
geom.satEcef[2]
|
|
12749
|
+
);
|
|
12750
|
+
const cosNadir = (e[0] * geom.satEcef[0] + e[1] * geom.satEcef[1] + e[2] * geom.satEcef[2]) / satR;
|
|
12751
|
+
const nadirDeg = Math.acos(Math.max(-1, Math.min(1, cosNadir))) * 180 / Math.PI;
|
|
12752
|
+
rangeM += interpPcv(off, nadirDeg);
|
|
12753
|
+
}
|
|
12754
|
+
}
|
|
12755
|
+
if (useRcv && geom.band1 && geom.band2) {
|
|
12756
|
+
const off = cfg.antenna.rcvOffset(
|
|
12757
|
+
cfg.rcvAntType,
|
|
12758
|
+
geom.band1,
|
|
12759
|
+
geom.band2,
|
|
12760
|
+
geom.f1,
|
|
12761
|
+
geom.f2
|
|
12762
|
+
);
|
|
12763
|
+
if (off) {
|
|
12764
|
+
const total = [
|
|
12765
|
+
off.pco[0] + antDelta[0],
|
|
12766
|
+
off.pco[1] + antDelta[1],
|
|
12767
|
+
off.pco[2] + antDelta[2]
|
|
12768
|
+
];
|
|
12769
|
+
const ecef = enuToEcef(total, latRad, lonRad);
|
|
12770
|
+
rangeM -= dot(e, ecef);
|
|
12771
|
+
const zenithDeg = 90 - geom.elRad * 180 / Math.PI;
|
|
12772
|
+
rangeM += interpPcv(off, zenithDeg);
|
|
12773
|
+
}
|
|
12774
|
+
}
|
|
12775
|
+
if (useTides && ctx) {
|
|
12776
|
+
rangeM -= dot(e, ctx.tideDisp);
|
|
12777
|
+
}
|
|
12778
|
+
if (useWindup && frame) {
|
|
12779
|
+
const wu = phaseWindup(geom.prn, e, frame, latRad, lonRad, windupState);
|
|
12780
|
+
const lambdaIf = 299792458 / (geom.f1 + geom.f2);
|
|
12781
|
+
phaseWindupM = wu * lambdaIf;
|
|
12782
|
+
}
|
|
12783
|
+
return { rangeM, phaseWindupM };
|
|
12784
|
+
}
|
|
12785
|
+
};
|
|
12786
|
+
}
|
|
12787
|
+
|
|
12788
|
+
// src/positioning/ppp.ts
|
|
12789
|
+
function matVec(P, h) {
|
|
12790
|
+
const n = P.length;
|
|
12791
|
+
const out = new Array(n).fill(0);
|
|
12792
|
+
for (let i = 0; i < n; i++) {
|
|
12793
|
+
let s = 0;
|
|
12794
|
+
const Pi = P[i];
|
|
12795
|
+
for (let j = 0; j < n; j++) s += Pi[j] * h[j];
|
|
12796
|
+
out[i] = s;
|
|
12797
|
+
}
|
|
12798
|
+
return out;
|
|
12799
|
+
}
|
|
12800
|
+
function ekfUpdateScalar(x, P, h, innovation, r, rejectK = 0) {
|
|
12801
|
+
const n = x.length;
|
|
12802
|
+
const Ph = matVec(P, h);
|
|
12803
|
+
let hPh = 0;
|
|
12804
|
+
for (let i = 0; i < n; i++) hPh += h[i] * Ph[i];
|
|
12805
|
+
const s = hPh + r;
|
|
12806
|
+
if (s <= 0) return false;
|
|
12807
|
+
if (rejectK > 0 && innovation * innovation > rejectK * rejectK * s) {
|
|
12808
|
+
return false;
|
|
12809
|
+
}
|
|
12810
|
+
const K = Ph.map((v) => v / s);
|
|
12811
|
+
for (let i = 0; i < n; i++) x[i] += K[i] * innovation;
|
|
12812
|
+
for (let i = 0; i < n; i++) {
|
|
12813
|
+
for (let j = 0; j < n; j++) {
|
|
12814
|
+
P[i][j] -= K[i] * Ph[j];
|
|
12815
|
+
}
|
|
12816
|
+
}
|
|
12817
|
+
for (let i = 0; i < n; i++) {
|
|
12818
|
+
for (let j = i + 1; j < n; j++) {
|
|
12819
|
+
const m = 0.5 * (P[i][j] + P[j][i]);
|
|
12820
|
+
P[i][j] = m;
|
|
12821
|
+
P[j][i] = m;
|
|
12822
|
+
}
|
|
12823
|
+
}
|
|
12824
|
+
return true;
|
|
12825
|
+
}
|
|
12826
|
+
function ifCoeffs(f1, f2) {
|
|
12827
|
+
const g = f1 * f1 / (f1 * f1 - f2 * f2);
|
|
12828
|
+
const lambdaIf = C_LIGHT / (f1 + f2);
|
|
12829
|
+
return { g, lambdaIf };
|
|
12830
|
+
}
|
|
12831
|
+
function sagnacRotate(x, y, z, travelS) {
|
|
12832
|
+
const theta = OMEGA_E * travelS;
|
|
12833
|
+
const c = Math.cos(theta);
|
|
12834
|
+
const s = Math.sin(theta);
|
|
12835
|
+
return [x * c + y * s, -x * s + y * c, z];
|
|
12836
|
+
}
|
|
12837
|
+
function satStateAtEmission(sp3, prn, recvTimeMs, rcv) {
|
|
12838
|
+
let travelS = 0.075;
|
|
12839
|
+
let sx = 0;
|
|
12840
|
+
let sy = 0;
|
|
12841
|
+
let sz = 0;
|
|
12842
|
+
let clkS = null;
|
|
12843
|
+
let velDotPos = 0;
|
|
12844
|
+
for (let iter = 0; iter < 3; iter++) {
|
|
12845
|
+
const tEmit = recvTimeMs - travelS * 1e3;
|
|
12846
|
+
const p = sp3Position(sp3, prn, tEmit);
|
|
12847
|
+
if (!p || p.clk == null) return null;
|
|
12848
|
+
const pPlus = sp3Position(sp3, prn, tEmit + 500);
|
|
12849
|
+
const pMinus = sp3Position(sp3, prn, tEmit - 500);
|
|
12850
|
+
if (pPlus && pMinus) {
|
|
12851
|
+
const vx = (pPlus.x - pMinus.x) / 1;
|
|
12852
|
+
const vy = (pPlus.y - pMinus.y) / 1;
|
|
12853
|
+
const vz = (pPlus.z - pMinus.z) / 1;
|
|
12854
|
+
velDotPos = p.x * vx + p.y * vy + p.z * vz;
|
|
12855
|
+
}
|
|
12856
|
+
clkS = p.clk;
|
|
12857
|
+
const [rx, ry, rz] = sagnacRotate(p.x, p.y, p.z, travelS);
|
|
12858
|
+
sx = rx;
|
|
12859
|
+
sy = ry;
|
|
12860
|
+
sz = rz;
|
|
12861
|
+
const dx = sx - rcv[0];
|
|
12862
|
+
const dy = sy - rcv[1];
|
|
12863
|
+
const dz = sz - rcv[2];
|
|
12864
|
+
const range = Math.hypot(dx, dy, dz);
|
|
12865
|
+
travelS = range / C_LIGHT;
|
|
12866
|
+
}
|
|
12867
|
+
if (clkS == null) return null;
|
|
12868
|
+
const relS = -2 * velDotPos / (C_LIGHT * C_LIGHT);
|
|
12869
|
+
const clkM = C_LIGHT * (clkS + relS);
|
|
12870
|
+
return { state: { x: sx, y: sy, z: sz, clkM }, travelS };
|
|
12871
|
+
}
|
|
12872
|
+
var IDX_X = 0;
|
|
12873
|
+
var IDX_Y = 1;
|
|
12874
|
+
var IDX_Z = 2;
|
|
12875
|
+
var IDX_CLK = 3;
|
|
12876
|
+
var IDX_ZWD = 4;
|
|
12877
|
+
var NBASE = 5;
|
|
12878
|
+
function solvePpp(epochs, sp3, opts) {
|
|
12879
|
+
const elevMask = (opts.elevationMaskDeg ?? 10) * Math.PI / 180;
|
|
12880
|
+
const codeSigma = opts.codeSigma ?? 3;
|
|
12881
|
+
const phaseSigma = opts.phaseSigma ?? 0.01;
|
|
12882
|
+
const ztdQ = opts.ztdProcessNoise ?? 1e-8;
|
|
12883
|
+
const corrections = opts.corrections;
|
|
12884
|
+
const x = [
|
|
12885
|
+
opts.aprioriPos[0],
|
|
12886
|
+
opts.aprioriPos[1],
|
|
12887
|
+
opts.aprioriPos[2],
|
|
12888
|
+
0,
|
|
12889
|
+
// receiver clock (m)
|
|
12890
|
+
0.1
|
|
12891
|
+
// zenith wet delay (m) a priori
|
|
12892
|
+
];
|
|
12893
|
+
const P = [];
|
|
12894
|
+
for (let i = 0; i < NBASE; i++) {
|
|
12895
|
+
P.push(new Array(NBASE).fill(0));
|
|
12896
|
+
}
|
|
12897
|
+
P[IDX_X][IDX_X] = 100 * 100;
|
|
12898
|
+
P[IDX_Y][IDX_Y] = 100 * 100;
|
|
12899
|
+
P[IDX_Z][IDX_Z] = 100 * 100;
|
|
12900
|
+
P[IDX_CLK][IDX_CLK] = 1e10;
|
|
12901
|
+
P[IDX_ZWD][IDX_ZWD] = 0.5 * 0.5;
|
|
12902
|
+
const ambIdx = /* @__PURE__ */ new Map();
|
|
12903
|
+
const lastSeen = /* @__PURE__ */ new Map();
|
|
12904
|
+
const mwState = /* @__PURE__ */ new Map();
|
|
12905
|
+
const detectSlip = (o, ei) => {
|
|
12906
|
+
const lamW = C_LIGHT / (o.f1 - o.f2);
|
|
12907
|
+
const lw = o.l1 - o.l2;
|
|
12908
|
+
const pn = (o.f1 * o.c1 + o.f2 * o.c2) / (o.f1 + o.f2);
|
|
12909
|
+
const mw = lw - pn / lamW;
|
|
12910
|
+
const st = mwState.get(o.prn);
|
|
12911
|
+
let slip = o.slip;
|
|
12912
|
+
if (!st || ei - st.lastEi > 2)
|
|
12913
|
+
slip = true;
|
|
12914
|
+
else if (Math.abs(mw - st.mean) > 4) slip = true;
|
|
12915
|
+
if (slip) mwState.set(o.prn, { mean: mw, n: 1, lastEi: ei });
|
|
12916
|
+
else {
|
|
12917
|
+
const n = st.n + 1;
|
|
12918
|
+
mwState.set(o.prn, {
|
|
12919
|
+
mean: st.mean + (mw - st.mean) / Math.min(n, 100),
|
|
12920
|
+
n,
|
|
12921
|
+
lastEi: ei
|
|
12922
|
+
});
|
|
12923
|
+
}
|
|
12924
|
+
return slip;
|
|
12925
|
+
};
|
|
12926
|
+
const growState = (initVal, initVar) => {
|
|
12927
|
+
const idx = x.length;
|
|
12928
|
+
x.push(initVal);
|
|
12929
|
+
for (const row of P) row.push(0);
|
|
12930
|
+
P.push(new Array(x.length).fill(0));
|
|
12931
|
+
P[idx][idx] = initVar;
|
|
12932
|
+
return idx;
|
|
12933
|
+
};
|
|
12934
|
+
const dropState = (idx) => {
|
|
12935
|
+
x.splice(idx, 1);
|
|
12936
|
+
P.splice(idx, 1);
|
|
12937
|
+
for (const row of P) row.splice(idx, 1);
|
|
12938
|
+
for (const [prn, i] of ambIdx) {
|
|
12939
|
+
if (i === idx) ambIdx.delete(prn);
|
|
12940
|
+
else if (i > idx) ambIdx.set(prn, i - 1);
|
|
12941
|
+
}
|
|
12942
|
+
};
|
|
12943
|
+
let clockSeeded = false;
|
|
12944
|
+
const series = [];
|
|
12945
|
+
const truth = opts.groundTruth;
|
|
12946
|
+
const t0 = epochs[0]?.timeMs ?? 0;
|
|
12947
|
+
let convergenceSec = null;
|
|
12948
|
+
let convergedStreak = 0;
|
|
12949
|
+
for (let ei = 0; ei < epochs.length; ei++) {
|
|
12950
|
+
const epoch = epochs[ei];
|
|
12951
|
+
P[IDX_CLK][IDX_CLK] = 1e10;
|
|
12952
|
+
P[IDX_ZWD][IDX_ZWD] += ztdQ * (ei > 0 ? 1 : 0);
|
|
12953
|
+
const rcv = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
|
|
12954
|
+
const [latDeg, , heightM] = ecefToGeodetic(rcv[0], rcv[1], rcv[2]);
|
|
12955
|
+
const latRad = latDeg * Math.PI / 180;
|
|
12956
|
+
const epochCtx = corrections?.epochContext?.(epoch.timeMs, rcv) ?? null;
|
|
12957
|
+
const vis = [];
|
|
12958
|
+
for (const o of epoch.obs) {
|
|
12959
|
+
if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
|
|
12960
|
+
const slip = detectSlip(o, ei);
|
|
12961
|
+
const sat = satStateAtEmission(sp3, o.prn, epoch.timeMs, rcv);
|
|
12962
|
+
if (!sat) continue;
|
|
12963
|
+
const [elRad, azRad] = getAer(
|
|
12964
|
+
sat.state.x,
|
|
12965
|
+
sat.state.y,
|
|
12966
|
+
sat.state.z,
|
|
12967
|
+
rcv[0],
|
|
12968
|
+
rcv[1],
|
|
12969
|
+
rcv[2]
|
|
12970
|
+
);
|
|
12971
|
+
if (elRad < elevMask) continue;
|
|
12972
|
+
const dx = sat.state.x - rcv[0];
|
|
12973
|
+
const dy = sat.state.y - rcv[1];
|
|
12974
|
+
const dz = sat.state.z - rcv[2];
|
|
12975
|
+
const range = Math.hypot(dx, dy, dz);
|
|
12976
|
+
const e = [dx / range, dy / range, dz / range];
|
|
12977
|
+
const { g } = ifCoeffs(o.f1, o.f2);
|
|
12978
|
+
const lam1 = C_LIGHT / o.f1;
|
|
12979
|
+
const lam2 = C_LIGHT / o.f2;
|
|
12980
|
+
if (o.c1 === 0 || o.c2 === 0 || o.l1 === 0 || o.l2 === 0) continue;
|
|
12981
|
+
const pIf = g * o.c1 - (g - 1) * o.c2;
|
|
12982
|
+
const lIf = g * (o.l1 * lam1) - (g - 1) * (o.l2 * lam2);
|
|
12983
|
+
if (!Number.isFinite(pIf) || !Number.isFinite(lIf)) continue;
|
|
12984
|
+
const trop = opts.troposphere ?? true ? niellMapping(elRad, latRad, heightM, epoch.timeMs) : { zhd: 0, mh: 0, mw: 0 };
|
|
12985
|
+
const { zhd, mh, mw } = trop;
|
|
12986
|
+
const geom = {
|
|
12987
|
+
prn: o.prn,
|
|
12988
|
+
satEcef: [sat.state.x, sat.state.y, sat.state.z],
|
|
12989
|
+
rcvEcef: rcv,
|
|
12990
|
+
los: e,
|
|
12991
|
+
elRad,
|
|
12992
|
+
azRad,
|
|
12993
|
+
f1: o.f1,
|
|
12994
|
+
f2: o.f2,
|
|
12995
|
+
band1: o.band1,
|
|
12996
|
+
band2: o.band2,
|
|
12997
|
+
g
|
|
12998
|
+
};
|
|
12999
|
+
const corr = corrections ? applyCorrections(corrections, geom, epochCtx) : { rangeM: 0, phaseWindupM: 0 };
|
|
13000
|
+
vis.push({
|
|
13001
|
+
prn: o.prn,
|
|
13002
|
+
e,
|
|
13003
|
+
elRad,
|
|
13004
|
+
pIf,
|
|
13005
|
+
lIf,
|
|
13006
|
+
satClkM: sat.state.clkM,
|
|
13007
|
+
range,
|
|
13008
|
+
tropoFixed: zhd * mh + corr.rangeM,
|
|
13009
|
+
mw,
|
|
13010
|
+
windupM: corr.phaseWindupM,
|
|
13011
|
+
slip
|
|
13012
|
+
});
|
|
13013
|
+
}
|
|
13014
|
+
const zwd0 = x[IDX_ZWD];
|
|
13015
|
+
if (vis.length > 0) {
|
|
13016
|
+
if (!clockSeeded) {
|
|
13017
|
+
const s = vis.map(
|
|
13018
|
+
(v) => v.pIf - (v.range - v.satClkM + v.tropoFixed + zwd0 * v.mw)
|
|
13019
|
+
).sort((a, b) => a - b);
|
|
13020
|
+
x[IDX_CLK] = s[Math.floor(s.length / 2)];
|
|
13021
|
+
clockSeeded = true;
|
|
13022
|
+
}
|
|
13023
|
+
P[IDX_CLK][IDX_CLK] = 1e10;
|
|
13024
|
+
}
|
|
13025
|
+
let nSats = 0;
|
|
13026
|
+
let sumPhaseResSq = 0;
|
|
13027
|
+
let nPhaseRes = 0;
|
|
13028
|
+
for (const v of vis) {
|
|
13029
|
+
const common = v.range + x[IDX_CLK] - v.satClkM + v.tropoFixed + zwd0 * v.mw;
|
|
13030
|
+
let ai = ambIdx.get(v.prn);
|
|
13031
|
+
if (ai === void 0 || v.slip) {
|
|
13032
|
+
const bInit = v.lIf - (common + v.windupM);
|
|
13033
|
+
if (ai === void 0) {
|
|
13034
|
+
ai = growState(bInit, 100 * 100);
|
|
13035
|
+
} else {
|
|
13036
|
+
x[ai] = bInit;
|
|
13037
|
+
for (let j = 0; j < P.length; j++) {
|
|
13038
|
+
P[ai][j] = 0;
|
|
13039
|
+
P[j][ai] = 0;
|
|
13040
|
+
}
|
|
13041
|
+
P[ai][ai] = 100 * 100;
|
|
13042
|
+
}
|
|
13043
|
+
ambIdx.set(v.prn, ai);
|
|
13044
|
+
}
|
|
13045
|
+
const n = x.length;
|
|
13046
|
+
const sinEl = Math.max(Math.sin(v.elRad), 0.1);
|
|
13047
|
+
const rCode = (codeSigma / sinEl) ** 2;
|
|
13048
|
+
const rPhase = (phaseSigma / sinEl) ** 2;
|
|
13049
|
+
{
|
|
13050
|
+
const h = new Array(n).fill(0);
|
|
13051
|
+
h[IDX_X] = -v.e[0];
|
|
13052
|
+
h[IDX_Y] = -v.e[1];
|
|
13053
|
+
h[IDX_Z] = -v.e[2];
|
|
13054
|
+
h[IDX_CLK] = 1;
|
|
13055
|
+
h[IDX_ZWD] = v.mw;
|
|
13056
|
+
const innov = v.pIf - common;
|
|
13057
|
+
if (Math.abs(innov) < 1e6) ekfUpdateScalar(x, P, h, innov, rCode, 4);
|
|
13058
|
+
}
|
|
13059
|
+
{
|
|
13060
|
+
const commonPh = v.range + x[IDX_CLK] - v.satClkM + v.tropoFixed + x[IDX_ZWD] * v.mw;
|
|
13061
|
+
const innov = v.lIf - (commonPh + v.windupM + x[ai]);
|
|
13062
|
+
if (Math.abs(innov) > 0.15) {
|
|
13063
|
+
x[ai] = v.lIf - (commonPh + v.windupM);
|
|
13064
|
+
for (let j = 0; j < P.length; j++) {
|
|
13065
|
+
P[ai][j] = 0;
|
|
13066
|
+
P[j][ai] = 0;
|
|
13067
|
+
}
|
|
13068
|
+
P[ai][ai] = 100 * 100;
|
|
13069
|
+
} else {
|
|
13070
|
+
const h = new Array(n).fill(0);
|
|
13071
|
+
h[IDX_X] = -v.e[0];
|
|
13072
|
+
h[IDX_Y] = -v.e[1];
|
|
13073
|
+
h[IDX_Z] = -v.e[2];
|
|
13074
|
+
h[IDX_CLK] = 1;
|
|
13075
|
+
h[IDX_ZWD] = v.mw;
|
|
13076
|
+
h[ai] = 1;
|
|
13077
|
+
if (ekfUpdateScalar(x, P, h, innov, rPhase, 4)) {
|
|
13078
|
+
sumPhaseResSq += innov * innov;
|
|
13079
|
+
nPhaseRes++;
|
|
13080
|
+
}
|
|
13081
|
+
}
|
|
13082
|
+
}
|
|
13083
|
+
lastSeen.set(v.prn, ei);
|
|
13084
|
+
nSats++;
|
|
13085
|
+
}
|
|
13086
|
+
for (const [prn, seen] of [...lastSeen]) {
|
|
13087
|
+
if (ei - seen > 20) {
|
|
13088
|
+
const idx = ambIdx.get(prn);
|
|
13089
|
+
if (idx !== void 0) dropState(idx);
|
|
13090
|
+
lastSeen.delete(prn);
|
|
13091
|
+
}
|
|
13092
|
+
}
|
|
13093
|
+
const pos = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
|
|
13094
|
+
let enu = null;
|
|
13095
|
+
let error3d = null;
|
|
13096
|
+
if (truth) {
|
|
13097
|
+
enu = getEnuDifference(
|
|
13098
|
+
pos[0],
|
|
13099
|
+
pos[1],
|
|
13100
|
+
pos[2],
|
|
13101
|
+
truth[0],
|
|
13102
|
+
truth[1],
|
|
13103
|
+
truth[2]
|
|
13104
|
+
);
|
|
13105
|
+
error3d = Math.hypot(
|
|
13106
|
+
pos[0] - truth[0],
|
|
13107
|
+
pos[1] - truth[1],
|
|
13108
|
+
pos[2] - truth[2]
|
|
13109
|
+
);
|
|
13110
|
+
if (error3d < 0.1) {
|
|
13111
|
+
convergedStreak++;
|
|
13112
|
+
if (convergedStreak >= 10 && convergenceSec == null) {
|
|
13113
|
+
convergenceSec = (epoch.timeMs - t0) / 1e3;
|
|
13114
|
+
}
|
|
13115
|
+
} else {
|
|
13116
|
+
convergedStreak = 0;
|
|
13117
|
+
convergenceSec = null;
|
|
13118
|
+
}
|
|
13119
|
+
}
|
|
13120
|
+
series.push({
|
|
13121
|
+
timeMs: epoch.timeMs,
|
|
13122
|
+
enu,
|
|
13123
|
+
error3d,
|
|
13124
|
+
position: pos,
|
|
13125
|
+
nSats,
|
|
13126
|
+
ztdWet: x[IDX_ZWD],
|
|
13127
|
+
phaseResRms: nPhaseRes > 0 ? Math.sqrt(sumPhaseResSq / nPhaseRes) : 0
|
|
13128
|
+
});
|
|
13129
|
+
}
|
|
13130
|
+
const finalPos = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
|
|
13131
|
+
const llh = ecefToGeodetic(finalPos[0], finalPos[1], finalPos[2]);
|
|
13132
|
+
const finalError3d = truth ? Math.hypot(
|
|
13133
|
+
finalPos[0] - truth[0],
|
|
13134
|
+
finalPos[1] - truth[1],
|
|
13135
|
+
finalPos[2] - truth[2]
|
|
13136
|
+
) : null;
|
|
13137
|
+
return {
|
|
13138
|
+
position: finalPos,
|
|
13139
|
+
llh,
|
|
13140
|
+
series,
|
|
13141
|
+
ztdWet: x[IDX_ZWD],
|
|
13142
|
+
epochsUsed: epochs.length,
|
|
13143
|
+
convergenceSec,
|
|
13144
|
+
finalError3d
|
|
13145
|
+
};
|
|
13146
|
+
}
|
|
13147
|
+
|
|
11909
13148
|
// src/positioning/index.ts
|
|
11910
13149
|
var GM_GPS3 = 3986005e8;
|
|
11911
13150
|
var F_REL = -4442807633e-19;
|
|
@@ -12046,7 +13285,8 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
12046
13285
|
let ionoM = 0;
|
|
12047
13286
|
if ((gim || iono) && positionSane) {
|
|
12048
13287
|
let l1M = null;
|
|
12049
|
-
if (gim)
|
|
13288
|
+
if (gim)
|
|
13289
|
+
l1M = gimSlantIonoDelayL1(gim, rxLat, rxLon, azim, elev, timeMs);
|
|
12050
13290
|
if (l1M === null && iono) {
|
|
12051
13291
|
l1M = C_LIGHT * klobucharDelay(iono, rxLat, rxLon, azim, elev, gpsTow);
|
|
12052
13292
|
}
|
|
@@ -14490,6 +15730,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
14490
15730
|
binexRecords,
|
|
14491
15731
|
buildGloChannelMap,
|
|
14492
15732
|
buildObsIndices,
|
|
15733
|
+
buildPppAntenna,
|
|
14493
15734
|
clampUnit,
|
|
14494
15735
|
computeAllPositions,
|
|
14495
15736
|
computeDop,
|
|
@@ -14503,6 +15744,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
14503
15744
|
connectToMountpoint,
|
|
14504
15745
|
crc32,
|
|
14505
15746
|
createGzipLineSink,
|
|
15747
|
+
createPppCorrections,
|
|
14506
15748
|
createStationMeta,
|
|
14507
15749
|
createStreamStats,
|
|
14508
15750
|
crxDecompress,
|
|
@@ -14588,6 +15830,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
14588
15830
|
glonassAlmanacEpochMs,
|
|
14589
15831
|
glonassAlmanacPosition,
|
|
14590
15832
|
glonassPosition,
|
|
15833
|
+
gmst,
|
|
14591
15834
|
greatCircleMidpoint,
|
|
14592
15835
|
hdrLine,
|
|
14593
15836
|
horizonDistance,
|
|
@@ -14597,8 +15840,10 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
14597
15840
|
lambdaReduction,
|
|
14598
15841
|
lambdaSearch,
|
|
14599
15842
|
maskRadForAzimuth,
|
|
15843
|
+
moonEcef,
|
|
14600
15844
|
msmEpochToDate,
|
|
14601
15845
|
navTimesFromEph,
|
|
15846
|
+
niellMapping,
|
|
14602
15847
|
nmeaCoordToDecimal,
|
|
14603
15848
|
oem4Frames,
|
|
14604
15849
|
padL,
|
|
@@ -14648,10 +15893,13 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
14648
15893
|
selectEphemeris,
|
|
14649
15894
|
setGloFreqNumber,
|
|
14650
15895
|
setRtcm3DebugHandler,
|
|
15896
|
+
solidEarthTide,
|
|
14651
15897
|
solveDgnss,
|
|
15898
|
+
solvePpp,
|
|
14652
15899
|
solveSpp,
|
|
14653
15900
|
sp3Position,
|
|
14654
15901
|
stationHeaderLines,
|
|
15902
|
+
sunEcef,
|
|
14655
15903
|
systemCmp,
|
|
14656
15904
|
systemName,
|
|
14657
15905
|
toRtkEpoch,
|
|
@@ -14662,6 +15910,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
14662
15910
|
updateStreamStats,
|
|
14663
15911
|
verifyChecksum,
|
|
14664
15912
|
vincenty,
|
|
15913
|
+
writeCrx,
|
|
14665
15914
|
writeModernObsBlob,
|
|
14666
15915
|
writeRinex2ObsBlob,
|
|
14667
15916
|
writeRinex4ObsBlob,
|