gnss-js 1.17.0 → 1.19.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-7QR2KPDU.js → chunk-2IM5VXNI.js} +11 -6
- package/dist/{chunk-ZNCQNHNI.js → chunk-5S5HMAKW.js} +41 -0
- package/dist/chunk-6NCMACDO.js +208 -0
- package/dist/{chunk-REYOYF7O.js → chunk-IQ5OIMQD.js} +1 -0
- package/dist/{chunk-IG5CDNDS.js → chunk-JW2ICDR7.js} +40 -1
- package/dist/{chunk-HXF7XVW7.js → chunk-K73SERD5.js} +299 -11
- package/dist/index.cjs +746 -189
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +14 -5
- package/dist/nav-DImXUdbp.d.cts +223 -0
- package/dist/nav-DImXUdbp.d.ts +223 -0
- package/dist/novatel.cjs +10 -5
- package/dist/novatel.d.cts +1 -1
- package/dist/novatel.d.ts +1 -1
- package/dist/novatel.js +2 -2
- package/dist/orbit.d.cts +1 -1
- package/dist/orbit.d.ts +1 -1
- package/dist/positioning.d.cts +1 -1
- package/dist/positioning.d.ts +1 -1
- package/dist/rinex.cjs +304 -11
- package/dist/rinex.d.cts +45 -3
- package/dist/rinex.d.ts +45 -3
- package/dist/rinex.js +7 -1
- package/dist/sbf.cjs +253 -2
- package/dist/sbf.d.cts +42 -2
- package/dist/sbf.d.ts +42 -2
- package/dist/sbf.js +5 -1
- package/dist/ubx.cjs +234 -2
- package/dist/ubx.d.cts +32 -2
- package/dist/ubx.d.ts +32 -2
- package/dist/ubx.js +5 -2
- package/package.json +1 -1
- package/dist/nav-BAI1a9vK.d.cts +0 -108
- package/dist/nav-BAI1a9vK.d.ts +0 -108
package/dist/sbf.cjs
CHANGED
|
@@ -21,6 +21,7 @@ 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,
|
|
24
25
|
parseSbfIonoUtc: () => parseSbfIonoUtc,
|
|
25
26
|
parseSbfMeas: () => parseSbfMeas,
|
|
26
27
|
parseSbfNav: () => parseSbfNav,
|
|
@@ -518,9 +519,258 @@ function parseSbfIonoUtc(data) {
|
|
|
518
519
|
return { ionoCorrections, leapSeconds };
|
|
519
520
|
}
|
|
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
|
+
|
|
521
771
|
// src/sbf/index.ts
|
|
522
772
|
var CLIGHT = 299792458;
|
|
523
|
-
var
|
|
773
|
+
var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
|
|
524
774
|
var MS_PER_WEEK2 = 7 * 864e5;
|
|
525
775
|
var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
|
|
526
776
|
var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
|
|
@@ -1174,7 +1424,7 @@ function parseSbfMeas(data) {
|
|
|
1174
1424
|
const tow = view.getUint32(i + 8, true);
|
|
1175
1425
|
const wnc = view.getUint16(i + 12, true);
|
|
1176
1426
|
if (tow !== 4294967295 && wnc !== 65535) {
|
|
1177
|
-
ensureEpoch(
|
|
1427
|
+
ensureEpoch(GPS_EPOCH_MS4 + wnc * MS_PER_WEEK2 + tow);
|
|
1178
1428
|
if (id === 4109) decodeMeas3Ranges(i, tow);
|
|
1179
1429
|
else if (id === 4110) decodeMeas3CN0(i, len);
|
|
1180
1430
|
else if (id === 4111) decodeMeas3Doppler(i, len);
|
|
@@ -1188,6 +1438,7 @@ function parseSbfMeas(data) {
|
|
|
1188
1438
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1189
1439
|
0 && (module.exports = {
|
|
1190
1440
|
parseSbfAlmanac,
|
|
1441
|
+
parseSbfCnav,
|
|
1191
1442
|
parseSbfIonoUtc,
|
|
1192
1443
|
parseSbfMeas,
|
|
1193
1444
|
parseSbfNav,
|
package/dist/sbf.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { E as Ephemeris } from './nav-
|
|
1
|
+
import { E as Ephemeris, C as CnavEphemeris } from './nav-DImXUdbp.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Septentrio SBF framing shared by the measurement and navigation
|
|
@@ -191,6 +191,46 @@ interface SbfIonoUtcResult {
|
|
|
191
191
|
*/
|
|
192
192
|
declare function parseSbfIonoUtc(data: Uint8Array): SbfIonoUtcResult;
|
|
193
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Septentrio SBF raw CNAV navigation-bit blocks: GPSRawL2C (4018) and
|
|
196
|
+
* GPSRawL5 (4019) each carry one 300-bit GPS CNAV message.
|
|
197
|
+
*
|
|
198
|
+
* Block layout (mosaic-X5 reference guide §4): after the 8-byte SBF
|
|
199
|
+
* header, TOW u4 + WNc u2, SVID u1, CRCPassed u1, ViterbiCnt u1,
|
|
200
|
+
* Source u1, FreqNr u1, RxChannel u1, then NAVBits as u4[10] — the
|
|
201
|
+
* first received bit is the MSB of NAVBits[0] (each u4 little-endian
|
|
202
|
+
* in the stream, message bits MSB-first within the word), the unused
|
|
203
|
+
* 20 bits of NAVBits[9] to be ignored. RTKLIB demo5's
|
|
204
|
+
* decode_gpsrawcnav (src/rcv/septentrio.c) reads the same header but
|
|
205
|
+
* leaves the message body undecoded (a TODO stub); the field decoding
|
|
206
|
+
* here is `src/navbits/cnav.ts` working from IS-GPS-200 directly.
|
|
207
|
+
*
|
|
208
|
+
* The receiver's own CRCPassed flag is ignored in favor of re-running
|
|
209
|
+
* CRC-24Q on the transported bits, so `badCrc` counts exactly the
|
|
210
|
+
* messages this library rejected.
|
|
211
|
+
*/
|
|
212
|
+
|
|
213
|
+
/** A CNAV ephemeris tagged with the SBF block (signal) it came from. */
|
|
214
|
+
interface SbfCnavEphemeris extends CnavEphemeris {
|
|
215
|
+
signal: 'L2C' | 'L5';
|
|
216
|
+
}
|
|
217
|
+
interface SbfCnavResult {
|
|
218
|
+
/** Assembled CNAV ephemerides in stream order, repeats suppressed. */
|
|
219
|
+
ephemerides: SbfCnavEphemeris[];
|
|
220
|
+
/** Raw messages whose CRC-24Q check failed (dropped). */
|
|
221
|
+
badCrc: number;
|
|
222
|
+
/** Total GPSRawL2C/GPSRawL5 blocks seen (with valid SBF framing). */
|
|
223
|
+
messages: number;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Decode every GPSRawL2C/GPSRawL5 block in an SBF byte stream and
|
|
227
|
+
* assemble the carried CNAV messages into ephemerides. L2C and L5 are
|
|
228
|
+
* assembled independently (one `CnavAssembler` per signal), so a data
|
|
229
|
+
* set complete on both signals yields one record per signal; each
|
|
230
|
+
* record's `signal` property names its source.
|
|
231
|
+
*/
|
|
232
|
+
declare function parseSbfCnav(data: Uint8Array): SbfCnavResult;
|
|
233
|
+
|
|
194
234
|
/**
|
|
195
235
|
* Septentrio SBF raw-measurement decoding (MeasEpoch + Meas3) — the
|
|
196
236
|
* path from a receiver log to RINEX-grade observables.
|
|
@@ -254,4 +294,4 @@ interface SbfParseResult {
|
|
|
254
294
|
*/
|
|
255
295
|
declare function parseSbfMeas(data: Uint8Array): SbfParseResult;
|
|
256
296
|
|
|
257
|
-
export { type SbfAlmanac, type SbfAlmanacResult, type SbfGlonassAlmanac, type SbfIonoUtcResult, type SbfKeplerAlmanac, type SbfMeasEpoch, type SbfMeasurement, type SbfNavResult, type SbfParseResult, parseSbfAlmanac, parseSbfIonoUtc, parseSbfMeas, parseSbfNav, crc16 as sbfCrc16, scanSbfFrames };
|
|
297
|
+
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,4 @@
|
|
|
1
|
-
import { E as Ephemeris } from './nav-
|
|
1
|
+
import { E as Ephemeris, C as CnavEphemeris } from './nav-DImXUdbp.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Septentrio SBF framing shared by the measurement and navigation
|
|
@@ -191,6 +191,46 @@ interface SbfIonoUtcResult {
|
|
|
191
191
|
*/
|
|
192
192
|
declare function parseSbfIonoUtc(data: Uint8Array): SbfIonoUtcResult;
|
|
193
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Septentrio SBF raw CNAV navigation-bit blocks: GPSRawL2C (4018) and
|
|
196
|
+
* GPSRawL5 (4019) each carry one 300-bit GPS CNAV message.
|
|
197
|
+
*
|
|
198
|
+
* Block layout (mosaic-X5 reference guide §4): after the 8-byte SBF
|
|
199
|
+
* header, TOW u4 + WNc u2, SVID u1, CRCPassed u1, ViterbiCnt u1,
|
|
200
|
+
* Source u1, FreqNr u1, RxChannel u1, then NAVBits as u4[10] — the
|
|
201
|
+
* first received bit is the MSB of NAVBits[0] (each u4 little-endian
|
|
202
|
+
* in the stream, message bits MSB-first within the word), the unused
|
|
203
|
+
* 20 bits of NAVBits[9] to be ignored. RTKLIB demo5's
|
|
204
|
+
* decode_gpsrawcnav (src/rcv/septentrio.c) reads the same header but
|
|
205
|
+
* leaves the message body undecoded (a TODO stub); the field decoding
|
|
206
|
+
* here is `src/navbits/cnav.ts` working from IS-GPS-200 directly.
|
|
207
|
+
*
|
|
208
|
+
* The receiver's own CRCPassed flag is ignored in favor of re-running
|
|
209
|
+
* CRC-24Q on the transported bits, so `badCrc` counts exactly the
|
|
210
|
+
* messages this library rejected.
|
|
211
|
+
*/
|
|
212
|
+
|
|
213
|
+
/** A CNAV ephemeris tagged with the SBF block (signal) it came from. */
|
|
214
|
+
interface SbfCnavEphemeris extends CnavEphemeris {
|
|
215
|
+
signal: 'L2C' | 'L5';
|
|
216
|
+
}
|
|
217
|
+
interface SbfCnavResult {
|
|
218
|
+
/** Assembled CNAV ephemerides in stream order, repeats suppressed. */
|
|
219
|
+
ephemerides: SbfCnavEphemeris[];
|
|
220
|
+
/** Raw messages whose CRC-24Q check failed (dropped). */
|
|
221
|
+
badCrc: number;
|
|
222
|
+
/** Total GPSRawL2C/GPSRawL5 blocks seen (with valid SBF framing). */
|
|
223
|
+
messages: number;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Decode every GPSRawL2C/GPSRawL5 block in an SBF byte stream and
|
|
227
|
+
* assemble the carried CNAV messages into ephemerides. L2C and L5 are
|
|
228
|
+
* assembled independently (one `CnavAssembler` per signal), so a data
|
|
229
|
+
* set complete on both signals yields one record per signal; each
|
|
230
|
+
* record's `signal` property names its source.
|
|
231
|
+
*/
|
|
232
|
+
declare function parseSbfCnav(data: Uint8Array): SbfCnavResult;
|
|
233
|
+
|
|
194
234
|
/**
|
|
195
235
|
* Septentrio SBF raw-measurement decoding (MeasEpoch + Meas3) — the
|
|
196
236
|
* path from a receiver log to RINEX-grade observables.
|
|
@@ -254,4 +294,4 @@ interface SbfParseResult {
|
|
|
254
294
|
*/
|
|
255
295
|
declare function parseSbfMeas(data: Uint8Array): SbfParseResult;
|
|
256
296
|
|
|
257
|
-
export { type SbfAlmanac, type SbfAlmanacResult, type SbfGlonassAlmanac, type SbfIonoUtcResult, type SbfKeplerAlmanac, type SbfMeasEpoch, type SbfMeasurement, type SbfNavResult, type SbfParseResult, parseSbfAlmanac, parseSbfIonoUtc, parseSbfMeas, parseSbfNav, crc16 as sbfCrc16, scanSbfFrames };
|
|
297
|
+
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,15 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
crc16,
|
|
3
3
|
parseSbfAlmanac,
|
|
4
|
+
parseSbfCnav,
|
|
4
5
|
parseSbfIonoUtc,
|
|
5
6
|
parseSbfMeas,
|
|
6
7
|
parseSbfNav,
|
|
7
8
|
scanSbfFrames
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-5S5HMAKW.js";
|
|
10
|
+
import "./chunk-6NCMACDO.js";
|
|
11
|
+
import "./chunk-IQ5OIMQD.js";
|
|
9
12
|
import "./chunk-HVXYFUCB.js";
|
|
10
13
|
import "./chunk-LEEU5OIO.js";
|
|
11
14
|
export {
|
|
12
15
|
parseSbfAlmanac,
|
|
16
|
+
parseSbfCnav,
|
|
13
17
|
parseSbfIonoUtc,
|
|
14
18
|
parseSbfMeas,
|
|
15
19
|
parseSbfNav,
|
package/dist/ubx.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/ubx/index.ts
|
|
21
21
|
var ubx_exports = {};
|
|
22
22
|
__export(ubx_exports, {
|
|
23
|
+
parseUbxCnav: () => parseUbxCnav,
|
|
23
24
|
parseUbxIonoUtc: () => parseUbxIonoUtc,
|
|
24
25
|
parseUbxNav: () => parseUbxNav,
|
|
25
26
|
parseUbxRawx: () => parseUbxRawx,
|
|
@@ -307,8 +308,238 @@ function parseUbxIonoUtc(data) {
|
|
|
307
308
|
return { ionoCorrections, leapSeconds };
|
|
308
309
|
}
|
|
309
310
|
|
|
310
|
-
// src/
|
|
311
|
+
// src/navbits/cnav.ts
|
|
311
312
|
var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
|
|
313
|
+
var SEC_PER_WEEK2 = 7 * 86400;
|
|
314
|
+
var HALF_WEEK = 302400;
|
|
315
|
+
var CNAV_PREAMBLE = 139;
|
|
316
|
+
var CNAV_A_REF = 26559710;
|
|
317
|
+
var CNAV_OMEGA_DOT_REF = -26e-10;
|
|
318
|
+
function crc24q(buff, bitLen) {
|
|
319
|
+
let crc = 0;
|
|
320
|
+
for (let i = 0; i < bitLen; i++) {
|
|
321
|
+
crc ^= (buff[i >> 3] >> 7 - (i & 7) & 1) << 23;
|
|
322
|
+
const msb = crc & 8388608;
|
|
323
|
+
crc = crc << 1 & 16777215;
|
|
324
|
+
if (msb) crc ^= 8801531;
|
|
325
|
+
}
|
|
326
|
+
return crc;
|
|
327
|
+
}
|
|
328
|
+
function cnavCrcOk(msg) {
|
|
329
|
+
if (msg.length < 38) return false;
|
|
330
|
+
return crc24q(msg, 276) === getBitU(msg, 276, 24);
|
|
331
|
+
}
|
|
332
|
+
function getBitU33(b, pos) {
|
|
333
|
+
return getBitU(b, pos, 1) * 2 ** 32 + getBitU(b, pos + 1, 32);
|
|
334
|
+
}
|
|
335
|
+
function getBitS33(b, pos) {
|
|
336
|
+
const u = getBitU33(b, pos);
|
|
337
|
+
return u < 2 ** 32 ? u : u - 2 ** 33;
|
|
338
|
+
}
|
|
339
|
+
function decodeType10(b, tow) {
|
|
340
|
+
return {
|
|
341
|
+
tow,
|
|
342
|
+
week: getBitU(b, 38, 13),
|
|
343
|
+
health: getBitU(b, 51, 3),
|
|
344
|
+
top: getBitU(b, 54, 11) * 300,
|
|
345
|
+
uraEd: getBitS(b, 65, 5),
|
|
346
|
+
toe: getBitU(b, 70, 11) * 300,
|
|
347
|
+
deltaA: getBitS(b, 81, 26) * 2 ** -9,
|
|
348
|
+
aDot: getBitS(b, 107, 25) * 2 ** -21,
|
|
349
|
+
deltaN0: getBitS(b, 132, 17) * 2 ** -44 * GPS_PI,
|
|
350
|
+
deltaN0Dot: getBitS(b, 149, 23) * 2 ** -57 * GPS_PI,
|
|
351
|
+
m0: getBitS33(b, 172) * 2 ** -32 * GPS_PI,
|
|
352
|
+
e: getBitU33(b, 205) * 2 ** -34,
|
|
353
|
+
omega: getBitS33(b, 238) * 2 ** -32 * GPS_PI,
|
|
354
|
+
integrityFlag: getBitU(b, 271, 1) === 1,
|
|
355
|
+
l2cPhasing: getBitU(b, 272, 1) === 1
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
function decodeType11(b) {
|
|
359
|
+
return {
|
|
360
|
+
toe: getBitU(b, 38, 11) * 300,
|
|
361
|
+
omega0: getBitS33(b, 49) * 2 ** -32 * GPS_PI,
|
|
362
|
+
i0: getBitS33(b, 82) * 2 ** -32 * GPS_PI,
|
|
363
|
+
deltaOmegaDot: getBitS(b, 115, 17) * 2 ** -44 * GPS_PI,
|
|
364
|
+
i0Dot: getBitS(b, 132, 15) * 2 ** -44 * GPS_PI,
|
|
365
|
+
cis: getBitS(b, 147, 16) * 2 ** -30,
|
|
366
|
+
cic: getBitS(b, 163, 16) * 2 ** -30,
|
|
367
|
+
crs: getBitS(b, 179, 24) * 2 ** -8,
|
|
368
|
+
crc: getBitS(b, 203, 24) * 2 ** -8,
|
|
369
|
+
cus: getBitS(b, 227, 21) * 2 ** -30,
|
|
370
|
+
cuc: getBitS(b, 248, 21) * 2 ** -30
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
var isc = (b, pos) => {
|
|
374
|
+
const raw = getBitS(b, pos, 13);
|
|
375
|
+
return raw === -4096 ? null : raw * 2 ** -35;
|
|
376
|
+
};
|
|
377
|
+
function decodeClock(b, msgType) {
|
|
378
|
+
const clock = {
|
|
379
|
+
msgType,
|
|
380
|
+
top: getBitU(b, 38, 11) * 300,
|
|
381
|
+
uraNed0: getBitS(b, 49, 5),
|
|
382
|
+
uraNed1: getBitU(b, 54, 3),
|
|
383
|
+
uraNed2: getBitU(b, 57, 3),
|
|
384
|
+
toc: getBitU(b, 60, 11) * 300,
|
|
385
|
+
af0: getBitS(b, 71, 26) * 2 ** -35,
|
|
386
|
+
af1: getBitS(b, 97, 20) * 2 ** -48,
|
|
387
|
+
af2: getBitS(b, 117, 10) * 2 ** -60
|
|
388
|
+
};
|
|
389
|
+
if (msgType === 30) {
|
|
390
|
+
clock.tgd = isc(b, 127);
|
|
391
|
+
clock.iscL1ca = isc(b, 140);
|
|
392
|
+
clock.iscL2c = isc(b, 153);
|
|
393
|
+
clock.iscL5i5 = isc(b, 166);
|
|
394
|
+
clock.iscL5q5 = isc(b, 179);
|
|
395
|
+
clock.ionoAlpha = [
|
|
396
|
+
getBitS(b, 192, 8) * 2 ** -30,
|
|
397
|
+
getBitS(b, 200, 8) * 2 ** -27,
|
|
398
|
+
getBitS(b, 208, 8) * 2 ** -24,
|
|
399
|
+
getBitS(b, 216, 8) * 2 ** -24
|
|
400
|
+
];
|
|
401
|
+
clock.ionoBeta = [
|
|
402
|
+
getBitS(b, 224, 8) * 2 ** 11,
|
|
403
|
+
getBitS(b, 232, 8) * 2 ** 14,
|
|
404
|
+
getBitS(b, 240, 8) * 2 ** 16,
|
|
405
|
+
getBitS(b, 248, 8) * 2 ** 16
|
|
406
|
+
];
|
|
407
|
+
clock.wnOp = getBitU(b, 256, 8);
|
|
408
|
+
}
|
|
409
|
+
return clock;
|
|
410
|
+
}
|
|
411
|
+
function resolveWeek(week, towSec, sec) {
|
|
412
|
+
if (sec < towSec - HALF_WEEK) return week + 1;
|
|
413
|
+
if (sec > towSec + HALF_WEEK) return week - 1;
|
|
414
|
+
return week;
|
|
415
|
+
}
|
|
416
|
+
function gpsDate(week, sec) {
|
|
417
|
+
return new Date(GPS_EPOCH_MS2 + (week * SEC_PER_WEEK2 + sec) * 1e3);
|
|
418
|
+
}
|
|
419
|
+
var CnavAssembler = class {
|
|
420
|
+
sats = /* @__PURE__ */ new Map();
|
|
421
|
+
/**
|
|
422
|
+
* Push one 300-bit CNAV message (38+ bytes, bit 0 = first bit of
|
|
423
|
+
* the preamble). Returns the newly completed ephemeris, or null.
|
|
424
|
+
* Messages that are not MT10/MT11/MT30-37, or whose preamble/PRN
|
|
425
|
+
* are out of range, are ignored.
|
|
426
|
+
*/
|
|
427
|
+
push(msg) {
|
|
428
|
+
if (msg.length < 38 || getBitU(msg, 0, 8) !== CNAV_PREAMBLE) return null;
|
|
429
|
+
const prn = getBitU(msg, 8, 6);
|
|
430
|
+
if (prn < 1 || prn > 32) return null;
|
|
431
|
+
const type = getBitU(msg, 14, 6);
|
|
432
|
+
const tow = getBitU(msg, 20, 17) * 6;
|
|
433
|
+
let sat = this.sats.get(prn);
|
|
434
|
+
if (!sat) {
|
|
435
|
+
sat = {};
|
|
436
|
+
this.sats.set(prn, sat);
|
|
437
|
+
}
|
|
438
|
+
if (type === 10) sat.t10 = decodeType10(msg, tow);
|
|
439
|
+
else if (type === 11) sat.t11 = decodeType11(msg);
|
|
440
|
+
else if (type >= 30 && type <= 37) {
|
|
441
|
+
sat.clock = decodeClock(msg, type);
|
|
442
|
+
if (type === 30) sat.extras = sat.clock;
|
|
443
|
+
} else return null;
|
|
444
|
+
return this.tryEmit(prn, sat);
|
|
445
|
+
}
|
|
446
|
+
tryEmit(prn, sat) {
|
|
447
|
+
const { t10, t11, clock, extras } = sat;
|
|
448
|
+
if (!t10 || !t11 || !clock) return null;
|
|
449
|
+
if (t10.toe !== t11.toe || clock.toc !== t10.toe) return null;
|
|
450
|
+
const key = `${t10.week}:${t10.toe}:${clock.af0}:${clock.af1}`;
|
|
451
|
+
if (key === sat.lastKey) return null;
|
|
452
|
+
sat.lastKey = key;
|
|
453
|
+
const weekToe = resolveWeek(t10.week, t10.tow, t10.toe);
|
|
454
|
+
const a = CNAV_A_REF + t10.deltaA;
|
|
455
|
+
return {
|
|
456
|
+
system: "G",
|
|
457
|
+
prn: `G${String(prn).padStart(2, "0")}`,
|
|
458
|
+
week: t10.week,
|
|
459
|
+
health: t10.health,
|
|
460
|
+
uraEd: t10.uraEd,
|
|
461
|
+
uraNed0: clock.uraNed0,
|
|
462
|
+
uraNed1: clock.uraNed1,
|
|
463
|
+
uraNed2: clock.uraNed2,
|
|
464
|
+
top: t10.top,
|
|
465
|
+
toe: t10.toe,
|
|
466
|
+
toeDate: gpsDate(weekToe, t10.toe),
|
|
467
|
+
a,
|
|
468
|
+
deltaA: t10.deltaA,
|
|
469
|
+
aDot: t10.aDot,
|
|
470
|
+
deltaN0: t10.deltaN0,
|
|
471
|
+
deltaN0Dot: t10.deltaN0Dot,
|
|
472
|
+
m0: t10.m0,
|
|
473
|
+
e: t10.e,
|
|
474
|
+
omega: t10.omega,
|
|
475
|
+
omega0: t11.omega0,
|
|
476
|
+
i0: t11.i0,
|
|
477
|
+
omegaDot: CNAV_OMEGA_DOT_REF * GPS_PI + t11.deltaOmegaDot,
|
|
478
|
+
deltaOmegaDot: t11.deltaOmegaDot,
|
|
479
|
+
i0Dot: t11.i0Dot,
|
|
480
|
+
cis: t11.cis,
|
|
481
|
+
cic: t11.cic,
|
|
482
|
+
crs: t11.crs,
|
|
483
|
+
crc: t11.crc,
|
|
484
|
+
cus: t11.cus,
|
|
485
|
+
cuc: t11.cuc,
|
|
486
|
+
toc: clock.toc,
|
|
487
|
+
tocDate: gpsDate(weekToe, clock.toc),
|
|
488
|
+
af0: clock.af0,
|
|
489
|
+
af1: clock.af1,
|
|
490
|
+
af2: clock.af2,
|
|
491
|
+
clockMsgType: clock.msgType,
|
|
492
|
+
tgd: extras?.tgd ?? null,
|
|
493
|
+
iscL1ca: extras?.iscL1ca ?? null,
|
|
494
|
+
iscL2c: extras?.iscL2c ?? null,
|
|
495
|
+
iscL5i5: extras?.iscL5i5 ?? null,
|
|
496
|
+
iscL5q5: extras?.iscL5q5 ?? null,
|
|
497
|
+
...extras?.ionoAlpha && { ionoAlpha: extras.ionoAlpha },
|
|
498
|
+
...extras?.ionoBeta && { ionoBeta: extras.ionoBeta },
|
|
499
|
+
...extras?.wnOp !== void 0 && { wnOp: extras.wnOp },
|
|
500
|
+
integrityFlag: t10.integrityFlag,
|
|
501
|
+
l2cPhasing: t10.l2cPhasing,
|
|
502
|
+
tow: t10.tow
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
// src/ubx/cnav.ts
|
|
508
|
+
function parseUbxCnav(data) {
|
|
509
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
510
|
+
const assembler = new CnavAssembler();
|
|
511
|
+
const ephemerides = [];
|
|
512
|
+
let badCrc = 0;
|
|
513
|
+
let messages = 0;
|
|
514
|
+
for (const f of ubxFrames(data)) {
|
|
515
|
+
if (f.msgClass !== 2 || f.msgId !== 19) continue;
|
|
516
|
+
const p = f.payload;
|
|
517
|
+
if (p.length < 8 + 40) continue;
|
|
518
|
+
if (p[0] !== 0 || p[2] !== 3 && p[2] !== 4) continue;
|
|
519
|
+
const svId = p[1];
|
|
520
|
+
if (svId < 1 || svId > 32) continue;
|
|
521
|
+
messages++;
|
|
522
|
+
const msg = new Uint8Array(40);
|
|
523
|
+
const base = f.payloadStart + 8;
|
|
524
|
+
for (let k = 0; k < 10; k++) {
|
|
525
|
+
const w = view.getUint32(base + 4 * k, true);
|
|
526
|
+
msg[4 * k] = w >>> 24;
|
|
527
|
+
msg[4 * k + 1] = w >>> 16 & 255;
|
|
528
|
+
msg[4 * k + 2] = w >>> 8 & 255;
|
|
529
|
+
msg[4 * k + 3] = w & 255;
|
|
530
|
+
}
|
|
531
|
+
if (!cnavCrcOk(msg)) {
|
|
532
|
+
badCrc++;
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
const eph = assembler.push(msg);
|
|
536
|
+
if (eph) ephemerides.push(eph);
|
|
537
|
+
}
|
|
538
|
+
return { ephemerides, badCrc, messages };
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// src/ubx/index.ts
|
|
542
|
+
var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
|
|
312
543
|
var MS_PER_WEEK = 7 * 864e5;
|
|
313
544
|
var SIGNALS = {
|
|
314
545
|
0: { 0: ["G", "1C"], 3: ["G", "2X"], 4: ["G", "2X"] },
|
|
@@ -391,7 +622,7 @@ function parseUbxRawx(data) {
|
|
|
391
622
|
if (!codes.includes(sig[1])) codes.push(sig[1]);
|
|
392
623
|
}
|
|
393
624
|
epochs.push({
|
|
394
|
-
timeMs:
|
|
625
|
+
timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK + Math.round(rcvTow * 1e3),
|
|
395
626
|
leapS: leapValid ? leapS : null,
|
|
396
627
|
meas
|
|
397
628
|
});
|
|
@@ -401,6 +632,7 @@ function parseUbxRawx(data) {
|
|
|
401
632
|
}
|
|
402
633
|
// Annotate the CommonJS export names for ESM import in node:
|
|
403
634
|
0 && (module.exports = {
|
|
635
|
+
parseUbxCnav,
|
|
404
636
|
parseUbxIonoUtc,
|
|
405
637
|
parseUbxNav,
|
|
406
638
|
parseUbxRawx,
|