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/binex.js
CHANGED
|
@@ -7,16 +7,18 @@ import {
|
|
|
7
7
|
galFnavPageCrcOk,
|
|
8
8
|
galInavPageCrcOk,
|
|
9
9
|
testGloString
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-FA2UTLEQ.js";
|
|
11
11
|
import {
|
|
12
12
|
CnavAssembler,
|
|
13
13
|
cnavCrcOk,
|
|
14
14
|
crc24q
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-YUW33VXK.js";
|
|
16
16
|
import {
|
|
17
|
+
GpsLnavAssembler,
|
|
17
18
|
getBitS,
|
|
18
|
-
getBitU
|
|
19
|
-
|
|
19
|
+
getBitU,
|
|
20
|
+
setBitU
|
|
21
|
+
} from "./chunk-V2D5KUKH.js";
|
|
20
22
|
import {
|
|
21
23
|
getGpsLeap
|
|
22
24
|
} from "./chunk-HVXYFUCB.js";
|
|
@@ -423,38 +425,78 @@ function parseSbfIonoUtc(data) {
|
|
|
423
425
|
return { ionoCorrections, leapSeconds };
|
|
424
426
|
}
|
|
425
427
|
|
|
428
|
+
// src/sbf/rawnav-gps.ts
|
|
429
|
+
var WNC_DNU = 65535;
|
|
430
|
+
function extractSbfLnavSubframe(view, b) {
|
|
431
|
+
const sf = new Uint8Array(30);
|
|
432
|
+
for (let k = 0; k < 10; k++) {
|
|
433
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
434
|
+
setBitU(sf, 24 * k, 24, w >>> 6 & 16777215);
|
|
435
|
+
}
|
|
436
|
+
return sf;
|
|
437
|
+
}
|
|
438
|
+
function feedGpsLnavBlock(view, b, assembler) {
|
|
439
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
440
|
+
if (!prn || prn[0] !== "G" && prn[0] !== "J") return {};
|
|
441
|
+
if (view.getUint8(b + 15) !== 1) return {};
|
|
442
|
+
const wnc = view.getUint16(b + 12, true);
|
|
443
|
+
if (wnc === WNC_DNU) return {};
|
|
444
|
+
const r = assembler.push(prn, extractSbfLnavSubframe(view, b), wnc);
|
|
445
|
+
if (r.kind === "eph") return { eph: r.eph };
|
|
446
|
+
if (r.kind === "decodeFailed") return { badParity: true };
|
|
447
|
+
return {};
|
|
448
|
+
}
|
|
449
|
+
function parseSbfGpsNav(data) {
|
|
450
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
451
|
+
const ephemerides = [];
|
|
452
|
+
const assembler = new GpsLnavAssembler();
|
|
453
|
+
let badParity = 0;
|
|
454
|
+
let messages = 0;
|
|
455
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
456
|
+
if (id !== 4017 && id !== 4066 || len < 60) return;
|
|
457
|
+
messages++;
|
|
458
|
+
const r = feedGpsLnavBlock(view, b, assembler);
|
|
459
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
460
|
+
else if (r.badParity) badParity++;
|
|
461
|
+
});
|
|
462
|
+
return { ephemerides, badParity, messages };
|
|
463
|
+
}
|
|
464
|
+
|
|
426
465
|
// src/sbf/rawnav.ts
|
|
427
|
-
var
|
|
466
|
+
var CNAV_SIGNAL_OF_BLOCK = {
|
|
428
467
|
4018: "L2C",
|
|
429
468
|
4019: "L5"
|
|
430
469
|
};
|
|
470
|
+
function newCnavAssemblers() {
|
|
471
|
+
return { L2C: new CnavAssembler(), L5: new CnavAssembler() };
|
|
472
|
+
}
|
|
473
|
+
function feedCnavBlock(view, b, id, asm) {
|
|
474
|
+
const signal = CNAV_SIGNAL_OF_BLOCK[id];
|
|
475
|
+
if (!signal) return {};
|
|
476
|
+
const msg = new Uint8Array(40);
|
|
477
|
+
for (let k = 0; k < 10; k++) {
|
|
478
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
479
|
+
msg[4 * k] = w >>> 24;
|
|
480
|
+
msg[4 * k + 1] = w >>> 16 & 255;
|
|
481
|
+
msg[4 * k + 2] = w >>> 8 & 255;
|
|
482
|
+
msg[4 * k + 3] = w & 255;
|
|
483
|
+
}
|
|
484
|
+
if (!cnavCrcOk(msg)) return { badCrc: true };
|
|
485
|
+
const eph = asm[signal].push(msg);
|
|
486
|
+
return eph ? { eph: { ...eph, signal } } : {};
|
|
487
|
+
}
|
|
431
488
|
function parseSbfCnav(data) {
|
|
432
489
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
433
490
|
const ephemerides = [];
|
|
434
|
-
const
|
|
435
|
-
L2C: new CnavAssembler(),
|
|
436
|
-
L5: new CnavAssembler()
|
|
437
|
-
};
|
|
491
|
+
const asm = newCnavAssemblers();
|
|
438
492
|
let badCrc = 0;
|
|
439
493
|
let messages = 0;
|
|
440
494
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
441
|
-
|
|
442
|
-
if (!signal || len < 60) return;
|
|
495
|
+
if (!CNAV_SIGNAL_OF_BLOCK[id] || len < 60) return;
|
|
443
496
|
messages++;
|
|
444
|
-
const
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
msg[4 * k] = w >>> 24;
|
|
448
|
-
msg[4 * k + 1] = w >>> 16 & 255;
|
|
449
|
-
msg[4 * k + 2] = w >>> 8 & 255;
|
|
450
|
-
msg[4 * k + 3] = w & 255;
|
|
451
|
-
}
|
|
452
|
-
if (!cnavCrcOk(msg)) {
|
|
453
|
-
badCrc++;
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
const eph = assemblers[signal].push(msg);
|
|
457
|
-
if (eph) ephemerides.push({ ...eph, signal });
|
|
497
|
+
const r = feedCnavBlock(view, b, id, asm);
|
|
498
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
499
|
+
else if (r.badCrc) badCrc++;
|
|
458
500
|
});
|
|
459
501
|
return { ephemerides, badCrc, messages };
|
|
460
502
|
}
|
|
@@ -462,50 +504,51 @@ function parseSbfCnav(data) {
|
|
|
462
504
|
// src/sbf/rawnav-gal.ts
|
|
463
505
|
var INAV_SOURCES = [17, 21, 22];
|
|
464
506
|
var FNAV_SOURCES = [20, 22];
|
|
507
|
+
function newGalAssemblers() {
|
|
508
|
+
return { inav: new GalInavAssembler(), fnav: new GalFnavAssembler() };
|
|
509
|
+
}
|
|
510
|
+
function feedGalBlock(data, view, b, id, asm) {
|
|
511
|
+
const prnStr = svidToPrn(data[b + 14]);
|
|
512
|
+
if (!prnStr || prnStr[0] !== "E") return {};
|
|
513
|
+
const prn = parseInt(prnStr.slice(1), 10);
|
|
514
|
+
const source = data[b + 17] & 31;
|
|
515
|
+
const page = new Uint8Array(32);
|
|
516
|
+
for (let k = 0; k < 8; k++) {
|
|
517
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
518
|
+
page[4 * k] = w >>> 24;
|
|
519
|
+
page[4 * k + 1] = w >>> 16 & 255;
|
|
520
|
+
page[4 * k + 2] = w >>> 8 & 255;
|
|
521
|
+
page[4 * k + 3] = w & 255;
|
|
522
|
+
}
|
|
523
|
+
let eph;
|
|
524
|
+
let src;
|
|
525
|
+
if (id === 4023) {
|
|
526
|
+
src = "inav";
|
|
527
|
+
if (!INAV_SOURCES.includes(source)) return {};
|
|
528
|
+
if (getBitU2(page, 0) !== 0 || getBitU2(page, 114) !== 1) return {};
|
|
529
|
+
if (!galInavPageCrcOk(page)) return { badCrc: true };
|
|
530
|
+
eph = asm.inav.push(prn, page);
|
|
531
|
+
} else {
|
|
532
|
+
src = "fnav";
|
|
533
|
+
if (!FNAV_SOURCES.includes(source)) return {};
|
|
534
|
+
if (isFnavDummy(page)) return {};
|
|
535
|
+
if (!galFnavPageCrcOk(page)) return { badCrc: true };
|
|
536
|
+
eph = asm.fnav.push(prn, page);
|
|
537
|
+
}
|
|
538
|
+
return eph ? { eph: { ...eph, source: src } } : {};
|
|
539
|
+
}
|
|
465
540
|
function parseSbfGalNav(data) {
|
|
466
541
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
467
542
|
const ephemerides = [];
|
|
468
|
-
const
|
|
469
|
-
const fnav = new GalFnavAssembler();
|
|
543
|
+
const asm = newGalAssemblers();
|
|
470
544
|
let badCrc = 0;
|
|
471
545
|
let messages = 0;
|
|
472
546
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
473
547
|
if (id !== 4022 && id !== 4023 || len < 52) return;
|
|
474
548
|
messages++;
|
|
475
|
-
const
|
|
476
|
-
if (
|
|
477
|
-
|
|
478
|
-
const source = data[b + 17] & 31;
|
|
479
|
-
const page = new Uint8Array(32);
|
|
480
|
-
for (let k = 0; k < 8; k++) {
|
|
481
|
-
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
482
|
-
page[4 * k] = w >>> 24;
|
|
483
|
-
page[4 * k + 1] = w >>> 16 & 255;
|
|
484
|
-
page[4 * k + 2] = w >>> 8 & 255;
|
|
485
|
-
page[4 * k + 3] = w & 255;
|
|
486
|
-
}
|
|
487
|
-
let eph;
|
|
488
|
-
let src;
|
|
489
|
-
if (id === 4023) {
|
|
490
|
-
src = "inav";
|
|
491
|
-
if (!INAV_SOURCES.includes(source)) return;
|
|
492
|
-
if (getBitU2(page, 0) !== 0 || getBitU2(page, 114) !== 1) return;
|
|
493
|
-
if (!galInavPageCrcOk(page)) {
|
|
494
|
-
badCrc++;
|
|
495
|
-
return;
|
|
496
|
-
}
|
|
497
|
-
eph = inav.push(prn, page);
|
|
498
|
-
} else {
|
|
499
|
-
src = "fnav";
|
|
500
|
-
if (!FNAV_SOURCES.includes(source)) return;
|
|
501
|
-
if (isFnavDummy(page)) return;
|
|
502
|
-
if (!galFnavPageCrcOk(page)) {
|
|
503
|
-
badCrc++;
|
|
504
|
-
return;
|
|
505
|
-
}
|
|
506
|
-
eph = fnav.push(prn, page);
|
|
507
|
-
}
|
|
508
|
-
if (eph) ephemerides.push({ ...eph, source: src });
|
|
549
|
+
const r = feedGalBlock(data, view, b, id, asm);
|
|
550
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
551
|
+
else if (r.badCrc) badCrc++;
|
|
509
552
|
});
|
|
510
553
|
return { ephemerides, badCrc, messages };
|
|
511
554
|
}
|
|
@@ -520,7 +563,26 @@ function isFnavDummy(page) {
|
|
|
520
563
|
var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
|
|
521
564
|
var MS_PER_WEEK2 = 7 * 86400 * 1e3;
|
|
522
565
|
var TOW_DNU = 4294967295;
|
|
523
|
-
var
|
|
566
|
+
var WNC_DNU2 = 65535;
|
|
567
|
+
function feedBdsBlock(view, b, assembler) {
|
|
568
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
569
|
+
if (!prn || prn[0] !== "C") return {};
|
|
570
|
+
const sf = new Uint8Array(38);
|
|
571
|
+
for (let k = 0; k < 10; k++) {
|
|
572
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
573
|
+
sf[4 * k] = w >>> 24;
|
|
574
|
+
if (k < 9) {
|
|
575
|
+
sf[4 * k + 1] = w >>> 16 & 255;
|
|
576
|
+
sf[4 * k + 2] = w >>> 8 & 255;
|
|
577
|
+
sf[4 * k + 3] = w & 255;
|
|
578
|
+
} else {
|
|
579
|
+
sf[37] = w >>> 16 & 240;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
if (!bdsSubframeParityOk(sf)) return { badCrc: true };
|
|
583
|
+
const eph = assembler.push(prn, sf);
|
|
584
|
+
return eph ? { eph } : {};
|
|
585
|
+
}
|
|
524
586
|
function parseSbfBdsNav(data) {
|
|
525
587
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
526
588
|
const ephemerides = [];
|
|
@@ -530,29 +592,41 @@ function parseSbfBdsNav(data) {
|
|
|
530
592
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
531
593
|
if (id !== 4047 || len < 60) return;
|
|
532
594
|
messages++;
|
|
533
|
-
const
|
|
534
|
-
if (
|
|
535
|
-
|
|
536
|
-
for (let k = 0; k < 10; k++) {
|
|
537
|
-
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
538
|
-
sf[4 * k] = w >>> 24;
|
|
539
|
-
if (k < 9) {
|
|
540
|
-
sf[4 * k + 1] = w >>> 16 & 255;
|
|
541
|
-
sf[4 * k + 2] = w >>> 8 & 255;
|
|
542
|
-
sf[4 * k + 3] = w & 255;
|
|
543
|
-
} else {
|
|
544
|
-
sf[37] = w >>> 16 & 240;
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
if (!bdsSubframeParityOk(sf)) {
|
|
548
|
-
badCrc++;
|
|
549
|
-
return;
|
|
550
|
-
}
|
|
551
|
-
const eph = assembler.push(prn, sf);
|
|
552
|
-
if (eph) ephemerides.push(eph);
|
|
595
|
+
const r = feedBdsBlock(view, b, assembler);
|
|
596
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
597
|
+
else if (r.badCrc) badCrc++;
|
|
553
598
|
});
|
|
554
599
|
return { ephemerides, badCrc, messages };
|
|
555
600
|
}
|
|
601
|
+
function feedGloBlock(view, b, assembler) {
|
|
602
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
603
|
+
if (!prn || prn[0] !== "R") return {};
|
|
604
|
+
const towMs = view.getUint32(b + 8, true);
|
|
605
|
+
const wnc = view.getUint16(b + 12, true);
|
|
606
|
+
if (towMs === TOW_DNU || wnc === WNC_DNU2) return {};
|
|
607
|
+
const str = new Uint8Array(11);
|
|
608
|
+
for (let k = 0; k < 3; k++) {
|
|
609
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
610
|
+
str[4 * k] = w >>> 24;
|
|
611
|
+
if (k < 2) {
|
|
612
|
+
str[4 * k + 1] = w >>> 16 & 255;
|
|
613
|
+
str[4 * k + 2] = w >>> 8 & 255;
|
|
614
|
+
str[4 * k + 3] = w & 255;
|
|
615
|
+
} else {
|
|
616
|
+
str[9] = w >>> 16 & 255;
|
|
617
|
+
str[10] = w >>> 8 & 248;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
if (!testGloString(str)) return { badCrc: true };
|
|
621
|
+
const eph = assembler.push(
|
|
622
|
+
prn,
|
|
623
|
+
str,
|
|
624
|
+
new Date(GPS_EPOCH_MS2 + wnc * MS_PER_WEEK2 + towMs),
|
|
625
|
+
view.getUint8(b + 18) - 8
|
|
626
|
+
// FreqNr, offset by 8
|
|
627
|
+
);
|
|
628
|
+
return eph ? { eph } : {};
|
|
629
|
+
}
|
|
556
630
|
function parseSbfGloNav(data) {
|
|
557
631
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
558
632
|
const ephemerides = [];
|
|
@@ -562,38 +636,161 @@ function parseSbfGloNav(data) {
|
|
|
562
636
|
scanSbfFrames(data, view, (id, b, len) => {
|
|
563
637
|
if (id !== 4026 || len < 32) return;
|
|
564
638
|
messages++;
|
|
565
|
-
const
|
|
566
|
-
if (
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
639
|
+
const r = feedGloBlock(view, b, assembler);
|
|
640
|
+
if (r.eph) ephemerides.push(r.eph);
|
|
641
|
+
else if (r.badCrc) badCrc++;
|
|
642
|
+
});
|
|
643
|
+
return { ephemerides, badCrc, messages };
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// src/sbf/navigation.ts
|
|
647
|
+
var F4_DNU3 = -2e10;
|
|
648
|
+
function ephKey(e) {
|
|
649
|
+
const source = "source" in e ? e.source : "";
|
|
650
|
+
return `${e.prn}|${e.tocDate.getTime()}|${source}`;
|
|
651
|
+
}
|
|
652
|
+
function decodeSbfNavigation(data) {
|
|
653
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
654
|
+
const ephemerides = [];
|
|
655
|
+
const seen = /* @__PURE__ */ new Set();
|
|
656
|
+
const cnav = [];
|
|
657
|
+
const ionoCorrections = {};
|
|
658
|
+
let leapSeconds = null;
|
|
659
|
+
const counts = {
|
|
660
|
+
decodedNav: 0,
|
|
661
|
+
gpsLnavRaw: 0,
|
|
662
|
+
cnavRaw: 0,
|
|
663
|
+
galRaw: 0,
|
|
664
|
+
gloRaw: 0,
|
|
665
|
+
bdsRaw: 0,
|
|
666
|
+
badFrames: 0
|
|
667
|
+
};
|
|
668
|
+
const cnavAsm = newCnavAssemblers();
|
|
669
|
+
const galAsm = newGalAssemblers();
|
|
670
|
+
const gloAsm = new GloStringAssembler();
|
|
671
|
+
const bdsAsm = new BdsAssembler();
|
|
672
|
+
const lnavAsm = new GpsLnavAssembler();
|
|
673
|
+
const addEph = (e) => {
|
|
674
|
+
if (!e) return;
|
|
675
|
+
const key = ephKey(e);
|
|
676
|
+
if (seen.has(key)) return;
|
|
677
|
+
seen.add(key);
|
|
678
|
+
ephemerides.push(e);
|
|
679
|
+
};
|
|
680
|
+
const f4s = (b, n) => {
|
|
681
|
+
const out = [];
|
|
682
|
+
for (let k = 0; k < n; k++) {
|
|
683
|
+
const v = view.getFloat32(b + 4 * k, true);
|
|
684
|
+
if (v === F4_DNU3) return null;
|
|
685
|
+
out.push(v);
|
|
582
686
|
}
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
687
|
+
return out;
|
|
688
|
+
};
|
|
689
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
690
|
+
switch (id) {
|
|
691
|
+
/* ---- decoded ephemeris blocks ---- */
|
|
692
|
+
case 5891:
|
|
693
|
+
if (len >= 140) {
|
|
694
|
+
counts.decodedNav++;
|
|
695
|
+
addEph(decodeGpsQzsNav(view, b, "G"));
|
|
696
|
+
}
|
|
697
|
+
return;
|
|
698
|
+
case 4095:
|
|
699
|
+
if (len >= 140) {
|
|
700
|
+
counts.decodedNav++;
|
|
701
|
+
addEph(decodeGpsQzsNav(view, b, "J"));
|
|
702
|
+
}
|
|
703
|
+
return;
|
|
704
|
+
case 4002:
|
|
705
|
+
if (len >= 149) {
|
|
706
|
+
counts.decodedNav++;
|
|
707
|
+
addEph(decodeGalNav(view, b));
|
|
708
|
+
}
|
|
709
|
+
return;
|
|
710
|
+
case 4081:
|
|
711
|
+
if (len >= 140) {
|
|
712
|
+
counts.decodedNav++;
|
|
713
|
+
addEph(decodeBdsNav(view, b));
|
|
714
|
+
}
|
|
715
|
+
return;
|
|
716
|
+
case 4004:
|
|
717
|
+
if (len >= 96) {
|
|
718
|
+
counts.decodedNav++;
|
|
719
|
+
addEph(decodeGloNav(view, b));
|
|
720
|
+
}
|
|
721
|
+
return;
|
|
722
|
+
/* ---- raw navigation-frame blocks ---- */
|
|
723
|
+
case 4017:
|
|
724
|
+
// GPSRawCA
|
|
725
|
+
case 4066: {
|
|
726
|
+
if (len < 60) return;
|
|
727
|
+
counts.gpsLnavRaw++;
|
|
728
|
+
const r = feedGpsLnavBlock(view, b, lnavAsm);
|
|
729
|
+
if (r.eph) addEph(r.eph);
|
|
730
|
+
else if (r.badParity) counts.badFrames++;
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
case 4018:
|
|
734
|
+
// GPSRawL2C
|
|
735
|
+
case 4019: {
|
|
736
|
+
if (len < 60) return;
|
|
737
|
+
counts.cnavRaw++;
|
|
738
|
+
const r = feedCnavBlock(view, b, id, cnavAsm);
|
|
739
|
+
if (r.eph) cnav.push(r.eph);
|
|
740
|
+
else if (r.badCrc) counts.badFrames++;
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
case 4022:
|
|
744
|
+
// GALRawFNAV
|
|
745
|
+
case 4023: {
|
|
746
|
+
if (len < 52) return;
|
|
747
|
+
counts.galRaw++;
|
|
748
|
+
const r = feedGalBlock(data, view, b, id, galAsm);
|
|
749
|
+
if (r.eph) addEph(r.eph);
|
|
750
|
+
else if (r.badCrc) counts.badFrames++;
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
case 4026: {
|
|
754
|
+
if (len < 32) return;
|
|
755
|
+
counts.gloRaw++;
|
|
756
|
+
const r = feedGloBlock(view, b, gloAsm);
|
|
757
|
+
if (r.eph) addEph(r.eph);
|
|
758
|
+
else if (r.badCrc) counts.badFrames++;
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
case 4047: {
|
|
762
|
+
if (len < 60) return;
|
|
763
|
+
counts.bdsRaw++;
|
|
764
|
+
const r = feedBdsBlock(view, b, bdsAsm);
|
|
765
|
+
if (r.eph) addEph(r.eph);
|
|
766
|
+
else if (r.badCrc) counts.badFrames++;
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
/* ---- iono / UTC ---- */
|
|
770
|
+
case 5893:
|
|
771
|
+
// GPSIon
|
|
772
|
+
case 4120: {
|
|
773
|
+
if (len < 48) return;
|
|
774
|
+
const alpha = f4s(b + 16, 4);
|
|
775
|
+
const beta = f4s(b + 32, 4);
|
|
776
|
+
if (!alpha || !beta) return;
|
|
777
|
+
const sys = id === 5893 ? "GPS" : "BDS";
|
|
778
|
+
ionoCorrections[`${sys}A`] = alpha;
|
|
779
|
+
ionoCorrections[`${sys}B`] = beta;
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
case 4030: {
|
|
783
|
+
if (len < 28) return;
|
|
784
|
+
const ai = f4s(b + 16, 3);
|
|
785
|
+
if (ai) ionoCorrections["GAL"] = ai;
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
case 5894:
|
|
789
|
+
if (len >= 37) leapSeconds = view.getInt8(b + 33);
|
|
790
|
+
return;
|
|
586
791
|
}
|
|
587
|
-
const eph = assembler.push(
|
|
588
|
-
prn,
|
|
589
|
-
str,
|
|
590
|
-
new Date(GPS_EPOCH_MS2 + wnc * MS_PER_WEEK2 + towMs),
|
|
591
|
-
view.getUint8(b + 18) - 8
|
|
592
|
-
// FreqNr, offset by 8
|
|
593
|
-
);
|
|
594
|
-
if (eph) ephemerides.push(eph);
|
|
595
792
|
});
|
|
596
|
-
return { ephemerides,
|
|
793
|
+
return { ephemerides, cnav, ionoCorrections, leapSeconds, counts };
|
|
597
794
|
}
|
|
598
795
|
|
|
599
796
|
// src/navbits/rs255.ts
|
|
@@ -1793,10 +1990,12 @@ export {
|
|
|
1793
1990
|
parseSbfNav,
|
|
1794
1991
|
parseSbfAlmanac,
|
|
1795
1992
|
parseSbfIonoUtc,
|
|
1993
|
+
parseSbfGpsNav,
|
|
1796
1994
|
parseSbfCnav,
|
|
1797
1995
|
parseSbfGalNav,
|
|
1798
1996
|
parseSbfBdsNav,
|
|
1799
1997
|
parseSbfGloNav,
|
|
1998
|
+
decodeSbfNavigation,
|
|
1800
1999
|
parseSbfHas,
|
|
1801
2000
|
parseSbfMeas
|
|
1802
2001
|
};
|
|
@@ -1959,6 +1959,28 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
1959
1959
|
phaseResRms: nPhaseRes > 0 ? Math.sqrt(sumPhaseResSq / nPhaseRes) : 0
|
|
1960
1960
|
});
|
|
1961
1961
|
}
|
|
1962
|
+
let finalState;
|
|
1963
|
+
if (opts.exposeState) {
|
|
1964
|
+
const ambs = [];
|
|
1965
|
+
for (const [prn, index] of ambIdx) {
|
|
1966
|
+
const s = arcSnap.get(prn);
|
|
1967
|
+
if (!s || s.nEpochs < 10) continue;
|
|
1968
|
+
ambs.push({
|
|
1969
|
+
prn,
|
|
1970
|
+
index,
|
|
1971
|
+
aIF: x[index],
|
|
1972
|
+
mwCyc: mwState.get(prn)?.mean ?? s.mwCyc,
|
|
1973
|
+
f1: s.f1,
|
|
1974
|
+
f2: s.f2,
|
|
1975
|
+
elevDeg: s.elevSum / s.nEpochs
|
|
1976
|
+
});
|
|
1977
|
+
}
|
|
1978
|
+
finalState = {
|
|
1979
|
+
position: [x[IDX_X], x[IDX_Y], x[IDX_Z]],
|
|
1980
|
+
covariance: P.map((row) => row.slice()),
|
|
1981
|
+
ambiguities: ambs
|
|
1982
|
+
};
|
|
1983
|
+
}
|
|
1962
1984
|
for (const prn of [...arcSnap.keys()]) flushArc(prn);
|
|
1963
1985
|
const finalPos = [x[IDX_X], x[IDX_Y], x[IDX_Z]];
|
|
1964
1986
|
const llh = ecefToGeodetic(finalPos[0], finalPos[1], finalPos[2]);
|
|
@@ -1975,7 +1997,8 @@ function solvePpp(epochs, sp3, opts) {
|
|
|
1975
1997
|
epochsUsed: epochs.length,
|
|
1976
1998
|
convergenceSec,
|
|
1977
1999
|
finalError3d,
|
|
1978
|
-
arcs
|
|
2000
|
+
arcs,
|
|
2001
|
+
finalState
|
|
1979
2002
|
};
|
|
1980
2003
|
}
|
|
1981
2004
|
|
|
@@ -2068,6 +2091,117 @@ function resolvePppAmbiguities(sats, Qaif, opts = {}) {
|
|
|
2068
2091
|
rejectedWl
|
|
2069
2092
|
};
|
|
2070
2093
|
}
|
|
2094
|
+
function solveSpd(A, b) {
|
|
2095
|
+
const n = b.length;
|
|
2096
|
+
const L = Array.from({ length: n }, () => new Array(n).fill(0));
|
|
2097
|
+
for (let i = 0; i < n; i++) {
|
|
2098
|
+
for (let j = 0; j <= i; j++) {
|
|
2099
|
+
let s = A[i][j];
|
|
2100
|
+
for (let k = 0; k < j; k++) s -= L[i][k] * L[j][k];
|
|
2101
|
+
if (i === j) {
|
|
2102
|
+
if (s <= 0) return null;
|
|
2103
|
+
L[i][j] = Math.sqrt(s);
|
|
2104
|
+
} else {
|
|
2105
|
+
L[i][j] = s / L[j][j];
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
const y = new Array(n).fill(0);
|
|
2110
|
+
for (let i = 0; i < n; i++) {
|
|
2111
|
+
let s = b[i];
|
|
2112
|
+
for (let k = 0; k < i; k++) s -= L[i][k] * y[k];
|
|
2113
|
+
y[i] = s / L[i][i];
|
|
2114
|
+
}
|
|
2115
|
+
const x = new Array(n).fill(0);
|
|
2116
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
2117
|
+
let s = y[i];
|
|
2118
|
+
for (let k = i + 1; k < n; k++) s -= L[k][i] * x[k];
|
|
2119
|
+
x[i] = s / L[i][i];
|
|
2120
|
+
}
|
|
2121
|
+
return x;
|
|
2122
|
+
}
|
|
2123
|
+
function fixPppPosition(state, fcb, opts = {}) {
|
|
2124
|
+
const floatPos = state.position;
|
|
2125
|
+
const noFix = {
|
|
2126
|
+
fixed: false,
|
|
2127
|
+
position: floatPos,
|
|
2128
|
+
floatPosition: floatPos,
|
|
2129
|
+
shift: [0, 0, 0],
|
|
2130
|
+
nFixed: 0,
|
|
2131
|
+
ratio: 0,
|
|
2132
|
+
refPrn: null
|
|
2133
|
+
};
|
|
2134
|
+
const amb = state.ambiguities;
|
|
2135
|
+
if (amb.length < 3) return noFix;
|
|
2136
|
+
const sats = amb.map((a) => ({
|
|
2137
|
+
prn: a.prn,
|
|
2138
|
+
aIF: a.aIF,
|
|
2139
|
+
mwCyc: a.mwCyc,
|
|
2140
|
+
f1: a.f1,
|
|
2141
|
+
f2: a.f2,
|
|
2142
|
+
wlBiasCyc: fcb.satWlFcb.get(a.prn) ?? 0,
|
|
2143
|
+
nlBiasCyc: fcb.satNlFcb.get(a.prn) ?? 0,
|
|
2144
|
+
elevDeg: a.elevDeg
|
|
2145
|
+
}));
|
|
2146
|
+
const n = sats.length;
|
|
2147
|
+
const Qaif = new Float64Array(n * n);
|
|
2148
|
+
for (let i = 0; i < n; i++)
|
|
2149
|
+
for (let j = 0; j < n; j++)
|
|
2150
|
+
Qaif[i * n + j] = state.covariance[amb[i].index][amb[j].index];
|
|
2151
|
+
const res = resolvePppAmbiguities(sats, Qaif, opts);
|
|
2152
|
+
if (!res.fixed || res.refPrn === null) {
|
|
2153
|
+
return { ...noFix, ratio: res.ratio, refPrn: res.refPrn };
|
|
2154
|
+
}
|
|
2155
|
+
const idxOfPrn = new Map(amb.map((a) => [a.prn, a.index]));
|
|
2156
|
+
const floatOfPrn = new Map(amb.map((a) => [a.prn, a.aIF]));
|
|
2157
|
+
const kept = res.sats.filter((s) => idxOfPrn.has(s.prn));
|
|
2158
|
+
const refPos = kept.findIndex((s) => s.prn === res.refPrn);
|
|
2159
|
+
if (refPos < 0 || kept.length < 2) {
|
|
2160
|
+
return { ...noFix, ratio: res.ratio, refPrn: res.refPrn };
|
|
2161
|
+
}
|
|
2162
|
+
const ambIdx = kept.map((s) => idxOfPrn.get(s.prn));
|
|
2163
|
+
const aFloat = kept.map((s) => floatOfPrn.get(s.prn));
|
|
2164
|
+
const aFixed = kept.map((s) => s.aIF);
|
|
2165
|
+
const others = kept.map((_, i) => i).filter((i) => i !== refPos);
|
|
2166
|
+
const m = others.length;
|
|
2167
|
+
const P = state.covariance;
|
|
2168
|
+
const qAA = (i, j) => P[ambIdx[i]][ambIdx[j]];
|
|
2169
|
+
const qXA = (r, i) => P[r][ambIdx[i]];
|
|
2170
|
+
const Qzz = Array.from({ length: m }, () => new Array(m).fill(0));
|
|
2171
|
+
const z = new Array(m).fill(0);
|
|
2172
|
+
for (let a = 0; a < m; a++) {
|
|
2173
|
+
const ia = others[a];
|
|
2174
|
+
z[a] = aFloat[ia] - aFloat[refPos] - (aFixed[ia] - aFixed[refPos]);
|
|
2175
|
+
for (let b = 0; b < m; b++) {
|
|
2176
|
+
const ib = others[b];
|
|
2177
|
+
Qzz[a][b] = qAA(ia, ib) - qAA(ia, refPos) - qAA(refPos, ib) + qAA(refPos, refPos);
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
const Qxz = [0, 1, 2].map(
|
|
2181
|
+
(r) => others.map((ia) => qXA(r, ia) - qXA(r, refPos))
|
|
2182
|
+
);
|
|
2183
|
+
const y = solveSpd(Qzz, z);
|
|
2184
|
+
if (!y) return { ...noFix, ratio: res.ratio, refPrn: res.refPrn };
|
|
2185
|
+
const shift = [0, 0, 0];
|
|
2186
|
+
for (let r = 0; r < 3; r++) {
|
|
2187
|
+
let s = 0;
|
|
2188
|
+
for (let a = 0; a < m; a++) s += Qxz[r][a] * y[a];
|
|
2189
|
+
shift[r] = -s;
|
|
2190
|
+
}
|
|
2191
|
+
return {
|
|
2192
|
+
fixed: true,
|
|
2193
|
+
position: [
|
|
2194
|
+
floatPos[0] + shift[0],
|
|
2195
|
+
floatPos[1] + shift[1],
|
|
2196
|
+
floatPos[2] + shift[2]
|
|
2197
|
+
],
|
|
2198
|
+
floatPosition: floatPos,
|
|
2199
|
+
shift,
|
|
2200
|
+
nFixed: m,
|
|
2201
|
+
ratio: res.ratio,
|
|
2202
|
+
refPrn: res.refPrn
|
|
2203
|
+
};
|
|
2204
|
+
}
|
|
2071
2205
|
|
|
2072
2206
|
// src/positioning/ppp-fcb.ts
|
|
2073
2207
|
function extractWidelaneArcs(station, epochs, opts = {}) {
|
|
@@ -2504,6 +2638,7 @@ export {
|
|
|
2504
2638
|
wlWavelength,
|
|
2505
2639
|
nlWavelength,
|
|
2506
2640
|
resolvePppAmbiguities,
|
|
2641
|
+
fixPppPosition,
|
|
2507
2642
|
extractWidelaneArcs,
|
|
2508
2643
|
estimateWidelaneFcb,
|
|
2509
2644
|
estimateNarrowlaneFcb,
|