gnss-js 1.13.0 → 1.14.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-5IXK25MX.js +116 -0
- package/dist/chunk-SWKWJEGY.js +246 -0
- package/dist/chunk-YIHO74OS.js +723 -0
- package/dist/index.cjs +1088 -6
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +38 -26
- package/dist/novatel.cjs +270 -0
- package/dist/novatel.d.cts +57 -0
- package/dist/novatel.d.ts +57 -0
- package/dist/novatel.js +6 -0
- package/dist/sbf.cjs +747 -0
- package/dist/sbf.d.cts +63 -0
- package/dist/sbf.d.ts +63 -0
- package/dist/sbf.js +6 -0
- package/dist/ubx.cjs +140 -0
- package/dist/ubx.d.cts +56 -0
- package/dist/ubx.d.ts +56 -0
- package/dist/ubx.js +6 -0
- package/package.json +16 -1
package/dist/index.cjs
CHANGED
|
@@ -215,10 +215,13 @@ __export(src_exports, {
|
|
|
215
215
|
parseIonex: () => parseIonex,
|
|
216
216
|
parseNavFile: () => parseNavFile,
|
|
217
217
|
parseNmeaFile: () => parseNmeaFile,
|
|
218
|
+
parseNovatelRange: () => parseNovatelRange,
|
|
218
219
|
parseRinexStream: () => parseRinexStream,
|
|
220
|
+
parseSbfMeas: () => parseSbfMeas,
|
|
219
221
|
parseSinexBiasDcb: () => parseSinexBiasDcb,
|
|
220
222
|
parseSourcetable: () => parseSourcetable,
|
|
221
223
|
parseSp3: () => parseSp3,
|
|
224
|
+
parseUbxRawx: () => parseUbxRawx,
|
|
222
225
|
phiAltBOC: () => phiAltBOC,
|
|
223
226
|
phiBOCc: () => phiBOCc,
|
|
224
227
|
phiBOCs: () => phiBOCs,
|
|
@@ -4591,6 +4594,1082 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
4591
4594
|
}
|
|
4592
4595
|
}
|
|
4593
4596
|
|
|
4597
|
+
// src/ubx/index.ts
|
|
4598
|
+
var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
|
|
4599
|
+
var MS_PER_WEEK2 = 7 * 864e5;
|
|
4600
|
+
var SIGNALS = {
|
|
4601
|
+
0: { 0: ["G", "1C"], 3: ["G", "2X"], 4: ["G", "2X"] },
|
|
4602
|
+
// GPS L1C/A, L2CL, L2CM
|
|
4603
|
+
1: { 0: ["S", "1C"] },
|
|
4604
|
+
// SBAS L1C/A
|
|
4605
|
+
2: { 0: ["E", "1X"], 1: ["E", "1X"], 5: ["E", "7X"], 6: ["E", "7X"] },
|
|
4606
|
+
// E1C/B, E5bI/Q
|
|
4607
|
+
3: { 0: ["C", "2I"], 1: ["C", "2I"], 2: ["C", "7I"], 3: ["C", "7I"] },
|
|
4608
|
+
// B1I D1/D2, B2I D1/D2
|
|
4609
|
+
5: { 0: ["J", "1C"], 4: ["J", "2X"], 5: ["J", "2X"] },
|
|
4610
|
+
// QZSS L1C/A, L2CM/CL
|
|
4611
|
+
6: { 0: ["R", "1C"], 2: ["R", "2C"] }
|
|
4612
|
+
// GLONASS L1OF, L2OF
|
|
4613
|
+
};
|
|
4614
|
+
function prnFor(gnssId, svId) {
|
|
4615
|
+
const two2 = (n) => String(n).padStart(2, "0");
|
|
4616
|
+
switch (gnssId) {
|
|
4617
|
+
case 0:
|
|
4618
|
+
return svId >= 1 && svId <= 32 ? `G${two2(svId)}` : null;
|
|
4619
|
+
case 1:
|
|
4620
|
+
return svId >= 120 && svId <= 158 ? `S${two2(svId - 100)}` : null;
|
|
4621
|
+
case 2:
|
|
4622
|
+
return svId >= 1 && svId <= 36 ? `E${two2(svId)}` : null;
|
|
4623
|
+
case 3:
|
|
4624
|
+
return svId >= 1 && svId <= 63 ? `C${two2(svId)}` : null;
|
|
4625
|
+
case 5:
|
|
4626
|
+
return svId >= 1 && svId <= 10 ? `J${two2(svId)}` : null;
|
|
4627
|
+
case 6:
|
|
4628
|
+
return svId >= 1 && svId <= 32 ? `R${two2(svId)}` : null;
|
|
4629
|
+
default:
|
|
4630
|
+
return null;
|
|
4631
|
+
}
|
|
4632
|
+
}
|
|
4633
|
+
function parseUbxRawx(data) {
|
|
4634
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
4635
|
+
const epochs = [];
|
|
4636
|
+
const messageCounts = {};
|
|
4637
|
+
const obsCodes = {};
|
|
4638
|
+
let badChecksums = 0;
|
|
4639
|
+
let i = 0;
|
|
4640
|
+
while (i + 8 <= data.length) {
|
|
4641
|
+
if (data[i] !== 181 || data[i + 1] !== 98) {
|
|
4642
|
+
i++;
|
|
4643
|
+
continue;
|
|
4644
|
+
}
|
|
4645
|
+
const cls = data[i + 2];
|
|
4646
|
+
const id = data[i + 3];
|
|
4647
|
+
const len = data[i + 4] | data[i + 5] << 8;
|
|
4648
|
+
const end = i + 6 + len + 2;
|
|
4649
|
+
if (end > data.length) break;
|
|
4650
|
+
let ckA = 0;
|
|
4651
|
+
let ckB = 0;
|
|
4652
|
+
for (let j = i + 2; j < i + 6 + len; j++) {
|
|
4653
|
+
ckA = ckA + data[j] & 255;
|
|
4654
|
+
ckB = ckB + ckA & 255;
|
|
4655
|
+
}
|
|
4656
|
+
if (ckA !== data[i + 6 + len] || ckB !== data[i + 7 + len]) {
|
|
4657
|
+
badChecksums++;
|
|
4658
|
+
i++;
|
|
4659
|
+
continue;
|
|
4660
|
+
}
|
|
4661
|
+
const key = `${cls.toString(16).padStart(2, "0")}-${id.toString(16).padStart(2, "0")}`;
|
|
4662
|
+
messageCounts[key] = (messageCounts[key] ?? 0) + 1;
|
|
4663
|
+
if (cls === 2 && id === 21 && len >= 16) {
|
|
4664
|
+
const p = i + 6;
|
|
4665
|
+
const rcvTow = view.getFloat64(p, true);
|
|
4666
|
+
const week = view.getUint16(p + 8, true);
|
|
4667
|
+
const leapS = view.getInt8(p + 10);
|
|
4668
|
+
const numMeas = data[p + 11];
|
|
4669
|
+
const recStat = data[p + 12];
|
|
4670
|
+
const leapValid = (recStat & 1) !== 0;
|
|
4671
|
+
const meas = [];
|
|
4672
|
+
for (let k = 0; k < numMeas; k++) {
|
|
4673
|
+
const off = p + 16 + 32 * k;
|
|
4674
|
+
if (off + 32 > p + len) break;
|
|
4675
|
+
const gnssId = data[off + 20];
|
|
4676
|
+
const svId = data[off + 21];
|
|
4677
|
+
const sigId = data[off + 22];
|
|
4678
|
+
const trkStat = data[off + 30];
|
|
4679
|
+
const prn = prnFor(gnssId, svId);
|
|
4680
|
+
const sig = SIGNALS[gnssId]?.[sigId];
|
|
4681
|
+
if (!prn || !sig) continue;
|
|
4682
|
+
const prValid = (trkStat & 1) !== 0;
|
|
4683
|
+
const cpValid = (trkStat & 2) !== 0;
|
|
4684
|
+
const cp = view.getFloat64(off + 8, true);
|
|
4685
|
+
meas.push({
|
|
4686
|
+
prn,
|
|
4687
|
+
code: sig[1],
|
|
4688
|
+
pr: prValid ? view.getFloat64(off, true) : null,
|
|
4689
|
+
cp: cpValid && cp !== 0 ? cp : null,
|
|
4690
|
+
doppler: view.getFloat32(off + 16, true),
|
|
4691
|
+
cn0: data[off + 26],
|
|
4692
|
+
halfCycleAmbiguous: (trkStat & 4) !== 0,
|
|
4693
|
+
lockTimeMs: view.getUint16(off + 24, true)
|
|
4694
|
+
});
|
|
4695
|
+
const sys = sig[0];
|
|
4696
|
+
const codes = obsCodes[sys] ??= [];
|
|
4697
|
+
if (!codes.includes(sig[1])) codes.push(sig[1]);
|
|
4698
|
+
}
|
|
4699
|
+
epochs.push({
|
|
4700
|
+
timeMs: GPS_EPOCH_MS + week * MS_PER_WEEK2 + Math.round(rcvTow * 1e3),
|
|
4701
|
+
leapS: leapValid ? leapS : null,
|
|
4702
|
+
meas
|
|
4703
|
+
});
|
|
4704
|
+
}
|
|
4705
|
+
i = end;
|
|
4706
|
+
}
|
|
4707
|
+
return { epochs, messageCounts, obsCodes, badChecksums };
|
|
4708
|
+
}
|
|
4709
|
+
|
|
4710
|
+
// src/sbf/index.ts
|
|
4711
|
+
var CLIGHT = 299792458;
|
|
4712
|
+
var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
|
|
4713
|
+
var MS_PER_WEEK3 = 7 * 864e5;
|
|
4714
|
+
var CRC_TABLE = (() => {
|
|
4715
|
+
const t = new Uint16Array(256);
|
|
4716
|
+
for (let n = 0; n < 256; n++) {
|
|
4717
|
+
let c = n << 8;
|
|
4718
|
+
for (let k = 0; k < 8; k++)
|
|
4719
|
+
c = c & 32768 ? (c << 1 ^ 4129) & 65535 : c << 1 & 65535;
|
|
4720
|
+
t[n] = c;
|
|
4721
|
+
}
|
|
4722
|
+
return t;
|
|
4723
|
+
})();
|
|
4724
|
+
function crc16(data, start, end) {
|
|
4725
|
+
let crc = 0;
|
|
4726
|
+
for (let i = start; i < end; i++)
|
|
4727
|
+
crc = (crc << 8 ^ CRC_TABLE[(crc >> 8 ^ data[i]) & 255]) & 65535;
|
|
4728
|
+
return crc;
|
|
4729
|
+
}
|
|
4730
|
+
var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
|
|
4731
|
+
var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
|
|
4732
|
+
var M3_INTERVALS = [
|
|
4733
|
+
1,
|
|
4734
|
+
500,
|
|
4735
|
+
1e3,
|
|
4736
|
+
2e3,
|
|
4737
|
+
5e3,
|
|
4738
|
+
1e4,
|
|
4739
|
+
15e3,
|
|
4740
|
+
3e4,
|
|
4741
|
+
6e4,
|
|
4742
|
+
12e4,
|
|
4743
|
+
1,
|
|
4744
|
+
1,
|
|
4745
|
+
1,
|
|
4746
|
+
1,
|
|
4747
|
+
1,
|
|
4748
|
+
1
|
|
4749
|
+
];
|
|
4750
|
+
var M3_LOCK_TIME = [
|
|
4751
|
+
0,
|
|
4752
|
+
6e4,
|
|
4753
|
+
3e4,
|
|
4754
|
+
15e3,
|
|
4755
|
+
1e4,
|
|
4756
|
+
5e3,
|
|
4757
|
+
2e3,
|
|
4758
|
+
1e3,
|
|
4759
|
+
500,
|
|
4760
|
+
200,
|
|
4761
|
+
100,
|
|
4762
|
+
50,
|
|
4763
|
+
40,
|
|
4764
|
+
20,
|
|
4765
|
+
10,
|
|
4766
|
+
0
|
|
4767
|
+
];
|
|
4768
|
+
var M3_SIG_DEFAULT = [
|
|
4769
|
+
["1C", "2L", "5Q", "1W", "2W", "1L"],
|
|
4770
|
+
// GPS
|
|
4771
|
+
["1C", "2C", "1P", "2P", "3Q"],
|
|
4772
|
+
// GLONASS
|
|
4773
|
+
["1C", "5Q", "7Q", "6C", "8Q"],
|
|
4774
|
+
// Galileo
|
|
4775
|
+
["2I", "7I", "6I", "1P", "5P", "7D"],
|
|
4776
|
+
// BeiDou
|
|
4777
|
+
["1C", "5I"],
|
|
4778
|
+
// SBAS
|
|
4779
|
+
["1C", "2L", "5Q", "6L", "1L", "1Z", "5P", "1E"],
|
|
4780
|
+
// QZSS
|
|
4781
|
+
["5A", "1E", "9A"]
|
|
4782
|
+
// NavIC
|
|
4783
|
+
];
|
|
4784
|
+
var MEAS2_SIG = [
|
|
4785
|
+
["G", "1C"],
|
|
4786
|
+
["G", "1W"],
|
|
4787
|
+
["G", "2W"],
|
|
4788
|
+
["G", "2L"],
|
|
4789
|
+
["G", "5Q"],
|
|
4790
|
+
["G", "1L"],
|
|
4791
|
+
["J", "1C"],
|
|
4792
|
+
["J", "2L"],
|
|
4793
|
+
["R", "1C"],
|
|
4794
|
+
["R", "1P"],
|
|
4795
|
+
["R", "2P"],
|
|
4796
|
+
["R", "2C"],
|
|
4797
|
+
["R", "3Q"],
|
|
4798
|
+
["C", "1P"],
|
|
4799
|
+
["C", "5P"],
|
|
4800
|
+
["I", "5A"],
|
|
4801
|
+
null,
|
|
4802
|
+
["E", "1C"],
|
|
4803
|
+
null,
|
|
4804
|
+
["E", "6C"],
|
|
4805
|
+
["E", "5Q"],
|
|
4806
|
+
["E", "7Q"],
|
|
4807
|
+
["E", "8Q"],
|
|
4808
|
+
null,
|
|
4809
|
+
// L-band
|
|
4810
|
+
["S", "1C"],
|
|
4811
|
+
["S", "5I"],
|
|
4812
|
+
["J", "5Q"],
|
|
4813
|
+
["J", "6L"],
|
|
4814
|
+
["C", "2I"],
|
|
4815
|
+
["C", "7I"],
|
|
4816
|
+
["C", "6I"],
|
|
4817
|
+
null,
|
|
4818
|
+
["J", "1L"],
|
|
4819
|
+
["J", "1Z"],
|
|
4820
|
+
["C", "7D"],
|
|
4821
|
+
null,
|
|
4822
|
+
["I", "9A"],
|
|
4823
|
+
null,
|
|
4824
|
+
// NavIC L1 (no obs code assigned)
|
|
4825
|
+
["J", "1E"],
|
|
4826
|
+
["J", "5P"]
|
|
4827
|
+
];
|
|
4828
|
+
var two = (n) => String(n).padStart(2, "0");
|
|
4829
|
+
function m3Prn(navsys, svid) {
|
|
4830
|
+
switch (navsys) {
|
|
4831
|
+
case 0:
|
|
4832
|
+
return svid < 32 ? `G${two(svid + 1)}` : null;
|
|
4833
|
+
case 1:
|
|
4834
|
+
return svid < 27 ? `R${two(svid + 1)}` : null;
|
|
4835
|
+
case 2:
|
|
4836
|
+
return svid < 36 ? `E${two(svid + 1)}` : null;
|
|
4837
|
+
case 3:
|
|
4838
|
+
return svid < 50 ? `C${two(svid + 1)}` : null;
|
|
4839
|
+
case 4:
|
|
4840
|
+
return svid <= 38 ? `S${two(svid + 20)}` : null;
|
|
4841
|
+
case 5:
|
|
4842
|
+
return svid < 10 ? `J${two(svid + 1)}` : null;
|
|
4843
|
+
case 6:
|
|
4844
|
+
return svid < 14 ? `I${two(svid + 1)}` : null;
|
|
4845
|
+
default:
|
|
4846
|
+
return null;
|
|
4847
|
+
}
|
|
4848
|
+
}
|
|
4849
|
+
function svidToPrn(svid) {
|
|
4850
|
+
if (svid >= 1 && svid <= 37) return svid <= 32 ? `G${two(svid)}` : null;
|
|
4851
|
+
if (svid <= 61) return svid - 37 <= 27 ? `R${two(svid - 37)}` : null;
|
|
4852
|
+
if (svid <= 62) return null;
|
|
4853
|
+
if (svid <= 68) return svid - 38 <= 27 ? `R${two(svid - 38)}` : null;
|
|
4854
|
+
if (svid <= 70) return null;
|
|
4855
|
+
if (svid <= 106) return svid - 70 <= 36 ? `E${two(svid - 70)}` : null;
|
|
4856
|
+
if (svid <= 119) return null;
|
|
4857
|
+
if (svid <= 140) return `S${two(svid - 100)}`;
|
|
4858
|
+
if (svid <= 180) return svid - 140 <= 50 ? `C${two(svid - 140)}` : null;
|
|
4859
|
+
if (svid <= 190) return `J${two(svid - 180)}`;
|
|
4860
|
+
if (svid <= 197) return svid - 190 <= 14 ? `I${two(svid - 190)}` : null;
|
|
4861
|
+
if (svid <= 215) return `S${two(svid - 157)}`;
|
|
4862
|
+
if (svid <= 222) return svid - 208 <= 14 ? `I${two(svid - 208)}` : null;
|
|
4863
|
+
if (svid <= 245) return svid - 182 <= 50 ? `C${two(svid - 182)}` : null;
|
|
4864
|
+
return null;
|
|
4865
|
+
}
|
|
4866
|
+
function carrierFreq(sys, code, fcn) {
|
|
4867
|
+
const band = code.charCodeAt(0) - 48;
|
|
4868
|
+
switch (sys) {
|
|
4869
|
+
case "G":
|
|
4870
|
+
case "J":
|
|
4871
|
+
if (band === 1) return 157542e4;
|
|
4872
|
+
if (band === 2) return 12276e5;
|
|
4873
|
+
if (band === 5) return 117645e4;
|
|
4874
|
+
if (band === 6) return 127875e4;
|
|
4875
|
+
return 0;
|
|
4876
|
+
case "R":
|
|
4877
|
+
if (band === 1) return 1602e6 + fcn * 562500;
|
|
4878
|
+
if (band === 2) return 1246e6 + fcn * 437500;
|
|
4879
|
+
if (band === 3) return 1202025e3;
|
|
4880
|
+
return 0;
|
|
4881
|
+
case "E":
|
|
4882
|
+
if (band === 1) return 157542e4;
|
|
4883
|
+
if (band === 5) return 117645e4;
|
|
4884
|
+
if (band === 6) return 127875e4;
|
|
4885
|
+
if (band === 7) return 120714e4;
|
|
4886
|
+
if (band === 8) return 1191795e3;
|
|
4887
|
+
return 0;
|
|
4888
|
+
case "C":
|
|
4889
|
+
if (band === 1) return 157542e4;
|
|
4890
|
+
if (band === 2) return 1561098e3;
|
|
4891
|
+
if (band === 5) return 117645e4;
|
|
4892
|
+
if (band === 6) return 126852e4;
|
|
4893
|
+
if (band === 7) return 120714e4;
|
|
4894
|
+
if (band === 8) return 1191795e3;
|
|
4895
|
+
return 0;
|
|
4896
|
+
case "S":
|
|
4897
|
+
if (band === 1) return 157542e4;
|
|
4898
|
+
if (band === 5) return 117645e4;
|
|
4899
|
+
return 0;
|
|
4900
|
+
case "I":
|
|
4901
|
+
if (band === 1) return 157542e4;
|
|
4902
|
+
if (band === 5) return 117645e4;
|
|
4903
|
+
if (band === 9) return 2492028e3;
|
|
4904
|
+
return 0;
|
|
4905
|
+
default:
|
|
4906
|
+
return 0;
|
|
4907
|
+
}
|
|
4908
|
+
}
|
|
4909
|
+
var ZERO_REF_SLOT = {
|
|
4910
|
+
sigIdx: 0,
|
|
4911
|
+
pr: 0,
|
|
4912
|
+
cp: 0,
|
|
4913
|
+
cn0: 0,
|
|
4914
|
+
lockTimeMs: null
|
|
4915
|
+
};
|
|
4916
|
+
function freshRefEpoch(tow) {
|
|
4917
|
+
return {
|
|
4918
|
+
tow,
|
|
4919
|
+
headers: new Array(7).fill(null),
|
|
4920
|
+
sats: Array.from({ length: 7 }, () => new Array(64))
|
|
4921
|
+
};
|
|
4922
|
+
}
|
|
4923
|
+
function parseSbfMeas(data) {
|
|
4924
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
4925
|
+
const epochs = [];
|
|
4926
|
+
const messageCounts = {};
|
|
4927
|
+
const obsCodes = {};
|
|
4928
|
+
let badCrc = 0;
|
|
4929
|
+
let ref = freshRefEpoch(-1);
|
|
4930
|
+
let curTime = NaN;
|
|
4931
|
+
let curMeas = [];
|
|
4932
|
+
let curSats = [];
|
|
4933
|
+
const flush = () => {
|
|
4934
|
+
if (curMeas.length > 0) {
|
|
4935
|
+
const meas = curMeas.map((m) => {
|
|
4936
|
+
const codes = obsCodes[m.sys] ??= [];
|
|
4937
|
+
if (!codes.includes(m.code)) codes.push(m.code);
|
|
4938
|
+
return {
|
|
4939
|
+
prn: m.prn,
|
|
4940
|
+
code: m.code,
|
|
4941
|
+
pr: m.pr !== 0 ? m.pr : null,
|
|
4942
|
+
cp: m.cp !== 0 ? m.cp : null,
|
|
4943
|
+
doppler: m.doppler,
|
|
4944
|
+
cn0: m.cn0,
|
|
4945
|
+
lockTimeMs: m.lockTimeMs
|
|
4946
|
+
};
|
|
4947
|
+
});
|
|
4948
|
+
epochs.push({ timeMs: curTime, meas });
|
|
4949
|
+
}
|
|
4950
|
+
curMeas = [];
|
|
4951
|
+
curSats = [];
|
|
4952
|
+
};
|
|
4953
|
+
const ensureEpoch = (timeMs) => {
|
|
4954
|
+
if (timeMs !== curTime) {
|
|
4955
|
+
flush();
|
|
4956
|
+
curTime = timeMs;
|
|
4957
|
+
}
|
|
4958
|
+
};
|
|
4959
|
+
const decodeMeas3Ranges = (i2, tow) => {
|
|
4960
|
+
const o = i2 + 8;
|
|
4961
|
+
const constellations = view.getUint16(o + 8, true) & 127;
|
|
4962
|
+
const misc = data[o + 10];
|
|
4963
|
+
const version = data[o + 11];
|
|
4964
|
+
if (version > 31) return;
|
|
4965
|
+
if ((misc & 7) !== 0) return;
|
|
4966
|
+
const prrAvailable = (misc & 8) !== 0;
|
|
4967
|
+
const interval = M3_INTERVALS[misc >> 4];
|
|
4968
|
+
const isRef = tow % interval === 0;
|
|
4969
|
+
const dtow = tow % interval;
|
|
4970
|
+
if (isRef) {
|
|
4971
|
+
ref = freshRefEpoch(tow);
|
|
4972
|
+
} else if (ref.tow !== Math.floor(tow / interval) * interval) {
|
|
4973
|
+
curMeas = [];
|
|
4974
|
+
curSats = [];
|
|
4975
|
+
return;
|
|
4976
|
+
}
|
|
4977
|
+
let idx = o + 12;
|
|
4978
|
+
for (let navsys = 0; navsys < 7; navsys++) {
|
|
4979
|
+
if ((constellations & 1 << navsys) === 0) continue;
|
|
4980
|
+
const sys = M3_SYS[navsys];
|
|
4981
|
+
const useRefHeader = data[idx] === 0;
|
|
4982
|
+
const hdr = useRefHeader ? ref.headers[navsys] ?? new Uint8Array(0) : data.subarray(idx, idx + 32);
|
|
4983
|
+
const BF1 = hdr[0] ?? 0;
|
|
4984
|
+
let nB = BF1 & 7;
|
|
4985
|
+
if (nB === 7) nB = 8;
|
|
4986
|
+
const sigIdxMasterShort = BF1 >> 3 & 15;
|
|
4987
|
+
const sigExclPresent = BF1 >> 7 !== 0;
|
|
4988
|
+
let h = 1;
|
|
4989
|
+
const maskBytes = hdr.subarray(h, h + nB);
|
|
4990
|
+
let nSats = 0;
|
|
4991
|
+
for (const b of maskBytes)
|
|
4992
|
+
for (let k = 0; k < 8; k++) nSats += b >> k & 1;
|
|
4993
|
+
h += nB;
|
|
4994
|
+
let gloFncs = new Uint8Array(0);
|
|
4995
|
+
let bdsLongRange = 0;
|
|
4996
|
+
if (navsys === 1) {
|
|
4997
|
+
gloFncs = hdr.subarray(h, h + (nSats + 1 >> 1));
|
|
4998
|
+
h += nSats + 1 >> 1;
|
|
4999
|
+
} else if (navsys === 3) {
|
|
5000
|
+
bdsLongRange = (hdr[h] ?? 0) | (hdr[h + 1] ?? 0) << 8;
|
|
5001
|
+
h += 2;
|
|
5002
|
+
}
|
|
5003
|
+
const sigExcluded = sigExclPresent ? hdr[h++] ?? 0 : 0;
|
|
5004
|
+
if (isRef) ref.headers[navsys] = data.slice(idx, idx + h);
|
|
5005
|
+
idx += useRefHeader ? 1 : h;
|
|
5006
|
+
const sigTable = [];
|
|
5007
|
+
for (let s = 0; s < 16; s++)
|
|
5008
|
+
if ((sigExcluded & 1 << s) === 0)
|
|
5009
|
+
sigTable.push(M3_SIG_DEFAULT[navsys][s] ?? null);
|
|
5010
|
+
while (sigTable.length < 16) sigTable.push(null);
|
|
5011
|
+
let satCnt = 0;
|
|
5012
|
+
for (let svid = 0; svid < 64 && satCnt < nSats; svid++) {
|
|
5013
|
+
if (((maskBytes[svid >> 3] ?? 0) >> (svid & 7) & 1) === 0) continue;
|
|
5014
|
+
const glofnc = navsys === 1 ? ((gloFncs[satCnt >> 1] ?? 0) >> 4 * (satCnt % 2) & 15) - 8 : 0;
|
|
5015
|
+
const prn = m3Prn(navsys, svid);
|
|
5016
|
+
const prbase = navsys === 3 && (bdsLongRange & 1 << satCnt) !== 0 ? 34e6 : M3_PR_BASE[navsys];
|
|
5017
|
+
const refSat = ref.sats[navsys][svid];
|
|
5018
|
+
const refSlot = (k) => refSat?.slots[k] ?? ZERO_REF_SLOT;
|
|
5019
|
+
const entry = { navsys, svid, prn, slots: [] };
|
|
5020
|
+
const bt = data[idx];
|
|
5021
|
+
let masterSigIdx;
|
|
5022
|
+
let slaveMask;
|
|
5023
|
+
let prRate = 0;
|
|
5024
|
+
let mPr = 0;
|
|
5025
|
+
let mCp = 0;
|
|
5026
|
+
let mCn0 = 0;
|
|
5027
|
+
let mLock = null;
|
|
5028
|
+
let masterCode;
|
|
5029
|
+
let mFreq = 0;
|
|
5030
|
+
if ((bt & 1) === 1) {
|
|
5031
|
+
const BF1m = view.getUint32(idx, true);
|
|
5032
|
+
const prLsb = view.getUint32(idx + 4, true);
|
|
5033
|
+
const cmc = BF1m >>> 1 & 262143;
|
|
5034
|
+
const prMsb = BF1m >>> 19 & 1;
|
|
5035
|
+
const lti3 = BF1m >>> 20 & 7;
|
|
5036
|
+
const cn0 = BF1m >>> 23 & 31;
|
|
5037
|
+
const signalList = BF1m >>> 28 & 15;
|
|
5038
|
+
masterSigIdx = sigIdxMasterShort;
|
|
5039
|
+
slaveMask = signalList << masterSigIdx + 1;
|
|
5040
|
+
masterCode = sigTable[masterSigIdx] ?? null;
|
|
5041
|
+
if (masterCode) {
|
|
5042
|
+
mFreq = carrierFreq(sys, masterCode, glofnc);
|
|
5043
|
+
mPr = prbase + (prLsb + 4294967296 * prMsb) * 1e-3;
|
|
5044
|
+
mCn0 = cn0 + 24;
|
|
5045
|
+
if (cmc !== 0) mCp = mPr / (CLIGHT / mFreq) - 131.072 + cmc * 1e-3;
|
|
5046
|
+
mLock = M3_LOCK_TIME[lti3];
|
|
5047
|
+
}
|
|
5048
|
+
prRate = prrAvailable ? view.getInt16(idx + 8, true) : 0;
|
|
5049
|
+
idx += prrAvailable ? 10 : 8;
|
|
5050
|
+
} else if ((bt & 3) === 0) {
|
|
5051
|
+
const BF1m = view.getUint32(idx, true);
|
|
5052
|
+
const prLsb = view.getUint32(idx + 4, true);
|
|
5053
|
+
const BF2 = view.getUint16(idx + 8, true);
|
|
5054
|
+
const BF3 = data[idx + 10];
|
|
5055
|
+
const prMsb = BF1m >>> 2 & 15;
|
|
5056
|
+
const cmc = BF1m >>> 6 & 4194303;
|
|
5057
|
+
const lti4 = BF1m >>> 28 & 15;
|
|
5058
|
+
const cn0 = BF2 & 63;
|
|
5059
|
+
let signalMask = BF2 >>> 6 & 511;
|
|
5060
|
+
const cont = BF2 >>> 15 & 1;
|
|
5061
|
+
if (cont !== 0) signalMask |= (BF3 & 127) << 9;
|
|
5062
|
+
masterSigIdx = 0;
|
|
5063
|
+
while (masterSigIdx < 32 && (signalMask >> masterSigIdx & 1) === 0)
|
|
5064
|
+
masterSigIdx++;
|
|
5065
|
+
slaveMask = signalMask !== 0 ? signalMask ^ 1 << masterSigIdx : 0;
|
|
5066
|
+
masterCode = sigTable[masterSigIdx] ?? null;
|
|
5067
|
+
if (masterCode) {
|
|
5068
|
+
mFreq = carrierFreq(sys, masterCode, glofnc);
|
|
5069
|
+
const isGpsPCode = navsys === 0 && (masterCode === "1W" || masterCode === "2W");
|
|
5070
|
+
mPr = (prLsb + 4294967296 * prMsb) * 1e-3;
|
|
5071
|
+
mCn0 = isGpsPCode ? cn0 : cn0 + 10;
|
|
5072
|
+
if (cmc !== 0)
|
|
5073
|
+
mCp = mPr / (CLIGHT / mFreq) - 2097.152 + cmc * 1e-3;
|
|
5074
|
+
mLock = M3_LOCK_TIME[lti4];
|
|
5075
|
+
}
|
|
5076
|
+
prRate = prrAvailable ? view.getInt16(idx + 10, true) : 0;
|
|
5077
|
+
idx += (prrAvailable ? 12 : 10) + cont;
|
|
5078
|
+
} else if ((bt & 12) === 12) {
|
|
5079
|
+
const BF1m = data[idx];
|
|
5080
|
+
const BF2 = view.getUint32(idx + 1, true);
|
|
5081
|
+
const prDelta = BF1m >> 4 << 13 | BF2 & 8191;
|
|
5082
|
+
const cn0Delta = BF2 >>> 13 & 7;
|
|
5083
|
+
const cmc = BF2 >>> 16;
|
|
5084
|
+
masterSigIdx = refSlot(0).sigIdx;
|
|
5085
|
+
slaveMask = refSat?.slaveMask ?? 0;
|
|
5086
|
+
masterCode = sigTable[masterSigIdx] ?? null;
|
|
5087
|
+
if (masterCode) {
|
|
5088
|
+
const r = refSlot(0);
|
|
5089
|
+
mFreq = carrierFreq(sys, masterCode, glofnc);
|
|
5090
|
+
mPr = r.pr + Math.trunc((refSat?.prRate ?? 0) * 64 * dtow / 1e3) * 1e-3 + prDelta * 1e-3 - 65.536;
|
|
5091
|
+
mCn0 = r.cn0 - 4 + cn0Delta;
|
|
5092
|
+
if (cmc !== 0)
|
|
5093
|
+
mCp = (mPr - r.pr) / (CLIGHT / mFreq) + r.cp - 32.768 + cmc * 1e-3;
|
|
5094
|
+
mLock = r.lockTimeMs;
|
|
5095
|
+
}
|
|
5096
|
+
idx += 5;
|
|
5097
|
+
} else {
|
|
5098
|
+
const BF1m = view.getUint32(idx, true);
|
|
5099
|
+
const prDelta = BF1m >>> 4 & 16383;
|
|
5100
|
+
const cmc = BF1m >>> 18 & 16383;
|
|
5101
|
+
const cn0Delta = BF1m >>> 2 & 3;
|
|
5102
|
+
masterSigIdx = refSlot(0).sigIdx;
|
|
5103
|
+
slaveMask = refSat?.slaveMask ?? 0;
|
|
5104
|
+
masterCode = sigTable[masterSigIdx] ?? null;
|
|
5105
|
+
if (masterCode) {
|
|
5106
|
+
const r = refSlot(0);
|
|
5107
|
+
mFreq = carrierFreq(sys, masterCode, glofnc);
|
|
5108
|
+
mPr = r.pr + Math.trunc((refSat?.prRate ?? 0) * 64 * dtow / 1e3) * 1e-3 + prDelta * 1e-3 - 8.192;
|
|
5109
|
+
mCn0 = r.cn0 - 1 + cn0Delta;
|
|
5110
|
+
if (cmc !== 0)
|
|
5111
|
+
mCp = (mPr - r.pr) / (CLIGHT / mFreq) + r.cp - 8.192 + cmc * 1e-3;
|
|
5112
|
+
mLock = r.lockTimeMs;
|
|
5113
|
+
}
|
|
5114
|
+
idx += 4;
|
|
5115
|
+
}
|
|
5116
|
+
let masterMeas = null;
|
|
5117
|
+
if (masterCode && prn) {
|
|
5118
|
+
masterMeas = {
|
|
5119
|
+
prn,
|
|
5120
|
+
sys,
|
|
5121
|
+
code: masterCode,
|
|
5122
|
+
freq: mFreq,
|
|
5123
|
+
pr: mPr,
|
|
5124
|
+
cp: mCp,
|
|
5125
|
+
cn0: mCn0,
|
|
5126
|
+
doppler: null,
|
|
5127
|
+
lockTimeMs: mLock
|
|
5128
|
+
};
|
|
5129
|
+
curMeas.push(masterMeas);
|
|
5130
|
+
}
|
|
5131
|
+
entry.slots.push(masterMeas);
|
|
5132
|
+
let newRefSat = null;
|
|
5133
|
+
if (isRef && prn) {
|
|
5134
|
+
newRefSat = {
|
|
5135
|
+
slaveMask,
|
|
5136
|
+
prRate,
|
|
5137
|
+
slots: [
|
|
5138
|
+
{
|
|
5139
|
+
sigIdx: masterSigIdx,
|
|
5140
|
+
pr: mPr,
|
|
5141
|
+
cp: mCp,
|
|
5142
|
+
cn0: mCn0,
|
|
5143
|
+
lockTimeMs: mLock
|
|
5144
|
+
}
|
|
5145
|
+
]
|
|
5146
|
+
};
|
|
5147
|
+
ref.sats[navsys][svid] = newRefSat;
|
|
5148
|
+
}
|
|
5149
|
+
let slaveCnt = 0;
|
|
5150
|
+
let mask = slaveMask;
|
|
5151
|
+
for (let s = 1; s < 16 && mask !== 0; s++) {
|
|
5152
|
+
if ((mask & 1 << s) === 0) continue;
|
|
5153
|
+
const bt2 = data[idx];
|
|
5154
|
+
const code = sigTable[s] ?? null;
|
|
5155
|
+
const freq = code ? carrierFreq(sys, code, glofnc) : 0;
|
|
5156
|
+
let sPr = 0;
|
|
5157
|
+
let sCp = 0;
|
|
5158
|
+
let sCn0 = 0;
|
|
5159
|
+
let sLock = null;
|
|
5160
|
+
if ((bt2 & 1) === 1) {
|
|
5161
|
+
const BF1s = view.getUint32(idx, true);
|
|
5162
|
+
const BF2s = data[idx + 4];
|
|
5163
|
+
const cmcRes = BF1s >>> 1 & 65535;
|
|
5164
|
+
const prRel = BF1s >>> 17;
|
|
5165
|
+
const lti3 = BF2s & 7;
|
|
5166
|
+
const cn0 = BF2s >> 3;
|
|
5167
|
+
if (code) {
|
|
5168
|
+
sPr = mFreq > freq ? mPr + prRel * 1e-3 - 10 : mPr - prRel * 1e-3 + 10;
|
|
5169
|
+
if (cmcRes !== 0)
|
|
5170
|
+
sCp = sPr / (CLIGHT / freq) + (mCp - mPr / (CLIGHT / mFreq)) * (mFreq / freq) - 32.768 + cmcRes * 1e-3;
|
|
5171
|
+
sCn0 = navsys === 0 && (code === "1W" || code === "2W") ? mCn0 - 3 - cn0 : cn0 + 24;
|
|
5172
|
+
sLock = M3_LOCK_TIME[lti3];
|
|
5173
|
+
}
|
|
5174
|
+
idx += 5;
|
|
5175
|
+
} else if ((bt2 & 3) === 0) {
|
|
5176
|
+
const BF1s = view.getUint32(idx, true);
|
|
5177
|
+
const prLsbRel = view.getUint16(idx + 4, true);
|
|
5178
|
+
const BF3s = data[idx + 6];
|
|
5179
|
+
const cmc = BF1s >>> 2 & 4194303;
|
|
5180
|
+
const lti4 = BF1s >>> 24 & 15;
|
|
5181
|
+
const prMsbRel = BF1s >>> 28 & 7;
|
|
5182
|
+
const cn0 = BF3s & 63;
|
|
5183
|
+
if (code) {
|
|
5184
|
+
sPr = mPr + (prMsbRel * 65536 + prLsbRel) * 1e-3 - 262.144;
|
|
5185
|
+
if (cmc !== 0)
|
|
5186
|
+
sCp = sPr / (CLIGHT / freq) - 2097.152 + cmc * 1e-3;
|
|
5187
|
+
sCn0 = navsys === 0 && (code === "1W" || code === "2W") ? cn0 : cn0 + 10;
|
|
5188
|
+
sLock = M3_LOCK_TIME[lti4];
|
|
5189
|
+
}
|
|
5190
|
+
idx += 7;
|
|
5191
|
+
} else {
|
|
5192
|
+
const BF1s = view.getUint16(idx, true);
|
|
5193
|
+
const dC = data[idx + 2];
|
|
5194
|
+
const dPr = BF1s >>> 2 & 4095;
|
|
5195
|
+
const cn0Delta = BF1s >>> 14;
|
|
5196
|
+
if (code) {
|
|
5197
|
+
const rS = refSlot(slaveCnt + 1);
|
|
5198
|
+
const rM = refSlot(0);
|
|
5199
|
+
sCp = rS.cp + (mCp - rM.cp) * (freq / mFreq) - 0.128 + dC * 1e-3;
|
|
5200
|
+
sPr = rS.pr + (sCp - rS.cp) * (CLIGHT / freq) - 2.048 + dPr * 1e-3;
|
|
5201
|
+
sCn0 = rS.cn0 - 2 + cn0Delta;
|
|
5202
|
+
sLock = rS.lockTimeMs;
|
|
5203
|
+
}
|
|
5204
|
+
idx += 3;
|
|
5205
|
+
}
|
|
5206
|
+
let slaveMeas = null;
|
|
5207
|
+
if (code && prn) {
|
|
5208
|
+
slaveMeas = {
|
|
5209
|
+
prn,
|
|
5210
|
+
sys,
|
|
5211
|
+
code,
|
|
5212
|
+
freq,
|
|
5213
|
+
pr: sPr,
|
|
5214
|
+
cp: sCp,
|
|
5215
|
+
cn0: sCn0,
|
|
5216
|
+
doppler: null,
|
|
5217
|
+
lockTimeMs: sLock
|
|
5218
|
+
};
|
|
5219
|
+
curMeas.push(slaveMeas);
|
|
5220
|
+
}
|
|
5221
|
+
entry.slots.push(slaveMeas);
|
|
5222
|
+
if (newRefSat)
|
|
5223
|
+
newRefSat.slots[slaveCnt + 1] = {
|
|
5224
|
+
sigIdx: s,
|
|
5225
|
+
pr: sPr,
|
|
5226
|
+
cp: sCp,
|
|
5227
|
+
cn0: sCn0,
|
|
5228
|
+
lockTimeMs: sLock
|
|
5229
|
+
};
|
|
5230
|
+
slaveCnt++;
|
|
5231
|
+
mask &= ~(1 << s);
|
|
5232
|
+
}
|
|
5233
|
+
curSats.push(entry);
|
|
5234
|
+
satCnt++;
|
|
5235
|
+
}
|
|
5236
|
+
}
|
|
5237
|
+
};
|
|
5238
|
+
const decodeMeas3CN0 = (i2, len) => {
|
|
5239
|
+
const flags = view.getUint16(i2 + 14, true);
|
|
5240
|
+
if ((flags & 7) !== 0) return;
|
|
5241
|
+
const maxNibbles = (len - 16) * 2;
|
|
5242
|
+
let off = 0;
|
|
5243
|
+
for (const e of curSats) {
|
|
5244
|
+
if (off >= maxNibbles) break;
|
|
5245
|
+
if (!e.prn) continue;
|
|
5246
|
+
for (let k = 0; k < e.slots.length; k++) {
|
|
5247
|
+
const slot = e.slots[k];
|
|
5248
|
+
if (k > 0 && !slot) break;
|
|
5249
|
+
const nib = (data[i2 + 16 + (off >> 1)] ?? 0) >> (off & 1) * 4 & 15;
|
|
5250
|
+
if (slot && slot.cn0 !== null) slot.cn0 += nib * 0.0625 - 0.5;
|
|
5251
|
+
off++;
|
|
5252
|
+
}
|
|
5253
|
+
}
|
|
5254
|
+
};
|
|
5255
|
+
const readPrRate = (base, off) => {
|
|
5256
|
+
const byteAt = (k) => data[base + off + k] ?? 0;
|
|
5257
|
+
const v = (byteAt(0) | byteAt(1) << 8 | byteAt(2) << 16 | byteAt(3) << 24) >>> 0;
|
|
5258
|
+
let value;
|
|
5259
|
+
let size;
|
|
5260
|
+
if ((v & 2) === 0) {
|
|
5261
|
+
value = (v & 255) >>> 2;
|
|
5262
|
+
size = 1;
|
|
5263
|
+
} else if ((v & 6) === 2) {
|
|
5264
|
+
value = (v & 65535) >>> 3;
|
|
5265
|
+
size = 2;
|
|
5266
|
+
} else if ((v & 14) === 6) {
|
|
5267
|
+
value = (v & 16777215) >>> 4;
|
|
5268
|
+
size = 3;
|
|
5269
|
+
} else {
|
|
5270
|
+
value = v >>> 4;
|
|
5271
|
+
size = 4;
|
|
5272
|
+
}
|
|
5273
|
+
if ((v & 1) === 1) value = -value;
|
|
5274
|
+
return { value, size };
|
|
5275
|
+
};
|
|
5276
|
+
const decodeMeas3Doppler = (i2, len) => {
|
|
5277
|
+
const flags = view.getUint16(i2 + 14, true);
|
|
5278
|
+
if ((flags & 7) !== 0) return;
|
|
5279
|
+
let off = 0;
|
|
5280
|
+
for (const e of curSats) {
|
|
5281
|
+
if (off + 16 >= len) break;
|
|
5282
|
+
if (!e.prn) continue;
|
|
5283
|
+
const master = readPrRate(i2 + 16, off);
|
|
5284
|
+
off += master.size;
|
|
5285
|
+
if (master.value === -268435455) continue;
|
|
5286
|
+
const refPrRate = ref.sats[e.navsys][e.svid]?.prRate ?? 0;
|
|
5287
|
+
const m = e.slots[0];
|
|
5288
|
+
const mD = m ? -(master.value + refPrRate * 64) * 1e-3 / (CLIGHT / m.freq) : 0;
|
|
5289
|
+
if (m) m.doppler = mD;
|
|
5290
|
+
for (let k = 1; k < e.slots.length; k++) {
|
|
5291
|
+
const slot = e.slots[k];
|
|
5292
|
+
if (!slot) break;
|
|
5293
|
+
const slave = readPrRate(i2 + 16, off);
|
|
5294
|
+
off += slave.size;
|
|
5295
|
+
if (m)
|
|
5296
|
+
slot.doppler = (mD * (CLIGHT / m.freq) * 1e3 - slave.value) * 1e-3 / (CLIGHT / slot.freq);
|
|
5297
|
+
}
|
|
5298
|
+
}
|
|
5299
|
+
};
|
|
5300
|
+
const decodeMeasEpoch = (i2, len) => {
|
|
5301
|
+
const n1 = data[i2 + 14];
|
|
5302
|
+
const len1 = data[i2 + 15];
|
|
5303
|
+
const len2 = data[i2 + 16];
|
|
5304
|
+
if ((data[i2 + 17] & 128) !== 0) return;
|
|
5305
|
+
const end = i2 + len;
|
|
5306
|
+
let p = i2 + 20;
|
|
5307
|
+
for (let b1 = 0; b1 < n1 && p + 20 <= end; b1++) {
|
|
5308
|
+
const ant = data[p + 1] >> 5;
|
|
5309
|
+
let sig = data[p + 1] & 31;
|
|
5310
|
+
const svid = data[p + 2];
|
|
5311
|
+
const misc = data[p + 3];
|
|
5312
|
+
const info = data[p + 18];
|
|
5313
|
+
const n2 = data[p + 19];
|
|
5314
|
+
let fcn = 0;
|
|
5315
|
+
if (sig === 31) sig = (info >> 3) + 32;
|
|
5316
|
+
else if (sig >= 8 && sig <= 11) fcn = (info >> 3) - 8;
|
|
5317
|
+
const prn = svidToPrn(svid);
|
|
5318
|
+
const sigDef = MEAS2_SIG[sig] ?? null;
|
|
5319
|
+
if (ant !== 0 || !prn || !sigDef || sigDef[0] !== prn[0]) {
|
|
5320
|
+
p += len1 + len2 * n2;
|
|
5321
|
+
continue;
|
|
5322
|
+
}
|
|
5323
|
+
const [sys, code] = sigDef;
|
|
5324
|
+
const freq1 = carrierFreq(sys, code, fcn);
|
|
5325
|
+
const codeLsb = view.getUint32(p + 4, true);
|
|
5326
|
+
const dopplerRaw = view.getInt32(p + 8, true);
|
|
5327
|
+
const carrierLsb = view.getUint16(p + 12, true);
|
|
5328
|
+
const carrierMsb = view.getInt8(p + 14);
|
|
5329
|
+
const cn0Raw = data[p + 15];
|
|
5330
|
+
const lock = view.getUint16(p + 16, true);
|
|
5331
|
+
let p1 = 0;
|
|
5332
|
+
if ((misc & 15) !== 0 || codeLsb !== 0)
|
|
5333
|
+
p1 = (misc & 15) * 4294967296e-3 + codeLsb * 1e-3;
|
|
5334
|
+
const d1 = dopplerRaw !== -2147483648 ? dopplerRaw * 1e-4 : null;
|
|
5335
|
+
let l1 = 0;
|
|
5336
|
+
if (p1 !== 0 && freq1 > 0 && lock !== 65535 && (carrierMsb !== -128 || carrierLsb !== 0))
|
|
5337
|
+
l1 = p1 * freq1 / CLIGHT + carrierMsb * 65.536 + carrierLsb * 1e-3;
|
|
5338
|
+
const cn0 = cn0Raw !== 255 ? cn0Raw * 0.25 + (sig === 1 || sig === 2 ? 0 : 10) : null;
|
|
5339
|
+
curMeas.push({
|
|
5340
|
+
prn,
|
|
5341
|
+
sys,
|
|
5342
|
+
code,
|
|
5343
|
+
freq: freq1,
|
|
5344
|
+
pr: p1,
|
|
5345
|
+
cp: l1,
|
|
5346
|
+
cn0,
|
|
5347
|
+
doppler: d1,
|
|
5348
|
+
lockTimeMs: lock !== 65535 ? lock * 1e3 : null
|
|
5349
|
+
});
|
|
5350
|
+
p += len1;
|
|
5351
|
+
for (let b2 = 0; b2 < n2 && p + 12 <= end; b2++, p += len2) {
|
|
5352
|
+
let sig2 = data[p] & 31;
|
|
5353
|
+
const ant2 = data[p] >> 5;
|
|
5354
|
+
const lock2 = data[p + 1];
|
|
5355
|
+
const cn0Raw2 = data[p + 2];
|
|
5356
|
+
const offsetsMsb = data[p + 3];
|
|
5357
|
+
const carrierMsb2 = view.getInt8(p + 4);
|
|
5358
|
+
const info2 = data[p + 5];
|
|
5359
|
+
if (sig2 === 31) sig2 = (info2 >> 3) + 32;
|
|
5360
|
+
const sigDef2 = MEAS2_SIG[sig2] ?? null;
|
|
5361
|
+
if (ant2 !== 0 || !sigDef2 || sigDef2[0] !== prn[0]) continue;
|
|
5362
|
+
const code2 = sigDef2[1];
|
|
5363
|
+
const freq2 = carrierFreq(sys, code2, fcn);
|
|
5364
|
+
const codeOffMsb = (offsetsMsb & 7) << 29 >> 29;
|
|
5365
|
+
const dopplerOffMsb = offsetsMsb >> 3 << 27 >> 27;
|
|
5366
|
+
const codeOffLsb = view.getUint16(p + 6, true);
|
|
5367
|
+
const carrierLsb2 = view.getUint16(p + 8, true);
|
|
5368
|
+
const dopplerOffLsb = view.getUint16(p + 10, true);
|
|
5369
|
+
let p2 = 0;
|
|
5370
|
+
if (p1 !== 0 && (codeOffMsb !== -4 || codeOffLsb !== 0))
|
|
5371
|
+
p2 = p1 + codeOffMsb * 65.536 + codeOffLsb * 1e-3;
|
|
5372
|
+
let l2 = 0;
|
|
5373
|
+
if (p2 !== 0 && freq2 > 0 && (carrierMsb2 !== -128 || carrierLsb2 !== 0))
|
|
5374
|
+
l2 = p2 * freq2 / CLIGHT + carrierMsb2 * 65.536 + carrierLsb2 * 1e-3;
|
|
5375
|
+
let d2 = null;
|
|
5376
|
+
if (d1 !== null && freq1 > 0 && freq2 > 0 && (dopplerOffMsb !== -16 || dopplerOffLsb !== 0))
|
|
5377
|
+
d2 = d1 * freq2 / freq1 + dopplerOffMsb * 6.5536 + dopplerOffLsb * 1e-4;
|
|
5378
|
+
const cn02 = cn0Raw2 !== 255 ? cn0Raw2 * 0.25 + (sig2 === 1 || sig2 === 2 ? 0 : 10) : null;
|
|
5379
|
+
curMeas.push({
|
|
5380
|
+
prn,
|
|
5381
|
+
sys,
|
|
5382
|
+
code: code2,
|
|
5383
|
+
freq: freq2,
|
|
5384
|
+
pr: p2,
|
|
5385
|
+
cp: l2,
|
|
5386
|
+
cn0: cn02,
|
|
5387
|
+
doppler: d2,
|
|
5388
|
+
lockTimeMs: lock2 !== 255 ? lock2 * 1e3 : null
|
|
5389
|
+
});
|
|
5390
|
+
}
|
|
5391
|
+
}
|
|
5392
|
+
};
|
|
5393
|
+
let i = 0;
|
|
5394
|
+
while (i + 8 <= data.length) {
|
|
5395
|
+
if (data[i] !== 36 || data[i + 1] !== 64) {
|
|
5396
|
+
i++;
|
|
5397
|
+
continue;
|
|
5398
|
+
}
|
|
5399
|
+
const len = view.getUint16(i + 6, true);
|
|
5400
|
+
if (len < 8 || len % 4 !== 0) {
|
|
5401
|
+
i++;
|
|
5402
|
+
continue;
|
|
5403
|
+
}
|
|
5404
|
+
if (i + len > data.length) break;
|
|
5405
|
+
if (crc16(data, i + 4, i + len) !== view.getUint16(i + 2, true)) {
|
|
5406
|
+
badCrc++;
|
|
5407
|
+
i++;
|
|
5408
|
+
continue;
|
|
5409
|
+
}
|
|
5410
|
+
const id = view.getUint16(i + 4, true) & 8191;
|
|
5411
|
+
const key = String(id);
|
|
5412
|
+
messageCounts[key] = (messageCounts[key] ?? 0) + 1;
|
|
5413
|
+
if ((id === 4027 || id === 4109 || id === 4110 || id === 4111) && len >= 16) {
|
|
5414
|
+
const tow = view.getUint32(i + 8, true);
|
|
5415
|
+
const wnc = view.getUint16(i + 12, true);
|
|
5416
|
+
if (tow !== 4294967295 && wnc !== 65535) {
|
|
5417
|
+
ensureEpoch(GPS_EPOCH_MS2 + wnc * MS_PER_WEEK3 + tow);
|
|
5418
|
+
if (id === 4109) decodeMeas3Ranges(i, tow);
|
|
5419
|
+
else if (id === 4110) decodeMeas3CN0(i, len);
|
|
5420
|
+
else if (id === 4111) decodeMeas3Doppler(i, len);
|
|
5421
|
+
else decodeMeasEpoch(i, len);
|
|
5422
|
+
}
|
|
5423
|
+
}
|
|
5424
|
+
i += len;
|
|
5425
|
+
}
|
|
5426
|
+
flush();
|
|
5427
|
+
return { epochs, messageCounts, obsCodes, badCrc };
|
|
5428
|
+
}
|
|
5429
|
+
|
|
5430
|
+
// src/novatel/index.ts
|
|
5431
|
+
var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
|
|
5432
|
+
var MS_PER_WEEK4 = 7 * 864e5;
|
|
5433
|
+
var HDR = 28;
|
|
5434
|
+
var ID_RANGE = 43;
|
|
5435
|
+
var ID_RANGECMP = 140;
|
|
5436
|
+
var ID_GLOEPHEMERIS = 723;
|
|
5437
|
+
var C_LIGHT2 = 299792458;
|
|
5438
|
+
var ADR_ROLL = 8388608;
|
|
5439
|
+
function carrierFreq2(sys, code, gloK) {
|
|
5440
|
+
const band = code[0];
|
|
5441
|
+
switch (sys) {
|
|
5442
|
+
case "G":
|
|
5443
|
+
case "J":
|
|
5444
|
+
return band === "1" ? 157542e4 : band === "2" ? 12276e5 : 117645e4;
|
|
5445
|
+
case "S":
|
|
5446
|
+
return band === "1" ? 157542e4 : 117645e4;
|
|
5447
|
+
case "E":
|
|
5448
|
+
return band === "1" ? 157542e4 : band === "5" ? 117645e4 : band === "7" ? 120714e4 : band === "8" ? 1191795e3 : 127875e4;
|
|
5449
|
+
case "C":
|
|
5450
|
+
return band === "1" ? 157542e4 : band === "2" ? 1561098e3 : band === "5" ? 117645e4 : band === "7" ? 120714e4 : 126852e4;
|
|
5451
|
+
case "R": {
|
|
5452
|
+
if (gloK === null) return 0;
|
|
5453
|
+
if (band === "1") return 1602e6 + gloK * 562500;
|
|
5454
|
+
if (band === "2") return 1246e6 + gloK * 437500;
|
|
5455
|
+
return 1202025e3;
|
|
5456
|
+
}
|
|
5457
|
+
default:
|
|
5458
|
+
return 0;
|
|
5459
|
+
}
|
|
5460
|
+
}
|
|
5461
|
+
function exsign(v, bits) {
|
|
5462
|
+
return v & 1 << bits - 1 ? v - 2 ** bits : v;
|
|
5463
|
+
}
|
|
5464
|
+
function crc32(data, start, len) {
|
|
5465
|
+
let crc = 0;
|
|
5466
|
+
for (let i = start; i < start + len; i++) {
|
|
5467
|
+
crc ^= data[i];
|
|
5468
|
+
for (let j = 0; j < 8; j++) {
|
|
5469
|
+
crc = crc & 1 ? crc >>> 1 ^ 3988292384 : crc >>> 1;
|
|
5470
|
+
}
|
|
5471
|
+
}
|
|
5472
|
+
return crc >>> 0;
|
|
5473
|
+
}
|
|
5474
|
+
var SIGNALS2 = {
|
|
5475
|
+
0: {
|
|
5476
|
+
0: ["G", "1C"],
|
|
5477
|
+
5: ["G", "2P"],
|
|
5478
|
+
9: ["G", "2W"],
|
|
5479
|
+
14: ["G", "5Q"],
|
|
5480
|
+
16: ["G", "1L"],
|
|
5481
|
+
17: ["G", "2S"]
|
|
5482
|
+
},
|
|
5483
|
+
1: { 0: ["R", "1C"], 1: ["R", "2C"], 5: ["R", "2P"], 6: ["R", "3Q"] },
|
|
5484
|
+
2: { 0: ["S", "1C"], 6: ["S", "5I"] },
|
|
5485
|
+
3: {
|
|
5486
|
+
1: ["E", "1C"],
|
|
5487
|
+
2: ["E", "1C"],
|
|
5488
|
+
6: ["E", "6B"],
|
|
5489
|
+
7: ["E", "6C"],
|
|
5490
|
+
12: ["E", "5Q"],
|
|
5491
|
+
17: ["E", "7Q"],
|
|
5492
|
+
20: ["E", "8Q"]
|
|
5493
|
+
},
|
|
5494
|
+
4: {
|
|
5495
|
+
0: ["C", "2I"],
|
|
5496
|
+
1: ["C", "7I"],
|
|
5497
|
+
2: ["C", "6I"],
|
|
5498
|
+
4: ["C", "2I"],
|
|
5499
|
+
5: ["C", "7I"],
|
|
5500
|
+
6: ["C", "6I"],
|
|
5501
|
+
7: ["C", "1P"],
|
|
5502
|
+
9: ["C", "5P"],
|
|
5503
|
+
11: ["C", "7D"]
|
|
5504
|
+
},
|
|
5505
|
+
5: {
|
|
5506
|
+
0: ["J", "1C"],
|
|
5507
|
+
14: ["J", "5Q"],
|
|
5508
|
+
16: ["J", "1L"],
|
|
5509
|
+
17: ["J", "2S"],
|
|
5510
|
+
27: ["J", "6L"]
|
|
5511
|
+
},
|
|
5512
|
+
6: { 0: ["I", "5A"] }
|
|
5513
|
+
};
|
|
5514
|
+
function parseNovatelRange(data) {
|
|
5515
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
5516
|
+
const epochs = [];
|
|
5517
|
+
const messageCounts = {};
|
|
5518
|
+
const obsCodes = {};
|
|
5519
|
+
let badCrc = 0;
|
|
5520
|
+
const gloFcn = /* @__PURE__ */ new Map();
|
|
5521
|
+
for (let j = 0; j + HDR + 4 <= data.length; j++) {
|
|
5522
|
+
if (data[j] !== 170 || data[j + 1] !== 68 || data[j + 2] !== 18)
|
|
5523
|
+
continue;
|
|
5524
|
+
const hl = data[j + 3];
|
|
5525
|
+
const id = view.getUint16(j + 4, true);
|
|
5526
|
+
const ln = view.getUint16(j + 8, true);
|
|
5527
|
+
if (id !== ID_GLOEPHEMERIS || hl < HDR || j + hl + ln + 4 > data.length)
|
|
5528
|
+
continue;
|
|
5529
|
+
if (crc32(data, j, hl + ln) !== view.getUint32(j + hl + ln, true)) continue;
|
|
5530
|
+
const slot = view.getUint16(j + hl, true) - 37;
|
|
5531
|
+
const k = view.getUint16(j + hl + 2, true) - 7;
|
|
5532
|
+
if (slot >= 1 && slot <= 32) gloFcn.set(slot, k);
|
|
5533
|
+
j += hl + ln + 3;
|
|
5534
|
+
}
|
|
5535
|
+
let i = 0;
|
|
5536
|
+
while (i + HDR + 4 <= data.length) {
|
|
5537
|
+
if (data[i] !== 170 || data[i + 1] !== 68 || data[i + 2] !== 18) {
|
|
5538
|
+
i++;
|
|
5539
|
+
continue;
|
|
5540
|
+
}
|
|
5541
|
+
const hlen = data[i + 3];
|
|
5542
|
+
const msgId = view.getUint16(i + 4, true);
|
|
5543
|
+
const msgLen = view.getUint16(i + 8, true);
|
|
5544
|
+
const total = hlen + msgLen + 4;
|
|
5545
|
+
if (hlen < HDR || i + total > data.length) {
|
|
5546
|
+
i++;
|
|
5547
|
+
continue;
|
|
5548
|
+
}
|
|
5549
|
+
if (crc32(data, i, hlen + msgLen) !== view.getUint32(i + hlen + msgLen, true)) {
|
|
5550
|
+
badCrc++;
|
|
5551
|
+
i++;
|
|
5552
|
+
continue;
|
|
5553
|
+
}
|
|
5554
|
+
messageCounts[msgId] = (messageCounts[msgId] ?? 0) + 1;
|
|
5555
|
+
const binary = (data[i + 6] >> 4 & 3) === 0;
|
|
5556
|
+
const week = view.getUint16(i + 14, true);
|
|
5557
|
+
const towMs = view.getUint32(i + 16, true);
|
|
5558
|
+
if (msgId === ID_RANGECMP && binary && week > 0) {
|
|
5559
|
+
const p = i + hlen;
|
|
5560
|
+
const nobs = view.getUint32(p, true);
|
|
5561
|
+
if (p + 4 + nobs * 24 <= i + hlen + msgLen) {
|
|
5562
|
+
const meas = [];
|
|
5563
|
+
for (let k = 0; k < nobs; k++) {
|
|
5564
|
+
const o = p + 4 + 24 * k;
|
|
5565
|
+
const stat = view.getUint32(o, true);
|
|
5566
|
+
const satsys = stat >>> 16 & 7;
|
|
5567
|
+
const sigtype = stat >>> 21 & 31;
|
|
5568
|
+
const plock = stat >>> 10 & 1;
|
|
5569
|
+
const parity = stat >>> 11 & 1;
|
|
5570
|
+
const clock = stat >>> 12 & 1;
|
|
5571
|
+
const sig = SIGNALS2[satsys]?.[sigtype];
|
|
5572
|
+
if (!sig) continue;
|
|
5573
|
+
let [sysL, code] = sig;
|
|
5574
|
+
let prnNum = data[o + 17];
|
|
5575
|
+
if (sysL === "R") prnNum -= 37;
|
|
5576
|
+
if (sysL === "S" && prnNum >= 183 && prnNum <= 191 && code === "1C") {
|
|
5577
|
+
sysL = "J";
|
|
5578
|
+
code = "1Z";
|
|
5579
|
+
prnNum -= 182;
|
|
5580
|
+
} else if (sysL === "S") {
|
|
5581
|
+
prnNum -= 100;
|
|
5582
|
+
}
|
|
5583
|
+
if (prnNum < 1 || prnNum > 99) continue;
|
|
5584
|
+
if (sysL === "R" && !parity) continue;
|
|
5585
|
+
const gloK = sysL === "R" ? gloFcn.get(prnNum) ?? null : null;
|
|
5586
|
+
const dop = exsign(view.getUint32(o + 4, true) & 268435455, 28) / 256;
|
|
5587
|
+
const psr = (view.getUint32(o + 7, true) >>> 4) / 128 + data[o + 11] * 2097152;
|
|
5588
|
+
let cp = null;
|
|
5589
|
+
const freq = carrierFreq2(sysL, code, gloK);
|
|
5590
|
+
if (freq > 0) {
|
|
5591
|
+
const adr = view.getInt32(o + 12, true) / 256;
|
|
5592
|
+
const rolls = psr * freq / C_LIGHT2 / ADR_ROLL + adr / ADR_ROLL;
|
|
5593
|
+
cp = -adr + ADR_ROLL * Math.floor(rolls + (rolls <= 0 ? -0.5 : 0.5));
|
|
5594
|
+
}
|
|
5595
|
+
const lockt = (view.getUint32(o + 18, true) & 2097151) / 32;
|
|
5596
|
+
const cn0 = ((view.getUint16(o + 20, true) & 1023) >>> 5) + 20;
|
|
5597
|
+
meas.push({
|
|
5598
|
+
prn: `${sysL}${String(prnNum).padStart(2, "0")}`,
|
|
5599
|
+
code,
|
|
5600
|
+
pr: clock ? psr : null,
|
|
5601
|
+
cp: plock ? cp : null,
|
|
5602
|
+
doppler: plock ? dop : null,
|
|
5603
|
+
cn0,
|
|
5604
|
+
lockTimeS: lockt,
|
|
5605
|
+
gloChannel: gloK
|
|
5606
|
+
});
|
|
5607
|
+
const codes = obsCodes[sysL] ??= [];
|
|
5608
|
+
if (!codes.includes(code)) codes.push(code);
|
|
5609
|
+
}
|
|
5610
|
+
epochs.push({
|
|
5611
|
+
timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK4 + towMs,
|
|
5612
|
+
meas
|
|
5613
|
+
});
|
|
5614
|
+
}
|
|
5615
|
+
} else if (msgId === ID_RANGE && binary && week > 0) {
|
|
5616
|
+
const p = i + hlen;
|
|
5617
|
+
const nobs = view.getUint32(p, true);
|
|
5618
|
+
if (p + 4 + nobs * 44 <= i + hlen + msgLen) {
|
|
5619
|
+
const meas = [];
|
|
5620
|
+
for (let k = 0; k < nobs; k++) {
|
|
5621
|
+
const o = p + 4 + 44 * k;
|
|
5622
|
+
const stat = view.getUint32(o + 40, true);
|
|
5623
|
+
const satsys = stat >>> 16 & 7;
|
|
5624
|
+
const sigtype = stat >>> 21 & 31;
|
|
5625
|
+
const plock = stat >>> 10 & 1;
|
|
5626
|
+
const parity = stat >>> 11 & 1;
|
|
5627
|
+
const clock = stat >>> 12 & 1;
|
|
5628
|
+
const sig = SIGNALS2[satsys]?.[sigtype];
|
|
5629
|
+
if (!sig) continue;
|
|
5630
|
+
let [sysL, code] = sig;
|
|
5631
|
+
let prnNum = view.getUint16(o, true);
|
|
5632
|
+
if (sysL === "R") prnNum -= 37;
|
|
5633
|
+
if (sysL === "S" && prnNum >= 183 && prnNum <= 191 && code === "1C") {
|
|
5634
|
+
sysL = "J";
|
|
5635
|
+
code = "1Z";
|
|
5636
|
+
prnNum -= 182;
|
|
5637
|
+
} else if (sysL === "S") {
|
|
5638
|
+
prnNum -= 100;
|
|
5639
|
+
}
|
|
5640
|
+
if (prnNum < 1 || prnNum > 99) continue;
|
|
5641
|
+
if (sysL === "R" && !parity) continue;
|
|
5642
|
+
const prn = `${sysL}${String(prnNum).padStart(2, "0")}`;
|
|
5643
|
+
const gfrq = view.getUint16(o + 2, true);
|
|
5644
|
+
const psr = view.getFloat64(o + 4, true);
|
|
5645
|
+
const adr = view.getFloat64(o + 16, true);
|
|
5646
|
+
const dop = view.getFloat32(o + 28, true);
|
|
5647
|
+
const snr = view.getFloat32(o + 32, true);
|
|
5648
|
+
const lockt = view.getFloat32(o + 36, true);
|
|
5649
|
+
meas.push({
|
|
5650
|
+
prn,
|
|
5651
|
+
code,
|
|
5652
|
+
pr: clock ? psr : null,
|
|
5653
|
+
cp: plock ? -adr : null,
|
|
5654
|
+
doppler: plock ? dop : null,
|
|
5655
|
+
cn0: snr,
|
|
5656
|
+
lockTimeS: lockt,
|
|
5657
|
+
gloChannel: sysL === "R" ? gfrq - 8 : null
|
|
5658
|
+
});
|
|
5659
|
+
const codes = obsCodes[sysL] ??= [];
|
|
5660
|
+
if (!codes.includes(code)) codes.push(code);
|
|
5661
|
+
}
|
|
5662
|
+
epochs.push({
|
|
5663
|
+
timeMs: GPS_EPOCH_MS3 + week * MS_PER_WEEK4 + towMs,
|
|
5664
|
+
meas
|
|
5665
|
+
});
|
|
5666
|
+
}
|
|
5667
|
+
}
|
|
5668
|
+
i += total;
|
|
5669
|
+
}
|
|
5670
|
+
return { epochs, messageCounts, obsCodes, badCrc };
|
|
5671
|
+
}
|
|
5672
|
+
|
|
4594
5673
|
// src/orbit/index.ts
|
|
4595
5674
|
var GM_GPS = 3986005e8;
|
|
4596
5675
|
var GM_GAL = 3986004418e5;
|
|
@@ -4940,10 +6019,10 @@ function selectBest(ephs, timeMs) {
|
|
|
4940
6019
|
}
|
|
4941
6020
|
return best;
|
|
4942
6021
|
}
|
|
4943
|
-
var
|
|
4944
|
-
var
|
|
6022
|
+
var GPS_EPOCH_MS4 = START_GPS_TIME.getTime();
|
|
6023
|
+
var MS_PER_WEEK5 = 7 * 864e5;
|
|
4945
6024
|
var BDS_EPOCH_MS = START_BDS_TIME.getTime();
|
|
4946
|
-
var GAL_EPOCH_MS =
|
|
6025
|
+
var GAL_EPOCH_MS = GPS_EPOCH_MS4 + 1024 * MS_PER_WEEK5;
|
|
4947
6026
|
function ephInfoToEphemeris(info) {
|
|
4948
6027
|
const sys = info.prn.charAt(0);
|
|
4949
6028
|
if (sys === "R") {
|
|
@@ -4994,11 +6073,11 @@ function ephInfoToEphemeris(info) {
|
|
|
4994
6073
|
} else if (sys === "E") {
|
|
4995
6074
|
epochMs = GAL_EPOCH_MS;
|
|
4996
6075
|
} else {
|
|
4997
|
-
epochMs =
|
|
4998
|
-
const weeksNow = (info.lastReceived -
|
|
6076
|
+
epochMs = GPS_EPOCH_MS4;
|
|
6077
|
+
const weeksNow = (info.lastReceived - GPS_EPOCH_MS4) / MS_PER_WEEK5;
|
|
4999
6078
|
week += 1024 * Math.round((weeksNow - week) / 1024);
|
|
5000
6079
|
}
|
|
5001
|
-
const tocDate = new Date(epochMs + week *
|
|
6080
|
+
const tocDate = new Date(epochMs + week * MS_PER_WEEK5 + tocSec * 1e3);
|
|
5002
6081
|
return {
|
|
5003
6082
|
system: sys,
|
|
5004
6083
|
prn: info.prn,
|
|
@@ -8090,10 +9169,13 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
8090
9169
|
parseIonex,
|
|
8091
9170
|
parseNavFile,
|
|
8092
9171
|
parseNmeaFile,
|
|
9172
|
+
parseNovatelRange,
|
|
8093
9173
|
parseRinexStream,
|
|
9174
|
+
parseSbfMeas,
|
|
8094
9175
|
parseSinexBiasDcb,
|
|
8095
9176
|
parseSourcetable,
|
|
8096
9177
|
parseSp3,
|
|
9178
|
+
parseUbxRawx,
|
|
8097
9179
|
phiAltBOC,
|
|
8098
9180
|
phiBOCc,
|
|
8099
9181
|
phiBOCs,
|