gnss-js 1.35.0 → 1.37.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/binex.js +2 -2
- package/dist/{chunk-AFEDNWXI.js → chunk-24TKGUTY.js} +310 -111
- package/dist/{chunk-BLGBMRX7.js → chunk-3FG4XVCB.js} +136 -1
- package/dist/{chunk-F4CM6Q4F.js → chunk-5X4AG4MK.js} +2 -2
- package/dist/{chunk-5RNDQQ6J.js → chunk-6SWJTN6H.js} +2 -2
- package/dist/{chunk-OK4GGNOO.js → chunk-D25WNE43.js} +1 -1
- package/dist/{chunk-5AUK42AL.js → chunk-FA2UTLEQ.js} +2 -2
- package/dist/{chunk-IQ5OIMQD.js → chunk-V2D5KUKH.js} +33 -0
- package/dist/{chunk-726LQBGM.js → chunk-YUW33VXK.js} +1 -1
- package/dist/{chunk-FEOMYZEU.js → chunk-ZQDLYLQA.js} +9 -28
- package/dist/index.cjs +480 -132
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +15 -9
- package/dist/novatel.js +3 -3
- package/dist/positioning.cjs +137 -1
- package/dist/positioning.d.cts +62 -1
- package/dist/positioning.d.ts +62 -1
- package/dist/positioning.js +3 -1
- package/dist/rinex.js +3 -3
- package/dist/sbf.cjs +462 -107
- package/dist/sbf.d.cts +103 -14
- package/dist/sbf.d.ts +103 -14
- package/dist/sbf.js +8 -4
- package/dist/ubx.cjs +37 -24
- package/dist/ubx.js +4 -4
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -142,6 +142,7 @@ __export(src_exports, {
|
|
|
142
142
|
decodeBinexEph: () => decodeBinexEph,
|
|
143
143
|
decodeEphemeris: () => decodeEphemeris,
|
|
144
144
|
decodeMsmFull: () => decodeMsmFull,
|
|
145
|
+
decodeSbfNavigation: () => decodeSbfNavigation,
|
|
145
146
|
deg2dms: () => deg2dms,
|
|
146
147
|
deg2rad: () => deg2rad,
|
|
147
148
|
detrendIonoArcs: () => detrendIonoArcs,
|
|
@@ -156,6 +157,7 @@ __export(src_exports, {
|
|
|
156
157
|
extractWidelaneArcs: () => extractWidelaneArcs,
|
|
157
158
|
fetchSourcetable: () => fetchSourcetable,
|
|
158
159
|
findSatBias: () => findSatBias,
|
|
160
|
+
fixPppPosition: () => fixPppPosition,
|
|
159
161
|
fmtD: () => fmtD,
|
|
160
162
|
fmtF: () => fmtF,
|
|
161
163
|
formatUTCTime: () => formatUTCTime,
|
|
@@ -259,6 +261,7 @@ __export(src_exports, {
|
|
|
259
261
|
parseSbfCnav: () => parseSbfCnav,
|
|
260
262
|
parseSbfGalNav: () => parseSbfGalNav,
|
|
261
263
|
parseSbfGloNav: () => parseSbfGloNav,
|
|
264
|
+
parseSbfGpsNav: () => parseSbfGpsNav,
|
|
262
265
|
parseSbfHas: () => parseSbfHas,
|
|
263
266
|
parseSbfIonoUtc: () => parseSbfIonoUtc,
|
|
264
267
|
parseSbfMeas: () => parseSbfMeas,
|
|
@@ -2698,6 +2701,38 @@ function setBitU(buff, pos, len, data) {
|
|
|
2698
2701
|
}
|
|
2699
2702
|
}
|
|
2700
2703
|
}
|
|
2704
|
+
var GpsLnavAssembler = class _GpsLnavAssembler {
|
|
2705
|
+
buffers = /* @__PURE__ */ new Map();
|
|
2706
|
+
last = /* @__PURE__ */ new Map();
|
|
2707
|
+
/** Subframe ID (1–5) from the HOW word of a parity-stripped subframe. */
|
|
2708
|
+
static subframeId(subframe) {
|
|
2709
|
+
return getBitU(subframe, 43, 3);
|
|
2710
|
+
}
|
|
2711
|
+
/**
|
|
2712
|
+
* Push one parity-stripped 30-byte LNAV subframe for `prn`, resolving
|
|
2713
|
+
* the 10-bit week against `refWeek`. See {@link LnavPush} for outcomes.
|
|
2714
|
+
*/
|
|
2715
|
+
push(prn, subframe, refWeek) {
|
|
2716
|
+
const id = _GpsLnavAssembler.subframeId(subframe);
|
|
2717
|
+
if (id < 1 || id > 3) return { kind: "skipped" };
|
|
2718
|
+
let sf = this.buffers.get(prn);
|
|
2719
|
+
if (!sf) {
|
|
2720
|
+
sf = { buf: new Uint8Array(90), have: 0 };
|
|
2721
|
+
this.buffers.set(prn, sf);
|
|
2722
|
+
}
|
|
2723
|
+
sf.buf.set(subframe, (id - 1) * 30);
|
|
2724
|
+
sf.have |= 1 << id - 1;
|
|
2725
|
+
if (id !== 3 || sf.have !== 7) return { kind: "incomplete" };
|
|
2726
|
+
const eph = decodeGpsLnavFrame(sf.buf, { prn, refWeek });
|
|
2727
|
+
if (!eph) return { kind: "decodeFailed" };
|
|
2728
|
+
const prev = this.last.get(prn);
|
|
2729
|
+
if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
|
|
2730
|
+
return { kind: "duplicate" };
|
|
2731
|
+
}
|
|
2732
|
+
this.last.set(prn, eph);
|
|
2733
|
+
return { kind: "eph", eph };
|
|
2734
|
+
}
|
|
2735
|
+
};
|
|
2701
2736
|
function decodeGpsLnavFrame(subframes, opts = {}) {
|
|
2702
2737
|
if (subframes.length < 90) return null;
|
|
2703
2738
|
const b = subframes;
|
|
@@ -5917,38 +5952,19 @@ function parseUbxNav(data, opts = {}) {
|
|
|
5917
5952
|
}
|
|
5918
5953
|
}
|
|
5919
5954
|
if (refWeek === void 0) return { ephemerides, badParity };
|
|
5920
|
-
const
|
|
5921
|
-
const last = /* @__PURE__ */ new Map();
|
|
5955
|
+
const assembler = new GpsLnavAssembler();
|
|
5922
5956
|
for (const f of ubxFrames(data)) {
|
|
5923
5957
|
if (f.msgClass !== 2 || f.msgId !== 19) continue;
|
|
5924
5958
|
const lnav = readLnavSubframe(view, f);
|
|
5925
5959
|
if (!lnav) continue;
|
|
5926
|
-
const { prn,
|
|
5960
|
+
const { prn, buff, id } = lnav;
|
|
5927
5961
|
if (id < 1 || id > 5) {
|
|
5928
5962
|
badParity++;
|
|
5929
5963
|
continue;
|
|
5930
5964
|
}
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
if (!sf) {
|
|
5935
|
-
sf = { buf: new Uint8Array(90), have: 0 };
|
|
5936
|
-
subframes.set(key, sf);
|
|
5937
|
-
}
|
|
5938
|
-
sf.buf.set(buff, (id - 1) * 30);
|
|
5939
|
-
sf.have |= 1 << id - 1;
|
|
5940
|
-
if (id !== 3 || sf.have !== 7) continue;
|
|
5941
|
-
const eph = decodeGpsLnavFrame(sf.buf, { prn, refWeek });
|
|
5942
|
-
if (!eph) {
|
|
5943
|
-
badParity++;
|
|
5944
|
-
continue;
|
|
5945
|
-
}
|
|
5946
|
-
const prev = last.get(prn);
|
|
5947
|
-
if (prev && prev.iode === eph.iode && prev.tocDate.getTime() === eph.tocDate.getTime()) {
|
|
5948
|
-
continue;
|
|
5949
|
-
}
|
|
5950
|
-
last.set(prn, eph);
|
|
5951
|
-
ephemerides.push(eph);
|
|
5965
|
+
const r = assembler.push(prn, buff, refWeek);
|
|
5966
|
+
if (r.kind === "eph") ephemerides.push(r.eph);
|
|
5967
|
+
else if (r.kind === "decodeFailed") badParity++;
|
|
5952
5968
|
}
|
|
5953
5969
|
return { ephemerides, badParity };
|
|
5954
5970
|
}
|
|
@@ -7359,38 +7375,78 @@ function parseSbfIonoUtc(data) {
|
|
|
7359
7375
|
return { ionoCorrections, leapSeconds };
|
|
7360
7376
|
}
|
|
7361
7377
|
|
|
7378
|
+
// src/sbf/rawnav-gps.ts
|
|
7379
|
+
var WNC_DNU = 65535;
|
|
7380
|
+
function extractSbfLnavSubframe(view, b) {
|
|
7381
|
+
const sf = new Uint8Array(30);
|
|
7382
|
+
for (let k = 0; k < 10; k++) {
|
|
7383
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
7384
|
+
setBitU(sf, 24 * k, 24, w >>> 6 & 16777215);
|
|
7385
|
+
}
|
|
7386
|
+
return sf;
|
|
7387
|
+
}
|
|
7388
|
+
function feedGpsLnavBlock(view, b, assembler) {
|
|
7389
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
7390
|
+
if (!prn || prn[0] !== "G" && prn[0] !== "J") return {};
|
|
7391
|
+
if (view.getUint8(b + 15) !== 1) return {};
|
|
7392
|
+
const wnc = view.getUint16(b + 12, true);
|
|
7393
|
+
if (wnc === WNC_DNU) return {};
|
|
7394
|
+
const r = assembler.push(prn, extractSbfLnavSubframe(view, b), wnc);
|
|
7395
|
+
if (r.kind === "eph") return { eph: r.eph };
|
|
7396
|
+
if (r.kind === "decodeFailed") return { badParity: true };
|
|
7397
|
+
return {};
|
|
7398
|
+
}
|
|
7399
|
+
function parseSbfGpsNav(data) {
|
|
7400
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
7401
|
+
const ephemerides = [];
|
|
7402
|
+
const assembler = new GpsLnavAssembler();
|
|
7403
|
+
let badParity = 0;
|
|
7404
|
+
let messages = 0;
|
|
7405
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
7406
|
+
if (id !== 4017 && id !== 4066 || len < 60) return;
|
|
7407
|
+
messages++;
|
|
7408
|
+
const r = feedGpsLnavBlock(view, b, assembler);
|
|
7409
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
7410
|
+
else if (r.badParity) badParity++;
|
|
7411
|
+
});
|
|
7412
|
+
return { ephemerides, badParity, messages };
|
|
7413
|
+
}
|
|
7414
|
+
|
|
7362
7415
|
// src/sbf/rawnav.ts
|
|
7363
|
-
var
|
|
7416
|
+
var CNAV_SIGNAL_OF_BLOCK = {
|
|
7364
7417
|
4018: "L2C",
|
|
7365
7418
|
4019: "L5"
|
|
7366
7419
|
};
|
|
7420
|
+
function newCnavAssemblers() {
|
|
7421
|
+
return { L2C: new CnavAssembler(), L5: new CnavAssembler() };
|
|
7422
|
+
}
|
|
7423
|
+
function feedCnavBlock(view, b, id, asm) {
|
|
7424
|
+
const signal = CNAV_SIGNAL_OF_BLOCK[id];
|
|
7425
|
+
if (!signal) return {};
|
|
7426
|
+
const msg = new Uint8Array(40);
|
|
7427
|
+
for (let k = 0; k < 10; k++) {
|
|
7428
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
7429
|
+
msg[4 * k] = w >>> 24;
|
|
7430
|
+
msg[4 * k + 1] = w >>> 16 & 255;
|
|
7431
|
+
msg[4 * k + 2] = w >>> 8 & 255;
|
|
7432
|
+
msg[4 * k + 3] = w & 255;
|
|
7433
|
+
}
|
|
7434
|
+
if (!cnavCrcOk(msg)) return { badCrc: true };
|
|
7435
|
+
const eph = asm[signal].push(msg);
|
|
7436
|
+
return eph ? { eph: { ...eph, signal } } : {};
|
|
7437
|
+
}
|
|
7367
7438
|
function parseSbfCnav(data) {
|
|
7368
7439
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
7369
7440
|
const ephemerides = [];
|
|
7370
|
-
const
|
|
7371
|
-
L2C: new CnavAssembler(),
|
|
7372
|
-
L5: new CnavAssembler()
|
|
7373
|
-
};
|
|
7441
|
+
const asm = newCnavAssemblers();
|
|
7374
7442
|
let badCrc = 0;
|
|
7375
7443
|
let messages = 0;
|
|
7376
7444
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
7377
|
-
|
|
7378
|
-
if (!signal || len < 60) return;
|
|
7445
|
+
if (!CNAV_SIGNAL_OF_BLOCK[id] || len < 60) return;
|
|
7379
7446
|
messages++;
|
|
7380
|
-
const
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
msg[4 * k] = w >>> 24;
|
|
7384
|
-
msg[4 * k + 1] = w >>> 16 & 255;
|
|
7385
|
-
msg[4 * k + 2] = w >>> 8 & 255;
|
|
7386
|
-
msg[4 * k + 3] = w & 255;
|
|
7387
|
-
}
|
|
7388
|
-
if (!cnavCrcOk(msg)) {
|
|
7389
|
-
badCrc++;
|
|
7390
|
-
return;
|
|
7391
|
-
}
|
|
7392
|
-
const eph = assemblers[signal].push(msg);
|
|
7393
|
-
if (eph) ephemerides.push({ ...eph, signal });
|
|
7447
|
+
const r = feedCnavBlock(view, b, id, asm);
|
|
7448
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
7449
|
+
else if (r.badCrc) badCrc++;
|
|
7394
7450
|
});
|
|
7395
7451
|
return { ephemerides, badCrc, messages };
|
|
7396
7452
|
}
|
|
@@ -7398,50 +7454,51 @@ function parseSbfCnav(data) {
|
|
|
7398
7454
|
// src/sbf/rawnav-gal.ts
|
|
7399
7455
|
var INAV_SOURCES = [17, 21, 22];
|
|
7400
7456
|
var FNAV_SOURCES = [20, 22];
|
|
7457
|
+
function newGalAssemblers() {
|
|
7458
|
+
return { inav: new GalInavAssembler(), fnav: new GalFnavAssembler() };
|
|
7459
|
+
}
|
|
7460
|
+
function feedGalBlock(data, view, b, id, asm) {
|
|
7461
|
+
const prnStr = svidToPrn(data[b + 14]);
|
|
7462
|
+
if (!prnStr || prnStr[0] !== "E") return {};
|
|
7463
|
+
const prn = parseInt(prnStr.slice(1), 10);
|
|
7464
|
+
const source = data[b + 17] & 31;
|
|
7465
|
+
const page = new Uint8Array(32);
|
|
7466
|
+
for (let k = 0; k < 8; k++) {
|
|
7467
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
7468
|
+
page[4 * k] = w >>> 24;
|
|
7469
|
+
page[4 * k + 1] = w >>> 16 & 255;
|
|
7470
|
+
page[4 * k + 2] = w >>> 8 & 255;
|
|
7471
|
+
page[4 * k + 3] = w & 255;
|
|
7472
|
+
}
|
|
7473
|
+
let eph;
|
|
7474
|
+
let src;
|
|
7475
|
+
if (id === 4023) {
|
|
7476
|
+
src = "inav";
|
|
7477
|
+
if (!INAV_SOURCES.includes(source)) return {};
|
|
7478
|
+
if (getBitU22(page, 0) !== 0 || getBitU22(page, 114) !== 1) return {};
|
|
7479
|
+
if (!galInavPageCrcOk(page)) return { badCrc: true };
|
|
7480
|
+
eph = asm.inav.push(prn, page);
|
|
7481
|
+
} else {
|
|
7482
|
+
src = "fnav";
|
|
7483
|
+
if (!FNAV_SOURCES.includes(source)) return {};
|
|
7484
|
+
if (isFnavDummy(page)) return {};
|
|
7485
|
+
if (!galFnavPageCrcOk(page)) return { badCrc: true };
|
|
7486
|
+
eph = asm.fnav.push(prn, page);
|
|
7487
|
+
}
|
|
7488
|
+
return eph ? { eph: { ...eph, source: src } } : {};
|
|
7489
|
+
}
|
|
7401
7490
|
function parseSbfGalNav(data) {
|
|
7402
7491
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
7403
7492
|
const ephemerides = [];
|
|
7404
|
-
const
|
|
7405
|
-
const fnav = new GalFnavAssembler();
|
|
7493
|
+
const asm = newGalAssemblers();
|
|
7406
7494
|
let badCrc = 0;
|
|
7407
7495
|
let messages = 0;
|
|
7408
7496
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
7409
7497
|
if (id !== 4022 && id !== 4023 || len < 52) return;
|
|
7410
7498
|
messages++;
|
|
7411
|
-
const
|
|
7412
|
-
if (
|
|
7413
|
-
|
|
7414
|
-
const source = data[b + 17] & 31;
|
|
7415
|
-
const page = new Uint8Array(32);
|
|
7416
|
-
for (let k = 0; k < 8; k++) {
|
|
7417
|
-
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
7418
|
-
page[4 * k] = w >>> 24;
|
|
7419
|
-
page[4 * k + 1] = w >>> 16 & 255;
|
|
7420
|
-
page[4 * k + 2] = w >>> 8 & 255;
|
|
7421
|
-
page[4 * k + 3] = w & 255;
|
|
7422
|
-
}
|
|
7423
|
-
let eph;
|
|
7424
|
-
let src;
|
|
7425
|
-
if (id === 4023) {
|
|
7426
|
-
src = "inav";
|
|
7427
|
-
if (!INAV_SOURCES.includes(source)) return;
|
|
7428
|
-
if (getBitU22(page, 0) !== 0 || getBitU22(page, 114) !== 1) return;
|
|
7429
|
-
if (!galInavPageCrcOk(page)) {
|
|
7430
|
-
badCrc++;
|
|
7431
|
-
return;
|
|
7432
|
-
}
|
|
7433
|
-
eph = inav.push(prn, page);
|
|
7434
|
-
} else {
|
|
7435
|
-
src = "fnav";
|
|
7436
|
-
if (!FNAV_SOURCES.includes(source)) return;
|
|
7437
|
-
if (isFnavDummy(page)) return;
|
|
7438
|
-
if (!galFnavPageCrcOk(page)) {
|
|
7439
|
-
badCrc++;
|
|
7440
|
-
return;
|
|
7441
|
-
}
|
|
7442
|
-
eph = fnav.push(prn, page);
|
|
7443
|
-
}
|
|
7444
|
-
if (eph) ephemerides.push({ ...eph, source: src });
|
|
7499
|
+
const r = feedGalBlock(data, view, b, id, asm);
|
|
7500
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
7501
|
+
else if (r.badCrc) badCrc++;
|
|
7445
7502
|
});
|
|
7446
7503
|
return { ephemerides, badCrc, messages };
|
|
7447
7504
|
}
|
|
@@ -7456,7 +7513,26 @@ function isFnavDummy(page) {
|
|
|
7456
7513
|
var GPS_EPOCH_MS10 = Date.UTC(1980, 0, 6);
|
|
7457
7514
|
var MS_PER_WEEK5 = 7 * 86400 * 1e3;
|
|
7458
7515
|
var TOW_DNU = 4294967295;
|
|
7459
|
-
var
|
|
7516
|
+
var WNC_DNU2 = 65535;
|
|
7517
|
+
function feedBdsBlock(view, b, assembler) {
|
|
7518
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
7519
|
+
if (!prn || prn[0] !== "C") return {};
|
|
7520
|
+
const sf = new Uint8Array(38);
|
|
7521
|
+
for (let k = 0; k < 10; k++) {
|
|
7522
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
7523
|
+
sf[4 * k] = w >>> 24;
|
|
7524
|
+
if (k < 9) {
|
|
7525
|
+
sf[4 * k + 1] = w >>> 16 & 255;
|
|
7526
|
+
sf[4 * k + 2] = w >>> 8 & 255;
|
|
7527
|
+
sf[4 * k + 3] = w & 255;
|
|
7528
|
+
} else {
|
|
7529
|
+
sf[37] = w >>> 16 & 240;
|
|
7530
|
+
}
|
|
7531
|
+
}
|
|
7532
|
+
if (!bdsSubframeParityOk(sf)) return { badCrc: true };
|
|
7533
|
+
const eph = assembler.push(prn, sf);
|
|
7534
|
+
return eph ? { eph } : {};
|
|
7535
|
+
}
|
|
7460
7536
|
function parseSbfBdsNav(data) {
|
|
7461
7537
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
7462
7538
|
const ephemerides = [];
|
|
@@ -7466,29 +7542,41 @@ function parseSbfBdsNav(data) {
|
|
|
7466
7542
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
7467
7543
|
if (id !== 4047 || len < 60) return;
|
|
7468
7544
|
messages++;
|
|
7469
|
-
const
|
|
7470
|
-
if (
|
|
7471
|
-
|
|
7472
|
-
for (let k = 0; k < 10; k++) {
|
|
7473
|
-
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
7474
|
-
sf[4 * k] = w >>> 24;
|
|
7475
|
-
if (k < 9) {
|
|
7476
|
-
sf[4 * k + 1] = w >>> 16 & 255;
|
|
7477
|
-
sf[4 * k + 2] = w >>> 8 & 255;
|
|
7478
|
-
sf[4 * k + 3] = w & 255;
|
|
7479
|
-
} else {
|
|
7480
|
-
sf[37] = w >>> 16 & 240;
|
|
7481
|
-
}
|
|
7482
|
-
}
|
|
7483
|
-
if (!bdsSubframeParityOk(sf)) {
|
|
7484
|
-
badCrc++;
|
|
7485
|
-
return;
|
|
7486
|
-
}
|
|
7487
|
-
const eph = assembler.push(prn, sf);
|
|
7488
|
-
if (eph) ephemerides.push(eph);
|
|
7545
|
+
const r = feedBdsBlock(view, b, assembler);
|
|
7546
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
7547
|
+
else if (r.badCrc) badCrc++;
|
|
7489
7548
|
});
|
|
7490
7549
|
return { ephemerides, badCrc, messages };
|
|
7491
7550
|
}
|
|
7551
|
+
function feedGloBlock(view, b, assembler) {
|
|
7552
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
7553
|
+
if (!prn || prn[0] !== "R") return {};
|
|
7554
|
+
const towMs = view.getUint32(b + 8, true);
|
|
7555
|
+
const wnc = view.getUint16(b + 12, true);
|
|
7556
|
+
if (towMs === TOW_DNU || wnc === WNC_DNU2) return {};
|
|
7557
|
+
const str = new Uint8Array(11);
|
|
7558
|
+
for (let k = 0; k < 3; k++) {
|
|
7559
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
7560
|
+
str[4 * k] = w >>> 24;
|
|
7561
|
+
if (k < 2) {
|
|
7562
|
+
str[4 * k + 1] = w >>> 16 & 255;
|
|
7563
|
+
str[4 * k + 2] = w >>> 8 & 255;
|
|
7564
|
+
str[4 * k + 3] = w & 255;
|
|
7565
|
+
} else {
|
|
7566
|
+
str[9] = w >>> 16 & 255;
|
|
7567
|
+
str[10] = w >>> 8 & 248;
|
|
7568
|
+
}
|
|
7569
|
+
}
|
|
7570
|
+
if (!testGloString(str)) return { badCrc: true };
|
|
7571
|
+
const eph = assembler.push(
|
|
7572
|
+
prn,
|
|
7573
|
+
str,
|
|
7574
|
+
new Date(GPS_EPOCH_MS10 + wnc * MS_PER_WEEK5 + towMs),
|
|
7575
|
+
view.getUint8(b + 18) - 8
|
|
7576
|
+
// FreqNr, offset by 8
|
|
7577
|
+
);
|
|
7578
|
+
return eph ? { eph } : {};
|
|
7579
|
+
}
|
|
7492
7580
|
function parseSbfGloNav(data) {
|
|
7493
7581
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
7494
7582
|
const ephemerides = [];
|
|
@@ -7498,38 +7586,161 @@ function parseSbfGloNav(data) {
|
|
|
7498
7586
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
7499
7587
|
if (id !== 4026 || len < 32) return;
|
|
7500
7588
|
messages++;
|
|
7501
|
-
const
|
|
7502
|
-
if (
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7589
|
+
const r = feedGloBlock(view, b, assembler);
|
|
7590
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
7591
|
+
else if (r.badCrc) badCrc++;
|
|
7592
|
+
});
|
|
7593
|
+
return { ephemerides, badCrc, messages };
|
|
7594
|
+
}
|
|
7595
|
+
|
|
7596
|
+
// src/sbf/navigation.ts
|
|
7597
|
+
var F4_DNU3 = -2e10;
|
|
7598
|
+
function ephKey(e) {
|
|
7599
|
+
const source = "source" in e ? e.source : "";
|
|
7600
|
+
return `${e.prn}|${e.tocDate.getTime()}|${source}`;
|
|
7601
|
+
}
|
|
7602
|
+
function decodeSbfNavigation(data) {
|
|
7603
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
7604
|
+
const ephemerides = [];
|
|
7605
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7606
|
+
const cnav = [];
|
|
7607
|
+
const ionoCorrections = {};
|
|
7608
|
+
let leapSeconds = null;
|
|
7609
|
+
const counts = {
|
|
7610
|
+
decodedNav: 0,
|
|
7611
|
+
gpsLnavRaw: 0,
|
|
7612
|
+
cnavRaw: 0,
|
|
7613
|
+
galRaw: 0,
|
|
7614
|
+
gloRaw: 0,
|
|
7615
|
+
bdsRaw: 0,
|
|
7616
|
+
badFrames: 0
|
|
7617
|
+
};
|
|
7618
|
+
const cnavAsm = newCnavAssemblers();
|
|
7619
|
+
const galAsm = newGalAssemblers();
|
|
7620
|
+
const gloAsm = new GloStringAssembler();
|
|
7621
|
+
const bdsAsm = new BdsAssembler();
|
|
7622
|
+
const lnavAsm = new GpsLnavAssembler();
|
|
7623
|
+
const addEph = (e) => {
|
|
7624
|
+
if (!e) return;
|
|
7625
|
+
const key = ephKey(e);
|
|
7626
|
+
if (seen.has(key)) return;
|
|
7627
|
+
seen.add(key);
|
|
7628
|
+
ephemerides.push(e);
|
|
7629
|
+
};
|
|
7630
|
+
const f4s = (b, n) => {
|
|
7631
|
+
const out = [];
|
|
7632
|
+
for (let k = 0; k < n; k++) {
|
|
7633
|
+
const v = view.getFloat32(b + 4 * k, true);
|
|
7634
|
+
if (v === F4_DNU3) return null;
|
|
7635
|
+
out.push(v);
|
|
7518
7636
|
}
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7637
|
+
return out;
|
|
7638
|
+
};
|
|
7639
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
7640
|
+
switch (id) {
|
|
7641
|
+
/* ---- decoded ephemeris blocks ---- */
|
|
7642
|
+
case 5891:
|
|
7643
|
+
if (len >= 140) {
|
|
7644
|
+
counts.decodedNav++;
|
|
7645
|
+
addEph(decodeGpsQzsNav(view, b, "G"));
|
|
7646
|
+
}
|
|
7647
|
+
return;
|
|
7648
|
+
case 4095:
|
|
7649
|
+
if (len >= 140) {
|
|
7650
|
+
counts.decodedNav++;
|
|
7651
|
+
addEph(decodeGpsQzsNav(view, b, "J"));
|
|
7652
|
+
}
|
|
7653
|
+
return;
|
|
7654
|
+
case 4002:
|
|
7655
|
+
if (len >= 149) {
|
|
7656
|
+
counts.decodedNav++;
|
|
7657
|
+
addEph(decodeGalNav(view, b));
|
|
7658
|
+
}
|
|
7659
|
+
return;
|
|
7660
|
+
case 4081:
|
|
7661
|
+
if (len >= 140) {
|
|
7662
|
+
counts.decodedNav++;
|
|
7663
|
+
addEph(decodeBdsNav(view, b));
|
|
7664
|
+
}
|
|
7665
|
+
return;
|
|
7666
|
+
case 4004:
|
|
7667
|
+
if (len >= 96) {
|
|
7668
|
+
counts.decodedNav++;
|
|
7669
|
+
addEph(decodeGloNav(view, b));
|
|
7670
|
+
}
|
|
7671
|
+
return;
|
|
7672
|
+
/* ---- raw navigation-frame blocks ---- */
|
|
7673
|
+
case 4017:
|
|
7674
|
+
// GPSRawCA
|
|
7675
|
+
case 4066: {
|
|
7676
|
+
if (len < 60) return;
|
|
7677
|
+
counts.gpsLnavRaw++;
|
|
7678
|
+
const r = feedGpsLnavBlock(view, b, lnavAsm);
|
|
7679
|
+
if (r.eph) addEph(r.eph);
|
|
7680
|
+
else if (r.badParity) counts.badFrames++;
|
|
7681
|
+
return;
|
|
7682
|
+
}
|
|
7683
|
+
case 4018:
|
|
7684
|
+
// GPSRawL2C
|
|
7685
|
+
case 4019: {
|
|
7686
|
+
if (len < 60) return;
|
|
7687
|
+
counts.cnavRaw++;
|
|
7688
|
+
const r = feedCnavBlock(view, b, id, cnavAsm);
|
|
7689
|
+
if (r.eph) cnav.push(r.eph);
|
|
7690
|
+
else if (r.badCrc) counts.badFrames++;
|
|
7691
|
+
return;
|
|
7692
|
+
}
|
|
7693
|
+
case 4022:
|
|
7694
|
+
// GALRawFNAV
|
|
7695
|
+
case 4023: {
|
|
7696
|
+
if (len < 52) return;
|
|
7697
|
+
counts.galRaw++;
|
|
7698
|
+
const r = feedGalBlock(data, view, b, id, galAsm);
|
|
7699
|
+
if (r.eph) addEph(r.eph);
|
|
7700
|
+
else if (r.badCrc) counts.badFrames++;
|
|
7701
|
+
return;
|
|
7702
|
+
}
|
|
7703
|
+
case 4026: {
|
|
7704
|
+
if (len < 32) return;
|
|
7705
|
+
counts.gloRaw++;
|
|
7706
|
+
const r = feedGloBlock(view, b, gloAsm);
|
|
7707
|
+
if (r.eph) addEph(r.eph);
|
|
7708
|
+
else if (r.badCrc) counts.badFrames++;
|
|
7709
|
+
return;
|
|
7710
|
+
}
|
|
7711
|
+
case 4047: {
|
|
7712
|
+
if (len < 60) return;
|
|
7713
|
+
counts.bdsRaw++;
|
|
7714
|
+
const r = feedBdsBlock(view, b, bdsAsm);
|
|
7715
|
+
if (r.eph) addEph(r.eph);
|
|
7716
|
+
else if (r.badCrc) counts.badFrames++;
|
|
7717
|
+
return;
|
|
7718
|
+
}
|
|
7719
|
+
/* ---- iono / UTC ---- */
|
|
7720
|
+
case 5893:
|
|
7721
|
+
// GPSIon
|
|
7722
|
+
case 4120: {
|
|
7723
|
+
if (len < 48) return;
|
|
7724
|
+
const alpha = f4s(b + 16, 4);
|
|
7725
|
+
const beta = f4s(b + 32, 4);
|
|
7726
|
+
if (!alpha || !beta) return;
|
|
7727
|
+
const sys = id === 5893 ? "GPS" : "BDS";
|
|
7728
|
+
ionoCorrections[`${sys}A`] = alpha;
|
|
7729
|
+
ionoCorrections[`${sys}B`] = beta;
|
|
7730
|
+
return;
|
|
7731
|
+
}
|
|
7732
|
+
case 4030: {
|
|
7733
|
+
if (len < 28) return;
|
|
7734
|
+
const ai = f4s(b + 16, 3);
|
|
7735
|
+
if (ai) ionoCorrections["GAL"] = ai;
|
|
7736
|
+
return;
|
|
7737
|
+
}
|
|
7738
|
+
case 5894:
|
|
7739
|
+
if (len >= 37) leapSeconds = view.getInt8(b + 33);
|
|
7740
|
+
return;
|
|
7522
7741
|
}
|
|
7523
|
-
const eph = assembler.push(
|
|
7524
|
-
prn,
|
|
7525
|
-
str,
|
|
7526
|
-
new Date(GPS_EPOCH_MS10 + wnc * MS_PER_WEEK5 + towMs),
|
|
7527
|
-
view.getUint8(b + 18) - 8
|
|
7528
|
-
// FreqNr, offset by 8
|
|
7529
|
-
);
|
|
7530
|
-
if (eph) ephemerides.push(eph);
|
|
7531
7742
|
});
|
|
7532
|
-
return { ephemerides,
|
|
7743
|
+
return { ephemerides, cnav, ionoCorrections, leapSeconds, counts };
|
|
7533
7744
|
}
|
|
7534
7745
|
|
|
7535
7746
|
// src/navbits/rs255.ts
|
|
@@ -13357,6 +13568,28 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
13357
13568
|
phaseResRms: nPhaseRes > 0 ? Math.sqrt(sumPhaseResSq / nPhaseRes) : 0
|
|
13358
13569
|
});
|
|
13359
13570
|
}
|
|
13571
|
+
let finalState;
|
|
13572
|
+
if (opts.exposeState) {
|
|
13573
|
+
const ambs = [];
|
|
13574
|
+
for (const [prn, index] of ambIdx) {
|
|
13575
|
+
const s = arcSnap.get(prn);
|
|
13576
|
+
if (!s || s.nEpochs < 10) continue;
|
|
13577
|
+
ambs.push({
|
|
13578
|
+
prn,
|
|
13579
|
+
index,
|
|
13580
|
+
aIF: x[index],
|
|
13581
|
+
mwCyc: mwState.get(prn)?.mean ?? s.mwCyc,
|
|
13582
|
+
f1: s.f1,
|
|
13583
|
+
f2: s.f2,
|
|
13584
|
+
elevDeg: s.elevSum / s.nEpochs
|
|
13585
|
+
});
|
|
13586
|
+
}
|
|
13587
|
+
finalState = {
|
|
13588
|
+
position: [x[IDX_X], x[IDX_Y], x[IDX_Z]],
|
|
13589
|
+
covariance: P.map((row) => row.slice()),
|
|
13590
|
+
ambiguities: ambs
|
|
13591
|
+
};
|
|
13592
|
+
}
|
|
13360
13593
|
for (const prn of [...arcSnap.keys()]) flushArc(prn);
|
|
13361
13594
|
const finalPos = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
|
|
13362
13595
|
const llh = ecefToGeodetic(finalPos[0], finalPos[1], finalPos[2]);
|
|
@@ -13373,7 +13606,8 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
13373
13606
|
epochsUsed: epochs.length,
|
|
13374
13607
|
convergenceSec,
|
|
13375
13608
|
finalError3d,
|
|
13376
|
-
arcs
|
|
13609
|
+
arcs,
|
|
13610
|
+
finalState
|
|
13377
13611
|
};
|
|
13378
13612
|
}
|
|
13379
13613
|
|
|
@@ -13466,6 +13700,117 @@ function resolvePppAmbiguities(sats, Qaif, opts = {}) {
|
|
|
13466
13700
|
rejectedWl
|
|
13467
13701
|
};
|
|
13468
13702
|
}
|
|
13703
|
+
function solveSpd(A, b) {
|
|
13704
|
+
const n = b.length;
|
|
13705
|
+
const L = Array.from({ length: n }, () => new Array(n).fill(0));
|
|
13706
|
+
for (let i = 0; i < n; i++) {
|
|
13707
|
+
for (let j = 0; j <= i; j++) {
|
|
13708
|
+
let s = A[i][j];
|
|
13709
|
+
for (let k = 0; k < j; k++) s -= L[i][k] * L[j][k];
|
|
13710
|
+
if (i === j) {
|
|
13711
|
+
if (s <= 0) return null;
|
|
13712
|
+
L[i][j] = Math.sqrt(s);
|
|
13713
|
+
} else {
|
|
13714
|
+
L[i][j] = s / L[j][j];
|
|
13715
|
+
}
|
|
13716
|
+
}
|
|
13717
|
+
}
|
|
13718
|
+
const y = new Array(n).fill(0);
|
|
13719
|
+
for (let i = 0; i < n; i++) {
|
|
13720
|
+
let s = b[i];
|
|
13721
|
+
for (let k = 0; k < i; k++) s -= L[i][k] * y[k];
|
|
13722
|
+
y[i] = s / L[i][i];
|
|
13723
|
+
}
|
|
13724
|
+
const x = new Array(n).fill(0);
|
|
13725
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
13726
|
+
let s = y[i];
|
|
13727
|
+
for (let k = i + 1; k < n; k++) s -= L[k][i] * x[k];
|
|
13728
|
+
x[i] = s / L[i][i];
|
|
13729
|
+
}
|
|
13730
|
+
return x;
|
|
13731
|
+
}
|
|
13732
|
+
function fixPppPosition(state, fcb, opts = {}) {
|
|
13733
|
+
const floatPos = state.position;
|
|
13734
|
+
const noFix = {
|
|
13735
|
+
fixed: false,
|
|
13736
|
+
position: floatPos,
|
|
13737
|
+
floatPosition: floatPos,
|
|
13738
|
+
shift: [0, 0, 0],
|
|
13739
|
+
nFixed: 0,
|
|
13740
|
+
ratio: 0,
|
|
13741
|
+
refPrn: null
|
|
13742
|
+
};
|
|
13743
|
+
const amb = state.ambiguities;
|
|
13744
|
+
if (amb.length < 3) return noFix;
|
|
13745
|
+
const sats = amb.map((a) => ({
|
|
13746
|
+
prn: a.prn,
|
|
13747
|
+
aIF: a.aIF,
|
|
13748
|
+
mwCyc: a.mwCyc,
|
|
13749
|
+
f1: a.f1,
|
|
13750
|
+
f2: a.f2,
|
|
13751
|
+
wlBiasCyc: fcb.satWlFcb.get(a.prn) ?? 0,
|
|
13752
|
+
nlBiasCyc: fcb.satNlFcb.get(a.prn) ?? 0,
|
|
13753
|
+
elevDeg: a.elevDeg
|
|
13754
|
+
}));
|
|
13755
|
+
const n = sats.length;
|
|
13756
|
+
const Qaif = new Float64Array(n * n);
|
|
13757
|
+
for (let i = 0; i < n; i++)
|
|
13758
|
+
for (let j = 0; j < n; j++)
|
|
13759
|
+
Qaif[i * n + j] = state.covariance[amb[i].index][amb[j].index];
|
|
13760
|
+
const res = resolvePppAmbiguities(sats, Qaif, opts);
|
|
13761
|
+
if (!res.fixed || res.refPrn === null) {
|
|
13762
|
+
return { ...noFix, ratio: res.ratio, refPrn: res.refPrn };
|
|
13763
|
+
}
|
|
13764
|
+
const idxOfPrn = new Map(amb.map((a) => [a.prn, a.index]));
|
|
13765
|
+
const floatOfPrn = new Map(amb.map((a) => [a.prn, a.aIF]));
|
|
13766
|
+
const kept = res.sats.filter((s) => idxOfPrn.has(s.prn));
|
|
13767
|
+
const refPos = kept.findIndex((s) => s.prn === res.refPrn);
|
|
13768
|
+
if (refPos < 0 || kept.length < 2) {
|
|
13769
|
+
return { ...noFix, ratio: res.ratio, refPrn: res.refPrn };
|
|
13770
|
+
}
|
|
13771
|
+
const ambIdx = kept.map((s) => idxOfPrn.get(s.prn));
|
|
13772
|
+
const aFloat = kept.map((s) => floatOfPrn.get(s.prn));
|
|
13773
|
+
const aFixed = kept.map((s) => s.aIF);
|
|
13774
|
+
const others = kept.map((_, i) => i).filter((i) => i !== refPos);
|
|
13775
|
+
const m = others.length;
|
|
13776
|
+
const P = state.covariance;
|
|
13777
|
+
const qAA = (i, j) => P[ambIdx[i]][ambIdx[j]];
|
|
13778
|
+
const qXA = (r, i) => P[r][ambIdx[i]];
|
|
13779
|
+
const Qzz = Array.from({ length: m }, () => new Array(m).fill(0));
|
|
13780
|
+
const z = new Array(m).fill(0);
|
|
13781
|
+
for (let a = 0; a < m; a++) {
|
|
13782
|
+
const ia = others[a];
|
|
13783
|
+
z[a] = aFloat[ia] - aFloat[refPos] - (aFixed[ia] - aFixed[refPos]);
|
|
13784
|
+
for (let b = 0; b < m; b++) {
|
|
13785
|
+
const ib = others[b];
|
|
13786
|
+
Qzz[a][b] = qAA(ia, ib) - qAA(ia, refPos) - qAA(refPos, ib) + qAA(refPos, refPos);
|
|
13787
|
+
}
|
|
13788
|
+
}
|
|
13789
|
+
const Qxz = [0, 1, 2].map(
|
|
13790
|
+
(r) => others.map((ia) => qXA(r, ia) - qXA(r, refPos))
|
|
13791
|
+
);
|
|
13792
|
+
const y = solveSpd(Qzz, z);
|
|
13793
|
+
if (!y) return { ...noFix, ratio: res.ratio, refPrn: res.refPrn };
|
|
13794
|
+
const shift = [0, 0, 0];
|
|
13795
|
+
for (let r = 0; r < 3; r++) {
|
|
13796
|
+
let s = 0;
|
|
13797
|
+
for (let a = 0; a < m; a++) s += Qxz[r][a] * y[a];
|
|
13798
|
+
shift[r] = -s;
|
|
13799
|
+
}
|
|
13800
|
+
return {
|
|
13801
|
+
fixed: true,
|
|
13802
|
+
position: [
|
|
13803
|
+
floatPos[0] + shift[0],
|
|
13804
|
+
floatPos[1] + shift[1],
|
|
13805
|
+
floatPos[2] + shift[2]
|
|
13806
|
+
],
|
|
13807
|
+
floatPosition: floatPos,
|
|
13808
|
+
shift,
|
|
13809
|
+
nFixed: m,
|
|
13810
|
+
ratio: res.ratio,
|
|
13811
|
+
refPrn: res.refPrn
|
|
13812
|
+
};
|
|
13813
|
+
}
|
|
13469
13814
|
|
|
13470
13815
|
// src/positioning/ppp-fcb.ts
|
|
13471
13816
|
function extractWidelaneArcs(station, epochs, opts = {}) {
|
|
@@ -16263,6 +16608,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
16263
16608
|
decodeBinexEph,
|
|
16264
16609
|
decodeEphemeris,
|
|
16265
16610
|
decodeMsmFull,
|
|
16611
|
+
decodeSbfNavigation,
|
|
16266
16612
|
deg2dms,
|
|
16267
16613
|
deg2rad,
|
|
16268
16614
|
detrendIonoArcs,
|
|
@@ -16277,6 +16623,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
16277
16623
|
extractWidelaneArcs,
|
|
16278
16624
|
fetchSourcetable,
|
|
16279
16625
|
findSatBias,
|
|
16626
|
+
fixPppPosition,
|
|
16280
16627
|
fmtD,
|
|
16281
16628
|
fmtF,
|
|
16282
16629
|
formatUTCTime,
|
|
@@ -16380,6 +16727,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
16380
16727
|
parseSbfCnav,
|
|
16381
16728
|
parseSbfGalNav,
|
|
16382
16729
|
parseSbfGloNav,
|
|
16730
|
+
parseSbfGpsNav,
|
|
16383
16731
|
parseSbfHas,
|
|
16384
16732
|
parseSbfIonoUtc,
|
|
16385
16733
|
parseSbfMeas,
|