gnss-js 1.18.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-CG7SF45F.js → chunk-5S5HMAKW.js} +1 -1
- package/dist/{chunk-Y5IWUPJQ.js → chunk-6NCMACDO.js} +2 -0
- package/dist/{chunk-FEGLXNWA.js → chunk-JW2ICDR7.js} +1 -1
- package/dist/{chunk-HXF7XVW7.js → chunk-K73SERD5.js} +299 -11
- package/dist/index.cjs +712 -430
- package/dist/index.d.cts +2 -3
- package/dist/index.d.ts +2 -3
- package/dist/index.js +9 -5
- package/dist/nav-DImXUdbp.d.cts +223 -0
- package/dist/nav-DImXUdbp.d.ts +223 -0
- package/dist/novatel.d.cts +1 -1
- package/dist/novatel.d.ts +1 -1
- 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.d.cts +1 -2
- package/dist/sbf.d.ts +1 -2
- package/dist/sbf.js +2 -2
- package/dist/ubx.d.cts +1 -2
- package/dist/ubx.d.ts +1 -2
- package/dist/ubx.js +2 -2
- package/package.json +1 -1
- package/dist/cnav-CRns0ECn.d.cts +0 -96
- package/dist/cnav-CRns0ECn.d.ts +0 -96
- 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,
|
|
@@ -265,6 +266,7 @@ __export(src_exports, {
|
|
|
265
266
|
writeRinex2ObsBlob: () => writeRinex2ObsBlob,
|
|
266
267
|
writeRinex4ObsBlob: () => writeRinex4ObsBlob,
|
|
267
268
|
writeRinexNav: () => writeRinexNav,
|
|
269
|
+
writeRinexNav4: () => writeRinexNav4,
|
|
268
270
|
writeRinexObsBlob: () => writeRinexObsBlob
|
|
269
271
|
});
|
|
270
272
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -2185,6 +2187,343 @@ var WarningAccumulator = class {
|
|
|
2185
2187
|
}
|
|
2186
2188
|
};
|
|
2187
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
|
+
|
|
2188
2527
|
// src/rinex/nav.ts
|
|
2189
2528
|
var DATA_LINES = {
|
|
2190
2529
|
G: 7,
|
|
@@ -2208,19 +2547,19 @@ var R4_MSG_LINES = {
|
|
|
2208
2547
|
SBAS: 4,
|
|
2209
2548
|
FDMA: 5,
|
|
2210
2549
|
// RINEX 4 adds orbit-4 (status flags) vs 3 in RINEX 3
|
|
2211
|
-
// EPH
|
|
2550
|
+
// EPH type parsed into RinexCnavEphemeris for G/J (skipped otherwise)
|
|
2212
2551
|
CNAV: 9,
|
|
2552
|
+
// EPH types we skip (different field layout)
|
|
2213
2553
|
CNV1: 10,
|
|
2214
2554
|
CNV2: 10,
|
|
2215
2555
|
CNV3: 9,
|
|
2216
2556
|
L1NV: 8,
|
|
2217
2557
|
L1OC: 9,
|
|
2218
|
-
L3OC: 9
|
|
2219
|
-
// Non-EPH records
|
|
2220
|
-
STO: 2,
|
|
2221
|
-
EOP: 3,
|
|
2222
|
-
ION: 3
|
|
2558
|
+
L3OC: 9
|
|
2223
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;
|
|
2224
2563
|
var SUPPORTED_EPH_MSGS = /* @__PURE__ */ new Set([
|
|
2225
2564
|
"LNAV",
|
|
2226
2565
|
"INAV",
|
|
@@ -2284,6 +2623,20 @@ function parseDataLine(line, colOffset = 4) {
|
|
|
2284
2623
|
}
|
|
2285
2624
|
return values;
|
|
2286
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
|
+
}
|
|
2287
2640
|
function buildKeplerEphemeris(sys, prn, date, epochVals, data) {
|
|
2288
2641
|
const d = [];
|
|
2289
2642
|
for (const line of data) {
|
|
@@ -2346,6 +2699,68 @@ function buildStateVectorEphemeris(sys, prn, date, epochVals, data) {
|
|
|
2346
2699
|
zAcc: d[10] ?? 0
|
|
2347
2700
|
};
|
|
2348
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
|
+
}
|
|
2349
2764
|
function parseNavFile(text) {
|
|
2350
2765
|
const lines = text.split("\n");
|
|
2351
2766
|
const header = {
|
|
@@ -2355,6 +2770,7 @@ function parseNavFile(text) {
|
|
|
2355
2770
|
ionoCorrections: {}
|
|
2356
2771
|
};
|
|
2357
2772
|
const ephemerides = [];
|
|
2773
|
+
const cnav = [];
|
|
2358
2774
|
let inHeader = true;
|
|
2359
2775
|
let i = 0;
|
|
2360
2776
|
while (i < lines.length) {
|
|
@@ -2415,8 +2831,15 @@ function parseNavFile(text) {
|
|
|
2415
2831
|
if (isV4 && line.charAt(0) === ">") {
|
|
2416
2832
|
const parts = line.substring(2).trim().split(/\s+/);
|
|
2417
2833
|
const recType = parts[0] ?? "";
|
|
2834
|
+
const svSys = (parts[1] ?? "").charAt(0);
|
|
2418
2835
|
const msgType = parts[2] ?? recType;
|
|
2419
|
-
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) {
|
|
2420
2843
|
const totalLines = R4_MSG_LINES[msgType] ?? 2;
|
|
2421
2844
|
i += totalLines + 1;
|
|
2422
2845
|
continue;
|
|
@@ -2428,6 +2851,21 @@ function parseNavFile(text) {
|
|
|
2428
2851
|
const sys2 = epochLine.charAt(0);
|
|
2429
2852
|
const parsed = parseNavEpochV3(epochLine);
|
|
2430
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
|
+
}
|
|
2431
2869
|
const dataLines2 = [];
|
|
2432
2870
|
for (let j = 0; j < numDataLines2; j++) {
|
|
2433
2871
|
i++;
|
|
@@ -2501,7 +2939,7 @@ function parseNavFile(text) {
|
|
|
2501
2939
|
}
|
|
2502
2940
|
i++;
|
|
2503
2941
|
}
|
|
2504
|
-
return { header, ephemerides };
|
|
2942
|
+
return cnav.length > 0 ? { header, ephemerides, cnav } : { header, ephemerides };
|
|
2505
2943
|
}
|
|
2506
2944
|
|
|
2507
2945
|
// src/rinex/nav-writer.ts
|
|
@@ -2509,9 +2947,13 @@ function fmtD(val) {
|
|
|
2509
2947
|
if (val === 0) return " 0.000000000000E+00";
|
|
2510
2948
|
const sign = val < 0 ? "-" : " ";
|
|
2511
2949
|
const abs = Math.abs(val);
|
|
2512
|
-
|
|
2950
|
+
let exp = Math.floor(Math.log10(abs));
|
|
2513
2951
|
const mantissa = abs / 10 ** exp;
|
|
2514
|
-
|
|
2952
|
+
let mStr = mantissa.toFixed(12);
|
|
2953
|
+
if (mStr.length > 14) {
|
|
2954
|
+
exp += 1;
|
|
2955
|
+
mStr = (mantissa / 10).toFixed(12);
|
|
2956
|
+
}
|
|
2515
2957
|
const expSign = exp >= 0 ? "+" : "-";
|
|
2516
2958
|
const expStr = String(Math.abs(exp)).padStart(2, "0");
|
|
2517
2959
|
return `${sign}${mStr}E${expSign}${expStr}`;
|
|
@@ -2586,7 +3028,7 @@ function writeKeplerRecord(eph) {
|
|
|
2586
3028
|
function writeGlonassRecord(eph) {
|
|
2587
3029
|
const lines = [];
|
|
2588
3030
|
lines.push(
|
|
2589
|
-
`${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)}`
|
|
2590
3032
|
);
|
|
2591
3033
|
lines.push(orbitLine([eph.x, eph.xDot, eph.xAcc, eph.health]));
|
|
2592
3034
|
lines.push(orbitLine([eph.y, eph.yDot, eph.yAcc, eph.freqNum]));
|
|
@@ -2606,6 +3048,181 @@ function writeRinexNav(nav) {
|
|
|
2606
3048
|
return header + records.join("\n") + "\n";
|
|
2607
3049
|
}
|
|
2608
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
|
+
|
|
2609
3226
|
// src/rinex/ionex.ts
|
|
2610
3227
|
function gridRange(l1, l2, dl) {
|
|
2611
3228
|
const out = [];
|
|
@@ -3229,7 +3846,7 @@ var BitReader = class {
|
|
|
3229
3846
|
return this.data.length * 8 - this.bitPos;
|
|
3230
3847
|
}
|
|
3231
3848
|
};
|
|
3232
|
-
function
|
|
3849
|
+
function crc24q2(data, length) {
|
|
3233
3850
|
let crc = 0;
|
|
3234
3851
|
for (let i = 0; i < length; i++) {
|
|
3235
3852
|
crc ^= data[i] << 16;
|
|
@@ -3271,7 +3888,7 @@ var Rtcm3Decoder = class {
|
|
|
3271
3888
|
}
|
|
3272
3889
|
const frameSize = 3 + length + 3;
|
|
3273
3890
|
if (this.buffer.length < frameSize) break;
|
|
3274
|
-
const crcComputed =
|
|
3891
|
+
const crcComputed = crc24q2(this.buffer, 3 + length);
|
|
3275
3892
|
const crcReceived = this.buffer[3 + length] << 16 | this.buffer[3 + length + 1] << 8 | this.buffer[3 + length + 2];
|
|
3276
3893
|
if (crcComputed !== crcReceived) {
|
|
3277
3894
|
this.buffer = this.buffer.slice(1);
|
|
@@ -4586,197 +5203,56 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
4586
5203
|
if (sig.cn0 !== void 0) sysSet.add(`S${sig.rinexCode}`);
|
|
4587
5204
|
}
|
|
4588
5205
|
}
|
|
4589
|
-
}
|
|
4590
|
-
const eph = decodeEphemeris(frame);
|
|
4591
|
-
if (eph) {
|
|
4592
|
-
stats.ephemerides.set(eph.prn, eph);
|
|
4593
|
-
if (eph.freqChannel !== void 0 && eph.prn.startsWith("R")) {
|
|
4594
|
-
setGloFreqNumber(parseInt(eph.prn.slice(1), 10), eph.freqChannel);
|
|
4595
|
-
}
|
|
4596
|
-
}
|
|
4597
|
-
updateStationMeta(stats.stationMeta, frame);
|
|
4598
|
-
}
|
|
4599
|
-
for (const [prn, sat] of stats.satellites) {
|
|
4600
|
-
if (now - sat.lastSeen > 3e4) stats.satellites.delete(prn);
|
|
4601
|
-
}
|
|
4602
|
-
const elapsed = (now - stats.startTime) / 1e3;
|
|
4603
|
-
if (elapsed > 0) {
|
|
4604
|
-
stats.bytesPerSecond = stats.totalBytes / elapsed;
|
|
4605
|
-
stats.framesPerSecond = stats.totalFrames / elapsed;
|
|
4606
|
-
}
|
|
4607
|
-
}
|
|
4608
|
-
|
|
4609
|
-
// src/ubx/frame.ts
|
|
4610
|
-
function* ubxFrames(data, stats = { badChecksums: 0 }) {
|
|
4611
|
-
let i = 0;
|
|
4612
|
-
while (i + 8 <= data.length) {
|
|
4613
|
-
if (data[i] !== 181 || data[i + 1] !== 98) {
|
|
4614
|
-
i++;
|
|
4615
|
-
continue;
|
|
4616
|
-
}
|
|
4617
|
-
const len = data[i + 4] | data[i + 5] << 8;
|
|
4618
|
-
const end = i + 6 + len + 2;
|
|
4619
|
-
if (end > data.length) break;
|
|
4620
|
-
let ckA = 0;
|
|
4621
|
-
let ckB = 0;
|
|
4622
|
-
for (let j = i + 2; j < i + 6 + len; j++) {
|
|
4623
|
-
ckA = ckA + data[j] & 255;
|
|
4624
|
-
ckB = ckB + ckA & 255;
|
|
4625
|
-
}
|
|
4626
|
-
if (ckA !== data[i + 6 + len] || ckB !== data[i + 7 + len]) {
|
|
4627
|
-
stats.badChecksums++;
|
|
4628
|
-
i++;
|
|
4629
|
-
continue;
|
|
4630
|
-
}
|
|
4631
|
-
yield {
|
|
4632
|
-
msgClass: data[i + 2],
|
|
4633
|
-
msgId: data[i + 3],
|
|
4634
|
-
payload: data.subarray(i + 6, i + 6 + len),
|
|
4635
|
-
payloadStart: i + 6
|
|
4636
|
-
};
|
|
4637
|
-
i = end;
|
|
4638
|
-
}
|
|
4639
|
-
}
|
|
4640
|
-
|
|
4641
|
-
// src/navbits/index.ts
|
|
4642
|
-
var GPS_PI = 3.1415926535898;
|
|
4643
|
-
var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
|
|
4644
|
-
var SEC_PER_WEEK = 7 * 86400;
|
|
4645
|
-
function getBitU(buff, pos, len) {
|
|
4646
|
-
let bits = 0;
|
|
4647
|
-
for (let i = pos; i < pos + len; i++) {
|
|
4648
|
-
bits = bits * 2 + (buff[i >> 3] >> 7 - (i & 7) & 1);
|
|
4649
|
-
}
|
|
4650
|
-
return bits;
|
|
4651
|
-
}
|
|
4652
|
-
function getBitS(buff, pos, len) {
|
|
4653
|
-
const bits = getBitU(buff, pos, len);
|
|
4654
|
-
if (len <= 0 || bits < 2 ** (len - 1)) return bits;
|
|
4655
|
-
return bits - 2 ** len;
|
|
4656
|
-
}
|
|
4657
|
-
function setBitU(buff, pos, len, data) {
|
|
4658
|
-
let mask = 2 ** (len - 1);
|
|
4659
|
-
for (let i = pos; i < pos + len; i++, mask /= 2) {
|
|
4660
|
-
if (data >= mask) {
|
|
4661
|
-
buff[i >> 3] |= 1 << 7 - (i & 7);
|
|
4662
|
-
data -= mask;
|
|
4663
|
-
} else {
|
|
4664
|
-
buff[i >> 3] &= ~(1 << 7 - (i & 7));
|
|
4665
|
-
}
|
|
4666
|
-
}
|
|
4667
|
-
}
|
|
4668
|
-
function decodeGpsLnavFrame(subframes, opts = {}) {
|
|
4669
|
-
if (subframes.length < 90) return null;
|
|
4670
|
-
const b = subframes;
|
|
4671
|
-
let i = 24;
|
|
4672
|
-
const tow1 = getBitU(b, i, 17) * 6;
|
|
4673
|
-
i += 17 + 2;
|
|
4674
|
-
const id1 = getBitU(b, i, 3);
|
|
4675
|
-
i += 3 + 2;
|
|
4676
|
-
const week10 = getBitU(b, i, 10);
|
|
4677
|
-
i += 10;
|
|
4678
|
-
i += 2;
|
|
4679
|
-
i += 4;
|
|
4680
|
-
const svHealth = getBitU(b, i, 6);
|
|
4681
|
-
i += 6;
|
|
4682
|
-
const iodc0 = getBitU(b, i, 2);
|
|
4683
|
-
i += 2;
|
|
4684
|
-
i += 1 + 87;
|
|
4685
|
-
const tgdRaw = getBitS(b, i, 8);
|
|
4686
|
-
i += 8;
|
|
4687
|
-
const iodc1 = getBitU(b, i, 8);
|
|
4688
|
-
i += 8;
|
|
4689
|
-
const tocSec = getBitU(b, i, 16) * 16;
|
|
4690
|
-
i += 16;
|
|
4691
|
-
const af2 = getBitS(b, i, 8) * 2 ** -55;
|
|
4692
|
-
i += 8;
|
|
4693
|
-
const af1 = getBitS(b, i, 16) * 2 ** -43;
|
|
4694
|
-
i += 16;
|
|
4695
|
-
const af0 = getBitS(b, i, 22) * 2 ** -31;
|
|
4696
|
-
i = 240 + 24;
|
|
4697
|
-
i += 17 + 2;
|
|
4698
|
-
const id2 = getBitU(b, i, 3);
|
|
4699
|
-
i += 3 + 2;
|
|
4700
|
-
const iode = getBitU(b, i, 8);
|
|
4701
|
-
i += 8;
|
|
4702
|
-
const crs = getBitS(b, i, 16) * 2 ** -5;
|
|
4703
|
-
i += 16;
|
|
4704
|
-
const deltaN = getBitS(b, i, 16) * 2 ** -43 * GPS_PI;
|
|
4705
|
-
i += 16;
|
|
4706
|
-
const m0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
4707
|
-
i += 32;
|
|
4708
|
-
const cuc = getBitS(b, i, 16) * 2 ** -29;
|
|
4709
|
-
i += 16;
|
|
4710
|
-
const e = getBitU(b, i, 32) * 2 ** -33;
|
|
4711
|
-
i += 32;
|
|
4712
|
-
const cus = getBitS(b, i, 16) * 2 ** -29;
|
|
4713
|
-
i += 16;
|
|
4714
|
-
const sqrtA = getBitU(b, i, 32) * 2 ** -19;
|
|
4715
|
-
i += 32;
|
|
4716
|
-
const toes = getBitU(b, i, 16) * 16;
|
|
4717
|
-
i = 480 + 24;
|
|
4718
|
-
i += 17 + 2;
|
|
4719
|
-
const id3 = getBitU(b, i, 3);
|
|
4720
|
-
i += 3 + 2;
|
|
4721
|
-
const cic = getBitS(b, i, 16) * 2 ** -29;
|
|
4722
|
-
i += 16;
|
|
4723
|
-
const omega0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
4724
|
-
i += 32;
|
|
4725
|
-
const cis = getBitS(b, i, 16) * 2 ** -29;
|
|
4726
|
-
i += 16;
|
|
4727
|
-
const i0 = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
4728
|
-
i += 32;
|
|
4729
|
-
const crc = getBitS(b, i, 16) * 2 ** -5;
|
|
4730
|
-
i += 16;
|
|
4731
|
-
const omega = getBitS(b, i, 32) * 2 ** -31 * GPS_PI;
|
|
4732
|
-
i += 32;
|
|
4733
|
-
const omegaDot = getBitS(b, i, 24) * 2 ** -43 * GPS_PI;
|
|
4734
|
-
i += 24;
|
|
4735
|
-
const iode3 = getBitU(b, i, 8);
|
|
4736
|
-
i += 8;
|
|
4737
|
-
const idot = getBitS(b, i, 14) * 2 ** -43 * GPS_PI;
|
|
4738
|
-
const iodc = iodc0 * 256 + iodc1;
|
|
4739
|
-
if (id1 !== 1 || id2 !== 2 || id3 !== 3) return null;
|
|
4740
|
-
if (iode3 !== iode || iode !== (iodc & 255)) return null;
|
|
4741
|
-
const ref = opts.refWeek ?? Math.floor((Date.now() - GPS_EPOCH_MS) / 1e3 / SEC_PER_WEEK);
|
|
4742
|
-
let week = week10 + 1024 * Math.round((ref - week10) / 1024);
|
|
4743
|
-
if (toes < tow1 - 302400) week++;
|
|
4744
|
-
else if (toes > tow1 + 302400) week--;
|
|
4745
|
-
const prn = opts.prn ?? "G00";
|
|
4746
|
-
const tocDate = new Date(
|
|
4747
|
-
GPS_EPOCH_MS + (week * SEC_PER_WEEK + tocSec) * 1e3
|
|
4748
|
-
);
|
|
4749
|
-
return {
|
|
4750
|
-
system: prn[0] === "J" ? "J" : "G",
|
|
4751
|
-
prn,
|
|
4752
|
-
tocDate,
|
|
4753
|
-
// Same seconds-of-week convention as parseNavFile (rinex/nav.ts).
|
|
4754
|
-
toc: tocDate.getTime() / 1e3 % SEC_PER_WEEK,
|
|
4755
|
-
af0,
|
|
4756
|
-
af1,
|
|
4757
|
-
af2,
|
|
4758
|
-
iode,
|
|
4759
|
-
crs,
|
|
4760
|
-
deltaN,
|
|
4761
|
-
m0,
|
|
4762
|
-
cuc,
|
|
4763
|
-
e,
|
|
4764
|
-
cus,
|
|
4765
|
-
sqrtA,
|
|
4766
|
-
toe: toes,
|
|
4767
|
-
cic,
|
|
4768
|
-
omega0,
|
|
4769
|
-
cis,
|
|
4770
|
-
i0,
|
|
4771
|
-
crc,
|
|
4772
|
-
omega,
|
|
4773
|
-
omegaDot,
|
|
4774
|
-
idot,
|
|
4775
|
-
week,
|
|
4776
|
-
svHealth,
|
|
4777
|
-
tgd: tgdRaw === -128 ? 0 : tgdRaw * 2 ** -31
|
|
4778
|
-
// IS-GPS-200: -128 reserved
|
|
4779
|
-
};
|
|
5206
|
+
}
|
|
5207
|
+
const eph = decodeEphemeris(frame);
|
|
5208
|
+
if (eph) {
|
|
5209
|
+
stats.ephemerides.set(eph.prn, eph);
|
|
5210
|
+
if (eph.freqChannel !== void 0 && eph.prn.startsWith("R")) {
|
|
5211
|
+
setGloFreqNumber(parseInt(eph.prn.slice(1), 10), eph.freqChannel);
|
|
5212
|
+
}
|
|
5213
|
+
}
|
|
5214
|
+
updateStationMeta(stats.stationMeta, frame);
|
|
5215
|
+
}
|
|
5216
|
+
for (const [prn, sat] of stats.satellites) {
|
|
5217
|
+
if (now - sat.lastSeen > 3e4) stats.satellites.delete(prn);
|
|
5218
|
+
}
|
|
5219
|
+
const elapsed = (now - stats.startTime) / 1e3;
|
|
5220
|
+
if (elapsed > 0) {
|
|
5221
|
+
stats.bytesPerSecond = stats.totalBytes / elapsed;
|
|
5222
|
+
stats.framesPerSecond = stats.totalFrames / elapsed;
|
|
5223
|
+
}
|
|
5224
|
+
}
|
|
5225
|
+
|
|
5226
|
+
// src/ubx/frame.ts
|
|
5227
|
+
function* ubxFrames(data, stats = { badChecksums: 0 }) {
|
|
5228
|
+
let i = 0;
|
|
5229
|
+
while (i + 8 <= data.length) {
|
|
5230
|
+
if (data[i] !== 181 || data[i + 1] !== 98) {
|
|
5231
|
+
i++;
|
|
5232
|
+
continue;
|
|
5233
|
+
}
|
|
5234
|
+
const len = data[i + 4] | data[i + 5] << 8;
|
|
5235
|
+
const end = i + 6 + len + 2;
|
|
5236
|
+
if (end > data.length) break;
|
|
5237
|
+
let ckA = 0;
|
|
5238
|
+
let ckB = 0;
|
|
5239
|
+
for (let j = i + 2; j < i + 6 + len; j++) {
|
|
5240
|
+
ckA = ckA + data[j] & 255;
|
|
5241
|
+
ckB = ckB + ckA & 255;
|
|
5242
|
+
}
|
|
5243
|
+
if (ckA !== data[i + 6 + len] || ckB !== data[i + 7 + len]) {
|
|
5244
|
+
stats.badChecksums++;
|
|
5245
|
+
i++;
|
|
5246
|
+
continue;
|
|
5247
|
+
}
|
|
5248
|
+
yield {
|
|
5249
|
+
msgClass: data[i + 2],
|
|
5250
|
+
msgId: data[i + 3],
|
|
5251
|
+
payload: data.subarray(i + 6, i + 6 + len),
|
|
5252
|
+
payloadStart: i + 6
|
|
5253
|
+
};
|
|
5254
|
+
i = end;
|
|
5255
|
+
}
|
|
4780
5256
|
}
|
|
4781
5257
|
|
|
4782
5258
|
// src/ubx/nav.ts
|
|
@@ -4886,202 +5362,6 @@ function parseUbxIonoUtc(data) {
|
|
|
4886
5362
|
return { ionoCorrections, leapSeconds };
|
|
4887
5363
|
}
|
|
4888
5364
|
|
|
4889
|
-
// src/navbits/cnav.ts
|
|
4890
|
-
var GPS_EPOCH_MS2 = Date.UTC(1980, 0, 6);
|
|
4891
|
-
var SEC_PER_WEEK2 = 7 * 86400;
|
|
4892
|
-
var HALF_WEEK = 302400;
|
|
4893
|
-
var CNAV_PREAMBLE = 139;
|
|
4894
|
-
var CNAV_A_REF = 26559710;
|
|
4895
|
-
var CNAV_OMEGA_DOT_REF = -26e-10;
|
|
4896
|
-
function crc24q2(buff, bitLen) {
|
|
4897
|
-
let crc = 0;
|
|
4898
|
-
for (let i = 0; i < bitLen; i++) {
|
|
4899
|
-
crc ^= (buff[i >> 3] >> 7 - (i & 7) & 1) << 23;
|
|
4900
|
-
const msb = crc & 8388608;
|
|
4901
|
-
crc = crc << 1 & 16777215;
|
|
4902
|
-
if (msb) crc ^= 8801531;
|
|
4903
|
-
}
|
|
4904
|
-
return crc;
|
|
4905
|
-
}
|
|
4906
|
-
function cnavCrcOk(msg) {
|
|
4907
|
-
if (msg.length < 38) return false;
|
|
4908
|
-
return crc24q2(msg, 276) === getBitU(msg, 276, 24);
|
|
4909
|
-
}
|
|
4910
|
-
function getBitU33(b, pos) {
|
|
4911
|
-
return getBitU(b, pos, 1) * 2 ** 32 + getBitU(b, pos + 1, 32);
|
|
4912
|
-
}
|
|
4913
|
-
function getBitS33(b, pos) {
|
|
4914
|
-
const u = getBitU33(b, pos);
|
|
4915
|
-
return u < 2 ** 32 ? u : u - 2 ** 33;
|
|
4916
|
-
}
|
|
4917
|
-
function decodeType10(b, tow) {
|
|
4918
|
-
return {
|
|
4919
|
-
tow,
|
|
4920
|
-
week: getBitU(b, 38, 13),
|
|
4921
|
-
health: getBitU(b, 51, 3),
|
|
4922
|
-
top: getBitU(b, 54, 11) * 300,
|
|
4923
|
-
uraEd: getBitS(b, 65, 5),
|
|
4924
|
-
toe: getBitU(b, 70, 11) * 300,
|
|
4925
|
-
deltaA: getBitS(b, 81, 26) * 2 ** -9,
|
|
4926
|
-
aDot: getBitS(b, 107, 25) * 2 ** -21,
|
|
4927
|
-
deltaN0: getBitS(b, 132, 17) * 2 ** -44 * GPS_PI,
|
|
4928
|
-
deltaN0Dot: getBitS(b, 149, 23) * 2 ** -57 * GPS_PI,
|
|
4929
|
-
m0: getBitS33(b, 172) * 2 ** -32 * GPS_PI,
|
|
4930
|
-
e: getBitU33(b, 205) * 2 ** -34,
|
|
4931
|
-
omega: getBitS33(b, 238) * 2 ** -32 * GPS_PI,
|
|
4932
|
-
integrityFlag: getBitU(b, 271, 1) === 1,
|
|
4933
|
-
l2cPhasing: getBitU(b, 272, 1) === 1
|
|
4934
|
-
};
|
|
4935
|
-
}
|
|
4936
|
-
function decodeType11(b) {
|
|
4937
|
-
return {
|
|
4938
|
-
toe: getBitU(b, 38, 11) * 300,
|
|
4939
|
-
omega0: getBitS33(b, 49) * 2 ** -32 * GPS_PI,
|
|
4940
|
-
i0: getBitS33(b, 82) * 2 ** -32 * GPS_PI,
|
|
4941
|
-
deltaOmegaDot: getBitS(b, 115, 17) * 2 ** -44 * GPS_PI,
|
|
4942
|
-
i0Dot: getBitS(b, 132, 15) * 2 ** -44 * GPS_PI,
|
|
4943
|
-
cis: getBitS(b, 147, 16) * 2 ** -30,
|
|
4944
|
-
cic: getBitS(b, 163, 16) * 2 ** -30,
|
|
4945
|
-
crs: getBitS(b, 179, 24) * 2 ** -8,
|
|
4946
|
-
crc: getBitS(b, 203, 24) * 2 ** -8,
|
|
4947
|
-
cus: getBitS(b, 227, 21) * 2 ** -30,
|
|
4948
|
-
cuc: getBitS(b, 248, 21) * 2 ** -30
|
|
4949
|
-
};
|
|
4950
|
-
}
|
|
4951
|
-
var isc = (b, pos) => {
|
|
4952
|
-
const raw = getBitS(b, pos, 13);
|
|
4953
|
-
return raw === -4096 ? null : raw * 2 ** -35;
|
|
4954
|
-
};
|
|
4955
|
-
function decodeClock(b, msgType) {
|
|
4956
|
-
const clock = {
|
|
4957
|
-
msgType,
|
|
4958
|
-
top: getBitU(b, 38, 11) * 300,
|
|
4959
|
-
uraNed0: getBitS(b, 49, 5),
|
|
4960
|
-
uraNed1: getBitU(b, 54, 3),
|
|
4961
|
-
uraNed2: getBitU(b, 57, 3),
|
|
4962
|
-
toc: getBitU(b, 60, 11) * 300,
|
|
4963
|
-
af0: getBitS(b, 71, 26) * 2 ** -35,
|
|
4964
|
-
af1: getBitS(b, 97, 20) * 2 ** -48,
|
|
4965
|
-
af2: getBitS(b, 117, 10) * 2 ** -60
|
|
4966
|
-
};
|
|
4967
|
-
if (msgType === 30) {
|
|
4968
|
-
clock.tgd = isc(b, 127);
|
|
4969
|
-
clock.iscL1ca = isc(b, 140);
|
|
4970
|
-
clock.iscL2c = isc(b, 153);
|
|
4971
|
-
clock.iscL5i5 = isc(b, 166);
|
|
4972
|
-
clock.iscL5q5 = isc(b, 179);
|
|
4973
|
-
clock.ionoAlpha = [
|
|
4974
|
-
getBitS(b, 192, 8) * 2 ** -30,
|
|
4975
|
-
getBitS(b, 200, 8) * 2 ** -27,
|
|
4976
|
-
getBitS(b, 208, 8) * 2 ** -24,
|
|
4977
|
-
getBitS(b, 216, 8) * 2 ** -24
|
|
4978
|
-
];
|
|
4979
|
-
clock.ionoBeta = [
|
|
4980
|
-
getBitS(b, 224, 8) * 2 ** 11,
|
|
4981
|
-
getBitS(b, 232, 8) * 2 ** 14,
|
|
4982
|
-
getBitS(b, 240, 8) * 2 ** 16,
|
|
4983
|
-
getBitS(b, 248, 8) * 2 ** 16
|
|
4984
|
-
];
|
|
4985
|
-
clock.wnOp = getBitU(b, 256, 8);
|
|
4986
|
-
}
|
|
4987
|
-
return clock;
|
|
4988
|
-
}
|
|
4989
|
-
function resolveWeek(week, towSec, sec) {
|
|
4990
|
-
if (sec < towSec - HALF_WEEK) return week + 1;
|
|
4991
|
-
if (sec > towSec + HALF_WEEK) return week - 1;
|
|
4992
|
-
return week;
|
|
4993
|
-
}
|
|
4994
|
-
function gpsDate(week, sec) {
|
|
4995
|
-
return new Date(GPS_EPOCH_MS2 + (week * SEC_PER_WEEK2 + sec) * 1e3);
|
|
4996
|
-
}
|
|
4997
|
-
var CnavAssembler = class {
|
|
4998
|
-
sats = /* @__PURE__ */ new Map();
|
|
4999
|
-
/**
|
|
5000
|
-
* Push one 300-bit CNAV message (38+ bytes, bit 0 = first bit of
|
|
5001
|
-
* the preamble). Returns the newly completed ephemeris, or null.
|
|
5002
|
-
* Messages that are not MT10/MT11/MT30-37, or whose preamble/PRN
|
|
5003
|
-
* are out of range, are ignored.
|
|
5004
|
-
*/
|
|
5005
|
-
push(msg) {
|
|
5006
|
-
if (msg.length < 38 || getBitU(msg, 0, 8) !== CNAV_PREAMBLE) return null;
|
|
5007
|
-
const prn = getBitU(msg, 8, 6);
|
|
5008
|
-
if (prn < 1 || prn > 32) return null;
|
|
5009
|
-
const type = getBitU(msg, 14, 6);
|
|
5010
|
-
const tow = getBitU(msg, 20, 17) * 6;
|
|
5011
|
-
let sat = this.sats.get(prn);
|
|
5012
|
-
if (!sat) {
|
|
5013
|
-
sat = {};
|
|
5014
|
-
this.sats.set(prn, sat);
|
|
5015
|
-
}
|
|
5016
|
-
if (type === 10) sat.t10 = decodeType10(msg, tow);
|
|
5017
|
-
else if (type === 11) sat.t11 = decodeType11(msg);
|
|
5018
|
-
else if (type >= 30 && type <= 37) {
|
|
5019
|
-
sat.clock = decodeClock(msg, type);
|
|
5020
|
-
if (type === 30) sat.extras = sat.clock;
|
|
5021
|
-
} else return null;
|
|
5022
|
-
return this.tryEmit(prn, sat);
|
|
5023
|
-
}
|
|
5024
|
-
tryEmit(prn, sat) {
|
|
5025
|
-
const { t10, t11, clock, extras } = sat;
|
|
5026
|
-
if (!t10 || !t11 || !clock) return null;
|
|
5027
|
-
if (t10.toe !== t11.toe || clock.toc !== t10.toe) return null;
|
|
5028
|
-
const key = `${t10.week}:${t10.toe}:${clock.af0}:${clock.af1}`;
|
|
5029
|
-
if (key === sat.lastKey) return null;
|
|
5030
|
-
sat.lastKey = key;
|
|
5031
|
-
const weekToe = resolveWeek(t10.week, t10.tow, t10.toe);
|
|
5032
|
-
const a = CNAV_A_REF + t10.deltaA;
|
|
5033
|
-
return {
|
|
5034
|
-
system: "G",
|
|
5035
|
-
prn: `G${String(prn).padStart(2, "0")}`,
|
|
5036
|
-
week: t10.week,
|
|
5037
|
-
health: t10.health,
|
|
5038
|
-
uraEd: t10.uraEd,
|
|
5039
|
-
uraNed0: clock.uraNed0,
|
|
5040
|
-
uraNed1: clock.uraNed1,
|
|
5041
|
-
uraNed2: clock.uraNed2,
|
|
5042
|
-
top: t10.top,
|
|
5043
|
-
toe: t10.toe,
|
|
5044
|
-
toeDate: gpsDate(weekToe, t10.toe),
|
|
5045
|
-
a,
|
|
5046
|
-
deltaA: t10.deltaA,
|
|
5047
|
-
aDot: t10.aDot,
|
|
5048
|
-
deltaN0: t10.deltaN0,
|
|
5049
|
-
deltaN0Dot: t10.deltaN0Dot,
|
|
5050
|
-
m0: t10.m0,
|
|
5051
|
-
e: t10.e,
|
|
5052
|
-
omega: t10.omega,
|
|
5053
|
-
omega0: t11.omega0,
|
|
5054
|
-
i0: t11.i0,
|
|
5055
|
-
omegaDot: CNAV_OMEGA_DOT_REF * GPS_PI + t11.deltaOmegaDot,
|
|
5056
|
-
deltaOmegaDot: t11.deltaOmegaDot,
|
|
5057
|
-
i0Dot: t11.i0Dot,
|
|
5058
|
-
cis: t11.cis,
|
|
5059
|
-
cic: t11.cic,
|
|
5060
|
-
crs: t11.crs,
|
|
5061
|
-
crc: t11.crc,
|
|
5062
|
-
cus: t11.cus,
|
|
5063
|
-
cuc: t11.cuc,
|
|
5064
|
-
toc: clock.toc,
|
|
5065
|
-
tocDate: gpsDate(weekToe, clock.toc),
|
|
5066
|
-
af0: clock.af0,
|
|
5067
|
-
af1: clock.af1,
|
|
5068
|
-
af2: clock.af2,
|
|
5069
|
-
clockMsgType: clock.msgType,
|
|
5070
|
-
tgd: extras?.tgd ?? null,
|
|
5071
|
-
iscL1ca: extras?.iscL1ca ?? null,
|
|
5072
|
-
iscL2c: extras?.iscL2c ?? null,
|
|
5073
|
-
iscL5i5: extras?.iscL5i5 ?? null,
|
|
5074
|
-
iscL5q5: extras?.iscL5q5 ?? null,
|
|
5075
|
-
...extras?.ionoAlpha && { ionoAlpha: extras.ionoAlpha },
|
|
5076
|
-
...extras?.ionoBeta && { ionoBeta: extras.ionoBeta },
|
|
5077
|
-
...extras?.wnOp !== void 0 && { wnOp: extras.wnOp },
|
|
5078
|
-
integrityFlag: t10.integrityFlag,
|
|
5079
|
-
l2cPhasing: t10.l2cPhasing,
|
|
5080
|
-
tow: t10.tow
|
|
5081
|
-
};
|
|
5082
|
-
}
|
|
5083
|
-
};
|
|
5084
|
-
|
|
5085
5365
|
// src/ubx/cnav.ts
|
|
5086
5366
|
function parseUbxCnav(data) {
|
|
5087
5367
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
@@ -5117,7 +5397,7 @@ function parseUbxCnav(data) {
|
|
|
5117
5397
|
}
|
|
5118
5398
|
|
|
5119
5399
|
// src/ubx/index.ts
|
|
5120
|
-
var
|
|
5400
|
+
var GPS_EPOCH_MS4 = Date.UTC(1980, 0, 6);
|
|
5121
5401
|
var MS_PER_WEEK2 = 7 * 864e5;
|
|
5122
5402
|
var SIGNALS = {
|
|
5123
5403
|
0: { 0: ["G", "1C"], 3: ["G", "2X"], 4: ["G", "2X"] },
|
|
@@ -5200,7 +5480,7 @@ function parseUbxRawx(data) {
|
|
|
5200
5480
|
if (!codes.includes(sig[1])) codes.push(sig[1]);
|
|
5201
5481
|
}
|
|
5202
5482
|
epochs.push({
|
|
5203
|
-
timeMs:
|
|
5483
|
+
timeMs: GPS_EPOCH_MS4 + week * MS_PER_WEEK2 + Math.round(rcvTow * 1e3),
|
|
5204
5484
|
leapS: leapValid ? leapS : null,
|
|
5205
5485
|
meas
|
|
5206
5486
|
});
|
|
@@ -5271,10 +5551,10 @@ function svidToPrn(svid) {
|
|
|
5271
5551
|
|
|
5272
5552
|
// src/sbf/nav.ts
|
|
5273
5553
|
var PI2 = Math.PI;
|
|
5274
|
-
var
|
|
5554
|
+
var GPS_EPOCH_MS5 = Date.UTC(1980, 0, 6);
|
|
5275
5555
|
var BDT_EPOCH_MS = Date.UTC(2006, 0, 1);
|
|
5276
|
-
var
|
|
5277
|
-
var MS_PER_WEEK3 =
|
|
5556
|
+
var SEC_PER_WEEK4 = 7 * 86400;
|
|
5557
|
+
var MS_PER_WEEK3 = SEC_PER_WEEK4 * 1e3;
|
|
5278
5558
|
var F4_DNU = -2e10;
|
|
5279
5559
|
var U4_DNU = 4294967295;
|
|
5280
5560
|
function adjustWeek(refWeek, wn, mod) {
|
|
@@ -5283,8 +5563,8 @@ function adjustWeek(refWeek, wn, mod) {
|
|
|
5283
5563
|
if (offset < -(mod / 2 - 1)) offset += mod;
|
|
5284
5564
|
return refWeek - offset;
|
|
5285
5565
|
}
|
|
5286
|
-
var gpsMs = (week, sec) =>
|
|
5287
|
-
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;
|
|
5288
5568
|
function decodeGpsQzsNav(view, b, sys) {
|
|
5289
5569
|
const svid = view.getUint8(b + 14);
|
|
5290
5570
|
const prn = sys === "G" ? svid : svid - 180;
|
|
@@ -5433,7 +5713,7 @@ function decodeGloNav(view, b) {
|
|
|
5433
5713
|
const tocDate = new Date(toeGpsMs - leapMs);
|
|
5434
5714
|
const tofGpsMs = gpsMs(wnc, 0) + view.getUint32(b + 8, true);
|
|
5435
5715
|
const tofLeapMs = getGpsLeap(new Date(tofGpsMs)) * 1e3;
|
|
5436
|
-
const messageFrameTime = (tofGpsMs - tofLeapMs -
|
|
5716
|
+
const messageFrameTime = (tofGpsMs - tofLeapMs - GPS_EPOCH_MS5) / 1e3 % SEC_PER_WEEK4;
|
|
5437
5717
|
return {
|
|
5438
5718
|
system: "R",
|
|
5439
5719
|
prn,
|
|
@@ -5649,7 +5929,7 @@ function parseSbfCnav(data) {
|
|
|
5649
5929
|
|
|
5650
5930
|
// src/sbf/index.ts
|
|
5651
5931
|
var CLIGHT = 299792458;
|
|
5652
|
-
var
|
|
5932
|
+
var GPS_EPOCH_MS6 = Date.UTC(1980, 0, 6);
|
|
5653
5933
|
var MS_PER_WEEK4 = 7 * 864e5;
|
|
5654
5934
|
var M3_SYS = ["G", "R", "E", "C", "S", "J", "I"];
|
|
5655
5935
|
var M3_PR_BASE = [19e6, 19e6, 22e6, 2e7, 34e6, 34e6, 34e6];
|
|
@@ -6303,7 +6583,7 @@ function parseSbfMeas(data) {
|
|
|
6303
6583
|
const tow = view.getUint32(i + 8, true);
|
|
6304
6584
|
const wnc = view.getUint16(i + 12, true);
|
|
6305
6585
|
if (tow !== 4294967295 && wnc !== 65535) {
|
|
6306
|
-
ensureEpoch(
|
|
6586
|
+
ensureEpoch(GPS_EPOCH_MS6 + wnc * MS_PER_WEEK4 + tow);
|
|
6307
6587
|
if (id === 4109) decodeMeas3Ranges(i, tow);
|
|
6308
6588
|
else if (id === 4110) decodeMeas3CN0(i, len);
|
|
6309
6589
|
else if (id === 4111) decodeMeas3Doppler(i, len);
|
|
@@ -6367,15 +6647,15 @@ var ID_GALEPHEMERIS = 1122;
|
|
|
6367
6647
|
var ID_QZSSEPHEMERIS = 1336;
|
|
6368
6648
|
var ID_GPSEPHEM = 7;
|
|
6369
6649
|
var ID_BDSEPHEMERIS = 1696;
|
|
6370
|
-
var
|
|
6650
|
+
var GPS_EPOCH_MS7 = Date.UTC(1980, 0, 6);
|
|
6371
6651
|
var BDT_EPOCH_MS2 = Date.UTC(2006, 0, 1);
|
|
6372
|
-
var
|
|
6652
|
+
var SEC_PER_WEEK5 = 7 * 86400;
|
|
6373
6653
|
var SEC_PER_DAY = 86400;
|
|
6374
|
-
var MS_PER_WEEK5 =
|
|
6375
|
-
var gpsMs2 = (week, sec) =>
|
|
6376
|
-
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;
|
|
6377
6657
|
function nearWeekMs(refMs, sow) {
|
|
6378
|
-
const refWeek = Math.floor((refMs -
|
|
6658
|
+
const refWeek = Math.floor((refMs - GPS_EPOCH_MS7) / MS_PER_WEEK5);
|
|
6379
6659
|
let ms = gpsMs2(refWeek, sow);
|
|
6380
6660
|
if (ms < refMs - MS_PER_WEEK5 / 2) ms += MS_PER_WEEK5;
|
|
6381
6661
|
else if (ms > refMs + MS_PER_WEEK5 / 2) ms -= MS_PER_WEEK5;
|
|
@@ -6402,9 +6682,9 @@ function decodeGloEphemeris(view, p) {
|
|
|
6402
6682
|
tof += Math.floor(tow / SEC_PER_DAY) * SEC_PER_DAY;
|
|
6403
6683
|
if (tof < tow - 43200) tof += SEC_PER_DAY;
|
|
6404
6684
|
else if (tof > tow + 43200) tof -= SEC_PER_DAY;
|
|
6405
|
-
const toeGpsMs =
|
|
6406
|
-
const tofGpsMs =
|
|
6407
|
-
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;
|
|
6408
6688
|
return {
|
|
6409
6689
|
system: "R",
|
|
6410
6690
|
prn: `R${String(slot).padStart(2, "0")}`,
|
|
@@ -6412,7 +6692,7 @@ function decodeGloEphemeris(view, p) {
|
|
|
6412
6692
|
tauN: -view.getFloat64(p + 100, true),
|
|
6413
6693
|
// RINEX stores −τ_n
|
|
6414
6694
|
gammaN: view.getFloat64(p + 116, true),
|
|
6415
|
-
messageFrameTime: (tofUtcSec %
|
|
6695
|
+
messageFrameTime: (tofUtcSec % SEC_PER_WEEK5 + SEC_PER_WEEK5) % SEC_PER_WEEK5,
|
|
6416
6696
|
x: view.getFloat64(p + 28, true) / 1e3,
|
|
6417
6697
|
y: view.getFloat64(p + 36, true) / 1e3,
|
|
6418
6698
|
z: view.getFloat64(p + 44, true) / 1e3,
|
|
@@ -6469,7 +6749,7 @@ function decodeGalEphemeris(view, p, headerMs) {
|
|
|
6469
6749
|
omega: view.getFloat64(p + 60, true),
|
|
6470
6750
|
omegaDot: view.getFloat64(p + 140, true),
|
|
6471
6751
|
idot: view.getFloat64(p + 124, true),
|
|
6472
|
-
week: Math.floor((toeMs -
|
|
6752
|
+
week: Math.floor((toeMs - GPS_EPOCH_MS7) / MS_PER_WEEK5),
|
|
6473
6753
|
// RINEX Galileo SVH bit layout (E1B DVS/HS in bits 0-2, E5a in
|
|
6474
6754
|
// 3-5, E5b in 6-8) — same packing as RTKLIB.
|
|
6475
6755
|
svHealth: svhE5b << 7 | dvsE5b << 6 | svhE5a << 4 | dvsE5a << 3 | svhE1b << 1 | dvsE1b,
|
|
@@ -6623,7 +6903,7 @@ function parseNovatelNav(data) {
|
|
|
6623
6903
|
}
|
|
6624
6904
|
|
|
6625
6905
|
// src/novatel/index.ts
|
|
6626
|
-
var
|
|
6906
|
+
var GPS_EPOCH_MS8 = Date.UTC(1980, 0, 6);
|
|
6627
6907
|
var MS_PER_WEEK6 = 7 * 864e5;
|
|
6628
6908
|
var HDR = 28;
|
|
6629
6909
|
var ID_RANGE = 43;
|
|
@@ -6793,7 +7073,7 @@ function parseNovatelRange(data) {
|
|
|
6793
7073
|
if (!codes.includes(code)) codes.push(code);
|
|
6794
7074
|
}
|
|
6795
7075
|
epochs.push({
|
|
6796
|
-
timeMs:
|
|
7076
|
+
timeMs: GPS_EPOCH_MS8 + week * MS_PER_WEEK6 + towMs,
|
|
6797
7077
|
meas
|
|
6798
7078
|
});
|
|
6799
7079
|
}
|
|
@@ -6845,7 +7125,7 @@ function parseNovatelRange(data) {
|
|
|
6845
7125
|
if (!codes.includes(code)) codes.push(code);
|
|
6846
7126
|
}
|
|
6847
7127
|
epochs.push({
|
|
6848
|
-
timeMs:
|
|
7128
|
+
timeMs: GPS_EPOCH_MS8 + week * MS_PER_WEEK6 + towMs,
|
|
6849
7129
|
meas
|
|
6850
7130
|
});
|
|
6851
7131
|
}
|
|
@@ -7204,10 +7484,10 @@ function selectBest(ephs, timeMs) {
|
|
|
7204
7484
|
}
|
|
7205
7485
|
return best;
|
|
7206
7486
|
}
|
|
7207
|
-
var
|
|
7487
|
+
var GPS_EPOCH_MS9 = START_GPS_TIME.getTime();
|
|
7208
7488
|
var MS_PER_WEEK7 = 7 * 864e5;
|
|
7209
7489
|
var BDS_EPOCH_MS = START_BDS_TIME.getTime();
|
|
7210
|
-
var GAL_EPOCH_MS =
|
|
7490
|
+
var GAL_EPOCH_MS = GPS_EPOCH_MS9 + 1024 * MS_PER_WEEK7;
|
|
7211
7491
|
function ephInfoToEphemeris(info) {
|
|
7212
7492
|
const sys = info.prn.charAt(0);
|
|
7213
7493
|
if (sys === "R") {
|
|
@@ -7258,8 +7538,8 @@ function ephInfoToEphemeris(info) {
|
|
|
7258
7538
|
} else if (sys === "E") {
|
|
7259
7539
|
epochMs = GAL_EPOCH_MS;
|
|
7260
7540
|
} else {
|
|
7261
|
-
epochMs =
|
|
7262
|
-
const weeksNow = (info.lastReceived -
|
|
7541
|
+
epochMs = GPS_EPOCH_MS9;
|
|
7542
|
+
const weeksNow = (info.lastReceived - GPS_EPOCH_MS9) / MS_PER_WEEK7;
|
|
7263
7543
|
week += 1024 * Math.round((weeksNow - week) / 1024);
|
|
7264
7544
|
}
|
|
7265
7545
|
const tocDate = new Date(epochMs + week * MS_PER_WEEK7 + tocSec * 1e3);
|
|
@@ -7795,8 +8075,8 @@ function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
|
7795
8075
|
const dtsClock = satClockCorrection(eph, tTx);
|
|
7796
8076
|
const sat = computeSatPosition(eph, tTx - dtsClock * 1e3);
|
|
7797
8077
|
if (!Number.isFinite(sat.x)) continue;
|
|
7798
|
-
const
|
|
7799
|
-
const dts = dtsClock - (tgd &&
|
|
8078
|
+
const isKepler3 = eph.system !== "R" && eph.system !== "S";
|
|
8079
|
+
const dts = dtsClock - (tgd && isKepler3 ? eph.tgd : 0);
|
|
7800
8080
|
const travel = Math.hypot(sat.x - x2, sat.y - y2, sat.z - z2) / C_LIGHT;
|
|
7801
8081
|
const [sx, sy, sz] = sagnac(sat, travel);
|
|
7802
8082
|
const rho = Math.hypot(sx - x2, sy - y2, sz - z2);
|
|
@@ -10277,6 +10557,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
10277
10557
|
ephInfoToEphemeris,
|
|
10278
10558
|
euclidean3D,
|
|
10279
10559
|
fetchSourcetable,
|
|
10560
|
+
fmtD,
|
|
10280
10561
|
fmtF,
|
|
10281
10562
|
formatUTCTime,
|
|
10282
10563
|
frequencyLabel,
|
|
@@ -10404,5 +10685,6 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
10404
10685
|
writeRinex2ObsBlob,
|
|
10405
10686
|
writeRinex4ObsBlob,
|
|
10406
10687
|
writeRinexNav,
|
|
10688
|
+
writeRinexNav4,
|
|
10407
10689
|
writeRinexObsBlob
|
|
10408
10690
|
});
|