gnss-js 2.1.0 → 2.3.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-DWUQRJ37.js → chunk-TYJNN77C.js} +275 -178
- package/dist/{chunk-WVTDVPKA.js → chunk-XPQ4BU6W.js} +2 -1
- package/dist/index.cjs +279 -178
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8 -2
- package/dist/positioning.cjs +277 -177
- package/dist/positioning.d.cts +91 -23
- package/dist/positioning.d.ts +91 -23
- package/dist/positioning.js +7 -1
- package/dist/rtcm3.cjs +2 -1
- package/dist/rtcm3.d.cts +4 -1
- package/dist/rtcm3.d.ts +4 -1
- package/dist/rtcm3.js +1 -1
- package/package.json +1 -1
|
@@ -302,6 +302,211 @@ function lambdaReduction(Q, n) {
|
|
|
302
302
|
return Z;
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
+
// src/positioning/ppp-antenna.ts
|
|
306
|
+
function parseAntexTime(s) {
|
|
307
|
+
const p = s.trim().split(/\s+/).map(Number);
|
|
308
|
+
if (p.length < 3 || p.some((v) => Number.isNaN(v))) return null;
|
|
309
|
+
return Date.UTC(
|
|
310
|
+
p[0],
|
|
311
|
+
(p[1] || 1) - 1,
|
|
312
|
+
p[2] || 1,
|
|
313
|
+
p[3] ?? 0,
|
|
314
|
+
p[4] ?? 0,
|
|
315
|
+
Math.floor(p[5] ?? 0)
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
function freqOf(entry, code) {
|
|
319
|
+
return entry.frequencies.find((f) => f.frequency === code);
|
|
320
|
+
}
|
|
321
|
+
function combineIf(fA, fB, f1, f2) {
|
|
322
|
+
const g = f1 * f1 / (f1 * f1 - f2 * f2);
|
|
323
|
+
const mm = 1e-3;
|
|
324
|
+
const pco = [
|
|
325
|
+
(g * fA.pcoN - (g - 1) * fB.pcoN) * mm,
|
|
326
|
+
(g * fA.pcoE - (g - 1) * fB.pcoE) * mm,
|
|
327
|
+
(g * fA.pcoU - (g - 1) * fB.pcoU) * mm
|
|
328
|
+
];
|
|
329
|
+
const nz = Math.min(fA.pcvNoazi.length, fB.pcvNoazi.length);
|
|
330
|
+
const pcvNoazi = new Array(nz);
|
|
331
|
+
for (let i = 0; i < nz; i++) {
|
|
332
|
+
pcvNoazi[i] = (g * fA.pcvNoazi[i] - (g - 1) * fB.pcvNoazi[i]) * mm;
|
|
333
|
+
}
|
|
334
|
+
return { pco, pcvZen1Deg: 0, pcvDzenDeg: 0, pcvNoazi };
|
|
335
|
+
}
|
|
336
|
+
function buildPppAntenna(antex) {
|
|
337
|
+
const sats = /* @__PURE__ */ new Map();
|
|
338
|
+
const rcvs = /* @__PURE__ */ new Map();
|
|
339
|
+
for (const a of antex.antennas) {
|
|
340
|
+
if (a.isSatellite) {
|
|
341
|
+
const list = sats.get(a.serialNo) ?? [];
|
|
342
|
+
list.push(a);
|
|
343
|
+
sats.set(a.serialNo, list);
|
|
344
|
+
} else if (!rcvs.has(a.type)) {
|
|
345
|
+
rcvs.set(a.type, a);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
const withZen = (entry, off) => ({
|
|
349
|
+
...off,
|
|
350
|
+
pcvZen1Deg: entry.zen1,
|
|
351
|
+
pcvDzenDeg: entry.dzen
|
|
352
|
+
});
|
|
353
|
+
return {
|
|
354
|
+
satOffset(prn, dateMs, band1, band2, f1, f2) {
|
|
355
|
+
const list = sats.get(prn);
|
|
356
|
+
if (!list) return null;
|
|
357
|
+
const entry = list.find((e) => {
|
|
358
|
+
const from = parseAntexTime(e.validFrom);
|
|
359
|
+
const until = parseAntexTime(e.validUntil);
|
|
360
|
+
return (from == null || dateMs >= from) && (until == null || dateMs <= until);
|
|
361
|
+
});
|
|
362
|
+
if (!entry) return null;
|
|
363
|
+
const a = freqOf(entry, band1);
|
|
364
|
+
const b = freqOf(entry, band2);
|
|
365
|
+
if (!a || !b) return null;
|
|
366
|
+
return withZen(entry, combineIf(a, b, f1, f2));
|
|
367
|
+
},
|
|
368
|
+
rcvOffset(antType, band1, band2, f1, f2) {
|
|
369
|
+
const entry = rcvs.get(antType);
|
|
370
|
+
if (!entry) return null;
|
|
371
|
+
const a = freqOf(entry, band1);
|
|
372
|
+
const b = freqOf(entry, band2);
|
|
373
|
+
if (!a || !b) return null;
|
|
374
|
+
return withZen(entry, combineIf(a, b, f1, f2));
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
function cross(a, b) {
|
|
379
|
+
return [
|
|
380
|
+
a[1] * b[2] - a[2] * b[1],
|
|
381
|
+
a[2] * b[0] - a[0] * b[2],
|
|
382
|
+
a[0] * b[1] - a[1] * b[0]
|
|
383
|
+
];
|
|
384
|
+
}
|
|
385
|
+
function norm(a) {
|
|
386
|
+
const n = Math.hypot(a[0], a[1], a[2]) || 1;
|
|
387
|
+
return [a[0] / n, a[1] / n, a[2] / n];
|
|
388
|
+
}
|
|
389
|
+
function dot(a, b) {
|
|
390
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
391
|
+
}
|
|
392
|
+
function satBodyFrame(satEcef, sunEcef2) {
|
|
393
|
+
const z = norm([-satEcef[0], -satEcef[1], -satEcef[2]]);
|
|
394
|
+
const eSun = norm([
|
|
395
|
+
sunEcef2[0] - satEcef[0],
|
|
396
|
+
sunEcef2[1] - satEcef[1],
|
|
397
|
+
sunEcef2[2] - satEcef[2]
|
|
398
|
+
]);
|
|
399
|
+
const y = norm(cross(z, eSun));
|
|
400
|
+
const x = norm(cross(y, z));
|
|
401
|
+
return { x, y, z };
|
|
402
|
+
}
|
|
403
|
+
function satPcoToEcef(pcoBody, frame) {
|
|
404
|
+
return [
|
|
405
|
+
pcoBody[0] * frame.x[0] + pcoBody[1] * frame.y[0] + pcoBody[2] * frame.z[0],
|
|
406
|
+
pcoBody[0] * frame.x[1] + pcoBody[1] * frame.y[1] + pcoBody[2] * frame.z[1],
|
|
407
|
+
pcoBody[0] * frame.x[2] + pcoBody[1] * frame.y[2] + pcoBody[2] * frame.z[2]
|
|
408
|
+
];
|
|
409
|
+
}
|
|
410
|
+
function enuToEcef(enu, latRad, lonRad) {
|
|
411
|
+
const sl = Math.sin(latRad);
|
|
412
|
+
const cl = Math.cos(latRad);
|
|
413
|
+
const so = Math.sin(lonRad);
|
|
414
|
+
const co = Math.cos(lonRad);
|
|
415
|
+
const [e, n, u] = enu;
|
|
416
|
+
return [
|
|
417
|
+
-so * e - sl * co * n + cl * co * u,
|
|
418
|
+
co * e - sl * so * n + cl * so * u,
|
|
419
|
+
cl * n + sl * u
|
|
420
|
+
];
|
|
421
|
+
}
|
|
422
|
+
function interpPcv(off, angleDeg) {
|
|
423
|
+
const { pcvZen1Deg, pcvDzenDeg, pcvNoazi } = off;
|
|
424
|
+
if (pcvDzenDeg <= 0 || pcvNoazi.length < 2) return 0;
|
|
425
|
+
const x = (angleDeg - pcvZen1Deg) / pcvDzenDeg;
|
|
426
|
+
if (x <= 0) return pcvNoazi[0];
|
|
427
|
+
if (x >= pcvNoazi.length - 1) return pcvNoazi[pcvNoazi.length - 1];
|
|
428
|
+
const i = Math.floor(x);
|
|
429
|
+
const t = x - i;
|
|
430
|
+
return pcvNoazi[i] * (1 - t) + pcvNoazi[i + 1] * t;
|
|
431
|
+
}
|
|
432
|
+
function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
|
|
433
|
+
const k = [
|
|
434
|
+
-losRcvToSat[0],
|
|
435
|
+
-losRcvToSat[1],
|
|
436
|
+
-losRcvToSat[2]
|
|
437
|
+
];
|
|
438
|
+
const kx = satFrame.x;
|
|
439
|
+
const ky = satFrame.y;
|
|
440
|
+
const kdotx = dot(k, kx);
|
|
441
|
+
const kcrossY = cross(k, ky);
|
|
442
|
+
const dS = [
|
|
443
|
+
kx[0] - k[0] * kdotx - kcrossY[0],
|
|
444
|
+
kx[1] - k[1] * kdotx - kcrossY[1],
|
|
445
|
+
kx[2] - k[2] * kdotx - kcrossY[2]
|
|
446
|
+
];
|
|
447
|
+
const north = enuToEcef([0, 1, 0], latRad, lonRad);
|
|
448
|
+
const east = enuToEcef([1, 0, 0], latRad, lonRad);
|
|
449
|
+
const kdotn = dot(k, north);
|
|
450
|
+
const kcrossE = cross(k, east);
|
|
451
|
+
const dR = [
|
|
452
|
+
north[0] - k[0] * kdotn + kcrossE[0],
|
|
453
|
+
north[1] - k[1] * kdotn + kcrossE[1],
|
|
454
|
+
north[2] - k[2] * kdotn + kcrossE[2]
|
|
455
|
+
];
|
|
456
|
+
const nS = Math.hypot(dS[0], dS[1], dS[2]) || 1;
|
|
457
|
+
const nR = Math.hypot(dR[0], dR[1], dR[2]) || 1;
|
|
458
|
+
let cosPhi = dot(dS, dR) / (nS * nR);
|
|
459
|
+
cosPhi = Math.max(-1, Math.min(1, cosPhi));
|
|
460
|
+
const zeta = cross(dS, dR);
|
|
461
|
+
const sign = dot(k, zeta) >= 0 ? 1 : -1;
|
|
462
|
+
const dphi = sign * Math.acos(cosPhi) / (2 * Math.PI);
|
|
463
|
+
const prev = state.get(prn);
|
|
464
|
+
const wu = prev == null ? dphi : dphi + Math.round(prev - dphi);
|
|
465
|
+
state.set(prn, wu);
|
|
466
|
+
return wu;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// src/positioning/rtk-antenna.ts
|
|
470
|
+
function freqOf2(entry, code) {
|
|
471
|
+
return entry.frequencies.find((f) => f.frequency === code);
|
|
472
|
+
}
|
|
473
|
+
function buildRtkAntenna(antex) {
|
|
474
|
+
const rcvs = /* @__PURE__ */ new Map();
|
|
475
|
+
for (const a of antex.antennas) {
|
|
476
|
+
if (!a.isSatellite && !rcvs.has(a.type)) rcvs.set(a.type, a);
|
|
477
|
+
}
|
|
478
|
+
const mm = 1e-3;
|
|
479
|
+
return {
|
|
480
|
+
rcvOffset(antType, freq) {
|
|
481
|
+
const entry = rcvs.get(antType);
|
|
482
|
+
if (!entry) return null;
|
|
483
|
+
const f = freqOf2(entry, freq);
|
|
484
|
+
if (!f) return null;
|
|
485
|
+
return {
|
|
486
|
+
pco: [f.pcoN * mm, f.pcoE * mm, f.pcoU * mm],
|
|
487
|
+
pcvZen1Deg: entry.zen1,
|
|
488
|
+
pcvDzenDeg: entry.dzen,
|
|
489
|
+
pcvNoazi: f.pcvNoazi.map((v) => v * mm)
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
function rcvAntennaRangeM(off, losRcvToSat, latRad, lonRad, elRad, antDeltaEnu = [0, 0, 0]) {
|
|
495
|
+
const total = [
|
|
496
|
+
off.pco[0] + antDeltaEnu[0],
|
|
497
|
+
off.pco[1] + antDeltaEnu[1],
|
|
498
|
+
off.pco[2] + antDeltaEnu[2]
|
|
499
|
+
];
|
|
500
|
+
const ecef = enuToEcef(total, latRad, lonRad);
|
|
501
|
+
let m = -dot(losRcvToSat, ecef);
|
|
502
|
+
const zenithDeg = 90 - elRad * 180 / Math.PI;
|
|
503
|
+
m += interpPcv(off, zenithDeg);
|
|
504
|
+
return m;
|
|
505
|
+
}
|
|
506
|
+
function antexFreqOfGroup(group) {
|
|
507
|
+
return `${group[0]}0${group[1]}`;
|
|
508
|
+
}
|
|
509
|
+
|
|
305
510
|
// src/positioning/rtk.ts
|
|
306
511
|
var L1_CODES = {
|
|
307
512
|
G: ["1C"],
|
|
@@ -367,8 +572,16 @@ function resolveEphemeris(src, prn, timeMs) {
|
|
|
367
572
|
return selectEphemeris(src, prn, timeMs);
|
|
368
573
|
return src.get(prn) ?? null;
|
|
369
574
|
}
|
|
370
|
-
|
|
575
|
+
var ZERO_DELTA = [0, 0, 0];
|
|
576
|
+
function buildGeometry(rover, base, basePos, ephemerides, timeMs, maskRad, troposphere, antenna = null) {
|
|
371
577
|
const out = [];
|
|
578
|
+
let baseLatRad = 0;
|
|
579
|
+
let baseLonRad = 0;
|
|
580
|
+
if (antenna?.base) {
|
|
581
|
+
const [latDeg, lonDeg] = ecefToGeodetic(basePos[0], basePos[1], basePos[2]);
|
|
582
|
+
baseLatRad = latDeg * Math.PI / 180;
|
|
583
|
+
baseLonRad = lonDeg * Math.PI / 180;
|
|
584
|
+
}
|
|
372
585
|
for (const [prn, mR] of rover) {
|
|
373
586
|
const sys = prn[0];
|
|
374
587
|
if (!"GERCJ".includes(sys)) continue;
|
|
@@ -393,14 +606,43 @@ function buildGeometry(rover, base, basePos, ephemerides, timeMs, maskRad, tropo
|
|
|
393
606
|
satB.z - basePos[2]
|
|
394
607
|
) / C_LIGHT;
|
|
395
608
|
const [bx, by, bz] = sagnac(satB, travelB);
|
|
396
|
-
|
|
609
|
+
let rhoB = Math.hypot(bx - basePos[0], by - basePos[1], bz - basePos[2]);
|
|
397
610
|
const elB = ecefToAzEl(basePos[0], basePos[1], basePos[2], bx, by, bz).el;
|
|
398
611
|
if (elB < maskRad) continue;
|
|
612
|
+
const group = sys + mR.code;
|
|
613
|
+
let offR = null;
|
|
614
|
+
let roverDelta = ZERO_DELTA;
|
|
615
|
+
if (antenna) {
|
|
616
|
+
const antexFreq = antexFreqOfGroup(group);
|
|
617
|
+
if (antenna.base) {
|
|
618
|
+
const offB = antenna.model.rcvOffset(antenna.base.type, antexFreq);
|
|
619
|
+
if (offB) {
|
|
620
|
+
const inv = 1 / rhoB;
|
|
621
|
+
const losB = [
|
|
622
|
+
(bx - basePos[0]) * inv,
|
|
623
|
+
(by - basePos[1]) * inv,
|
|
624
|
+
(bz - basePos[2]) * inv
|
|
625
|
+
];
|
|
626
|
+
rhoB += rcvAntennaRangeM(
|
|
627
|
+
offB,
|
|
628
|
+
losB,
|
|
629
|
+
baseLatRad,
|
|
630
|
+
baseLonRad,
|
|
631
|
+
elB,
|
|
632
|
+
antenna.base.deltaEnu
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
if (antenna.rover) {
|
|
637
|
+
offR = antenna.model.rcvOffset(antenna.rover.type, antexFreq);
|
|
638
|
+
roverDelta = antenna.rover.deltaEnu ?? ZERO_DELTA;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
399
641
|
const gloK = sys === "R" ? mR.gloChannel ?? mB.gloChannel ?? eph.freqNum ?? null : null;
|
|
400
642
|
const freq = carrierFreqHz(sys, mR.code, gloK);
|
|
401
643
|
out.push({
|
|
402
644
|
prn,
|
|
403
|
-
group
|
|
645
|
+
group,
|
|
404
646
|
lambda: freq > 0 ? C_LIGHT / freq : 0,
|
|
405
647
|
satR,
|
|
406
648
|
rhoB,
|
|
@@ -411,7 +653,9 @@ function buildGeometry(rover, base, basePos, ephemerides, timeMs, maskRad, tropo
|
|
|
411
653
|
cpR: mR.cp ?? null,
|
|
412
654
|
cpB: mB.cp ?? null,
|
|
413
655
|
lockR: mR.lockTimeMs,
|
|
414
|
-
lockB: mB.lockTimeMs
|
|
656
|
+
lockB: mB.lockTimeMs,
|
|
657
|
+
offR,
|
|
658
|
+
roverDelta
|
|
415
659
|
});
|
|
416
660
|
}
|
|
417
661
|
return out;
|
|
@@ -419,17 +663,29 @@ function buildGeometry(rover, base, basePos, ephemerides, timeMs, maskRad, tropo
|
|
|
419
663
|
function roverTerms(g, x, y, z, troposphere) {
|
|
420
664
|
const travel = Math.hypot(g.satR.x - x, g.satR.y - y, g.satR.z - z) / C_LIGHT;
|
|
421
665
|
const [sx, sy, sz] = sagnac(g.satR, travel);
|
|
422
|
-
|
|
666
|
+
let rho = Math.hypot(sx - x, sy - y, sz - z);
|
|
423
667
|
const u = [
|
|
424
668
|
(x - sx) / rho,
|
|
425
669
|
(y - sy) / rho,
|
|
426
670
|
(z - sz) / rho
|
|
427
671
|
];
|
|
672
|
+
const needEl = troposphere || g.offR != null;
|
|
673
|
+
const elR = needEl ? ecefToAzEl(x, y, z, sx, sy, sz).el : 0;
|
|
428
674
|
let dTropo = 0;
|
|
429
675
|
if (troposphere) {
|
|
430
|
-
const elR = ecefToAzEl(x, y, z, sx, sy, sz).el;
|
|
431
676
|
dTropo = tropoDelay(Math.max(elR, 0.05)) - g.tropoB;
|
|
432
677
|
}
|
|
678
|
+
if (g.offR) {
|
|
679
|
+
const [latDeg, lonDeg] = ecefToGeodetic(x, y, z);
|
|
680
|
+
rho += rcvAntennaRangeM(
|
|
681
|
+
g.offR,
|
|
682
|
+
[-u[0], -u[1], -u[2]],
|
|
683
|
+
latDeg * Math.PI / 180,
|
|
684
|
+
lonDeg * Math.PI / 180,
|
|
685
|
+
elR,
|
|
686
|
+
g.roverDelta
|
|
687
|
+
);
|
|
688
|
+
}
|
|
433
689
|
return { rho, u, dTropo };
|
|
434
690
|
}
|
|
435
691
|
function sdVariance(sigmaM, elRad) {
|
|
@@ -668,7 +924,8 @@ var RtkFloatEngine = class {
|
|
|
668
924
|
arElevationMaskDeg: opts.arElevationMaskDeg ?? 0,
|
|
669
925
|
glonassAr: opts.glonassAr ?? false,
|
|
670
926
|
partialFixing: opts.partialFixing ?? true,
|
|
671
|
-
minFixAmbiguities: opts.minFixAmbiguities ?? 4
|
|
927
|
+
minFixAmbiguities: opts.minFixAmbiguities ?? 4,
|
|
928
|
+
antenna: opts.antenna ?? null
|
|
672
929
|
};
|
|
673
930
|
}
|
|
674
931
|
/** Clear all filter state (position, ambiguities, lock history). */
|
|
@@ -791,7 +1048,8 @@ var RtkFloatEngine = class {
|
|
|
791
1048
|
this.ephemerides,
|
|
792
1049
|
timeMs,
|
|
793
1050
|
o.elevationMaskDeg * Math.PI / 180,
|
|
794
|
-
o.troposphere
|
|
1051
|
+
o.troposphere,
|
|
1052
|
+
o.antenna
|
|
795
1053
|
);
|
|
796
1054
|
const byPrn = new Map(geom.map((g) => [g.prn, g]));
|
|
797
1055
|
const dtS = this.lastMs !== null ? (timeMs - this.lastMs) / 1e3 : 0;
|
|
@@ -1919,14 +2177,14 @@ var SbasProcessor = class {
|
|
|
1919
2177
|
};
|
|
1920
2178
|
|
|
1921
2179
|
// src/positioning/ssr-apply.ts
|
|
1922
|
-
var
|
|
2180
|
+
var cross2 = (a, b) => [
|
|
1923
2181
|
a[1] * b[2] - a[2] * b[1],
|
|
1924
2182
|
a[2] * b[0] - a[0] * b[2],
|
|
1925
2183
|
a[0] * b[1] - a[1] * b[0]
|
|
1926
2184
|
];
|
|
1927
|
-
var
|
|
2185
|
+
var norm2 = (a) => Math.hypot(a[0], a[1], a[2]);
|
|
1928
2186
|
var unit = (a) => {
|
|
1929
|
-
const n =
|
|
2187
|
+
const n = norm2(a);
|
|
1930
2188
|
return n > 0 ? [a[0] / n, a[1] / n, a[2] / n] : [0, 0, 0];
|
|
1931
2189
|
};
|
|
1932
2190
|
function applyOrbitClock(eph, corr, timeMs) {
|
|
@@ -1940,8 +2198,8 @@ function applyOrbitClock(eph, corr, timeMs) {
|
|
|
1940
2198
|
const p = [s.x, s.y, s.z];
|
|
1941
2199
|
const v = [s.vx, s.vy, s.vz];
|
|
1942
2200
|
const er = unit(p);
|
|
1943
|
-
const en = unit(
|
|
1944
|
-
const ea =
|
|
2201
|
+
const en = unit(cross2(p, v));
|
|
2202
|
+
const ea = cross2(en, er);
|
|
1945
2203
|
const dr = corr.radial + (corr.dotRadial ?? 0) * age;
|
|
1946
2204
|
const da = corr.along + (corr.dotAlong ?? 0) * age;
|
|
1947
2205
|
const dc = corr.cross + (corr.dotCross ?? 0) * age;
|
|
@@ -2151,170 +2409,6 @@ function solidEarthTide(rcv, sun, moon) {
|
|
|
2151
2409
|
return disp;
|
|
2152
2410
|
}
|
|
2153
2411
|
|
|
2154
|
-
// src/positioning/ppp-antenna.ts
|
|
2155
|
-
function parseAntexTime(s) {
|
|
2156
|
-
const p = s.trim().split(/\s+/).map(Number);
|
|
2157
|
-
if (p.length < 3 || p.some((v) => Number.isNaN(v))) return null;
|
|
2158
|
-
return Date.UTC(
|
|
2159
|
-
p[0],
|
|
2160
|
-
(p[1] || 1) - 1,
|
|
2161
|
-
p[2] || 1,
|
|
2162
|
-
p[3] ?? 0,
|
|
2163
|
-
p[4] ?? 0,
|
|
2164
|
-
Math.floor(p[5] ?? 0)
|
|
2165
|
-
);
|
|
2166
|
-
}
|
|
2167
|
-
function freqOf(entry, code) {
|
|
2168
|
-
return entry.frequencies.find((f) => f.frequency === code);
|
|
2169
|
-
}
|
|
2170
|
-
function combineIf(fA, fB, f1, f2) {
|
|
2171
|
-
const g = f1 * f1 / (f1 * f1 - f2 * f2);
|
|
2172
|
-
const mm = 1e-3;
|
|
2173
|
-
const pco = [
|
|
2174
|
-
(g * fA.pcoN - (g - 1) * fB.pcoN) * mm,
|
|
2175
|
-
(g * fA.pcoE - (g - 1) * fB.pcoE) * mm,
|
|
2176
|
-
(g * fA.pcoU - (g - 1) * fB.pcoU) * mm
|
|
2177
|
-
];
|
|
2178
|
-
const nz = Math.min(fA.pcvNoazi.length, fB.pcvNoazi.length);
|
|
2179
|
-
const pcvNoazi = new Array(nz);
|
|
2180
|
-
for (let i = 0; i < nz; i++) {
|
|
2181
|
-
pcvNoazi[i] = (g * fA.pcvNoazi[i] - (g - 1) * fB.pcvNoazi[i]) * mm;
|
|
2182
|
-
}
|
|
2183
|
-
return { pco, pcvZen1Deg: 0, pcvDzenDeg: 0, pcvNoazi };
|
|
2184
|
-
}
|
|
2185
|
-
function buildPppAntenna(antex) {
|
|
2186
|
-
const sats = /* @__PURE__ */ new Map();
|
|
2187
|
-
const rcvs = /* @__PURE__ */ new Map();
|
|
2188
|
-
for (const a of antex.antennas) {
|
|
2189
|
-
if (a.isSatellite) {
|
|
2190
|
-
const list = sats.get(a.serialNo) ?? [];
|
|
2191
|
-
list.push(a);
|
|
2192
|
-
sats.set(a.serialNo, list);
|
|
2193
|
-
} else if (!rcvs.has(a.type)) {
|
|
2194
|
-
rcvs.set(a.type, a);
|
|
2195
|
-
}
|
|
2196
|
-
}
|
|
2197
|
-
const withZen = (entry, off) => ({
|
|
2198
|
-
...off,
|
|
2199
|
-
pcvZen1Deg: entry.zen1,
|
|
2200
|
-
pcvDzenDeg: entry.dzen
|
|
2201
|
-
});
|
|
2202
|
-
return {
|
|
2203
|
-
satOffset(prn, dateMs, band1, band2, f1, f2) {
|
|
2204
|
-
const list = sats.get(prn);
|
|
2205
|
-
if (!list) return null;
|
|
2206
|
-
const entry = list.find((e) => {
|
|
2207
|
-
const from = parseAntexTime(e.validFrom);
|
|
2208
|
-
const until = parseAntexTime(e.validUntil);
|
|
2209
|
-
return (from == null || dateMs >= from) && (until == null || dateMs <= until);
|
|
2210
|
-
});
|
|
2211
|
-
if (!entry) return null;
|
|
2212
|
-
const a = freqOf(entry, band1);
|
|
2213
|
-
const b = freqOf(entry, band2);
|
|
2214
|
-
if (!a || !b) return null;
|
|
2215
|
-
return withZen(entry, combineIf(a, b, f1, f2));
|
|
2216
|
-
},
|
|
2217
|
-
rcvOffset(antType, band1, band2, f1, f2) {
|
|
2218
|
-
const entry = rcvs.get(antType);
|
|
2219
|
-
if (!entry) return null;
|
|
2220
|
-
const a = freqOf(entry, band1);
|
|
2221
|
-
const b = freqOf(entry, band2);
|
|
2222
|
-
if (!a || !b) return null;
|
|
2223
|
-
return withZen(entry, combineIf(a, b, f1, f2));
|
|
2224
|
-
}
|
|
2225
|
-
};
|
|
2226
|
-
}
|
|
2227
|
-
function cross2(a, b) {
|
|
2228
|
-
return [
|
|
2229
|
-
a[1] * b[2] - a[2] * b[1],
|
|
2230
|
-
a[2] * b[0] - a[0] * b[2],
|
|
2231
|
-
a[0] * b[1] - a[1] * b[0]
|
|
2232
|
-
];
|
|
2233
|
-
}
|
|
2234
|
-
function norm2(a) {
|
|
2235
|
-
const n = Math.hypot(a[0], a[1], a[2]) || 1;
|
|
2236
|
-
return [a[0] / n, a[1] / n, a[2] / n];
|
|
2237
|
-
}
|
|
2238
|
-
function dot(a, b) {
|
|
2239
|
-
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
2240
|
-
}
|
|
2241
|
-
function satBodyFrame(satEcef, sunEcef2) {
|
|
2242
|
-
const z = norm2([-satEcef[0], -satEcef[1], -satEcef[2]]);
|
|
2243
|
-
const eSun = norm2([
|
|
2244
|
-
sunEcef2[0] - satEcef[0],
|
|
2245
|
-
sunEcef2[1] - satEcef[1],
|
|
2246
|
-
sunEcef2[2] - satEcef[2]
|
|
2247
|
-
]);
|
|
2248
|
-
const y = norm2(cross2(z, eSun));
|
|
2249
|
-
const x = norm2(cross2(y, z));
|
|
2250
|
-
return { x, y, z };
|
|
2251
|
-
}
|
|
2252
|
-
function satPcoToEcef(pcoBody, frame) {
|
|
2253
|
-
return [
|
|
2254
|
-
pcoBody[0] * frame.x[0] + pcoBody[1] * frame.y[0] + pcoBody[2] * frame.z[0],
|
|
2255
|
-
pcoBody[0] * frame.x[1] + pcoBody[1] * frame.y[1] + pcoBody[2] * frame.z[1],
|
|
2256
|
-
pcoBody[0] * frame.x[2] + pcoBody[1] * frame.y[2] + pcoBody[2] * frame.z[2]
|
|
2257
|
-
];
|
|
2258
|
-
}
|
|
2259
|
-
function enuToEcef(enu, latRad, lonRad) {
|
|
2260
|
-
const sl = Math.sin(latRad);
|
|
2261
|
-
const cl = Math.cos(latRad);
|
|
2262
|
-
const so = Math.sin(lonRad);
|
|
2263
|
-
const co = Math.cos(lonRad);
|
|
2264
|
-
const [e, n, u] = enu;
|
|
2265
|
-
return [
|
|
2266
|
-
-so * e - sl * co * n + cl * co * u,
|
|
2267
|
-
co * e - sl * so * n + cl * so * u,
|
|
2268
|
-
cl * n + sl * u
|
|
2269
|
-
];
|
|
2270
|
-
}
|
|
2271
|
-
function interpPcv(off, angleDeg) {
|
|
2272
|
-
const { pcvZen1Deg, pcvDzenDeg, pcvNoazi } = off;
|
|
2273
|
-
if (pcvDzenDeg <= 0 || pcvNoazi.length < 2) return 0;
|
|
2274
|
-
const x = (angleDeg - pcvZen1Deg) / pcvDzenDeg;
|
|
2275
|
-
if (x <= 0) return pcvNoazi[0];
|
|
2276
|
-
if (x >= pcvNoazi.length - 1) return pcvNoazi[pcvNoazi.length - 1];
|
|
2277
|
-
const i = Math.floor(x);
|
|
2278
|
-
const t = x - i;
|
|
2279
|
-
return pcvNoazi[i] * (1 - t) + pcvNoazi[i + 1] * t;
|
|
2280
|
-
}
|
|
2281
|
-
function phaseWindup(prn, losRcvToSat, satFrame, latRad, lonRad, state) {
|
|
2282
|
-
const k = [
|
|
2283
|
-
-losRcvToSat[0],
|
|
2284
|
-
-losRcvToSat[1],
|
|
2285
|
-
-losRcvToSat[2]
|
|
2286
|
-
];
|
|
2287
|
-
const kx = satFrame.x;
|
|
2288
|
-
const ky = satFrame.y;
|
|
2289
|
-
const kdotx = dot(k, kx);
|
|
2290
|
-
const kcrossY = cross2(k, ky);
|
|
2291
|
-
const dS = [
|
|
2292
|
-
kx[0] - k[0] * kdotx - kcrossY[0],
|
|
2293
|
-
kx[1] - k[1] * kdotx - kcrossY[1],
|
|
2294
|
-
kx[2] - k[2] * kdotx - kcrossY[2]
|
|
2295
|
-
];
|
|
2296
|
-
const north = enuToEcef([0, 1, 0], latRad, lonRad);
|
|
2297
|
-
const east = enuToEcef([1, 0, 0], latRad, lonRad);
|
|
2298
|
-
const kdotn = dot(k, north);
|
|
2299
|
-
const kcrossE = cross2(k, east);
|
|
2300
|
-
const dR = [
|
|
2301
|
-
north[0] - k[0] * kdotn + kcrossE[0],
|
|
2302
|
-
north[1] - k[1] * kdotn + kcrossE[1],
|
|
2303
|
-
north[2] - k[2] * kdotn + kcrossE[2]
|
|
2304
|
-
];
|
|
2305
|
-
const nS = Math.hypot(dS[0], dS[1], dS[2]) || 1;
|
|
2306
|
-
const nR = Math.hypot(dR[0], dR[1], dR[2]) || 1;
|
|
2307
|
-
let cosPhi = dot(dS, dR) / (nS * nR);
|
|
2308
|
-
cosPhi = Math.max(-1, Math.min(1, cosPhi));
|
|
2309
|
-
const zeta = cross2(dS, dR);
|
|
2310
|
-
const sign = dot(k, zeta) >= 0 ? 1 : -1;
|
|
2311
|
-
const dphi = sign * Math.acos(cosPhi) / (2 * Math.PI);
|
|
2312
|
-
const prev = state.get(prn);
|
|
2313
|
-
const wu = prev == null ? dphi : dphi + Math.round(prev - dphi);
|
|
2314
|
-
state.set(prn, wu);
|
|
2315
|
-
return wu;
|
|
2316
|
-
}
|
|
2317
|
-
|
|
2318
2412
|
// src/positioning/ppp-corrections.ts
|
|
2319
2413
|
function applyCorrections(corrections, geom, ctx) {
|
|
2320
2414
|
if (corrections.evaluate) return corrections.evaluate(geom, ctx);
|
|
@@ -3714,6 +3808,10 @@ export {
|
|
|
3714
3808
|
gimSlantIonoDelayL1,
|
|
3715
3809
|
lambdaSearch,
|
|
3716
3810
|
lambdaReduction,
|
|
3811
|
+
buildPppAntenna,
|
|
3812
|
+
buildRtkAntenna,
|
|
3813
|
+
rcvAntennaRangeM,
|
|
3814
|
+
antexFreqOfGroup,
|
|
3717
3815
|
toRtkEpoch,
|
|
3718
3816
|
solveDgnss,
|
|
3719
3817
|
RtkFloatEngine,
|
|
@@ -3728,7 +3826,6 @@ export {
|
|
|
3728
3826
|
sunEcef,
|
|
3729
3827
|
moonEcef,
|
|
3730
3828
|
solidEarthTide,
|
|
3731
|
-
buildPppAntenna,
|
|
3732
3829
|
createPppCorrections,
|
|
3733
3830
|
Sp3EphemerisSource,
|
|
3734
3831
|
PppEngine,
|
|
@@ -1839,7 +1839,8 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
1839
1839
|
stats.satellites.set(obs.prn, {
|
|
1840
1840
|
prn: obs.prn,
|
|
1841
1841
|
system: obs.system,
|
|
1842
|
-
cn0: bestCn0,
|
|
1842
|
+
cn0: bestCn0 > 0 ? bestCn0 : null,
|
|
1843
|
+
// null = no C/N0 reported
|
|
1843
1844
|
lastSeen: now,
|
|
1844
1845
|
signals
|
|
1845
1846
|
});
|