gnss-js 1.16.0 → 1.18.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-R33A2VA7.js → chunk-2IM5VXNI.js} +193 -12
- package/dist/{chunk-YPOVPXNK.js → chunk-CG7SF45F.js} +75 -0
- package/dist/{chunk-6CX6EXRK.js → chunk-FEGLXNWA.js} +97 -23
- package/dist/{chunk-4LVD4DYL.js → chunk-IQ5OIMQD.js} +2 -0
- package/dist/chunk-Y5IWUPJQ.js +206 -0
- package/dist/cnav-CRns0ECn.d.cts +96 -0
- package/dist/cnav-CRns0ECn.d.ts +96 -0
- package/dist/index.cjs +577 -56
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +13 -4
- package/dist/novatel.cjs +192 -11
- package/dist/novatel.d.cts +36 -13
- package/dist/novatel.d.ts +36 -13
- package/dist/novatel.js +2 -2
- package/dist/sbf.cjs +288 -2
- package/dist/sbf.d.cts +82 -1
- package/dist/sbf.d.ts +82 -1
- package/dist/sbf.js +7 -1
- package/dist/ubx.cjs +291 -24
- package/dist/ubx.d.cts +73 -2
- package/dist/ubx.d.ts +73 -2
- package/dist/ubx.js +7 -2
- package/package.json +1 -1
package/dist/sbf.cjs
CHANGED
|
@@ -21,6 +21,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var sbf_exports = {};
|
|
22
22
|
__export(sbf_exports, {
|
|
23
23
|
parseSbfAlmanac: () => parseSbfAlmanac,
|
|
24
|
+
parseSbfCnav: () => parseSbfCnav,
|
|
25
|
+
parseSbfIonoUtc: () => parseSbfIonoUtc,
|
|
24
26
|
parseSbfMeas: () => parseSbfMeas,
|
|
25
27
|
parseSbfNav: () => parseSbfNav,
|
|
26
28
|
sbfCrc16: () => crc16,
|
|
@@ -484,9 +486,291 @@ function parseSbfAlmanac(data) {
|
|
|
484
486
|
return { almanacs, badCrc };
|
|
485
487
|
}
|
|
486
488
|
|
|
489
|
+
// src/sbf/iono.ts
|
|
490
|
+
var F4_DNU2 = -2e10;
|
|
491
|
+
function parseSbfIonoUtc(data) {
|
|
492
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
493
|
+
const ionoCorrections = {};
|
|
494
|
+
let leapSeconds = null;
|
|
495
|
+
const f4s = (b, n) => {
|
|
496
|
+
const out = [];
|
|
497
|
+
for (let k = 0; k < n; k++) {
|
|
498
|
+
const v = view.getFloat32(b + 4 * k, true);
|
|
499
|
+
if (v === F4_DNU2) return null;
|
|
500
|
+
out.push(v);
|
|
501
|
+
}
|
|
502
|
+
return out;
|
|
503
|
+
};
|
|
504
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
505
|
+
if ((id === 5893 || id === 4120) && len >= 48) {
|
|
506
|
+
const alpha = f4s(b + 16, 4);
|
|
507
|
+
const beta = f4s(b + 32, 4);
|
|
508
|
+
if (!alpha || !beta) return;
|
|
509
|
+
const sys = id === 5893 ? "GPS" : "BDS";
|
|
510
|
+
ionoCorrections[`${sys}A`] = alpha;
|
|
511
|
+
ionoCorrections[`${sys}B`] = beta;
|
|
512
|
+
} else if (id === 4030 && len >= 28) {
|
|
513
|
+
const ai = f4s(b + 16, 3);
|
|
514
|
+
if (ai) ionoCorrections["GAL"] = ai;
|
|
515
|
+
} else if (id === 5894 && len >= 37) {
|
|
516
|
+
leapSeconds = view.getInt8(b + 33);
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
return { ionoCorrections, leapSeconds };
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// src/navbits/index.ts
|
|
523
|
+
var GPS_PI = 3.1415926535898;
|
|
524
|
+
var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
|
|
525
|
+
var SEC_PER_WEEK2 = 7 * 86400;
|
|
526
|
+
function getBitU(buff, pos, len) {
|
|
527
|
+
let bits = 0;
|
|
528
|
+
for (let i = pos; i < pos + len; i++) {
|
|
529
|
+
bits = bits * 2 + (buff[i >> 3] >> 7 - (i & 7) & 1);
|
|
530
|
+
}
|
|
531
|
+
return bits;
|
|
532
|
+
}
|
|
533
|
+
function getBitS(buff, pos, len) {
|
|
534
|
+
const bits = getBitU(buff, pos, len);
|
|
535
|
+
if (len <= 0 || bits < 2 ** (len - 1)) return bits;
|
|
536
|
+
return bits - 2 ** len;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// src/navbits/cnav.ts
|
|
540
|
+
var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
|
|
541
|
+
var SEC_PER_WEEK3 = 7 * 86400;
|
|
542
|
+
var HALF_WEEK = 302400;
|
|
543
|
+
var CNAV_PREAMBLE = 139;
|
|
544
|
+
var CNAV_A_REF = 26559710;
|
|
545
|
+
var CNAV_OMEGA_DOT_REF = -26e-10;
|
|
546
|
+
function crc24q(buff, bitLen) {
|
|
547
|
+
let crc = 0;
|
|
548
|
+
for (let i = 0; i < bitLen; i++) {
|
|
549
|
+
crc ^= (buff[i >> 3] >> 7 - (i & 7) & 1) << 23;
|
|
550
|
+
const msb = crc & 8388608;
|
|
551
|
+
crc = crc << 1 & 16777215;
|
|
552
|
+
if (msb) crc ^= 8801531;
|
|
553
|
+
}
|
|
554
|
+
return crc;
|
|
555
|
+
}
|
|
556
|
+
function cnavCrcOk(msg) {
|
|
557
|
+
if (msg.length < 38) return false;
|
|
558
|
+
return crc24q(msg, 276) === getBitU(msg, 276, 24);
|
|
559
|
+
}
|
|
560
|
+
function getBitU33(b, pos) {
|
|
561
|
+
return getBitU(b, pos, 1) * 2 ** 32 + getBitU(b, pos + 1, 32);
|
|
562
|
+
}
|
|
563
|
+
function getBitS33(b, pos) {
|
|
564
|
+
const u = getBitU33(b, pos);
|
|
565
|
+
return u < 2 ** 32 ? u : u - 2 ** 33;
|
|
566
|
+
}
|
|
567
|
+
function decodeType10(b, tow) {
|
|
568
|
+
return {
|
|
569
|
+
tow,
|
|
570
|
+
week: getBitU(b, 38, 13),
|
|
571
|
+
health: getBitU(b, 51, 3),
|
|
572
|
+
top: getBitU(b, 54, 11) * 300,
|
|
573
|
+
uraEd: getBitS(b, 65, 5),
|
|
574
|
+
toe: getBitU(b, 70, 11) * 300,
|
|
575
|
+
deltaA: getBitS(b, 81, 26) * 2 ** -9,
|
|
576
|
+
aDot: getBitS(b, 107, 25) * 2 ** -21,
|
|
577
|
+
deltaN0: getBitS(b, 132, 17) * 2 ** -44 * GPS_PI,
|
|
578
|
+
deltaN0Dot: getBitS(b, 149, 23) * 2 ** -57 * GPS_PI,
|
|
579
|
+
m0: getBitS33(b, 172) * 2 ** -32 * GPS_PI,
|
|
580
|
+
e: getBitU33(b, 205) * 2 ** -34,
|
|
581
|
+
omega: getBitS33(b, 238) * 2 ** -32 * GPS_PI,
|
|
582
|
+
integrityFlag: getBitU(b, 271, 1) === 1,
|
|
583
|
+
l2cPhasing: getBitU(b, 272, 1) === 1
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
function decodeType11(b) {
|
|
587
|
+
return {
|
|
588
|
+
toe: getBitU(b, 38, 11) * 300,
|
|
589
|
+
omega0: getBitS33(b, 49) * 2 ** -32 * GPS_PI,
|
|
590
|
+
i0: getBitS33(b, 82) * 2 ** -32 * GPS_PI,
|
|
591
|
+
deltaOmegaDot: getBitS(b, 115, 17) * 2 ** -44 * GPS_PI,
|
|
592
|
+
i0Dot: getBitS(b, 132, 15) * 2 ** -44 * GPS_PI,
|
|
593
|
+
cis: getBitS(b, 147, 16) * 2 ** -30,
|
|
594
|
+
cic: getBitS(b, 163, 16) * 2 ** -30,
|
|
595
|
+
crs: getBitS(b, 179, 24) * 2 ** -8,
|
|
596
|
+
crc: getBitS(b, 203, 24) * 2 ** -8,
|
|
597
|
+
cus: getBitS(b, 227, 21) * 2 ** -30,
|
|
598
|
+
cuc: getBitS(b, 248, 21) * 2 ** -30
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
var isc = (b, pos) => {
|
|
602
|
+
const raw = getBitS(b, pos, 13);
|
|
603
|
+
return raw === -4096 ? null : raw * 2 ** -35;
|
|
604
|
+
};
|
|
605
|
+
function decodeClock(b, msgType) {
|
|
606
|
+
const clock = {
|
|
607
|
+
msgType,
|
|
608
|
+
top: getBitU(b, 38, 11) * 300,
|
|
609
|
+
uraNed0: getBitS(b, 49, 5),
|
|
610
|
+
uraNed1: getBitU(b, 54, 3),
|
|
611
|
+
uraNed2: getBitU(b, 57, 3),
|
|
612
|
+
toc: getBitU(b, 60, 11) * 300,
|
|
613
|
+
af0: getBitS(b, 71, 26) * 2 ** -35,
|
|
614
|
+
af1: getBitS(b, 97, 20) * 2 ** -48,
|
|
615
|
+
af2: getBitS(b, 117, 10) * 2 ** -60
|
|
616
|
+
};
|
|
617
|
+
if (msgType === 30) {
|
|
618
|
+
clock.tgd = isc(b, 127);
|
|
619
|
+
clock.iscL1ca = isc(b, 140);
|
|
620
|
+
clock.iscL2c = isc(b, 153);
|
|
621
|
+
clock.iscL5i5 = isc(b, 166);
|
|
622
|
+
clock.iscL5q5 = isc(b, 179);
|
|
623
|
+
clock.ionoAlpha = [
|
|
624
|
+
getBitS(b, 192, 8) * 2 ** -30,
|
|
625
|
+
getBitS(b, 200, 8) * 2 ** -27,
|
|
626
|
+
getBitS(b, 208, 8) * 2 ** -24,
|
|
627
|
+
getBitS(b, 216, 8) * 2 ** -24
|
|
628
|
+
];
|
|
629
|
+
clock.ionoBeta = [
|
|
630
|
+
getBitS(b, 224, 8) * 2 ** 11,
|
|
631
|
+
getBitS(b, 232, 8) * 2 ** 14,
|
|
632
|
+
getBitS(b, 240, 8) * 2 ** 16,
|
|
633
|
+
getBitS(b, 248, 8) * 2 ** 16
|
|
634
|
+
];
|
|
635
|
+
clock.wnOp = getBitU(b, 256, 8);
|
|
636
|
+
}
|
|
637
|
+
return clock;
|
|
638
|
+
}
|
|
639
|
+
function resolveWeek(week, towSec, sec) {
|
|
640
|
+
if (sec < towSec - HALF_WEEK) return week + 1;
|
|
641
|
+
if (sec > towSec + HALF_WEEK) return week - 1;
|
|
642
|
+
return week;
|
|
643
|
+
}
|
|
644
|
+
function gpsDate(week, sec) {
|
|
645
|
+
return new Date(GPS_EPOCH_MS3 + (week * SEC_PER_WEEK3 + sec) * 1e3);
|
|
646
|
+
}
|
|
647
|
+
var CnavAssembler = class {
|
|
648
|
+
sats = /* @__PURE__ */ new Map();
|
|
649
|
+
/**
|
|
650
|
+
* Push one 300-bit CNAV message (38+ bytes, bit 0 = first bit of
|
|
651
|
+
* the preamble). Returns the newly completed ephemeris, or null.
|
|
652
|
+
* Messages that are not MT10/MT11/MT30-37, or whose preamble/PRN
|
|
653
|
+
* are out of range, are ignored.
|
|
654
|
+
*/
|
|
655
|
+
push(msg) {
|
|
656
|
+
if (msg.length < 38 || getBitU(msg, 0, 8) !== CNAV_PREAMBLE) return null;
|
|
657
|
+
const prn = getBitU(msg, 8, 6);
|
|
658
|
+
if (prn < 1 || prn > 32) return null;
|
|
659
|
+
const type = getBitU(msg, 14, 6);
|
|
660
|
+
const tow = getBitU(msg, 20, 17) * 6;
|
|
661
|
+
let sat = this.sats.get(prn);
|
|
662
|
+
if (!sat) {
|
|
663
|
+
sat = {};
|
|
664
|
+
this.sats.set(prn, sat);
|
|
665
|
+
}
|
|
666
|
+
if (type === 10) sat.t10 = decodeType10(msg, tow);
|
|
667
|
+
else if (type === 11) sat.t11 = decodeType11(msg);
|
|
668
|
+
else if (type >= 30 && type <= 37) {
|
|
669
|
+
sat.clock = decodeClock(msg, type);
|
|
670
|
+
if (type === 30) sat.extras = sat.clock;
|
|
671
|
+
} else return null;
|
|
672
|
+
return this.tryEmit(prn, sat);
|
|
673
|
+
}
|
|
674
|
+
tryEmit(prn, sat) {
|
|
675
|
+
const { t10, t11, clock, extras } = sat;
|
|
676
|
+
if (!t10 || !t11 || !clock) return null;
|
|
677
|
+
if (t10.toe !== t11.toe || clock.toc !== t10.toe) return null;
|
|
678
|
+
const key = `${t10.week}:${t10.toe}:${clock.af0}:${clock.af1}`;
|
|
679
|
+
if (key === sat.lastKey) return null;
|
|
680
|
+
sat.lastKey = key;
|
|
681
|
+
const weekToe = resolveWeek(t10.week, t10.tow, t10.toe);
|
|
682
|
+
const a = CNAV_A_REF + t10.deltaA;
|
|
683
|
+
return {
|
|
684
|
+
system: "G",
|
|
685
|
+
prn: `G${String(prn).padStart(2, "0")}`,
|
|
686
|
+
week: t10.week,
|
|
687
|
+
health: t10.health,
|
|
688
|
+
uraEd: t10.uraEd,
|
|
689
|
+
uraNed0: clock.uraNed0,
|
|
690
|
+
uraNed1: clock.uraNed1,
|
|
691
|
+
uraNed2: clock.uraNed2,
|
|
692
|
+
top: t10.top,
|
|
693
|
+
toe: t10.toe,
|
|
694
|
+
toeDate: gpsDate(weekToe, t10.toe),
|
|
695
|
+
a,
|
|
696
|
+
deltaA: t10.deltaA,
|
|
697
|
+
aDot: t10.aDot,
|
|
698
|
+
deltaN0: t10.deltaN0,
|
|
699
|
+
deltaN0Dot: t10.deltaN0Dot,
|
|
700
|
+
m0: t10.m0,
|
|
701
|
+
e: t10.e,
|
|
702
|
+
omega: t10.omega,
|
|
703
|
+
omega0: t11.omega0,
|
|
704
|
+
i0: t11.i0,
|
|
705
|
+
omegaDot: CNAV_OMEGA_DOT_REF * GPS_PI + t11.deltaOmegaDot,
|
|
706
|
+
deltaOmegaDot: t11.deltaOmegaDot,
|
|
707
|
+
i0Dot: t11.i0Dot,
|
|
708
|
+
cis: t11.cis,
|
|
709
|
+
cic: t11.cic,
|
|
710
|
+
crs: t11.crs,
|
|
711
|
+
crc: t11.crc,
|
|
712
|
+
cus: t11.cus,
|
|
713
|
+
cuc: t11.cuc,
|
|
714
|
+
toc: clock.toc,
|
|
715
|
+
tocDate: gpsDate(weekToe, clock.toc),
|
|
716
|
+
af0: clock.af0,
|
|
717
|
+
af1: clock.af1,
|
|
718
|
+
af2: clock.af2,
|
|
719
|
+
clockMsgType: clock.msgType,
|
|
720
|
+
tgd: extras?.tgd ?? null,
|
|
721
|
+
iscL1ca: extras?.iscL1ca ?? null,
|
|
722
|
+
iscL2c: extras?.iscL2c ?? null,
|
|
723
|
+
iscL5i5: extras?.iscL5i5 ?? null,
|
|
724
|
+
iscL5q5: extras?.iscL5q5 ?? null,
|
|
725
|
+
...extras?.ionoAlpha && { ionoAlpha: extras.ionoAlpha },
|
|
726
|
+
...extras?.ionoBeta && { ionoBeta: extras.ionoBeta },
|
|
727
|
+
...extras?.wnOp !== void 0 && { wnOp: extras.wnOp },
|
|
728
|
+
integrityFlag: t10.integrityFlag,
|
|
729
|
+
l2cPhasing: t10.l2cPhasing,
|
|
730
|
+
tow: t10.tow
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
// src/sbf/rawnav.ts
|
|
736
|
+
var SIGNAL_OF_BLOCK = {
|
|
737
|
+
4018: "L2C",
|
|
738
|
+
4019: "L5"
|
|
739
|
+
};
|
|
740
|
+
function parseSbfCnav(data) {
|
|
741
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
742
|
+
const ephemerides = [];
|
|
743
|
+
const assemblers = {
|
|
744
|
+
L2C: new CnavAssembler(),
|
|
745
|
+
L5: new CnavAssembler()
|
|
746
|
+
};
|
|
747
|
+
let badCrc = 0;
|
|
748
|
+
let messages = 0;
|
|
749
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
750
|
+
const signal = SIGNAL_OF_BLOCK[id];
|
|
751
|
+
if (!signal || len < 60) return;
|
|
752
|
+
messages++;
|
|
753
|
+
const msg = new Uint8Array(40);
|
|
754
|
+
for (let k = 0; k < 10; k++) {
|
|
755
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
756
|
+
msg[4 * k] = w >>> 24;
|
|
757
|
+
msg[4 * k + 1] = w >>> 16 & 255;
|
|
758
|
+
msg[4 * k + 2] = w >>> 8 & 255;
|
|
759
|
+
msg[4 * k + 3] = w & 255;
|
|
760
|
+
}
|
|
761
|
+
if (!cnavCrcOk(msg)) {
|
|
762
|
+
badCrc++;
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
const eph = assemblers[signal].push(msg);
|
|
766
|
+
if (eph) ephemerides.push({ ...eph, signal });
|
|
767
|
+
});
|
|
768
|
+
return { ephemerides, badCrc, messages };
|
|
769
|
+
}
|
|
770
|
+
|
|
487
771
|
// src/sbf/index.ts
|
|
488
772
|
var CLIGHT = 299792458;
|
|
489
|
-
var
|
|
773
|
+
var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
|
|
490
774
|
var MS_PER_WEEK2 = 7 * 864e5;
|
|
491
775
|
var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
|
|
492
776
|
var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
|
|
@@ -1140,7 +1424,7 @@ function parseSbfMeas(data) {
|
|
|
1140
1424
|
const tow = view.getUint32(i + 8, true);
|
|
1141
1425
|
const wnc = view.getUint16(i + 12, true);
|
|
1142
1426
|
if (tow !== 4294967295 && wnc !== 65535) {
|
|
1143
|
-
ensureEpoch(
|
|
1427
|
+
ensureEpoch(GPS_EPOCH_MS4 + wnc * MS_PER_WEEK2 + tow);
|
|
1144
1428
|
if (id === 4109) decodeMeas3Ranges(i, tow);
|
|
1145
1429
|
else if (id === 4110) decodeMeas3CN0(i, len);
|
|
1146
1430
|
else if (id === 4111) decodeMeas3Doppler(i, len);
|
|
@@ -1154,6 +1438,8 @@ function parseSbfMeas(data) {
|
|
|
1154
1438
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1155
1439
|
0 && (module.exports = {
|
|
1156
1440
|
parseSbfAlmanac,
|
|
1441
|
+
parseSbfCnav,
|
|
1442
|
+
parseSbfIonoUtc,
|
|
1157
1443
|
parseSbfMeas,
|
|
1158
1444
|
parseSbfNav,
|
|
1159
1445
|
sbfCrc16,
|
package/dist/sbf.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { E as Ephemeris } from './nav-BAI1a9vK.cjs';
|
|
2
|
+
import { C as CnavEphemeris } from './cnav-CRns0ECn.cjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Septentrio SBF framing shared by the measurement and navigation
|
|
@@ -151,6 +152,86 @@ interface SbfAlmanacResult {
|
|
|
151
152
|
*/
|
|
152
153
|
declare function parseSbfAlmanac(data: Uint8Array): SbfAlmanacResult;
|
|
153
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Septentrio SBF decoded ionosphere / UTC blocks.
|
|
157
|
+
*
|
|
158
|
+
* GPSIon (5893) and BDSIon (4120) carry the eight Klobuchar vertical
|
|
159
|
+
* delay coefficients, GALIon (4030) the three NeQuick-G effective
|
|
160
|
+
* ionisation level coefficients, and GPSUtc (5894) the GPS-UTC
|
|
161
|
+
* parameters from LNAV subframe 4 page 18 (only ΔtLS, the current
|
|
162
|
+
* leap-second count, is extracted here).
|
|
163
|
+
*
|
|
164
|
+
* Units: SBF stores the coefficients as f4 floats already in the
|
|
165
|
+
* semicircle-based SI units of the broadcast messages — alpha_n in
|
|
166
|
+
* s/semicircle^n, beta_n in s/semicircle^n, ai_n in sfu/deg^n — which
|
|
167
|
+
* are exactly the units a RINEX nav header prints. Values are passed
|
|
168
|
+
* through unscaled, so the output matches what `parseNavFile` reads
|
|
169
|
+
* from a converted nav header to float32 precision.
|
|
170
|
+
*
|
|
171
|
+
* Ported from RTKLIB demo5 (rtklibexplorer), src/rcv/septentrio.c
|
|
172
|
+
* (decode_gpsion / decode_galion / decode_cmpion / decode_gpsutc),
|
|
173
|
+
* BSD-2-Clause, and cross-checked against the Septentrio mosaic-X5
|
|
174
|
+
* reference guide (which documents all four block layouts, including
|
|
175
|
+
* the do-not-use markers RTKLIB does not check).
|
|
176
|
+
*/
|
|
177
|
+
interface SbfIonoUtcResult {
|
|
178
|
+
/**
|
|
179
|
+
* Iono coefficient sets keyed like `NavHeader.ionoCorrections`:
|
|
180
|
+
* `GPSA`/`GPSB` (Klobuchar alpha/beta), `GAL` ([ai0, ai1, ai2],
|
|
181
|
+
* RINEX GAL header convention), `BDSA`/`BDSB`. The blocks repeat;
|
|
182
|
+
* the last valid block of each type in the stream wins.
|
|
183
|
+
*/
|
|
184
|
+
ionoCorrections: Record<string, number[]>;
|
|
185
|
+
/** GPS-UTC ΔtLS from the last GPSUtc block, if any. */
|
|
186
|
+
leapSeconds: number | null;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Decode every GPSIon/GALIon/BDSIon/GPSUtc block in an SBF byte
|
|
190
|
+
* stream. Blocks with do-not-use coefficients are skipped; other block
|
|
191
|
+
* types are skipped silently.
|
|
192
|
+
*/
|
|
193
|
+
declare function parseSbfIonoUtc(data: Uint8Array): SbfIonoUtcResult;
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Septentrio SBF raw CNAV navigation-bit blocks: GPSRawL2C (4018) and
|
|
197
|
+
* GPSRawL5 (4019) each carry one 300-bit GPS CNAV message.
|
|
198
|
+
*
|
|
199
|
+
* Block layout (mosaic-X5 reference guide §4): after the 8-byte SBF
|
|
200
|
+
* header, TOW u4 + WNc u2, SVID u1, CRCPassed u1, ViterbiCnt u1,
|
|
201
|
+
* Source u1, FreqNr u1, RxChannel u1, then NAVBits as u4[10] — the
|
|
202
|
+
* first received bit is the MSB of NAVBits[0] (each u4 little-endian
|
|
203
|
+
* in the stream, message bits MSB-first within the word), the unused
|
|
204
|
+
* 20 bits of NAVBits[9] to be ignored. RTKLIB demo5's
|
|
205
|
+
* decode_gpsrawcnav (src/rcv/septentrio.c) reads the same header but
|
|
206
|
+
* leaves the message body undecoded (a TODO stub); the field decoding
|
|
207
|
+
* here is `src/navbits/cnav.ts` working from IS-GPS-200 directly.
|
|
208
|
+
*
|
|
209
|
+
* The receiver's own CRCPassed flag is ignored in favor of re-running
|
|
210
|
+
* CRC-24Q on the transported bits, so `badCrc` counts exactly the
|
|
211
|
+
* messages this library rejected.
|
|
212
|
+
*/
|
|
213
|
+
|
|
214
|
+
/** A CNAV ephemeris tagged with the SBF block (signal) it came from. */
|
|
215
|
+
interface SbfCnavEphemeris extends CnavEphemeris {
|
|
216
|
+
signal: 'L2C' | 'L5';
|
|
217
|
+
}
|
|
218
|
+
interface SbfCnavResult {
|
|
219
|
+
/** Assembled CNAV ephemerides in stream order, repeats suppressed. */
|
|
220
|
+
ephemerides: SbfCnavEphemeris[];
|
|
221
|
+
/** Raw messages whose CRC-24Q check failed (dropped). */
|
|
222
|
+
badCrc: number;
|
|
223
|
+
/** Total GPSRawL2C/GPSRawL5 blocks seen (with valid SBF framing). */
|
|
224
|
+
messages: number;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Decode every GPSRawL2C/GPSRawL5 block in an SBF byte stream and
|
|
228
|
+
* assemble the carried CNAV messages into ephemerides. L2C and L5 are
|
|
229
|
+
* assembled independently (one `CnavAssembler` per signal), so a data
|
|
230
|
+
* set complete on both signals yields one record per signal; each
|
|
231
|
+
* record's `signal` property names its source.
|
|
232
|
+
*/
|
|
233
|
+
declare function parseSbfCnav(data: Uint8Array): SbfCnavResult;
|
|
234
|
+
|
|
154
235
|
/**
|
|
155
236
|
* Septentrio SBF raw-measurement decoding (MeasEpoch + Meas3) — the
|
|
156
237
|
* path from a receiver log to RINEX-grade observables.
|
|
@@ -214,4 +295,4 @@ interface SbfParseResult {
|
|
|
214
295
|
*/
|
|
215
296
|
declare function parseSbfMeas(data: Uint8Array): SbfParseResult;
|
|
216
297
|
|
|
217
|
-
export { type SbfAlmanac, type SbfAlmanacResult, type SbfGlonassAlmanac, type SbfKeplerAlmanac, type SbfMeasEpoch, type SbfMeasurement, type SbfNavResult, type SbfParseResult, parseSbfAlmanac, parseSbfMeas, parseSbfNav, crc16 as sbfCrc16, scanSbfFrames };
|
|
298
|
+
export { CnavEphemeris, type SbfAlmanac, type SbfAlmanacResult, type SbfCnavEphemeris, type SbfCnavResult, type SbfGlonassAlmanac, type SbfIonoUtcResult, type SbfKeplerAlmanac, type SbfMeasEpoch, type SbfMeasurement, type SbfNavResult, type SbfParseResult, parseSbfAlmanac, parseSbfCnav, parseSbfIonoUtc, parseSbfMeas, parseSbfNav, crc16 as sbfCrc16, scanSbfFrames };
|
package/dist/sbf.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { E as Ephemeris } from './nav-BAI1a9vK.js';
|
|
2
|
+
import { C as CnavEphemeris } from './cnav-CRns0ECn.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Septentrio SBF framing shared by the measurement and navigation
|
|
@@ -151,6 +152,86 @@ interface SbfAlmanacResult {
|
|
|
151
152
|
*/
|
|
152
153
|
declare function parseSbfAlmanac(data: Uint8Array): SbfAlmanacResult;
|
|
153
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Septentrio SBF decoded ionosphere / UTC blocks.
|
|
157
|
+
*
|
|
158
|
+
* GPSIon (5893) and BDSIon (4120) carry the eight Klobuchar vertical
|
|
159
|
+
* delay coefficients, GALIon (4030) the three NeQuick-G effective
|
|
160
|
+
* ionisation level coefficients, and GPSUtc (5894) the GPS-UTC
|
|
161
|
+
* parameters from LNAV subframe 4 page 18 (only ΔtLS, the current
|
|
162
|
+
* leap-second count, is extracted here).
|
|
163
|
+
*
|
|
164
|
+
* Units: SBF stores the coefficients as f4 floats already in the
|
|
165
|
+
* semicircle-based SI units of the broadcast messages — alpha_n in
|
|
166
|
+
* s/semicircle^n, beta_n in s/semicircle^n, ai_n in sfu/deg^n — which
|
|
167
|
+
* are exactly the units a RINEX nav header prints. Values are passed
|
|
168
|
+
* through unscaled, so the output matches what `parseNavFile` reads
|
|
169
|
+
* from a converted nav header to float32 precision.
|
|
170
|
+
*
|
|
171
|
+
* Ported from RTKLIB demo5 (rtklibexplorer), src/rcv/septentrio.c
|
|
172
|
+
* (decode_gpsion / decode_galion / decode_cmpion / decode_gpsutc),
|
|
173
|
+
* BSD-2-Clause, and cross-checked against the Septentrio mosaic-X5
|
|
174
|
+
* reference guide (which documents all four block layouts, including
|
|
175
|
+
* the do-not-use markers RTKLIB does not check).
|
|
176
|
+
*/
|
|
177
|
+
interface SbfIonoUtcResult {
|
|
178
|
+
/**
|
|
179
|
+
* Iono coefficient sets keyed like `NavHeader.ionoCorrections`:
|
|
180
|
+
* `GPSA`/`GPSB` (Klobuchar alpha/beta), `GAL` ([ai0, ai1, ai2],
|
|
181
|
+
* RINEX GAL header convention), `BDSA`/`BDSB`. The blocks repeat;
|
|
182
|
+
* the last valid block of each type in the stream wins.
|
|
183
|
+
*/
|
|
184
|
+
ionoCorrections: Record<string, number[]>;
|
|
185
|
+
/** GPS-UTC ΔtLS from the last GPSUtc block, if any. */
|
|
186
|
+
leapSeconds: number | null;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Decode every GPSIon/GALIon/BDSIon/GPSUtc block in an SBF byte
|
|
190
|
+
* stream. Blocks with do-not-use coefficients are skipped; other block
|
|
191
|
+
* types are skipped silently.
|
|
192
|
+
*/
|
|
193
|
+
declare function parseSbfIonoUtc(data: Uint8Array): SbfIonoUtcResult;
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Septentrio SBF raw CNAV navigation-bit blocks: GPSRawL2C (4018) and
|
|
197
|
+
* GPSRawL5 (4019) each carry one 300-bit GPS CNAV message.
|
|
198
|
+
*
|
|
199
|
+
* Block layout (mosaic-X5 reference guide §4): after the 8-byte SBF
|
|
200
|
+
* header, TOW u4 + WNc u2, SVID u1, CRCPassed u1, ViterbiCnt u1,
|
|
201
|
+
* Source u1, FreqNr u1, RxChannel u1, then NAVBits as u4[10] — the
|
|
202
|
+
* first received bit is the MSB of NAVBits[0] (each u4 little-endian
|
|
203
|
+
* in the stream, message bits MSB-first within the word), the unused
|
|
204
|
+
* 20 bits of NAVBits[9] to be ignored. RTKLIB demo5's
|
|
205
|
+
* decode_gpsrawcnav (src/rcv/septentrio.c) reads the same header but
|
|
206
|
+
* leaves the message body undecoded (a TODO stub); the field decoding
|
|
207
|
+
* here is `src/navbits/cnav.ts` working from IS-GPS-200 directly.
|
|
208
|
+
*
|
|
209
|
+
* The receiver's own CRCPassed flag is ignored in favor of re-running
|
|
210
|
+
* CRC-24Q on the transported bits, so `badCrc` counts exactly the
|
|
211
|
+
* messages this library rejected.
|
|
212
|
+
*/
|
|
213
|
+
|
|
214
|
+
/** A CNAV ephemeris tagged with the SBF block (signal) it came from. */
|
|
215
|
+
interface SbfCnavEphemeris extends CnavEphemeris {
|
|
216
|
+
signal: 'L2C' | 'L5';
|
|
217
|
+
}
|
|
218
|
+
interface SbfCnavResult {
|
|
219
|
+
/** Assembled CNAV ephemerides in stream order, repeats suppressed. */
|
|
220
|
+
ephemerides: SbfCnavEphemeris[];
|
|
221
|
+
/** Raw messages whose CRC-24Q check failed (dropped). */
|
|
222
|
+
badCrc: number;
|
|
223
|
+
/** Total GPSRawL2C/GPSRawL5 blocks seen (with valid SBF framing). */
|
|
224
|
+
messages: number;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Decode every GPSRawL2C/GPSRawL5 block in an SBF byte stream and
|
|
228
|
+
* assemble the carried CNAV messages into ephemerides. L2C and L5 are
|
|
229
|
+
* assembled independently (one `CnavAssembler` per signal), so a data
|
|
230
|
+
* set complete on both signals yields one record per signal; each
|
|
231
|
+
* record's `signal` property names its source.
|
|
232
|
+
*/
|
|
233
|
+
declare function parseSbfCnav(data: Uint8Array): SbfCnavResult;
|
|
234
|
+
|
|
154
235
|
/**
|
|
155
236
|
* Septentrio SBF raw-measurement decoding (MeasEpoch + Meas3) — the
|
|
156
237
|
* path from a receiver log to RINEX-grade observables.
|
|
@@ -214,4 +295,4 @@ interface SbfParseResult {
|
|
|
214
295
|
*/
|
|
215
296
|
declare function parseSbfMeas(data: Uint8Array): SbfParseResult;
|
|
216
297
|
|
|
217
|
-
export { type SbfAlmanac, type SbfAlmanacResult, type SbfGlonassAlmanac, type SbfKeplerAlmanac, type SbfMeasEpoch, type SbfMeasurement, type SbfNavResult, type SbfParseResult, parseSbfAlmanac, parseSbfMeas, parseSbfNav, crc16 as sbfCrc16, scanSbfFrames };
|
|
298
|
+
export { CnavEphemeris, type SbfAlmanac, type SbfAlmanacResult, type SbfCnavEphemeris, type SbfCnavResult, type SbfGlonassAlmanac, type SbfIonoUtcResult, type SbfKeplerAlmanac, type SbfMeasEpoch, type SbfMeasurement, type SbfNavResult, type SbfParseResult, parseSbfAlmanac, parseSbfCnav, parseSbfIonoUtc, parseSbfMeas, parseSbfNav, crc16 as sbfCrc16, scanSbfFrames };
|
package/dist/sbf.js
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
crc16,
|
|
3
3
|
parseSbfAlmanac,
|
|
4
|
+
parseSbfCnav,
|
|
5
|
+
parseSbfIonoUtc,
|
|
4
6
|
parseSbfMeas,
|
|
5
7
|
parseSbfNav,
|
|
6
8
|
scanSbfFrames
|
|
7
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-CG7SF45F.js";
|
|
10
|
+
import "./chunk-Y5IWUPJQ.js";
|
|
11
|
+
import "./chunk-IQ5OIMQD.js";
|
|
8
12
|
import "./chunk-HVXYFUCB.js";
|
|
9
13
|
import "./chunk-LEEU5OIO.js";
|
|
10
14
|
export {
|
|
11
15
|
parseSbfAlmanac,
|
|
16
|
+
parseSbfCnav,
|
|
17
|
+
parseSbfIonoUtc,
|
|
12
18
|
parseSbfMeas,
|
|
13
19
|
parseSbfNav,
|
|
14
20
|
crc16 as sbfCrc16,
|