gnss-js 1.0.0 → 1.1.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/README.md +26 -0
- package/dist/analysis.cjs +143 -36
- package/dist/analysis.js +3 -3
- package/dist/{chunk-HKN3PUGN.js → chunk-5SPJH4MG.js} +35 -26
- package/dist/{chunk-WR7LCB52.js → chunk-BJHTBYNG.js} +15 -4
- package/dist/{chunk-Y3R57B5P.js → chunk-G3N4S3DM.js} +37 -8
- package/dist/{chunk-PRSZIWKM.js → chunk-JDO3LEPC.js} +100 -132
- package/dist/{chunk-K7WZQFBV.js → chunk-MIIM4LDY.js} +4 -1
- package/dist/{chunk-CB6EOOLA.js → chunk-OZCYOM5D.js} +70 -21
- package/dist/{chunk-SDRRAJT5.js → chunk-PGHDJFQK.js} +31 -14
- package/dist/{chunk-IS4UUDBV.js → chunk-W4YMQKWH.js} +54 -9
- package/dist/{chunk-354IRDOG.js → chunk-W5WKEV7U.js} +39 -9
- package/dist/constants.cjs +39 -9
- package/dist/constants.js +26 -26
- package/dist/coordinates.cjs +4 -1
- package/dist/coordinates.js +1 -1
- package/dist/{ephemeris-BUWzfmBy.d.cts → ephemeris-Ohl6NAfw.d.cts} +12 -2
- package/dist/{ephemeris-BUWzfmBy.d.ts → ephemeris-Ohl6NAfw.d.ts} +12 -2
- package/dist/index.cjs +366 -220
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +40 -34
- package/dist/ntrip.cjs +15 -4
- package/dist/ntrip.js +1 -1
- package/dist/orbit.cjs +31 -14
- package/dist/orbit.d.cts +1 -1
- package/dist/orbit.d.ts +1 -1
- package/dist/orbit.js +2 -1
- package/dist/rinex.cjs +123 -29
- package/dist/rinex.js +3 -3
- package/dist/rtcm3.cjs +123 -131
- package/dist/rtcm3.d.cts +9 -3
- package/dist/rtcm3.d.ts +9 -3
- package/dist/rtcm3.js +9 -2
- package/dist/signals.cjs +55 -26
- package/dist/signals.d.cts +26 -26
- package/dist/signals.d.ts +26 -26
- package/dist/signals.js +2 -1
- package/package.json +1 -2
package/dist/index.cjs
CHANGED
|
@@ -206,10 +206,13 @@ __export(src_exports, {
|
|
|
206
206
|
phiBPSK: () => phiBPSK,
|
|
207
207
|
rad2deg: () => rad2deg,
|
|
208
208
|
readString: () => readString,
|
|
209
|
+
reportDecodeError: () => reportDecodeError,
|
|
209
210
|
resetGloFreqCache: () => resetGloFreqCache,
|
|
210
211
|
rhumbLine: () => rhumbLine,
|
|
211
212
|
rtcm3Constellation: () => rtcm3Constellation,
|
|
212
213
|
selectEphemeris: () => selectEphemeris,
|
|
214
|
+
setGloFreqNumber: () => setGloFreqNumber,
|
|
215
|
+
setRtcm3DebugHandler: () => setRtcm3DebugHandler,
|
|
213
216
|
systemCmp: () => systemCmp,
|
|
214
217
|
systemName: () => systemName,
|
|
215
218
|
updateStationMeta: () => updateStationMeta,
|
|
@@ -298,9 +301,22 @@ var SYS_SHORT = {
|
|
|
298
301
|
var C_LIGHT = 299792458;
|
|
299
302
|
var FREQ = {
|
|
300
303
|
G: { "1": 157542e4, "2": 12276e5, "5": 117645e4 },
|
|
301
|
-
R
|
|
302
|
-
|
|
303
|
-
|
|
304
|
+
// R bands 4/6 are the CDMA L1OC/L2OC center frequencies
|
|
305
|
+
R: { "3": 1202025e3, "4": 1600995e3, "6": 124806e4 },
|
|
306
|
+
E: {
|
|
307
|
+
"1": 157542e4,
|
|
308
|
+
"5": 117645e4,
|
|
309
|
+
"6": 127875e4,
|
|
310
|
+
"7": 120714e4,
|
|
311
|
+
"8": 1191795e3
|
|
312
|
+
},
|
|
313
|
+
C: {
|
|
314
|
+
"1": 157542e4,
|
|
315
|
+
"2": 1561098e3,
|
|
316
|
+
"5": 117645e4,
|
|
317
|
+
"6": 126852e4,
|
|
318
|
+
"7": 120714e4
|
|
319
|
+
},
|
|
304
320
|
J: { "1": 157542e4, "2": 12276e5, "5": 117645e4, "6": 127875e4 },
|
|
305
321
|
I: { "5": 117645e4, "9": 2492028e3 },
|
|
306
322
|
S: { "1": 157542e4, "5": 117645e4 }
|
|
@@ -315,11 +331,28 @@ var BAND_LABELS = {
|
|
|
315
331
|
S: { "1": "L1", "5": "L5" }
|
|
316
332
|
};
|
|
317
333
|
var DUAL_FREQ_PAIRS = {
|
|
318
|
-
G: [
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
334
|
+
G: [
|
|
335
|
+
["1", "2"],
|
|
336
|
+
["1", "5"]
|
|
337
|
+
],
|
|
338
|
+
R: [
|
|
339
|
+
["1", "2"],
|
|
340
|
+
["1", "3"]
|
|
341
|
+
],
|
|
342
|
+
E: [
|
|
343
|
+
["1", "5"],
|
|
344
|
+
["1", "7"],
|
|
345
|
+
["1", "6"]
|
|
346
|
+
],
|
|
347
|
+
C: [
|
|
348
|
+
["2", "7"],
|
|
349
|
+
["2", "6"],
|
|
350
|
+
["1", "5"]
|
|
351
|
+
],
|
|
352
|
+
J: [
|
|
353
|
+
["1", "2"],
|
|
354
|
+
["1", "5"]
|
|
355
|
+
],
|
|
323
356
|
I: [["5", "9"]],
|
|
324
357
|
S: [["1", "5"]]
|
|
325
358
|
};
|
|
@@ -363,11 +396,11 @@ function buildGloChannelMap(slots) {
|
|
|
363
396
|
return map;
|
|
364
397
|
}
|
|
365
398
|
function gloFreq(gloChannels, prn, band) {
|
|
399
|
+
if (band === "3" || band === "4" || band === "6") return FREQ.R[band];
|
|
366
400
|
const k = gloChannels[prn];
|
|
367
401
|
if (k === void 0) return void 0;
|
|
368
402
|
if (band === "1") return GLO_F1_BASE + k * GLO_F1_STEP;
|
|
369
403
|
if (band === "2") return GLO_F2_BASE + k * GLO_F2_STEP;
|
|
370
|
-
if (band === "3") return GLO_F3;
|
|
371
404
|
return void 0;
|
|
372
405
|
}
|
|
373
406
|
function getFreq(gloChannels, prn, band) {
|
|
@@ -964,7 +997,10 @@ function vincenty(lat1, lon1, lat2, lon2) {
|
|
|
964
997
|
const cosLat2 = Math.cos(lat2), sinLat2 = Math.sin(lat2);
|
|
965
998
|
const dLon = lon2 - lon1;
|
|
966
999
|
sigma = Math.acos(
|
|
967
|
-
Math.min(
|
|
1000
|
+
Math.min(
|
|
1001
|
+
1,
|
|
1002
|
+
Math.max(-1, sinLat1 * sinLat2 + cosLat1 * cosLat2 * Math.cos(dLon))
|
|
1003
|
+
)
|
|
968
1004
|
);
|
|
969
1005
|
const distance2 = WGS84_SEMI_MAJOR_AXIS * sigma;
|
|
970
1006
|
const ib = Math.atan2(
|
|
@@ -1162,10 +1198,20 @@ function parseCrxDataLine(line, ntype) {
|
|
|
1162
1198
|
if (token.length >= 3 && token[1] === "&") {
|
|
1163
1199
|
const arcOrder = parseInt(token[0]);
|
|
1164
1200
|
const value = parseInt(token.substring(2));
|
|
1165
|
-
fields.push({
|
|
1201
|
+
fields.push({
|
|
1202
|
+
empty: false,
|
|
1203
|
+
init: true,
|
|
1204
|
+
arcOrder,
|
|
1205
|
+
value: isNaN(value) ? 0 : value
|
|
1206
|
+
});
|
|
1166
1207
|
} else {
|
|
1167
1208
|
const value = parseInt(token);
|
|
1168
|
-
fields.push({
|
|
1209
|
+
fields.push({
|
|
1210
|
+
empty: false,
|
|
1211
|
+
init: false,
|
|
1212
|
+
arcOrder: -1,
|
|
1213
|
+
value: isNaN(value) ? 0 : value
|
|
1214
|
+
});
|
|
1169
1215
|
}
|
|
1170
1216
|
}
|
|
1171
1217
|
const flagStr = pos < line.length ? line.substring(pos) : "";
|
|
@@ -1175,7 +1221,10 @@ function crxDecompress(prev, field) {
|
|
|
1175
1221
|
if (field.init) {
|
|
1176
1222
|
const a = new Array(Math.max(field.arcOrder + 1, 1)).fill(0);
|
|
1177
1223
|
a[0] = field.value;
|
|
1178
|
-
return {
|
|
1224
|
+
return {
|
|
1225
|
+
state: { accum: a, order: 0, arcOrder: field.arcOrder },
|
|
1226
|
+
result: field.value
|
|
1227
|
+
};
|
|
1179
1228
|
}
|
|
1180
1229
|
if (!prev) {
|
|
1181
1230
|
return { state: { accum: [0], order: 0, arcOrder: 0 }, result: 0 };
|
|
@@ -1188,7 +1237,10 @@ function crxDecompress(prev, field) {
|
|
|
1188
1237
|
for (let k = order; k >= 1; k--) {
|
|
1189
1238
|
accum[k - 1] += accum[k];
|
|
1190
1239
|
}
|
|
1191
|
-
return {
|
|
1240
|
+
return {
|
|
1241
|
+
state: { accum, order, arcOrder: prev.arcOrder },
|
|
1242
|
+
result: accum[0]
|
|
1243
|
+
};
|
|
1192
1244
|
}
|
|
1193
1245
|
|
|
1194
1246
|
// src/rinex/format.ts
|
|
@@ -1210,7 +1262,9 @@ var CHUNK_SIZE = 2 * 1024 * 1024;
|
|
|
1210
1262
|
var yieldToMain = () => new Promise((r) => setTimeout(r, 0));
|
|
1211
1263
|
var noYield = () => Promise.resolve();
|
|
1212
1264
|
var SYSTEM_ORDER = ["G", "R", "E", "C", "J", "I", "S"];
|
|
1213
|
-
var SYSTEM_RANK = Object.fromEntries(
|
|
1265
|
+
var SYSTEM_RANK = Object.fromEntries(
|
|
1266
|
+
SYSTEM_ORDER.map((s, i) => [s, i])
|
|
1267
|
+
);
|
|
1214
1268
|
function systemCmp(a, b) {
|
|
1215
1269
|
const ra = SYSTEM_RANK[a.charAt(0)] ?? 99;
|
|
1216
1270
|
const rb = SYSTEM_RANK[b.charAt(0)] ?? 99;
|
|
@@ -1396,7 +1450,11 @@ function parseEpochLine3(line) {
|
|
|
1396
1450
|
const wholeSec = Math.floor(sc);
|
|
1397
1451
|
const ms = Math.round((sc - wholeSec) * 1e3);
|
|
1398
1452
|
const time = Date.UTC(yr, mo - 1, dy, hr, mn, wholeSec, ms);
|
|
1399
|
-
return {
|
|
1453
|
+
return {
|
|
1454
|
+
time,
|
|
1455
|
+
flag: isNaN(flag) ? 0 : flag,
|
|
1456
|
+
numSats: isNaN(numSats) ? 0 : numSats
|
|
1457
|
+
};
|
|
1400
1458
|
}
|
|
1401
1459
|
function parseEpochLine2(line) {
|
|
1402
1460
|
const yr2 = parseInt(line.substring(1, 3));
|
|
@@ -1418,7 +1476,12 @@ function parseEpochLine2(line) {
|
|
|
1418
1476
|
const id = satPart.substring(i, i + 3).trim();
|
|
1419
1477
|
if (id) satIds.push(id);
|
|
1420
1478
|
}
|
|
1421
|
-
return {
|
|
1479
|
+
return {
|
|
1480
|
+
time,
|
|
1481
|
+
flag: isNaN(flag) ? 0 : flag,
|
|
1482
|
+
numSats: isNaN(numSats) ? 0 : numSats,
|
|
1483
|
+
satIds
|
|
1484
|
+
};
|
|
1422
1485
|
}
|
|
1423
1486
|
async function parseRinexStream(file, onProgress, signal, onSatObs, workerMode) {
|
|
1424
1487
|
const skipEpochs = !!workerMode;
|
|
@@ -1471,16 +1534,19 @@ async function parseRinexStream(file, onProgress, signal, onSatObs, workerMode)
|
|
|
1471
1534
|
if (!skipEpochs) {
|
|
1472
1535
|
const snrBySys = {};
|
|
1473
1536
|
for (const [sys, vals] of Object.entries(snrPerSystemAccum)) {
|
|
1474
|
-
if (vals.length > 0)
|
|
1537
|
+
if (vals.length > 0)
|
|
1538
|
+
snrBySys[sys] = vals.reduce((a, b) => a + b, 0) / vals.length;
|
|
1475
1539
|
}
|
|
1476
1540
|
const meanSnr = snrValues.length > 0 ? snrValues.reduce((a, b) => a + b, 0) / snrValues.length : null;
|
|
1477
1541
|
const snrPerSat = {};
|
|
1478
1542
|
for (const [prn, vals] of Object.entries(snrPerSatAccum)) {
|
|
1479
|
-
if (vals.length > 0)
|
|
1543
|
+
if (vals.length > 0)
|
|
1544
|
+
snrPerSat[prn] = vals.reduce((a, b) => a + b, 0) / vals.length;
|
|
1480
1545
|
}
|
|
1481
1546
|
const snrPerSatBand = {};
|
|
1482
1547
|
for (const [key, vals] of Object.entries(snrPerSatBandAccum)) {
|
|
1483
|
-
if (vals.length > 0)
|
|
1548
|
+
if (vals.length > 0)
|
|
1549
|
+
snrPerSatBand[key] = vals.reduce((a, b) => a + b, 0) / vals.length;
|
|
1484
1550
|
}
|
|
1485
1551
|
epochs.push({
|
|
1486
1552
|
time: epochInfo.time,
|
|
@@ -1525,7 +1591,8 @@ async function parseRinexStream(file, onProgress, signal, onSatObs, workerMode)
|
|
|
1525
1591
|
const codes = header.obsTypes[sys] ?? [];
|
|
1526
1592
|
if (onSatObs && epochInfo) {
|
|
1527
1593
|
const values = new Array(codes.length);
|
|
1528
|
-
for (let i = 0; i < codes.length; i++)
|
|
1594
|
+
for (let i = 0; i < codes.length; i++)
|
|
1595
|
+
values[i] = readObsValue(obsLine, i);
|
|
1529
1596
|
if (!skipEpochs) {
|
|
1530
1597
|
for (const { idx, band } of getSnrIndices(sys)) {
|
|
1531
1598
|
const val = values[idx] ?? null;
|
|
@@ -1762,7 +1829,10 @@ async function parseRinexStream(file, onProgress, signal, onSatObs, workerMode)
|
|
|
1762
1829
|
v2SnrBandInfo = snrIndicesWithBandV2(header.obsTypes);
|
|
1763
1830
|
v2SatIndex = 0;
|
|
1764
1831
|
v2CurrentSatLine = 0;
|
|
1765
|
-
const continuationLines = Math.max(
|
|
1832
|
+
const continuationLines = Math.max(
|
|
1833
|
+
0,
|
|
1834
|
+
Math.ceil((info.numSats - 12) / 12)
|
|
1835
|
+
);
|
|
1766
1836
|
if (continuationLines > 0) {
|
|
1767
1837
|
v2ContinuationSatsRemaining = continuationLines;
|
|
1768
1838
|
} else {
|
|
@@ -1802,7 +1872,9 @@ async function parseRinexStream(file, onProgress, signal, onSatObs, workerMode)
|
|
|
1802
1872
|
const magic = new Uint8Array(await file.slice(0, 2).arrayBuffer());
|
|
1803
1873
|
const isGz = magic[0] === 31 && magic[1] === 139;
|
|
1804
1874
|
if (magic[0] === 31 && magic[1] === 157) {
|
|
1805
|
-
throw new Error(
|
|
1875
|
+
throw new Error(
|
|
1876
|
+
"Unix compress (.Z) files are not supported. Please decompress first (e.g. uncompress or gzip -d)."
|
|
1877
|
+
);
|
|
1806
1878
|
}
|
|
1807
1879
|
if (isGz) {
|
|
1808
1880
|
let bytesRead = 0;
|
|
@@ -1818,7 +1890,9 @@ async function parseRinexStream(file, onProgress, signal, onSatObs, workerMode)
|
|
|
1818
1890
|
if (done) break;
|
|
1819
1891
|
bytesRead += value.byteLength;
|
|
1820
1892
|
processChunkText(decoder.decode(value, { stream: true }), false);
|
|
1821
|
-
onProgress?.(
|
|
1893
|
+
onProgress?.(
|
|
1894
|
+
Math.min(99, Math.round(bytesRead / (file.size * 4) * 100))
|
|
1895
|
+
);
|
|
1822
1896
|
await yield_();
|
|
1823
1897
|
}
|
|
1824
1898
|
processChunkText(decoder.decode(), true);
|
|
@@ -1828,7 +1902,10 @@ async function parseRinexStream(file, onProgress, signal, onSatObs, workerMode)
|
|
|
1828
1902
|
const end = Math.min(offset + CHUNK_SIZE, file.size);
|
|
1829
1903
|
const slice = file.slice(offset, end);
|
|
1830
1904
|
const arrayBuf = await slice.arrayBuffer();
|
|
1831
|
-
processChunkText(
|
|
1905
|
+
processChunkText(
|
|
1906
|
+
decoder.decode(arrayBuf, { stream: end < file.size }),
|
|
1907
|
+
false
|
|
1908
|
+
);
|
|
1832
1909
|
onProgress?.(Math.min(99, Math.round(end / file.size * 100)));
|
|
1833
1910
|
await yield_();
|
|
1834
1911
|
}
|
|
@@ -1836,19 +1913,27 @@ async function parseRinexStream(file, onProgress, signal, onSatObs, workerMode)
|
|
|
1836
1913
|
processChunkText("", true);
|
|
1837
1914
|
}
|
|
1838
1915
|
}
|
|
1839
|
-
if (epochInfo && satLinesRemaining === 0 && crxPhase === "epoch")
|
|
1840
|
-
|
|
1916
|
+
if (epochInfo && satLinesRemaining === 0 && crxPhase === "epoch")
|
|
1917
|
+
finishEpoch();
|
|
1918
|
+
if (!header)
|
|
1919
|
+
throw new Error("No valid RINEX header found (missing END OF HEADER).");
|
|
1841
1920
|
onProgress?.(100);
|
|
1842
|
-
return {
|
|
1921
|
+
return {
|
|
1922
|
+
header,
|
|
1923
|
+
epochs,
|
|
1924
|
+
stats: computeStats(header, epochs, satellitesSeen)
|
|
1925
|
+
};
|
|
1843
1926
|
}
|
|
1844
1927
|
function computeStats(header, epochs, satellitesSeen) {
|
|
1845
1928
|
const n = epochs.length;
|
|
1846
1929
|
const startTime = n > 0 ? new Date(epochs[0].time) : header.timeOfFirstObs;
|
|
1847
1930
|
const endTime = n > 0 ? new Date(epochs[n - 1].time) : header.timeOfLastObs;
|
|
1848
1931
|
let duration = null;
|
|
1849
|
-
if (startTime && endTime)
|
|
1932
|
+
if (startTime && endTime)
|
|
1933
|
+
duration = (endTime.getTime() - startTime.getTime()) / 1e3;
|
|
1850
1934
|
let interval = header.interval;
|
|
1851
|
-
if (interval === null && n >= 2)
|
|
1935
|
+
if (interval === null && n >= 2)
|
|
1936
|
+
interval = (epochs[1].time - epochs[0].time) / 1e3;
|
|
1852
1937
|
const uniqueSatsPerSystem = {};
|
|
1853
1938
|
let totalUnique = 0;
|
|
1854
1939
|
const systems = [];
|
|
@@ -1903,10 +1988,18 @@ var WarningAccumulator = class {
|
|
|
1903
1988
|
);
|
|
1904
1989
|
}
|
|
1905
1990
|
if (!header.antType) {
|
|
1906
|
-
this.add(
|
|
1991
|
+
this.add(
|
|
1992
|
+
"MISSING_ANT_TYPE",
|
|
1993
|
+
"info",
|
|
1994
|
+
"Missing antenna type (ANT # / TYPE)"
|
|
1995
|
+
);
|
|
1907
1996
|
}
|
|
1908
1997
|
if (!header.receiverType) {
|
|
1909
|
-
this.add(
|
|
1998
|
+
this.add(
|
|
1999
|
+
"MISSING_REC_TYPE",
|
|
2000
|
+
"info",
|
|
2001
|
+
"Missing receiver type (REC # / TYPE / VERS)"
|
|
2002
|
+
);
|
|
1910
2003
|
}
|
|
1911
2004
|
if (!header.markerName) {
|
|
1912
2005
|
this.add("MISSING_MARKER", "info", "Missing marker name (MARKER NAME)");
|
|
@@ -1915,7 +2008,11 @@ var WarningAccumulator = class {
|
|
|
1915
2008
|
this.add("MISSING_INTERVAL", "info", "No observation interval in header");
|
|
1916
2009
|
}
|
|
1917
2010
|
if (Object.keys(header.obsTypes).length === 0) {
|
|
1918
|
-
this.add(
|
|
2011
|
+
this.add(
|
|
2012
|
+
"NO_OBS_TYPES",
|
|
2013
|
+
"error",
|
|
2014
|
+
"No observation types defined in header"
|
|
2015
|
+
);
|
|
1919
2016
|
}
|
|
1920
2017
|
}
|
|
1921
2018
|
setInterval(intervalMs) {
|
|
@@ -1982,7 +2079,12 @@ var WarningAccumulator = class {
|
|
|
1982
2079
|
};
|
|
1983
2080
|
const range = ranges[sys];
|
|
1984
2081
|
if (!range) {
|
|
1985
|
-
this.add(
|
|
2082
|
+
this.add(
|
|
2083
|
+
"UNKNOWN_SYSTEM",
|
|
2084
|
+
"info",
|
|
2085
|
+
"Unknown satellite system letter",
|
|
2086
|
+
prn
|
|
2087
|
+
);
|
|
1986
2088
|
} else if (num < range[0] || num > range[1]) {
|
|
1987
2089
|
this.add(
|
|
1988
2090
|
"PRN_OUT_OF_RANGE",
|
|
@@ -2072,7 +2174,15 @@ var R4_MSG_LINES = {
|
|
|
2072
2174
|
EOP: 3,
|
|
2073
2175
|
ION: 3
|
|
2074
2176
|
};
|
|
2075
|
-
var SUPPORTED_EPH_MSGS = /* @__PURE__ */ new Set([
|
|
2177
|
+
var SUPPORTED_EPH_MSGS = /* @__PURE__ */ new Set([
|
|
2178
|
+
"LNAV",
|
|
2179
|
+
"INAV",
|
|
2180
|
+
"FNAV",
|
|
2181
|
+
"D1",
|
|
2182
|
+
"D2",
|
|
2183
|
+
"SBAS",
|
|
2184
|
+
"FDMA"
|
|
2185
|
+
]);
|
|
2076
2186
|
function parseFloat19(s) {
|
|
2077
2187
|
return parseFloat(s.trim().replace(/[dD]/g, "E"));
|
|
2078
2188
|
}
|
|
@@ -2279,9 +2389,25 @@ function parseNavFile(text) {
|
|
|
2279
2389
|
}
|
|
2280
2390
|
if (dataLines2.length === numDataLines2) {
|
|
2281
2391
|
if (sys2 === "R" || sys2 === "S") {
|
|
2282
|
-
ephemerides.push(
|
|
2392
|
+
ephemerides.push(
|
|
2393
|
+
buildStateVectorEphemeris(
|
|
2394
|
+
sys2,
|
|
2395
|
+
prn2,
|
|
2396
|
+
parsed.date,
|
|
2397
|
+
parsed.values,
|
|
2398
|
+
dataLines2
|
|
2399
|
+
)
|
|
2400
|
+
);
|
|
2283
2401
|
} else if (sys2 === "G" || sys2 === "E" || sys2 === "C" || sys2 === "J" || sys2 === "I") {
|
|
2284
|
-
ephemerides.push(
|
|
2402
|
+
ephemerides.push(
|
|
2403
|
+
buildKeplerEphemeris(
|
|
2404
|
+
sys2,
|
|
2405
|
+
prn2,
|
|
2406
|
+
parsed.date,
|
|
2407
|
+
parsed.values,
|
|
2408
|
+
dataLines2
|
|
2409
|
+
)
|
|
2410
|
+
);
|
|
2285
2411
|
}
|
|
2286
2412
|
}
|
|
2287
2413
|
i++;
|
|
@@ -2317,9 +2443,13 @@ function parseNavFile(text) {
|
|
|
2317
2443
|
}
|
|
2318
2444
|
if (dataLines.length === numDataLines) {
|
|
2319
2445
|
if (sys === "R" || sys === "S") {
|
|
2320
|
-
ephemerides.push(
|
|
2446
|
+
ephemerides.push(
|
|
2447
|
+
buildStateVectorEphemeris(sys, prn, date, epochVals, dataLines)
|
|
2448
|
+
);
|
|
2321
2449
|
} else if (sys === "G" || sys === "E" || sys === "C" || sys === "J" || sys === "I") {
|
|
2322
|
-
ephemerides.push(
|
|
2450
|
+
ephemerides.push(
|
|
2451
|
+
buildKeplerEphemeris(sys, prn, date, epochVals, dataLines)
|
|
2452
|
+
);
|
|
2323
2453
|
}
|
|
2324
2454
|
}
|
|
2325
2455
|
i++;
|
|
@@ -2430,27 +2560,31 @@ function writeRinexNav(nav) {
|
|
|
2430
2560
|
}
|
|
2431
2561
|
|
|
2432
2562
|
// src/rtcm3/decoder.ts
|
|
2563
|
+
var debugHandler = null;
|
|
2564
|
+
function setRtcm3DebugHandler(fn) {
|
|
2565
|
+
debugHandler = fn;
|
|
2566
|
+
}
|
|
2567
|
+
function reportDecodeError(context, error) {
|
|
2568
|
+
if (debugHandler) debugHandler(context, error);
|
|
2569
|
+
}
|
|
2433
2570
|
var BitReader = class {
|
|
2434
2571
|
data;
|
|
2435
2572
|
bitPos = 0;
|
|
2436
2573
|
constructor(data) {
|
|
2437
2574
|
this.data = data;
|
|
2438
2575
|
}
|
|
2439
|
-
/** Read `n` bits as unsigned integer (max
|
|
2576
|
+
/** Read `n` bits as unsigned integer (max 53). */
|
|
2440
2577
|
readU(n) {
|
|
2441
2578
|
if (n === 0) return 0;
|
|
2442
2579
|
let val = 0;
|
|
2443
2580
|
for (let i = 0; i < n; i++) {
|
|
2444
2581
|
const byteIdx = this.bitPos + i >> 3;
|
|
2445
2582
|
const bitIdx = 7 - (this.bitPos + i & 7);
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
} else {
|
|
2449
|
-
val <<= 1;
|
|
2450
|
-
}
|
|
2583
|
+
const bit = byteIdx < this.data.length ? this.data[byteIdx] >> bitIdx & 1 : 0;
|
|
2584
|
+
val = val * 2 + bit;
|
|
2451
2585
|
}
|
|
2452
2586
|
this.bitPos += n;
|
|
2453
|
-
return val
|
|
2587
|
+
return val;
|
|
2454
2588
|
}
|
|
2455
2589
|
/** Read `n` bits as signed (two's complement) integer. */
|
|
2456
2590
|
readS(n) {
|
|
@@ -2461,9 +2595,9 @@ var BitReader = class {
|
|
|
2461
2595
|
/** Read `n` bits as sign-magnitude integer (MSB = sign, rest = magnitude). */
|
|
2462
2596
|
readSM(n) {
|
|
2463
2597
|
const val = this.readU(n);
|
|
2464
|
-
const
|
|
2465
|
-
const mag = val
|
|
2466
|
-
return
|
|
2598
|
+
const half = 2 ** (n - 1);
|
|
2599
|
+
const mag = val % half;
|
|
2600
|
+
return val >= half ? -mag : mag;
|
|
2467
2601
|
}
|
|
2468
2602
|
/** Skip `n` bits. */
|
|
2469
2603
|
skip(n) {
|
|
@@ -2967,31 +3101,32 @@ function decodeEphemeris(frame) {
|
|
|
2967
3101
|
default:
|
|
2968
3102
|
return null;
|
|
2969
3103
|
}
|
|
2970
|
-
} catch {
|
|
3104
|
+
} catch (err) {
|
|
3105
|
+
reportDecodeError("ephemeris", err);
|
|
2971
3106
|
return null;
|
|
2972
3107
|
}
|
|
2973
3108
|
}
|
|
2974
3109
|
|
|
2975
3110
|
// src/rtcm3/msm.ts
|
|
2976
|
-
var GPS_L1 =
|
|
2977
|
-
var GPS_L2 =
|
|
2978
|
-
var GPS_L5 =
|
|
2979
|
-
var GLO_L1a =
|
|
2980
|
-
var GLO_L2a =
|
|
2981
|
-
var GLO_L3 =
|
|
2982
|
-
var GAL_E1 =
|
|
2983
|
-
var GAL_E5a =
|
|
2984
|
-
var GAL_E5b =
|
|
2985
|
-
var GAL_E5 =
|
|
2986
|
-
var GAL_E6 =
|
|
2987
|
-
var BDS_B1 =
|
|
2988
|
-
var BDS_B3 =
|
|
2989
|
-
var BDS_B2 =
|
|
2990
|
-
var BDS_B1C =
|
|
2991
|
-
var BDS_B2a =
|
|
2992
|
-
var BDS_B2b =
|
|
2993
|
-
var QZSS_L6 =
|
|
2994
|
-
var NAVIC_S =
|
|
3111
|
+
var GPS_L1 = FREQ.G["1"];
|
|
3112
|
+
var GPS_L2 = FREQ.G["2"];
|
|
3113
|
+
var GPS_L5 = FREQ.G["5"];
|
|
3114
|
+
var GLO_L1a = FREQ.R["4"];
|
|
3115
|
+
var GLO_L2a = FREQ.R["6"];
|
|
3116
|
+
var GLO_L3 = FREQ.R["3"];
|
|
3117
|
+
var GAL_E1 = FREQ.E["1"];
|
|
3118
|
+
var GAL_E5a = FREQ.E["5"];
|
|
3119
|
+
var GAL_E5b = FREQ.E["7"];
|
|
3120
|
+
var GAL_E5 = FREQ.E["8"];
|
|
3121
|
+
var GAL_E6 = FREQ.E["6"];
|
|
3122
|
+
var BDS_B1 = FREQ.C["2"];
|
|
3123
|
+
var BDS_B3 = FREQ.C["6"];
|
|
3124
|
+
var BDS_B2 = FREQ.C["7"];
|
|
3125
|
+
var BDS_B1C = FREQ.C["1"];
|
|
3126
|
+
var BDS_B2a = FREQ.C["5"];
|
|
3127
|
+
var BDS_B2b = FREQ.C["7"];
|
|
3128
|
+
var QZSS_L6 = FREQ.J["6"];
|
|
3129
|
+
var NAVIC_S = FREQ.I["9"];
|
|
2995
3130
|
var EMPTY = { code: "", freq: 0 };
|
|
2996
3131
|
function sd(code, freq) {
|
|
2997
3132
|
return { code, freq };
|
|
@@ -3243,43 +3378,6 @@ function signalTable(sys) {
|
|
|
3243
3378
|
return GPS_SIGNALS;
|
|
3244
3379
|
}
|
|
3245
3380
|
}
|
|
3246
|
-
var BitReader2 = class {
|
|
3247
|
-
data;
|
|
3248
|
-
pos;
|
|
3249
|
-
constructor(data, startBit = 0) {
|
|
3250
|
-
this.data = data;
|
|
3251
|
-
this.pos = startBit;
|
|
3252
|
-
}
|
|
3253
|
-
/** Read unsigned value of numBits bits */
|
|
3254
|
-
u(numBits) {
|
|
3255
|
-
let val = 0;
|
|
3256
|
-
for (let i = 0; i < numBits; i++) {
|
|
3257
|
-
const byteIdx = this.pos + i >>> 3;
|
|
3258
|
-
const bitIdx = 7 - (this.pos + i & 7);
|
|
3259
|
-
if (byteIdx < this.data.length) {
|
|
3260
|
-
val = val << 1 | this.data[byteIdx] >>> bitIdx & 1;
|
|
3261
|
-
} else {
|
|
3262
|
-
val <<= 1;
|
|
3263
|
-
}
|
|
3264
|
-
}
|
|
3265
|
-
this.pos += numBits;
|
|
3266
|
-
return val;
|
|
3267
|
-
}
|
|
3268
|
-
/** Read signed value (two's complement) */
|
|
3269
|
-
s(numBits) {
|
|
3270
|
-
const raw = this.u(numBits);
|
|
3271
|
-
const sign = 1 << numBits - 1;
|
|
3272
|
-
return (raw & sign - 1) - (raw & sign);
|
|
3273
|
-
}
|
|
3274
|
-
/** Skip bits */
|
|
3275
|
-
skip(n) {
|
|
3276
|
-
this.pos += n;
|
|
3277
|
-
}
|
|
3278
|
-
/** Current bit position */
|
|
3279
|
-
get position() {
|
|
3280
|
-
return this.pos;
|
|
3281
|
-
}
|
|
3282
|
-
};
|
|
3283
3381
|
var gloFreqNum = new Int8Array(64).fill(-128);
|
|
3284
3382
|
function gloWavelength(satIdx, freqMarker) {
|
|
3285
3383
|
const k = gloFreqNum[satIdx];
|
|
@@ -3314,28 +3412,9 @@ function lockTimeSec(msmType, lti) {
|
|
|
3314
3412
|
if (variant <= 5) {
|
|
3315
3413
|
return LTI_TABLE_4BIT[lti] ?? 0;
|
|
3316
3414
|
}
|
|
3317
|
-
if (lti < 64) return lti;
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
if (lti < 160) return (lti - 128) * 8 + 256;
|
|
3321
|
-
if (lti < 192) return (lti - 160) * 16 + 512;
|
|
3322
|
-
if (lti < 224) return (lti - 192) * 32 + 1024;
|
|
3323
|
-
if (lti < 256) return (lti - 224) * 64 + 2048;
|
|
3324
|
-
if (lti < 288) return (lti - 256) * 128 + 4096;
|
|
3325
|
-
if (lti < 320) return (lti - 288) * 256 + 8192;
|
|
3326
|
-
if (lti < 352) return (lti - 320) * 512 + 16384;
|
|
3327
|
-
if (lti < 384) return (lti - 352) * 1024 + 32768;
|
|
3328
|
-
if (lti < 416) return (lti - 384) * 2048 + 65536;
|
|
3329
|
-
if (lti < 448) return (lti - 416) * 4096 + 131072;
|
|
3330
|
-
if (lti < 480) return (lti - 448) * 8192 + 262144;
|
|
3331
|
-
if (lti < 512) return (lti - 480) * 16384 + 524288;
|
|
3332
|
-
if (lti < 544) return (lti - 512) * 32768 + 1048576;
|
|
3333
|
-
if (lti < 576) return (lti - 544) * 65536 + 2097152;
|
|
3334
|
-
if (lti < 608) return (lti - 576) * 131072 + 4194304;
|
|
3335
|
-
if (lti < 640) return (lti - 608) * 262144 + 8388608;
|
|
3336
|
-
if (lti < 672) return (lti - 640) * 524288 + 16777216;
|
|
3337
|
-
if (lti < 704) return (lti - 672) * 1048576 + 33554432;
|
|
3338
|
-
return (lti - 704) * 2097152 + 67108864;
|
|
3415
|
+
if (lti < 64) return lti / 1e3;
|
|
3416
|
+
const n = Math.min(20, Math.floor((lti - 64) / 32));
|
|
3417
|
+
return ((lti - 64 - 32 * n) * 2 ** (n + 1) + 2 ** (n + 6)) / 1e3;
|
|
3339
3418
|
}
|
|
3340
3419
|
function msmSystem(type) {
|
|
3341
3420
|
if (type >= 1071 && type <= 1077) return "G";
|
|
@@ -3361,10 +3440,10 @@ function decodeMsmFull(frame) {
|
|
|
3361
3440
|
const payload = frame.payload;
|
|
3362
3441
|
if (!payload || payload.length < 10) return null;
|
|
3363
3442
|
try {
|
|
3364
|
-
const bits = new
|
|
3443
|
+
const bits = new BitReader(payload);
|
|
3365
3444
|
bits.skip(12);
|
|
3366
3445
|
bits.skip(12);
|
|
3367
|
-
const epochMs = bits.
|
|
3446
|
+
const epochMs = bits.readU(30);
|
|
3368
3447
|
bits.skip(1);
|
|
3369
3448
|
bits.skip(3);
|
|
3370
3449
|
bits.skip(7);
|
|
@@ -3372,8 +3451,8 @@ function decodeMsmFull(frame) {
|
|
|
3372
3451
|
bits.skip(2);
|
|
3373
3452
|
bits.skip(1);
|
|
3374
3453
|
bits.skip(3);
|
|
3375
|
-
const satMaskHi = bits.
|
|
3376
|
-
const satMaskLo = bits.
|
|
3454
|
+
const satMaskHi = bits.readU(32) >>> 0;
|
|
3455
|
+
const satMaskLo = bits.readU(32) >>> 0;
|
|
3377
3456
|
const satIndices = [];
|
|
3378
3457
|
for (let i = 0; i < 32; i++) {
|
|
3379
3458
|
if (satMaskHi & 1 << 31 - i) satIndices.push(i + 1);
|
|
@@ -3383,7 +3462,7 @@ function decodeMsmFull(frame) {
|
|
|
3383
3462
|
}
|
|
3384
3463
|
const numSat = satIndices.length;
|
|
3385
3464
|
if (numSat === 0) return null;
|
|
3386
|
-
const sigMask = bits.
|
|
3465
|
+
const sigMask = bits.readU(32) >>> 0;
|
|
3387
3466
|
const sigIndices = [];
|
|
3388
3467
|
for (let i = 0; i < 32; i++) {
|
|
3389
3468
|
if (sigMask & 1 << 31 - i) sigIndices.push(i);
|
|
@@ -3393,7 +3472,7 @@ function decodeMsmFull(frame) {
|
|
|
3393
3472
|
const numCells = numSat * numSig;
|
|
3394
3473
|
const cellMask = [];
|
|
3395
3474
|
for (let i = 0; i < numCells; i++) {
|
|
3396
|
-
cellMask.push(bits.
|
|
3475
|
+
cellMask.push(bits.readU(1) === 1);
|
|
3397
3476
|
}
|
|
3398
3477
|
let activeCells = 0;
|
|
3399
3478
|
for (const c of cellMask) if (c) activeCells++;
|
|
@@ -3403,14 +3482,13 @@ function decodeMsmFull(frame) {
|
|
|
3403
3482
|
const extsat = new Int8Array(numSat);
|
|
3404
3483
|
const rdop = new Float64Array(numSat);
|
|
3405
3484
|
if (variant === 4 || variant === 6) {
|
|
3406
|
-
for (let j = 0; j < numSat; j++) rrint[j] = bits.
|
|
3407
|
-
for (let j = 0; j < numSat; j++)
|
|
3408
|
-
for (let j = 0; j < numSat; j++) rrmod[j] = bits.u(10) / 1024;
|
|
3485
|
+
for (let j = 0; j < numSat; j++) rrint[j] = bits.readU(8);
|
|
3486
|
+
for (let j = 0; j < numSat; j++) rrmod[j] = bits.readU(10) / 1024;
|
|
3409
3487
|
} else {
|
|
3410
|
-
for (let j = 0; j < numSat; j++) rrint[j] = bits.
|
|
3411
|
-
for (let j = 0; j < numSat; j++) extsat[j] = bits.
|
|
3412
|
-
for (let j = 0; j < numSat; j++) rrmod[j] = bits.
|
|
3413
|
-
for (let j = 0; j < numSat; j++) rdop[j] = bits.
|
|
3488
|
+
for (let j = 0; j < numSat; j++) rrint[j] = bits.readU(8);
|
|
3489
|
+
for (let j = 0; j < numSat; j++) extsat[j] = bits.readU(4);
|
|
3490
|
+
for (let j = 0; j < numSat; j++) rrmod[j] = bits.readU(10) / 1024;
|
|
3491
|
+
for (let j = 0; j < numSat; j++) rdop[j] = bits.readS(14) * 1;
|
|
3414
3492
|
}
|
|
3415
3493
|
if (sys === "R") {
|
|
3416
3494
|
for (let j = 0; j < numSat; j++) {
|
|
@@ -3430,31 +3508,31 @@ function decodeMsmFull(frame) {
|
|
|
3430
3508
|
cp.fill(-1e30);
|
|
3431
3509
|
dop.fill(-1e30);
|
|
3432
3510
|
if (variant === 4) {
|
|
3433
|
-
for (let i = 0; i < activeCells; i++) psr[i] = bits.
|
|
3434
|
-
for (let i = 0; i < activeCells; i++) cp[i] = bits.
|
|
3435
|
-
for (let i = 0; i < activeCells; i++) ll[i] = bits.
|
|
3436
|
-
for (let i = 0; i < activeCells; i++) hc[i] = bits.
|
|
3437
|
-
for (let i = 0; i < activeCells; i++) cnr[i] = bits.
|
|
3511
|
+
for (let i = 0; i < activeCells; i++) psr[i] = bits.readS(15) / 2 ** 24;
|
|
3512
|
+
for (let i = 0; i < activeCells; i++) cp[i] = bits.readS(22) / 2 ** 29;
|
|
3513
|
+
for (let i = 0; i < activeCells; i++) ll[i] = bits.readU(4);
|
|
3514
|
+
for (let i = 0; i < activeCells; i++) hc[i] = bits.readU(1);
|
|
3515
|
+
for (let i = 0; i < activeCells; i++) cnr[i] = bits.readU(6);
|
|
3438
3516
|
} else if (variant === 5) {
|
|
3439
|
-
for (let i = 0; i < activeCells; i++) psr[i] = bits.
|
|
3440
|
-
for (let i = 0; i < activeCells; i++) cp[i] = bits.
|
|
3441
|
-
for (let i = 0; i < activeCells; i++) ll[i] = bits.
|
|
3442
|
-
for (let i = 0; i < activeCells; i++) hc[i] = bits.
|
|
3443
|
-
for (let i = 0; i < activeCells; i++) cnr[i] = bits.
|
|
3444
|
-
for (let i = 0; i < activeCells; i++) dop[i] = bits.
|
|
3517
|
+
for (let i = 0; i < activeCells; i++) psr[i] = bits.readS(15) / 2 ** 24;
|
|
3518
|
+
for (let i = 0; i < activeCells; i++) cp[i] = bits.readS(22) / 2 ** 29;
|
|
3519
|
+
for (let i = 0; i < activeCells; i++) ll[i] = bits.readU(4);
|
|
3520
|
+
for (let i = 0; i < activeCells; i++) hc[i] = bits.readU(1);
|
|
3521
|
+
for (let i = 0; i < activeCells; i++) cnr[i] = bits.readU(6);
|
|
3522
|
+
for (let i = 0; i < activeCells; i++) dop[i] = bits.readS(15) * 1e-4;
|
|
3445
3523
|
} else if (variant === 6) {
|
|
3446
|
-
for (let i = 0; i < activeCells; i++) psr[i] = bits.
|
|
3447
|
-
for (let i = 0; i < activeCells; i++) cp[i] = bits.
|
|
3448
|
-
for (let i = 0; i < activeCells; i++) ll[i] = bits.
|
|
3449
|
-
for (let i = 0; i < activeCells; i++) hc[i] = bits.
|
|
3450
|
-
for (let i = 0; i < activeCells; i++) cnr[i] = bits.
|
|
3524
|
+
for (let i = 0; i < activeCells; i++) psr[i] = bits.readS(20) / 2 ** 29;
|
|
3525
|
+
for (let i = 0; i < activeCells; i++) cp[i] = bits.readS(24) / 2 ** 31;
|
|
3526
|
+
for (let i = 0; i < activeCells; i++) ll[i] = bits.readU(10);
|
|
3527
|
+
for (let i = 0; i < activeCells; i++) hc[i] = bits.readU(1);
|
|
3528
|
+
for (let i = 0; i < activeCells; i++) cnr[i] = bits.readU(10) / 16;
|
|
3451
3529
|
} else {
|
|
3452
|
-
for (let i = 0; i < activeCells; i++) psr[i] = bits.
|
|
3453
|
-
for (let i = 0; i < activeCells; i++) cp[i] = bits.
|
|
3454
|
-
for (let i = 0; i < activeCells; i++) ll[i] = bits.
|
|
3455
|
-
for (let i = 0; i < activeCells; i++) hc[i] = bits.
|
|
3456
|
-
for (let i = 0; i < activeCells; i++) cnr[i] = bits.
|
|
3457
|
-
for (let i = 0; i < activeCells; i++) dop[i] = bits.
|
|
3530
|
+
for (let i = 0; i < activeCells; i++) psr[i] = bits.readS(20) / 2 ** 29;
|
|
3531
|
+
for (let i = 0; i < activeCells; i++) cp[i] = bits.readS(24) / 2 ** 31;
|
|
3532
|
+
for (let i = 0; i < activeCells; i++) ll[i] = bits.readU(10);
|
|
3533
|
+
for (let i = 0; i < activeCells; i++) hc[i] = bits.readU(1);
|
|
3534
|
+
for (let i = 0; i < activeCells; i++) cnr[i] = bits.readU(10) / 16;
|
|
3535
|
+
for (let i = 0; i < activeCells; i++) dop[i] = bits.readS(15) * 1e-4;
|
|
3458
3536
|
}
|
|
3459
3537
|
const sigTable = signalTable(sys);
|
|
3460
3538
|
const observations = [];
|
|
@@ -3488,11 +3566,11 @@ function decodeMsmFull(frame) {
|
|
|
3488
3566
|
wavelength
|
|
3489
3567
|
};
|
|
3490
3568
|
const psrVal = psr[cellIdx];
|
|
3491
|
-
if (psrVal > -
|
|
3569
|
+
if (psrVal > -(2 ** -10)) {
|
|
3492
3570
|
signal.pseudorange = psrVal * C_LIGHT / 1e3 + roughRange_m;
|
|
3493
3571
|
}
|
|
3494
3572
|
const cpVal = cp[cellIdx];
|
|
3495
|
-
if (cpVal > -
|
|
3573
|
+
if (cpVal > -(2 ** -8) && wavelength > 0) {
|
|
3496
3574
|
signal.phase = cpVal * C_LIGHT / 1e3 / wavelength + roughRange_m / wavelength;
|
|
3497
3575
|
}
|
|
3498
3576
|
if (variant === 5 || variant === 7) {
|
|
@@ -3520,12 +3598,13 @@ function decodeMsmFull(frame) {
|
|
|
3520
3598
|
system: sys,
|
|
3521
3599
|
observations
|
|
3522
3600
|
};
|
|
3523
|
-
} catch {
|
|
3601
|
+
} catch (err) {
|
|
3602
|
+
reportDecodeError("msm", err);
|
|
3524
3603
|
return null;
|
|
3525
3604
|
}
|
|
3526
3605
|
}
|
|
3527
|
-
var GPS_EPOCH =
|
|
3528
|
-
var MS_PER_WEEK =
|
|
3606
|
+
var GPS_EPOCH = START_GPS_TIME.getTime();
|
|
3607
|
+
var MS_PER_WEEK = MILLISECONDS_IN_WEEK;
|
|
3529
3608
|
function msmEpochToDate(sys, epochMs, refTime = /* @__PURE__ */ new Date()) {
|
|
3530
3609
|
const refMs = refTime.getTime();
|
|
3531
3610
|
if (sys === "R") {
|
|
@@ -3540,11 +3619,12 @@ function msmEpochToDate(sys, epochMs, refTime = /* @__PURE__ */ new Date()) {
|
|
|
3540
3619
|
return new Date(t2);
|
|
3541
3620
|
}
|
|
3542
3621
|
if (sys === "C") {
|
|
3543
|
-
const BDS_EPOCH =
|
|
3622
|
+
const BDS_EPOCH = START_BDS_TIME.getTime();
|
|
3544
3623
|
const weeksSinceEpoch2 = Math.floor((refMs - BDS_EPOCH) / MS_PER_WEEK);
|
|
3545
3624
|
let t2 = BDS_EPOCH + weeksSinceEpoch2 * MS_PER_WEEK + epochMs;
|
|
3546
3625
|
if (t2 - refMs > MS_PER_WEEK / 2) t2 -= MS_PER_WEEK;
|
|
3547
3626
|
else if (refMs - t2 > MS_PER_WEEK / 2) t2 += MS_PER_WEEK;
|
|
3627
|
+
t2 -= 18e3;
|
|
3548
3628
|
return new Date(t2);
|
|
3549
3629
|
}
|
|
3550
3630
|
const weeksSinceEpoch = Math.floor((refMs - GPS_EPOCH) / MS_PER_WEEK);
|
|
@@ -3554,6 +3634,11 @@ function msmEpochToDate(sys, epochMs, refTime = /* @__PURE__ */ new Date()) {
|
|
|
3554
3634
|
t -= 18e3;
|
|
3555
3635
|
return new Date(t);
|
|
3556
3636
|
}
|
|
3637
|
+
function setGloFreqNumber(slot, k) {
|
|
3638
|
+
if (slot >= 1 && slot <= 64 && k >= -7 && k <= 13) {
|
|
3639
|
+
gloFreqNum[slot - 1] = k;
|
|
3640
|
+
}
|
|
3641
|
+
}
|
|
3557
3642
|
function resetGloFreqCache() {
|
|
3558
3643
|
gloFreqNum.fill(-128);
|
|
3559
3644
|
}
|
|
@@ -3687,7 +3772,8 @@ function updateStationMeta(meta, frame) {
|
|
|
3687
3772
|
default:
|
|
3688
3773
|
return false;
|
|
3689
3774
|
}
|
|
3690
|
-
} catch {
|
|
3775
|
+
} catch (err) {
|
|
3776
|
+
reportDecodeError("station", err);
|
|
3691
3777
|
return false;
|
|
3692
3778
|
}
|
|
3693
3779
|
}
|
|
@@ -3875,6 +3961,9 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
3875
3961
|
const eph = decodeEphemeris(frame);
|
|
3876
3962
|
if (eph) {
|
|
3877
3963
|
stats.ephemerides.set(eph.prn, eph);
|
|
3964
|
+
if (eph.freqChannel !== void 0 && eph.prn.startsWith("R")) {
|
|
3965
|
+
setGloFreqNumber(parseInt(eph.prn.slice(1), 10), eph.freqChannel);
|
|
3966
|
+
}
|
|
3878
3967
|
}
|
|
3879
3968
|
updateStationMeta(stats.stationMeta, frame);
|
|
3880
3969
|
}
|
|
@@ -3894,6 +3983,8 @@ var GM_GAL = 3986004418e5;
|
|
|
3894
3983
|
var GM_BDS = 3986004418e5;
|
|
3895
3984
|
var GM_GLO = 39860044e7;
|
|
3896
3985
|
var OMEGA_E = 72921151467e-15;
|
|
3986
|
+
var BDS_GEO_MAX_INCLINATION_RAD = 0.1;
|
|
3987
|
+
var BDS_GEO_MIN_SEMIMAJOR_AXIS_M = 4e7;
|
|
3897
3988
|
var AE_GLO = 6378136;
|
|
3898
3989
|
var J2_GLO = 108263e-8;
|
|
3899
3990
|
var TWO_PI = 2 * Math.PI;
|
|
@@ -3919,10 +4010,7 @@ function keplerPosition(eph, t) {
|
|
|
3919
4010
|
}
|
|
3920
4011
|
const sinE = Math.sin(Ek);
|
|
3921
4012
|
const cosE = Math.cos(Ek);
|
|
3922
|
-
const vk = Math.atan2(
|
|
3923
|
-
Math.sqrt(1 - eph.e * eph.e) * sinE,
|
|
3924
|
-
cosE - eph.e
|
|
3925
|
-
);
|
|
4013
|
+
const vk = Math.atan2(Math.sqrt(1 - eph.e * eph.e) * sinE, cosE - eph.e);
|
|
3926
4014
|
const phik = vk + eph.omega;
|
|
3927
4015
|
const sin2phi = Math.sin(2 * phik);
|
|
3928
4016
|
const cos2phi = Math.cos(2 * phik);
|
|
@@ -3934,7 +4022,7 @@ function keplerPosition(eph, t) {
|
|
|
3934
4022
|
const ik = eph.i0 + dik + eph.idot * tk;
|
|
3935
4023
|
const xp = rk * Math.cos(uk);
|
|
3936
4024
|
const yp = rk * Math.sin(uk);
|
|
3937
|
-
const isBdsGeo = eph.system === "C" && Math.abs(eph.i0) <
|
|
4025
|
+
const isBdsGeo = eph.system === "C" && Math.abs(eph.i0) < BDS_GEO_MAX_INCLINATION_RAD && a > BDS_GEO_MIN_SEMIMAJOR_AXIS_M;
|
|
3938
4026
|
if (isBdsGeo) {
|
|
3939
4027
|
const omegak2 = eph.omega0 + eph.omegaDot * tk - OMEGA_E * eph.toe;
|
|
3940
4028
|
const cosO2 = Math.cos(omegak2);
|
|
@@ -4085,7 +4173,10 @@ function invert4x4(m) {
|
|
|
4085
4173
|
let det = a[0] * inv[0] + a[1] * inv[4] + a[2] * inv[8] + a[3] * inv[12];
|
|
4086
4174
|
if (Math.abs(det) < 1e-20) return null;
|
|
4087
4175
|
det = 1 / det;
|
|
4088
|
-
const result = Array.from(
|
|
4176
|
+
const result = Array.from(
|
|
4177
|
+
{ length: 4 },
|
|
4178
|
+
() => new Array(4).fill(0)
|
|
4179
|
+
);
|
|
4089
4180
|
for (let i = 0; i < 4; i++) {
|
|
4090
4181
|
for (let j = 0; j < 4; j++) {
|
|
4091
4182
|
result[i][j] = inv[i * 4 + j] * det;
|
|
@@ -4112,9 +4203,10 @@ function computeSatPosition(eph, timeMs) {
|
|
|
4112
4203
|
if (eph.system === "R" || eph.system === "S") {
|
|
4113
4204
|
return glonassPosition(eph, timeMs / 1e3);
|
|
4114
4205
|
}
|
|
4115
|
-
const GPS_EPOCH2 =
|
|
4206
|
+
const GPS_EPOCH2 = START_GPS_TIME.getTime();
|
|
4116
4207
|
const gpsSeconds = (timeMs - GPS_EPOCH2) / 1e3;
|
|
4117
|
-
|
|
4208
|
+
let tow = gpsSeconds % (7 * 86400);
|
|
4209
|
+
if (eph.system === "C") tow = (tow - 14 + 604800) % 604800;
|
|
4118
4210
|
return keplerPosition(eph, tow);
|
|
4119
4211
|
}
|
|
4120
4212
|
function navTimesFromEph(ephs) {
|
|
@@ -4196,16 +4288,22 @@ function selectBest(ephs, timeMs) {
|
|
|
4196
4288
|
}
|
|
4197
4289
|
return best;
|
|
4198
4290
|
}
|
|
4199
|
-
var GPS_EPOCH_MS =
|
|
4200
|
-
var BDS_EPOCH_MS =
|
|
4291
|
+
var GPS_EPOCH_MS = START_GPS_TIME.getTime();
|
|
4292
|
+
var BDS_EPOCH_MS = START_BDS_TIME.getTime();
|
|
4201
4293
|
var GAL_EPOCH_MS = GPS_EPOCH_MS;
|
|
4202
4294
|
function ephInfoToEphemeris(info) {
|
|
4203
4295
|
const sys = info.prn.charAt(0);
|
|
4204
4296
|
if (sys === "R") {
|
|
4205
|
-
if (info.x === void 0 || info.y === void 0 || info.z === void 0)
|
|
4206
|
-
|
|
4297
|
+
if (info.x === void 0 || info.y === void 0 || info.z === void 0)
|
|
4298
|
+
return null;
|
|
4299
|
+
if (info.vx === void 0 || info.vy === void 0 || info.vz === void 0)
|
|
4300
|
+
return null;
|
|
4207
4301
|
const now = new Date(info.lastReceived);
|
|
4208
|
-
const utcMidnight = Date.UTC(
|
|
4302
|
+
const utcMidnight = Date.UTC(
|
|
4303
|
+
now.getUTCFullYear(),
|
|
4304
|
+
now.getUTCMonth(),
|
|
4305
|
+
now.getUTCDate()
|
|
4306
|
+
);
|
|
4209
4307
|
const tbSec = (info.tb ?? 0) * 900;
|
|
4210
4308
|
const moscowOffset = 3 * 3600;
|
|
4211
4309
|
const tocMs = utcMidnight + (tbSec - moscowOffset) * 1e3;
|
|
@@ -4230,7 +4328,11 @@ function ephInfoToEphemeris(info) {
|
|
|
4230
4328
|
freqNum: info.freqChannel ?? 0
|
|
4231
4329
|
};
|
|
4232
4330
|
}
|
|
4233
|
-
if (info.sqrtA === void 0 || info.eccentricity === void 0 || info.inclination === void 0 || info.omega0 === void 0 || info.argPerigee === void 0 || info.meanAnomaly === void 0 || info.toe === void 0 || info.week === void 0)
|
|
4331
|
+
if (info.sqrtA === void 0 || info.eccentricity === void 0 || info.inclination === void 0 || info.omega0 === void 0 || info.argPerigee === void 0 || info.meanAnomaly === void 0 || info.toe === void 0 || info.week === void 0)
|
|
4332
|
+
return null;
|
|
4333
|
+
if (info.eccentricity < 0 || info.eccentricity >= 1 || info.sqrtA < 3e3 || info.sqrtA > 9e3 || info.toe < 0 || info.toe > 604800) {
|
|
4334
|
+
return null;
|
|
4335
|
+
}
|
|
4234
4336
|
let epochMs;
|
|
4235
4337
|
const tocSec = info.toc ?? info.toe;
|
|
4236
4338
|
if (sys === "C") {
|
|
@@ -4406,14 +4508,18 @@ async function ntripFetch(proxyUrl, path, headers, signal) {
|
|
|
4406
4508
|
} catch (err) {
|
|
4407
4509
|
if (err instanceof Error && err.name === "AbortError") throw err;
|
|
4408
4510
|
const message = err instanceof Error ? err.message : "The service may be temporarily unavailable.";
|
|
4409
|
-
throw new Error(`Could not reach the NTRIP proxy: ${message}`, {
|
|
4511
|
+
throw new Error(`Could not reach the NTRIP proxy: ${message}`, {
|
|
4512
|
+
cause: err
|
|
4513
|
+
});
|
|
4410
4514
|
}
|
|
4411
4515
|
}
|
|
4412
4516
|
async function fetchSourcetable(proxyUrl, info, signal) {
|
|
4413
4517
|
const headers = ntripHeaders(info);
|
|
4414
4518
|
const res = await ntripFetch(proxyUrl, "/", headers, signal);
|
|
4415
4519
|
if (res.status === 401) {
|
|
4416
|
-
throw new Error(
|
|
4520
|
+
throw new Error(
|
|
4521
|
+
"Authentication required. Please provide valid credentials."
|
|
4522
|
+
);
|
|
4417
4523
|
}
|
|
4418
4524
|
if (!res.ok) {
|
|
4419
4525
|
throw new Error(`Caster returned ${res.status} ${res.statusText}`);
|
|
@@ -4425,7 +4531,12 @@ async function connectToMountpoint(proxyUrl, info, signal) {
|
|
|
4425
4531
|
const headers = ntripHeaders(info);
|
|
4426
4532
|
const controller = new AbortController();
|
|
4427
4533
|
const combinedSignal = signal ? AbortSignal.any([signal, controller.signal]) : controller.signal;
|
|
4428
|
-
const res = await ntripFetch(
|
|
4534
|
+
const res = await ntripFetch(
|
|
4535
|
+
proxyUrl,
|
|
4536
|
+
`/${info.mountpoint}`,
|
|
4537
|
+
headers,
|
|
4538
|
+
combinedSignal
|
|
4539
|
+
);
|
|
4429
4540
|
if (res.status === 401) {
|
|
4430
4541
|
throw new Error("Authentication required for this mountpoint.");
|
|
4431
4542
|
}
|
|
@@ -4436,7 +4547,9 @@ async function connectToMountpoint(proxyUrl, info, signal) {
|
|
|
4436
4547
|
throw new Error(`Caster returned ${res.status} ${res.statusText}`);
|
|
4437
4548
|
}
|
|
4438
4549
|
if (!res.body) {
|
|
4439
|
-
throw new Error(
|
|
4550
|
+
throw new Error(
|
|
4551
|
+
"No response body \u2014 streaming not supported by this environment."
|
|
4552
|
+
);
|
|
4440
4553
|
}
|
|
4441
4554
|
return {
|
|
4442
4555
|
reader: res.body.getReader(),
|
|
@@ -4530,8 +4643,18 @@ var MultipathAccumulator = class {
|
|
|
4530
4643
|
time: t,
|
|
4531
4644
|
mp: arc.rawMp[i] - mean
|
|
4532
4645
|
}));
|
|
4533
|
-
const rms = Math.sqrt(
|
|
4534
|
-
|
|
4646
|
+
const rms = Math.sqrt(
|
|
4647
|
+
points.reduce((s, p) => s + p.mp * p.mp, 0) / points.length
|
|
4648
|
+
);
|
|
4649
|
+
this.results.push({
|
|
4650
|
+
prn,
|
|
4651
|
+
system: sys,
|
|
4652
|
+
band,
|
|
4653
|
+
refBand,
|
|
4654
|
+
label: label2,
|
|
4655
|
+
points,
|
|
4656
|
+
rms
|
|
4657
|
+
});
|
|
4535
4658
|
}
|
|
4536
4659
|
state.arc = { times: [], rawMp: [] };
|
|
4537
4660
|
}
|
|
@@ -4685,10 +4808,20 @@ var CycleSlipAccumulator = class {
|
|
|
4685
4808
|
const sigKey = `${sys}:${signal}`;
|
|
4686
4809
|
this.countEpoch(sigKey);
|
|
4687
4810
|
const stddev = mwSmoothStddev(prevSmooth);
|
|
4688
|
-
const threshold = Math.max(
|
|
4811
|
+
const threshold = Math.max(
|
|
4812
|
+
MW_MIN_THRESHOLD,
|
|
4813
|
+
MW_SIGMA_FACTOR * stddev
|
|
4814
|
+
);
|
|
4689
4815
|
const deviation = Math.abs(mw - prevSmooth.mean);
|
|
4690
4816
|
if (deviation > threshold) {
|
|
4691
|
-
this.recordSlip(
|
|
4817
|
+
this.recordSlip(
|
|
4818
|
+
sigKey,
|
|
4819
|
+
time,
|
|
4820
|
+
prn,
|
|
4821
|
+
signal,
|
|
4822
|
+
deviation,
|
|
4823
|
+
/* @__PURE__ */ new Set([b1, b2])
|
|
4824
|
+
);
|
|
4692
4825
|
mwSmooth.set(pairKey, mwSmoothInit(mw));
|
|
4693
4826
|
} else {
|
|
4694
4827
|
mwSmooth.set(pairKey, mwSmoothUpdate(prevSmooth, mw));
|
|
@@ -4743,7 +4876,13 @@ var CycleSlipAccumulator = class {
|
|
|
4743
4876
|
}
|
|
4744
4877
|
}
|
|
4745
4878
|
}
|
|
4746
|
-
this.prev.set(prn, {
|
|
4879
|
+
this.prev.set(prn, {
|
|
4880
|
+
time,
|
|
4881
|
+
mwSmooth,
|
|
4882
|
+
gf: gfMap,
|
|
4883
|
+
phase: phaseM,
|
|
4884
|
+
code: codeM
|
|
4885
|
+
});
|
|
4747
4886
|
};
|
|
4748
4887
|
finalize() {
|
|
4749
4888
|
const satSlipCounts = {};
|
|
@@ -4751,7 +4890,10 @@ var CycleSlipAccumulator = class {
|
|
|
4751
4890
|
satSlipCounts[ev.prn] = (satSlipCounts[ev.prn] ?? 0) + 1;
|
|
4752
4891
|
}
|
|
4753
4892
|
const signalStats = [];
|
|
4754
|
-
const allKeys = /* @__PURE__ */ new Set([
|
|
4893
|
+
const allKeys = /* @__PURE__ */ new Set([
|
|
4894
|
+
...this.signalEpochs.keys(),
|
|
4895
|
+
...this.signalSlips.keys()
|
|
4896
|
+
]);
|
|
4755
4897
|
for (const sigKey of allKeys) {
|
|
4756
4898
|
const [sys, ...rest] = sigKey.split(":");
|
|
4757
4899
|
const signal = rest.join(":");
|
|
@@ -5321,32 +5463,33 @@ function parseNmeaFile(content) {
|
|
|
5321
5463
|
}
|
|
5322
5464
|
|
|
5323
5465
|
// src/signals/definitions.ts
|
|
5324
|
-
var
|
|
5325
|
-
var
|
|
5326
|
-
var
|
|
5327
|
-
var
|
|
5328
|
-
var
|
|
5329
|
-
var
|
|
5330
|
-
var
|
|
5331
|
-
var
|
|
5332
|
-
var
|
|
5333
|
-
var
|
|
5334
|
-
var
|
|
5335
|
-
var
|
|
5336
|
-
var
|
|
5337
|
-
var
|
|
5338
|
-
var
|
|
5339
|
-
var
|
|
5340
|
-
var
|
|
5341
|
-
var
|
|
5342
|
-
var
|
|
5343
|
-
var
|
|
5344
|
-
var
|
|
5345
|
-
var
|
|
5346
|
-
var
|
|
5347
|
-
var
|
|
5348
|
-
var
|
|
5349
|
-
var
|
|
5466
|
+
var MHz = 1e6;
|
|
5467
|
+
var FREQ_GPS_L1 = FREQ.G["1"] / MHz;
|
|
5468
|
+
var FREQ_GPS_L2 = FREQ.G["2"] / MHz;
|
|
5469
|
+
var FREQ_GPS_L5 = FREQ.G["5"] / MHz;
|
|
5470
|
+
var FREQ_GLO_L1 = GLO_F1_BASE / MHz;
|
|
5471
|
+
var FREQ_GLO_L2 = GLO_F2_BASE / MHz;
|
|
5472
|
+
var DELTA_GLO_L1 = GLO_F1_STEP / MHz;
|
|
5473
|
+
var DELTA_GLO_L2 = GLO_F2_STEP / MHz;
|
|
5474
|
+
var FREQ_GLO_L1OC = FREQ.R["4"] / MHz;
|
|
5475
|
+
var FREQ_GLO_L2OC = FREQ.R["6"] / MHz;
|
|
5476
|
+
var FREQ_GLO_L3OC = FREQ.R["3"] / MHz;
|
|
5477
|
+
var FREQ_GAL_E1 = FREQ.E["1"] / MHz;
|
|
5478
|
+
var FREQ_GAL_E5 = FREQ.E["8"] / MHz;
|
|
5479
|
+
var FREQ_GAL_E5a = FREQ.E["5"] / MHz;
|
|
5480
|
+
var FREQ_GAL_E5b = FREQ.E["7"] / MHz;
|
|
5481
|
+
var FREQ_GAL_E6 = FREQ.E["6"] / MHz;
|
|
5482
|
+
var FREQ_BDS_B1I = FREQ.C["2"] / MHz;
|
|
5483
|
+
var FREQ_BDS_B2I = FREQ.C["7"] / MHz;
|
|
5484
|
+
var FREQ_BDS_B3I = FREQ.C["6"] / MHz;
|
|
5485
|
+
var FREQ_BDS_B1A = FREQ.C["1"] / MHz;
|
|
5486
|
+
var FREQ_BDS_B1C = FREQ.C["1"] / MHz;
|
|
5487
|
+
var FREQ_BDS_B3A = FREQ.C["6"] / MHz;
|
|
5488
|
+
var FREQ_QZS_L1 = FREQ.J["1"] / MHz;
|
|
5489
|
+
var FREQ_QZS_L2 = FREQ.J["2"] / MHz;
|
|
5490
|
+
var FREQ_QZS_L5 = FREQ.J["5"] / MHz;
|
|
5491
|
+
var FREQ_QZS_L6 = FREQ.J["6"] / MHz;
|
|
5492
|
+
var FREQ_NAVIC_L5 = FREQ.I["5"] / MHz;
|
|
5350
5493
|
var GPS_COLOR = "#4ade80";
|
|
5351
5494
|
var GPS_M_COLOR = "#ef4444";
|
|
5352
5495
|
var GPS_P_COLOR = "#dbc51f";
|
|
@@ -6272,10 +6415,13 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
6272
6415
|
phiBPSK,
|
|
6273
6416
|
rad2deg,
|
|
6274
6417
|
readString,
|
|
6418
|
+
reportDecodeError,
|
|
6275
6419
|
resetGloFreqCache,
|
|
6276
6420
|
rhumbLine,
|
|
6277
6421
|
rtcm3Constellation,
|
|
6278
6422
|
selectEphemeris,
|
|
6423
|
+
setGloFreqNumber,
|
|
6424
|
+
setRtcm3DebugHandler,
|
|
6279
6425
|
systemCmp,
|
|
6280
6426
|
systemName,
|
|
6281
6427
|
updateStationMeta,
|