gnss-js 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -23
- package/dist/analysis.cjs +130 -28
- package/dist/analysis.d.cts +43 -3
- package/dist/analysis.d.ts +43 -3
- package/dist/analysis.js +5 -1
- package/dist/{chunk-PQYBTE42.js → chunk-CD5YSYCG.js} +11 -17
- package/dist/{chunk-65CQINSB.js → chunk-FGRC3PB3.js} +6 -2
- package/dist/{chunk-PX7TPPTQ.js → chunk-SOJNWF5T.js} +1 -1
- package/dist/{chunk-EJQ6NG5U.js → chunk-Z5UZUNCB.js} +126 -26
- package/dist/index.cjs +145 -45
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8 -4
- package/dist/orbit.cjs +11 -17
- package/dist/orbit.d.cts +1 -1
- package/dist/orbit.d.ts +1 -1
- package/dist/orbit.js +1 -1
- package/dist/positioning.cjs +2 -0
- package/dist/positioning.js +2 -2
- package/dist/rtcm3.cjs +6 -2
- package/dist/rtcm3.js +1 -1
- package/package.json +7 -7
|
@@ -13,16 +13,22 @@ import {
|
|
|
13
13
|
getFreq
|
|
14
14
|
} from "./chunk-FIEWO4J4.js";
|
|
15
15
|
|
|
16
|
-
// src/analysis/
|
|
16
|
+
// src/analysis/stats-util.ts
|
|
17
17
|
var MIN_ARC_LENGTH = 10;
|
|
18
|
-
var MP_JUMP_M = 1.25;
|
|
19
|
-
var MP_JUMP_WINDOW = 5;
|
|
20
|
-
var MP_EDIT_SIGMA = 3;
|
|
21
18
|
function median(values) {
|
|
22
19
|
const s = [...values].sort((a, b) => a - b);
|
|
23
20
|
const m = s.length >> 1;
|
|
24
21
|
return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
|
|
25
22
|
}
|
|
23
|
+
function percentile(values, p) {
|
|
24
|
+
const s = [...values].sort((a, b) => a - b);
|
|
25
|
+
return s[Math.min(s.length - 1, Math.floor(p * s.length))] ?? 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/analysis/multipath.ts
|
|
29
|
+
var MP_JUMP_M = 1.25;
|
|
30
|
+
var MP_JUMP_WINDOW = 5;
|
|
31
|
+
var MP_EDIT_SIGMA = 3;
|
|
26
32
|
var MultipathAccumulator = class {
|
|
27
33
|
state = /* @__PURE__ */ new Map();
|
|
28
34
|
results = [];
|
|
@@ -503,15 +509,10 @@ var CompletenessAccumulator = class {
|
|
|
503
509
|
// src/analysis/ionosphere.ts
|
|
504
510
|
var TEC_FACTOR = 403e15;
|
|
505
511
|
var GF_JUMP_M = 0.15;
|
|
506
|
-
var MIN_ARC_LENGTH2 = 10;
|
|
507
|
-
function median2(values) {
|
|
508
|
-
const s = [...values].sort((a, b) => a - b);
|
|
509
|
-
const m = s.length >> 1;
|
|
510
|
-
return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
|
|
511
|
-
}
|
|
512
512
|
var IonoAccumulator = class {
|
|
513
513
|
state = /* @__PURE__ */ new Map();
|
|
514
514
|
closed = /* @__PURE__ */ new Map();
|
|
515
|
+
closedArcStarts = /* @__PURE__ */ new Map();
|
|
515
516
|
interval;
|
|
516
517
|
obsIndices;
|
|
517
518
|
gloChannels;
|
|
@@ -611,8 +612,8 @@ var IonoAccumulator = class {
|
|
|
611
612
|
}
|
|
612
613
|
closeArc(prn, pairKey, ps) {
|
|
613
614
|
const arc = ps.arc;
|
|
614
|
-
if (arc.times.length >=
|
|
615
|
-
const level =
|
|
615
|
+
if (arc.times.length >= MIN_ARC_LENGTH) {
|
|
616
|
+
const level = median(arc.l4.map((v, k) => v - arc.p4[k]));
|
|
616
617
|
const toTecu = arc.fi * arc.fi / TEC_FACTOR / (arc.gamma - 1);
|
|
617
618
|
let satArcs = this.closed.get(prn);
|
|
618
619
|
if (!satArcs) {
|
|
@@ -624,6 +625,17 @@ var IonoAccumulator = class {
|
|
|
624
625
|
points = [];
|
|
625
626
|
satArcs.set(pairKey, points);
|
|
626
627
|
}
|
|
628
|
+
let satStarts = this.closedArcStarts.get(prn);
|
|
629
|
+
if (!satStarts) {
|
|
630
|
+
satStarts = /* @__PURE__ */ new Map();
|
|
631
|
+
this.closedArcStarts.set(prn, satStarts);
|
|
632
|
+
}
|
|
633
|
+
let starts = satStarts.get(pairKey);
|
|
634
|
+
if (!starts) {
|
|
635
|
+
starts = [];
|
|
636
|
+
satStarts.set(pairKey, starts);
|
|
637
|
+
}
|
|
638
|
+
starts.push(points.length);
|
|
627
639
|
for (let k = 0; k < arc.times.length; k++) {
|
|
628
640
|
points.push({
|
|
629
641
|
time: arc.times[k],
|
|
@@ -643,7 +655,7 @@ var IonoAccumulator = class {
|
|
|
643
655
|
const series = [];
|
|
644
656
|
let sum = 0;
|
|
645
657
|
let count = 0;
|
|
646
|
-
let maxStec =
|
|
658
|
+
let maxStec = -Infinity;
|
|
647
659
|
for (const [prn, satArcs] of this.closed) {
|
|
648
660
|
let bestKey = null;
|
|
649
661
|
let bestLen = 0;
|
|
@@ -655,7 +667,7 @@ var IonoAccumulator = class {
|
|
|
655
667
|
}
|
|
656
668
|
if (!bestKey) continue;
|
|
657
669
|
const points = satArcs.get(bestKey);
|
|
658
|
-
|
|
670
|
+
const arcStarts = this.closedArcStarts.get(prn)?.get(bestKey) ?? [0];
|
|
659
671
|
const sys = prn[0];
|
|
660
672
|
for (const p of points) {
|
|
661
673
|
sum += p.stec;
|
|
@@ -670,21 +682,107 @@ var IonoAccumulator = class {
|
|
|
670
682
|
label: this.pairLabel.get(`${sys}:${bestKey}`) ?? bestKey,
|
|
671
683
|
codes: this.pairCodes.get(`${sys}:${bestKey}`) ?? ["", ""],
|
|
672
684
|
tecuPerNs,
|
|
673
|
-
points
|
|
685
|
+
points,
|
|
686
|
+
arcStarts
|
|
674
687
|
});
|
|
675
688
|
}
|
|
676
689
|
series.sort((a, b) => a.prn.localeCompare(b.prn));
|
|
677
|
-
return {
|
|
690
|
+
return {
|
|
691
|
+
series,
|
|
692
|
+
maxStec: count > 0 ? maxStec : 0,
|
|
693
|
+
meanStec: count > 0 ? sum / count : 0
|
|
694
|
+
};
|
|
678
695
|
}
|
|
679
696
|
};
|
|
697
|
+
function computeIonoRate(result, intervalSec, order = 1) {
|
|
698
|
+
const out = [];
|
|
699
|
+
for (const s of result.series) {
|
|
700
|
+
const pts = [];
|
|
701
|
+
const bounds = [...s.arcStarts, s.points.length];
|
|
702
|
+
for (let a = 0; a < bounds.length - 1; a++) {
|
|
703
|
+
const lo = bounds[a];
|
|
704
|
+
const hi = bounds[a + 1];
|
|
705
|
+
if (order === 2) {
|
|
706
|
+
for (let i = lo + 2; i < hi; i++) {
|
|
707
|
+
const dt1 = s.points[i - 1].time - s.points[i - 2].time;
|
|
708
|
+
const dt2 = s.points[i].time - s.points[i - 1].time;
|
|
709
|
+
if (Math.abs(dt1 - dt2) > 0.1 * Math.max(dt1, dt2)) continue;
|
|
710
|
+
pts.push({
|
|
711
|
+
time: s.points[i].time,
|
|
712
|
+
value: s.points[i].stec - 2 * s.points[i - 1].stec + s.points[i - 2].stec
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
717
|
+
if (intervalSec === void 0) {
|
|
718
|
+
for (let i = lo + 1; i < hi; i++) {
|
|
719
|
+
const dtMin = (s.points[i].time - s.points[i - 1].time) / 6e4;
|
|
720
|
+
if (dtMin <= 0) continue;
|
|
721
|
+
pts.push({
|
|
722
|
+
time: s.points[i].time,
|
|
723
|
+
value: (s.points[i].stec - s.points[i - 1].stec) / dtMin
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
} else {
|
|
727
|
+
const targetMs = intervalSec * 1e3;
|
|
728
|
+
let j = lo;
|
|
729
|
+
for (let i = lo; i < hi; i++) {
|
|
730
|
+
if (j <= i) j = i + 1;
|
|
731
|
+
while (j < hi && s.points[j].time - s.points[i].time < targetMs)
|
|
732
|
+
j++;
|
|
733
|
+
if (j >= hi) break;
|
|
734
|
+
const dtMs = s.points[j].time - s.points[i].time;
|
|
735
|
+
if (dtMs > 1.5 * targetMs) continue;
|
|
736
|
+
pts.push({
|
|
737
|
+
time: s.points[j].time,
|
|
738
|
+
value: (s.points[j].stec - s.points[i].stec) / dtMs * 6e4
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
if (pts.length > 0) out.push({ prn: s.prn, system: s.system, points: pts });
|
|
744
|
+
}
|
|
745
|
+
return out;
|
|
746
|
+
}
|
|
747
|
+
function detrendIonoArcs(result) {
|
|
748
|
+
let sum = 0;
|
|
749
|
+
let count = 0;
|
|
750
|
+
let maxStec = -Infinity;
|
|
751
|
+
const series = result.series.map((s) => {
|
|
752
|
+
const bounds = [...s.arcStarts, s.points.length];
|
|
753
|
+
const points = new Array(s.points.length);
|
|
754
|
+
for (let a = 0; a < bounds.length - 1; a++) {
|
|
755
|
+
const lo = bounds[a];
|
|
756
|
+
const hi = bounds[a + 1];
|
|
757
|
+
const anchor = s.points[lo]?.stec ?? 0;
|
|
758
|
+
for (let i = lo; i < hi; i++) {
|
|
759
|
+
points[i] = {
|
|
760
|
+
time: s.points[i].time,
|
|
761
|
+
stec: s.points[i].stec - anchor
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
for (const p of points) {
|
|
766
|
+
sum += p.stec;
|
|
767
|
+
count++;
|
|
768
|
+
if (p.stec > maxStec) maxStec = p.stec;
|
|
769
|
+
}
|
|
770
|
+
return { ...s, points };
|
|
771
|
+
});
|
|
772
|
+
return {
|
|
773
|
+
series,
|
|
774
|
+
maxStec: count > 0 ? maxStec : 0,
|
|
775
|
+
meanStec: count > 0 ? sum / count : 0
|
|
776
|
+
};
|
|
777
|
+
}
|
|
680
778
|
|
|
681
779
|
// src/analysis/dcb.ts
|
|
682
780
|
var PRN_RE = /^[A-Z]\d{2}$/;
|
|
683
781
|
var SVN_RE = /^[A-Z]\d{3}$/;
|
|
684
782
|
var OBS_RE = /^[CL]\d[A-Z]$/;
|
|
685
|
-
function sinexEpochMs(s) {
|
|
783
|
+
function sinexEpochMs(s, openValue) {
|
|
686
784
|
const [y, d, sec] = s.split(":").map(Number);
|
|
687
|
-
if (!y) return
|
|
785
|
+
if (!y) return openValue;
|
|
688
786
|
return Date.UTC(y, 0, 1) + ((d ?? 1) - 1) * 864e5 + (sec ?? 0) * 1e3;
|
|
689
787
|
}
|
|
690
788
|
function parseSinexBiasDcb(text, epochMs) {
|
|
@@ -699,8 +797,8 @@ function parseSinexBiasDcb(text, epochMs) {
|
|
|
699
797
|
if (unitIdx < 0 || unitIdx + 1 >= t.length) continue;
|
|
700
798
|
const value = parseFloat(t[unitIdx + 1]);
|
|
701
799
|
if (!isFinite(value)) continue;
|
|
702
|
-
const start = sinexEpochMs(t[5] ?? "");
|
|
703
|
-
const end = sinexEpochMs(t[6] ?? "");
|
|
800
|
+
const start = sinexEpochMs(t[5] ?? "", -Infinity);
|
|
801
|
+
const end = sinexEpochMs(t[6] ?? "", Infinity);
|
|
704
802
|
const covers = epochMs !== void 0 && epochMs >= start && epochMs < end;
|
|
705
803
|
const prn = t[2];
|
|
706
804
|
const pair = `${t[3]}-${t[4]}`;
|
|
@@ -722,10 +820,6 @@ function parseSinexBiasDcb(text, epochMs) {
|
|
|
722
820
|
}
|
|
723
821
|
return out;
|
|
724
822
|
}
|
|
725
|
-
function percentile(values, p) {
|
|
726
|
-
const s = [...values].sort((a, b) => a - b);
|
|
727
|
-
return s[Math.min(s.length - 1, Math.floor(p * s.length))] ?? 0;
|
|
728
|
-
}
|
|
729
823
|
function applyIonoDcb(iono, satDcb) {
|
|
730
824
|
const missing = [];
|
|
731
825
|
let corrected = 0;
|
|
@@ -789,7 +883,7 @@ function applyIonoDcb(iono, satDcb) {
|
|
|
789
883
|
out.sort((a, b) => a.prn.localeCompare(b.prn));
|
|
790
884
|
let sum = 0;
|
|
791
885
|
let count = 0;
|
|
792
|
-
let maxStec =
|
|
886
|
+
let maxStec = -Infinity;
|
|
793
887
|
for (const s of out) {
|
|
794
888
|
for (const p of s.points) {
|
|
795
889
|
sum += p.stec;
|
|
@@ -798,7 +892,11 @@ function applyIonoDcb(iono, satDcb) {
|
|
|
798
892
|
}
|
|
799
893
|
}
|
|
800
894
|
return {
|
|
801
|
-
result: {
|
|
895
|
+
result: {
|
|
896
|
+
series: out,
|
|
897
|
+
maxStec: count > 0 ? maxStec : 0,
|
|
898
|
+
meanStec: count > 0 ? sum / count : 0
|
|
899
|
+
},
|
|
802
900
|
satellitesCorrected: corrected,
|
|
803
901
|
satellitesMissing: [...new Set(missing)].sort(),
|
|
804
902
|
receiverDcbTecu
|
|
@@ -840,6 +938,8 @@ export {
|
|
|
840
938
|
CycleSlipAccumulator,
|
|
841
939
|
CompletenessAccumulator,
|
|
842
940
|
IonoAccumulator,
|
|
941
|
+
computeIonoRate,
|
|
942
|
+
detrendIonoArcs,
|
|
843
943
|
parseSinexBiasDcb,
|
|
844
944
|
applyIonoDcb,
|
|
845
945
|
analyzeQuality
|
package/dist/index.cjs
CHANGED
|
@@ -111,6 +111,7 @@ __export(src_exports, {
|
|
|
111
111
|
clampUnit: () => clampUnit,
|
|
112
112
|
computeAllPositions: () => computeAllPositions,
|
|
113
113
|
computeDop: () => computeDop,
|
|
114
|
+
computeIonoRate: () => computeIonoRate,
|
|
114
115
|
computeLiveSkyPositions: () => computeLiveSkyPositions,
|
|
115
116
|
computePsdDb: () => computePsdDb,
|
|
116
117
|
computeSatPosition: () => computeSatPosition,
|
|
@@ -126,6 +127,7 @@ __export(src_exports, {
|
|
|
126
127
|
decodeMsmFull: () => decodeMsmFull,
|
|
127
128
|
deg2dms: () => deg2dms,
|
|
128
129
|
deg2rad: () => deg2rad,
|
|
130
|
+
detrendIonoArcs: () => detrendIonoArcs,
|
|
129
131
|
ecefToAzEl: () => ecefToAzEl,
|
|
130
132
|
ecefToGeodetic: () => ecefToGeodetic,
|
|
131
133
|
ephInfoToEphemeris: () => ephInfoToEphemeris,
|
|
@@ -3906,6 +3908,11 @@ function rtcm3Constellation(msgType) {
|
|
|
3906
3908
|
if (msgType >= 1111 && msgType <= 1117) return "QZSS";
|
|
3907
3909
|
if (msgType >= 1121 && msgType <= 1127) return "BeiDou";
|
|
3908
3910
|
if (msgType >= 1131 && msgType <= 1137) return "NavIC";
|
|
3911
|
+
if (msgType >= 1015 && msgType <= 1017) return "GPS";
|
|
3912
|
+
if (msgType === 1030) return "GPS";
|
|
3913
|
+
if (msgType === 1031) return "GLONASS";
|
|
3914
|
+
if (msgType >= 1057 && msgType <= 1062) return "GPS";
|
|
3915
|
+
if (msgType >= 1063 && msgType <= 1068) return "GLONASS";
|
|
3909
3916
|
if (msgType === 1230) return "GLONASS";
|
|
3910
3917
|
return null;
|
|
3911
3918
|
}
|
|
@@ -3945,7 +3952,6 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
3945
3952
|
entry.totalBytes += frame.length + 6;
|
|
3946
3953
|
const msmEpoch = decodeMsmFull(frame);
|
|
3947
3954
|
if (msmEpoch) {
|
|
3948
|
-
const now2 = Date.now();
|
|
3949
3955
|
for (const obs of msmEpoch.observations) {
|
|
3950
3956
|
const signals = [];
|
|
3951
3957
|
let bestCn0 = 0;
|
|
@@ -3960,7 +3966,7 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
3960
3966
|
prn: obs.prn,
|
|
3961
3967
|
system: obs.system,
|
|
3962
3968
|
cn0: bestCn0,
|
|
3963
|
-
lastSeen:
|
|
3969
|
+
lastSeen: now,
|
|
3964
3970
|
signals
|
|
3965
3971
|
});
|
|
3966
3972
|
}
|
|
@@ -4203,20 +4209,10 @@ function invert4x4(m) {
|
|
|
4203
4209
|
return result;
|
|
4204
4210
|
}
|
|
4205
4211
|
function selectEphemeris(ephemerides, prn, timeMs) {
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
const ephTime = eph.tocDate.getTime();
|
|
4211
|
-
const dt = Math.abs(timeMs - ephTime);
|
|
4212
|
-
const maxAge = eph.system === "R" || eph.system === "S" ? 18e5 : 4 * 36e5;
|
|
4213
|
-
if (dt > maxAge) continue;
|
|
4214
|
-
if (dt < bestDt) {
|
|
4215
|
-
bestDt = dt;
|
|
4216
|
-
best = eph;
|
|
4217
|
-
}
|
|
4218
|
-
}
|
|
4219
|
-
return best;
|
|
4212
|
+
return selectBest(
|
|
4213
|
+
ephemerides.filter((e) => e.prn === prn),
|
|
4214
|
+
timeMs
|
|
4215
|
+
);
|
|
4220
4216
|
}
|
|
4221
4217
|
function computeSatPosition(eph, timeMs) {
|
|
4222
4218
|
if (eph.system === "R" || eph.system === "S") {
|
|
@@ -4309,8 +4305,9 @@ function selectBest(ephs, timeMs) {
|
|
|
4309
4305
|
return best;
|
|
4310
4306
|
}
|
|
4311
4307
|
var GPS_EPOCH_MS = START_GPS_TIME.getTime();
|
|
4308
|
+
var MS_PER_WEEK2 = 7 * 864e5;
|
|
4312
4309
|
var BDS_EPOCH_MS = START_BDS_TIME.getTime();
|
|
4313
|
-
var GAL_EPOCH_MS = GPS_EPOCH_MS;
|
|
4310
|
+
var GAL_EPOCH_MS = GPS_EPOCH_MS + 1024 * MS_PER_WEEK2;
|
|
4314
4311
|
function ephInfoToEphemeris(info) {
|
|
4315
4312
|
const sys = info.prn.charAt(0);
|
|
4316
4313
|
if (sys === "R") {
|
|
@@ -4354,6 +4351,7 @@ function ephInfoToEphemeris(info) {
|
|
|
4354
4351
|
return null;
|
|
4355
4352
|
}
|
|
4356
4353
|
let epochMs;
|
|
4354
|
+
let week = info.week;
|
|
4357
4355
|
const tocSec = info.toc ?? info.toe;
|
|
4358
4356
|
if (sys === "C") {
|
|
4359
4357
|
epochMs = BDS_EPOCH_MS;
|
|
@@ -4361,8 +4359,10 @@ function ephInfoToEphemeris(info) {
|
|
|
4361
4359
|
epochMs = GAL_EPOCH_MS;
|
|
4362
4360
|
} else {
|
|
4363
4361
|
epochMs = GPS_EPOCH_MS;
|
|
4362
|
+
const weeksNow = (info.lastReceived - GPS_EPOCH_MS) / MS_PER_WEEK2;
|
|
4363
|
+
week += 1024 * Math.round((weeksNow - week) / 1024);
|
|
4364
4364
|
}
|
|
4365
|
-
const tocDate = new Date(epochMs +
|
|
4365
|
+
const tocDate = new Date(epochMs + week * MS_PER_WEEK2 + tocSec * 1e3);
|
|
4366
4366
|
return {
|
|
4367
4367
|
system: sys,
|
|
4368
4368
|
prn: info.prn,
|
|
@@ -4388,7 +4388,7 @@ function ephInfoToEphemeris(info) {
|
|
|
4388
4388
|
omega: info.argPerigee,
|
|
4389
4389
|
omegaDot: info.omegaDot ?? 0,
|
|
4390
4390
|
idot: info.idot ?? 0,
|
|
4391
|
-
week
|
|
4391
|
+
week,
|
|
4392
4392
|
svHealth: info.health,
|
|
4393
4393
|
tgd: 0
|
|
4394
4394
|
};
|
|
@@ -5044,16 +5044,22 @@ async function connectToMountpoint(proxyUrl, info, signal) {
|
|
|
5044
5044
|
};
|
|
5045
5045
|
}
|
|
5046
5046
|
|
|
5047
|
-
// src/analysis/
|
|
5047
|
+
// src/analysis/stats-util.ts
|
|
5048
5048
|
var MIN_ARC_LENGTH = 10;
|
|
5049
|
-
var MP_JUMP_M = 1.25;
|
|
5050
|
-
var MP_JUMP_WINDOW = 5;
|
|
5051
|
-
var MP_EDIT_SIGMA = 3;
|
|
5052
5049
|
function median(values) {
|
|
5053
5050
|
const s = [...values].sort((a, b) => a - b);
|
|
5054
5051
|
const m = s.length >> 1;
|
|
5055
5052
|
return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
|
|
5056
5053
|
}
|
|
5054
|
+
function percentile(values, p) {
|
|
5055
|
+
const s = [...values].sort((a, b) => a - b);
|
|
5056
|
+
return s[Math.min(s.length - 1, Math.floor(p * s.length))] ?? 0;
|
|
5057
|
+
}
|
|
5058
|
+
|
|
5059
|
+
// src/analysis/multipath.ts
|
|
5060
|
+
var MP_JUMP_M = 1.25;
|
|
5061
|
+
var MP_JUMP_WINDOW = 5;
|
|
5062
|
+
var MP_EDIT_SIGMA = 3;
|
|
5057
5063
|
var MultipathAccumulator = class {
|
|
5058
5064
|
state = /* @__PURE__ */ new Map();
|
|
5059
5065
|
results = [];
|
|
@@ -5534,15 +5540,10 @@ var CompletenessAccumulator = class {
|
|
|
5534
5540
|
// src/analysis/ionosphere.ts
|
|
5535
5541
|
var TEC_FACTOR = 403e15;
|
|
5536
5542
|
var GF_JUMP_M = 0.15;
|
|
5537
|
-
var MIN_ARC_LENGTH2 = 10;
|
|
5538
|
-
function median2(values) {
|
|
5539
|
-
const s = [...values].sort((a, b) => a - b);
|
|
5540
|
-
const m = s.length >> 1;
|
|
5541
|
-
return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
|
|
5542
|
-
}
|
|
5543
5543
|
var IonoAccumulator = class {
|
|
5544
5544
|
state = /* @__PURE__ */ new Map();
|
|
5545
5545
|
closed = /* @__PURE__ */ new Map();
|
|
5546
|
+
closedArcStarts = /* @__PURE__ */ new Map();
|
|
5546
5547
|
interval;
|
|
5547
5548
|
obsIndices;
|
|
5548
5549
|
gloChannels;
|
|
@@ -5642,8 +5643,8 @@ var IonoAccumulator = class {
|
|
|
5642
5643
|
}
|
|
5643
5644
|
closeArc(prn, pairKey, ps) {
|
|
5644
5645
|
const arc = ps.arc;
|
|
5645
|
-
if (arc.times.length >=
|
|
5646
|
-
const level =
|
|
5646
|
+
if (arc.times.length >= MIN_ARC_LENGTH) {
|
|
5647
|
+
const level = median(arc.l4.map((v, k) => v - arc.p4[k]));
|
|
5647
5648
|
const toTecu = arc.fi * arc.fi / TEC_FACTOR / (arc.gamma - 1);
|
|
5648
5649
|
let satArcs = this.closed.get(prn);
|
|
5649
5650
|
if (!satArcs) {
|
|
@@ -5655,6 +5656,17 @@ var IonoAccumulator = class {
|
|
|
5655
5656
|
points = [];
|
|
5656
5657
|
satArcs.set(pairKey, points);
|
|
5657
5658
|
}
|
|
5659
|
+
let satStarts = this.closedArcStarts.get(prn);
|
|
5660
|
+
if (!satStarts) {
|
|
5661
|
+
satStarts = /* @__PURE__ */ new Map();
|
|
5662
|
+
this.closedArcStarts.set(prn, satStarts);
|
|
5663
|
+
}
|
|
5664
|
+
let starts = satStarts.get(pairKey);
|
|
5665
|
+
if (!starts) {
|
|
5666
|
+
starts = [];
|
|
5667
|
+
satStarts.set(pairKey, starts);
|
|
5668
|
+
}
|
|
5669
|
+
starts.push(points.length);
|
|
5658
5670
|
for (let k = 0; k < arc.times.length; k++) {
|
|
5659
5671
|
points.push({
|
|
5660
5672
|
time: arc.times[k],
|
|
@@ -5674,7 +5686,7 @@ var IonoAccumulator = class {
|
|
|
5674
5686
|
const series = [];
|
|
5675
5687
|
let sum = 0;
|
|
5676
5688
|
let count = 0;
|
|
5677
|
-
let maxStec =
|
|
5689
|
+
let maxStec = -Infinity;
|
|
5678
5690
|
for (const [prn, satArcs] of this.closed) {
|
|
5679
5691
|
let bestKey = null;
|
|
5680
5692
|
let bestLen = 0;
|
|
@@ -5686,7 +5698,7 @@ var IonoAccumulator = class {
|
|
|
5686
5698
|
}
|
|
5687
5699
|
if (!bestKey) continue;
|
|
5688
5700
|
const points = satArcs.get(bestKey);
|
|
5689
|
-
|
|
5701
|
+
const arcStarts = this.closedArcStarts.get(prn)?.get(bestKey) ?? [0];
|
|
5690
5702
|
const sys = prn[0];
|
|
5691
5703
|
for (const p of points) {
|
|
5692
5704
|
sum += p.stec;
|
|
@@ -5701,21 +5713,107 @@ var IonoAccumulator = class {
|
|
|
5701
5713
|
label: this.pairLabel.get(`${sys}:${bestKey}`) ?? bestKey,
|
|
5702
5714
|
codes: this.pairCodes.get(`${sys}:${bestKey}`) ?? ["", ""],
|
|
5703
5715
|
tecuPerNs,
|
|
5704
|
-
points
|
|
5716
|
+
points,
|
|
5717
|
+
arcStarts
|
|
5705
5718
|
});
|
|
5706
5719
|
}
|
|
5707
5720
|
series.sort((a, b) => a.prn.localeCompare(b.prn));
|
|
5708
|
-
return {
|
|
5721
|
+
return {
|
|
5722
|
+
series,
|
|
5723
|
+
maxStec: count > 0 ? maxStec : 0,
|
|
5724
|
+
meanStec: count > 0 ? sum / count : 0
|
|
5725
|
+
};
|
|
5709
5726
|
}
|
|
5710
5727
|
};
|
|
5728
|
+
function computeIonoRate(result, intervalSec, order = 1) {
|
|
5729
|
+
const out = [];
|
|
5730
|
+
for (const s of result.series) {
|
|
5731
|
+
const pts = [];
|
|
5732
|
+
const bounds = [...s.arcStarts, s.points.length];
|
|
5733
|
+
for (let a = 0; a < bounds.length - 1; a++) {
|
|
5734
|
+
const lo = bounds[a];
|
|
5735
|
+
const hi = bounds[a + 1];
|
|
5736
|
+
if (order === 2) {
|
|
5737
|
+
for (let i = lo + 2; i < hi; i++) {
|
|
5738
|
+
const dt1 = s.points[i - 1].time - s.points[i - 2].time;
|
|
5739
|
+
const dt2 = s.points[i].time - s.points[i - 1].time;
|
|
5740
|
+
if (Math.abs(dt1 - dt2) > 0.1 * Math.max(dt1, dt2)) continue;
|
|
5741
|
+
pts.push({
|
|
5742
|
+
time: s.points[i].time,
|
|
5743
|
+
value: s.points[i].stec - 2 * s.points[i - 1].stec + s.points[i - 2].stec
|
|
5744
|
+
});
|
|
5745
|
+
}
|
|
5746
|
+
continue;
|
|
5747
|
+
}
|
|
5748
|
+
if (intervalSec === void 0) {
|
|
5749
|
+
for (let i = lo + 1; i < hi; i++) {
|
|
5750
|
+
const dtMin = (s.points[i].time - s.points[i - 1].time) / 6e4;
|
|
5751
|
+
if (dtMin <= 0) continue;
|
|
5752
|
+
pts.push({
|
|
5753
|
+
time: s.points[i].time,
|
|
5754
|
+
value: (s.points[i].stec - s.points[i - 1].stec) / dtMin
|
|
5755
|
+
});
|
|
5756
|
+
}
|
|
5757
|
+
} else {
|
|
5758
|
+
const targetMs = intervalSec * 1e3;
|
|
5759
|
+
let j = lo;
|
|
5760
|
+
for (let i = lo; i < hi; i++) {
|
|
5761
|
+
if (j <= i) j = i + 1;
|
|
5762
|
+
while (j < hi && s.points[j].time - s.points[i].time < targetMs)
|
|
5763
|
+
j++;
|
|
5764
|
+
if (j >= hi) break;
|
|
5765
|
+
const dtMs = s.points[j].time - s.points[i].time;
|
|
5766
|
+
if (dtMs > 1.5 * targetMs) continue;
|
|
5767
|
+
pts.push({
|
|
5768
|
+
time: s.points[j].time,
|
|
5769
|
+
value: (s.points[j].stec - s.points[i].stec) / dtMs * 6e4
|
|
5770
|
+
});
|
|
5771
|
+
}
|
|
5772
|
+
}
|
|
5773
|
+
}
|
|
5774
|
+
if (pts.length > 0) out.push({ prn: s.prn, system: s.system, points: pts });
|
|
5775
|
+
}
|
|
5776
|
+
return out;
|
|
5777
|
+
}
|
|
5778
|
+
function detrendIonoArcs(result) {
|
|
5779
|
+
let sum = 0;
|
|
5780
|
+
let count = 0;
|
|
5781
|
+
let maxStec = -Infinity;
|
|
5782
|
+
const series = result.series.map((s) => {
|
|
5783
|
+
const bounds = [...s.arcStarts, s.points.length];
|
|
5784
|
+
const points = new Array(s.points.length);
|
|
5785
|
+
for (let a = 0; a < bounds.length - 1; a++) {
|
|
5786
|
+
const lo = bounds[a];
|
|
5787
|
+
const hi = bounds[a + 1];
|
|
5788
|
+
const anchor = s.points[lo]?.stec ?? 0;
|
|
5789
|
+
for (let i = lo; i < hi; i++) {
|
|
5790
|
+
points[i] = {
|
|
5791
|
+
time: s.points[i].time,
|
|
5792
|
+
stec: s.points[i].stec - anchor
|
|
5793
|
+
};
|
|
5794
|
+
}
|
|
5795
|
+
}
|
|
5796
|
+
for (const p of points) {
|
|
5797
|
+
sum += p.stec;
|
|
5798
|
+
count++;
|
|
5799
|
+
if (p.stec > maxStec) maxStec = p.stec;
|
|
5800
|
+
}
|
|
5801
|
+
return { ...s, points };
|
|
5802
|
+
});
|
|
5803
|
+
return {
|
|
5804
|
+
series,
|
|
5805
|
+
maxStec: count > 0 ? maxStec : 0,
|
|
5806
|
+
meanStec: count > 0 ? sum / count : 0
|
|
5807
|
+
};
|
|
5808
|
+
}
|
|
5711
5809
|
|
|
5712
5810
|
// src/analysis/dcb.ts
|
|
5713
5811
|
var PRN_RE = /^[A-Z]\d{2}$/;
|
|
5714
5812
|
var SVN_RE = /^[A-Z]\d{3}$/;
|
|
5715
5813
|
var OBS_RE = /^[CL]\d[A-Z]$/;
|
|
5716
|
-
function sinexEpochMs(s) {
|
|
5814
|
+
function sinexEpochMs(s, openValue) {
|
|
5717
5815
|
const [y, d, sec] = s.split(":").map(Number);
|
|
5718
|
-
if (!y) return
|
|
5816
|
+
if (!y) return openValue;
|
|
5719
5817
|
return Date.UTC(y, 0, 1) + ((d ?? 1) - 1) * 864e5 + (sec ?? 0) * 1e3;
|
|
5720
5818
|
}
|
|
5721
5819
|
function parseSinexBiasDcb(text, epochMs) {
|
|
@@ -5730,8 +5828,8 @@ function parseSinexBiasDcb(text, epochMs) {
|
|
|
5730
5828
|
if (unitIdx < 0 || unitIdx + 1 >= t.length) continue;
|
|
5731
5829
|
const value = parseFloat(t[unitIdx + 1]);
|
|
5732
5830
|
if (!isFinite(value)) continue;
|
|
5733
|
-
const start = sinexEpochMs(t[5] ?? "");
|
|
5734
|
-
const end = sinexEpochMs(t[6] ?? "");
|
|
5831
|
+
const start = sinexEpochMs(t[5] ?? "", -Infinity);
|
|
5832
|
+
const end = sinexEpochMs(t[6] ?? "", Infinity);
|
|
5735
5833
|
const covers = epochMs !== void 0 && epochMs >= start && epochMs < end;
|
|
5736
5834
|
const prn = t[2];
|
|
5737
5835
|
const pair = `${t[3]}-${t[4]}`;
|
|
@@ -5753,10 +5851,6 @@ function parseSinexBiasDcb(text, epochMs) {
|
|
|
5753
5851
|
}
|
|
5754
5852
|
return out;
|
|
5755
5853
|
}
|
|
5756
|
-
function percentile(values, p) {
|
|
5757
|
-
const s = [...values].sort((a, b) => a - b);
|
|
5758
|
-
return s[Math.min(s.length - 1, Math.floor(p * s.length))] ?? 0;
|
|
5759
|
-
}
|
|
5760
5854
|
function applyIonoDcb(iono, satDcb) {
|
|
5761
5855
|
const missing = [];
|
|
5762
5856
|
let corrected = 0;
|
|
@@ -5820,7 +5914,7 @@ function applyIonoDcb(iono, satDcb) {
|
|
|
5820
5914
|
out.sort((a, b) => a.prn.localeCompare(b.prn));
|
|
5821
5915
|
let sum = 0;
|
|
5822
5916
|
let count = 0;
|
|
5823
|
-
let maxStec =
|
|
5917
|
+
let maxStec = -Infinity;
|
|
5824
5918
|
for (const s of out) {
|
|
5825
5919
|
for (const p of s.points) {
|
|
5826
5920
|
sum += p.stec;
|
|
@@ -5829,7 +5923,11 @@ function applyIonoDcb(iono, satDcb) {
|
|
|
5829
5923
|
}
|
|
5830
5924
|
}
|
|
5831
5925
|
return {
|
|
5832
|
-
result: {
|
|
5926
|
+
result: {
|
|
5927
|
+
series: out,
|
|
5928
|
+
maxStec: count > 0 ? maxStec : 0,
|
|
5929
|
+
meanStec: count > 0 ? sum / count : 0
|
|
5930
|
+
},
|
|
5833
5931
|
satellitesCorrected: corrected,
|
|
5834
5932
|
satellitesMissing: [...new Set(missing)].sort(),
|
|
5835
5933
|
receiverDcbTecu
|
|
@@ -7148,6 +7246,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
7148
7246
|
clampUnit,
|
|
7149
7247
|
computeAllPositions,
|
|
7150
7248
|
computeDop,
|
|
7249
|
+
computeIonoRate,
|
|
7151
7250
|
computeLiveSkyPositions,
|
|
7152
7251
|
computePsdDb,
|
|
7153
7252
|
computeSatPosition,
|
|
@@ -7163,6 +7262,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
7163
7262
|
decodeMsmFull,
|
|
7164
7263
|
deg2dms,
|
|
7165
7264
|
deg2rad,
|
|
7265
|
+
detrendIonoArcs,
|
|
7166
7266
|
ecefToAzEl,
|
|
7167
7267
|
ecefToGeodetic,
|
|
7168
7268
|
ephInfoToEphemeris,
|
package/dist/index.d.cts
CHANGED
|
@@ -13,7 +13,7 @@ export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPositi
|
|
|
13
13
|
export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.cjs';
|
|
14
14
|
export { SppOptions, SppSolution, ionoFree, satClockCorrection, solveSpp } from './positioning.cjs';
|
|
15
15
|
export { NtripCaster, NtripConnectionInfo, NtripNetwork, NtripStream, NtripStreamConnection, NtripVersion, Sourcetable, SourcetableEntry, connectToMountpoint, fetchSourcetable, parseSourcetable } from './ntrip.cjs';
|
|
16
|
-
export { CompleteSatSignal, CompleteSignalStats, CompletenessAccumulator, CompletenessResult, CycleSlipAccumulator, CycleSlipEvent, CycleSlipResult, CycleSlipSignalStats, IonoAccumulator, IonoDcbResult, IonoPoint, IonoResult, IonoSeries, MultipathAccumulator, MultipathPoint, MultipathResult, MultipathSeries, MultipathSignalStat, QualityResult, SatDcbMap, analyzeQuality, applyIonoDcb, parseSinexBiasDcb } from './analysis.cjs';
|
|
16
|
+
export { CompleteSatSignal, CompleteSignalStats, CompletenessAccumulator, CompletenessResult, CycleSlipAccumulator, CycleSlipEvent, CycleSlipResult, CycleSlipSignalStats, IonoAccumulator, IonoDcbResult, IonoPoint, IonoRatePoint, IonoRateSeries, IonoResult, IonoSeries, MultipathAccumulator, MultipathPoint, MultipathResult, MultipathSeries, MultipathSignalStat, QualityResult, SatDcbMap, analyzeQuality, applyIonoDcb, computeIonoRate, detrendIonoArcs, parseSinexBiasDcb } from './analysis.cjs';
|
|
17
17
|
export { AntennaEntry, AntexFile, FrequencyData, frequencyLabel, parseAntex } from './antex.cjs';
|
|
18
18
|
export { NmeaFix, NmeaStats, NmeaTrack, computeStats, nmeaCoordToDecimal, parseNmeaFile, verifyChecksum } from './nmea.cjs';
|
|
19
19
|
export { BAND_PRESETS, BandPreset, CONSTELLATIONS, ConstellationRow, DELTA_GLO_L1, DELTA_GLO_L2, FREQ_BDS_B1A, FREQ_BDS_B1C, FREQ_BDS_B1I, FREQ_BDS_B2I, FREQ_BDS_B3A, FREQ_BDS_B3I, FREQ_GAL_E1, FREQ_GAL_E5, FREQ_GAL_E5a, FREQ_GAL_E5b, FREQ_GAL_E6, FREQ_GLO_L1, FREQ_GLO_L1OC, FREQ_GLO_L2, FREQ_GLO_L2OC, FREQ_GLO_L3OC, FREQ_GPS_L1, FREQ_GPS_L2, FREQ_GPS_L5, FREQ_NAVIC_L5, FREQ_QZS_L1, FREQ_QZS_L2, FREQ_QZS_L5, FREQ_QZS_L6, Modulation, SignalDef, computePsdDb, phiAltBOC, phiBOCc, phiBOCs, phiBPSK } from './signals.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPositi
|
|
|
13
13
|
export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.js';
|
|
14
14
|
export { SppOptions, SppSolution, ionoFree, satClockCorrection, solveSpp } from './positioning.js';
|
|
15
15
|
export { NtripCaster, NtripConnectionInfo, NtripNetwork, NtripStream, NtripStreamConnection, NtripVersion, Sourcetable, SourcetableEntry, connectToMountpoint, fetchSourcetable, parseSourcetable } from './ntrip.js';
|
|
16
|
-
export { CompleteSatSignal, CompleteSignalStats, CompletenessAccumulator, CompletenessResult, CycleSlipAccumulator, CycleSlipEvent, CycleSlipResult, CycleSlipSignalStats, IonoAccumulator, IonoDcbResult, IonoPoint, IonoResult, IonoSeries, MultipathAccumulator, MultipathPoint, MultipathResult, MultipathSeries, MultipathSignalStat, QualityResult, SatDcbMap, analyzeQuality, applyIonoDcb, parseSinexBiasDcb } from './analysis.js';
|
|
16
|
+
export { CompleteSatSignal, CompleteSignalStats, CompletenessAccumulator, CompletenessResult, CycleSlipAccumulator, CycleSlipEvent, CycleSlipResult, CycleSlipSignalStats, IonoAccumulator, IonoDcbResult, IonoPoint, IonoRatePoint, IonoRateSeries, IonoResult, IonoSeries, MultipathAccumulator, MultipathPoint, MultipathResult, MultipathSeries, MultipathSignalStat, QualityResult, SatDcbMap, analyzeQuality, applyIonoDcb, computeIonoRate, detrendIonoArcs, parseSinexBiasDcb } from './analysis.js';
|
|
17
17
|
export { AntennaEntry, AntexFile, FrequencyData, frequencyLabel, parseAntex } from './antex.js';
|
|
18
18
|
export { NmeaFix, NmeaStats, NmeaTrack, computeStats, nmeaCoordToDecimal, parseNmeaFile, verifyChecksum } from './nmea.js';
|
|
19
19
|
export { BAND_PRESETS, BandPreset, CONSTELLATIONS, ConstellationRow, DELTA_GLO_L1, DELTA_GLO_L2, FREQ_BDS_B1A, FREQ_BDS_B1C, FREQ_BDS_B1I, FREQ_BDS_B2I, FREQ_BDS_B3A, FREQ_BDS_B3I, FREQ_GAL_E1, FREQ_GAL_E5, FREQ_GAL_E5a, FREQ_GAL_E5b, FREQ_GAL_E6, FREQ_GLO_L1, FREQ_GLO_L1OC, FREQ_GLO_L2, FREQ_GLO_L2OC, FREQ_GLO_L3OC, FREQ_GPS_L1, FREQ_GPS_L2, FREQ_GPS_L5, FREQ_NAVIC_L5, FREQ_QZS_L1, FREQ_QZS_L2, FREQ_QZS_L5, FREQ_QZS_L6, Modulation, SignalDef, computePsdDb, phiAltBOC, phiBOCc, phiBOCs, phiBPSK } from './signals.js';
|
package/dist/index.js
CHANGED
|
@@ -10,8 +10,10 @@ import {
|
|
|
10
10
|
MultipathAccumulator,
|
|
11
11
|
analyzeQuality,
|
|
12
12
|
applyIonoDcb,
|
|
13
|
+
computeIonoRate,
|
|
14
|
+
detrendIonoArcs,
|
|
13
15
|
parseSinexBiasDcb
|
|
14
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-Z5UZUNCB.js";
|
|
15
17
|
import {
|
|
16
18
|
frequencyLabel,
|
|
17
19
|
parseAntex
|
|
@@ -100,7 +102,7 @@ import {
|
|
|
100
102
|
ionoFree,
|
|
101
103
|
satClockCorrection,
|
|
102
104
|
solveSpp
|
|
103
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-SOJNWF5T.js";
|
|
104
106
|
import {
|
|
105
107
|
computeAllPositions,
|
|
106
108
|
computeDop,
|
|
@@ -113,7 +115,7 @@ import {
|
|
|
113
115
|
keplerPosition,
|
|
114
116
|
navTimesFromEph,
|
|
115
117
|
selectEphemeris
|
|
116
|
-
} from "./chunk-
|
|
118
|
+
} from "./chunk-CD5YSYCG.js";
|
|
117
119
|
import {
|
|
118
120
|
getBdsTime,
|
|
119
121
|
getDateFromBdsTime,
|
|
@@ -199,7 +201,7 @@ import {
|
|
|
199
201
|
setRtcm3DebugHandler,
|
|
200
202
|
updateStationMeta,
|
|
201
203
|
updateStreamStats
|
|
202
|
-
} from "./chunk-
|
|
204
|
+
} from "./chunk-FGRC3PB3.js";
|
|
203
205
|
import {
|
|
204
206
|
DAYS_MJD2000_MJD,
|
|
205
207
|
DAYS_MJD_JULIAN,
|
|
@@ -340,6 +342,7 @@ export {
|
|
|
340
342
|
clampUnit,
|
|
341
343
|
computeAllPositions,
|
|
342
344
|
computeDop,
|
|
345
|
+
computeIonoRate,
|
|
343
346
|
computeLiveSkyPositions,
|
|
344
347
|
computePsdDb,
|
|
345
348
|
computeSatPosition,
|
|
@@ -355,6 +358,7 @@ export {
|
|
|
355
358
|
decodeMsmFull,
|
|
356
359
|
deg2dms,
|
|
357
360
|
deg2rad,
|
|
361
|
+
detrendIonoArcs,
|
|
358
362
|
ecefToAzEl,
|
|
359
363
|
ecefToGeodetic,
|
|
360
364
|
ephInfoToEphemeris,
|