gnss-js 1.17.0 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-7QR2KPDU.js → chunk-2IM5VXNI.js} +11 -6
- package/dist/{chunk-ZNCQNHNI.js → chunk-5S5HMAKW.js} +41 -0
- package/dist/chunk-6NCMACDO.js +208 -0
- package/dist/{chunk-REYOYF7O.js → chunk-IQ5OIMQD.js} +1 -0
- package/dist/{chunk-IG5CDNDS.js → chunk-JW2ICDR7.js} +40 -1
- package/dist/{chunk-HXF7XVW7.js → chunk-K73SERD5.js} +299 -11
- package/dist/index.cjs +746 -189
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +14 -5
- package/dist/nav-DImXUdbp.d.cts +223 -0
- package/dist/nav-DImXUdbp.d.ts +223 -0
- package/dist/novatel.cjs +10 -5
- package/dist/novatel.d.cts +1 -1
- package/dist/novatel.d.ts +1 -1
- package/dist/novatel.js +2 -2
- package/dist/orbit.d.cts +1 -1
- package/dist/orbit.d.ts +1 -1
- package/dist/positioning.d.cts +1 -1
- package/dist/positioning.d.ts +1 -1
- package/dist/rinex.cjs +304 -11
- package/dist/rinex.d.cts +45 -3
- package/dist/rinex.d.ts +45 -3
- package/dist/rinex.js +7 -1
- package/dist/sbf.cjs +253 -2
- package/dist/sbf.d.cts +42 -2
- package/dist/sbf.d.ts +42 -2
- package/dist/sbf.js +5 -1
- package/dist/ubx.cjs +234 -2
- package/dist/ubx.d.cts +32 -2
- package/dist/ubx.d.ts +32 -2
- package/dist/ubx.js +5 -2
- package/package.json +1 -1
- package/dist/nav-BAI1a9vK.d.cts +0 -108
- package/dist/nav-BAI1a9vK.d.ts +0 -108
package/dist/index.cjs
CHANGED
|
@@ -138,6 +138,7 @@ __export(src_exports, {
|
|
|
138
138
|
ephInfoToEphemeris: () => ephInfoToEphemeris,
|
|
139
139
|
euclidean3D: () => euclidean3D,
|
|
140
140
|
fetchSourcetable: () => fetchSourcetable,
|
|
141
|
+
fmtD: () => fmtD,
|
|
141
142
|
fmtF: () => fmtF,
|
|
142
143
|
formatUTCTime: () => formatUTCTime,
|
|
143
144
|
frequencyLabel: () => frequencyLabel,
|
|
@@ -222,12 +223,14 @@ __export(src_exports, {
|
|
|
222
223
|
parseNovatelRange: () => parseNovatelRange,
|
|
223
224
|
parseRinexStream: () => parseRinexStream,
|
|
224
225
|
parseSbfAlmanac: () => parseSbfAlmanac,
|
|
226
|
+
parseSbfCnav: () => parseSbfCnav,
|
|
225
227
|
parseSbfIonoUtc: () => parseSbfIonoUtc,
|
|
226
228
|
parseSbfMeas: () => parseSbfMeas,
|
|
227
229
|
parseSbfNav: () => parseSbfNav,
|
|
228
230
|
parseSinexBiasDcb: () => parseSinexBiasDcb,
|
|
229
231
|
parseSourcetable: () => parseSourcetable,
|
|
230
232
|
parseSp3: () => parseSp3,
|
|
233
|
+
parseUbxCnav: () => parseUbxCnav,
|
|
231
234
|
parseUbxIonoUtc: () => parseUbxIonoUtc,
|
|
232
235
|
parseUbxNav: () => parseUbxNav,
|
|
233
236
|
parseUbxRawx: () => parseUbxRawx,
|
|
@@ -263,6 +266,7 @@ __export(src_exports, {
|
|
|
263
266
|
writeRinex2ObsBlob: () => writeRinex2ObsBlob,
|
|
264
267
|
writeRinex4ObsBlob: () => writeRinex4ObsBlob,
|
|
265
268
|
writeRinexNav: () => writeRinexNav,
|
|
269
|
+
writeRinexNav4: () => writeRinexNav4,
|
|
266
270
|
writeRinexObsBlob: () => writeRinexObsBlob
|
|
267
271
|
});
|
|
268
272
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -2183,6 +2187,343 @@ var WarningAccumulator = class {
|
|
|
2183
2187
|
}
|
|
2184
2188
|
};
|
|
2185
2189
|
|
|
2190
|
+
// src/navbits/index.ts
|
|
2191
|
+
var GPS_PI = 3.1415926535898;
|
|
2192
|
+
var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
|
|
2193
|
+
var SEC_PER_WEEK = 7 * 86400;
|
|
2194
|
+
function getBitU(buff, pos, len) {
|
|
2195
|
+
let bits = 0;
|
|
2196
|
+
for (let i = pos; i < pos + len; i++) {
|
|
2197
|
+
bits = bits * 2 + (buff[i >> 3] >> 7 - (i & 7) & 1);
|
|
2198
|
+
}
|
|
2199
|
+
return bits;
|
|
2200
|
+
}
|
|
2201
|
+
function getBitS(buff, pos, len) {
|
|
2202
|
+
const bits = getBitU(buff, pos, len);
|
|
2203
|
+
if (len <= 0 || bits < 2 ** (len - 1)) return bits;
|
|
2204
|
+
return bits - 2 ** len;
|
|
2205
|
+
}
|
|
2206
|
+
function setBitU(buff, pos, len, data) {
|
|
2207
|
+
let mask = 2 ** (len - 1);
|
|
2208
|
+
for (let i = pos; i < pos + len; i++, mask /= 2) {
|
|
2209
|
+
if (data >= mask) {
|
|
2210
|
+
buff[i >> 3] |= 1 << 7 - (i & 7);
|
|
2211
|
+
data -= mask;
|
|
2212
|
+
} else {
|
|
2213
|
+
buff[i >> 3] &= ~(1 << 7 - (i & 7));
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
function decodeGpsLnavFrame(subframes, opts = {}) {
|
|
2218
|
+
if (subframes.length < 90) return null;
|
|
2219
|
+
const b = subframes;
|
|
2220
|
+
let i = 24;
|
|
2221
|
+
const tow1 = getBitU(b, i, 17) * 6;
|
|
2222
|
+
i += 17 + 2;
|
|
2223
|
+
const id1 = getBitU(b, i, 3);
|
|
2224
|
+
i += 3 + 2;
|
|
2225
|
+
const week10 = getBitU(b, i, 10);
|
|
2226
|
+
i += 10;
|
|
2227
|
+
i += 2;
|
|
2228
|
+
i += 4;
|
|
2229
|
+
const svHealth = getBitU(b, i, 6);
|
|
2230
|
+
i += 6;
|
|
2231
|
+
const iodc0 = getBitU(b, i, 2);
|
|
2232
|
+
i += 2;
|
|
2233
|
+
i += 1 + 87;
|
|
2234
|
+
const tgdRaw = getBitS(b, i, 8);
|
|
2235
|
+
i += 8;
|
|
2236
|
+
const iodc1 = getBitU(b, i, 8);
|
|
2237
|
+
i += 8;
|
|
2238
|
+
const tocSec = getBitU(b, i, 16) * 16;
|
|
2239
|
+
i += 16;
|
|
2240
|
+
const af2 = getBitS(b, i, 8) * 2 ** -55;
|
|
2241
|
+
i += 8;
|
|
2242
|
+
const af1 = getBitS(b, i, 16) * 2 ** -43;
|
|
2243
|
+
i += 16;
|
|
2244
|
+
const af0 = getBitS(b, i, 22) * 2 ** -31;
|
|
2245
|
+
i = 240 + 24;
|
|
2246
|
+
i += 17 + 2;
|
|
2247
|
+
const id2 = getBitU(b, i, 3);
|
|
2248
|
+
i += 3 + 2;
|
|
2249
|
+
const iode = getBitU(b, i, 8);
|
|
2250
|
+
i += 8;
|
|
2251
|
+
const crs = getBitS(b, i, 16) * 2 ** -5;
|
|
2252
|
+
i += 16;
|
|
2253
|
+
const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
|
|
2254
|
+
i += 16;
|
|
2255
|
+
const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
2256
|
+
i += 32;
|
|
2257
|
+
const cuc = getBitS(b, i, 16) * 2 ** -29;
|
|
2258
|
+
i += 16;
|
|
2259
|
+
const e = getBitU(b, i, 32) * 2 ** -33;
|
|
2260
|
+
i += 32;
|
|
2261
|
+
const cus = getBitS(b, i, 16) * 2 ** -29;
|
|
2262
|
+
i += 16;
|
|
2263
|
+
const sqrtA = getBitU(b, i, 32) * 2 ** -19;
|
|
2264
|
+
i += 32;
|
|
2265
|
+
const toes = getBitU(b, i, 16) * 16;
|
|
2266
|
+
i = 480 + 24;
|
|
2267
|
+
i += 17 + 2;
|
|
2268
|
+
const id3 = getBitU(b, i, 3);
|
|
2269
|
+
i += 3 + 2;
|
|
2270
|
+
const cic = getBitS(b, i, 16) * 2 ** -29;
|
|
2271
|
+
i += 16;
|
|
2272
|
+
const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
2273
|
+
i += 32;
|
|
2274
|
+
const cis = getBitS(b, i, 16) * 2 ** -29;
|
|
2275
|
+
i += 16;
|
|
2276
|
+
const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
2277
|
+
i += 32;
|
|
2278
|
+
const crc = getBitS(b, i, 16) * 2 ** -5;
|
|
2279
|
+
i += 16;
|
|
2280
|
+
const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
2281
|
+
i += 32;
|
|
2282
|
+
const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
|
|
2283
|
+
i += 24;
|
|
2284
|
+
const iode3 = getBitU(b, i, 8);
|
|
2285
|
+
i += 8;
|
|
2286
|
+
const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
|
|
2287
|
+
const iodc = iodc0 * 256 + iodc1;
|
|
2288
|
+
if (id1 !== 1 || id2 !== 2 || id3 !== 3) return null;
|
|
2289
|
+
if (iode3 !== iode || iode !== (iodc & 255)) return null;
|
|
2290
|
+
const ref = opts.refWeek ?? Math.floor((Date.now() - GPS_EPOCH_MS) / 1e3 / SEC_PER_WEEK);
|
|
2291
|
+
let week = week10 + 1024 * Math.round((ref - week10) / 1024);
|
|
2292
|
+
if (toes < tow1 - 302400) week++;
|
|
2293
|
+
else if (toes > tow1 + 302400) week--;
|
|
2294
|
+
const prn = opts.prn ?? "G00";
|
|
2295
|
+
const tocDate = new Date(
|
|
2296
|
+
GPS_EPOCH_MS + (week * SEC_PER_WEEK + tocSec) * 1e3
|
|
2297
|
+
);
|
|
2298
|
+
return {
|
|
2299
|
+
system: prn[0] === "J" ? "J" : "G",
|
|
2300
|
+
prn,
|
|
2301
|
+
tocDate,
|
|
2302
|
+
// Same seconds-of-week convention as parseNavFile (rinex/nav.ts).
|
|
2303
|
+
toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK,
|
|
2304
|
+
af0,
|
|
2305
|
+
af1,
|
|
2306
|
+
af2,
|
|
2307
|
+
iode,
|
|
2308
|
+
crs,
|
|
2309
|
+
deltaN,
|
|
2310
|
+
m0,
|
|
2311
|
+
cuc,
|
|
2312
|
+
e,
|
|
2313
|
+
cus,
|
|
2314
|
+
sqrtA,
|
|
2315
|
+
toe: toes,
|
|
2316
|
+
cic,
|
|
2317
|
+
omega0,
|
|
2318
|
+
cis,
|
|
2319
|
+
i0,
|
|
2320
|
+
crc,
|
|
2321
|
+
omega,
|
|
2322
|
+
omegaDot,
|
|
2323
|
+
idot,
|
|
2324
|
+
week,
|
|
2325
|
+
svHealth,
|
|
2326
|
+
tgd: tgdRaw === -128 ? 0 : tgdRaw * 2 ** -31
|
|
2327
|
+
// IS-GPS-200: -128 reserved
|
|
2328
|
+
};
|
|
2329
|
+
}
|
|
2330
|
+
|
|
2331
|
+
// src/navbits/cnav.ts
|
|
2332
|
+
var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
|
|
2333
|
+
var SEC_PER_WEEK2 = 7 * 86400;
|
|
2334
|
+
var HALF_WEEK = 302400;
|
|
2335
|
+
var CNAV_PREAMBLE = 139;
|
|
2336
|
+
var CNAV_A_REF = 26559710;
|
|
2337
|
+
var CNAV_OMEGA_DOT_REF = -26e-10;
|
|
2338
|
+
function crc24q(buff, bitLen) {
|
|
2339
|
+
let crc = 0;
|
|
2340
|
+
for (let i = 0; i < bitLen; i++) {
|
|
2341
|
+
crc ^= (buff[i >> 3] >> 7 - (i & 7) & 1) << 23;
|
|
2342
|
+
const msb = crc & 8388608;
|
|
2343
|
+
crc = crc << 1 & 16777215;
|
|
2344
|
+
if (msb) crc ^= 8801531;
|
|
2345
|
+
}
|
|
2346
|
+
return crc;
|
|
2347
|
+
}
|
|
2348
|
+
function cnavCrcOk(msg) {
|
|
2349
|
+
if (msg.length < 38) return false;
|
|
2350
|
+
return crc24q(msg, 276) === getBitU(msg, 276, 24);
|
|
2351
|
+
}
|
|
2352
|
+
function getBitU33(b, pos) {
|
|
2353
|
+
return getBitU(b, pos, 1) * 2 ** 32 + getBitU(b, pos + 1, 32);
|
|
2354
|
+
}
|
|
2355
|
+
function getBitS33(b, pos) {
|
|
2356
|
+
const u = getBitU33(b, pos);
|
|
2357
|
+
return u < 2 ** 32 ? u : u - 2 ** 33;
|
|
2358
|
+
}
|
|
2359
|
+
function decodeType10(b, tow) {
|
|
2360
|
+
return {
|
|
2361
|
+
tow,
|
|
2362
|
+
week: getBitU(b, 38, 13),
|
|
2363
|
+
health: getBitU(b, 51, 3),
|
|
2364
|
+
top: getBitU(b, 54, 11) * 300,
|
|
2365
|
+
uraEd: getBitS(b, 65, 5),
|
|
2366
|
+
toe: getBitU(b, 70, 11) * 300,
|
|
2367
|
+
deltaA: getBitS(b, 81, 26) * 2 ** -9,
|
|
2368
|
+
aDot: getBitS(b, 107, 25) * 2 ** -21,
|
|
2369
|
+
deltaN0: getBitS(b, 132, 17) * 2 ** -44 * GPS_PI,
|
|
2370
|
+
deltaN0Dot: getBitS(b, 149, 23) * 2 ** -57 * GPS_PI,
|
|
2371
|
+
m0: getBitS33(b, 172) * 2 ** -32 * GPS_PI,
|
|
2372
|
+
e: getBitU33(b, 205) * 2 ** -34,
|
|
2373
|
+
omega: getBitS33(b, 238) * 2 ** -32 * GPS_PI,
|
|
2374
|
+
integrityFlag: getBitU(b, 271, 1) === 1,
|
|
2375
|
+
l2cPhasing: getBitU(b, 272, 1) === 1
|
|
2376
|
+
};
|
|
2377
|
+
}
|
|
2378
|
+
function decodeType11(b) {
|
|
2379
|
+
return {
|
|
2380
|
+
toe: getBitU(b, 38, 11) * 300,
|
|
2381
|
+
omega0: getBitS33(b, 49) * 2 ** -32 * GPS_PI,
|
|
2382
|
+
i0: getBitS33(b, 82) * 2 ** -32 * GPS_PI,
|
|
2383
|
+
deltaOmegaDot: getBitS(b, 115, 17) * 2 ** -44 * GPS_PI,
|
|
2384
|
+
i0Dot: getBitS(b, 132, 15) * 2 ** -44 * GPS_PI,
|
|
2385
|
+
cis: getBitS(b, 147, 16) * 2 ** -30,
|
|
2386
|
+
cic: getBitS(b, 163, 16) * 2 ** -30,
|
|
2387
|
+
crs: getBitS(b, 179, 24) * 2 ** -8,
|
|
2388
|
+
crc: getBitS(b, 203, 24) * 2 ** -8,
|
|
2389
|
+
cus: getBitS(b, 227, 21) * 2 ** -30,
|
|
2390
|
+
cuc: getBitS(b, 248, 21) * 2 ** -30
|
|
2391
|
+
};
|
|
2392
|
+
}
|
|
2393
|
+
var isc = (b, pos) => {
|
|
2394
|
+
const raw = getBitS(b, pos, 13);
|
|
2395
|
+
return raw === -4096 ? null : raw * 2 ** -35;
|
|
2396
|
+
};
|
|
2397
|
+
function decodeClock(b, msgType) {
|
|
2398
|
+
const clock = {
|
|
2399
|
+
msgType,
|
|
2400
|
+
top: getBitU(b, 38, 11) * 300,
|
|
2401
|
+
uraNed0: getBitS(b, 49, 5),
|
|
2402
|
+
uraNed1: getBitU(b, 54, 3),
|
|
2403
|
+
uraNed2: getBitU(b, 57, 3),
|
|
2404
|
+
toc: getBitU(b, 60, 11) * 300,
|
|
2405
|
+
af0: getBitS(b, 71, 26) * 2 ** -35,
|
|
2406
|
+
af1: getBitS(b, 97, 20) * 2 ** -48,
|
|
2407
|
+
af2: getBitS(b, 117, 10) * 2 ** -60
|
|
2408
|
+
};
|
|
2409
|
+
if (msgType === 30) {
|
|
2410
|
+
clock.tgd = isc(b, 127);
|
|
2411
|
+
clock.iscL1ca = isc(b, 140);
|
|
2412
|
+
clock.iscL2c = isc(b, 153);
|
|
2413
|
+
clock.iscL5i5 = isc(b, 166);
|
|
2414
|
+
clock.iscL5q5 = isc(b, 179);
|
|
2415
|
+
clock.ionoAlpha = [
|
|
2416
|
+
getBitS(b, 192, 8) * 2 ** -30,
|
|
2417
|
+
getBitS(b, 200, 8) * 2 ** -27,
|
|
2418
|
+
getBitS(b, 208, 8) * 2 ** -24,
|
|
2419
|
+
getBitS(b, 216, 8) * 2 ** -24
|
|
2420
|
+
];
|
|
2421
|
+
clock.ionoBeta = [
|
|
2422
|
+
getBitS(b, 224, 8) * 2 ** 11,
|
|
2423
|
+
getBitS(b, 232, 8) * 2 ** 14,
|
|
2424
|
+
getBitS(b, 240, 8) * 2 ** 16,
|
|
2425
|
+
getBitS(b, 248, 8) * 2 ** 16
|
|
2426
|
+
];
|
|
2427
|
+
clock.wnOp = getBitU(b, 256, 8);
|
|
2428
|
+
}
|
|
2429
|
+
return clock;
|
|
2430
|
+
}
|
|
2431
|
+
function resolveWeek(week, towSec, sec) {
|
|
2432
|
+
if (sec < towSec - HALF_WEEK) return week + 1;
|
|
2433
|
+
if (sec > towSec + HALF_WEEK) return week - 1;
|
|
2434
|
+
return week;
|
|
2435
|
+
}
|
|
2436
|
+
function gpsDate(week, sec) {
|
|
2437
|
+
return new Date(GPS_EPOCH_MS2 + (week * SEC_PER_WEEK2 + sec) * 1e3);
|
|
2438
|
+
}
|
|
2439
|
+
var CnavAssembler = class {
|
|
2440
|
+
sats = /* @__PURE__ */ new Map();
|
|
2441
|
+
/**
|
|
2442
|
+
* Push one 300-bit CNAV message (38+ bytes, bit 0 = first bit of
|
|
2443
|
+
* the preamble). Returns the newly completed ephemeris, or null.
|
|
2444
|
+
* Messages that are not MT10/MT11/MT30-37, or whose preamble/PRN
|
|
2445
|
+
* are out of range, are ignored.
|
|
2446
|
+
*/
|
|
2447
|
+
push(msg) {
|
|
2448
|
+
if (msg.length < 38 || getBitU(msg, 0, 8) !== CNAV_PREAMBLE) return null;
|
|
2449
|
+
const prn = getBitU(msg, 8, 6);
|
|
2450
|
+
if (prn < 1 || prn > 32) return null;
|
|
2451
|
+
const type = getBitU(msg, 14, 6);
|
|
2452
|
+
const tow = getBitU(msg, 20, 17) * 6;
|
|
2453
|
+
let sat = this.sats.get(prn);
|
|
2454
|
+
if (!sat) {
|
|
2455
|
+
sat = {};
|
|
2456
|
+
this.sats.set(prn, sat);
|
|
2457
|
+
}
|
|
2458
|
+
if (type === 10) sat.t10 = decodeType10(msg, tow);
|
|
2459
|
+
else if (type === 11) sat.t11 = decodeType11(msg);
|
|
2460
|
+
else if (type >= 30 && type <= 37) {
|
|
2461
|
+
sat.clock = decodeClock(msg, type);
|
|
2462
|
+
if (type === 30) sat.extras = sat.clock;
|
|
2463
|
+
} else return null;
|
|
2464
|
+
return this.tryEmit(prn, sat);
|
|
2465
|
+
}
|
|
2466
|
+
tryEmit(prn, sat) {
|
|
2467
|
+
const { t10, t11, clock, extras } = sat;
|
|
2468
|
+
if (!t10 || !t11 || !clock) return null;
|
|
2469
|
+
if (t10.toe !== t11.toe || clock.toc !== t10.toe) return null;
|
|
2470
|
+
const key = `${t10.week}:${t10.toe}:${clock.af0}:${clock.af1}`;
|
|
2471
|
+
if (key === sat.lastKey) return null;
|
|
2472
|
+
sat.lastKey = key;
|
|
2473
|
+
const weekToe = resolveWeek(t10.week, t10.tow, t10.toe);
|
|
2474
|
+
const a = CNAV_A_REF + t10.deltaA;
|
|
2475
|
+
return {
|
|
2476
|
+
system: "G",
|
|
2477
|
+
prn: `G${String(prn).padStart(2, "0")}`,
|
|
2478
|
+
week: t10.week,
|
|
2479
|
+
health: t10.health,
|
|
2480
|
+
uraEd: t10.uraEd,
|
|
2481
|
+
uraNed0: clock.uraNed0,
|
|
2482
|
+
uraNed1: clock.uraNed1,
|
|
2483
|
+
uraNed2: clock.uraNed2,
|
|
2484
|
+
top: t10.top,
|
|
2485
|
+
toe: t10.toe,
|
|
2486
|
+
toeDate: gpsDate(weekToe, t10.toe),
|
|
2487
|
+
a,
|
|
2488
|
+
deltaA: t10.deltaA,
|
|
2489
|
+
aDot: t10.aDot,
|
|
2490
|
+
deltaN0: t10.deltaN0,
|
|
2491
|
+
deltaN0Dot: t10.deltaN0Dot,
|
|
2492
|
+
m0: t10.m0,
|
|
2493
|
+
e: t10.e,
|
|
2494
|
+
omega: t10.omega,
|
|
2495
|
+
omega0: t11.omega0,
|
|
2496
|
+
i0: t11.i0,
|
|
2497
|
+
omegaDot: CNAV_OMEGA_DOT_REF * GPS_PI + t11.deltaOmegaDot,
|
|
2498
|
+
deltaOmegaDot: t11.deltaOmegaDot,
|
|
2499
|
+
i0Dot: t11.i0Dot,
|
|
2500
|
+
cis: t11.cis,
|
|
2501
|
+
cic: t11.cic,
|
|
2502
|
+
crs: t11.crs,
|
|
2503
|
+
crc: t11.crc,
|
|
2504
|
+
cus: t11.cus,
|
|
2505
|
+
cuc: t11.cuc,
|
|
2506
|
+
toc: clock.toc,
|
|
2507
|
+
tocDate: gpsDate(weekToe, clock.toc),
|
|
2508
|
+
af0: clock.af0,
|
|
2509
|
+
af1: clock.af1,
|
|
2510
|
+
af2: clock.af2,
|
|
2511
|
+
clockMsgType: clock.msgType,
|
|
2512
|
+
tgd: extras?.tgd ?? null,
|
|
2513
|
+
iscL1ca: extras?.iscL1ca ?? null,
|
|
2514
|
+
iscL2c: extras?.iscL2c ?? null,
|
|
2515
|
+
iscL5i5: extras?.iscL5i5 ?? null,
|
|
2516
|
+
iscL5q5: extras?.iscL5q5 ?? null,
|
|
2517
|
+
...extras?.ionoAlpha && { ionoAlpha: extras.ionoAlpha },
|
|
2518
|
+
...extras?.ionoBeta && { ionoBeta: extras.ionoBeta },
|
|
2519
|
+
...extras?.wnOp !== void 0 && { wnOp: extras.wnOp },
|
|
2520
|
+
integrityFlag: t10.integrityFlag,
|
|
2521
|
+
l2cPhasing: t10.l2cPhasing,
|
|
2522
|
+
tow: t10.tow
|
|
2523
|
+
};
|
|
2524
|
+
}
|
|
2525
|
+
};
|
|
2526
|
+
|
|
2186
2527
|
// src/rinex/nav.ts
|
|
2187
2528
|
var DATA_LINES = {
|
|
2188
2529
|
G: 7,
|
|
@@ -2206,19 +2547,19 @@ var R4_MSG_LINES = {
|
|
|
2206
2547
|
SBAS: 4,
|
|
2207
2548
|
FDMA: 5,
|
|
2208
2549
|
// RINEX 4 adds orbit-4 (status flags) vs 3 in RINEX 3
|
|
2209
|
-
// EPH
|
|
2550
|
+
// EPH type parsed into RinexCnavEphemeris for G/J (skipped otherwise)
|
|
2210
2551
|
CNAV: 9,
|
|
2552
|
+
// EPH types we skip (different field layout)
|
|
2211
2553
|
CNV1: 10,
|
|
2212
2554
|
CNV2: 10,
|
|
2213
2555
|
CNV3: 9,
|
|
2214
2556
|
L1NV: 8,
|
|
2215
2557
|
L1OC: 9,
|
|
2216
|
-
L3OC: 9
|
|
2217
|
-
// Non-EPH records
|
|
2218
|
-
STO: 2,
|
|
2219
|
-
EOP: 3,
|
|
2220
|
-
ION: 3
|
|
2558
|
+
L3OC: 9
|
|
2221
2559
|
};
|
|
2560
|
+
var GPS_EPOCH_MS3 = Date.UTC(1980, 0, 6);
|
|
2561
|
+
var SEC_PER_WEEK3 = 7 * 86400;
|
|
2562
|
+
var QZSS_CNAV_A_REF = 42164200;
|
|
2222
2563
|
var SUPPORTED_EPH_MSGS = /* @__PURE__ */ new Set([
|
|
2223
2564
|
"LNAV",
|
|
2224
2565
|
"INAV",
|
|
@@ -2282,6 +2623,20 @@ function parseDataLine(line, colOffset = 4) {
|
|
|
2282
2623
|
}
|
|
2283
2624
|
return values;
|
|
2284
2625
|
}
|
|
2626
|
+
function parseDataLineSlots(line) {
|
|
2627
|
+
const values = [];
|
|
2628
|
+
for (let i = 0; i < 4; i++) {
|
|
2629
|
+
const start = 4 + i * 19;
|
|
2630
|
+
const s = start < line.length ? line.substring(start, start + 19).trim() : "";
|
|
2631
|
+
if (s.length === 0) {
|
|
2632
|
+
values.push(null);
|
|
2633
|
+
continue;
|
|
2634
|
+
}
|
|
2635
|
+
const v = parseFloat19(s);
|
|
2636
|
+
values.push(Number.isFinite(v) ? v : null);
|
|
2637
|
+
}
|
|
2638
|
+
return values;
|
|
2639
|
+
}
|
|
2285
2640
|
function buildKeplerEphemeris(sys, prn, date, epochVals, data) {
|
|
2286
2641
|
const d = [];
|
|
2287
2642
|
for (const line of data) {
|
|
@@ -2344,6 +2699,68 @@ function buildStateVectorEphemeris(sys, prn, date, epochVals, data) {
|
|
|
2344
2699
|
zAcc: d[10] ?? 0
|
|
2345
2700
|
};
|
|
2346
2701
|
}
|
|
2702
|
+
function buildCnavEphemeris(sys, prn, date, epochVals, d) {
|
|
2703
|
+
const num = (r, c) => d[r]?.[c] ?? 0;
|
|
2704
|
+
const opt = (r, c) => d[r]?.[c] ?? null;
|
|
2705
|
+
const t = (date.getTime() - GPS_EPOCH_MS3) / 1e3;
|
|
2706
|
+
const week = Math.floor(t / SEC_PER_WEEK3);
|
|
2707
|
+
const toc = t - week * SEC_PER_WEEK3;
|
|
2708
|
+
const sqrtA = num(1, 3);
|
|
2709
|
+
const a = sqrtA * sqrtA;
|
|
2710
|
+
const aRef = sys === "J" ? QZSS_CNAV_A_REF : CNAV_A_REF;
|
|
2711
|
+
const omegaDot = num(3, 3);
|
|
2712
|
+
const wnOp = d[7]?.[1];
|
|
2713
|
+
return {
|
|
2714
|
+
system: sys,
|
|
2715
|
+
prn,
|
|
2716
|
+
week,
|
|
2717
|
+
health: num(5, 1),
|
|
2718
|
+
uraEd: num(5, 0),
|
|
2719
|
+
uraNed0: num(4, 2),
|
|
2720
|
+
uraNed1: num(4, 3),
|
|
2721
|
+
uraNed2: num(5, 3),
|
|
2722
|
+
top: num(2, 0),
|
|
2723
|
+
toe: toc,
|
|
2724
|
+
toeDate: date,
|
|
2725
|
+
a,
|
|
2726
|
+
deltaA: a - aRef,
|
|
2727
|
+
aDot: num(0, 0),
|
|
2728
|
+
deltaN0: num(0, 2),
|
|
2729
|
+
deltaN0Dot: num(4, 1),
|
|
2730
|
+
m0: num(0, 3),
|
|
2731
|
+
e: num(1, 1),
|
|
2732
|
+
omega: num(3, 2),
|
|
2733
|
+
omega0: num(2, 2),
|
|
2734
|
+
i0: num(3, 0),
|
|
2735
|
+
omegaDot,
|
|
2736
|
+
deltaOmegaDot: omegaDot - CNAV_OMEGA_DOT_REF * GPS_PI,
|
|
2737
|
+
i0Dot: num(4, 0),
|
|
2738
|
+
cis: num(2, 3),
|
|
2739
|
+
cic: num(2, 1),
|
|
2740
|
+
crs: num(0, 1),
|
|
2741
|
+
crc: num(3, 1),
|
|
2742
|
+
cus: num(1, 2),
|
|
2743
|
+
cuc: num(1, 0),
|
|
2744
|
+
toc,
|
|
2745
|
+
tocDate: date,
|
|
2746
|
+
af0: epochVals[0] ?? 0,
|
|
2747
|
+
af1: epochVals[1] ?? 0,
|
|
2748
|
+
af2: epochVals[2] ?? 0,
|
|
2749
|
+
clockMsgType: 0,
|
|
2750
|
+
// not recorded in RINEX
|
|
2751
|
+
tgd: opt(5, 2),
|
|
2752
|
+
iscL1ca: opt(6, 0),
|
|
2753
|
+
iscL2c: opt(6, 1),
|
|
2754
|
+
iscL5i5: opt(6, 2),
|
|
2755
|
+
iscL5q5: opt(6, 3),
|
|
2756
|
+
...wnOp != null && { wnOp },
|
|
2757
|
+
integrityFlag: false,
|
|
2758
|
+
// not recorded in RINEX
|
|
2759
|
+
l2cPhasing: false,
|
|
2760
|
+
// not recorded in RINEX
|
|
2761
|
+
tow: num(7, 0)
|
|
2762
|
+
};
|
|
2763
|
+
}
|
|
2347
2764
|
function parseNavFile(text) {
|
|
2348
2765
|
const lines = text.split("\n");
|
|
2349
2766
|
const header = {
|
|
@@ -2353,6 +2770,7 @@ function parseNavFile(text) {
|
|
|
2353
2770
|
ionoCorrections: {}
|
|
2354
2771
|
};
|
|
2355
2772
|
const ephemerides = [];
|
|
2773
|
+
const cnav = [];
|
|
2356
2774
|
let inHeader = true;
|
|
2357
2775
|
let i = 0;
|
|
2358
2776
|
while (i < lines.length) {
|
|
@@ -2413,8 +2831,15 @@ function parseNavFile(text) {
|
|
|
2413
2831
|
if (isV4 && line.charAt(0) === ">") {
|
|
2414
2832
|
const parts = line.substring(2).trim().split(/\s+/);
|
|
2415
2833
|
const recType = parts[0] ?? "";
|
|
2834
|
+
const svSys = (parts[1] ?? "").charAt(0);
|
|
2416
2835
|
const msgType = parts[2] ?? recType;
|
|
2417
|
-
if (recType !== "EPH"
|
|
2836
|
+
if (recType !== "EPH") {
|
|
2837
|
+
const totalLines = recType === "STO" ? 2 : recType === "EOP" ? 3 : recType === "ION" ? svSys === "E" ? 2 : 3 : 2;
|
|
2838
|
+
i += totalLines + 1;
|
|
2839
|
+
continue;
|
|
2840
|
+
}
|
|
2841
|
+
const isCnav = msgType === "CNAV" && (svSys === "G" || svSys === "J");
|
|
2842
|
+
if (!SUPPORTED_EPH_MSGS.has(msgType) && !isCnav) {
|
|
2418
2843
|
const totalLines = R4_MSG_LINES[msgType] ?? 2;
|
|
2419
2844
|
i += totalLines + 1;
|
|
2420
2845
|
continue;
|
|
@@ -2426,6 +2851,21 @@ function parseNavFile(text) {
|
|
|
2426
2851
|
const sys2 = epochLine.charAt(0);
|
|
2427
2852
|
const parsed = parseNavEpochV3(epochLine);
|
|
2428
2853
|
const prn2 = `${sys2}${parsed.prn.substring(1)}`;
|
|
2854
|
+
if (isCnav) {
|
|
2855
|
+
const slotLines = [];
|
|
2856
|
+
for (let j = 0; j < numDataLines2; j++) {
|
|
2857
|
+
i++;
|
|
2858
|
+
if (i >= lines.length) break;
|
|
2859
|
+
slotLines.push(parseDataLineSlots(lines[i]));
|
|
2860
|
+
}
|
|
2861
|
+
if (slotLines.length === numDataLines2 && (sys2 === "G" || sys2 === "J")) {
|
|
2862
|
+
cnav.push(
|
|
2863
|
+
buildCnavEphemeris(sys2, prn2, parsed.date, parsed.values, slotLines)
|
|
2864
|
+
);
|
|
2865
|
+
}
|
|
2866
|
+
i++;
|
|
2867
|
+
continue;
|
|
2868
|
+
}
|
|
2429
2869
|
const dataLines2 = [];
|
|
2430
2870
|
for (let j = 0; j < numDataLines2; j++) {
|
|
2431
2871
|
i++;
|
|
@@ -2499,7 +2939,7 @@ function parseNavFile(text) {
|
|
|
2499
2939
|
}
|
|
2500
2940
|
i++;
|
|
2501
2941
|
}
|
|
2502
|
-
return { header, ephemerides };
|
|
2942
|
+
return cnav.length > 0 ? { header, ephemerides, cnav } : { header, ephemerides };
|
|
2503
2943
|
}
|
|
2504
2944
|
|
|
2505
2945
|
// src/rinex/nav-writer.ts
|
|
@@ -2507,9 +2947,13 @@ function fmtD(val) {
|
|
|
2507
2947
|
if (val === 0) return " 0.000000000000E+00";
|
|
2508
2948
|
const sign = val < 0 ? "-" : " ";
|
|
2509
2949
|
const abs = Math.abs(val);
|
|
2510
|
-
|
|
2950
|
+
let exp = Math.floor(Math.log10(abs));
|
|
2511
2951
|
const mantissa = abs / 10 ** exp;
|
|
2512
|
-
|
|
2952
|
+
let mStr = mantissa.toFixed(12);
|
|
2953
|
+
if (mStr.length > 14) {
|
|
2954
|
+
exp += 1;
|
|
2955
|
+
mStr = (mantissa / 10).toFixed(12);
|
|
2956
|
+
}
|
|
2513
2957
|
const expSign = exp >= 0 ? "+" : "-";
|
|
2514
2958
|
const expStr = String(Math.abs(exp)).padStart(2, "0");
|
|
2515
2959
|
return `${sign}${mStr}E${expSign}${expStr}`;
|
|
@@ -2584,7 +3028,7 @@ function writeKeplerRecord(eph) {
|
|
|
2584
3028
|
function writeGlonassRecord(eph) {
|
|
2585
3029
|
const lines = [];
|
|
2586
3030
|
lines.push(
|
|
2587
|
-
`${padL(eph.prn, 3)} ${fmtEpoch(eph.tocDate)}${fmtD(
|
|
3031
|
+
`${padL(eph.prn, 3)} ${fmtEpoch(eph.tocDate)}${fmtD(eph.tauN)}${fmtD(eph.gammaN)}${fmtD(eph.messageFrameTime)}`
|
|
2588
3032
|
);
|
|
2589
3033
|
lines.push(orbitLine([eph.x, eph.xDot, eph.xAcc, eph.health]));
|
|
2590
3034
|
lines.push(orbitLine([eph.y, eph.yDot, eph.yAcc, eph.freqNum]));
|
|
@@ -2604,6 +3048,181 @@ function writeRinexNav(nav) {
|
|
|
2604
3048
|
return header + records.join("\n") + "\n";
|
|
2605
3049
|
}
|
|
2606
3050
|
|
|
3051
|
+
// src/rinex/nav-writer-v4.ts
|
|
3052
|
+
var BLANK19 = " ".repeat(19);
|
|
3053
|
+
function fmtEpoch4(d) {
|
|
3054
|
+
const p2 = (v) => String(v).padStart(2, "0");
|
|
3055
|
+
return `${d.getUTCFullYear()} ${p2(d.getUTCMonth() + 1)} ${p2(d.getUTCDate())} ${p2(d.getUTCHours())} ${p2(d.getUTCMinutes())} ${p2(d.getUTCSeconds())}`;
|
|
3056
|
+
}
|
|
3057
|
+
function orbitLine4(values) {
|
|
3058
|
+
const line = " " + values.map((v) => v == null ? BLANK19 : fmtD(v)).join("");
|
|
3059
|
+
return line.replace(/ +$/, "");
|
|
3060
|
+
}
|
|
3061
|
+
function epochLine4(prn, date, vals) {
|
|
3062
|
+
return `${padL(prn, 3)} ${fmtEpoch4(date)}${vals.map(fmtD).join("")}`;
|
|
3063
|
+
}
|
|
3064
|
+
var BDS_GEO = /* @__PURE__ */ new Set([
|
|
3065
|
+
"C01",
|
|
3066
|
+
"C02",
|
|
3067
|
+
"C03",
|
|
3068
|
+
"C04",
|
|
3069
|
+
"C05",
|
|
3070
|
+
"C59",
|
|
3071
|
+
"C60",
|
|
3072
|
+
"C61",
|
|
3073
|
+
"C62",
|
|
3074
|
+
"C63"
|
|
3075
|
+
]);
|
|
3076
|
+
function msgLabel(eph) {
|
|
3077
|
+
switch (eph.system) {
|
|
3078
|
+
case "E":
|
|
3079
|
+
return "INAV";
|
|
3080
|
+
case "C":
|
|
3081
|
+
return BDS_GEO.has(eph.prn) ? "D2" : "D1";
|
|
3082
|
+
case "R":
|
|
3083
|
+
return "FDMA";
|
|
3084
|
+
case "S":
|
|
3085
|
+
return "SBAS";
|
|
3086
|
+
default:
|
|
3087
|
+
return "LNAV";
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3090
|
+
function isKepler2(eph) {
|
|
3091
|
+
return "af0" in eph;
|
|
3092
|
+
}
|
|
3093
|
+
function keplerRecord(eph) {
|
|
3094
|
+
return [
|
|
3095
|
+
epochLine4(eph.prn, eph.tocDate, [eph.af0, eph.af1, eph.af2]),
|
|
3096
|
+
orbitLine4([eph.iode, eph.crs, eph.deltaN, eph.m0]),
|
|
3097
|
+
orbitLine4([eph.cuc, eph.e, eph.cus, eph.sqrtA]),
|
|
3098
|
+
orbitLine4([eph.toe, eph.cic, eph.omega0, eph.cis]),
|
|
3099
|
+
orbitLine4([eph.i0, eph.crc, eph.omega, eph.omegaDot]),
|
|
3100
|
+
orbitLine4([eph.idot, 0, eph.week, 0]),
|
|
3101
|
+
orbitLine4([0, eph.svHealth, eph.tgd, 0]),
|
|
3102
|
+
orbitLine4([eph.toe, 0, 0, 0])
|
|
3103
|
+
].join("\n");
|
|
3104
|
+
}
|
|
3105
|
+
function stateVectorRecord(eph) {
|
|
3106
|
+
const lines = [
|
|
3107
|
+
epochLine4(eph.prn, eph.tocDate, [
|
|
3108
|
+
eph.tauN,
|
|
3109
|
+
eph.gammaN,
|
|
3110
|
+
eph.messageFrameTime
|
|
3111
|
+
]),
|
|
3112
|
+
orbitLine4([eph.x, eph.xDot, eph.xAcc, eph.health]),
|
|
3113
|
+
orbitLine4([eph.y, eph.yDot, eph.yAcc, eph.freqNum]),
|
|
3114
|
+
orbitLine4([eph.z, eph.zDot, eph.zAcc, 0])
|
|
3115
|
+
];
|
|
3116
|
+
if (eph.system === "R") {
|
|
3117
|
+
lines.push(orbitLine4([null, 999999999999e-3, 15, null]));
|
|
3118
|
+
}
|
|
3119
|
+
return lines.join("\n");
|
|
3120
|
+
}
|
|
3121
|
+
function resolveWnOp(week, wnOp) {
|
|
3122
|
+
if (wnOp == null) return week;
|
|
3123
|
+
return week - ((week - wnOp) % 256 + 256) % 256;
|
|
3124
|
+
}
|
|
3125
|
+
function cnavRecord(eph) {
|
|
3126
|
+
return [
|
|
3127
|
+
epochLine4(eph.prn, eph.tocDate, [eph.af0, eph.af1, eph.af2]),
|
|
3128
|
+
orbitLine4([eph.aDot, eph.crs, eph.deltaN0, eph.m0]),
|
|
3129
|
+
orbitLine4([eph.cuc, eph.e, eph.cus, Math.sqrt(eph.a)]),
|
|
3130
|
+
orbitLine4([eph.top, eph.cic, eph.omega0, eph.cis]),
|
|
3131
|
+
orbitLine4([eph.i0, eph.crc, eph.omega, eph.omegaDot]),
|
|
3132
|
+
orbitLine4([eph.i0Dot, eph.deltaN0Dot, eph.uraNed0, eph.uraNed1]),
|
|
3133
|
+
orbitLine4([eph.uraEd, eph.health, eph.tgd, eph.uraNed2]),
|
|
3134
|
+
orbitLine4([eph.iscL1ca, eph.iscL2c, eph.iscL5i5, eph.iscL5q5]),
|
|
3135
|
+
orbitLine4([eph.tow, resolveWnOp(eph.week, eph.wnOp)])
|
|
3136
|
+
].join("\n");
|
|
3137
|
+
}
|
|
3138
|
+
var KLOBUCHAR_SOURCES = [
|
|
3139
|
+
["GPSA", "GPSB", "G", "LNAV"],
|
|
3140
|
+
["QZSA", "QZSB", "J", "LNAV"],
|
|
3141
|
+
["BDSA", "BDSB", "C", "D1D2"],
|
|
3142
|
+
["IRNA", "IRNB", "I", "LNAV"]
|
|
3143
|
+
];
|
|
3144
|
+
function ionRecords(header, epoch) {
|
|
3145
|
+
const records = [];
|
|
3146
|
+
const iono = header.ionoCorrections;
|
|
3147
|
+
for (const [alphaKey, betaKey, sys, msg] of KLOBUCHAR_SOURCES) {
|
|
3148
|
+
const alpha = iono[alphaKey];
|
|
3149
|
+
if (!alpha) continue;
|
|
3150
|
+
const beta = iono[betaKey] ?? [0, 0, 0, 0];
|
|
3151
|
+
records.push(
|
|
3152
|
+
[
|
|
3153
|
+
`> ION ${sys} ${msg}`,
|
|
3154
|
+
` ${fmtEpoch4(epoch)}${[alpha[0] ?? 0, alpha[1] ?? 0, alpha[2] ?? 0].map(fmtD).join("")}`,
|
|
3155
|
+
orbitLine4([alpha[3] ?? 0, beta[0] ?? 0, beta[1] ?? 0, beta[2] ?? 0]),
|
|
3156
|
+
orbitLine4([beta[3] ?? 0, null])
|
|
3157
|
+
].join("\n")
|
|
3158
|
+
);
|
|
3159
|
+
}
|
|
3160
|
+
const gal = iono["GAL"];
|
|
3161
|
+
if (gal) {
|
|
3162
|
+
records.push(
|
|
3163
|
+
[
|
|
3164
|
+
"> ION E IFNV",
|
|
3165
|
+
` ${fmtEpoch4(epoch)}${[gal[0] ?? 0, gal[1] ?? 0, gal[2] ?? 0].map(fmtD).join("")}`,
|
|
3166
|
+
orbitLine4([gal[3] ?? 0])
|
|
3167
|
+
].join("\n")
|
|
3168
|
+
);
|
|
3169
|
+
}
|
|
3170
|
+
return records;
|
|
3171
|
+
}
|
|
3172
|
+
function writeHeader4(header) {
|
|
3173
|
+
const lines = [];
|
|
3174
|
+
lines.push(
|
|
3175
|
+
hdrLine(
|
|
3176
|
+
padL(" 4.01", 9) + " " + padL("NAVIGATION DATA", 20) + padL("M", 20),
|
|
3177
|
+
"RINEX VERSION / TYPE"
|
|
3178
|
+
)
|
|
3179
|
+
);
|
|
3180
|
+
const now = /* @__PURE__ */ new Date();
|
|
3181
|
+
const dateStr = now.getUTCFullYear().toString() + String(now.getUTCMonth() + 1).padStart(2, "0") + String(now.getUTCDate()).padStart(2, "0") + " " + String(now.getUTCHours()).padStart(2, "0") + String(now.getUTCMinutes()).padStart(2, "0") + String(now.getUTCSeconds()).padStart(2, "0") + " UTC";
|
|
3182
|
+
lines.push(
|
|
3183
|
+
hdrLine(
|
|
3184
|
+
padL("GNSSCalc", 20) + padL("", 20) + padL(dateStr, 20),
|
|
3185
|
+
"PGM / RUN BY / DATE"
|
|
3186
|
+
)
|
|
3187
|
+
);
|
|
3188
|
+
if (header.leapSeconds != null) {
|
|
3189
|
+
lines.push(hdrLine(padR(String(header.leapSeconds), 6), "LEAP SECONDS"));
|
|
3190
|
+
}
|
|
3191
|
+
lines.push(hdrLine("", "END OF HEADER"));
|
|
3192
|
+
return lines.join("\n") + "\n";
|
|
3193
|
+
}
|
|
3194
|
+
function writeRinexNav4(nav) {
|
|
3195
|
+
const records = [];
|
|
3196
|
+
for (const eph of nav.ephemerides) {
|
|
3197
|
+
const label2 = msgLabel(eph);
|
|
3198
|
+
records.push({
|
|
3199
|
+
prn: eph.prn,
|
|
3200
|
+
time: eph.tocDate.getTime(),
|
|
3201
|
+
label: label2,
|
|
3202
|
+
body: `> EPH ${padL(eph.prn, 3)} ${label2}
|
|
3203
|
+
` + (isKepler2(eph) ? keplerRecord(eph) : stateVectorRecord(eph))
|
|
3204
|
+
});
|
|
3205
|
+
}
|
|
3206
|
+
for (const eph of nav.cnav ?? []) {
|
|
3207
|
+
records.push({
|
|
3208
|
+
prn: eph.prn,
|
|
3209
|
+
time: eph.tocDate.getTime(),
|
|
3210
|
+
label: "CNAV",
|
|
3211
|
+
body: `> EPH ${padL(eph.prn, 3)} CNAV
|
|
3212
|
+
` + cnavRecord(eph)
|
|
3213
|
+
});
|
|
3214
|
+
}
|
|
3215
|
+
records.sort(
|
|
3216
|
+
(a, b) => a.prn.localeCompare(b.prn) || a.time - b.time || a.label.localeCompare(b.label)
|
|
3217
|
+
);
|
|
3218
|
+
const bodies = records.map((r) => r.body);
|
|
3219
|
+
if (records.length > 0) {
|
|
3220
|
+
const earliest = new Date(Math.min(...records.map((r) => r.time)));
|
|
3221
|
+
bodies.push(...ionRecords(nav.header, earliest));
|
|
3222
|
+
}
|
|
3223
|
+
return writeHeader4(nav.header) + (bodies.length > 0 ? bodies.join("\n") + "\n" : "");
|
|
3224
|
+
}
|
|
3225
|
+
|
|
2607
3226
|
// src/rinex/ionex.ts
|
|
2608
3227
|
function gridRange(l1, l2, dl) {
|
|
2609
3228
|
const out = [];
|
|
@@ -3227,7 +3846,7 @@ var BitReader = class {
|
|
|
3227
3846
|
return this.data.length * 8 - this.bitPos;
|
|
3228
3847
|
}
|
|
3229
3848
|
};
|
|
3230
|
-
function
|
|
3849
|
+
function crc24q2(data, length) {
|
|
3231
3850
|
let crc = 0;
|
|
3232
3851
|
for (let i = 0; i < length; i++) {
|
|
3233
3852
|
crc ^= data[i] << 16;
|
|
@@ -3269,7 +3888,7 @@ var Rtcm3Decoder = class {
|
|
|
3269
3888
|
}
|
|
3270
3889
|
const frameSize = 3 + length + 3;
|
|
3271
3890
|
if (this.buffer.length < frameSize) break;
|
|
3272
|
-
const crcComputed =
|
|
3891
|
+
const crcComputed = crc24q2(this.buffer, 3 + length);
|
|
3273
3892
|
const crcReceived = this.buffer[3 + length] << 16 | this.buffer[3 + length + 1] << 8 | this.buffer[3 + length + 2];
|
|
3274
3893
|
if (crcComputed !== crcReceived) {
|
|
3275
3894
|
this.buffer = this.buffer.slice(1);
|
|
@@ -4636,147 +5255,6 @@ function* ubxFrames(data, stats = { badChecksums: 0 }) {
|
|
|
4636
5255
|
}
|
|
4637
5256
|
}
|
|
4638
5257
|
|
|
4639
|
-
// src/navbits/index.ts
|
|
4640
|
-
var GPS_PI = 3.1415926535898;
|
|
4641
|
-
var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
|
|
4642
|
-
var SEC_PER_WEEK = 7 * 86400;
|
|
4643
|
-
function getBitU(buff, pos, len) {
|
|
4644
|
-
let bits = 0;
|
|
4645
|
-
for (let i = pos; i < pos + len; i++) {
|
|
4646
|
-
bits = bits * 2 + (buff[i >> 3] >> 7 - (i & 7) & 1);
|
|
4647
|
-
}
|
|
4648
|
-
return bits;
|
|
4649
|
-
}
|
|
4650
|
-
function getBitS(buff, pos, len) {
|
|
4651
|
-
const bits = getBitU(buff, pos, len);
|
|
4652
|
-
if (len <= 0 || bits < 2 ** (len - 1)) return bits;
|
|
4653
|
-
return bits - 2 ** len;
|
|
4654
|
-
}
|
|
4655
|
-
function setBitU(buff, pos, len, data) {
|
|
4656
|
-
let mask = 2 ** (len - 1);
|
|
4657
|
-
for (let i = pos; i < pos + len; i++, mask /= 2) {
|
|
4658
|
-
if (data >= mask) {
|
|
4659
|
-
buff[i >> 3] |= 1 << 7 - (i & 7);
|
|
4660
|
-
data -= mask;
|
|
4661
|
-
} else {
|
|
4662
|
-
buff[i >> 3] &= ~(1 << 7 - (i & 7));
|
|
4663
|
-
}
|
|
4664
|
-
}
|
|
4665
|
-
}
|
|
4666
|
-
function decodeGpsLnavFrame(subframes, opts = {}) {
|
|
4667
|
-
if (subframes.length < 90) return null;
|
|
4668
|
-
const b = subframes;
|
|
4669
|
-
let i = 24;
|
|
4670
|
-
const tow1 = getBitU(b, i, 17) * 6;
|
|
4671
|
-
i += 17 + 2;
|
|
4672
|
-
const id1 = getBitU(b, i, 3);
|
|
4673
|
-
i += 3 + 2;
|
|
4674
|
-
const week10 = getBitU(b, i, 10);
|
|
4675
|
-
i += 10;
|
|
4676
|
-
i += 2;
|
|
4677
|
-
i += 4;
|
|
4678
|
-
const svHealth = getBitU(b, i, 6);
|
|
4679
|
-
i += 6;
|
|
4680
|
-
const iodc0 = getBitU(b, i, 2);
|
|
4681
|
-
i += 2;
|
|
4682
|
-
i += 1 + 87;
|
|
4683
|
-
const tgdRaw = getBitS(b, i, 8);
|
|
4684
|
-
i += 8;
|
|
4685
|
-
const iodc1 = getBitU(b, i, 8);
|
|
4686
|
-
i += 8;
|
|
4687
|
-
const tocSec = getBitU(b, i, 16) * 16;
|
|
4688
|
-
i += 16;
|
|
4689
|
-
const af2 = getBitS(b, i, 8) * 2 ** -55;
|
|
4690
|
-
i += 8;
|
|
4691
|
-
const af1 = getBitS(b, i, 16) * 2 ** -43;
|
|
4692
|
-
i += 16;
|
|
4693
|
-
const af0 = getBitS(b, i, 22) * 2 ** -31;
|
|
4694
|
-
i = 240 + 24;
|
|
4695
|
-
i += 17 + 2;
|
|
4696
|
-
const id2 = getBitU(b, i, 3);
|
|
4697
|
-
i += 3 + 2;
|
|
4698
|
-
const iode = getBitU(b, i, 8);
|
|
4699
|
-
i += 8;
|
|
4700
|
-
const crs = getBitS(b, i, 16) * 2 ** -5;
|
|
4701
|
-
i += 16;
|
|
4702
|
-
const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
|
|
4703
|
-
i += 16;
|
|
4704
|
-
const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
4705
|
-
i += 32;
|
|
4706
|
-
const cuc = getBitS(b, i, 16) * 2 ** -29;
|
|
4707
|
-
i += 16;
|
|
4708
|
-
const e = getBitU(b, i, 32) * 2 ** -33;
|
|
4709
|
-
i += 32;
|
|
4710
|
-
const cus = getBitS(b, i, 16) * 2 ** -29;
|
|
4711
|
-
i += 16;
|
|
4712
|
-
const sqrtA = getBitU(b, i, 32) * 2 ** -19;
|
|
4713
|
-
i += 32;
|
|
4714
|
-
const toes = getBitU(b, i, 16) * 16;
|
|
4715
|
-
i = 480 + 24;
|
|
4716
|
-
i += 17 + 2;
|
|
4717
|
-
const id3 = getBitU(b, i, 3);
|
|
4718
|
-
i += 3 + 2;
|
|
4719
|
-
const cic = getBitS(b, i, 16) * 2 ** -29;
|
|
4720
|
-
i += 16;
|
|
4721
|
-
const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
4722
|
-
i += 32;
|
|
4723
|
-
const cis = getBitS(b, i, 16) * 2 ** -29;
|
|
4724
|
-
i += 16;
|
|
4725
|
-
const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
4726
|
-
i += 32;
|
|
4727
|
-
const crc = getBitS(b, i, 16) * 2 ** -5;
|
|
4728
|
-
i += 16;
|
|
4729
|
-
const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
4730
|
-
i += 32;
|
|
4731
|
-
const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
|
|
4732
|
-
i += 24;
|
|
4733
|
-
const iode3 = getBitU(b, i, 8);
|
|
4734
|
-
i += 8;
|
|
4735
|
-
const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
|
|
4736
|
-
const iodc = iodc0 * 256 + iodc1;
|
|
4737
|
-
if (id1 !== 1 || id2 !== 2 || id3 !== 3) return null;
|
|
4738
|
-
if (iode3 !== iode || iode !== (iodc & 255)) return null;
|
|
4739
|
-
const ref = opts.refWeek ?? Math.floor((Date.now() - GPS_EPOCH_MS) / 1e3 / SEC_PER_WEEK);
|
|
4740
|
-
let week = week10 + 1024 * Math.round((ref - week10) / 1024);
|
|
4741
|
-
if (toes < tow1 - 302400) week++;
|
|
4742
|
-
else if (toes > tow1 + 302400) week--;
|
|
4743
|
-
const prn = opts.prn ?? "G00";
|
|
4744
|
-
const tocDate = new Date(
|
|
4745
|
-
GPS_EPOCH_MS + (week * SEC_PER_WEEK + tocSec) * 1e3
|
|
4746
|
-
);
|
|
4747
|
-
return {
|
|
4748
|
-
system: prn[0] === "J" ? "J" : "G",
|
|
4749
|
-
prn,
|
|
4750
|
-
tocDate,
|
|
4751
|
-
// Same seconds-of-week convention as parseNavFile (rinex/nav.ts).
|
|
4752
|
-
toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK,
|
|
4753
|
-
af0,
|
|
4754
|
-
af1,
|
|
4755
|
-
af2,
|
|
4756
|
-
iode,
|
|
4757
|
-
crs,
|
|
4758
|
-
deltaN,
|
|
4759
|
-
m0,
|
|
4760
|
-
cuc,
|
|
4761
|
-
e,
|
|
4762
|
-
cus,
|
|
4763
|
-
sqrtA,
|
|
4764
|
-
toe: toes,
|
|
4765
|
-
cic,
|
|
4766
|
-
omega0,
|
|
4767
|
-
cis,
|
|
4768
|
-
i0,
|
|
4769
|
-
crc,
|
|
4770
|
-
omega,
|
|
4771
|
-
omegaDot,
|
|
4772
|
-
idot,
|
|
4773
|
-
week,
|
|
4774
|
-
svHealth,
|
|
4775
|
-
tgd: tgdRaw === -128 ? 0 : tgdRaw * 2 ** -31
|
|
4776
|
-
// IS-GPS-200: -128 reserved
|
|
4777
|
-
};
|
|
4778
|
-
}
|
|
4779
|
-
|
|
4780
5258
|
// src/ubx/nav.ts
|
|
4781
5259
|
var PREAMB_CNAV = 139;
|
|
4782
5260
|
function readLnavSubframe(view, f) {
|
|
@@ -4884,8 +5362,42 @@ function parseUbxIonoUtc(data) {
|
|
|
4884
5362
|
return { ionoCorrections, leapSeconds };
|
|
4885
5363
|
}
|
|
4886
5364
|
|
|
5365
|
+
// src/ubx/cnav.ts
|
|
5366
|
+
function parseUbxCnav(data) {
|
|
5367
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
5368
|
+
const assembler = new CnavAssembler();
|
|
5369
|
+
const ephemerides = [];
|
|
5370
|
+
let badCrc = 0;
|
|
5371
|
+
let messages = 0;
|
|
5372
|
+
for (const f of ubxFrames(data)) {
|
|
5373
|
+
if (f.msgClass !== 2 || f.msgId !== 19) continue;
|
|
5374
|
+
const p = f.payload;
|
|
5375
|
+
if (p.length < 8 + 40) continue;
|
|
5376
|
+
if (p[0] !== 0 || p[2] !== 3 && p[2] !== 4) continue;
|
|
5377
|
+
const svId = p[1];
|
|
5378
|
+
if (svId < 1 || svId > 32) continue;
|
|
5379
|
+
messages++;
|
|
5380
|
+
const msg = new Uint8Array(40);
|
|
5381
|
+
const base = f.payloadStart + 8;
|
|
5382
|
+
for (let k = 0; k < 10; k++) {
|
|
5383
|
+
const w = view.getUint32(base + 4 * k, true);
|
|
5384
|
+
msg[4 * k] = w >>> 24;
|
|
5385
|
+
msg[4 * k + 1] = w >>> 16 & 255;
|
|
5386
|
+
msg[4 * k + 2] = w >>> 8 & 255;
|
|
5387
|
+
msg[4 * k + 3] = w & 255;
|
|
5388
|
+
}
|
|
5389
|
+
if (!cnavCrcOk(msg)) {
|
|
5390
|
+
badCrc++;
|
|
5391
|
+
continue;
|
|
5392
|
+
}
|
|
5393
|
+
const eph = assembler.push(msg);
|
|
5394
|
+
if (eph) ephemerides.push(eph);
|
|
5395
|
+
}
|
|
5396
|
+
return { ephemerides, badCrc, messages };
|
|
5397
|
+
}
|
|
5398
|
+
|
|
4887
5399
|
// src/ubx/index.ts
|
|
4888
|
-
var
|
|
5400
|
+
var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
|
|
4889
5401
|
var MS_PER_WEEK2 = 7 * 864e5;
|
|
4890
5402
|
var SIGNALS = {
|
|
4891
5403
|
0: { 0: ["G", "1C"], 3: ["G", "2X"], 4: ["G", "2X"] },
|
|
@@ -4968,7 +5480,7 @@ function parseUbxRawx(data) {
|
|
|
4968
5480
|
if (!codes.includes(sig[1])) codes.push(sig[1]);
|
|
4969
5481
|
}
|
|
4970
5482
|
epochs.push({
|
|
4971
|
-
timeMs:
|
|
5483
|
+
timeMs: GPS_EPOCH_MS4 + week * MS_PER_WEEK2 + Math.round(rcvTow * 1e3),
|
|
4972
5484
|
leapS: leapValid ? leapS : null,
|
|
4973
5485
|
meas
|
|
4974
5486
|
});
|
|
@@ -5039,10 +5551,10 @@ function svidToPrn(svid) {
|
|
|
5039
5551
|
|
|
5040
5552
|
// src/sbf/nav.ts
|
|
5041
5553
|
var PI2 = Math.PI;
|
|
5042
|
-
var
|
|
5554
|
+
var GPS_EPOCH_MS5 = Date.UTC(1980, 0, 6);
|
|
5043
5555
|
var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
|
|
5044
|
-
var
|
|
5045
|
-
var MS_PER_WEEK3 =
|
|
5556
|
+
var SEC_PER_WEEK4 = 7 * 86400;
|
|
5557
|
+
var MS_PER_WEEK3 = SEC_PER_WEEK4 * 1e3;
|
|
5046
5558
|
var F4_DNU = -2e10;
|
|
5047
5559
|
var U4_DNU = 4294967295;
|
|
5048
5560
|
function adjustWeek(refWeek, wn, mod) {
|
|
@@ -5051,8 +5563,8 @@ function adjustWeek(refWeek, wn, mod) {
|
|
|
5051
5563
|
if (offset < -(mod / 2 - 1)) offset += mod;
|
|
5052
5564
|
return refWeek - offset;
|
|
5053
5565
|
}
|
|
5054
|
-
var gpsMs = (week, sec) =>
|
|
5055
|
-
var sowOf = (dateMs) => dateMs / 1e3 %
|
|
5566
|
+
var gpsMs = (week, sec) => GPS_EPOCH_MS5 + week * MS_PER_WEEK3 + sec * 1e3;
|
|
5567
|
+
var sowOf = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK4;
|
|
5056
5568
|
function decodeGpsQzsNav(view, b, sys) {
|
|
5057
5569
|
const svid = view.getUint8(b + 14);
|
|
5058
5570
|
const prn = sys === "G" ? svid : svid - 180;
|
|
@@ -5201,7 +5713,7 @@ function decodeGloNav(view, b) {
|
|
|
5201
5713
|
const tocDate = new Date(toeGpsMs - leapMs);
|
|
5202
5714
|
const tofGpsMs = gpsMs(wnc, 0) + view.getUint32(b + 8, true);
|
|
5203
5715
|
const tofLeapMs = getGpsLeap(new Date(tofGpsMs)) * 1e3;
|
|
5204
|
-
const messageFrameTime = (tofGpsMs - tofLeapMs -
|
|
5716
|
+
const messageFrameTime = (tofGpsMs - tofLeapMs - GPS_EPOCH_MS5) / 1e3 % SEC_PER_WEEK4;
|
|
5205
5717
|
return {
|
|
5206
5718
|
system: "R",
|
|
5207
5719
|
prn,
|
|
@@ -5379,9 +5891,45 @@ function parseSbfIonoUtc(data) {
|
|
|
5379
5891
|
return { ionoCorrections, leapSeconds };
|
|
5380
5892
|
}
|
|
5381
5893
|
|
|
5894
|
+
// src/sbf/rawnav.ts
|
|
5895
|
+
var SIGNAL_OF_BLOCK = {
|
|
5896
|
+
4018: "L2C",
|
|
5897
|
+
4019: "L5"
|
|
5898
|
+
};
|
|
5899
|
+
function parseSbfCnav(data) {
|
|
5900
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
5901
|
+
const ephemerides = [];
|
|
5902
|
+
const assemblers = {
|
|
5903
|
+
L2C: new CnavAssembler(),
|
|
5904
|
+
L5: new CnavAssembler()
|
|
5905
|
+
};
|
|
5906
|
+
let badCrc = 0;
|
|
5907
|
+
let messages = 0;
|
|
5908
|
+
scanSbfFrames(data, view, (id, b, len) => {
|
|
5909
|
+
const signal = SIGNAL_OF_BLOCK[id];
|
|
5910
|
+
if (!signal || len < 60) return;
|
|
5911
|
+
messages++;
|
|
5912
|
+
const msg = new Uint8Array(40);
|
|
5913
|
+
for (let k = 0; k < 10; k++) {
|
|
5914
|
+
const w = view.getUint32(b + 20 + 4 * k, true);
|
|
5915
|
+
msg[4 * k] = w >>> 24;
|
|
5916
|
+
msg[4 * k + 1] = w >>> 16 & 255;
|
|
5917
|
+
msg[4 * k + 2] = w >>> 8 & 255;
|
|
5918
|
+
msg[4 * k + 3] = w & 255;
|
|
5919
|
+
}
|
|
5920
|
+
if (!cnavCrcOk(msg)) {
|
|
5921
|
+
badCrc++;
|
|
5922
|
+
return;
|
|
5923
|
+
}
|
|
5924
|
+
const eph = assemblers[signal].push(msg);
|
|
5925
|
+
if (eph) ephemerides.push({ ...eph, signal });
|
|
5926
|
+
});
|
|
5927
|
+
return { ephemerides, badCrc, messages };
|
|
5928
|
+
}
|
|
5929
|
+
|
|
5382
5930
|
// src/sbf/index.ts
|
|
5383
5931
|
var CLIGHT = 299792458;
|
|
5384
|
-
var
|
|
5932
|
+
var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
|
|
5385
5933
|
var MS_PER_WEEK4 = 7 * 864e5;
|
|
5386
5934
|
var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
|
|
5387
5935
|
var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
|
|
@@ -6035,7 +6583,7 @@ function parseSbfMeas(data) {
|
|
|
6035
6583
|
const tow = view.getUint32(i + 8, true);
|
|
6036
6584
|
const wnc = view.getUint16(i + 12, true);
|
|
6037
6585
|
if (tow !== 4294967295 && wnc !== 65535) {
|
|
6038
|
-
ensureEpoch(
|
|
6586
|
+
ensureEpoch(GPS_EPOCH_MS6 + wnc * MS_PER_WEEK4 + tow);
|
|
6039
6587
|
if (id === 4109) decodeMeas3Ranges(i, tow);
|
|
6040
6588
|
else if (id === 4110) decodeMeas3CN0(i, len);
|
|
6041
6589
|
else if (id === 4111) decodeMeas3Doppler(i, len);
|
|
@@ -6097,16 +6645,17 @@ var ID_RAWEPHEM = 41;
|
|
|
6097
6645
|
var ID_GLOEPHEMERIS = 723;
|
|
6098
6646
|
var ID_GALEPHEMERIS = 1122;
|
|
6099
6647
|
var ID_QZSSEPHEMERIS = 1336;
|
|
6648
|
+
var ID_GPSEPHEM = 7;
|
|
6100
6649
|
var ID_BDSEPHEMERIS = 1696;
|
|
6101
|
-
var
|
|
6650
|
+
var GPS_EPOCH_MS7 = Date.UTC(1980, 0, 6);
|
|
6102
6651
|
var BDT_EPOCH_MS2 = Date.UTC(2006, 0, 1);
|
|
6103
|
-
var
|
|
6652
|
+
var SEC_PER_WEEK5 = 7 * 86400;
|
|
6104
6653
|
var SEC_PER_DAY = 86400;
|
|
6105
|
-
var MS_PER_WEEK5 =
|
|
6106
|
-
var gpsMs2 = (week, sec) =>
|
|
6107
|
-
var sowOf2 = (dateMs) => dateMs / 1e3 %
|
|
6654
|
+
var MS_PER_WEEK5 = SEC_PER_WEEK5 * 1e3;
|
|
6655
|
+
var gpsMs2 = (week, sec) => GPS_EPOCH_MS7 + week * MS_PER_WEEK5 + sec * 1e3;
|
|
6656
|
+
var sowOf2 = (dateMs) => dateMs / 1e3 % SEC_PER_WEEK5;
|
|
6108
6657
|
function nearWeekMs(refMs, sow) {
|
|
6109
|
-
const refWeek = Math.floor((refMs -
|
|
6658
|
+
const refWeek = Math.floor((refMs - GPS_EPOCH_MS7) / MS_PER_WEEK5);
|
|
6110
6659
|
let ms = gpsMs2(refWeek, sow);
|
|
6111
6660
|
if (ms < refMs - MS_PER_WEEK5 / 2) ms += MS_PER_WEEK5;
|
|
6112
6661
|
else if (ms > refMs + MS_PER_WEEK5 / 2) ms -= MS_PER_WEEK5;
|
|
@@ -6133,9 +6682,9 @@ function decodeGloEphemeris(view, p) {
|
|
|
6133
6682
|
tof += Math.floor(tow / SEC_PER_DAY) * SEC_PER_DAY;
|
|
6134
6683
|
if (tof < tow - 43200) tof += SEC_PER_DAY;
|
|
6135
6684
|
else if (tof > tow + 43200) tof -= SEC_PER_DAY;
|
|
6136
|
-
const toeGpsMs =
|
|
6137
|
-
const tofGpsMs =
|
|
6138
|
-
const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() -
|
|
6685
|
+
const toeGpsMs = GPS_EPOCH_MS7 + (week * SEC_PER_WEEK5 + tow) * 1e3;
|
|
6686
|
+
const tofGpsMs = GPS_EPOCH_MS7 + (week * SEC_PER_WEEK5 + tof) * 1e3;
|
|
6687
|
+
const tofUtcSec = (getUtcDate(new Date(tofGpsMs)).getTime() - GPS_EPOCH_MS7) / 1e3;
|
|
6139
6688
|
return {
|
|
6140
6689
|
system: "R",
|
|
6141
6690
|
prn: `R${String(slot).padStart(2, "0")}`,
|
|
@@ -6143,7 +6692,7 @@ function decodeGloEphemeris(view, p) {
|
|
|
6143
6692
|
tauN: -view.getFloat64(p + 100, true),
|
|
6144
6693
|
// RINEX stores −τ_n
|
|
6145
6694
|
gammaN: view.getFloat64(p + 116, true),
|
|
6146
|
-
messageFrameTime: (tofUtcSec %
|
|
6695
|
+
messageFrameTime: (tofUtcSec % SEC_PER_WEEK5 + SEC_PER_WEEK5) % SEC_PER_WEEK5,
|
|
6147
6696
|
x: view.getFloat64(p + 28, true) / 1e3,
|
|
6148
6697
|
y: view.getFloat64(p + 36, true) / 1e3,
|
|
6149
6698
|
z: view.getFloat64(p + 44, true) / 1e3,
|
|
@@ -6200,7 +6749,7 @@ function decodeGalEphemeris(view, p, headerMs) {
|
|
|
6200
6749
|
omega: view.getFloat64(p + 60, true),
|
|
6201
6750
|
omegaDot: view.getFloat64(p + 140, true),
|
|
6202
6751
|
idot: view.getFloat64(p + 124, true),
|
|
6203
|
-
week: Math.floor((toeMs -
|
|
6752
|
+
week: Math.floor((toeMs - GPS_EPOCH_MS7) / MS_PER_WEEK5),
|
|
6204
6753
|
// RINEX Galileo SVH bit layout (E1B DVS/HS in bits 0-2, E5a in
|
|
6205
6754
|
// 3-5, E5b in 6-8) — same packing as RTKLIB.
|
|
6206
6755
|
svHealth: svhE5b << 7 | dvsE5b << 6 | svhE5a << 4 | dvsE5a << 3 | svhE1b << 1 | dvsE1b,
|
|
@@ -6251,9 +6800,10 @@ function decodeBdsEphemeris2(view, p) {
|
|
|
6251
6800
|
// TGD1 (B1) — RINEX slot
|
|
6252
6801
|
};
|
|
6253
6802
|
}
|
|
6254
|
-
function
|
|
6803
|
+
function decodeGpsQzssEphemeris(view, p, sys) {
|
|
6255
6804
|
const prn = view.getUint32(p, true);
|
|
6256
|
-
if (prn <
|
|
6805
|
+
if (sys === "G" && (prn < 1 || prn > 32)) return null;
|
|
6806
|
+
if (sys === "J" && (prn < 193 || prn > 202)) return null;
|
|
6257
6807
|
const health = view.getUint32(p + 12, true) & 63;
|
|
6258
6808
|
const iode1 = view.getUint32(p + 16, true);
|
|
6259
6809
|
const week = view.getUint32(p + 24, true);
|
|
@@ -6262,8 +6812,8 @@ function decodeQzssEphemeris2(view, p) {
|
|
|
6262
6812
|
const tocs = view.getFloat64(p + 164, true);
|
|
6263
6813
|
const tocDate = new Date(nearWeekMs(toeMs, tocs));
|
|
6264
6814
|
return {
|
|
6265
|
-
system:
|
|
6266
|
-
prn:
|
|
6815
|
+
system: sys,
|
|
6816
|
+
prn: `${sys}${String(sys === "J" ? prn - 192 : prn).padStart(2, "0")}`,
|
|
6267
6817
|
toc: sowOf2(tocDate.getTime()),
|
|
6268
6818
|
tocDate,
|
|
6269
6819
|
af0: view.getFloat64(p + 180, true),
|
|
@@ -6321,8 +6871,11 @@ function parseNovatelNav(data) {
|
|
|
6321
6871
|
} else if (frame.id === ID_BDSEPHEMERIS && frame.msgLen >= 196) {
|
|
6322
6872
|
const eph = decodeBdsEphemeris2(view, frame.payload);
|
|
6323
6873
|
if (eph) pushKepler(eph.prn, eph);
|
|
6874
|
+
} else if (frame.id === ID_GPSEPHEM && frame.msgLen >= 204) {
|
|
6875
|
+
const eph = decodeGpsQzssEphemeris(view, frame.payload, "G");
|
|
6876
|
+
if (eph) pushKepler(eph.prn, eph);
|
|
6324
6877
|
} else if (frame.id === ID_QZSSEPHEMERIS && frame.msgLen >= 204) {
|
|
6325
|
-
const eph =
|
|
6878
|
+
const eph = decodeGpsQzssEphemeris(view, frame.payload, "J");
|
|
6326
6879
|
if (eph) pushKepler(eph.prn, eph);
|
|
6327
6880
|
} else if (frame.id === ID_IONUTC && frame.msgLen >= 108) {
|
|
6328
6881
|
const p = frame.payload;
|
|
@@ -6350,7 +6903,7 @@ function parseNovatelNav(data) {
|
|
|
6350
6903
|
}
|
|
6351
6904
|
|
|
6352
6905
|
// src/novatel/index.ts
|
|
6353
|
-
var
|
|
6906
|
+
var GPS_EPOCH_MS8 = Date.UTC(1980, 0, 6);
|
|
6354
6907
|
var MS_PER_WEEK6 = 7 * 864e5;
|
|
6355
6908
|
var HDR = 28;
|
|
6356
6909
|
var ID_RANGE = 43;
|
|
@@ -6520,7 +7073,7 @@ function parseNovatelRange(data) {
|
|
|
6520
7073
|
if (!codes.includes(code)) codes.push(code);
|
|
6521
7074
|
}
|
|
6522
7075
|
epochs.push({
|
|
6523
|
-
timeMs:
|
|
7076
|
+
timeMs: GPS_EPOCH_MS8 + week * MS_PER_WEEK6 + towMs,
|
|
6524
7077
|
meas
|
|
6525
7078
|
});
|
|
6526
7079
|
}
|
|
@@ -6572,7 +7125,7 @@ function parseNovatelRange(data) {
|
|
|
6572
7125
|
if (!codes.includes(code)) codes.push(code);
|
|
6573
7126
|
}
|
|
6574
7127
|
epochs.push({
|
|
6575
|
-
timeMs:
|
|
7128
|
+
timeMs: GPS_EPOCH_MS8 + week * MS_PER_WEEK6 + towMs,
|
|
6576
7129
|
meas
|
|
6577
7130
|
});
|
|
6578
7131
|
}
|
|
@@ -6931,10 +7484,10 @@ function selectBest(ephs, timeMs) {
|
|
|
6931
7484
|
}
|
|
6932
7485
|
return best;
|
|
6933
7486
|
}
|
|
6934
|
-
var
|
|
7487
|
+
var GPS_EPOCH_MS9 = START_GPS_TIME.getTime();
|
|
6935
7488
|
var MS_PER_WEEK7 = 7 * 864e5;
|
|
6936
7489
|
var BDS_EPOCH_MS = START_BDS_TIME.getTime();
|
|
6937
|
-
var GAL_EPOCH_MS =
|
|
7490
|
+
var GAL_EPOCH_MS = GPS_EPOCH_MS9 + 1024 * MS_PER_WEEK7;
|
|
6938
7491
|
function ephInfoToEphemeris(info) {
|
|
6939
7492
|
const sys = info.prn.charAt(0);
|
|
6940
7493
|
if (sys === "R") {
|
|
@@ -6985,8 +7538,8 @@ function ephInfoToEphemeris(info) {
|
|
|
6985
7538
|
} else if (sys === "E") {
|
|
6986
7539
|
epochMs = GAL_EPOCH_MS;
|
|
6987
7540
|
} else {
|
|
6988
|
-
epochMs =
|
|
6989
|
-
const weeksNow = (info.lastReceived -
|
|
7541
|
+
epochMs = GPS_EPOCH_MS9;
|
|
7542
|
+
const weeksNow = (info.lastReceived - GPS_EPOCH_MS9) / MS_PER_WEEK7;
|
|
6990
7543
|
week += 1024 * Math.round((weeksNow - week) / 1024);
|
|
6991
7544
|
}
|
|
6992
7545
|
const tocDate = new Date(epochMs + week * MS_PER_WEEK7 + tocSec * 1e3);
|
|
@@ -7522,8 +8075,8 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
7522
8075
|
const dtsClock = satClockCorrection(eph, tTx);
|
|
7523
8076
|
const sat = computeSatPosition(eph, tTx - dtsClock * 1e3);
|
|
7524
8077
|
if (!Number.isFinite(sat.x)) continue;
|
|
7525
|
-
const
|
|
7526
|
-
const dts = dtsClock - (tgd &&
|
|
8078
|
+
const isKepler3 = eph.system !== "R" && eph.system !== "S";
|
|
8079
|
+
const dts = dtsClock - (tgd && isKepler3 ? eph.tgd : 0);
|
|
7527
8080
|
const travel = Math.hypot(sat.x - x2, sat.y - y2, sat.z - z2) / C_LIGHT;
|
|
7528
8081
|
const [sx, sy, sz] = sagnac(sat, travel);
|
|
7529
8082
|
const rho = Math.hypot(sx - x2, sy - y2, sz - z2);
|
|
@@ -10004,6 +10557,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
10004
10557
|
ephInfoToEphemeris,
|
|
10005
10558
|
euclidean3D,
|
|
10006
10559
|
fetchSourcetable,
|
|
10560
|
+
fmtD,
|
|
10007
10561
|
fmtF,
|
|
10008
10562
|
formatUTCTime,
|
|
10009
10563
|
frequencyLabel,
|
|
@@ -10088,12 +10642,14 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
10088
10642
|
parseNovatelRange,
|
|
10089
10643
|
parseRinexStream,
|
|
10090
10644
|
parseSbfAlmanac,
|
|
10645
|
+
parseSbfCnav,
|
|
10091
10646
|
parseSbfIonoUtc,
|
|
10092
10647
|
parseSbfMeas,
|
|
10093
10648
|
parseSbfNav,
|
|
10094
10649
|
parseSinexBiasDcb,
|
|
10095
10650
|
parseSourcetable,
|
|
10096
10651
|
parseSp3,
|
|
10652
|
+
parseUbxCnav,
|
|
10097
10653
|
parseUbxIonoUtc,
|
|
10098
10654
|
parseUbxNav,
|
|
10099
10655
|
parseUbxRawx,
|
|
@@ -10129,5 +10685,6 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
10129
10685
|
writeRinex2ObsBlob,
|
|
10130
10686
|
writeRinex4ObsBlob,
|
|
10131
10687
|
writeRinexNav,
|
|
10688
|
+
writeRinexNav4,
|
|
10132
10689
|
writeRinexObsBlob
|
|
10133
10690
|
});
|