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
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CNAV_A_REF,
|
|
3
|
+
CNAV_OMEGA_DOT_REF
|
|
4
|
+
} from "./chunk-6NCMACDO.js";
|
|
5
|
+
import {
|
|
6
|
+
GPS_PI
|
|
7
|
+
} from "./chunk-IQ5OIMQD.js";
|
|
8
|
+
|
|
1
9
|
// src/rinex/format.ts
|
|
2
10
|
function padL(s, w) {
|
|
3
11
|
return s.length >= w ? s.slice(0, w) : s + " ".repeat(w - s.length);
|
|
@@ -212,19 +220,19 @@ var R4_MSG_LINES = {
|
|
|
212
220
|
SBAS: 4,
|
|
213
221
|
FDMA: 5,
|
|
214
222
|
// RINEX 4 adds orbit-4 (status flags) vs 3 in RINEX 3
|
|
215
|
-
// EPH
|
|
223
|
+
// EPH type parsed into RinexCnavEphemeris for G/J (skipped otherwise)
|
|
216
224
|
CNAV: 9,
|
|
225
|
+
// EPH types we skip (different field layout)
|
|
217
226
|
CNV1: 10,
|
|
218
227
|
CNV2: 10,
|
|
219
228
|
CNV3: 9,
|
|
220
229
|
L1NV: 8,
|
|
221
230
|
L1OC: 9,
|
|
222
|
-
L3OC: 9
|
|
223
|
-
// Non-EPH records
|
|
224
|
-
STO: 2,
|
|
225
|
-
EOP: 3,
|
|
226
|
-
ION: 3
|
|
231
|
+
L3OC: 9
|
|
227
232
|
};
|
|
233
|
+
var GPS_EPOCH_MS = Date.UTC(1980, 0, 6);
|
|
234
|
+
var SEC_PER_WEEK = 7 * 86400;
|
|
235
|
+
var QZSS_CNAV_A_REF = 42164200;
|
|
228
236
|
var SUPPORTED_EPH_MSGS = /* @__PURE__ */ new Set([
|
|
229
237
|
"LNAV",
|
|
230
238
|
"INAV",
|
|
@@ -288,6 +296,20 @@ function parseDataLine(line, colOffset = 4) {
|
|
|
288
296
|
}
|
|
289
297
|
return values;
|
|
290
298
|
}
|
|
299
|
+
function parseDataLineSlots(line) {
|
|
300
|
+
const values = [];
|
|
301
|
+
for (let i = 0; i < 4; i++) {
|
|
302
|
+
const start = 4 + i * 19;
|
|
303
|
+
const s = start < line.length ? line.substring(start, start + 19).trim() : "";
|
|
304
|
+
if (s.length === 0) {
|
|
305
|
+
values.push(null);
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
const v = parseFloat19(s);
|
|
309
|
+
values.push(Number.isFinite(v) ? v : null);
|
|
310
|
+
}
|
|
311
|
+
return values;
|
|
312
|
+
}
|
|
291
313
|
function buildKeplerEphemeris(sys, prn, date, epochVals, data) {
|
|
292
314
|
const d = [];
|
|
293
315
|
for (const line of data) {
|
|
@@ -350,6 +372,68 @@ function buildStateVectorEphemeris(sys, prn, date, epochVals, data) {
|
|
|
350
372
|
zAcc: d[10] ?? 0
|
|
351
373
|
};
|
|
352
374
|
}
|
|
375
|
+
function buildCnavEphemeris(sys, prn, date, epochVals, d) {
|
|
376
|
+
const num = (r, c) => d[r]?.[c] ?? 0;
|
|
377
|
+
const opt = (r, c) => d[r]?.[c] ?? null;
|
|
378
|
+
const t = (date.getTime() - GPS_EPOCH_MS) / 1e3;
|
|
379
|
+
const week = Math.floor(t / SEC_PER_WEEK);
|
|
380
|
+
const toc = t - week * SEC_PER_WEEK;
|
|
381
|
+
const sqrtA = num(1, 3);
|
|
382
|
+
const a = sqrtA * sqrtA;
|
|
383
|
+
const aRef = sys === "J" ? QZSS_CNAV_A_REF : CNAV_A_REF;
|
|
384
|
+
const omegaDot = num(3, 3);
|
|
385
|
+
const wnOp = d[7]?.[1];
|
|
386
|
+
return {
|
|
387
|
+
system: sys,
|
|
388
|
+
prn,
|
|
389
|
+
week,
|
|
390
|
+
health: num(5, 1),
|
|
391
|
+
uraEd: num(5, 0),
|
|
392
|
+
uraNed0: num(4, 2),
|
|
393
|
+
uraNed1: num(4, 3),
|
|
394
|
+
uraNed2: num(5, 3),
|
|
395
|
+
top: num(2, 0),
|
|
396
|
+
toe: toc,
|
|
397
|
+
toeDate: date,
|
|
398
|
+
a,
|
|
399
|
+
deltaA: a - aRef,
|
|
400
|
+
aDot: num(0, 0),
|
|
401
|
+
deltaN0: num(0, 2),
|
|
402
|
+
deltaN0Dot: num(4, 1),
|
|
403
|
+
m0: num(0, 3),
|
|
404
|
+
e: num(1, 1),
|
|
405
|
+
omega: num(3, 2),
|
|
406
|
+
omega0: num(2, 2),
|
|
407
|
+
i0: num(3, 0),
|
|
408
|
+
omegaDot,
|
|
409
|
+
deltaOmegaDot: omegaDot - CNAV_OMEGA_DOT_REF * GPS_PI,
|
|
410
|
+
i0Dot: num(4, 0),
|
|
411
|
+
cis: num(2, 3),
|
|
412
|
+
cic: num(2, 1),
|
|
413
|
+
crs: num(0, 1),
|
|
414
|
+
crc: num(3, 1),
|
|
415
|
+
cus: num(1, 2),
|
|
416
|
+
cuc: num(1, 0),
|
|
417
|
+
toc,
|
|
418
|
+
tocDate: date,
|
|
419
|
+
af0: epochVals[0] ?? 0,
|
|
420
|
+
af1: epochVals[1] ?? 0,
|
|
421
|
+
af2: epochVals[2] ?? 0,
|
|
422
|
+
clockMsgType: 0,
|
|
423
|
+
// not recorded in RINEX
|
|
424
|
+
tgd: opt(5, 2),
|
|
425
|
+
iscL1ca: opt(6, 0),
|
|
426
|
+
iscL2c: opt(6, 1),
|
|
427
|
+
iscL5i5: opt(6, 2),
|
|
428
|
+
iscL5q5: opt(6, 3),
|
|
429
|
+
...wnOp != null && { wnOp },
|
|
430
|
+
integrityFlag: false,
|
|
431
|
+
// not recorded in RINEX
|
|
432
|
+
l2cPhasing: false,
|
|
433
|
+
// not recorded in RINEX
|
|
434
|
+
tow: num(7, 0)
|
|
435
|
+
};
|
|
436
|
+
}
|
|
353
437
|
function parseNavFile(text) {
|
|
354
438
|
const lines = text.split("\n");
|
|
355
439
|
const header = {
|
|
@@ -359,6 +443,7 @@ function parseNavFile(text) {
|
|
|
359
443
|
ionoCorrections: {}
|
|
360
444
|
};
|
|
361
445
|
const ephemerides = [];
|
|
446
|
+
const cnav = [];
|
|
362
447
|
let inHeader = true;
|
|
363
448
|
let i = 0;
|
|
364
449
|
while (i < lines.length) {
|
|
@@ -419,8 +504,15 @@ function parseNavFile(text) {
|
|
|
419
504
|
if (isV4 && line.charAt(0) === ">") {
|
|
420
505
|
const parts = line.substring(2).trim().split(/\s+/);
|
|
421
506
|
const recType = parts[0] ?? "";
|
|
507
|
+
const svSys = (parts[1] ?? "").charAt(0);
|
|
422
508
|
const msgType = parts[2] ?? recType;
|
|
423
|
-
if (recType !== "EPH"
|
|
509
|
+
if (recType !== "EPH") {
|
|
510
|
+
const totalLines = recType === "STO" ? 2 : recType === "EOP" ? 3 : recType === "ION" ? svSys === "E" ? 2 : 3 : 2;
|
|
511
|
+
i += totalLines + 1;
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
const isCnav = msgType === "CNAV" && (svSys === "G" || svSys === "J");
|
|
515
|
+
if (!SUPPORTED_EPH_MSGS.has(msgType) && !isCnav) {
|
|
424
516
|
const totalLines = R4_MSG_LINES[msgType] ?? 2;
|
|
425
517
|
i += totalLines + 1;
|
|
426
518
|
continue;
|
|
@@ -432,6 +524,21 @@ function parseNavFile(text) {
|
|
|
432
524
|
const sys2 = epochLine.charAt(0);
|
|
433
525
|
const parsed = parseNavEpochV3(epochLine);
|
|
434
526
|
const prn2 = `${sys2}${parsed.prn.substring(1)}`;
|
|
527
|
+
if (isCnav) {
|
|
528
|
+
const slotLines = [];
|
|
529
|
+
for (let j = 0; j < numDataLines2; j++) {
|
|
530
|
+
i++;
|
|
531
|
+
if (i >= lines.length) break;
|
|
532
|
+
slotLines.push(parseDataLineSlots(lines[i]));
|
|
533
|
+
}
|
|
534
|
+
if (slotLines.length === numDataLines2 && (sys2 === "G" || sys2 === "J")) {
|
|
535
|
+
cnav.push(
|
|
536
|
+
buildCnavEphemeris(sys2, prn2, parsed.date, parsed.values, slotLines)
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
i++;
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
435
542
|
const dataLines2 = [];
|
|
436
543
|
for (let j = 0; j < numDataLines2; j++) {
|
|
437
544
|
i++;
|
|
@@ -505,7 +612,7 @@ function parseNavFile(text) {
|
|
|
505
612
|
}
|
|
506
613
|
i++;
|
|
507
614
|
}
|
|
508
|
-
return { header, ephemerides };
|
|
615
|
+
return cnav.length > 0 ? { header, ephemerides, cnav } : { header, ephemerides };
|
|
509
616
|
}
|
|
510
617
|
|
|
511
618
|
// src/rinex/nav-writer.ts
|
|
@@ -513,9 +620,13 @@ function fmtD(val) {
|
|
|
513
620
|
if (val === 0) return " 0.000000000000E+00";
|
|
514
621
|
const sign = val < 0 ? "-" : " ";
|
|
515
622
|
const abs = Math.abs(val);
|
|
516
|
-
|
|
623
|
+
let exp = Math.floor(Math.log10(abs));
|
|
517
624
|
const mantissa = abs / 10 ** exp;
|
|
518
|
-
|
|
625
|
+
let mStr = mantissa.toFixed(12);
|
|
626
|
+
if (mStr.length > 14) {
|
|
627
|
+
exp += 1;
|
|
628
|
+
mStr = (mantissa / 10).toFixed(12);
|
|
629
|
+
}
|
|
519
630
|
const expSign = exp >= 0 ? "+" : "-";
|
|
520
631
|
const expStr = String(Math.abs(exp)).padStart(2, "0");
|
|
521
632
|
return `${sign}${mStr}E${expSign}${expStr}`;
|
|
@@ -590,7 +701,7 @@ function writeKeplerRecord(eph) {
|
|
|
590
701
|
function writeGlonassRecord(eph) {
|
|
591
702
|
const lines = [];
|
|
592
703
|
lines.push(
|
|
593
|
-
`${padL(eph.prn, 3)} ${fmtEpoch(eph.tocDate)}${fmtD(
|
|
704
|
+
`${padL(eph.prn, 3)} ${fmtEpoch(eph.tocDate)}${fmtD(eph.tauN)}${fmtD(eph.gammaN)}${fmtD(eph.messageFrameTime)}`
|
|
594
705
|
);
|
|
595
706
|
lines.push(orbitLine([eph.x, eph.xDot, eph.xAcc, eph.health]));
|
|
596
707
|
lines.push(orbitLine([eph.y, eph.yDot, eph.yAcc, eph.freqNum]));
|
|
@@ -610,6 +721,181 @@ function writeRinexNav(nav) {
|
|
|
610
721
|
return header + records.join("\n") + "\n";
|
|
611
722
|
}
|
|
612
723
|
|
|
724
|
+
// src/rinex/nav-writer-v4.ts
|
|
725
|
+
var BLANK19 = " ".repeat(19);
|
|
726
|
+
function fmtEpoch4(d) {
|
|
727
|
+
const p2 = (v) => String(v).padStart(2, "0");
|
|
728
|
+
return `${d.getUTCFullYear()} ${p2(d.getUTCMonth() + 1)} ${p2(d.getUTCDate())} ${p2(d.getUTCHours())} ${p2(d.getUTCMinutes())} ${p2(d.getUTCSeconds())}`;
|
|
729
|
+
}
|
|
730
|
+
function orbitLine4(values) {
|
|
731
|
+
const line = " " + values.map((v) => v == null ? BLANK19 : fmtD(v)).join("");
|
|
732
|
+
return line.replace(/ +$/, "");
|
|
733
|
+
}
|
|
734
|
+
function epochLine4(prn, date, vals) {
|
|
735
|
+
return `${padL(prn, 3)} ${fmtEpoch4(date)}${vals.map(fmtD).join("")}`;
|
|
736
|
+
}
|
|
737
|
+
var BDS_GEO = /* @__PURE__ */ new Set([
|
|
738
|
+
"C01",
|
|
739
|
+
"C02",
|
|
740
|
+
"C03",
|
|
741
|
+
"C04",
|
|
742
|
+
"C05",
|
|
743
|
+
"C59",
|
|
744
|
+
"C60",
|
|
745
|
+
"C61",
|
|
746
|
+
"C62",
|
|
747
|
+
"C63"
|
|
748
|
+
]);
|
|
749
|
+
function msgLabel(eph) {
|
|
750
|
+
switch (eph.system) {
|
|
751
|
+
case "E":
|
|
752
|
+
return "INAV";
|
|
753
|
+
case "C":
|
|
754
|
+
return BDS_GEO.has(eph.prn) ? "D2" : "D1";
|
|
755
|
+
case "R":
|
|
756
|
+
return "FDMA";
|
|
757
|
+
case "S":
|
|
758
|
+
return "SBAS";
|
|
759
|
+
default:
|
|
760
|
+
return "LNAV";
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
function isKepler2(eph) {
|
|
764
|
+
return "af0" in eph;
|
|
765
|
+
}
|
|
766
|
+
function keplerRecord(eph) {
|
|
767
|
+
return [
|
|
768
|
+
epochLine4(eph.prn, eph.tocDate, [eph.af0, eph.af1, eph.af2]),
|
|
769
|
+
orbitLine4([eph.iode, eph.crs, eph.deltaN, eph.m0]),
|
|
770
|
+
orbitLine4([eph.cuc, eph.e, eph.cus, eph.sqrtA]),
|
|
771
|
+
orbitLine4([eph.toe, eph.cic, eph.omega0, eph.cis]),
|
|
772
|
+
orbitLine4([eph.i0, eph.crc, eph.omega, eph.omegaDot]),
|
|
773
|
+
orbitLine4([eph.idot, 0, eph.week, 0]),
|
|
774
|
+
orbitLine4([0, eph.svHealth, eph.tgd, 0]),
|
|
775
|
+
orbitLine4([eph.toe, 0, 0, 0])
|
|
776
|
+
].join("\n");
|
|
777
|
+
}
|
|
778
|
+
function stateVectorRecord(eph) {
|
|
779
|
+
const lines = [
|
|
780
|
+
epochLine4(eph.prn, eph.tocDate, [
|
|
781
|
+
eph.tauN,
|
|
782
|
+
eph.gammaN,
|
|
783
|
+
eph.messageFrameTime
|
|
784
|
+
]),
|
|
785
|
+
orbitLine4([eph.x, eph.xDot, eph.xAcc, eph.health]),
|
|
786
|
+
orbitLine4([eph.y, eph.yDot, eph.yAcc, eph.freqNum]),
|
|
787
|
+
orbitLine4([eph.z, eph.zDot, eph.zAcc, 0])
|
|
788
|
+
];
|
|
789
|
+
if (eph.system === "R") {
|
|
790
|
+
lines.push(orbitLine4([null, 999999999999e-3, 15, null]));
|
|
791
|
+
}
|
|
792
|
+
return lines.join("\n");
|
|
793
|
+
}
|
|
794
|
+
function resolveWnOp(week, wnOp) {
|
|
795
|
+
if (wnOp == null) return week;
|
|
796
|
+
return week - ((week - wnOp) % 256 + 256) % 256;
|
|
797
|
+
}
|
|
798
|
+
function cnavRecord(eph) {
|
|
799
|
+
return [
|
|
800
|
+
epochLine4(eph.prn, eph.tocDate, [eph.af0, eph.af1, eph.af2]),
|
|
801
|
+
orbitLine4([eph.aDot, eph.crs, eph.deltaN0, eph.m0]),
|
|
802
|
+
orbitLine4([eph.cuc, eph.e, eph.cus, Math.sqrt(eph.a)]),
|
|
803
|
+
orbitLine4([eph.top, eph.cic, eph.omega0, eph.cis]),
|
|
804
|
+
orbitLine4([eph.i0, eph.crc, eph.omega, eph.omegaDot]),
|
|
805
|
+
orbitLine4([eph.i0Dot, eph.deltaN0Dot, eph.uraNed0, eph.uraNed1]),
|
|
806
|
+
orbitLine4([eph.uraEd, eph.health, eph.tgd, eph.uraNed2]),
|
|
807
|
+
orbitLine4([eph.iscL1ca, eph.iscL2c, eph.iscL5i5, eph.iscL5q5]),
|
|
808
|
+
orbitLine4([eph.tow, resolveWnOp(eph.week, eph.wnOp)])
|
|
809
|
+
].join("\n");
|
|
810
|
+
}
|
|
811
|
+
var KLOBUCHAR_SOURCES = [
|
|
812
|
+
["GPSA", "GPSB", "G", "LNAV"],
|
|
813
|
+
["QZSA", "QZSB", "J", "LNAV"],
|
|
814
|
+
["BDSA", "BDSB", "C", "D1D2"],
|
|
815
|
+
["IRNA", "IRNB", "I", "LNAV"]
|
|
816
|
+
];
|
|
817
|
+
function ionRecords(header, epoch) {
|
|
818
|
+
const records = [];
|
|
819
|
+
const iono = header.ionoCorrections;
|
|
820
|
+
for (const [alphaKey, betaKey, sys, msg] of KLOBUCHAR_SOURCES) {
|
|
821
|
+
const alpha = iono[alphaKey];
|
|
822
|
+
if (!alpha) continue;
|
|
823
|
+
const beta = iono[betaKey] ?? [0, 0, 0, 0];
|
|
824
|
+
records.push(
|
|
825
|
+
[
|
|
826
|
+
`> ION ${sys} ${msg}`,
|
|
827
|
+
` ${fmtEpoch4(epoch)}${[alpha[0] ?? 0, alpha[1] ?? 0, alpha[2] ?? 0].map(fmtD).join("")}`,
|
|
828
|
+
orbitLine4([alpha[3] ?? 0, beta[0] ?? 0, beta[1] ?? 0, beta[2] ?? 0]),
|
|
829
|
+
orbitLine4([beta[3] ?? 0, null])
|
|
830
|
+
].join("\n")
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
const gal = iono["GAL"];
|
|
834
|
+
if (gal) {
|
|
835
|
+
records.push(
|
|
836
|
+
[
|
|
837
|
+
"> ION E IFNV",
|
|
838
|
+
` ${fmtEpoch4(epoch)}${[gal[0] ?? 0, gal[1] ?? 0, gal[2] ?? 0].map(fmtD).join("")}`,
|
|
839
|
+
orbitLine4([gal[3] ?? 0])
|
|
840
|
+
].join("\n")
|
|
841
|
+
);
|
|
842
|
+
}
|
|
843
|
+
return records;
|
|
844
|
+
}
|
|
845
|
+
function writeHeader4(header) {
|
|
846
|
+
const lines = [];
|
|
847
|
+
lines.push(
|
|
848
|
+
hdrLine(
|
|
849
|
+
padL(" 4.01", 9) + " " + padL("NAVIGATION DATA", 20) + padL("M", 20),
|
|
850
|
+
"RINEX VERSION / TYPE"
|
|
851
|
+
)
|
|
852
|
+
);
|
|
853
|
+
const now = /* @__PURE__ */ new Date();
|
|
854
|
+
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";
|
|
855
|
+
lines.push(
|
|
856
|
+
hdrLine(
|
|
857
|
+
padL("GNSSCalc", 20) + padL("", 20) + padL(dateStr, 20),
|
|
858
|
+
"PGM / RUN BY / DATE"
|
|
859
|
+
)
|
|
860
|
+
);
|
|
861
|
+
if (header.leapSeconds != null) {
|
|
862
|
+
lines.push(hdrLine(padR(String(header.leapSeconds), 6), "LEAP SECONDS"));
|
|
863
|
+
}
|
|
864
|
+
lines.push(hdrLine("", "END OF HEADER"));
|
|
865
|
+
return lines.join("\n") + "\n";
|
|
866
|
+
}
|
|
867
|
+
function writeRinexNav4(nav) {
|
|
868
|
+
const records = [];
|
|
869
|
+
for (const eph of nav.ephemerides) {
|
|
870
|
+
const label = msgLabel(eph);
|
|
871
|
+
records.push({
|
|
872
|
+
prn: eph.prn,
|
|
873
|
+
time: eph.tocDate.getTime(),
|
|
874
|
+
label,
|
|
875
|
+
body: `> EPH ${padL(eph.prn, 3)} ${label}
|
|
876
|
+
` + (isKepler2(eph) ? keplerRecord(eph) : stateVectorRecord(eph))
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
for (const eph of nav.cnav ?? []) {
|
|
880
|
+
records.push({
|
|
881
|
+
prn: eph.prn,
|
|
882
|
+
time: eph.tocDate.getTime(),
|
|
883
|
+
label: "CNAV",
|
|
884
|
+
body: `> EPH ${padL(eph.prn, 3)} CNAV
|
|
885
|
+
` + cnavRecord(eph)
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
records.sort(
|
|
889
|
+
(a, b) => a.prn.localeCompare(b.prn) || a.time - b.time || a.label.localeCompare(b.label)
|
|
890
|
+
);
|
|
891
|
+
const bodies = records.map((r) => r.body);
|
|
892
|
+
if (records.length > 0) {
|
|
893
|
+
const earliest = new Date(Math.min(...records.map((r) => r.time)));
|
|
894
|
+
bodies.push(...ionRecords(nav.header, earliest));
|
|
895
|
+
}
|
|
896
|
+
return writeHeader4(nav.header) + (bodies.length > 0 ? bodies.join("\n") + "\n" : "");
|
|
897
|
+
}
|
|
898
|
+
|
|
613
899
|
// src/rinex/ionex.ts
|
|
614
900
|
function gridRange(l1, l2, dl) {
|
|
615
901
|
const out = [];
|
|
@@ -1193,7 +1479,9 @@ export {
|
|
|
1193
1479
|
EMPTY_WARNINGS,
|
|
1194
1480
|
WarningAccumulator,
|
|
1195
1481
|
parseNavFile,
|
|
1482
|
+
fmtD,
|
|
1196
1483
|
writeRinexNav,
|
|
1484
|
+
writeRinexNav4,
|
|
1197
1485
|
parseIonex,
|
|
1198
1486
|
parseSp3,
|
|
1199
1487
|
sp3Position,
|