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.d.cts
CHANGED
|
@@ -9,6 +9,9 @@ export { E as EpochSummary, P as ParseOptions, R as RinexHeader, a as RinexResul
|
|
|
9
9
|
export { E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHeader, a as NavResult, p as parseNavFile } from './nav-BAI1a9vK.cjs';
|
|
10
10
|
export { B as BitReader, E as EphemerisInfo, R as Rtcm3DebugHandler, a as Rtcm3Decoder, b as Rtcm3Frame, d as decodeEphemeris, r as readString, c as reportDecodeError, s as setRtcm3DebugHandler } from './ephemeris-Ohl6NAfw.cjs';
|
|
11
11
|
export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.cjs';
|
|
12
|
+
export { UbxMeasurement, UbxParseResult, UbxRawxEpoch, parseUbxRawx } from './ubx.cjs';
|
|
13
|
+
export { SbfMeasEpoch, SbfMeasurement, SbfParseResult, parseSbfMeas } from './sbf.cjs';
|
|
14
|
+
export { NovatelEpoch, NovatelMeasurement, NovatelParseResult, parseNovatelRange } from './novatel.cjs';
|
|
12
15
|
export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.cjs';
|
|
13
16
|
export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.cjs';
|
|
14
17
|
export { KlobucharCoeffs, SppOptions, SppSolution, ionoFree, klobucharDelay, satClockCorrection, solveSpp } from './positioning.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,9 @@ export { E as EpochSummary, P as ParseOptions, R as RinexHeader, a as RinexResul
|
|
|
9
9
|
export { E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHeader, a as NavResult, p as parseNavFile } from './nav-BAI1a9vK.js';
|
|
10
10
|
export { B as BitReader, E as EphemerisInfo, R as Rtcm3DebugHandler, a as Rtcm3Decoder, b as Rtcm3Frame, d as decodeEphemeris, r as readString, c as reportDecodeError, s as setRtcm3DebugHandler } from './ephemeris-Ohl6NAfw.js';
|
|
11
11
|
export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.js';
|
|
12
|
+
export { UbxMeasurement, UbxParseResult, UbxRawxEpoch, parseUbxRawx } from './ubx.js';
|
|
13
|
+
export { SbfMeasEpoch, SbfMeasurement, SbfParseResult, parseSbfMeas } from './sbf.js';
|
|
14
|
+
export { NovatelEpoch, NovatelMeasurement, NovatelParseResult, parseNovatelRange } from './novatel.js';
|
|
12
15
|
export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, computeVisibilityFromPositions, dopplerHz, ecefToAzEl, ephInfoToEphemeris, glonassPosition, keplerPosition, maskRadForAzimuth, navTimesFromEph, rangeRate, selectEphemeris } from './orbit.js';
|
|
13
16
|
export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.js';
|
|
14
17
|
export { KlobucharCoeffs, SppOptions, SppSolution, ionoFree, klobucharDelay, satClockCorrection, solveSpp } from './positioning.js';
|
package/dist/index.js
CHANGED
|
@@ -1,29 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
connectToMountpoint,
|
|
3
|
-
fetchSourcetable,
|
|
4
|
-
parseSourcetable
|
|
5
|
-
} from "./chunk-BJHTBYNG.js";
|
|
6
|
-
import {
|
|
7
|
-
CompletenessAccumulator,
|
|
8
|
-
CycleSlipAccumulator,
|
|
9
|
-
IonoAccumulator,
|
|
10
|
-
MultipathAccumulator,
|
|
11
|
-
analyzeQuality,
|
|
12
|
-
applyIonoDcb,
|
|
13
|
-
computeIonoRate,
|
|
14
|
-
detrendIonoArcs,
|
|
15
|
-
parseSinexBiasDcb
|
|
16
|
-
} from "./chunk-Z5UZUNCB.js";
|
|
17
|
-
import {
|
|
18
|
-
frequencyLabel,
|
|
19
|
-
parseAntex
|
|
20
|
-
} from "./chunk-5CMSYIYM.js";
|
|
21
|
-
import {
|
|
22
|
-
computeStats,
|
|
23
|
-
nmeaCoordToDecimal,
|
|
24
|
-
parseNmeaFile,
|
|
25
|
-
verifyChecksum
|
|
26
|
-
} from "./chunk-YDMYO3YK.js";
|
|
27
1
|
import {
|
|
28
2
|
BAND_PRESETS,
|
|
29
3
|
CONSTELLATIONS,
|
|
@@ -59,6 +33,41 @@ import {
|
|
|
59
33
|
phiBOCs,
|
|
60
34
|
phiBPSK
|
|
61
35
|
} from "./chunk-2K3FCJBX.js";
|
|
36
|
+
import {
|
|
37
|
+
parseUbxRawx
|
|
38
|
+
} from "./chunk-5IXK25MX.js";
|
|
39
|
+
import {
|
|
40
|
+
parseSbfMeas
|
|
41
|
+
} from "./chunk-YIHO74OS.js";
|
|
42
|
+
import {
|
|
43
|
+
parseNovatelRange
|
|
44
|
+
} from "./chunk-SWKWJEGY.js";
|
|
45
|
+
import {
|
|
46
|
+
connectToMountpoint,
|
|
47
|
+
fetchSourcetable,
|
|
48
|
+
parseSourcetable
|
|
49
|
+
} from "./chunk-BJHTBYNG.js";
|
|
50
|
+
import {
|
|
51
|
+
CompletenessAccumulator,
|
|
52
|
+
CycleSlipAccumulator,
|
|
53
|
+
IonoAccumulator,
|
|
54
|
+
MultipathAccumulator,
|
|
55
|
+
analyzeQuality,
|
|
56
|
+
applyIonoDcb,
|
|
57
|
+
computeIonoRate,
|
|
58
|
+
detrendIonoArcs,
|
|
59
|
+
parseSinexBiasDcb
|
|
60
|
+
} from "./chunk-Z5UZUNCB.js";
|
|
61
|
+
import {
|
|
62
|
+
frequencyLabel,
|
|
63
|
+
parseAntex
|
|
64
|
+
} from "./chunk-5CMSYIYM.js";
|
|
65
|
+
import {
|
|
66
|
+
computeStats,
|
|
67
|
+
nmeaCoordToDecimal,
|
|
68
|
+
parseNmeaFile,
|
|
69
|
+
verifyChecksum
|
|
70
|
+
} from "./chunk-YDMYO3YK.js";
|
|
62
71
|
import {
|
|
63
72
|
Scale,
|
|
64
73
|
getDateFromDayOfWeek,
|
|
@@ -460,10 +469,13 @@ export {
|
|
|
460
469
|
parseIonex,
|
|
461
470
|
parseNavFile,
|
|
462
471
|
parseNmeaFile,
|
|
472
|
+
parseNovatelRange,
|
|
463
473
|
parseRinexStream,
|
|
474
|
+
parseSbfMeas,
|
|
464
475
|
parseSinexBiasDcb,
|
|
465
476
|
parseSourcetable,
|
|
466
477
|
parseSp3,
|
|
478
|
+
parseUbxRawx,
|
|
467
479
|
phiAltBOC,
|
|
468
480
|
phiBOCc,
|
|
469
481
|
phiBOCs,
|
package/dist/novatel.cjs
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/novatel/index.ts
|
|
21
|
+
var novatel_exports = {};
|
|
22
|
+
__export(novatel_exports, {
|
|
23
|
+
parseNovatelRange: () => parseNovatelRange
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(novatel_exports);
|
|
26
|
+
var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
|
|
27
|
+
var MS_PER_WEEK = 7 * 864e5;
|
|
28
|
+
var HDR = 28;
|
|
29
|
+
var ID_RANGE = 43;
|
|
30
|
+
var ID_RANGECMP = 140;
|
|
31
|
+
var ID_GLOEPHEMERIS = 723;
|
|
32
|
+
var C_LIGHT = 299792458;
|
|
33
|
+
var ADR_ROLL = 8388608;
|
|
34
|
+
function carrierFreq(sys, code, gloK) {
|
|
35
|
+
const band = code[0];
|
|
36
|
+
switch (sys) {
|
|
37
|
+
case "G":
|
|
38
|
+
case "J":
|
|
39
|
+
return band === "1" ? 157542e4 : band === "2" ? 12276e5 : 117645e4;
|
|
40
|
+
case "S":
|
|
41
|
+
return band === "1" ? 157542e4 : 117645e4;
|
|
42
|
+
case "E":
|
|
43
|
+
return band === "1" ? 157542e4 : band === "5" ? 117645e4 : band === "7" ? 120714e4 : band === "8" ? 1191795e3 : 127875e4;
|
|
44
|
+
case "C":
|
|
45
|
+
return band === "1" ? 157542e4 : band === "2" ? 1561098e3 : band === "5" ? 117645e4 : band === "7" ? 120714e4 : 126852e4;
|
|
46
|
+
case "R": {
|
|
47
|
+
if (gloK === null) return 0;
|
|
48
|
+
if (band === "1") return 1602e6 + gloK * 562500;
|
|
49
|
+
if (band === "2") return 1246e6 + gloK * 437500;
|
|
50
|
+
return 1202025e3;
|
|
51
|
+
}
|
|
52
|
+
default:
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function exsign(v, bits) {
|
|
57
|
+
return v & 1 << bits - 1 ? v - 2 ** bits : v;
|
|
58
|
+
}
|
|
59
|
+
function crc32(data, start, len) {
|
|
60
|
+
let crc = 0;
|
|
61
|
+
for (let i = start; i < start + len; i++) {
|
|
62
|
+
crc ^= data[i];
|
|
63
|
+
for (let j = 0; j < 8; j++) {
|
|
64
|
+
crc = crc & 1 ? crc >>> 1 ^ 3988292384 : crc >>> 1;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return crc >>> 0;
|
|
68
|
+
}
|
|
69
|
+
var SIGNALS = {
|
|
70
|
+
0: {
|
|
71
|
+
0: ["G", "1C"],
|
|
72
|
+
5: ["G", "2P"],
|
|
73
|
+
9: ["G", "2W"],
|
|
74
|
+
14: ["G", "5Q"],
|
|
75
|
+
16: ["G", "1L"],
|
|
76
|
+
17: ["G", "2S"]
|
|
77
|
+
},
|
|
78
|
+
1: { 0: ["R", "1C"], 1: ["R", "2C"], 5: ["R", "2P"], 6: ["R", "3Q"] },
|
|
79
|
+
2: { 0: ["S", "1C"], 6: ["S", "5I"] },
|
|
80
|
+
3: {
|
|
81
|
+
1: ["E", "1C"],
|
|
82
|
+
2: ["E", "1C"],
|
|
83
|
+
6: ["E", "6B"],
|
|
84
|
+
7: ["E", "6C"],
|
|
85
|
+
12: ["E", "5Q"],
|
|
86
|
+
17: ["E", "7Q"],
|
|
87
|
+
20: ["E", "8Q"]
|
|
88
|
+
},
|
|
89
|
+
4: {
|
|
90
|
+
0: ["C", "2I"],
|
|
91
|
+
1: ["C", "7I"],
|
|
92
|
+
2: ["C", "6I"],
|
|
93
|
+
4: ["C", "2I"],
|
|
94
|
+
5: ["C", "7I"],
|
|
95
|
+
6: ["C", "6I"],
|
|
96
|
+
7: ["C", "1P"],
|
|
97
|
+
9: ["C", "5P"],
|
|
98
|
+
11: ["C", "7D"]
|
|
99
|
+
},
|
|
100
|
+
5: {
|
|
101
|
+
0: ["J", "1C"],
|
|
102
|
+
14: ["J", "5Q"],
|
|
103
|
+
16: ["J", "1L"],
|
|
104
|
+
17: ["J", "2S"],
|
|
105
|
+
27: ["J", "6L"]
|
|
106
|
+
},
|
|
107
|
+
6: { 0: ["I", "5A"] }
|
|
108
|
+
};
|
|
109
|
+
function parseNovatelRange(data) {
|
|
110
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
111
|
+
const epochs = [];
|
|
112
|
+
const messageCounts = {};
|
|
113
|
+
const obsCodes = {};
|
|
114
|
+
let badCrc = 0;
|
|
115
|
+
const gloFcn = /* @__PURE__ */ new Map();
|
|
116
|
+
for (let j = 0; j + HDR + 4 <= data.length; j++) {
|
|
117
|
+
if (data[j] !== 170 || data[j + 1] !== 68 || data[j + 2] !== 18)
|
|
118
|
+
continue;
|
|
119
|
+
const hl = data[j + 3];
|
|
120
|
+
const id = view.getUint16(j + 4, true);
|
|
121
|
+
const ln = view.getUint16(j + 8, true);
|
|
122
|
+
if (id !== ID_GLOEPHEMERIS || hl < HDR || j + hl + ln + 4 > data.length)
|
|
123
|
+
continue;
|
|
124
|
+
if (crc32(data, j, hl + ln) !== view.getUint32(j + hl + ln, true)) continue;
|
|
125
|
+
const slot = view.getUint16(j + hl, true) - 37;
|
|
126
|
+
const k = view.getUint16(j + hl + 2, true) - 7;
|
|
127
|
+
if (slot >= 1 && slot <= 32) gloFcn.set(slot, k);
|
|
128
|
+
j += hl + ln + 3;
|
|
129
|
+
}
|
|
130
|
+
let i = 0;
|
|
131
|
+
while (i + HDR + 4 <= data.length) {
|
|
132
|
+
if (data[i] !== 170 || data[i + 1] !== 68 || data[i + 2] !== 18) {
|
|
133
|
+
i++;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const hlen = data[i + 3];
|
|
137
|
+
const msgId = view.getUint16(i + 4, true);
|
|
138
|
+
const msgLen = view.getUint16(i + 8, true);
|
|
139
|
+
const total = hlen + msgLen + 4;
|
|
140
|
+
if (hlen < HDR || i + total > data.length) {
|
|
141
|
+
i++;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (crc32(data, i, hlen + msgLen) !== view.getUint32(i + hlen + msgLen, true)) {
|
|
145
|
+
badCrc++;
|
|
146
|
+
i++;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
messageCounts[msgId] = (messageCounts[msgId] ?? 0) + 1;
|
|
150
|
+
const binary = (data[i + 6] >> 4 & 3) === 0;
|
|
151
|
+
const week = view.getUint16(i + 14, true);
|
|
152
|
+
const towMs = view.getUint32(i + 16, true);
|
|
153
|
+
if (msgId === ID_RANGECMP && binary && week > 0) {
|
|
154
|
+
const p = i + hlen;
|
|
155
|
+
const nobs = view.getUint32(p, true);
|
|
156
|
+
if (p + 4 + nobs * 24 <= i + hlen + msgLen) {
|
|
157
|
+
const meas = [];
|
|
158
|
+
for (let k = 0; k < nobs; k++) {
|
|
159
|
+
const o = p + 4 + 24 * k;
|
|
160
|
+
const stat = view.getUint32(o, true);
|
|
161
|
+
const satsys = stat >>> 16 & 7;
|
|
162
|
+
const sigtype = stat >>> 21 & 31;
|
|
163
|
+
const plock = stat >>> 10 & 1;
|
|
164
|
+
const parity = stat >>> 11 & 1;
|
|
165
|
+
const clock = stat >>> 12 & 1;
|
|
166
|
+
const sig = SIGNALS[satsys]?.[sigtype];
|
|
167
|
+
if (!sig) continue;
|
|
168
|
+
let [sysL, code] = sig;
|
|
169
|
+
let prnNum = data[o + 17];
|
|
170
|
+
if (sysL === "R") prnNum -= 37;
|
|
171
|
+
if (sysL === "S" && prnNum >= 183 && prnNum <= 191 && code === "1C") {
|
|
172
|
+
sysL = "J";
|
|
173
|
+
code = "1Z";
|
|
174
|
+
prnNum -= 182;
|
|
175
|
+
} else if (sysL === "S") {
|
|
176
|
+
prnNum -= 100;
|
|
177
|
+
}
|
|
178
|
+
if (prnNum < 1 || prnNum > 99) continue;
|
|
179
|
+
if (sysL === "R" && !parity) continue;
|
|
180
|
+
const gloK = sysL === "R" ? gloFcn.get(prnNum) ?? null : null;
|
|
181
|
+
const dop = exsign(view.getUint32(o + 4, true) & 268435455, 28) / 256;
|
|
182
|
+
const psr = (view.getUint32(o + 7, true) >>> 4) / 128 + data[o + 11] * 2097152;
|
|
183
|
+
let cp = null;
|
|
184
|
+
const freq = carrierFreq(sysL, code, gloK);
|
|
185
|
+
if (freq > 0) {
|
|
186
|
+
const adr = view.getInt32(o + 12, true) / 256;
|
|
187
|
+
const rolls = psr * freq / C_LIGHT / ADR_ROLL + adr / ADR_ROLL;
|
|
188
|
+
cp = -adr + ADR_ROLL * Math.floor(rolls + (rolls <= 0 ? -0.5 : 0.5));
|
|
189
|
+
}
|
|
190
|
+
const lockt = (view.getUint32(o + 18, true) & 2097151) / 32;
|
|
191
|
+
const cn0 = ((view.getUint16(o + 20, true) & 1023) >>> 5) + 20;
|
|
192
|
+
meas.push({
|
|
193
|
+
prn: `${sysL}${String(prnNum).padStart(2, "0")}`,
|
|
194
|
+
code,
|
|
195
|
+
pr: clock ? psr : null,
|
|
196
|
+
cp: plock ? cp : null,
|
|
197
|
+
doppler: plock ? dop : null,
|
|
198
|
+
cn0,
|
|
199
|
+
lockTimeS: lockt,
|
|
200
|
+
gloChannel: gloK
|
|
201
|
+
});
|
|
202
|
+
const codes = obsCodes[sysL] ??= [];
|
|
203
|
+
if (!codes.includes(code)) codes.push(code);
|
|
204
|
+
}
|
|
205
|
+
epochs.push({
|
|
206
|
+
timeMs: GPS_EPOCH_MS + week * MS_PER_WEEK + towMs,
|
|
207
|
+
meas
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
} else if (msgId === ID_RANGE && binary && week > 0) {
|
|
211
|
+
const p = i + hlen;
|
|
212
|
+
const nobs = view.getUint32(p, true);
|
|
213
|
+
if (p + 4 + nobs * 44 <= i + hlen + msgLen) {
|
|
214
|
+
const meas = [];
|
|
215
|
+
for (let k = 0; k < nobs; k++) {
|
|
216
|
+
const o = p + 4 + 44 * k;
|
|
217
|
+
const stat = view.getUint32(o + 40, true);
|
|
218
|
+
const satsys = stat >>> 16 & 7;
|
|
219
|
+
const sigtype = stat >>> 21 & 31;
|
|
220
|
+
const plock = stat >>> 10 & 1;
|
|
221
|
+
const parity = stat >>> 11 & 1;
|
|
222
|
+
const clock = stat >>> 12 & 1;
|
|
223
|
+
const sig = SIGNALS[satsys]?.[sigtype];
|
|
224
|
+
if (!sig) continue;
|
|
225
|
+
let [sysL, code] = sig;
|
|
226
|
+
let prnNum = view.getUint16(o, true);
|
|
227
|
+
if (sysL === "R") prnNum -= 37;
|
|
228
|
+
if (sysL === "S" && prnNum >= 183 && prnNum <= 191 && code === "1C") {
|
|
229
|
+
sysL = "J";
|
|
230
|
+
code = "1Z";
|
|
231
|
+
prnNum -= 182;
|
|
232
|
+
} else if (sysL === "S") {
|
|
233
|
+
prnNum -= 100;
|
|
234
|
+
}
|
|
235
|
+
if (prnNum < 1 || prnNum > 99) continue;
|
|
236
|
+
if (sysL === "R" && !parity) continue;
|
|
237
|
+
const prn = `${sysL}${String(prnNum).padStart(2, "0")}`;
|
|
238
|
+
const gfrq = view.getUint16(o + 2, true);
|
|
239
|
+
const psr = view.getFloat64(o + 4, true);
|
|
240
|
+
const adr = view.getFloat64(o + 16, true);
|
|
241
|
+
const dop = view.getFloat32(o + 28, true);
|
|
242
|
+
const snr = view.getFloat32(o + 32, true);
|
|
243
|
+
const lockt = view.getFloat32(o + 36, true);
|
|
244
|
+
meas.push({
|
|
245
|
+
prn,
|
|
246
|
+
code,
|
|
247
|
+
pr: clock ? psr : null,
|
|
248
|
+
cp: plock ? -adr : null,
|
|
249
|
+
doppler: plock ? dop : null,
|
|
250
|
+
cn0: snr,
|
|
251
|
+
lockTimeS: lockt,
|
|
252
|
+
gloChannel: sysL === "R" ? gfrq - 8 : null
|
|
253
|
+
});
|
|
254
|
+
const codes = obsCodes[sysL] ??= [];
|
|
255
|
+
if (!codes.includes(code)) codes.push(code);
|
|
256
|
+
}
|
|
257
|
+
epochs.push({
|
|
258
|
+
timeMs: GPS_EPOCH_MS + week * MS_PER_WEEK + towMs,
|
|
259
|
+
meas
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
i += total;
|
|
264
|
+
}
|
|
265
|
+
return { epochs, messageCounts, obsCodes, badCrc };
|
|
266
|
+
}
|
|
267
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
268
|
+
0 && (module.exports = {
|
|
269
|
+
parseNovatelRange
|
|
270
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NovAtel OEM4/6/7 raw-measurement decoding (RANGE log, message 43).
|
|
3
|
+
*
|
|
4
|
+
* Framing: 0xAA 0x44 0x12, a 28-byte binary header (message ID,
|
|
5
|
+
* GPS week + milliseconds), payload, and a reflected CRC-32
|
|
6
|
+
* (poly 0xEDB88320) over the whole frame. Each RANGE observation is a
|
|
7
|
+
* 44-byte record whose channel-tracking-status word carries the
|
|
8
|
+
* constellation and signal type.
|
|
9
|
+
*
|
|
10
|
+
* Field layout and signal tables ported from RTKLIB demo5
|
|
11
|
+
* (rtklibexplorer fork, src/rcv/novatel.c, BSD-2-Clause) and
|
|
12
|
+
* cross-checked against the OEM7 Commands and Logs Reference Manual.
|
|
13
|
+
* Notably: RINEX carrier phase is the NEGATED accumulated Doppler
|
|
14
|
+
* range (L = −adr), GLONASS PRNs are offset by 37, GLONASS phases
|
|
15
|
+
* without known parity are dropped, and code/phase are individually
|
|
16
|
+
* gated by their lock flags.
|
|
17
|
+
*/
|
|
18
|
+
interface NovatelMeasurement {
|
|
19
|
+
/** RINEX PRN, e.g. "G04", "R11", "S23", "J01". */
|
|
20
|
+
prn: string;
|
|
21
|
+
/** RINEX band+attribute, e.g. "1C", "2W", "5Q". */
|
|
22
|
+
code: string;
|
|
23
|
+
/** Pseudorange (m), null when the code is unlocked. */
|
|
24
|
+
pr: number | null;
|
|
25
|
+
/** Carrier phase (cycles, RINEX sign), null when phase is unlocked. */
|
|
26
|
+
cp: number | null;
|
|
27
|
+
/** Instantaneous Doppler (Hz), null when phase is unlocked. */
|
|
28
|
+
doppler: number | null;
|
|
29
|
+
/** C/N0 (dB-Hz). */
|
|
30
|
+
cn0: number;
|
|
31
|
+
/** Continuous lock time (s). */
|
|
32
|
+
lockTimeS: number;
|
|
33
|
+
/** GLONASS frequency channel k (freqId − 8), null for CDMA systems. */
|
|
34
|
+
gloChannel: number | null;
|
|
35
|
+
}
|
|
36
|
+
interface NovatelEpoch {
|
|
37
|
+
/** Epoch (GPS-scale ms — same convention as the RINEX parser). */
|
|
38
|
+
timeMs: number;
|
|
39
|
+
meas: NovatelMeasurement[];
|
|
40
|
+
}
|
|
41
|
+
interface NovatelParseResult {
|
|
42
|
+
epochs: NovatelEpoch[];
|
|
43
|
+
/** Count per message ID, for diagnostics. */
|
|
44
|
+
messageCounts: Record<number, number>;
|
|
45
|
+
/** Observation codes seen per system letter, in first-seen order. */
|
|
46
|
+
obsCodes: Record<string, string[]>;
|
|
47
|
+
/** Frames whose CRC failed (corruption indicator). */
|
|
48
|
+
badCrc: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Decode every valid RANGE message in a NovAtel binary byte stream.
|
|
52
|
+
* Other messages are counted and skipped; CRC failures resync at the
|
|
53
|
+
* next byte.
|
|
54
|
+
*/
|
|
55
|
+
declare function parseNovatelRange(data: Uint8Array): NovatelParseResult;
|
|
56
|
+
|
|
57
|
+
export { type NovatelEpoch, type NovatelMeasurement, type NovatelParseResult, parseNovatelRange };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NovAtel OEM4/6/7 raw-measurement decoding (RANGE log, message 43).
|
|
3
|
+
*
|
|
4
|
+
* Framing: 0xAA 0x44 0x12, a 28-byte binary header (message ID,
|
|
5
|
+
* GPS week + milliseconds), payload, and a reflected CRC-32
|
|
6
|
+
* (poly 0xEDB88320) over the whole frame. Each RANGE observation is a
|
|
7
|
+
* 44-byte record whose channel-tracking-status word carries the
|
|
8
|
+
* constellation and signal type.
|
|
9
|
+
*
|
|
10
|
+
* Field layout and signal tables ported from RTKLIB demo5
|
|
11
|
+
* (rtklibexplorer fork, src/rcv/novatel.c, BSD-2-Clause) and
|
|
12
|
+
* cross-checked against the OEM7 Commands and Logs Reference Manual.
|
|
13
|
+
* Notably: RINEX carrier phase is the NEGATED accumulated Doppler
|
|
14
|
+
* range (L = −adr), GLONASS PRNs are offset by 37, GLONASS phases
|
|
15
|
+
* without known parity are dropped, and code/phase are individually
|
|
16
|
+
* gated by their lock flags.
|
|
17
|
+
*/
|
|
18
|
+
interface NovatelMeasurement {
|
|
19
|
+
/** RINEX PRN, e.g. "G04", "R11", "S23", "J01". */
|
|
20
|
+
prn: string;
|
|
21
|
+
/** RINEX band+attribute, e.g. "1C", "2W", "5Q". */
|
|
22
|
+
code: string;
|
|
23
|
+
/** Pseudorange (m), null when the code is unlocked. */
|
|
24
|
+
pr: number | null;
|
|
25
|
+
/** Carrier phase (cycles, RINEX sign), null when phase is unlocked. */
|
|
26
|
+
cp: number | null;
|
|
27
|
+
/** Instantaneous Doppler (Hz), null when phase is unlocked. */
|
|
28
|
+
doppler: number | null;
|
|
29
|
+
/** C/N0 (dB-Hz). */
|
|
30
|
+
cn0: number;
|
|
31
|
+
/** Continuous lock time (s). */
|
|
32
|
+
lockTimeS: number;
|
|
33
|
+
/** GLONASS frequency channel k (freqId − 8), null for CDMA systems. */
|
|
34
|
+
gloChannel: number | null;
|
|
35
|
+
}
|
|
36
|
+
interface NovatelEpoch {
|
|
37
|
+
/** Epoch (GPS-scale ms — same convention as the RINEX parser). */
|
|
38
|
+
timeMs: number;
|
|
39
|
+
meas: NovatelMeasurement[];
|
|
40
|
+
}
|
|
41
|
+
interface NovatelParseResult {
|
|
42
|
+
epochs: NovatelEpoch[];
|
|
43
|
+
/** Count per message ID, for diagnostics. */
|
|
44
|
+
messageCounts: Record<number, number>;
|
|
45
|
+
/** Observation codes seen per system letter, in first-seen order. */
|
|
46
|
+
obsCodes: Record<string, string[]>;
|
|
47
|
+
/** Frames whose CRC failed (corruption indicator). */
|
|
48
|
+
badCrc: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Decode every valid RANGE message in a NovAtel binary byte stream.
|
|
52
|
+
* Other messages are counted and skipped; CRC failures resync at the
|
|
53
|
+
* next byte.
|
|
54
|
+
*/
|
|
55
|
+
declare function parseNovatelRange(data: Uint8Array): NovatelParseResult;
|
|
56
|
+
|
|
57
|
+
export { type NovatelEpoch, type NovatelMeasurement, type NovatelParseResult, parseNovatelRange };
|