gnss-js 1.21.0 → 1.22.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-DLXTTHRK.js → chunk-MCAVU3XL.js} +118 -9
- package/dist/{chunk-K3V3NHWL.js → chunk-PZNVFCKJ.js} +25 -766
- package/dist/chunk-VTX3VCL4.js +769 -0
- package/dist/index.cjs +1397 -1295
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -2
- package/dist/sbf.js +2 -1
- package/dist/ubx.cjs +809 -10
- package/dist/ubx.d.cts +111 -1
- package/dist/ubx.d.ts +111 -1
- package/dist/ubx.js +6 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -241,6 +241,7 @@ __export(src_exports, {
|
|
|
241
241
|
parseUbxCnav: () => parseUbxCnav,
|
|
242
242
|
parseUbxIonoUtc: () => parseUbxIonoUtc,
|
|
243
243
|
parseUbxNav: () => parseUbxNav,
|
|
244
|
+
parseUbxRawNav: () => parseUbxRawNav,
|
|
244
245
|
parseUbxRawx: () => parseUbxRawx,
|
|
245
246
|
phiAltBOC: () => phiAltBOC,
|
|
246
247
|
phiBOCc: () => phiBOCc,
|
|
@@ -5404,1345 +5405,1445 @@ function parseUbxCnav(data) {
|
|
|
5404
5405
|
return { ephemerides, badCrc, messages };
|
|
5405
5406
|
}
|
|
5406
5407
|
|
|
5407
|
-
// src/
|
|
5408
|
-
var
|
|
5409
|
-
var
|
|
5410
|
-
var
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
// E1C/B, E5bI/Q
|
|
5417
|
-
3: { 0: ["C", "2I"], 1: ["C", "2I"], 2: ["C", "7I"], 3: ["C", "7I"] },
|
|
5418
|
-
// B1I D1/D2, B2I D1/D2
|
|
5419
|
-
5: { 0: ["J", "1C"], 4: ["J", "2X"], 5: ["J", "2X"] },
|
|
5420
|
-
// QZSS L1C/A, L2CM/CL
|
|
5421
|
-
6: { 0: ["R", "1C"], 2: ["R", "2C"] }
|
|
5422
|
-
// GLONASS L1OF, L2OF
|
|
5423
|
-
};
|
|
5424
|
-
function prnFor(gnssId, svId) {
|
|
5425
|
-
const two4 = (n) => String(n).padStart(2, "0");
|
|
5426
|
-
switch (gnssId) {
|
|
5427
|
-
case 0:
|
|
5428
|
-
return svId >= 1 && svId <= 32 ? `G${two4(svId)}` : null;
|
|
5429
|
-
case 1:
|
|
5430
|
-
return svId >= 120 && svId <= 158 ? `S${two4(svId - 100)}` : null;
|
|
5431
|
-
case 2:
|
|
5432
|
-
return svId >= 1 && svId <= 36 ? `E${two4(svId)}` : null;
|
|
5433
|
-
case 3:
|
|
5434
|
-
return svId >= 1 && svId <= 63 ? `C${two4(svId)}` : null;
|
|
5435
|
-
case 5:
|
|
5436
|
-
return svId >= 1 && svId <= 10 ? `J${two4(svId)}` : null;
|
|
5437
|
-
case 6:
|
|
5438
|
-
return svId >= 1 && svId <= 32 ? `R${two4(svId)}` : null;
|
|
5439
|
-
default:
|
|
5440
|
-
return null;
|
|
5441
|
-
}
|
|
5408
|
+
// src/navbits/bds.ts
|
|
5409
|
+
var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
|
|
5410
|
+
var SEC_PER_WEEK4 = 7 * 86400;
|
|
5411
|
+
var MS_PER_WEEK2 = SEC_PER_WEEK4 * 1e3;
|
|
5412
|
+
var HALF_WEEK2 = 302400;
|
|
5413
|
+
var sowOf = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK4;
|
|
5414
|
+
var BDS_SUBFRAME_BYTES = 38;
|
|
5415
|
+
function getBitU2(b, p1, l1, p2, l2) {
|
|
5416
|
+
return getBitU(b, p1, l1) * 2 ** l2 + getBitU(b, p2, l2);
|
|
5442
5417
|
}
|
|
5443
|
-
function
|
|
5444
|
-
|
|
5445
|
-
const epochs = [];
|
|
5446
|
-
const messageCounts = {};
|
|
5447
|
-
const obsCodes = {};
|
|
5448
|
-
const stats = { badChecksums: 0 };
|
|
5449
|
-
for (const frame of ubxFrames(data, stats)) {
|
|
5450
|
-
const { msgClass: cls, msgId: id } = frame;
|
|
5451
|
-
const len = frame.payload.length;
|
|
5452
|
-
const key = `${cls.toString(16).padStart(2, "0")}-${id.toString(16).padStart(2, "0")}`;
|
|
5453
|
-
messageCounts[key] = (messageCounts[key] ?? 0) + 1;
|
|
5454
|
-
if (cls === 2 && id === 21 && len >= 16) {
|
|
5455
|
-
const p = frame.payloadStart;
|
|
5456
|
-
const rcvTow = view.getFloat64(p, true);
|
|
5457
|
-
const week = view.getUint16(p + 8, true);
|
|
5458
|
-
const leapS = view.getInt8(p + 10);
|
|
5459
|
-
const numMeas = data[p + 11];
|
|
5460
|
-
const recStat = data[p + 12];
|
|
5461
|
-
const leapValid = (recStat & 1) !== 0;
|
|
5462
|
-
const meas = [];
|
|
5463
|
-
for (let k = 0; k < numMeas; k++) {
|
|
5464
|
-
const off = p + 16 + 32 * k;
|
|
5465
|
-
if (off + 32 > p + len) break;
|
|
5466
|
-
const gnssId = data[off + 20];
|
|
5467
|
-
const svId = data[off + 21];
|
|
5468
|
-
const sigId = data[off + 22];
|
|
5469
|
-
const trkStat = data[off + 30];
|
|
5470
|
-
const prn = prnFor(gnssId, svId);
|
|
5471
|
-
const sig = SIGNALS[gnssId]?.[sigId];
|
|
5472
|
-
if (!prn || !sig) continue;
|
|
5473
|
-
const prValid = (trkStat & 1) !== 0;
|
|
5474
|
-
const cpValid = (trkStat & 2) !== 0;
|
|
5475
|
-
const cp = view.getFloat64(off + 8, true);
|
|
5476
|
-
meas.push({
|
|
5477
|
-
prn,
|
|
5478
|
-
code: sig[1],
|
|
5479
|
-
pr: prValid ? view.getFloat64(off, true) : null,
|
|
5480
|
-
cp: cpValid && cp !== 0 ? cp : null,
|
|
5481
|
-
doppler: view.getFloat32(off + 16, true),
|
|
5482
|
-
cn0: data[off + 26],
|
|
5483
|
-
halfCycleAmbiguous: (trkStat & 4) !== 0,
|
|
5484
|
-
lockTimeMs: view.getUint16(off + 24, true)
|
|
5485
|
-
});
|
|
5486
|
-
const sys = sig[0];
|
|
5487
|
-
const codes = obsCodes[sys] ??= [];
|
|
5488
|
-
if (!codes.includes(sig[1])) codes.push(sig[1]);
|
|
5489
|
-
}
|
|
5490
|
-
epochs.push({
|
|
5491
|
-
timeMs: GPS_EPOCH_MS4 + week * MS_PER_WEEK2 + Math.round(rcvTow * 1e3),
|
|
5492
|
-
leapS: leapValid ? leapS : null,
|
|
5493
|
-
meas
|
|
5494
|
-
});
|
|
5495
|
-
}
|
|
5496
|
-
}
|
|
5497
|
-
return { epochs, messageCounts, obsCodes, badChecksums: stats.badChecksums };
|
|
5418
|
+
function getBitS2(b, p1, l1, p2, l2) {
|
|
5419
|
+
return getBitS(b, p1, l1) * 2 ** l2 + getBitU(b, p2, l2);
|
|
5498
5420
|
}
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
var CRC_TABLE = (() => {
|
|
5502
|
-
const t = new Uint16Array(256);
|
|
5503
|
-
for (let n = 0; n < 256; n++) {
|
|
5504
|
-
let c = n << 8;
|
|
5505
|
-
for (let k = 0; k < 8; k++)
|
|
5506
|
-
c = c & 32768 ? (c << 1 ^ 4129) & 65535 : c << 1 & 65535;
|
|
5507
|
-
t[n] = c;
|
|
5508
|
-
}
|
|
5509
|
-
return t;
|
|
5510
|
-
})();
|
|
5511
|
-
function crc16(data, start, end) {
|
|
5512
|
-
let crc = 0;
|
|
5513
|
-
for (let i = start; i < end; i++)
|
|
5514
|
-
crc = (crc << 8 ^ CRC_TABLE[(crc >> 8 ^ data[i]) & 255]) & 65535;
|
|
5515
|
-
return crc;
|
|
5421
|
+
function getBitU3(b, p1, l1, p2, l2, p3, l3) {
|
|
5422
|
+
return getBitU(b, p1, l1) * 2 ** (l2 + l3) + getBitU(b, p2, l2) * 2 ** l3 + getBitU(b, p3, l3);
|
|
5516
5423
|
}
|
|
5517
|
-
function
|
|
5518
|
-
|
|
5519
|
-
let i = 0;
|
|
5520
|
-
while (i + 8 <= data.length) {
|
|
5521
|
-
if (data[i] !== 36 || data[i + 1] !== 64) {
|
|
5522
|
-
i++;
|
|
5523
|
-
continue;
|
|
5524
|
-
}
|
|
5525
|
-
const len = view.getUint16(i + 6, true);
|
|
5526
|
-
if (len < 8 || len % 4 !== 0) {
|
|
5527
|
-
i++;
|
|
5528
|
-
continue;
|
|
5529
|
-
}
|
|
5530
|
-
if (i + len > data.length) break;
|
|
5531
|
-
if (crc16(data, i + 4, i + len) !== view.getUint16(i + 2, true)) {
|
|
5532
|
-
badCrc++;
|
|
5533
|
-
i++;
|
|
5534
|
-
continue;
|
|
5535
|
-
}
|
|
5536
|
-
onBlock(view.getUint16(i + 4, true) & 8191, i, len);
|
|
5537
|
-
i += len;
|
|
5538
|
-
}
|
|
5539
|
-
return badCrc;
|
|
5424
|
+
function getBitS3(b, p1, l1, p2, l2, p3, l3) {
|
|
5425
|
+
return getBitS(b, p1, l1) * 2 ** (l2 + l3) + getBitU(b, p2, l2) * 2 ** l3 + getBitU(b, p3, l3);
|
|
5540
5426
|
}
|
|
5541
|
-
var
|
|
5542
|
-
function
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
if (svid <= 70) return null;
|
|
5548
|
-
if (svid <= 106) return svid - 70 <= 36 ? `E${two(svid - 70)}` : null;
|
|
5549
|
-
if (svid <= 119) return null;
|
|
5550
|
-
if (svid <= 140) return `S${two(svid - 100)}`;
|
|
5551
|
-
if (svid <= 180) return svid - 140 <= 50 ? `C${two(svid - 140)}` : null;
|
|
5552
|
-
if (svid <= 190) return `J${two(svid - 180)}`;
|
|
5553
|
-
if (svid <= 197) return svid - 190 <= 14 ? `I${two(svid - 190)}` : null;
|
|
5554
|
-
if (svid <= 215) return `S${two(svid - 157)}`;
|
|
5555
|
-
if (svid <= 222) return svid - 208 <= 14 ? `I${two(svid - 208)}` : null;
|
|
5556
|
-
if (svid <= 245) return svid - 182 <= 50 ? `C${two(svid - 182)}` : null;
|
|
5557
|
-
return null;
|
|
5427
|
+
var mergeS = (hi, lo, n) => hi * 2 ** n + lo;
|
|
5428
|
+
function bchOk(cw) {
|
|
5429
|
+
for (let i = 14; i >= 4; i--) {
|
|
5430
|
+
if (cw & 1 << i) cw ^= 19 << i - 4;
|
|
5431
|
+
}
|
|
5432
|
+
return cw === 0;
|
|
5558
5433
|
}
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
let offset = refWeek % mod - wn;
|
|
5570
|
-
if (offset > mod / 2) offset -= mod;
|
|
5571
|
-
if (offset < -(mod / 2 - 1)) offset += mod;
|
|
5572
|
-
return refWeek - offset;
|
|
5434
|
+
function bdsSubframeParityOk(subframe) {
|
|
5435
|
+
if (subframe.length < BDS_SUBFRAME_BYTES) return false;
|
|
5436
|
+
if (!bchOk(getBitU(subframe, 15, 15))) return false;
|
|
5437
|
+
for (let w = 1; w < 10; w++) {
|
|
5438
|
+
const base = 30 * w;
|
|
5439
|
+
const cw1 = getBitU(subframe, base, 11) * 16 + getBitU(subframe, base + 22, 4);
|
|
5440
|
+
const cw2 = getBitU(subframe, base + 11, 11) * 16 + getBitU(subframe, base + 26, 4);
|
|
5441
|
+
if (!bchOk(cw1) || !bchOk(cw2)) return false;
|
|
5442
|
+
}
|
|
5443
|
+
return true;
|
|
5573
5444
|
}
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
const
|
|
5579
|
-
const max = sys === "G" ? 32 : 10;
|
|
5580
|
-
if (prn < 1 || prn > max) return null;
|
|
5581
|
-
const wnc = view.getUint16(b + 12, true);
|
|
5582
|
-
const tgdRaw = view.getFloat32(b + 28, true);
|
|
5583
|
-
const tocs = view.getUint32(b + 32, true);
|
|
5584
|
-
const toes = view.getUint32(b + 88, true);
|
|
5585
|
-
const wnToc = adjustWeek(wnc, view.getUint16(b + 136, true), 1024);
|
|
5586
|
-
const tocDate = new Date(gpsMs(wnToc, tocs));
|
|
5445
|
+
function buildBdsEphemeris(prn, f) {
|
|
5446
|
+
let week = f.week;
|
|
5447
|
+
if (f.toes < f.sow - HALF_WEEK2) week++;
|
|
5448
|
+
else if (f.toes > f.sow + HALF_WEEK2) week--;
|
|
5449
|
+
const tocDate = new Date(BDT_EPOCH_MS + week * MS_PER_WEEK2 + f.tocSec * 1e3);
|
|
5587
5450
|
return {
|
|
5588
|
-
system:
|
|
5589
|
-
prn
|
|
5451
|
+
system: "C",
|
|
5452
|
+
prn,
|
|
5590
5453
|
toc: sowOf(tocDate.getTime()),
|
|
5591
5454
|
tocDate,
|
|
5592
|
-
af0:
|
|
5593
|
-
af1:
|
|
5594
|
-
af2:
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
week
|
|
5616
|
-
svHealth:
|
|
5617
|
-
|
|
5455
|
+
af0: f.af0,
|
|
5456
|
+
af1: f.af1,
|
|
5457
|
+
af2: f.af2,
|
|
5458
|
+
// AODE is not in the ephemeris subframes; RTKLIB derives the RINEX
|
|
5459
|
+
// IODE/AODE slot from toc per the BDS ICD update schedule.
|
|
5460
|
+
iode: Math.floor(f.tocSec / 720) % 240,
|
|
5461
|
+
crs: f.crs,
|
|
5462
|
+
deltaN: f.deltaN,
|
|
5463
|
+
m0: f.m0,
|
|
5464
|
+
cuc: f.cuc,
|
|
5465
|
+
e: f.e,
|
|
5466
|
+
cus: f.cus,
|
|
5467
|
+
sqrtA: f.sqrtA,
|
|
5468
|
+
toe: f.toes,
|
|
5469
|
+
cic: f.cic,
|
|
5470
|
+
omega0: f.omega0,
|
|
5471
|
+
cis: f.cis,
|
|
5472
|
+
i0: f.i0,
|
|
5473
|
+
crc: f.crc,
|
|
5474
|
+
omega: f.omega,
|
|
5475
|
+
omegaDot: f.omegaDot,
|
|
5476
|
+
idot: f.idot,
|
|
5477
|
+
week,
|
|
5478
|
+
// RINEX BDS week field is the BDT week of toe
|
|
5479
|
+
svHealth: f.svh,
|
|
5480
|
+
// SatH1
|
|
5481
|
+
tgd: f.tgd1
|
|
5482
|
+
// TGD1 (B1) — RINEX slot
|
|
5618
5483
|
};
|
|
5619
5484
|
}
|
|
5620
|
-
function
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
const
|
|
5626
|
-
const
|
|
5627
|
-
const
|
|
5628
|
-
const
|
|
5629
|
-
const
|
|
5630
|
-
const
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
const
|
|
5485
|
+
function decodeBdsD1Frame(subframes, opts = {}) {
|
|
5486
|
+
if (subframes.length < 3 * BDS_SUBFRAME_BYTES) return null;
|
|
5487
|
+
const b = subframes;
|
|
5488
|
+
let i = 8 * 38 * 0;
|
|
5489
|
+
const frn1 = getBitU(b, i + 15, 3);
|
|
5490
|
+
const sow1 = getBitU2(b, i + 18, 8, i + 30, 12);
|
|
5491
|
+
const svh = getBitU(b, i + 42, 1);
|
|
5492
|
+
const week = getBitU(b, i + 60, 13);
|
|
5493
|
+
const tocSec = getBitU2(b, i + 73, 9, i + 90, 8) * 8;
|
|
5494
|
+
const tgd1 = getBitS(b, i + 98, 10) * 0.1 * 1e-9;
|
|
5495
|
+
const af2 = getBitS(b, i + 214, 11) * 2 ** -66;
|
|
5496
|
+
const af0 = getBitS2(b, i + 225, 7, i + 240, 17) * 2 ** -33;
|
|
5497
|
+
const af1 = getBitS2(b, i + 257, 5, i + 270, 17) * 2 ** -50;
|
|
5498
|
+
i = 8 * 38 * 1;
|
|
5499
|
+
const frn2 = getBitU(b, i + 15, 3);
|
|
5500
|
+
const sow2 = getBitU2(b, i + 18, 8, i + 30, 12);
|
|
5501
|
+
const deltaN = getBitS2(b, i + 42, 10, i + 60, 6) * 2 ** -43 * GPS_PI;
|
|
5502
|
+
const cuc = getBitS2(b, i + 66, 16, i + 90, 2) * 2 ** -31;
|
|
5503
|
+
const m0 = getBitS2(b, i + 92, 20, i + 120, 12) * 2 ** -31 * GPS_PI;
|
|
5504
|
+
const e = getBitU2(b, i + 132, 10, i + 150, 22) * 2 ** -33;
|
|
5505
|
+
const cus = getBitS(b, i + 180, 18) * 2 ** -31;
|
|
5506
|
+
const crc = getBitS2(b, i + 198, 4, i + 210, 14) * 2 ** -6;
|
|
5507
|
+
const crs = getBitS2(b, i + 224, 8, i + 240, 10) * 2 ** -6;
|
|
5508
|
+
const sqrtA = getBitU2(b, i + 250, 12, i + 270, 20) * 2 ** -19;
|
|
5509
|
+
const toe1 = getBitU(b, i + 290, 2);
|
|
5510
|
+
i = 8 * 38 * 2;
|
|
5511
|
+
const frn3 = getBitU(b, i + 15, 3);
|
|
5512
|
+
const sow3 = getBitU2(b, i + 18, 8, i + 30, 12);
|
|
5513
|
+
const toe2 = getBitU2(b, i + 42, 10, i + 60, 5);
|
|
5514
|
+
const i0 = getBitS2(b, i + 65, 17, i + 90, 15) * 2 ** -31 * GPS_PI;
|
|
5515
|
+
const cic = getBitS2(b, i + 105, 7, i + 120, 11) * 2 ** -31;
|
|
5516
|
+
const omegaDot = getBitS2(b, i + 131, 11, i + 150, 13) * 2 ** -43 * GPS_PI;
|
|
5517
|
+
const cis = getBitS2(b, i + 163, 9, i + 180, 9) * 2 ** -31;
|
|
5518
|
+
const idot = getBitS2(b, i + 189, 13, i + 210, 1) * 2 ** -43 * GPS_PI;
|
|
5519
|
+
const omega0 = getBitS2(b, i + 211, 21, i + 240, 11) * 2 ** -31 * GPS_PI;
|
|
5520
|
+
const omega = getBitS2(b, i + 251, 11, i + 270, 21) * 2 ** -31 * GPS_PI;
|
|
5521
|
+
const toes = (toe1 * 2 ** 15 + toe2) * 8;
|
|
5522
|
+
if (frn1 !== 1 || frn2 !== 2 || frn3 !== 3) return null;
|
|
5523
|
+
if (sow2 !== sow1 + 6 || sow3 !== sow2 + 6) return null;
|
|
5524
|
+
if (tocSec !== toes) return null;
|
|
5525
|
+
return buildBdsEphemeris(opts.prn ?? "C00", {
|
|
5526
|
+
week,
|
|
5527
|
+
sow: sow1,
|
|
5528
|
+
toes,
|
|
5529
|
+
tocSec,
|
|
5530
|
+
svh,
|
|
5531
|
+
tgd1,
|
|
5532
|
+
af0,
|
|
5533
|
+
af1,
|
|
5534
|
+
af2,
|
|
5535
|
+
crs,
|
|
5536
|
+
deltaN,
|
|
5537
|
+
m0,
|
|
5538
|
+
cuc,
|
|
5539
|
+
e,
|
|
5540
|
+
cus,
|
|
5541
|
+
sqrtA,
|
|
5542
|
+
cic,
|
|
5543
|
+
omega0,
|
|
5544
|
+
cis,
|
|
5545
|
+
i0,
|
|
5546
|
+
crc,
|
|
5547
|
+
omega,
|
|
5548
|
+
omegaDot,
|
|
5549
|
+
idot
|
|
5550
|
+
});
|
|
5551
|
+
}
|
|
5552
|
+
function decodeBdsD2Frame(pages, opts = {}) {
|
|
5553
|
+
if (pages.length < 10 * BDS_SUBFRAME_BYTES) return null;
|
|
5554
|
+
const b = pages;
|
|
5555
|
+
let i = 8 * 38 * 0;
|
|
5556
|
+
const pgn1 = getBitU(b, i + 42, 4);
|
|
5557
|
+
const sow1 = getBitU2(b, i + 18, 8, i + 30, 12);
|
|
5558
|
+
const svh = getBitU(b, i + 46, 1);
|
|
5559
|
+
const week = getBitU(b, i + 64, 13);
|
|
5560
|
+
const tocSec = getBitU2(b, i + 77, 5, i + 90, 12) * 8;
|
|
5561
|
+
const tgd1 = getBitS(b, i + 102, 10) * 0.1 * 1e-9;
|
|
5562
|
+
i = 8 * 38 * 2;
|
|
5563
|
+
const pgn3 = getBitU(b, i + 42, 4);
|
|
5564
|
+
const sow3 = getBitU2(b, i + 18, 8, i + 30, 12);
|
|
5565
|
+
const af0 = getBitS2(b, i + 100, 12, i + 120, 12) * 2 ** -33;
|
|
5566
|
+
const af1p3 = getBitS(b, i + 132, 4);
|
|
5567
|
+
i = 8 * 38 * 3;
|
|
5568
|
+
const pgn4 = getBitU(b, i + 42, 4);
|
|
5569
|
+
const sow4 = getBitU2(b, i + 18, 8, i + 30, 12);
|
|
5570
|
+
const af1p4 = getBitU2(b, i + 46, 6, i + 60, 12);
|
|
5571
|
+
const af2 = getBitS2(b, i + 72, 10, i + 90, 1) * 2 ** -66;
|
|
5572
|
+
const deltaN = getBitS(b, i + 96, 16) * 2 ** -43 * GPS_PI;
|
|
5573
|
+
const cucp4 = getBitS(b, i + 120, 14);
|
|
5574
|
+
i = 8 * 38 * 4;
|
|
5575
|
+
const pgn5 = getBitU(b, i + 42, 4);
|
|
5576
|
+
const sow5 = getBitU2(b, i + 18, 8, i + 30, 12);
|
|
5577
|
+
const cucp5 = getBitU(b, i + 46, 4);
|
|
5578
|
+
const m0 = getBitS3(b, i + 50, 2, i + 60, 22, i + 90, 8) * 2 ** -31 * GPS_PI;
|
|
5579
|
+
const cus = getBitS2(b, i + 98, 14, i + 120, 4) * 2 ** -31;
|
|
5580
|
+
const ep5 = getBitS(b, i + 124, 10);
|
|
5581
|
+
i = 8 * 38 * 5;
|
|
5582
|
+
const pgn6 = getBitU(b, i + 42, 4);
|
|
5583
|
+
const sow6 = getBitU2(b, i + 18, 8, i + 30, 12);
|
|
5584
|
+
const ep6 = getBitU2(b, i + 46, 6, i + 60, 16);
|
|
5585
|
+
const sqrtA = getBitU3(b, i + 76, 6, i + 90, 22, i + 120, 4) * 2 ** -19;
|
|
5586
|
+
const cicp6 = getBitS(b, i + 124, 10);
|
|
5587
|
+
i = 8 * 38 * 6;
|
|
5588
|
+
const pgn7 = getBitU(b, i + 42, 4);
|
|
5589
|
+
const sow7 = getBitU2(b, i + 18, 8, i + 30, 12);
|
|
5590
|
+
const cicp7 = getBitU2(b, i + 46, 6, i + 60, 2);
|
|
5591
|
+
const cis = getBitS(b, i + 62, 18) * 2 ** -31;
|
|
5592
|
+
const toes = getBitU2(b, i + 80, 2, i + 90, 15) * 8;
|
|
5593
|
+
const i0p7 = getBitS2(b, i + 105, 7, i + 120, 14);
|
|
5594
|
+
i = 8 * 38 * 7;
|
|
5595
|
+
const pgn8 = getBitU(b, i + 42, 4);
|
|
5596
|
+
const sow8 = getBitU2(b, i + 18, 8, i + 30, 12);
|
|
5597
|
+
const i0p8 = getBitU2(b, i + 46, 6, i + 60, 5);
|
|
5598
|
+
const crc = getBitS2(b, i + 65, 17, i + 90, 1) * 2 ** -6;
|
|
5599
|
+
const crs = getBitS(b, i + 91, 18) * 2 ** -6;
|
|
5600
|
+
const omegaDotP8 = getBitS2(b, i + 109, 3, i + 120, 16);
|
|
5601
|
+
i = 8 * 38 * 8;
|
|
5602
|
+
const pgn9 = getBitU(b, i + 42, 4);
|
|
5603
|
+
const sow9 = getBitU2(b, i + 18, 8, i + 30, 12);
|
|
5604
|
+
const omegaDotP9 = getBitU(b, i + 46, 5);
|
|
5605
|
+
const omega0 = getBitS3(b, i + 51, 1, i + 60, 22, i + 90, 9) * 2 ** -31 * GPS_PI;
|
|
5606
|
+
const omegaP9 = getBitS2(b, i + 99, 13, i + 120, 14);
|
|
5607
|
+
i = 8 * 38 * 9;
|
|
5608
|
+
const pgn10 = getBitU(b, i + 42, 4);
|
|
5609
|
+
const sow10 = getBitU2(b, i + 18, 8, i + 30, 12);
|
|
5610
|
+
const omegaP10 = getBitU(b, i + 46, 5);
|
|
5611
|
+
const idot = getBitS2(b, i + 51, 1, i + 60, 13) * 2 ** -43 * GPS_PI;
|
|
5612
|
+
if (pgn1 !== 1 || pgn3 !== 3 || pgn4 !== 4 || pgn5 !== 5 || pgn6 !== 6 || pgn7 !== 7 || pgn8 !== 8 || pgn9 !== 9 || pgn10 !== 10) {
|
|
5613
|
+
return null;
|
|
5614
|
+
}
|
|
5615
|
+
if (sow3 !== sow1 + 6 || sow4 !== sow3 + 3 || sow5 !== sow4 + 3 || sow6 !== sow5 + 3 || sow7 !== sow6 + 3 || sow8 !== sow7 + 3 || sow9 !== sow8 + 3 || sow10 !== sow9 + 3) {
|
|
5616
|
+
return null;
|
|
5617
|
+
}
|
|
5618
|
+
if (tocSec !== toes) return null;
|
|
5619
|
+
return buildBdsEphemeris(opts.prn ?? "C00", {
|
|
5620
|
+
week,
|
|
5621
|
+
sow: sow1,
|
|
5622
|
+
toes,
|
|
5623
|
+
tocSec,
|
|
5624
|
+
svh,
|
|
5625
|
+
tgd1,
|
|
5626
|
+
af0,
|
|
5627
|
+
af1: mergeS(af1p3, af1p4, 18) * 2 ** -50,
|
|
5628
|
+
af2,
|
|
5629
|
+
crs,
|
|
5630
|
+
deltaN,
|
|
5631
|
+
m0,
|
|
5632
|
+
cuc: mergeS(cucp4, cucp5, 4) * 2 ** -31,
|
|
5633
|
+
e: mergeS(ep5, ep6, 22) * 2 ** -33,
|
|
5634
|
+
cus,
|
|
5635
|
+
sqrtA,
|
|
5636
|
+
cic: mergeS(cicp6, cicp7, 8) * 2 ** -31,
|
|
5637
|
+
omega0,
|
|
5638
|
+
cis,
|
|
5639
|
+
i0: mergeS(i0p7, i0p8, 11) * 2 ** -31 * GPS_PI,
|
|
5640
|
+
crc,
|
|
5641
|
+
omega: mergeS(omegaP9, omegaP10, 5) * 2 ** -31 * GPS_PI,
|
|
5642
|
+
omegaDot: mergeS(omegaDotP8, omegaDotP9, 5) * 2 ** -43 * GPS_PI,
|
|
5643
|
+
idot
|
|
5644
|
+
});
|
|
5645
|
+
}
|
|
5646
|
+
function isBdsGeoPrn(prn) {
|
|
5647
|
+
return prn < 6 || prn > 58;
|
|
5648
|
+
}
|
|
5649
|
+
var BdsAssembler = class {
|
|
5650
|
+
sats = /* @__PURE__ */ new Map();
|
|
5651
|
+
/**
|
|
5652
|
+
* Push one 300-bit subframe (38+ bytes, bit 0 = first bit of the
|
|
5653
|
+
* preamble) for the satellite `prn` ("C06"). Returns the newly
|
|
5654
|
+
* completed ephemeris, or null.
|
|
5655
|
+
*/
|
|
5656
|
+
push(prn, subframe) {
|
|
5657
|
+
if (subframe.length < BDS_SUBFRAME_BYTES) return null;
|
|
5658
|
+
const num = parseInt(prn.slice(1), 10);
|
|
5659
|
+
if (!Number.isFinite(num) || num < 1 || num > 63) return null;
|
|
5660
|
+
const id = getBitU(subframe, 15, 3);
|
|
5661
|
+
if (id < 1 || id > 5) return null;
|
|
5662
|
+
let sat = this.sats.get(prn);
|
|
5663
|
+
if (!sat) {
|
|
5664
|
+
sat = { buf: new Uint8Array(10 * BDS_SUBFRAME_BYTES) };
|
|
5665
|
+
this.sats.set(prn, sat);
|
|
5666
|
+
}
|
|
5667
|
+
let eph = null;
|
|
5668
|
+
if (!isBdsGeoPrn(num)) {
|
|
5669
|
+
sat.buf.set(subframe.subarray(0, BDS_SUBFRAME_BYTES), (id - 1) * 38);
|
|
5670
|
+
if (id === 3) eph = decodeBdsD1Frame(sat.buf, { prn });
|
|
5671
|
+
} else {
|
|
5672
|
+
if (id !== 1) return null;
|
|
5673
|
+
const pgn = getBitU(subframe, 42, 4);
|
|
5674
|
+
if (pgn < 1 || pgn > 10) return null;
|
|
5675
|
+
sat.buf.set(subframe.subarray(0, BDS_SUBFRAME_BYTES), (pgn - 1) * 38);
|
|
5676
|
+
if (pgn === 10) eph = decodeBdsD2Frame(sat.buf, { prn });
|
|
5677
|
+
}
|
|
5678
|
+
if (!eph) return null;
|
|
5679
|
+
const key = `${eph.week}:${eph.toe}`;
|
|
5680
|
+
if (key === sat.lastKey) return null;
|
|
5681
|
+
sat.lastKey = key;
|
|
5682
|
+
return eph;
|
|
5683
|
+
}
|
|
5684
|
+
};
|
|
5685
|
+
|
|
5686
|
+
// src/navbits/gal.ts
|
|
5687
|
+
var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
|
|
5688
|
+
var SEC_PER_WEEK5 = 7 * 86400;
|
|
5689
|
+
var HALF_WEEK3 = 302400;
|
|
5690
|
+
var GST_GPS_WEEK_OFFSET = 1024;
|
|
5691
|
+
function galInavPageCrcOk(page) {
|
|
5692
|
+
if (page.length < 28) return false;
|
|
5693
|
+
return crc24q(page, 196) === getBitU(page, 196, 24);
|
|
5694
|
+
}
|
|
5695
|
+
function galFnavPageCrcOk(page) {
|
|
5696
|
+
if (page.length < 30) return false;
|
|
5697
|
+
return crc24q(page, 214) === getBitU(page, 214, 24);
|
|
5698
|
+
}
|
|
5699
|
+
function gpsDate2(week, sec) {
|
|
5700
|
+
return new Date(GPS_EPOCH_MS4 + (week * SEC_PER_WEEK5 + sec) * 1e3);
|
|
5701
|
+
}
|
|
5702
|
+
function weekOfToe(week, tow, toe) {
|
|
5703
|
+
if (toe - tow > HALF_WEEK3) return week - 1;
|
|
5704
|
+
if (toe - tow < -HALF_WEEK3) return week + 1;
|
|
5705
|
+
return week;
|
|
5706
|
+
}
|
|
5707
|
+
var two = (n) => String(n).padStart(2, "0");
|
|
5708
|
+
function decodeGalInavWords(words) {
|
|
5709
|
+
if (words.length < 96) return null;
|
|
5710
|
+
const b = words;
|
|
5711
|
+
let i = 128;
|
|
5712
|
+
const type1 = getBitU(b, i, 6);
|
|
5713
|
+
i += 6;
|
|
5714
|
+
const iodNav1 = getBitU(b, i, 10);
|
|
5715
|
+
i += 10;
|
|
5716
|
+
const toes = getBitU(b, i, 14) * 60;
|
|
5717
|
+
i += 14;
|
|
5718
|
+
const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
5719
|
+
i += 32;
|
|
5720
|
+
const e = getBitU(b, i, 32) * 2 ** -33;
|
|
5721
|
+
i += 32;
|
|
5722
|
+
const sqrtA = getBitU(b, i, 32) * 2 ** -19;
|
|
5723
|
+
i = 128 * 2;
|
|
5724
|
+
const type2 = getBitU(b, i, 6);
|
|
5725
|
+
i += 6;
|
|
5726
|
+
const iodNav2 = getBitU(b, i, 10);
|
|
5727
|
+
i += 10;
|
|
5728
|
+
const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
5729
|
+
i += 32;
|
|
5730
|
+
const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
5731
|
+
i += 32;
|
|
5732
|
+
const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
5733
|
+
i += 32;
|
|
5734
|
+
const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
|
|
5735
|
+
i = 128 * 3;
|
|
5736
|
+
const type3 = getBitU(b, i, 6);
|
|
5737
|
+
i += 6;
|
|
5738
|
+
const iodNav3 = getBitU(b, i, 10);
|
|
5739
|
+
i += 10;
|
|
5740
|
+
const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
|
|
5741
|
+
i += 24;
|
|
5742
|
+
const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
|
|
5743
|
+
i += 16;
|
|
5744
|
+
const cuc = getBitS(b, i, 16) * 2 ** -29;
|
|
5745
|
+
i += 16;
|
|
5746
|
+
const cus = getBitS(b, i, 16) * 2 ** -29;
|
|
5747
|
+
i += 16;
|
|
5748
|
+
const crc = getBitS(b, i, 16) * 2 ** -5;
|
|
5749
|
+
i += 16;
|
|
5750
|
+
const crs = getBitS(b, i, 16) * 2 ** -5;
|
|
5751
|
+
i = 128 * 4;
|
|
5752
|
+
const type4 = getBitU(b, i, 6);
|
|
5753
|
+
i += 6;
|
|
5754
|
+
const iodNav4 = getBitU(b, i, 10);
|
|
5755
|
+
i += 10;
|
|
5756
|
+
const svid = getBitU(b, i, 6);
|
|
5757
|
+
i += 6;
|
|
5758
|
+
const cic = getBitS(b, i, 16) * 2 ** -29;
|
|
5759
|
+
i += 16;
|
|
5760
|
+
const cis = getBitS(b, i, 16) * 2 ** -29;
|
|
5761
|
+
i += 16;
|
|
5762
|
+
const tocs = getBitU(b, i, 14) * 60;
|
|
5763
|
+
i += 14;
|
|
5764
|
+
const af0 = getBitS(b, i, 31) * 2 ** -34;
|
|
5765
|
+
i += 31;
|
|
5766
|
+
const af1 = getBitS(b, i, 21) * 2 ** -46;
|
|
5767
|
+
i += 21;
|
|
5768
|
+
const af2 = getBitS(b, i, 6) * 2 ** -59;
|
|
5769
|
+
i = 128 * 5;
|
|
5770
|
+
const type5 = getBitU(b, i, 6);
|
|
5771
|
+
i += 6 + 11 + 11 + 14 + 5;
|
|
5772
|
+
const bgdE5a = getBitS(b, i, 10) * 2 ** -32;
|
|
5773
|
+
i += 10;
|
|
5774
|
+
i += 10;
|
|
5775
|
+
const e5bHs = getBitU(b, i, 2);
|
|
5776
|
+
i += 2;
|
|
5777
|
+
const e1bHs = getBitU(b, i, 2);
|
|
5778
|
+
i += 2;
|
|
5779
|
+
const e5bDvs = getBitU(b, i, 1);
|
|
5780
|
+
i += 1;
|
|
5781
|
+
const e1bDvs = getBitU(b, i, 1);
|
|
5782
|
+
i += 1;
|
|
5783
|
+
const gstWeek = getBitU(b, i, 12);
|
|
5784
|
+
i += 12;
|
|
5785
|
+
const tow = getBitU(b, i, 20);
|
|
5786
|
+
if (type1 !== 1 || type2 !== 2 || type3 !== 3 || type4 !== 4 || type5 !== 5)
|
|
5787
|
+
return null;
|
|
5788
|
+
if (iodNav1 !== iodNav2 || iodNav1 !== iodNav3 || iodNav1 !== iodNav4)
|
|
5789
|
+
return null;
|
|
5790
|
+
if (svid < 1 || svid > 36) return null;
|
|
5791
|
+
const week = weekOfToe(gstWeek, tow, toes) + GST_GPS_WEEK_OFFSET;
|
|
5792
|
+
const tocDate = gpsDate2(week, tocs);
|
|
5636
5793
|
return {
|
|
5637
5794
|
system: "E",
|
|
5638
|
-
prn: `E${
|
|
5639
|
-
toc:
|
|
5795
|
+
prn: `E${two(svid)}`,
|
|
5796
|
+
toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK5,
|
|
5640
5797
|
tocDate,
|
|
5641
|
-
af0
|
|
5642
|
-
af1
|
|
5643
|
-
af2
|
|
5644
|
-
iode:
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
sqrtA: view.getFloat64(b + 16, true),
|
|
5798
|
+
af0,
|
|
5799
|
+
af1,
|
|
5800
|
+
af2,
|
|
5801
|
+
iode: iodNav1,
|
|
5802
|
+
crs,
|
|
5803
|
+
deltaN,
|
|
5804
|
+
m0,
|
|
5805
|
+
cuc,
|
|
5806
|
+
e,
|
|
5807
|
+
cus,
|
|
5808
|
+
sqrtA,
|
|
5653
5809
|
toe: toes,
|
|
5654
|
-
cic
|
|
5655
|
-
omega0
|
|
5656
|
-
cis
|
|
5657
|
-
i0
|
|
5658
|
-
crc
|
|
5659
|
-
omega
|
|
5660
|
-
omegaDot
|
|
5661
|
-
idot
|
|
5662
|
-
week
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
tgd: bgdE5a !== F4_DNU ? bgdE5a : 0
|
|
5666
|
-
// BGD E5a/E1 (RINEX slot)
|
|
5810
|
+
cic,
|
|
5811
|
+
omega0,
|
|
5812
|
+
cis,
|
|
5813
|
+
i0,
|
|
5814
|
+
crc,
|
|
5815
|
+
omega,
|
|
5816
|
+
omegaDot,
|
|
5817
|
+
idot,
|
|
5818
|
+
week,
|
|
5819
|
+
svHealth: e5bHs << 7 | e5bDvs << 6 | e1bHs << 1 | e1bDvs,
|
|
5820
|
+
tgd: bgdE5a
|
|
5667
5821
|
};
|
|
5668
5822
|
}
|
|
5669
|
-
function
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
const
|
|
5674
|
-
|
|
5675
|
-
const
|
|
5676
|
-
|
|
5677
|
-
const
|
|
5678
|
-
|
|
5823
|
+
function decodeGalFnavPages(pages) {
|
|
5824
|
+
if (pages.length < 124) return null;
|
|
5825
|
+
const b = pages;
|
|
5826
|
+
let i = 0;
|
|
5827
|
+
const type1 = getBitU(b, i, 6);
|
|
5828
|
+
i += 6;
|
|
5829
|
+
const svid = getBitU(b, i, 6);
|
|
5830
|
+
i += 6;
|
|
5831
|
+
const iodNav1 = getBitU(b, i, 10);
|
|
5832
|
+
i += 10;
|
|
5833
|
+
const tocs = getBitU(b, i, 14) * 60;
|
|
5834
|
+
i += 14;
|
|
5835
|
+
const af0 = getBitS(b, i, 31) * 2 ** -34;
|
|
5836
|
+
i += 31;
|
|
5837
|
+
const af1 = getBitS(b, i, 21) * 2 ** -46;
|
|
5838
|
+
i += 21;
|
|
5839
|
+
const af2 = getBitS(b, i, 6) * 2 ** -59;
|
|
5840
|
+
i += 6;
|
|
5841
|
+
i += 8 + 11 + 11 + 14 + 5;
|
|
5842
|
+
const bgdE5a = getBitS(b, i, 10) * 2 ** -32;
|
|
5843
|
+
i += 10;
|
|
5844
|
+
const e5aHs = getBitU(b, i, 2);
|
|
5845
|
+
i += 2;
|
|
5846
|
+
const gstWeek = getBitU(b, i, 12);
|
|
5847
|
+
i += 12;
|
|
5848
|
+
const tow = getBitU(b, i, 20);
|
|
5849
|
+
i += 20;
|
|
5850
|
+
const e5aDvs = getBitU(b, i, 1);
|
|
5851
|
+
i = 31 * 8;
|
|
5852
|
+
const type2 = getBitU(b, i, 6);
|
|
5853
|
+
i += 6;
|
|
5854
|
+
const iodNav2 = getBitU(b, i, 10);
|
|
5855
|
+
i += 10;
|
|
5856
|
+
const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
5857
|
+
i += 32;
|
|
5858
|
+
const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
|
|
5859
|
+
i += 24;
|
|
5860
|
+
const e = getBitU(b, i, 32) * 2 ** -33;
|
|
5861
|
+
i += 32;
|
|
5862
|
+
const sqrtA = getBitU(b, i, 32) * 2 ** -19;
|
|
5863
|
+
i += 32;
|
|
5864
|
+
const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
5865
|
+
i += 32;
|
|
5866
|
+
const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
|
|
5867
|
+
i = 62 * 8;
|
|
5868
|
+
const type3 = getBitU(b, i, 6);
|
|
5869
|
+
i += 6;
|
|
5870
|
+
const iodNav3 = getBitU(b, i, 10);
|
|
5871
|
+
i += 10;
|
|
5872
|
+
const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
5873
|
+
i += 32;
|
|
5874
|
+
const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
5875
|
+
i += 32;
|
|
5876
|
+
const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
|
|
5877
|
+
i += 16;
|
|
5878
|
+
const cuc = getBitS(b, i, 16) * 2 ** -29;
|
|
5879
|
+
i += 16;
|
|
5880
|
+
const cus = getBitS(b, i, 16) * 2 ** -29;
|
|
5881
|
+
i += 16;
|
|
5882
|
+
const crc = getBitS(b, i, 16) * 2 ** -5;
|
|
5883
|
+
i += 16;
|
|
5884
|
+
const crs = getBitS(b, i, 16) * 2 ** -5;
|
|
5885
|
+
i += 16;
|
|
5886
|
+
const toes = getBitU(b, i, 14) * 60;
|
|
5887
|
+
i = 93 * 8;
|
|
5888
|
+
const type4 = getBitU(b, i, 6);
|
|
5889
|
+
i += 6;
|
|
5890
|
+
const iodNav4 = getBitU(b, i, 10);
|
|
5891
|
+
i += 10;
|
|
5892
|
+
const cic = getBitS(b, i, 16) * 2 ** -29;
|
|
5893
|
+
i += 16;
|
|
5894
|
+
const cis = getBitS(b, i, 16) * 2 ** -29;
|
|
5895
|
+
if (type1 !== 1 || type2 !== 2 || type3 !== 3 || type4 !== 4) return null;
|
|
5896
|
+
if (iodNav1 !== iodNav2 || iodNav1 !== iodNav3 || iodNav1 !== iodNav4)
|
|
5897
|
+
return null;
|
|
5898
|
+
if (svid < 1 || svid > 36) return null;
|
|
5899
|
+
const week = weekOfToe(gstWeek, tow, toes) + GST_GPS_WEEK_OFFSET;
|
|
5900
|
+
const tocDate = gpsDate2(week, tocs);
|
|
5679
5901
|
return {
|
|
5680
|
-
system: "
|
|
5681
|
-
prn
|
|
5682
|
-
toc:
|
|
5902
|
+
system: "E",
|
|
5903
|
+
prn: `E${two(svid)}`,
|
|
5904
|
+
toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK5,
|
|
5683
5905
|
tocDate,
|
|
5684
|
-
af0
|
|
5685
|
-
af1
|
|
5686
|
-
af2
|
|
5687
|
-
iode:
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
sqrtA: view.getFloat64(b + 80, true),
|
|
5906
|
+
af0,
|
|
5907
|
+
af1,
|
|
5908
|
+
af2,
|
|
5909
|
+
iode: iodNav1,
|
|
5910
|
+
crs,
|
|
5911
|
+
deltaN,
|
|
5912
|
+
m0,
|
|
5913
|
+
cuc,
|
|
5914
|
+
e,
|
|
5915
|
+
cus,
|
|
5916
|
+
sqrtA,
|
|
5696
5917
|
toe: toes,
|
|
5697
|
-
cic
|
|
5698
|
-
omega0
|
|
5699
|
-
cis
|
|
5700
|
-
i0
|
|
5701
|
-
crc
|
|
5702
|
-
omega
|
|
5703
|
-
omegaDot
|
|
5704
|
-
idot
|
|
5705
|
-
week
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
// SatH1
|
|
5709
|
-
tgd: tgd1 !== F4_DNU ? tgd1 : 0
|
|
5710
|
-
// TGD1 B1/B3 (RINEX slot)
|
|
5918
|
+
cic,
|
|
5919
|
+
omega0,
|
|
5920
|
+
cis,
|
|
5921
|
+
i0,
|
|
5922
|
+
crc,
|
|
5923
|
+
omega,
|
|
5924
|
+
omegaDot,
|
|
5925
|
+
idot,
|
|
5926
|
+
week,
|
|
5927
|
+
svHealth: e5aHs << 4 | e5aDvs << 3,
|
|
5928
|
+
tgd: bgdE5a
|
|
5711
5929
|
};
|
|
5712
5930
|
}
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5931
|
+
var dedupKey = (eph) => `${eph.iode}:${eph.toe}:${eph.tocDate.getTime()}`;
|
|
5932
|
+
var GalInavAssembler = class {
|
|
5933
|
+
sats = /* @__PURE__ */ new Map();
|
|
5934
|
+
/**
|
|
5935
|
+
* Push one I/NAV page pair for satellite `prn` (1-36): the 234-bit
|
|
5936
|
+
* even+odd concatenation, even part first with its 6 tail bits
|
|
5937
|
+
* removed, bit 0 = the even part's Even/Odd bit (≥ 17 bytes).
|
|
5938
|
+
* Returns the newly completed ephemeris, or null. Pages that are
|
|
5939
|
+
* not an even/odd nominal pair, alert pages and word types outside
|
|
5940
|
+
* 1-5 are ignored.
|
|
5941
|
+
*/
|
|
5942
|
+
push(prn, page) {
|
|
5943
|
+
if (prn < 1 || prn > 36 || page.length < 17) return null;
|
|
5944
|
+
if (getBitU(page, 0, 1) !== 0 || getBitU(page, 114, 1) !== 1) return null;
|
|
5945
|
+
if (getBitU(page, 1, 1) === 1 || getBitU(page, 115, 1) === 1) return null;
|
|
5946
|
+
const type = getBitU(page, 2, 6);
|
|
5947
|
+
if (type < 1 || type > 5) return null;
|
|
5948
|
+
let sat = this.sats.get(prn);
|
|
5949
|
+
if (!sat) {
|
|
5950
|
+
sat = { words: new Uint8Array(96) };
|
|
5951
|
+
this.sats.set(prn, sat);
|
|
5952
|
+
}
|
|
5953
|
+
for (let k = 0; k < 14; k++)
|
|
5954
|
+
sat.words[type * 16 + k] = getBitU(page, 2 + 8 * k, 8);
|
|
5955
|
+
sat.words[type * 16 + 14] = getBitU(page, 116, 8);
|
|
5956
|
+
sat.words[type * 16 + 15] = getBitU(page, 124, 8);
|
|
5957
|
+
if (type !== 5) return null;
|
|
5958
|
+
const eph = decodeGalInavWords(sat.words);
|
|
5959
|
+
if (!eph || eph.prn !== `E${two(prn)}`) return null;
|
|
5960
|
+
const key = dedupKey(eph);
|
|
5961
|
+
if (key === sat.lastKey) return null;
|
|
5962
|
+
sat.lastKey = key;
|
|
5963
|
+
return eph;
|
|
5964
|
+
}
|
|
5965
|
+
};
|
|
5966
|
+
var GalFnavAssembler = class {
|
|
5967
|
+
sats = /* @__PURE__ */ new Map();
|
|
5968
|
+
/**
|
|
5969
|
+
* Push one F/NAV page for satellite `prn` (1-36): 244 bits with the
|
|
5970
|
+
* sync field stripped, bit 0 = first page-type bit (≥ 31 bytes).
|
|
5971
|
+
* Returns the newly completed ephemeris, or null. Dummy pages
|
|
5972
|
+
* (type 63) and page types outside 1-4 are ignored.
|
|
5973
|
+
*/
|
|
5974
|
+
push(prn, page) {
|
|
5975
|
+
if (prn < 1 || prn > 36 || page.length < 31) return null;
|
|
5976
|
+
const type = getBitU(page, 0, 6);
|
|
5977
|
+
if (type < 1 || type > 4) return null;
|
|
5978
|
+
let sat = this.sats.get(prn);
|
|
5979
|
+
if (!sat) {
|
|
5980
|
+
sat = { words: new Uint8Array(124) };
|
|
5981
|
+
this.sats.set(prn, sat);
|
|
5982
|
+
}
|
|
5983
|
+
sat.words.set(page.subarray(0, 31), (type - 1) * 31);
|
|
5984
|
+
if (type !== 4) return null;
|
|
5985
|
+
const eph = decodeGalFnavPages(sat.words);
|
|
5986
|
+
if (!eph || eph.prn !== `E${two(prn)}`) return null;
|
|
5987
|
+
const key = dedupKey(eph);
|
|
5988
|
+
if (key === sat.lastKey) return null;
|
|
5989
|
+
sat.lastKey = key;
|
|
5990
|
+
return eph;
|
|
5991
|
+
}
|
|
5992
|
+
};
|
|
5993
|
+
|
|
5994
|
+
// src/navbits/glo.ts
|
|
5995
|
+
var GPS_EPOCH_MS5 = Date.UTC(1980, 0, 6);
|
|
5996
|
+
var SEC_PER_WEEK6 = 7 * 86400;
|
|
5997
|
+
var SEC_PER_DAY = 86400;
|
|
5998
|
+
var GLO_STRING_BYTES = 10;
|
|
5999
|
+
function getBitG(b, pos, len) {
|
|
6000
|
+
const value = getBitU(b, pos + 1, len - 1);
|
|
6001
|
+
return getBitU(b, pos, 1) && value !== 0 ? -value : value;
|
|
6002
|
+
}
|
|
6003
|
+
var HAMMING_MASKS = [
|
|
6004
|
+
[85, 85, 90, 170, 170, 170, 181, 85, 106, 216, 8],
|
|
6005
|
+
[102, 102, 108, 204, 204, 204, 217, 153, 179, 104, 16],
|
|
6006
|
+
[135, 135, 143, 15, 15, 15, 30, 30, 60, 112, 32],
|
|
6007
|
+
[7, 248, 15, 240, 15, 240, 31, 224, 63, 128, 64],
|
|
6008
|
+
[248, 0, 15, 255, 240, 0, 31, 255, 192, 0, 128],
|
|
6009
|
+
[0, 0, 15, 255, 255, 255, 224, 0, 0, 1, 0],
|
|
6010
|
+
[255, 255, 240, 0, 0, 0, 0, 0, 0, 2, 0],
|
|
6011
|
+
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 248]
|
|
6012
|
+
];
|
|
6013
|
+
function testGloString(buff) {
|
|
6014
|
+
if (buff.length < 11) return false;
|
|
6015
|
+
let n = 0;
|
|
6016
|
+
let cs = 0;
|
|
6017
|
+
for (const mask of HAMMING_MASKS) {
|
|
6018
|
+
cs = 0;
|
|
6019
|
+
for (let j = 0; j < 11; j++) {
|
|
6020
|
+
let x = buff[j] & mask[j];
|
|
6021
|
+
x ^= x >> 4;
|
|
6022
|
+
x ^= x >> 2;
|
|
6023
|
+
x ^= x >> 1;
|
|
6024
|
+
cs ^= x & 1;
|
|
6025
|
+
}
|
|
6026
|
+
if (cs) n++;
|
|
6027
|
+
}
|
|
6028
|
+
return n === 0 || n === 2 && cs === 1;
|
|
6029
|
+
}
|
|
6030
|
+
function decodeGloStrings(strings, refDate, opts = {}) {
|
|
6031
|
+
if (strings.length < 4 * GLO_STRING_BYTES) return null;
|
|
6032
|
+
const b = strings;
|
|
6033
|
+
let i = 1;
|
|
6034
|
+
const frn1 = getBitU(b, i, 4);
|
|
6035
|
+
i += 4 + 2;
|
|
6036
|
+
i += 2;
|
|
6037
|
+
const tkH = getBitU(b, i, 5);
|
|
6038
|
+
i += 5;
|
|
6039
|
+
const tkM = getBitU(b, i, 6);
|
|
6040
|
+
i += 6;
|
|
6041
|
+
const tkS = getBitU(b, i, 1) * 30;
|
|
6042
|
+
i += 1;
|
|
6043
|
+
const xDot = getBitG(b, i, 24) * 2 ** -20;
|
|
6044
|
+
i += 24;
|
|
6045
|
+
const xAcc = getBitG(b, i, 5) * 2 ** -30;
|
|
6046
|
+
i += 5;
|
|
6047
|
+
const x = getBitG(b, i, 27) * 2 ** -11;
|
|
6048
|
+
i = 80 + 1;
|
|
6049
|
+
const frn2 = getBitU(b, i, 4);
|
|
6050
|
+
i += 4;
|
|
6051
|
+
const bn = getBitU(b, i, 1);
|
|
6052
|
+
i += 1 + 2;
|
|
6053
|
+
i += 1;
|
|
6054
|
+
const tb = getBitU(b, i, 7);
|
|
6055
|
+
i += 7 + 5;
|
|
6056
|
+
const yDot = getBitG(b, i, 24) * 2 ** -20;
|
|
6057
|
+
i += 24;
|
|
6058
|
+
const yAcc = getBitG(b, i, 5) * 2 ** -30;
|
|
6059
|
+
i += 5;
|
|
6060
|
+
const y = getBitG(b, i, 27) * 2 ** -11;
|
|
6061
|
+
i = 160 + 1;
|
|
6062
|
+
const frn3 = getBitU(b, i, 4);
|
|
6063
|
+
i += 4;
|
|
6064
|
+
i += 1;
|
|
6065
|
+
const gammaN = getBitG(b, i, 11) * 2 ** -40;
|
|
6066
|
+
i += 11 + 1;
|
|
6067
|
+
i += 2;
|
|
6068
|
+
i += 1;
|
|
6069
|
+
const zDot = getBitG(b, i, 24) * 2 ** -20;
|
|
6070
|
+
i += 24;
|
|
6071
|
+
const zAcc = getBitG(b, i, 5) * 2 ** -30;
|
|
6072
|
+
i += 5;
|
|
6073
|
+
const z = getBitG(b, i, 27) * 2 ** -11;
|
|
6074
|
+
i = 240 + 1;
|
|
6075
|
+
const frn4 = getBitU(b, i, 4);
|
|
6076
|
+
i += 4;
|
|
6077
|
+
const tauN = getBitG(b, i, 22) * 2 ** -30;
|
|
6078
|
+
i += 22;
|
|
6079
|
+
i += 5;
|
|
6080
|
+
i += 5;
|
|
6081
|
+
i += 14;
|
|
6082
|
+
i += 1;
|
|
6083
|
+
i += 4;
|
|
6084
|
+
i += 3;
|
|
6085
|
+
i += 11;
|
|
6086
|
+
const slot = getBitU(b, i, 5);
|
|
6087
|
+
if (frn1 !== 1 || frn2 !== 2 || frn3 !== 3 || frn4 !== 4) return null;
|
|
6088
|
+
if (slot < 1 || slot > 27) return null;
|
|
6089
|
+
const utcSec = (getUtcDate(refDate).getTime() - GPS_EPOCH_MS5) / 1e3;
|
|
6090
|
+
const week = Math.floor(utcSec / SEC_PER_WEEK6);
|
|
6091
|
+
let tow = utcSec - week * SEC_PER_WEEK6;
|
|
6092
|
+
const tod = tow % SEC_PER_DAY;
|
|
6093
|
+
tow -= tod;
|
|
6094
|
+
let tof = tkH * 3600 + tkM * 60 + tkS - 10800;
|
|
6095
|
+
if (tof < tod - 43200) tof += SEC_PER_DAY;
|
|
6096
|
+
else if (tof > tod + 43200) tof -= SEC_PER_DAY;
|
|
6097
|
+
let toe = tb * 900 - 10800;
|
|
6098
|
+
if (toe < tod - 43200) toe += SEC_PER_DAY;
|
|
6099
|
+
else if (toe > tod + 43200) toe -= SEC_PER_DAY;
|
|
5725
6100
|
return {
|
|
5726
6101
|
system: "R",
|
|
5727
|
-
prn,
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
tauN: -
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
6102
|
+
prn: `R${String(slot).padStart(2, "0")}`,
|
|
6103
|
+
// RINEX GLONASS epochs are UTC: build the UTC toe Date directly.
|
|
6104
|
+
tocDate: new Date(GPS_EPOCH_MS5 + (week * SEC_PER_WEEK6 + tow + toe) * 1e3),
|
|
6105
|
+
tauN: -tauN,
|
|
6106
|
+
// RINEX stores −τn; the SIS carries τn (ICD sign)
|
|
6107
|
+
gammaN,
|
|
6108
|
+
// v3 message frame time: seconds of the UTC week (RTKLIB tof).
|
|
6109
|
+
messageFrameTime: ((tow + tof) % SEC_PER_WEEK6 + SEC_PER_WEEK6) % SEC_PER_WEEK6,
|
|
6110
|
+
x,
|
|
6111
|
+
xDot,
|
|
6112
|
+
xAcc,
|
|
6113
|
+
y,
|
|
6114
|
+
yDot,
|
|
6115
|
+
yAcc,
|
|
6116
|
+
z,
|
|
6117
|
+
zDot,
|
|
6118
|
+
zAcc,
|
|
5743
6119
|
// MSB of the 3-bit Bn word — the unhealthy flag RINEX carries
|
|
5744
|
-
health:
|
|
5745
|
-
freqNum:
|
|
6120
|
+
health: bn,
|
|
6121
|
+
freqNum: opts.freqNum ?? 0
|
|
5746
6122
|
};
|
|
5747
6123
|
}
|
|
5748
|
-
|
|
6124
|
+
var GloStringAssembler = class {
|
|
6125
|
+
sats = /* @__PURE__ */ new Map();
|
|
6126
|
+
/**
|
|
6127
|
+
* Push one navigation string (10+ bytes, bit 0 = string bit 85) for
|
|
6128
|
+
* the satellite `prn` ("R09"), received at the GPS-scale `time`.
|
|
6129
|
+
* Returns the newly completed ephemeris, or null. The decoded
|
|
6130
|
+
* string-4 slot number must match `prn`, or nothing is emitted.
|
|
6131
|
+
*/
|
|
6132
|
+
push(prn, str, time, freqNum = 0) {
|
|
6133
|
+
if (str.length < GLO_STRING_BYTES) return null;
|
|
6134
|
+
const m = getBitU(str, 1, 4);
|
|
6135
|
+
if (m < 1) return null;
|
|
6136
|
+
const sec = Math.floor(time.getTime() / 1e3);
|
|
6137
|
+
let sat = this.sats.get(prn);
|
|
6138
|
+
if (!sat) {
|
|
6139
|
+
sat = { buf: new Uint8Array(4 * GLO_STRING_BYTES), batchSec: sec };
|
|
6140
|
+
this.sats.set(prn, sat);
|
|
6141
|
+
} else if (Math.abs(sec - sat.batchSec) > 30) {
|
|
6142
|
+
sat.buf.fill(0);
|
|
6143
|
+
sat.batchSec = sec;
|
|
6144
|
+
}
|
|
6145
|
+
if (m > 4) return null;
|
|
6146
|
+
sat.buf.set(str.subarray(0, GLO_STRING_BYTES), (m - 1) * 10);
|
|
6147
|
+
if (m !== 4) return null;
|
|
6148
|
+
const eph = decodeGloStrings(sat.buf, time, { freqNum });
|
|
6149
|
+
if (!eph || eph.prn !== prn) return null;
|
|
6150
|
+
const key = `${eph.tocDate.getTime()}:${eph.health}`;
|
|
6151
|
+
if (key === sat.lastKey) return null;
|
|
6152
|
+
sat.lastKey = key;
|
|
6153
|
+
return eph;
|
|
6154
|
+
}
|
|
6155
|
+
};
|
|
6156
|
+
|
|
6157
|
+
// src/ubx/rawnav.ts
|
|
6158
|
+
var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
|
|
6159
|
+
var SEC_PER_WEEK7 = 7 * 86400;
|
|
6160
|
+
var two2 = (n) => String(n).padStart(2, "0");
|
|
6161
|
+
function parseUbxRawNav(data, opts = {}) {
|
|
5749
6162
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
5750
6163
|
const ephemerides = [];
|
|
5751
|
-
const
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
if (
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
6164
|
+
const counts = { gal: 0, bds: 0, glo: 0 };
|
|
6165
|
+
let badParity = 0;
|
|
6166
|
+
const inav = new GalInavAssembler();
|
|
6167
|
+
const bds = new BdsAssembler();
|
|
6168
|
+
const glo = new GloStringAssembler();
|
|
6169
|
+
let refDate = null;
|
|
6170
|
+
for (const f of ubxFrames(data)) {
|
|
6171
|
+
if (f.msgClass !== 2) continue;
|
|
6172
|
+
if (f.msgId === 21 && f.payload.length >= 16) {
|
|
6173
|
+
const rcvTow = view.getFloat64(f.payloadStart, true);
|
|
6174
|
+
let week = view.getUint16(f.payloadStart + 8, true);
|
|
6175
|
+
if (week === 0 && opts.refWeek !== void 0) week = opts.refWeek;
|
|
6176
|
+
if (week > 0) {
|
|
6177
|
+
refDate = new Date(
|
|
6178
|
+
GPS_EPOCH_MS6 + (week * SEC_PER_WEEK7 + rcvTow) * 1e3
|
|
6179
|
+
);
|
|
6180
|
+
}
|
|
6181
|
+
continue;
|
|
6182
|
+
}
|
|
6183
|
+
if (f.msgId !== 19) continue;
|
|
6184
|
+
const p = f.payload;
|
|
6185
|
+
if (p.length < 8) continue;
|
|
6186
|
+
const gnssId = p[0];
|
|
6187
|
+
const svId = p[1];
|
|
6188
|
+
const sigId = p[2];
|
|
6189
|
+
const base = f.payloadStart + 8;
|
|
6190
|
+
if (gnssId === 2) {
|
|
6191
|
+
if (sigId === 3 || sigId === 8) continue;
|
|
6192
|
+
if (p.length < 8 + 32) continue;
|
|
6193
|
+
counts.gal++;
|
|
6194
|
+
if (svId < 1 || svId > 36) continue;
|
|
6195
|
+
const buff = new Uint8Array(32);
|
|
6196
|
+
for (let k = 0; k < 8; k++) {
|
|
6197
|
+
const w = view.getUint32(base + 4 * k, true);
|
|
6198
|
+
buff[4 * k] = w >>> 24;
|
|
6199
|
+
buff[4 * k + 1] = w >>> 16 & 255;
|
|
6200
|
+
buff[4 * k + 2] = w >>> 8 & 255;
|
|
6201
|
+
buff[4 * k + 3] = w & 255;
|
|
6202
|
+
}
|
|
6203
|
+
const page = new Uint8Array(30);
|
|
6204
|
+
for (let k = 0; k < 14; k++) page[k] = buff[k];
|
|
6205
|
+
setBitU(page, 112, 2, getBitU(buff, 112, 2));
|
|
6206
|
+
for (let k = 0; k < 15; k++) {
|
|
6207
|
+
setBitU(page, 114 + 8 * k, 8, getBitU(buff, 128 + 8 * k, 8));
|
|
6208
|
+
}
|
|
6209
|
+
if (getBitU(page, 0, 1) !== 0 || getBitU(page, 114, 1) !== 1) continue;
|
|
6210
|
+
if (getBitU(page, 1, 1) === 1 || getBitU(page, 115, 1) === 1) continue;
|
|
6211
|
+
if (!galInavPageCrcOk(page)) {
|
|
6212
|
+
badParity++;
|
|
6213
|
+
continue;
|
|
6214
|
+
}
|
|
6215
|
+
const eph = inav.push(svId, page);
|
|
6216
|
+
if (eph) ephemerides.push(eph);
|
|
6217
|
+
} else if (gnssId === 3) {
|
|
6218
|
+
if (sigId === 6 || sigId === 8) continue;
|
|
6219
|
+
if (p.length < 8 + 40) continue;
|
|
6220
|
+
counts.bds++;
|
|
6221
|
+
if (svId < 1 || svId > 63) continue;
|
|
6222
|
+
const sf = new Uint8Array(38);
|
|
6223
|
+
for (let k = 0; k < 10; k++) {
|
|
6224
|
+
const w = view.getUint32(base + 4 * k, true);
|
|
6225
|
+
setBitU(sf, 30 * k, 30, w & 1073741823);
|
|
6226
|
+
}
|
|
6227
|
+
if (!bdsSubframeParityOk(sf)) {
|
|
6228
|
+
badParity++;
|
|
6229
|
+
continue;
|
|
6230
|
+
}
|
|
6231
|
+
const eph = bds.push(`C${two2(svId)}`, sf);
|
|
6232
|
+
if (eph) ephemerides.push(eph);
|
|
6233
|
+
} else if (gnssId === 6) {
|
|
6234
|
+
if (p.length < 8 + 16) continue;
|
|
6235
|
+
counts.glo++;
|
|
6236
|
+
if (svId < 1 || svId > 32) continue;
|
|
6237
|
+
const str = new Uint8Array(16);
|
|
6238
|
+
for (let k = 0; k < 4; k++) {
|
|
6239
|
+
const w = view.getUint32(base + 4 * k, true);
|
|
6240
|
+
str[4 * k] = w >>> 24;
|
|
6241
|
+
str[4 * k + 1] = w >>> 16 & 255;
|
|
6242
|
+
str[4 * k + 2] = w >>> 8 & 255;
|
|
6243
|
+
str[4 * k + 3] = w & 255;
|
|
6244
|
+
}
|
|
6245
|
+
if (!testGloString(str)) {
|
|
6246
|
+
badParity++;
|
|
6247
|
+
continue;
|
|
6248
|
+
}
|
|
6249
|
+
if (!refDate) continue;
|
|
6250
|
+
const eph = glo.push(`R${two2(svId)}`, str, refDate, p[3] - 7);
|
|
6251
|
+
if (eph) ephemerides.push(eph);
|
|
6252
|
+
}
|
|
5787
6253
|
}
|
|
5788
|
-
return {
|
|
5789
|
-
system: sys,
|
|
5790
|
-
prn: `${sys}${String(prn).padStart(2, "0")}`,
|
|
5791
|
-
weekAlm,
|
|
5792
|
-
toaSec: toa,
|
|
5793
|
-
sqrtA,
|
|
5794
|
-
e: view.getFloat32(b + 16, true),
|
|
5795
|
-
i0OrDeltaI: i0,
|
|
5796
|
-
omega0: view.getFloat32(b + 36, true) * PI2,
|
|
5797
|
-
omega: view.getFloat32(b + 40, true) * PI2,
|
|
5798
|
-
m0: view.getFloat32(b + 44, true) * PI2,
|
|
5799
|
-
omegaDot: view.getFloat32(b + 28, true) * PI2,
|
|
5800
|
-
af0: view.getFloat32(b + 52, true),
|
|
5801
|
-
af1: view.getFloat32(b + 48, true),
|
|
5802
|
-
health
|
|
5803
|
-
};
|
|
5804
|
-
}
|
|
5805
|
-
function decodeBdsAlm(view, b) {
|
|
5806
|
-
const prnStr = svidToPrn(view.getUint8(b + 14));
|
|
5807
|
-
if (!prnStr || prnStr[0] !== "C") return null;
|
|
5808
|
-
const prn = parseInt(prnStr.slice(1), 10);
|
|
5809
|
-
const toa = view.getUint32(b + 16, true);
|
|
5810
|
-
if (toa === U4_DNU) return null;
|
|
5811
|
-
const bdsWeekRef = view.getUint16(b + 12, true) - 1356;
|
|
5812
|
-
const geo = prn <= 5 || prn >= 59;
|
|
5813
|
-
return {
|
|
5814
|
-
system: "C",
|
|
5815
|
-
prn: prnStr,
|
|
5816
|
-
weekAlm: adjustWeek(bdsWeekRef, view.getUint8(b + 15), 256),
|
|
5817
|
-
toaSec: toa,
|
|
5818
|
-
sqrtA: view.getFloat32(b + 20, true),
|
|
5819
|
-
e: view.getFloat32(b + 24, true),
|
|
5820
|
-
i0OrDeltaI: (geo ? 0 : I_REF_03) + view.getFloat32(b + 44, true) * PI2,
|
|
5821
|
-
omega0: view.getFloat32(b + 36, true) * PI2,
|
|
5822
|
-
omega: view.getFloat32(b + 28, true) * PI2,
|
|
5823
|
-
m0: view.getFloat32(b + 32, true) * PI2,
|
|
5824
|
-
omegaDot: view.getFloat32(b + 40, true) * PI2,
|
|
5825
|
-
af0: view.getFloat32(b + 48, true),
|
|
5826
|
-
af1: view.getFloat32(b + 52, true),
|
|
5827
|
-
health: view.getUint16(b + 56, true)
|
|
5828
|
-
};
|
|
5829
|
-
}
|
|
5830
|
-
function decodeGloAlm(view, b) {
|
|
5831
|
-
const prn = svidToPrn(view.getUint8(b + 14));
|
|
5832
|
-
if (!prn || prn[0] !== "R") return null;
|
|
5833
|
-
const wnc = view.getUint16(b + 12, true);
|
|
5834
|
-
const toa = view.getUint32(b + 20, true);
|
|
5835
|
-
if (toa === U4_DNU) return null;
|
|
5836
|
-
return {
|
|
5837
|
-
system: "R",
|
|
5838
|
-
prn,
|
|
5839
|
-
freqNr: view.getUint8(b + 15) - 8,
|
|
5840
|
-
weekAlm: adjustWeek(wnc, view.getUint8(b + 52), 256),
|
|
5841
|
-
toaSec: toa,
|
|
5842
|
-
epsilon: view.getFloat32(b + 16, true),
|
|
5843
|
-
deltaI: view.getFloat32(b + 24, true) * PI2,
|
|
5844
|
-
lambda: view.getFloat32(b + 28, true) * PI2,
|
|
5845
|
-
tLambda: view.getFloat32(b + 32, true),
|
|
5846
|
-
omega: view.getFloat32(b + 36, true) * PI2,
|
|
5847
|
-
deltaT: view.getFloat32(b + 40, true),
|
|
5848
|
-
deltaTDot: view.getFloat32(b + 44, true),
|
|
5849
|
-
tau: view.getFloat32(b + 48, true),
|
|
5850
|
-
health: view.getUint8(b + 53),
|
|
5851
|
-
nDay: view.getUint16(b + 54, true),
|
|
5852
|
-
n4: view.getUint8(b + 57)
|
|
5853
|
-
};
|
|
5854
|
-
}
|
|
5855
|
-
function parseSbfAlmanac(data) {
|
|
5856
|
-
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
5857
|
-
const almanacs = [];
|
|
5858
|
-
const badCrc = scanSbfFrames(data, view, (id, b, len) => {
|
|
5859
|
-
let alm = null;
|
|
5860
|
-
if (id === 5892 && len >= 60) alm = decodeGpsGalAlm(view, b, "G");
|
|
5861
|
-
else if (id === 4003 && len >= 61) alm = decodeGpsGalAlm(view, b, "E");
|
|
5862
|
-
else if (id === 4119 && len >= 60) alm = decodeBdsAlm(view, b);
|
|
5863
|
-
else if (id === 4005 && len >= 60) alm = decodeGloAlm(view, b);
|
|
5864
|
-
if (alm) almanacs.push(alm);
|
|
5865
|
-
});
|
|
5866
|
-
return { almanacs, badCrc };
|
|
6254
|
+
return { ephemerides, counts, badParity };
|
|
5867
6255
|
}
|
|
5868
6256
|
|
|
5869
|
-
// src/
|
|
5870
|
-
var
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
}
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
6257
|
+
// src/ubx/index.ts
|
|
6258
|
+
var GPS_EPOCH_MS7 = Date.UTC(1980, 0, 6);
|
|
6259
|
+
var MS_PER_WEEK3 = 7 * 864e5;
|
|
6260
|
+
var SIGNALS = {
|
|
6261
|
+
0: { 0: ["G", "1C"], 3: ["G", "2X"], 4: ["G", "2X"] },
|
|
6262
|
+
// GPS L1C/A, L2CL, L2CM
|
|
6263
|
+
1: { 0: ["S", "1C"] },
|
|
6264
|
+
// SBAS L1C/A
|
|
6265
|
+
2: { 0: ["E", "1X"], 1: ["E", "1X"], 5: ["E", "7X"], 6: ["E", "7X"] },
|
|
6266
|
+
// E1C/B, E5bI/Q
|
|
6267
|
+
3: { 0: ["C", "2I"], 1: ["C", "2I"], 2: ["C", "7I"], 3: ["C", "7I"] },
|
|
6268
|
+
// B1I D1/D2, B2I D1/D2
|
|
6269
|
+
5: { 0: ["J", "1C"], 4: ["J", "2X"], 5: ["J", "2X"] },
|
|
6270
|
+
// QZSS L1C/A, L2CM/CL
|
|
6271
|
+
6: { 0: ["R", "1C"], 2: ["R", "2C"] }
|
|
6272
|
+
// GLONASS L1OF, L2OF
|
|
6273
|
+
};
|
|
6274
|
+
function prnFor(gnssId, svId) {
|
|
6275
|
+
const two5 = (n) => String(n).padStart(2, "0");
|
|
6276
|
+
switch (gnssId) {
|
|
6277
|
+
case 0:
|
|
6278
|
+
return svId >= 1 && svId <= 32 ? `G${two5(svId)}` : null;
|
|
6279
|
+
case 1:
|
|
6280
|
+
return svId >= 120 && svId <= 158 ? `S${two5(svId - 100)}` : null;
|
|
6281
|
+
case 2:
|
|
6282
|
+
return svId >= 1 && svId <= 36 ? `E${two5(svId)}` : null;
|
|
6283
|
+
case 3:
|
|
6284
|
+
return svId >= 1 && svId <= 63 ? `C${two5(svId)}` : null;
|
|
6285
|
+
case 5:
|
|
6286
|
+
return svId >= 1 && svId <= 10 ? `J${two5(svId)}` : null;
|
|
6287
|
+
case 6:
|
|
6288
|
+
return svId >= 1 && svId <= 32 ? `R${two5(svId)}` : null;
|
|
6289
|
+
default:
|
|
6290
|
+
return null;
|
|
6291
|
+
}
|
|
6292
|
+
}
|
|
6293
|
+
function parseUbxRawx(data) {
|
|
6294
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
6295
|
+
const epochs = [];
|
|
6296
|
+
const messageCounts = {};
|
|
6297
|
+
const obsCodes = {};
|
|
6298
|
+
const stats = { badChecksums: 0 };
|
|
6299
|
+
for (const frame of ubxFrames(data, stats)) {
|
|
6300
|
+
const { msgClass: cls, msgId: id } = frame;
|
|
6301
|
+
const len = frame.payload.length;
|
|
6302
|
+
const key = `${cls.toString(16).padStart(2, "0")}-${id.toString(16).padStart(2, "0")}`;
|
|
6303
|
+
messageCounts[key] = (messageCounts[key] ?? 0) + 1;
|
|
6304
|
+
if (cls === 2 && id === 21 && len >= 16) {
|
|
6305
|
+
const p = frame.payloadStart;
|
|
6306
|
+
const rcvTow = view.getFloat64(p, true);
|
|
6307
|
+
const week = view.getUint16(p + 8, true);
|
|
6308
|
+
const leapS = view.getInt8(p + 10);
|
|
6309
|
+
const numMeas = data[p + 11];
|
|
6310
|
+
const recStat = data[p + 12];
|
|
6311
|
+
const leapValid = (recStat & 1) !== 0;
|
|
6312
|
+
const meas = [];
|
|
6313
|
+
for (let k = 0; k < numMeas; k++) {
|
|
6314
|
+
const off = p + 16 + 32 * k;
|
|
6315
|
+
if (off + 32 > p + len) break;
|
|
6316
|
+
const gnssId = data[off + 20];
|
|
6317
|
+
const svId = data[off + 21];
|
|
6318
|
+
const sigId = data[off + 22];
|
|
6319
|
+
const trkStat = data[off + 30];
|
|
6320
|
+
const prn = prnFor(gnssId, svId);
|
|
6321
|
+
const sig = SIGNALS[gnssId]?.[sigId];
|
|
6322
|
+
if (!prn || !sig) continue;
|
|
6323
|
+
const prValid = (trkStat & 1) !== 0;
|
|
6324
|
+
const cpValid = (trkStat & 2) !== 0;
|
|
6325
|
+
const cp = view.getFloat64(off + 8, true);
|
|
6326
|
+
meas.push({
|
|
6327
|
+
prn,
|
|
6328
|
+
code: sig[1],
|
|
6329
|
+
pr: prValid ? view.getFloat64(off, true) : null,
|
|
6330
|
+
cp: cpValid && cp !== 0 ? cp : null,
|
|
6331
|
+
doppler: view.getFloat32(off + 16, true),
|
|
6332
|
+
cn0: data[off + 26],
|
|
6333
|
+
halfCycleAmbiguous: (trkStat & 4) !== 0,
|
|
6334
|
+
lockTimeMs: view.getUint16(off + 24, true)
|
|
6335
|
+
});
|
|
6336
|
+
const sys = sig[0];
|
|
6337
|
+
const codes = obsCodes[sys] ??= [];
|
|
6338
|
+
if (!codes.includes(sig[1])) codes.push(sig[1]);
|
|
6339
|
+
}
|
|
6340
|
+
epochs.push({
|
|
6341
|
+
timeMs: GPS_EPOCH_MS7 + week * MS_PER_WEEK3 + Math.round(rcvTow * 1e3),
|
|
6342
|
+
leapS: leapValid ? leapS : null,
|
|
6343
|
+
meas
|
|
6344
|
+
});
|
|
5897
6345
|
}
|
|
5898
|
-
}
|
|
5899
|
-
return {
|
|
6346
|
+
}
|
|
6347
|
+
return { epochs, messageCounts, obsCodes, badChecksums: stats.badChecksums };
|
|
5900
6348
|
}
|
|
5901
6349
|
|
|
5902
|
-
// src/sbf/
|
|
5903
|
-
var
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
6350
|
+
// src/sbf/frame.ts
|
|
6351
|
+
var CRC_TABLE = (() => {
|
|
6352
|
+
const t = new Uint16Array(256);
|
|
6353
|
+
for (let n = 0; n < 256; n++) {
|
|
6354
|
+
let c = n << 8;
|
|
6355
|
+
for (let k = 0; k < 8; k++)
|
|
6356
|
+
c = c & 32768 ? (c << 1 ^ 4129) & 65535 : c << 1 & 65535;
|
|
6357
|
+
t[n] = c;
|
|
6358
|
+
}
|
|
6359
|
+
return t;
|
|
6360
|
+
})();
|
|
6361
|
+
function crc16(data, start, end) {
|
|
6362
|
+
let crc = 0;
|
|
6363
|
+
for (let i = start; i < end; i++)
|
|
6364
|
+
crc = (crc << 8 ^ CRC_TABLE[(crc >> 8 ^ data[i]) & 255]) & 65535;
|
|
6365
|
+
return crc;
|
|
6366
|
+
}
|
|
6367
|
+
function scanSbfFrames(data, view, onBlock) {
|
|
5914
6368
|
let badCrc = 0;
|
|
5915
|
-
let
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
const msg = new Uint8Array(40);
|
|
5921
|
-
for (let k = 0; k < 10; k++) {
|
|
5922
|
-
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
5923
|
-
msg[4 * k] = w >>> 24;
|
|
5924
|
-
msg[4 * k + 1] = w >>> 16 & 255;
|
|
5925
|
-
msg[4 * k + 2] = w >>> 8 & 255;
|
|
5926
|
-
msg[4 * k + 3] = w & 255;
|
|
6369
|
+
let i = 0;
|
|
6370
|
+
while (i + 8 <= data.length) {
|
|
6371
|
+
if (data[i] !== 36 || data[i + 1] !== 64) {
|
|
6372
|
+
i++;
|
|
6373
|
+
continue;
|
|
5927
6374
|
}
|
|
5928
|
-
|
|
6375
|
+
const len = view.getUint16(i + 6, true);
|
|
6376
|
+
if (len < 8 || len % 4 !== 0) {
|
|
6377
|
+
i++;
|
|
6378
|
+
continue;
|
|
6379
|
+
}
|
|
6380
|
+
if (i + len > data.length) break;
|
|
6381
|
+
if (crc16(data, i + 4, i + len) !== view.getUint16(i + 2, true)) {
|
|
5929
6382
|
badCrc++;
|
|
5930
|
-
|
|
6383
|
+
i++;
|
|
6384
|
+
continue;
|
|
5931
6385
|
}
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
}
|
|
5935
|
-
return
|
|
5936
|
-
}
|
|
5937
|
-
|
|
5938
|
-
// src/navbits/gal.ts
|
|
5939
|
-
var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
|
|
5940
|
-
var SEC_PER_WEEK5 = 7 * 86400;
|
|
5941
|
-
var HALF_WEEK2 = 302400;
|
|
5942
|
-
var GST_GPS_WEEK_OFFSET = 1024;
|
|
5943
|
-
function galInavPageCrcOk(page) {
|
|
5944
|
-
if (page.length < 28) return false;
|
|
5945
|
-
return crc24q(page, 196) === getBitU(page, 196, 24);
|
|
5946
|
-
}
|
|
5947
|
-
function galFnavPageCrcOk(page) {
|
|
5948
|
-
if (page.length < 30) return false;
|
|
5949
|
-
return crc24q(page, 214) === getBitU(page, 214, 24);
|
|
5950
|
-
}
|
|
5951
|
-
function gpsDate2(week, sec) {
|
|
5952
|
-
return new Date(GPS_EPOCH_MS6 + (week * SEC_PER_WEEK5 + sec) * 1e3);
|
|
6386
|
+
onBlock(view.getUint16(i + 4, true) & 8191, i, len);
|
|
6387
|
+
i += len;
|
|
6388
|
+
}
|
|
6389
|
+
return badCrc;
|
|
5953
6390
|
}
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
if (
|
|
5957
|
-
return
|
|
6391
|
+
var two3 = (n) => String(n).padStart(2, "0");
|
|
6392
|
+
function svidToPrn(svid) {
|
|
6393
|
+
if (svid >= 1 && svid <= 37) return svid <= 32 ? `G${two3(svid)}` : null;
|
|
6394
|
+
if (svid <= 61) return svid - 37 <= 27 ? `R${two3(svid - 37)}` : null;
|
|
6395
|
+
if (svid <= 62) return null;
|
|
6396
|
+
if (svid <= 68) return svid - 38 <= 27 ? `R${two3(svid - 38)}` : null;
|
|
6397
|
+
if (svid <= 70) return null;
|
|
6398
|
+
if (svid <= 106) return svid - 70 <= 36 ? `E${two3(svid - 70)}` : null;
|
|
6399
|
+
if (svid <= 119) return null;
|
|
6400
|
+
if (svid <= 140) return `S${two3(svid - 100)}`;
|
|
6401
|
+
if (svid <= 180) return svid - 140 <= 50 ? `C${two3(svid - 140)}` : null;
|
|
6402
|
+
if (svid <= 190) return `J${two3(svid - 180)}`;
|
|
6403
|
+
if (svid <= 197) return svid - 190 <= 14 ? `I${two3(svid - 190)}` : null;
|
|
6404
|
+
if (svid <= 215) return `S${two3(svid - 157)}`;
|
|
6405
|
+
if (svid <= 222) return svid - 208 <= 14 ? `I${two3(svid - 208)}` : null;
|
|
6406
|
+
if (svid <= 245) return svid - 182 <= 50 ? `C${two3(svid - 182)}` : null;
|
|
6407
|
+
return null;
|
|
5958
6408
|
}
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
const
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
const
|
|
5983
|
-
|
|
5984
|
-
const
|
|
5985
|
-
|
|
5986
|
-
const
|
|
5987
|
-
i = 128 * 3;
|
|
5988
|
-
const type3 = getBitU(b, i, 6);
|
|
5989
|
-
i += 6;
|
|
5990
|
-
const iodNav3 = getBitU(b, i, 10);
|
|
5991
|
-
i += 10;
|
|
5992
|
-
const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
|
|
5993
|
-
i += 24;
|
|
5994
|
-
const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
|
|
5995
|
-
i += 16;
|
|
5996
|
-
const cuc = getBitS(b, i, 16) * 2 ** -29;
|
|
5997
|
-
i += 16;
|
|
5998
|
-
const cus = getBitS(b, i, 16) * 2 ** -29;
|
|
5999
|
-
i += 16;
|
|
6000
|
-
const crc = getBitS(b, i, 16) * 2 ** -5;
|
|
6001
|
-
i += 16;
|
|
6002
|
-
const crs = getBitS(b, i, 16) * 2 ** -5;
|
|
6003
|
-
i = 128 * 4;
|
|
6004
|
-
const type4 = getBitU(b, i, 6);
|
|
6005
|
-
i += 6;
|
|
6006
|
-
const iodNav4 = getBitU(b, i, 10);
|
|
6007
|
-
i += 10;
|
|
6008
|
-
const svid = getBitU(b, i, 6);
|
|
6009
|
-
i += 6;
|
|
6010
|
-
const cic = getBitS(b, i, 16) * 2 ** -29;
|
|
6011
|
-
i += 16;
|
|
6012
|
-
const cis = getBitS(b, i, 16) * 2 ** -29;
|
|
6013
|
-
i += 16;
|
|
6014
|
-
const tocs = getBitU(b, i, 14) * 60;
|
|
6015
|
-
i += 14;
|
|
6016
|
-
const af0 = getBitS(b, i, 31) * 2 ** -34;
|
|
6017
|
-
i += 31;
|
|
6018
|
-
const af1 = getBitS(b, i, 21) * 2 ** -46;
|
|
6019
|
-
i += 21;
|
|
6020
|
-
const af2 = getBitS(b, i, 6) * 2 ** -59;
|
|
6021
|
-
i = 128 * 5;
|
|
6022
|
-
const type5 = getBitU(b, i, 6);
|
|
6023
|
-
i += 6 + 11 + 11 + 14 + 5;
|
|
6024
|
-
const bgdE5a = getBitS(b, i, 10) * 2 ** -32;
|
|
6025
|
-
i += 10;
|
|
6026
|
-
i += 10;
|
|
6027
|
-
const e5bHs = getBitU(b, i, 2);
|
|
6028
|
-
i += 2;
|
|
6029
|
-
const e1bHs = getBitU(b, i, 2);
|
|
6030
|
-
i += 2;
|
|
6031
|
-
const e5bDvs = getBitU(b, i, 1);
|
|
6032
|
-
i += 1;
|
|
6033
|
-
const e1bDvs = getBitU(b, i, 1);
|
|
6034
|
-
i += 1;
|
|
6035
|
-
const gstWeek = getBitU(b, i, 12);
|
|
6036
|
-
i += 12;
|
|
6037
|
-
const tow = getBitU(b, i, 20);
|
|
6038
|
-
if (type1 !== 1 || type2 !== 2 || type3 !== 3 || type4 !== 4 || type5 !== 5)
|
|
6039
|
-
return null;
|
|
6040
|
-
if (iodNav1 !== iodNav2 || iodNav1 !== iodNav3 || iodNav1 !== iodNav4)
|
|
6041
|
-
return null;
|
|
6042
|
-
if (svid < 1 || svid > 36) return null;
|
|
6043
|
-
const week = weekOfToe(gstWeek, tow, toes) + GST_GPS_WEEK_OFFSET;
|
|
6044
|
-
const tocDate = gpsDate2(week, tocs);
|
|
6409
|
+
|
|
6410
|
+
// src/sbf/nav.ts
|
|
6411
|
+
var PI2 = Math.PI;
|
|
6412
|
+
var GPS_EPOCH_MS8 = Date.UTC(1980, 0, 6);
|
|
6413
|
+
var BDT_EPOCH_MS2 = Date.UTC(2006, 0, 1);
|
|
6414
|
+
var SEC_PER_WEEK8 = 7 * 86400;
|
|
6415
|
+
var MS_PER_WEEK4 = SEC_PER_WEEK8 * 1e3;
|
|
6416
|
+
var F4_DNU = -2e10;
|
|
6417
|
+
var U4_DNU = 4294967295;
|
|
6418
|
+
function adjustWeek(refWeek, wn, mod) {
|
|
6419
|
+
let offset = refWeek % mod - wn;
|
|
6420
|
+
if (offset > mod / 2) offset -= mod;
|
|
6421
|
+
if (offset < -(mod / 2 - 1)) offset += mod;
|
|
6422
|
+
return refWeek - offset;
|
|
6423
|
+
}
|
|
6424
|
+
var gpsMs = (week, sec) => GPS_EPOCH_MS8 + week * MS_PER_WEEK4 + sec * 1e3;
|
|
6425
|
+
var sowOf2 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK8;
|
|
6426
|
+
function decodeGpsQzsNav(view, b, sys) {
|
|
6427
|
+
const svid = view.getUint8(b + 14);
|
|
6428
|
+
const prn = sys === "G" ? svid : svid - 180;
|
|
6429
|
+
const max = sys === "G" ? 32 : 10;
|
|
6430
|
+
if (prn < 1 || prn > max) return null;
|
|
6431
|
+
const wnc = view.getUint16(b + 12, true);
|
|
6432
|
+
const tgdRaw = view.getFloat32(b + 28, true);
|
|
6433
|
+
const tocs = view.getUint32(b + 32, true);
|
|
6434
|
+
const toes = view.getUint32(b + 88, true);
|
|
6435
|
+
const wnToc = adjustWeek(wnc, view.getUint16(b + 136, true), 1024);
|
|
6436
|
+
const tocDate = new Date(gpsMs(wnToc, tocs));
|
|
6045
6437
|
return {
|
|
6046
|
-
system:
|
|
6047
|
-
prn:
|
|
6048
|
-
toc: tocDate.getTime()
|
|
6438
|
+
system: sys,
|
|
6439
|
+
prn: `${sys}${String(prn).padStart(2, "0")}`,
|
|
6440
|
+
toc: sowOf2(tocDate.getTime()),
|
|
6049
6441
|
tocDate,
|
|
6050
|
-
af0,
|
|
6051
|
-
af1,
|
|
6052
|
-
af2,
|
|
6053
|
-
iode:
|
|
6054
|
-
crs,
|
|
6055
|
-
deltaN,
|
|
6056
|
-
m0,
|
|
6057
|
-
cuc,
|
|
6058
|
-
e,
|
|
6059
|
-
cus,
|
|
6060
|
-
sqrtA,
|
|
6442
|
+
af0: view.getFloat32(b + 44, true),
|
|
6443
|
+
af1: view.getFloat32(b + 40, true),
|
|
6444
|
+
af2: view.getFloat32(b + 36, true),
|
|
6445
|
+
iode: view.getUint8(b + 24),
|
|
6446
|
+
crs: view.getFloat32(b + 48, true),
|
|
6447
|
+
deltaN: view.getFloat32(b + 52, true) * PI2,
|
|
6448
|
+
m0: view.getFloat64(b + 56, true) * PI2,
|
|
6449
|
+
cuc: view.getFloat32(b + 64, true),
|
|
6450
|
+
e: view.getFloat64(b + 68, true),
|
|
6451
|
+
cus: view.getFloat32(b + 76, true),
|
|
6452
|
+
sqrtA: view.getFloat64(b + 80, true),
|
|
6061
6453
|
toe: toes,
|
|
6062
|
-
cic,
|
|
6063
|
-
omega0,
|
|
6064
|
-
cis,
|
|
6065
|
-
i0,
|
|
6066
|
-
crc,
|
|
6067
|
-
omega,
|
|
6068
|
-
omegaDot,
|
|
6069
|
-
idot,
|
|
6070
|
-
week
|
|
6071
|
-
|
|
6072
|
-
|
|
6454
|
+
cic: view.getFloat32(b + 92, true),
|
|
6455
|
+
omega0: view.getFloat64(b + 96, true) * PI2,
|
|
6456
|
+
cis: view.getFloat32(b + 104, true),
|
|
6457
|
+
i0: view.getFloat64(b + 108, true) * PI2,
|
|
6458
|
+
crc: view.getFloat32(b + 116, true),
|
|
6459
|
+
omega: view.getFloat64(b + 120, true) * PI2,
|
|
6460
|
+
omegaDot: view.getFloat32(b + 128, true) * PI2,
|
|
6461
|
+
idot: view.getFloat32(b + 132, true) * PI2,
|
|
6462
|
+
// RINEX "GPS week to go with toe": RTKLIB writes WNc for GPS and
|
|
6463
|
+
// the week of toc for QZSS — mirrored here so records compare
|
|
6464
|
+
// 1:1 against convbin output. wnToe is still used for `toe` above.
|
|
6465
|
+
week: sys === "G" ? wnc : wnToc,
|
|
6466
|
+
svHealth: view.getUint8(b + 20),
|
|
6467
|
+
tgd: tgdRaw !== F4_DNU ? tgdRaw : 0
|
|
6073
6468
|
};
|
|
6074
6469
|
}
|
|
6075
|
-
function
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
const
|
|
6082
|
-
|
|
6083
|
-
const
|
|
6084
|
-
|
|
6085
|
-
const
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
const af2 = getBitS(b, i, 6) * 2 ** -59;
|
|
6092
|
-
i += 6;
|
|
6093
|
-
i += 8 + 11 + 11 + 14 + 5;
|
|
6094
|
-
const bgdE5a = getBitS(b, i, 10) * 2 ** -32;
|
|
6095
|
-
i += 10;
|
|
6096
|
-
const e5aHs = getBitU(b, i, 2);
|
|
6097
|
-
i += 2;
|
|
6098
|
-
const gstWeek = getBitU(b, i, 12);
|
|
6099
|
-
i += 12;
|
|
6100
|
-
const tow = getBitU(b, i, 20);
|
|
6101
|
-
i += 20;
|
|
6102
|
-
const e5aDvs = getBitU(b, i, 1);
|
|
6103
|
-
i = 31 * 8;
|
|
6104
|
-
const type2 = getBitU(b, i, 6);
|
|
6105
|
-
i += 6;
|
|
6106
|
-
const iodNav2 = getBitU(b, i, 10);
|
|
6107
|
-
i += 10;
|
|
6108
|
-
const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
6109
|
-
i += 32;
|
|
6110
|
-
const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
|
|
6111
|
-
i += 24;
|
|
6112
|
-
const e = getBitU(b, i, 32) * 2 ** -33;
|
|
6113
|
-
i += 32;
|
|
6114
|
-
const sqrtA = getBitU(b, i, 32) * 2 ** -19;
|
|
6115
|
-
i += 32;
|
|
6116
|
-
const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
6117
|
-
i += 32;
|
|
6118
|
-
const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
|
|
6119
|
-
i = 62 * 8;
|
|
6120
|
-
const type3 = getBitU(b, i, 6);
|
|
6121
|
-
i += 6;
|
|
6122
|
-
const iodNav3 = getBitU(b, i, 10);
|
|
6123
|
-
i += 10;
|
|
6124
|
-
const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
6125
|
-
i += 32;
|
|
6126
|
-
const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
6127
|
-
i += 32;
|
|
6128
|
-
const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
|
|
6129
|
-
i += 16;
|
|
6130
|
-
const cuc = getBitS(b, i, 16) * 2 ** -29;
|
|
6131
|
-
i += 16;
|
|
6132
|
-
const cus = getBitS(b, i, 16) * 2 ** -29;
|
|
6133
|
-
i += 16;
|
|
6134
|
-
const crc = getBitS(b, i, 16) * 2 ** -5;
|
|
6135
|
-
i += 16;
|
|
6136
|
-
const crs = getBitS(b, i, 16) * 2 ** -5;
|
|
6137
|
-
i += 16;
|
|
6138
|
-
const toes = getBitU(b, i, 14) * 60;
|
|
6139
|
-
i = 93 * 8;
|
|
6140
|
-
const type4 = getBitU(b, i, 6);
|
|
6141
|
-
i += 6;
|
|
6142
|
-
const iodNav4 = getBitU(b, i, 10);
|
|
6143
|
-
i += 10;
|
|
6144
|
-
const cic = getBitS(b, i, 16) * 2 ** -29;
|
|
6145
|
-
i += 16;
|
|
6146
|
-
const cis = getBitS(b, i, 16) * 2 ** -29;
|
|
6147
|
-
if (type1 !== 1 || type2 !== 2 || type3 !== 3 || type4 !== 4) return null;
|
|
6148
|
-
if (iodNav1 !== iodNav2 || iodNav1 !== iodNav3 || iodNav1 !== iodNav4)
|
|
6149
|
-
return null;
|
|
6150
|
-
if (svid < 1 || svid > 36) return null;
|
|
6151
|
-
const week = weekOfToe(gstWeek, tow, toes) + GST_GPS_WEEK_OFFSET;
|
|
6152
|
-
const tocDate = gpsDate2(week, tocs);
|
|
6470
|
+
function decodeGalNav(view, b) {
|
|
6471
|
+
const prn = view.getUint8(b + 14) - 70;
|
|
6472
|
+
if (prn < 1 || prn > 36) return null;
|
|
6473
|
+
const source = view.getUint8(b + 15);
|
|
6474
|
+
if (source !== 2 && source !== 16) return null;
|
|
6475
|
+
const wnc = view.getUint16(b + 12, true);
|
|
6476
|
+
const toes = view.getUint32(b + 100, true);
|
|
6477
|
+
const tocs = view.getUint32(b + 104, true);
|
|
6478
|
+
const wnToc = adjustWeek(wnc, view.getUint16(b + 126, true), 4096);
|
|
6479
|
+
const tocDate = new Date(gpsMs(wnToc, tocs));
|
|
6480
|
+
const health = view.getUint16(b + 130, true);
|
|
6481
|
+
let svh = 0;
|
|
6482
|
+
if (health & 1) svh |= health >> 1 & 7;
|
|
6483
|
+
if (health & 16) svh |= (health >> 5 & 7) << 6;
|
|
6484
|
+
if (health & 256) svh |= (health >> 9 & 7) << 3;
|
|
6485
|
+
const bgdE5a = view.getFloat32(b + 136, true);
|
|
6153
6486
|
return {
|
|
6154
6487
|
system: "E",
|
|
6155
|
-
prn: `E${
|
|
6156
|
-
toc: tocDate.getTime()
|
|
6488
|
+
prn: `E${String(prn).padStart(2, "0")}`,
|
|
6489
|
+
toc: sowOf2(tocDate.getTime()),
|
|
6157
6490
|
tocDate,
|
|
6158
|
-
af0,
|
|
6159
|
-
af1,
|
|
6160
|
-
af2,
|
|
6161
|
-
iode:
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6491
|
+
af0: view.getFloat64(b + 116, true),
|
|
6492
|
+
af1: view.getFloat32(b + 112, true),
|
|
6493
|
+
af2: view.getFloat32(b + 108, true),
|
|
6494
|
+
iode: view.getUint16(b + 128, true),
|
|
6495
|
+
// IODnav
|
|
6496
|
+
crs: view.getFloat32(b + 88, true),
|
|
6497
|
+
deltaN: view.getFloat32(b + 72, true) * PI2,
|
|
6498
|
+
m0: view.getFloat64(b + 24, true) * PI2,
|
|
6499
|
+
cuc: view.getFloat32(b + 76, true),
|
|
6500
|
+
e: view.getFloat64(b + 32, true),
|
|
6501
|
+
cus: view.getFloat32(b + 80, true),
|
|
6502
|
+
sqrtA: view.getFloat64(b + 16, true),
|
|
6169
6503
|
toe: toes,
|
|
6170
|
-
cic,
|
|
6171
|
-
omega0,
|
|
6172
|
-
cis,
|
|
6173
|
-
i0,
|
|
6174
|
-
crc,
|
|
6175
|
-
omega,
|
|
6176
|
-
omegaDot,
|
|
6177
|
-
idot,
|
|
6178
|
-
week,
|
|
6179
|
-
|
|
6180
|
-
|
|
6504
|
+
cic: view.getFloat32(b + 92, true),
|
|
6505
|
+
omega0: view.getFloat64(b + 56, true) * PI2,
|
|
6506
|
+
cis: view.getFloat32(b + 96, true),
|
|
6507
|
+
i0: view.getFloat64(b + 40, true) * PI2,
|
|
6508
|
+
crc: view.getFloat32(b + 84, true),
|
|
6509
|
+
omega: view.getFloat64(b + 48, true) * PI2,
|
|
6510
|
+
omegaDot: view.getFloat32(b + 64, true) * PI2,
|
|
6511
|
+
idot: view.getFloat32(b + 68, true) * PI2,
|
|
6512
|
+
week: wnc,
|
|
6513
|
+
// RINEX GAL week is GPS-aligned and continuous
|
|
6514
|
+
svHealth: svh,
|
|
6515
|
+
tgd: bgdE5a !== F4_DNU ? bgdE5a : 0
|
|
6516
|
+
// BGD E5a/E1 (RINEX slot)
|
|
6517
|
+
};
|
|
6518
|
+
}
|
|
6519
|
+
function decodeBdsNav(view, b) {
|
|
6520
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
6521
|
+
if (!prn || prn[0] !== "C") return null;
|
|
6522
|
+
const bdsWeekRef = view.getUint16(b + 12, true) - 1356;
|
|
6523
|
+
const tgd1 = view.getFloat32(b + 24, true);
|
|
6524
|
+
const tocs = view.getUint32(b + 32, true);
|
|
6525
|
+
const toes = view.getUint32(b + 88, true);
|
|
6526
|
+
const wnToc = adjustWeek(bdsWeekRef, view.getUint16(b + 136, true), 8192);
|
|
6527
|
+
const wnToe = adjustWeek(bdsWeekRef, view.getUint16(b + 138, true), 8192);
|
|
6528
|
+
const tocDate = new Date(BDT_EPOCH_MS2 + wnToc * MS_PER_WEEK4 + tocs * 1e3);
|
|
6529
|
+
return {
|
|
6530
|
+
system: "C",
|
|
6531
|
+
prn,
|
|
6532
|
+
toc: sowOf2(tocDate.getTime()),
|
|
6533
|
+
tocDate,
|
|
6534
|
+
af0: view.getFloat32(b + 44, true),
|
|
6535
|
+
af1: view.getFloat32(b + 40, true),
|
|
6536
|
+
af2: view.getFloat32(b + 36, true),
|
|
6537
|
+
iode: view.getUint8(b + 21),
|
|
6538
|
+
// AODE
|
|
6539
|
+
crs: view.getFloat32(b + 48, true),
|
|
6540
|
+
deltaN: view.getFloat32(b + 52, true) * PI2,
|
|
6541
|
+
m0: view.getFloat64(b + 56, true) * PI2,
|
|
6542
|
+
cuc: view.getFloat32(b + 64, true),
|
|
6543
|
+
e: view.getFloat64(b + 68, true),
|
|
6544
|
+
cus: view.getFloat32(b + 76, true),
|
|
6545
|
+
sqrtA: view.getFloat64(b + 80, true),
|
|
6546
|
+
toe: toes,
|
|
6547
|
+
cic: view.getFloat32(b + 92, true),
|
|
6548
|
+
omega0: view.getFloat64(b + 96, true) * PI2,
|
|
6549
|
+
cis: view.getFloat32(b + 104, true),
|
|
6550
|
+
i0: view.getFloat64(b + 108, true) * PI2,
|
|
6551
|
+
crc: view.getFloat32(b + 116, true),
|
|
6552
|
+
omega: view.getFloat64(b + 120, true) * PI2,
|
|
6553
|
+
omegaDot: view.getFloat32(b + 128, true) * PI2,
|
|
6554
|
+
idot: view.getFloat32(b + 132, true) * PI2,
|
|
6555
|
+
week: wnToe,
|
|
6556
|
+
// RINEX BDS week field is the BDT week
|
|
6557
|
+
svHealth: view.getUint8(b + 19),
|
|
6558
|
+
// SatH1
|
|
6559
|
+
tgd: tgd1 !== F4_DNU ? tgd1 : 0
|
|
6560
|
+
// TGD1 B1/B3 (RINEX slot)
|
|
6561
|
+
};
|
|
6562
|
+
}
|
|
6563
|
+
function decodeGloNav(view, b) {
|
|
6564
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
6565
|
+
if (!prn || prn[0] !== "R") return null;
|
|
6566
|
+
const wnc = view.getUint16(b + 12, true);
|
|
6567
|
+
const toes = view.getUint32(b + 76, true);
|
|
6568
|
+
const wnToe = adjustWeek(wnc, view.getUint16(b + 80, true), 1024);
|
|
6569
|
+
const toeGpsMs = gpsMs(wnToe, toes);
|
|
6570
|
+
const leapMs = getGpsLeap(new Date(toeGpsMs)) * 1e3;
|
|
6571
|
+
const tocDate = new Date(toeGpsMs - leapMs);
|
|
6572
|
+
const tofGpsMs = gpsMs(wnc, 0) + view.getUint32(b + 8, true);
|
|
6573
|
+
const tofLeapMs = getGpsLeap(new Date(tofGpsMs)) * 1e3;
|
|
6574
|
+
const messageFrameTime = (tofGpsMs - tofLeapMs - GPS_EPOCH_MS8) / 1e3 % SEC_PER_WEEK8;
|
|
6575
|
+
return {
|
|
6576
|
+
system: "R",
|
|
6577
|
+
prn,
|
|
6578
|
+
tocDate,
|
|
6579
|
+
// RINEX stores −τn as the clock bias; SBF carries τn (ICD sign)
|
|
6580
|
+
tauN: -view.getFloat32(b + 68, true),
|
|
6581
|
+
gammaN: view.getFloat32(b + 64, true),
|
|
6582
|
+
messageFrameTime,
|
|
6583
|
+
x: view.getFloat64(b + 16, true),
|
|
6584
|
+
// SBF unit is km, like RINEX
|
|
6585
|
+
xDot: view.getFloat32(b + 40, true),
|
|
6586
|
+
xAcc: view.getFloat32(b + 52, true),
|
|
6587
|
+
y: view.getFloat64(b + 24, true),
|
|
6588
|
+
yDot: view.getFloat32(b + 44, true),
|
|
6589
|
+
yAcc: view.getFloat32(b + 56, true),
|
|
6590
|
+
z: view.getFloat64(b + 32, true),
|
|
6591
|
+
zDot: view.getFloat32(b + 48, true),
|
|
6592
|
+
zAcc: view.getFloat32(b + 60, true),
|
|
6593
|
+
// MSB of the 3-bit Bn word — the unhealthy flag RINEX carries
|
|
6594
|
+
health: view.getUint8(b + 85) >> 2,
|
|
6595
|
+
freqNum: view.getUint8(b + 15) - 8
|
|
6181
6596
|
};
|
|
6182
6597
|
}
|
|
6183
|
-
|
|
6184
|
-
var GalInavAssembler = class {
|
|
6185
|
-
sats = /* @__PURE__ */ new Map();
|
|
6186
|
-
/**
|
|
6187
|
-
* Push one I/NAV page pair for satellite `prn` (1-36): the 234-bit
|
|
6188
|
-
* even+odd concatenation, even part first with its 6 tail bits
|
|
6189
|
-
* removed, bit 0 = the even part's Even/Odd bit (≥ 17 bytes).
|
|
6190
|
-
* Returns the newly completed ephemeris, or null. Pages that are
|
|
6191
|
-
* not an even/odd nominal pair, alert pages and word types outside
|
|
6192
|
-
* 1-5 are ignored.
|
|
6193
|
-
*/
|
|
6194
|
-
push(prn, page) {
|
|
6195
|
-
if (prn < 1 || prn > 36 || page.length < 17) return null;
|
|
6196
|
-
if (getBitU(page, 0, 1) !== 0 || getBitU(page, 114, 1) !== 1) return null;
|
|
6197
|
-
if (getBitU(page, 1, 1) === 1 || getBitU(page, 115, 1) === 1) return null;
|
|
6198
|
-
const type = getBitU(page, 2, 6);
|
|
6199
|
-
if (type < 1 || type > 5) return null;
|
|
6200
|
-
let sat = this.sats.get(prn);
|
|
6201
|
-
if (!sat) {
|
|
6202
|
-
sat = { words: new Uint8Array(96) };
|
|
6203
|
-
this.sats.set(prn, sat);
|
|
6204
|
-
}
|
|
6205
|
-
for (let k = 0; k < 14; k++)
|
|
6206
|
-
sat.words[type * 16 + k] = getBitU(page, 2 + 8 * k, 8);
|
|
6207
|
-
sat.words[type * 16 + 14] = getBitU(page, 116, 8);
|
|
6208
|
-
sat.words[type * 16 + 15] = getBitU(page, 124, 8);
|
|
6209
|
-
if (type !== 5) return null;
|
|
6210
|
-
const eph = decodeGalInavWords(sat.words);
|
|
6211
|
-
if (!eph || eph.prn !== `E${two2(prn)}`) return null;
|
|
6212
|
-
const key = dedupKey(eph);
|
|
6213
|
-
if (key === sat.lastKey) return null;
|
|
6214
|
-
sat.lastKey = key;
|
|
6215
|
-
return eph;
|
|
6216
|
-
}
|
|
6217
|
-
};
|
|
6218
|
-
var GalFnavAssembler = class {
|
|
6219
|
-
sats = /* @__PURE__ */ new Map();
|
|
6220
|
-
/**
|
|
6221
|
-
* Push one F/NAV page for satellite `prn` (1-36): 244 bits with the
|
|
6222
|
-
* sync field stripped, bit 0 = first page-type bit (≥ 31 bytes).
|
|
6223
|
-
* Returns the newly completed ephemeris, or null. Dummy pages
|
|
6224
|
-
* (type 63) and page types outside 1-4 are ignored.
|
|
6225
|
-
*/
|
|
6226
|
-
push(prn, page) {
|
|
6227
|
-
if (prn < 1 || prn > 36 || page.length < 31) return null;
|
|
6228
|
-
const type = getBitU(page, 0, 6);
|
|
6229
|
-
if (type < 1 || type > 4) return null;
|
|
6230
|
-
let sat = this.sats.get(prn);
|
|
6231
|
-
if (!sat) {
|
|
6232
|
-
sat = { words: new Uint8Array(124) };
|
|
6233
|
-
this.sats.set(prn, sat);
|
|
6234
|
-
}
|
|
6235
|
-
sat.words.set(page.subarray(0, 31), (type - 1) * 31);
|
|
6236
|
-
if (type !== 4) return null;
|
|
6237
|
-
const eph = decodeGalFnavPages(sat.words);
|
|
6238
|
-
if (!eph || eph.prn !== `E${two2(prn)}`) return null;
|
|
6239
|
-
const key = dedupKey(eph);
|
|
6240
|
-
if (key === sat.lastKey) return null;
|
|
6241
|
-
sat.lastKey = key;
|
|
6242
|
-
return eph;
|
|
6243
|
-
}
|
|
6244
|
-
};
|
|
6245
|
-
|
|
6246
|
-
// src/sbf/rawnav-gal.ts
|
|
6247
|
-
var INAV_SOURCES = [17, 21, 22];
|
|
6248
|
-
var FNAV_SOURCES = [20, 22];
|
|
6249
|
-
function parseSbfGalNav(data) {
|
|
6598
|
+
function parseSbfNav(data) {
|
|
6250
6599
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
6251
6600
|
const ephemerides = [];
|
|
6252
|
-
const
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
if (id
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
if (!prnStr || prnStr[0] !== "E") return;
|
|
6261
|
-
const prn = parseInt(prnStr.slice(1), 10);
|
|
6262
|
-
const source = data[b + 17] & 31;
|
|
6263
|
-
const page = new Uint8Array(32);
|
|
6264
|
-
for (let k = 0; k < 8; k++) {
|
|
6265
|
-
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
6266
|
-
page[4 * k] = w >>> 24;
|
|
6267
|
-
page[4 * k + 1] = w >>> 16 & 255;
|
|
6268
|
-
page[4 * k + 2] = w >>> 8 & 255;
|
|
6269
|
-
page[4 * k + 3] = w & 255;
|
|
6270
|
-
}
|
|
6271
|
-
let eph;
|
|
6272
|
-
let src;
|
|
6273
|
-
if (id === 4023) {
|
|
6274
|
-
src = "inav";
|
|
6275
|
-
if (!INAV_SOURCES.includes(source)) return;
|
|
6276
|
-
if (getBitU2(page, 0) !== 0 || getBitU2(page, 114) !== 1) return;
|
|
6277
|
-
if (!galInavPageCrcOk(page)) {
|
|
6278
|
-
badCrc++;
|
|
6279
|
-
return;
|
|
6280
|
-
}
|
|
6281
|
-
eph = inav.push(prn, page);
|
|
6282
|
-
} else {
|
|
6283
|
-
src = "fnav";
|
|
6284
|
-
if (!FNAV_SOURCES.includes(source)) return;
|
|
6285
|
-
if (isFnavDummy(page)) return;
|
|
6286
|
-
if (!galFnavPageCrcOk(page)) {
|
|
6287
|
-
badCrc++;
|
|
6288
|
-
return;
|
|
6289
|
-
}
|
|
6290
|
-
eph = fnav.push(prn, page);
|
|
6291
|
-
}
|
|
6292
|
-
if (eph) ephemerides.push({ ...eph, source: src });
|
|
6601
|
+
const badCrc = scanSbfFrames(data, view, (id, b, len) => {
|
|
6602
|
+
let eph = null;
|
|
6603
|
+
if (id === 5891 && len >= 140) eph = decodeGpsQzsNav(view, b, "G");
|
|
6604
|
+
else if (id === 4095 && len >= 140) eph = decodeGpsQzsNav(view, b, "J");
|
|
6605
|
+
else if (id === 4002 && len >= 149) eph = decodeGalNav(view, b);
|
|
6606
|
+
else if (id === 4081 && len >= 140) eph = decodeBdsNav(view, b);
|
|
6607
|
+
else if (id === 4004 && len >= 96) eph = decodeGloNav(view, b);
|
|
6608
|
+
if (eph) ephemerides.push(eph);
|
|
6293
6609
|
});
|
|
6294
|
-
return { ephemerides, badCrc
|
|
6295
|
-
}
|
|
6296
|
-
function getBitU2(buff, pos) {
|
|
6297
|
-
return buff[pos >> 3] >> 7 - (pos & 7) & 1;
|
|
6298
|
-
}
|
|
6299
|
-
function isFnavDummy(page) {
|
|
6300
|
-
return page[0] >> 2 === 63;
|
|
6301
|
-
}
|
|
6302
|
-
|
|
6303
|
-
// src/navbits/bds.ts
|
|
6304
|
-
var BDT_EPOCH_MS2 = Date.UTC(2006, 0, 1);
|
|
6305
|
-
var SEC_PER_WEEK6 = 7 * 86400;
|
|
6306
|
-
var MS_PER_WEEK4 = SEC_PER_WEEK6 * 1e3;
|
|
6307
|
-
var HALF_WEEK3 = 302400;
|
|
6308
|
-
var sowOf2 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK6;
|
|
6309
|
-
var BDS_SUBFRAME_BYTES = 38;
|
|
6310
|
-
function getBitU22(b, p1, l1, p2, l2) {
|
|
6311
|
-
return getBitU(b, p1, l1) * 2 ** l2 + getBitU(b, p2, l2);
|
|
6312
|
-
}
|
|
6313
|
-
function getBitS2(b, p1, l1, p2, l2) {
|
|
6314
|
-
return getBitS(b, p1, l1) * 2 ** l2 + getBitU(b, p2, l2);
|
|
6315
|
-
}
|
|
6316
|
-
function getBitU3(b, p1, l1, p2, l2, p3, l3) {
|
|
6317
|
-
return getBitU(b, p1, l1) * 2 ** (l2 + l3) + getBitU(b, p2, l2) * 2 ** l3 + getBitU(b, p3, l3);
|
|
6318
|
-
}
|
|
6319
|
-
function getBitS3(b, p1, l1, p2, l2, p3, l3) {
|
|
6320
|
-
return getBitS(b, p1, l1) * 2 ** (l2 + l3) + getBitU(b, p2, l2) * 2 ** l3 + getBitU(b, p3, l3);
|
|
6610
|
+
return { ephemerides, badCrc };
|
|
6321
6611
|
}
|
|
6322
|
-
var
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6612
|
+
var GAL_SQRT_A_NOMINAL = Math.sqrt(296e5);
|
|
6613
|
+
var GAL_I_NOMINAL = 56 / 180 * PI2;
|
|
6614
|
+
var I_REF_03 = 0.3 * PI2;
|
|
6615
|
+
function decodeGpsGalAlm(view, b, sys) {
|
|
6616
|
+
const wnc = view.getUint16(b + 12, true);
|
|
6617
|
+
const toa = view.getUint32(b + 20, true);
|
|
6618
|
+
if (toa === U4_DNU) return null;
|
|
6619
|
+
let prn;
|
|
6620
|
+
let weekAlm;
|
|
6621
|
+
let i0;
|
|
6622
|
+
let sqrtA = view.getFloat32(b + 32, true);
|
|
6623
|
+
let health;
|
|
6624
|
+
if (sys === "G") {
|
|
6625
|
+
prn = view.getUint8(b + 14);
|
|
6626
|
+
if (prn < 1 || prn > 32) return null;
|
|
6627
|
+
weekAlm = adjustWeek(wnc, view.getUint8(b + 56), 256);
|
|
6628
|
+
i0 = I_REF_03 + view.getFloat32(b + 24, true) * PI2;
|
|
6629
|
+
health = view.getUint8(b + 58);
|
|
6630
|
+
} else {
|
|
6631
|
+
prn = view.getUint8(b + 57) - 70;
|
|
6632
|
+
if (prn < 1 || prn > 36) return null;
|
|
6633
|
+
weekAlm = adjustWeek(wnc, view.getUint8(b + 56), 4);
|
|
6634
|
+
i0 = GAL_I_NOMINAL + view.getFloat32(b + 24, true) * PI2;
|
|
6635
|
+
sqrtA += GAL_SQRT_A_NOMINAL;
|
|
6636
|
+
health = view.getUint16(b + 58, true);
|
|
6326
6637
|
}
|
|
6327
|
-
return
|
|
6638
|
+
return {
|
|
6639
|
+
system: sys,
|
|
6640
|
+
prn: `${sys}${String(prn).padStart(2, "0")}`,
|
|
6641
|
+
weekAlm,
|
|
6642
|
+
toaSec: toa,
|
|
6643
|
+
sqrtA,
|
|
6644
|
+
e: view.getFloat32(b + 16, true),
|
|
6645
|
+
i0OrDeltaI: i0,
|
|
6646
|
+
omega0: view.getFloat32(b + 36, true) * PI2,
|
|
6647
|
+
omega: view.getFloat32(b + 40, true) * PI2,
|
|
6648
|
+
m0: view.getFloat32(b + 44, true) * PI2,
|
|
6649
|
+
omegaDot: view.getFloat32(b + 28, true) * PI2,
|
|
6650
|
+
af0: view.getFloat32(b + 52, true),
|
|
6651
|
+
af1: view.getFloat32(b + 48, true),
|
|
6652
|
+
health
|
|
6653
|
+
};
|
|
6328
6654
|
}
|
|
6329
|
-
function
|
|
6330
|
-
|
|
6331
|
-
if (!
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6655
|
+
function decodeBdsAlm(view, b) {
|
|
6656
|
+
const prnStr = svidToPrn(view.getUint8(b + 14));
|
|
6657
|
+
if (!prnStr || prnStr[0] !== "C") return null;
|
|
6658
|
+
const prn = parseInt(prnStr.slice(1), 10);
|
|
6659
|
+
const toa = view.getUint32(b + 16, true);
|
|
6660
|
+
if (toa === U4_DNU) return null;
|
|
6661
|
+
const bdsWeekRef = view.getUint16(b + 12, true) - 1356;
|
|
6662
|
+
const geo = prn <= 5 || prn >= 59;
|
|
6663
|
+
return {
|
|
6664
|
+
system: "C",
|
|
6665
|
+
prn: prnStr,
|
|
6666
|
+
weekAlm: adjustWeek(bdsWeekRef, view.getUint8(b + 15), 256),
|
|
6667
|
+
toaSec: toa,
|
|
6668
|
+
sqrtA: view.getFloat32(b + 20, true),
|
|
6669
|
+
e: view.getFloat32(b + 24, true),
|
|
6670
|
+
i0OrDeltaI: (geo ? 0 : I_REF_03) + view.getFloat32(b + 44, true) * PI2,
|
|
6671
|
+
omega0: view.getFloat32(b + 36, true) * PI2,
|
|
6672
|
+
omega: view.getFloat32(b + 28, true) * PI2,
|
|
6673
|
+
m0: view.getFloat32(b + 32, true) * PI2,
|
|
6674
|
+
omegaDot: view.getFloat32(b + 40, true) * PI2,
|
|
6675
|
+
af0: view.getFloat32(b + 48, true),
|
|
6676
|
+
af1: view.getFloat32(b + 52, true),
|
|
6677
|
+
health: view.getUint16(b + 56, true)
|
|
6678
|
+
};
|
|
6339
6679
|
}
|
|
6340
|
-
function
|
|
6341
|
-
|
|
6342
|
-
if (
|
|
6343
|
-
|
|
6344
|
-
const
|
|
6680
|
+
function decodeGloAlm(view, b) {
|
|
6681
|
+
const prn = svidToPrn(view.getUint8(b + 14));
|
|
6682
|
+
if (!prn || prn[0] !== "R") return null;
|
|
6683
|
+
const wnc = view.getUint16(b + 12, true);
|
|
6684
|
+
const toa = view.getUint32(b + 20, true);
|
|
6685
|
+
if (toa === U4_DNU) return null;
|
|
6345
6686
|
return {
|
|
6346
|
-
system: "
|
|
6687
|
+
system: "R",
|
|
6347
6688
|
prn,
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
sqrtA: f.sqrtA,
|
|
6363
|
-
toe: f.toes,
|
|
6364
|
-
cic: f.cic,
|
|
6365
|
-
omega0: f.omega0,
|
|
6366
|
-
cis: f.cis,
|
|
6367
|
-
i0: f.i0,
|
|
6368
|
-
crc: f.crc,
|
|
6369
|
-
omega: f.omega,
|
|
6370
|
-
omegaDot: f.omegaDot,
|
|
6371
|
-
idot: f.idot,
|
|
6372
|
-
week,
|
|
6373
|
-
// RINEX BDS week field is the BDT week of toe
|
|
6374
|
-
svHealth: f.svh,
|
|
6375
|
-
// SatH1
|
|
6376
|
-
tgd: f.tgd1
|
|
6377
|
-
// TGD1 (B1) — RINEX slot
|
|
6689
|
+
freqNr: view.getUint8(b + 15) - 8,
|
|
6690
|
+
weekAlm: adjustWeek(wnc, view.getUint8(b + 52), 256),
|
|
6691
|
+
toaSec: toa,
|
|
6692
|
+
epsilon: view.getFloat32(b + 16, true),
|
|
6693
|
+
deltaI: view.getFloat32(b + 24, true) * PI2,
|
|
6694
|
+
lambda: view.getFloat32(b + 28, true) * PI2,
|
|
6695
|
+
tLambda: view.getFloat32(b + 32, true),
|
|
6696
|
+
omega: view.getFloat32(b + 36, true) * PI2,
|
|
6697
|
+
deltaT: view.getFloat32(b + 40, true),
|
|
6698
|
+
deltaTDot: view.getFloat32(b + 44, true),
|
|
6699
|
+
tau: view.getFloat32(b + 48, true),
|
|
6700
|
+
health: view.getUint8(b + 53),
|
|
6701
|
+
nDay: view.getUint16(b + 54, true),
|
|
6702
|
+
n4: view.getUint8(b + 57)
|
|
6378
6703
|
};
|
|
6379
6704
|
}
|
|
6380
|
-
function
|
|
6381
|
-
|
|
6382
|
-
const
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
const af2 = getBitS(b, i + 214, 11) * 2 ** -66;
|
|
6391
|
-
const af0 = getBitS2(b, i + 225, 7, i + 240, 17) * 2 ** -33;
|
|
6392
|
-
const af1 = getBitS2(b, i + 257, 5, i + 270, 17) * 2 ** -50;
|
|
6393
|
-
i = 8 * 38 * 1;
|
|
6394
|
-
const frn2 = getBitU(b, i + 15, 3);
|
|
6395
|
-
const sow2 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
6396
|
-
const deltaN = getBitS2(b, i + 42, 10, i + 60, 6) * 2 ** -43 * GPS_PI;
|
|
6397
|
-
const cuc = getBitS2(b, i + 66, 16, i + 90, 2) * 2 ** -31;
|
|
6398
|
-
const m0 = getBitS2(b, i + 92, 20, i + 120, 12) * 2 ** -31 * GPS_PI;
|
|
6399
|
-
const e = getBitU22(b, i + 132, 10, i + 150, 22) * 2 ** -33;
|
|
6400
|
-
const cus = getBitS(b, i + 180, 18) * 2 ** -31;
|
|
6401
|
-
const crc = getBitS2(b, i + 198, 4, i + 210, 14) * 2 ** -6;
|
|
6402
|
-
const crs = getBitS2(b, i + 224, 8, i + 240, 10) * 2 ** -6;
|
|
6403
|
-
const sqrtA = getBitU22(b, i + 250, 12, i + 270, 20) * 2 ** -19;
|
|
6404
|
-
const toe1 = getBitU(b, i + 290, 2);
|
|
6405
|
-
i = 8 * 38 * 2;
|
|
6406
|
-
const frn3 = getBitU(b, i + 15, 3);
|
|
6407
|
-
const sow3 = getBitU22(b, i + 18, 8, i + 30, 12);
|
|
6408
|
-
const toe2 = getBitU22(b, i + 42, 10, i + 60, 5);
|
|
6409
|
-
const i0 = getBitS2(b, i + 65, 17, i + 90, 15) * 2 ** -31 * GPS_PI;
|
|
6410
|
-
const cic = getBitS2(b, i + 105, 7, i + 120, 11) * 2 ** -31;
|
|
6411
|
-
const omegaDot = getBitS2(b, i + 131, 11, i + 150, 13) * 2 ** -43 * GPS_PI;
|
|
6412
|
-
const cis = getBitS2(b, i + 163, 9, i + 180, 9) * 2 ** -31;
|
|
6413
|
-
const idot = getBitS2(b, i + 189, 13, i + 210, 1) * 2 ** -43 * GPS_PI;
|
|
6414
|
-
const omega0 = getBitS2(b, i + 211, 21, i + 240, 11) * 2 ** -31 * GPS_PI;
|
|
6415
|
-
const omega = getBitS2(b, i + 251, 11, i + 270, 21) * 2 ** -31 * GPS_PI;
|
|
6416
|
-
const toes = (toe1 * 2 ** 15 + toe2) * 8;
|
|
6417
|
-
if (frn1 !== 1 || frn2 !== 2 || frn3 !== 3) return null;
|
|
6418
|
-
if (sow2 !== sow1 + 6 || sow3 !== sow2 + 6) return null;
|
|
6419
|
-
if (tocSec !== toes) return null;
|
|
6420
|
-
return buildBdsEphemeris(opts.prn ?? "C00", {
|
|
6421
|
-
week,
|
|
6422
|
-
sow: sow1,
|
|
6423
|
-
toes,
|
|
6424
|
-
tocSec,
|
|
6425
|
-
svh,
|
|
6426
|
-
tgd1,
|
|
6427
|
-
af0,
|
|
6428
|
-
af1,
|
|
6429
|
-
af2,
|
|
6430
|
-
crs,
|
|
6431
|
-
deltaN,
|
|
6432
|
-
m0,
|
|
6433
|
-
cuc,
|
|
6434
|
-
e,
|
|
6435
|
-
cus,
|
|
6436
|
-
sqrtA,
|
|
6437
|
-
cic,
|
|
6438
|
-
omega0,
|
|
6439
|
-
cis,
|
|
6440
|
-
i0,
|
|
6441
|
-
crc,
|
|
6442
|
-
omega,
|
|
6443
|
-
omegaDot,
|
|
6444
|
-
idot
|
|
6705
|
+
function parseSbfAlmanac(data) {
|
|
6706
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
6707
|
+
const almanacs = [];
|
|
6708
|
+
const badCrc = scanSbfFrames(data, view, (id, b, len) => {
|
|
6709
|
+
let alm = null;
|
|
6710
|
+
if (id === 5892 && len >= 60) alm = decodeGpsGalAlm(view, b, "G");
|
|
6711
|
+
else if (id === 4003 && len >= 61) alm = decodeGpsGalAlm(view, b, "E");
|
|
6712
|
+
else if (id === 4119 && len >= 60) alm = decodeBdsAlm(view, b);
|
|
6713
|
+
else if (id === 4005 && len >= 60) alm = decodeGloAlm(view, b);
|
|
6714
|
+
if (alm) almanacs.push(alm);
|
|
6445
6715
|
});
|
|
6716
|
+
return { almanacs, badCrc };
|
|
6446
6717
|
}
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
const
|
|
6452
|
-
const
|
|
6453
|
-
|
|
6454
|
-
const
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
const
|
|
6488
|
-
const
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
if (tocSec !== toes) return null;
|
|
6514
|
-
return buildBdsEphemeris(opts.prn ?? "C00", {
|
|
6515
|
-
week,
|
|
6516
|
-
sow: sow1,
|
|
6517
|
-
toes,
|
|
6518
|
-
tocSec,
|
|
6519
|
-
svh,
|
|
6520
|
-
tgd1,
|
|
6521
|
-
af0,
|
|
6522
|
-
af1: mergeS(af1p3, af1p4, 18) * 2 ** -50,
|
|
6523
|
-
af2,
|
|
6524
|
-
crs,
|
|
6525
|
-
deltaN,
|
|
6526
|
-
m0,
|
|
6527
|
-
cuc: mergeS(cucp4, cucp5, 4) * 2 ** -31,
|
|
6528
|
-
e: mergeS(ep5, ep6, 22) * 2 ** -33,
|
|
6529
|
-
cus,
|
|
6530
|
-
sqrtA,
|
|
6531
|
-
cic: mergeS(cicp6, cicp7, 8) * 2 ** -31,
|
|
6532
|
-
omega0,
|
|
6533
|
-
cis,
|
|
6534
|
-
i0: mergeS(i0p7, i0p8, 11) * 2 ** -31 * GPS_PI,
|
|
6535
|
-
crc,
|
|
6536
|
-
omega: mergeS(omegaP9, omegaP10, 5) * 2 ** -31 * GPS_PI,
|
|
6537
|
-
omegaDot: mergeS(omegaDotP8, omegaDotP9, 5) * 2 ** -43 * GPS_PI,
|
|
6538
|
-
idot
|
|
6718
|
+
|
|
6719
|
+
// src/sbf/iono.ts
|
|
6720
|
+
var F4_DNU2 = -2e10;
|
|
6721
|
+
function parseSbfIonoUtc(data) {
|
|
6722
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
6723
|
+
const ionoCorrections = {};
|
|
6724
|
+
let leapSeconds = null;
|
|
6725
|
+
const f4s = (b, n) => {
|
|
6726
|
+
const out = [];
|
|
6727
|
+
for (let k = 0; k < n; k++) {
|
|
6728
|
+
const v = view.getFloat32(b + 4 * k, true);
|
|
6729
|
+
if (v === F4_DNU2) return null;
|
|
6730
|
+
out.push(v);
|
|
6731
|
+
}
|
|
6732
|
+
return out;
|
|
6733
|
+
};
|
|
6734
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
6735
|
+
if ((id === 5893 || id === 4120) && len >= 48) {
|
|
6736
|
+
const alpha = f4s(b + 16, 4);
|
|
6737
|
+
const beta = f4s(b + 32, 4);
|
|
6738
|
+
if (!alpha || !beta) return;
|
|
6739
|
+
const sys = id === 5893 ? "GPS" : "BDS";
|
|
6740
|
+
ionoCorrections[`${sys}A`] = alpha;
|
|
6741
|
+
ionoCorrections[`${sys}B`] = beta;
|
|
6742
|
+
} else if (id === 4030 && len >= 28) {
|
|
6743
|
+
const ai = f4s(b + 16, 3);
|
|
6744
|
+
if (ai) ionoCorrections["GAL"] = ai;
|
|
6745
|
+
} else if (id === 5894 && len >= 37) {
|
|
6746
|
+
leapSeconds = view.getInt8(b + 33);
|
|
6747
|
+
}
|
|
6748
|
+
});
|
|
6749
|
+
return { ionoCorrections, leapSeconds };
|
|
6750
|
+
}
|
|
6751
|
+
|
|
6752
|
+
// src/sbf/rawnav.ts
|
|
6753
|
+
var SIGNAL_OF_BLOCK = {
|
|
6754
|
+
4018: "L2C",
|
|
6755
|
+
4019: "L5"
|
|
6756
|
+
};
|
|
6757
|
+
function parseSbfCnav(data) {
|
|
6758
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
6759
|
+
const ephemerides = [];
|
|
6760
|
+
const assemblers = {
|
|
6761
|
+
L2C: new CnavAssembler(),
|
|
6762
|
+
L5: new CnavAssembler()
|
|
6763
|
+
};
|
|
6764
|
+
let badCrc = 0;
|
|
6765
|
+
let messages = 0;
|
|
6766
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
6767
|
+
const signal = SIGNAL_OF_BLOCK[id];
|
|
6768
|
+
if (!signal || len < 60) return;
|
|
6769
|
+
messages++;
|
|
6770
|
+
const msg = new Uint8Array(40);
|
|
6771
|
+
for (let k = 0; k < 10; k++) {
|
|
6772
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
6773
|
+
msg[4 * k] = w >>> 24;
|
|
6774
|
+
msg[4 * k + 1] = w >>> 16 & 255;
|
|
6775
|
+
msg[4 * k + 2] = w >>> 8 & 255;
|
|
6776
|
+
msg[4 * k + 3] = w & 255;
|
|
6777
|
+
}
|
|
6778
|
+
if (!cnavCrcOk(msg)) {
|
|
6779
|
+
badCrc++;
|
|
6780
|
+
return;
|
|
6781
|
+
}
|
|
6782
|
+
const eph = assemblers[signal].push(msg);
|
|
6783
|
+
if (eph) ephemerides.push({ ...eph, signal });
|
|
6539
6784
|
});
|
|
6785
|
+
return { ephemerides, badCrc, messages };
|
|
6540
6786
|
}
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
var
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
const
|
|
6556
|
-
if (
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6787
|
+
|
|
6788
|
+
// src/sbf/rawnav-gal.ts
|
|
6789
|
+
var INAV_SOURCES = [17, 21, 22];
|
|
6790
|
+
var FNAV_SOURCES = [20, 22];
|
|
6791
|
+
function parseSbfGalNav(data) {
|
|
6792
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
6793
|
+
const ephemerides = [];
|
|
6794
|
+
const inav = new GalInavAssembler();
|
|
6795
|
+
const fnav = new GalFnavAssembler();
|
|
6796
|
+
let badCrc = 0;
|
|
6797
|
+
let messages = 0;
|
|
6798
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
6799
|
+
if (id !== 4022 && id !== 4023 || len < 52) return;
|
|
6800
|
+
messages++;
|
|
6801
|
+
const prnStr = svidToPrn(data[b + 14]);
|
|
6802
|
+
if (!prnStr || prnStr[0] !== "E") return;
|
|
6803
|
+
const prn = parseInt(prnStr.slice(1), 10);
|
|
6804
|
+
const source = data[b + 17] & 31;
|
|
6805
|
+
const page = new Uint8Array(32);
|
|
6806
|
+
for (let k = 0; k < 8; k++) {
|
|
6807
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
6808
|
+
page[4 * k] = w >>> 24;
|
|
6809
|
+
page[4 * k + 1] = w >>> 16 & 255;
|
|
6810
|
+
page[4 * k + 2] = w >>> 8 & 255;
|
|
6811
|
+
page[4 * k + 3] = w & 255;
|
|
6561
6812
|
}
|
|
6562
|
-
let eph
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6813
|
+
let eph;
|
|
6814
|
+
let src;
|
|
6815
|
+
if (id === 4023) {
|
|
6816
|
+
src = "inav";
|
|
6817
|
+
if (!INAV_SOURCES.includes(source)) return;
|
|
6818
|
+
if (getBitU22(page, 0) !== 0 || getBitU22(page, 114) !== 1) return;
|
|
6819
|
+
if (!galInavPageCrcOk(page)) {
|
|
6820
|
+
badCrc++;
|
|
6821
|
+
return;
|
|
6822
|
+
}
|
|
6823
|
+
eph = inav.push(prn, page);
|
|
6566
6824
|
} else {
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
if (
|
|
6570
|
-
|
|
6571
|
-
|
|
6825
|
+
src = "fnav";
|
|
6826
|
+
if (!FNAV_SOURCES.includes(source)) return;
|
|
6827
|
+
if (isFnavDummy(page)) return;
|
|
6828
|
+
if (!galFnavPageCrcOk(page)) {
|
|
6829
|
+
badCrc++;
|
|
6830
|
+
return;
|
|
6831
|
+
}
|
|
6832
|
+
eph = fnav.push(prn, page);
|
|
6572
6833
|
}
|
|
6573
|
-
if (
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
sat.lastKey = key;
|
|
6577
|
-
return eph;
|
|
6578
|
-
}
|
|
6579
|
-
};
|
|
6580
|
-
|
|
6581
|
-
// src/navbits/glo.ts
|
|
6582
|
-
var GPS_EPOCH_MS7 = Date.UTC(1980, 0, 6);
|
|
6583
|
-
var SEC_PER_WEEK7 = 7 * 86400;
|
|
6584
|
-
var SEC_PER_DAY = 86400;
|
|
6585
|
-
var GLO_STRING_BYTES = 10;
|
|
6586
|
-
function getBitG(b, pos, len) {
|
|
6587
|
-
const value = getBitU(b, pos + 1, len - 1);
|
|
6588
|
-
return getBitU(b, pos, 1) && value !== 0 ? -value : value;
|
|
6834
|
+
if (eph) ephemerides.push({ ...eph, source: src });
|
|
6835
|
+
});
|
|
6836
|
+
return { ephemerides, badCrc, messages };
|
|
6589
6837
|
}
|
|
6590
|
-
|
|
6591
|
-
[
|
|
6592
|
-
[102, 102, 108, 204, 204, 204, 217, 153, 179, 104, 16],
|
|
6593
|
-
[135, 135, 143, 15, 15, 15, 30, 30, 60, 112, 32],
|
|
6594
|
-
[7, 248, 15, 240, 15, 240, 31, 224, 63, 128, 64],
|
|
6595
|
-
[248, 0, 15, 255, 240, 0, 31, 255, 192, 0, 128],
|
|
6596
|
-
[0, 0, 15, 255, 255, 255, 224, 0, 0, 1, 0],
|
|
6597
|
-
[255, 255, 240, 0, 0, 0, 0, 0, 0, 2, 0],
|
|
6598
|
-
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 248]
|
|
6599
|
-
];
|
|
6600
|
-
function testGloString(buff) {
|
|
6601
|
-
if (buff.length < 11) return false;
|
|
6602
|
-
let n = 0;
|
|
6603
|
-
let cs = 0;
|
|
6604
|
-
for (const mask of HAMMING_MASKS) {
|
|
6605
|
-
cs = 0;
|
|
6606
|
-
for (let j = 0; j < 11; j++) {
|
|
6607
|
-
let x = buff[j] & mask[j];
|
|
6608
|
-
x ^= x >> 4;
|
|
6609
|
-
x ^= x >> 2;
|
|
6610
|
-
x ^= x >> 1;
|
|
6611
|
-
cs ^= x & 1;
|
|
6612
|
-
}
|
|
6613
|
-
if (cs) n++;
|
|
6614
|
-
}
|
|
6615
|
-
return n === 0 || n === 2 && cs === 1;
|
|
6838
|
+
function getBitU22(buff, pos) {
|
|
6839
|
+
return buff[pos >> 3] >> 7 - (pos & 7) & 1;
|
|
6616
6840
|
}
|
|
6617
|
-
function
|
|
6618
|
-
|
|
6619
|
-
const b = strings;
|
|
6620
|
-
let i = 1;
|
|
6621
|
-
const frn1 = getBitU(b, i, 4);
|
|
6622
|
-
i += 4 + 2;
|
|
6623
|
-
i += 2;
|
|
6624
|
-
const tkH = getBitU(b, i, 5);
|
|
6625
|
-
i += 5;
|
|
6626
|
-
const tkM = getBitU(b, i, 6);
|
|
6627
|
-
i += 6;
|
|
6628
|
-
const tkS = getBitU(b, i, 1) * 30;
|
|
6629
|
-
i += 1;
|
|
6630
|
-
const xDot = getBitG(b, i, 24) * 2 ** -20;
|
|
6631
|
-
i += 24;
|
|
6632
|
-
const xAcc = getBitG(b, i, 5) * 2 ** -30;
|
|
6633
|
-
i += 5;
|
|
6634
|
-
const x = getBitG(b, i, 27) * 2 ** -11;
|
|
6635
|
-
i = 80 + 1;
|
|
6636
|
-
const frn2 = getBitU(b, i, 4);
|
|
6637
|
-
i += 4;
|
|
6638
|
-
const bn = getBitU(b, i, 1);
|
|
6639
|
-
i += 1 + 2;
|
|
6640
|
-
i += 1;
|
|
6641
|
-
const tb = getBitU(b, i, 7);
|
|
6642
|
-
i += 7 + 5;
|
|
6643
|
-
const yDot = getBitG(b, i, 24) * 2 ** -20;
|
|
6644
|
-
i += 24;
|
|
6645
|
-
const yAcc = getBitG(b, i, 5) * 2 ** -30;
|
|
6646
|
-
i += 5;
|
|
6647
|
-
const y = getBitG(b, i, 27) * 2 ** -11;
|
|
6648
|
-
i = 160 + 1;
|
|
6649
|
-
const frn3 = getBitU(b, i, 4);
|
|
6650
|
-
i += 4;
|
|
6651
|
-
i += 1;
|
|
6652
|
-
const gammaN = getBitG(b, i, 11) * 2 ** -40;
|
|
6653
|
-
i += 11 + 1;
|
|
6654
|
-
i += 2;
|
|
6655
|
-
i += 1;
|
|
6656
|
-
const zDot = getBitG(b, i, 24) * 2 ** -20;
|
|
6657
|
-
i += 24;
|
|
6658
|
-
const zAcc = getBitG(b, i, 5) * 2 ** -30;
|
|
6659
|
-
i += 5;
|
|
6660
|
-
const z = getBitG(b, i, 27) * 2 ** -11;
|
|
6661
|
-
i = 240 + 1;
|
|
6662
|
-
const frn4 = getBitU(b, i, 4);
|
|
6663
|
-
i += 4;
|
|
6664
|
-
const tauN = getBitG(b, i, 22) * 2 ** -30;
|
|
6665
|
-
i += 22;
|
|
6666
|
-
i += 5;
|
|
6667
|
-
i += 5;
|
|
6668
|
-
i += 14;
|
|
6669
|
-
i += 1;
|
|
6670
|
-
i += 4;
|
|
6671
|
-
i += 3;
|
|
6672
|
-
i += 11;
|
|
6673
|
-
const slot = getBitU(b, i, 5);
|
|
6674
|
-
if (frn1 !== 1 || frn2 !== 2 || frn3 !== 3 || frn4 !== 4) return null;
|
|
6675
|
-
if (slot < 1 || slot > 27) return null;
|
|
6676
|
-
const utcSec = (getUtcDate(refDate).getTime() - GPS_EPOCH_MS7) / 1e3;
|
|
6677
|
-
const week = Math.floor(utcSec / SEC_PER_WEEK7);
|
|
6678
|
-
let tow = utcSec - week * SEC_PER_WEEK7;
|
|
6679
|
-
const tod = tow % SEC_PER_DAY;
|
|
6680
|
-
tow -= tod;
|
|
6681
|
-
let tof = tkH * 3600 + tkM * 60 + tkS - 10800;
|
|
6682
|
-
if (tof < tod - 43200) tof += SEC_PER_DAY;
|
|
6683
|
-
else if (tof > tod + 43200) tof -= SEC_PER_DAY;
|
|
6684
|
-
let toe = tb * 900 - 10800;
|
|
6685
|
-
if (toe < tod - 43200) toe += SEC_PER_DAY;
|
|
6686
|
-
else if (toe > tod + 43200) toe -= SEC_PER_DAY;
|
|
6687
|
-
return {
|
|
6688
|
-
system: "R",
|
|
6689
|
-
prn: `R${String(slot).padStart(2, "0")}`,
|
|
6690
|
-
// RINEX GLONASS epochs are UTC: build the UTC toe Date directly.
|
|
6691
|
-
tocDate: new Date(GPS_EPOCH_MS7 + (week * SEC_PER_WEEK7 + tow + toe) * 1e3),
|
|
6692
|
-
tauN: -tauN,
|
|
6693
|
-
// RINEX stores −τn; the SIS carries τn (ICD sign)
|
|
6694
|
-
gammaN,
|
|
6695
|
-
// v3 message frame time: seconds of the UTC week (RTKLIB tof).
|
|
6696
|
-
messageFrameTime: ((tow + tof) % SEC_PER_WEEK7 + SEC_PER_WEEK7) % SEC_PER_WEEK7,
|
|
6697
|
-
x,
|
|
6698
|
-
xDot,
|
|
6699
|
-
xAcc,
|
|
6700
|
-
y,
|
|
6701
|
-
yDot,
|
|
6702
|
-
yAcc,
|
|
6703
|
-
z,
|
|
6704
|
-
zDot,
|
|
6705
|
-
zAcc,
|
|
6706
|
-
// MSB of the 3-bit Bn word — the unhealthy flag RINEX carries
|
|
6707
|
-
health: bn,
|
|
6708
|
-
freqNum: opts.freqNum ?? 0
|
|
6709
|
-
};
|
|
6841
|
+
function isFnavDummy(page) {
|
|
6842
|
+
return page[0] >> 2 === 63;
|
|
6710
6843
|
}
|
|
6711
|
-
var GloStringAssembler = class {
|
|
6712
|
-
sats = /* @__PURE__ */ new Map();
|
|
6713
|
-
/**
|
|
6714
|
-
* Push one navigation string (10+ bytes, bit 0 = string bit 85) for
|
|
6715
|
-
* the satellite `prn` ("R09"), received at the GPS-scale `time`.
|
|
6716
|
-
* Returns the newly completed ephemeris, or null. The decoded
|
|
6717
|
-
* string-4 slot number must match `prn`, or nothing is emitted.
|
|
6718
|
-
*/
|
|
6719
|
-
push(prn, str, time, freqNum = 0) {
|
|
6720
|
-
if (str.length < GLO_STRING_BYTES) return null;
|
|
6721
|
-
const m = getBitU(str, 1, 4);
|
|
6722
|
-
if (m < 1) return null;
|
|
6723
|
-
const sec = Math.floor(time.getTime() / 1e3);
|
|
6724
|
-
let sat = this.sats.get(prn);
|
|
6725
|
-
if (!sat) {
|
|
6726
|
-
sat = { buf: new Uint8Array(4 * GLO_STRING_BYTES), batchSec: sec };
|
|
6727
|
-
this.sats.set(prn, sat);
|
|
6728
|
-
} else if (Math.abs(sec - sat.batchSec) > 30) {
|
|
6729
|
-
sat.buf.fill(0);
|
|
6730
|
-
sat.batchSec = sec;
|
|
6731
|
-
}
|
|
6732
|
-
if (m > 4) return null;
|
|
6733
|
-
sat.buf.set(str.subarray(0, GLO_STRING_BYTES), (m - 1) * 10);
|
|
6734
|
-
if (m !== 4) return null;
|
|
6735
|
-
const eph = decodeGloStrings(sat.buf, time, { freqNum });
|
|
6736
|
-
if (!eph || eph.prn !== prn) return null;
|
|
6737
|
-
const key = `${eph.tocDate.getTime()}:${eph.health}`;
|
|
6738
|
-
if (key === sat.lastKey) return null;
|
|
6739
|
-
sat.lastKey = key;
|
|
6740
|
-
return eph;
|
|
6741
|
-
}
|
|
6742
|
-
};
|
|
6743
6844
|
|
|
6744
6845
|
// src/sbf/rawnav-bds.ts
|
|
6745
|
-
var
|
|
6846
|
+
var GPS_EPOCH_MS9 = Date.UTC(1980, 0, 6);
|
|
6746
6847
|
var MS_PER_WEEK5 = 7 * 86400 * 1e3;
|
|
6747
6848
|
var TOW_DNU = 4294967295;
|
|
6748
6849
|
var WNC_DNU = 65535;
|
|
@@ -6812,7 +6913,7 @@ function parseSbfGloNav(data) {
|
|
|
6812
6913
|
const eph = assembler.push(
|
|
6813
6914
|
prn,
|
|
6814
6915
|
str,
|
|
6815
|
-
new Date(
|
|
6916
|
+
new Date(GPS_EPOCH_MS9 + wnc * MS_PER_WEEK5 + towMs),
|
|
6816
6917
|
view.getUint8(b + 18) - 8
|
|
6817
6918
|
// FreqNr, offset by 8
|
|
6818
6919
|
);
|
|
@@ -7346,7 +7447,7 @@ function parseSbfHas(data) {
|
|
|
7346
7447
|
|
|
7347
7448
|
// src/sbf/index.ts
|
|
7348
7449
|
var CLIGHT = 299792458;
|
|
7349
|
-
var
|
|
7450
|
+
var GPS_EPOCH_MS10 = Date.UTC(1980, 0, 6);
|
|
7350
7451
|
var MS_PER_WEEK6 = 7 * 864e5;
|
|
7351
7452
|
var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
|
|
7352
7453
|
var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
|
|
@@ -7446,23 +7547,23 @@ var MEAS2_SIG = [
|
|
|
7446
7547
|
["J", "1E"],
|
|
7447
7548
|
["J", "5P"]
|
|
7448
7549
|
];
|
|
7449
|
-
var
|
|
7550
|
+
var two4 = (n) => String(n).padStart(2, "0");
|
|
7450
7551
|
function m3Prn(navsys, svid) {
|
|
7451
7552
|
switch (navsys) {
|
|
7452
7553
|
case 0:
|
|
7453
|
-
return svid < 32 ? `G${
|
|
7554
|
+
return svid < 32 ? `G${two4(svid + 1)}` : null;
|
|
7454
7555
|
case 1:
|
|
7455
|
-
return svid < 27 ? `R${
|
|
7556
|
+
return svid < 27 ? `R${two4(svid + 1)}` : null;
|
|
7456
7557
|
case 2:
|
|
7457
|
-
return svid < 36 ? `E${
|
|
7558
|
+
return svid < 36 ? `E${two4(svid + 1)}` : null;
|
|
7458
7559
|
case 3:
|
|
7459
|
-
return svid < 50 ? `C${
|
|
7560
|
+
return svid < 50 ? `C${two4(svid + 1)}` : null;
|
|
7460
7561
|
case 4:
|
|
7461
|
-
return svid <= 38 ? `S${
|
|
7562
|
+
return svid <= 38 ? `S${two4(svid + 20)}` : null;
|
|
7462
7563
|
case 5:
|
|
7463
|
-
return svid < 10 ? `J${
|
|
7564
|
+
return svid < 10 ? `J${two4(svid + 1)}` : null;
|
|
7464
7565
|
case 6:
|
|
7465
|
-
return svid < 14 ? `I${
|
|
7566
|
+
return svid < 14 ? `I${two4(svid + 1)}` : null;
|
|
7466
7567
|
default:
|
|
7467
7568
|
return null;
|
|
7468
7569
|
}
|
|
@@ -8000,7 +8101,7 @@ function parseSbfMeas(data) {
|
|
|
8000
8101
|
const tow = view.getUint32(i + 8, true);
|
|
8001
8102
|
const wnc = view.getUint16(i + 12, true);
|
|
8002
8103
|
if (tow !== 4294967295 && wnc !== 65535) {
|
|
8003
|
-
ensureEpoch(
|
|
8104
|
+
ensureEpoch(GPS_EPOCH_MS10 + wnc * MS_PER_WEEK6 + tow);
|
|
8004
8105
|
if (id === 4109) decodeMeas3Ranges(i, tow);
|
|
8005
8106
|
else if (id === 4110) decodeMeas3CN0(i, len);
|
|
8006
8107
|
else if (id === 4111) decodeMeas3Doppler(i, len);
|
|
@@ -8065,15 +8166,15 @@ var ID_GALEPHEMERIS = 1122;
|
|
|
8065
8166
|
var ID_QZSSEPHEMERIS = 1336;
|
|
8066
8167
|
var ID_GPSEPHEM = 7;
|
|
8067
8168
|
var ID_BDSEPHEMERIS = 1696;
|
|
8068
|
-
var
|
|
8169
|
+
var GPS_EPOCH_MS11 = Date.UTC(1980, 0, 6);
|
|
8069
8170
|
var BDT_EPOCH_MS3 = Date.UTC(2006, 0, 1);
|
|
8070
|
-
var
|
|
8171
|
+
var SEC_PER_WEEK9 = 7 * 86400;
|
|
8071
8172
|
var SEC_PER_DAY2 = 86400;
|
|
8072
|
-
var MS_PER_WEEK7 =
|
|
8073
|
-
var gpsMs2 = (week, sec) =>
|
|
8074
|
-
var sowOf3 = (dateMs) => dateMs / 1e3 %
|
|
8173
|
+
var MS_PER_WEEK7 = SEC_PER_WEEK9 * 1e3;
|
|
8174
|
+
var gpsMs2 = (week, sec) => GPS_EPOCH_MS11 + week * MS_PER_WEEK7 + sec * 1e3;
|
|
8175
|
+
var sowOf3 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK9;
|
|
8075
8176
|
function nearWeekMs(refMs, sow) {
|
|
8076
|
-
const refWeek = Math.floor((refMs -
|
|
8177
|
+
const refWeek = Math.floor((refMs - GPS_EPOCH_MS11) / MS_PER_WEEK7);
|
|
8077
8178
|
let ms = gpsMs2(refWeek, sow);
|
|
8078
8179
|
if (ms < refMs - MS_PER_WEEK7 / 2) ms += MS_PER_WEEK7;
|
|
8079
8180
|
else if (ms > refMs + MS_PER_WEEK7 / 2) ms -= MS_PER_WEEK7;
|
|
@@ -8100,9 +8201,9 @@ function decodeGloEphemeris(view, p) {
|
|
|
8100
8201
|
tof += Math.floor(tow / SEC_PER_DAY2) * SEC_PER_DAY2;
|
|
8101
8202
|
if (tof < tow - 43200) tof += SEC_PER_DAY2;
|
|
8102
8203
|
else if (tof > tow + 43200) tof -= SEC_PER_DAY2;
|
|
8103
|
-
const toeGpsMs =
|
|
8104
|
-
const tofGpsMs =
|
|
8105
|
-
const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() -
|
|
8204
|
+
const toeGpsMs = GPS_EPOCH_MS11 + (week * SEC_PER_WEEK9 + tow) * 1e3;
|
|
8205
|
+
const tofGpsMs = GPS_EPOCH_MS11 + (week * SEC_PER_WEEK9 + tof) * 1e3;
|
|
8206
|
+
const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS11) / 1e3;
|
|
8106
8207
|
return {
|
|
8107
8208
|
system: "R",
|
|
8108
8209
|
prn: `R${String(slot).padStart(2, "0")}`,
|
|
@@ -8110,7 +8211,7 @@ function decodeGloEphemeris(view, p) {
|
|
|
8110
8211
|
tauN: -view.getFloat64(p + 100, true),
|
|
8111
8212
|
// RINEX stores −τ_n
|
|
8112
8213
|
gammaN: view.getFloat64(p + 116, true),
|
|
8113
|
-
messageFrameTime: (tofUtcSec %
|
|
8214
|
+
messageFrameTime: (tofUtcSec % SEC_PER_WEEK9 + SEC_PER_WEEK9) % SEC_PER_WEEK9,
|
|
8114
8215
|
x: view.getFloat64(p + 28, true) / 1e3,
|
|
8115
8216
|
y: view.getFloat64(p + 36, true) / 1e3,
|
|
8116
8217
|
z: view.getFloat64(p + 44, true) / 1e3,
|
|
@@ -8167,7 +8268,7 @@ function decodeGalEphemeris(view, p, headerMs) {
|
|
|
8167
8268
|
omega: view.getFloat64(p + 60, true),
|
|
8168
8269
|
omegaDot: view.getFloat64(p + 140, true),
|
|
8169
8270
|
idot: view.getFloat64(p + 124, true),
|
|
8170
|
-
week: Math.floor((toeMs -
|
|
8271
|
+
week: Math.floor((toeMs - GPS_EPOCH_MS11) / MS_PER_WEEK7),
|
|
8171
8272
|
// RINEX Galileo SVH bit layout (E1B DVS/HS in bits 0-2, E5a in
|
|
8172
8273
|
// 3-5, E5b in 6-8) — same packing as RTKLIB.
|
|
8173
8274
|
svHealth: svhE5b << 7 | dvsE5b << 6 | svhE5a << 4 | dvsE5a << 3 | svhE1b << 1 | dvsE1b,
|
|
@@ -8339,7 +8440,7 @@ function parseNovatelNav(data) {
|
|
|
8339
8440
|
}
|
|
8340
8441
|
|
|
8341
8442
|
// src/novatel/index.ts
|
|
8342
|
-
var
|
|
8443
|
+
var GPS_EPOCH_MS12 = Date.UTC(1980, 0, 6);
|
|
8343
8444
|
var MS_PER_WEEK8 = 7 * 864e5;
|
|
8344
8445
|
var HDR = 28;
|
|
8345
8446
|
var ID_RANGE = 43;
|
|
@@ -8509,7 +8610,7 @@ function parseNovatelRange(data) {
|
|
|
8509
8610
|
if (!codes.includes(code)) codes.push(code);
|
|
8510
8611
|
}
|
|
8511
8612
|
epochs.push({
|
|
8512
|
-
timeMs:
|
|
8613
|
+
timeMs: GPS_EPOCH_MS12 + week * MS_PER_WEEK8 + towMs,
|
|
8513
8614
|
meas
|
|
8514
8615
|
});
|
|
8515
8616
|
}
|
|
@@ -8561,7 +8662,7 @@ function parseNovatelRange(data) {
|
|
|
8561
8662
|
if (!codes.includes(code)) codes.push(code);
|
|
8562
8663
|
}
|
|
8563
8664
|
epochs.push({
|
|
8564
|
-
timeMs:
|
|
8665
|
+
timeMs: GPS_EPOCH_MS12 + week * MS_PER_WEEK8 + towMs,
|
|
8565
8666
|
meas
|
|
8566
8667
|
});
|
|
8567
8668
|
}
|
|
@@ -8575,7 +8676,7 @@ function parseNovatelRange(data) {
|
|
|
8575
8676
|
var GM_GPS = 3986005e8;
|
|
8576
8677
|
var GM_GAL = 3986004418e5;
|
|
8577
8678
|
var GM_BDS = 3986004418e5;
|
|
8578
|
-
var
|
|
8679
|
+
var GPS_EPOCH_MS13 = Date.UTC(1980, 0, 6);
|
|
8579
8680
|
var BDT_EPOCH_MS4 = Date.UTC(2006, 0, 1);
|
|
8580
8681
|
var WEEK_MS = 6048e5;
|
|
8581
8682
|
var BDT_MINUS_GPST_MS = 14e3;
|
|
@@ -8584,7 +8685,7 @@ function almanacEpochMs(alm) {
|
|
|
8584
8685
|
if (alm.system === "C") {
|
|
8585
8686
|
return BDT_EPOCH_MS4 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3 + BDT_MINUS_GPST_MS;
|
|
8586
8687
|
}
|
|
8587
|
-
return
|
|
8688
|
+
return GPS_EPOCH_MS13 + alm.weekAlm * WEEK_MS + alm.toaSec * 1e3;
|
|
8588
8689
|
}
|
|
8589
8690
|
function almanacSatPosition(alm, timeMs) {
|
|
8590
8691
|
const GM = alm.system === "E" ? GM_GAL : alm.system === "C" ? GM_BDS : GM_GPS;
|
|
@@ -9094,10 +9195,10 @@ function selectBest(ephs, timeMs) {
|
|
|
9094
9195
|
}
|
|
9095
9196
|
return best;
|
|
9096
9197
|
}
|
|
9097
|
-
var
|
|
9198
|
+
var GPS_EPOCH_MS14 = START_GPS_TIME.getTime();
|
|
9098
9199
|
var MS_PER_WEEK9 = 7 * 864e5;
|
|
9099
9200
|
var BDS_EPOCH_MS = START_BDS_TIME.getTime();
|
|
9100
|
-
var GAL_EPOCH_MS =
|
|
9201
|
+
var GAL_EPOCH_MS = GPS_EPOCH_MS14 + 1024 * MS_PER_WEEK9;
|
|
9101
9202
|
function ephInfoToEphemeris(info) {
|
|
9102
9203
|
const sys = info.prn.charAt(0);
|
|
9103
9204
|
if (sys === "R") {
|
|
@@ -9148,8 +9249,8 @@ function ephInfoToEphemeris(info) {
|
|
|
9148
9249
|
} else if (sys === "E") {
|
|
9149
9250
|
epochMs = GAL_EPOCH_MS;
|
|
9150
9251
|
} else {
|
|
9151
|
-
epochMs =
|
|
9152
|
-
const weeksNow = (info.lastReceived -
|
|
9252
|
+
epochMs = GPS_EPOCH_MS14;
|
|
9253
|
+
const weeksNow = (info.lastReceived - GPS_EPOCH_MS14) / MS_PER_WEEK9;
|
|
9153
9254
|
week += 1024 * Math.round((weeksNow - week) / 1024);
|
|
9154
9255
|
}
|
|
9155
9256
|
const tocDate = new Date(epochMs + week * MS_PER_WEEK9 + tocSec * 1e3);
|
|
@@ -12270,6 +12371,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
12270
12371
|
parseUbxCnav,
|
|
12271
12372
|
parseUbxIonoUtc,
|
|
12272
12373
|
parseUbxNav,
|
|
12374
|
+
parseUbxRawNav,
|
|
12273
12375
|
parseUbxRawx,
|
|
12274
12376
|
phiAltBOC,
|
|
12275
12377
|
phiBOCc,
|