gnss-js 1.5.0 → 1.5.1
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 +30 -26
- package/dist/analysis.d.cts +2 -2
- package/dist/analysis.d.ts +2 -2
- package/dist/analysis.js +1 -1
- package/dist/{chunk-PQYBTE42.js → chunk-CD5YSYCG.js} +11 -17
- package/dist/{chunk-65CQINSB.js → chunk-FGRC3PB3.js} +6 -2
- package/dist/{chunk-EJQ6NG5U.js → chunk-GDGHTC3E.js} +28 -24
- package/dist/{chunk-PX7TPPTQ.js → chunk-SOJNWF5T.js} +1 -1
- package/dist/index.cjs +45 -43
- package/dist/index.js +4 -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 +3 -3
package/README.md
CHANGED
|
@@ -94,12 +94,16 @@ const itrf = transformFrame(
|
|
|
94
94
|
```ts
|
|
95
95
|
import { parseRinexStream, parseNavFile } from 'gnss-js/rinex';
|
|
96
96
|
|
|
97
|
-
// Streaming observation parser (
|
|
98
|
-
const result = await parseRinexStream(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
97
|
+
// Streaming observation parser (positional arguments)
|
|
98
|
+
const result = await parseRinexStream(
|
|
99
|
+
file, // File (plain, Hatanaka .crx, or .gz)
|
|
100
|
+
(percent) => {}, // optional progress callback
|
|
101
|
+
undefined, // optional AbortSignal
|
|
102
|
+
(time, prn, codes, values) => {
|
|
103
|
+
// per-satellite observation callback
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
// result.header: RinexHeader
|
|
103
107
|
|
|
104
108
|
// Navigation file parser
|
|
105
109
|
const nav = parseNavFile(navFileText);
|
|
@@ -125,28 +129,36 @@ for (const frame of decoder) {
|
|
|
125
129
|
import { computeAllPositions, computeDop } from 'gnss-js/orbit';
|
|
126
130
|
|
|
127
131
|
const positions = computeAllPositions(ephemerides, times, receiverPosition);
|
|
128
|
-
// positions.prns: string[], positions.times: number[]
|
|
132
|
+
// positions.prns: string[], positions.times: number[]
|
|
133
|
+
// positions.positions[prn][epochIdx]: { lat, lon, az, el } | null
|
|
129
134
|
```
|
|
130
135
|
|
|
131
136
|
### Signal analysis
|
|
132
137
|
|
|
133
138
|
```ts
|
|
134
|
-
import {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
139
|
+
import { analyzeQuality } from 'gnss-js/analysis';
|
|
140
|
+
|
|
141
|
+
// One re-parse pass: multipath (per code band, Anubis-style), cycle
|
|
142
|
+
// slips, completeness, and slant-TEC ionosphere series.
|
|
143
|
+
const q = await analyzeQuality(file, header);
|
|
144
|
+
// q.multipath, q.cycleSlips, q.completeness, q.iono
|
|
145
|
+
|
|
146
|
+
// The accumulators (MultipathAccumulator, CycleSlipAccumulator,
|
|
147
|
+
// CompletenessAccumulator, IonoAccumulator) are also exported for
|
|
148
|
+
// wiring into a custom parseRinexStream pass.
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Ionosphere and DCBs
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { parseSinexBiasDcb, applyIonoDcb } from 'gnss-js/analysis';
|
|
155
|
+
|
|
156
|
+
// q.iono: slant TEC per satellite from the geometry-free phase
|
|
157
|
+
// levelled to the code — DCB-biased until calibrated:
|
|
158
|
+
const satDcb = parseSinexBiasDcb(sinexBiasText, obsEpochMs); // ESA .BIA / CAS .BSX
|
|
159
|
+
const { result, receiverDcbTecu } = applyIonoDcb(q.iono, satDcb);
|
|
160
|
+
// result.series[n].points: calibrated STEC (TECU); receiver bias
|
|
161
|
+
// estimated from the night-time floor per system/signal pair.
|
|
150
162
|
```
|
|
151
163
|
|
|
152
164
|
### NTRIP client
|
|
@@ -173,6 +185,17 @@ const { reader, abort } = await connectToMountpoint(
|
|
|
173
185
|
);
|
|
174
186
|
```
|
|
175
187
|
|
|
188
|
+
### NMEA and ANTEX
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import { parseNmeaFile, computeStats } from 'gnss-js/nmea';
|
|
192
|
+
import { parseAntex } from 'gnss-js/antex';
|
|
193
|
+
|
|
194
|
+
const track = parseNmeaFile(nmeaText); // fixes, satellites, per-sentence records
|
|
195
|
+
const stats = computeStats(track.fixes); // position/HDOP/speed statistics
|
|
196
|
+
const antex = parseAntex(antexText); // antenna PCO/PCV calibrations
|
|
197
|
+
```
|
|
198
|
+
|
|
176
199
|
### Constants
|
|
177
200
|
|
|
178
201
|
```ts
|
package/dist/analysis.cjs
CHANGED
|
@@ -30,6 +30,18 @@ __export(analysis_exports, {
|
|
|
30
30
|
});
|
|
31
31
|
module.exports = __toCommonJS(analysis_exports);
|
|
32
32
|
|
|
33
|
+
// src/analysis/stats-util.ts
|
|
34
|
+
var MIN_ARC_LENGTH = 10;
|
|
35
|
+
function median(values) {
|
|
36
|
+
const s = [...values].sort((a, b) => a - b);
|
|
37
|
+
const m = s.length >> 1;
|
|
38
|
+
return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
|
|
39
|
+
}
|
|
40
|
+
function percentile(values, p) {
|
|
41
|
+
const s = [...values].sort((a, b) => a - b);
|
|
42
|
+
return s[Math.min(s.length - 1, Math.floor(p * s.length))] ?? 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
33
45
|
// src/constants/gnss.ts
|
|
34
46
|
var SYSTEM_NAMES = {
|
|
35
47
|
G: "GPS",
|
|
@@ -217,15 +229,9 @@ function buildObsIndices(header) {
|
|
|
217
229
|
var ARC_GAP_FACTOR = 5;
|
|
218
230
|
|
|
219
231
|
// src/analysis/multipath.ts
|
|
220
|
-
var MIN_ARC_LENGTH = 10;
|
|
221
232
|
var MP_JUMP_M = 1.25;
|
|
222
233
|
var MP_JUMP_WINDOW = 5;
|
|
223
234
|
var MP_EDIT_SIGMA = 3;
|
|
224
|
-
function median(values) {
|
|
225
|
-
const s = [...values].sort((a, b) => a - b);
|
|
226
|
-
const m = s.length >> 1;
|
|
227
|
-
return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
|
|
228
|
-
}
|
|
229
235
|
var MultipathAccumulator = class {
|
|
230
236
|
state = /* @__PURE__ */ new Map();
|
|
231
237
|
results = [];
|
|
@@ -706,12 +712,6 @@ var CompletenessAccumulator = class {
|
|
|
706
712
|
// src/analysis/ionosphere.ts
|
|
707
713
|
var TEC_FACTOR = 403e15;
|
|
708
714
|
var GF_JUMP_M = 0.15;
|
|
709
|
-
var MIN_ARC_LENGTH2 = 10;
|
|
710
|
-
function median2(values) {
|
|
711
|
-
const s = [...values].sort((a, b) => a - b);
|
|
712
|
-
const m = s.length >> 1;
|
|
713
|
-
return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
|
|
714
|
-
}
|
|
715
715
|
var IonoAccumulator = class {
|
|
716
716
|
state = /* @__PURE__ */ new Map();
|
|
717
717
|
closed = /* @__PURE__ */ new Map();
|
|
@@ -814,8 +814,8 @@ var IonoAccumulator = class {
|
|
|
814
814
|
}
|
|
815
815
|
closeArc(prn, pairKey, ps) {
|
|
816
816
|
const arc = ps.arc;
|
|
817
|
-
if (arc.times.length >=
|
|
818
|
-
const level =
|
|
817
|
+
if (arc.times.length >= MIN_ARC_LENGTH) {
|
|
818
|
+
const level = median(arc.l4.map((v, k) => v - arc.p4[k]));
|
|
819
819
|
const toTecu = arc.fi * arc.fi / TEC_FACTOR / (arc.gamma - 1);
|
|
820
820
|
let satArcs = this.closed.get(prn);
|
|
821
821
|
if (!satArcs) {
|
|
@@ -846,7 +846,7 @@ var IonoAccumulator = class {
|
|
|
846
846
|
const series = [];
|
|
847
847
|
let sum = 0;
|
|
848
848
|
let count = 0;
|
|
849
|
-
let maxStec =
|
|
849
|
+
let maxStec = -Infinity;
|
|
850
850
|
for (const [prn, satArcs] of this.closed) {
|
|
851
851
|
let bestKey = null;
|
|
852
852
|
let bestLen = 0;
|
|
@@ -877,7 +877,11 @@ var IonoAccumulator = class {
|
|
|
877
877
|
});
|
|
878
878
|
}
|
|
879
879
|
series.sort((a, b) => a.prn.localeCompare(b.prn));
|
|
880
|
-
return {
|
|
880
|
+
return {
|
|
881
|
+
series,
|
|
882
|
+
maxStec: count > 0 ? maxStec : 0,
|
|
883
|
+
meanStec: count > 0 ? sum / count : 0
|
|
884
|
+
};
|
|
881
885
|
}
|
|
882
886
|
};
|
|
883
887
|
|
|
@@ -885,9 +889,9 @@ var IonoAccumulator = class {
|
|
|
885
889
|
var PRN_RE = /^[A-Z]\d{2}$/;
|
|
886
890
|
var SVN_RE = /^[A-Z]\d{3}$/;
|
|
887
891
|
var OBS_RE = /^[CL]\d[A-Z]$/;
|
|
888
|
-
function sinexEpochMs(s) {
|
|
892
|
+
function sinexEpochMs(s, openValue) {
|
|
889
893
|
const [y, d, sec] = s.split(":").map(Number);
|
|
890
|
-
if (!y) return
|
|
894
|
+
if (!y) return openValue;
|
|
891
895
|
return Date.UTC(y, 0, 1) + ((d ?? 1) - 1) * 864e5 + (sec ?? 0) * 1e3;
|
|
892
896
|
}
|
|
893
897
|
function parseSinexBiasDcb(text, epochMs) {
|
|
@@ -902,8 +906,8 @@ function parseSinexBiasDcb(text, epochMs) {
|
|
|
902
906
|
if (unitIdx < 0 || unitIdx + 1 >= t.length) continue;
|
|
903
907
|
const value = parseFloat(t[unitIdx + 1]);
|
|
904
908
|
if (!isFinite(value)) continue;
|
|
905
|
-
const start = sinexEpochMs(t[5] ?? "");
|
|
906
|
-
const end = sinexEpochMs(t[6] ?? "");
|
|
909
|
+
const start = sinexEpochMs(t[5] ?? "", -Infinity);
|
|
910
|
+
const end = sinexEpochMs(t[6] ?? "", Infinity);
|
|
907
911
|
const covers = epochMs !== void 0 && epochMs >= start && epochMs < end;
|
|
908
912
|
const prn = t[2];
|
|
909
913
|
const pair = `${t[3]}-${t[4]}`;
|
|
@@ -925,10 +929,6 @@ function parseSinexBiasDcb(text, epochMs) {
|
|
|
925
929
|
}
|
|
926
930
|
return out;
|
|
927
931
|
}
|
|
928
|
-
function percentile(values, p) {
|
|
929
|
-
const s = [...values].sort((a, b) => a - b);
|
|
930
|
-
return s[Math.min(s.length - 1, Math.floor(p * s.length))] ?? 0;
|
|
931
|
-
}
|
|
932
932
|
function applyIonoDcb(iono, satDcb) {
|
|
933
933
|
const missing = [];
|
|
934
934
|
let corrected = 0;
|
|
@@ -992,7 +992,7 @@ function applyIonoDcb(iono, satDcb) {
|
|
|
992
992
|
out.sort((a, b) => a.prn.localeCompare(b.prn));
|
|
993
993
|
let sum = 0;
|
|
994
994
|
let count = 0;
|
|
995
|
-
let maxStec =
|
|
995
|
+
let maxStec = -Infinity;
|
|
996
996
|
for (const s of out) {
|
|
997
997
|
for (const p of s.points) {
|
|
998
998
|
sum += p.stec;
|
|
@@ -1001,7 +1001,11 @@ function applyIonoDcb(iono, satDcb) {
|
|
|
1001
1001
|
}
|
|
1002
1002
|
}
|
|
1003
1003
|
return {
|
|
1004
|
-
result: {
|
|
1004
|
+
result: {
|
|
1005
|
+
series: out,
|
|
1006
|
+
maxStec: count > 0 ? maxStec : 0,
|
|
1007
|
+
meanStec: count > 0 ? sum / count : 0
|
|
1008
|
+
},
|
|
1005
1009
|
satellitesCorrected: corrected,
|
|
1006
1010
|
satellitesMissing: [...new Set(missing)].sort(),
|
|
1007
1011
|
receiverDcbTecu
|
package/dist/analysis.d.cts
CHANGED
|
@@ -26,7 +26,7 @@ interface MultipathSeries {
|
|
|
26
26
|
band: string;
|
|
27
27
|
/** Reference band digit used in dual-frequency combination, e.g. "2". */
|
|
28
28
|
refBand: string;
|
|
29
|
-
/** Human-readable label, e.g. "
|
|
29
|
+
/** Human-readable label, e.g. "G01 MP L1-L2". */
|
|
30
30
|
label: string;
|
|
31
31
|
/** Time series of multipath values. */
|
|
32
32
|
points: MultipathPoint[];
|
|
@@ -34,7 +34,7 @@ interface MultipathSeries {
|
|
|
34
34
|
rms: number;
|
|
35
35
|
}
|
|
36
36
|
interface MultipathSignalStat {
|
|
37
|
-
/** Human-readable label, e.g. "
|
|
37
|
+
/** Human-readable label, e.g. "MP L1-L2 (GPS)". */
|
|
38
38
|
label: string;
|
|
39
39
|
/** System letter, e.g. "G". */
|
|
40
40
|
system: string;
|
package/dist/analysis.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ interface MultipathSeries {
|
|
|
26
26
|
band: string;
|
|
27
27
|
/** Reference band digit used in dual-frequency combination, e.g. "2". */
|
|
28
28
|
refBand: string;
|
|
29
|
-
/** Human-readable label, e.g. "
|
|
29
|
+
/** Human-readable label, e.g. "G01 MP L1-L2". */
|
|
30
30
|
label: string;
|
|
31
31
|
/** Time series of multipath values. */
|
|
32
32
|
points: MultipathPoint[];
|
|
@@ -34,7 +34,7 @@ interface MultipathSeries {
|
|
|
34
34
|
rms: number;
|
|
35
35
|
}
|
|
36
36
|
interface MultipathSignalStat {
|
|
37
|
-
/** Human-readable label, e.g. "
|
|
37
|
+
/** Human-readable label, e.g. "MP L1-L2 (GPS)". */
|
|
38
38
|
label: string;
|
|
39
39
|
/** System letter, e.g. "G". */
|
|
40
40
|
system: string;
|
package/dist/analysis.js
CHANGED
|
@@ -219,20 +219,10 @@ function invert4x4(m) {
|
|
|
219
219
|
return result;
|
|
220
220
|
}
|
|
221
221
|
function selectEphemeris(ephemerides, prn, timeMs) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const ephTime = eph.tocDate.getTime();
|
|
227
|
-
const dt = Math.abs(timeMs - ephTime);
|
|
228
|
-
const maxAge = eph.system === "R" || eph.system === "S" ? 18e5 : 4 * 36e5;
|
|
229
|
-
if (dt > maxAge) continue;
|
|
230
|
-
if (dt < bestDt) {
|
|
231
|
-
bestDt = dt;
|
|
232
|
-
best = eph;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
return best;
|
|
222
|
+
return selectBest(
|
|
223
|
+
ephemerides.filter((e) => e.prn === prn),
|
|
224
|
+
timeMs
|
|
225
|
+
);
|
|
236
226
|
}
|
|
237
227
|
function computeSatPosition(eph, timeMs) {
|
|
238
228
|
if (eph.system === "R" || eph.system === "S") {
|
|
@@ -325,8 +315,9 @@ function selectBest(ephs, timeMs) {
|
|
|
325
315
|
return best;
|
|
326
316
|
}
|
|
327
317
|
var GPS_EPOCH_MS = START_GPS_TIME.getTime();
|
|
318
|
+
var MS_PER_WEEK = 7 * 864e5;
|
|
328
319
|
var BDS_EPOCH_MS = START_BDS_TIME.getTime();
|
|
329
|
-
var GAL_EPOCH_MS = GPS_EPOCH_MS;
|
|
320
|
+
var GAL_EPOCH_MS = GPS_EPOCH_MS + 1024 * MS_PER_WEEK;
|
|
330
321
|
function ephInfoToEphemeris(info) {
|
|
331
322
|
const sys = info.prn.charAt(0);
|
|
332
323
|
if (sys === "R") {
|
|
@@ -370,6 +361,7 @@ function ephInfoToEphemeris(info) {
|
|
|
370
361
|
return null;
|
|
371
362
|
}
|
|
372
363
|
let epochMs;
|
|
364
|
+
let week = info.week;
|
|
373
365
|
const tocSec = info.toc ?? info.toe;
|
|
374
366
|
if (sys === "C") {
|
|
375
367
|
epochMs = BDS_EPOCH_MS;
|
|
@@ -377,8 +369,10 @@ function ephInfoToEphemeris(info) {
|
|
|
377
369
|
epochMs = GAL_EPOCH_MS;
|
|
378
370
|
} else {
|
|
379
371
|
epochMs = GPS_EPOCH_MS;
|
|
372
|
+
const weeksNow = (info.lastReceived - GPS_EPOCH_MS) / MS_PER_WEEK;
|
|
373
|
+
week += 1024 * Math.round((weeksNow - week) / 1024);
|
|
380
374
|
}
|
|
381
|
-
const tocDate = new Date(epochMs +
|
|
375
|
+
const tocDate = new Date(epochMs + week * MS_PER_WEEK + tocSec * 1e3);
|
|
382
376
|
return {
|
|
383
377
|
system: sys,
|
|
384
378
|
prn: info.prn,
|
|
@@ -404,7 +398,7 @@ function ephInfoToEphemeris(info) {
|
|
|
404
398
|
omega: info.argPerigee,
|
|
405
399
|
omegaDot: info.omegaDot ?? 0,
|
|
406
400
|
idot: info.idot ?? 0,
|
|
407
|
-
week
|
|
401
|
+
week,
|
|
408
402
|
svHealth: info.health,
|
|
409
403
|
tgd: 0
|
|
410
404
|
};
|
|
@@ -1345,6 +1345,11 @@ function rtcm3Constellation(msgType) {
|
|
|
1345
1345
|
if (msgType >= 1111 && msgType <= 1117) return "QZSS";
|
|
1346
1346
|
if (msgType >= 1121 && msgType <= 1127) return "BeiDou";
|
|
1347
1347
|
if (msgType >= 1131 && msgType <= 1137) return "NavIC";
|
|
1348
|
+
if (msgType >= 1015 && msgType <= 1017) return "GPS";
|
|
1349
|
+
if (msgType === 1030) return "GPS";
|
|
1350
|
+
if (msgType === 1031) return "GLONASS";
|
|
1351
|
+
if (msgType >= 1057 && msgType <= 1062) return "GPS";
|
|
1352
|
+
if (msgType >= 1063 && msgType <= 1068) return "GLONASS";
|
|
1348
1353
|
if (msgType === 1230) return "GLONASS";
|
|
1349
1354
|
return null;
|
|
1350
1355
|
}
|
|
@@ -1384,7 +1389,6 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
1384
1389
|
entry.totalBytes += frame.length + 6;
|
|
1385
1390
|
const msmEpoch = decodeMsmFull(frame);
|
|
1386
1391
|
if (msmEpoch) {
|
|
1387
|
-
const now2 = Date.now();
|
|
1388
1392
|
for (const obs of msmEpoch.observations) {
|
|
1389
1393
|
const signals = [];
|
|
1390
1394
|
let bestCn0 = 0;
|
|
@@ -1399,7 +1403,7 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
1399
1403
|
prn: obs.prn,
|
|
1400
1404
|
system: obs.system,
|
|
1401
1405
|
cn0: bestCn0,
|
|
1402
|
-
lastSeen:
|
|
1406
|
+
lastSeen: now,
|
|
1403
1407
|
signals
|
|
1404
1408
|
});
|
|
1405
1409
|
}
|
|
@@ -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,12 +509,6 @@ 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();
|
|
@@ -611,8 +611,8 @@ var IonoAccumulator = class {
|
|
|
611
611
|
}
|
|
612
612
|
closeArc(prn, pairKey, ps) {
|
|
613
613
|
const arc = ps.arc;
|
|
614
|
-
if (arc.times.length >=
|
|
615
|
-
const level =
|
|
614
|
+
if (arc.times.length >= MIN_ARC_LENGTH) {
|
|
615
|
+
const level = median(arc.l4.map((v, k) => v - arc.p4[k]));
|
|
616
616
|
const toTecu = arc.fi * arc.fi / TEC_FACTOR / (arc.gamma - 1);
|
|
617
617
|
let satArcs = this.closed.get(prn);
|
|
618
618
|
if (!satArcs) {
|
|
@@ -643,7 +643,7 @@ var IonoAccumulator = class {
|
|
|
643
643
|
const series = [];
|
|
644
644
|
let sum = 0;
|
|
645
645
|
let count = 0;
|
|
646
|
-
let maxStec =
|
|
646
|
+
let maxStec = -Infinity;
|
|
647
647
|
for (const [prn, satArcs] of this.closed) {
|
|
648
648
|
let bestKey = null;
|
|
649
649
|
let bestLen = 0;
|
|
@@ -674,7 +674,11 @@ var IonoAccumulator = class {
|
|
|
674
674
|
});
|
|
675
675
|
}
|
|
676
676
|
series.sort((a, b) => a.prn.localeCompare(b.prn));
|
|
677
|
-
return {
|
|
677
|
+
return {
|
|
678
|
+
series,
|
|
679
|
+
maxStec: count > 0 ? maxStec : 0,
|
|
680
|
+
meanStec: count > 0 ? sum / count : 0
|
|
681
|
+
};
|
|
678
682
|
}
|
|
679
683
|
};
|
|
680
684
|
|
|
@@ -682,9 +686,9 @@ var IonoAccumulator = class {
|
|
|
682
686
|
var PRN_RE = /^[A-Z]\d{2}$/;
|
|
683
687
|
var SVN_RE = /^[A-Z]\d{3}$/;
|
|
684
688
|
var OBS_RE = /^[CL]\d[A-Z]$/;
|
|
685
|
-
function sinexEpochMs(s) {
|
|
689
|
+
function sinexEpochMs(s, openValue) {
|
|
686
690
|
const [y, d, sec] = s.split(":").map(Number);
|
|
687
|
-
if (!y) return
|
|
691
|
+
if (!y) return openValue;
|
|
688
692
|
return Date.UTC(y, 0, 1) + ((d ?? 1) - 1) * 864e5 + (sec ?? 0) * 1e3;
|
|
689
693
|
}
|
|
690
694
|
function parseSinexBiasDcb(text, epochMs) {
|
|
@@ -699,8 +703,8 @@ function parseSinexBiasDcb(text, epochMs) {
|
|
|
699
703
|
if (unitIdx < 0 || unitIdx + 1 >= t.length) continue;
|
|
700
704
|
const value = parseFloat(t[unitIdx + 1]);
|
|
701
705
|
if (!isFinite(value)) continue;
|
|
702
|
-
const start = sinexEpochMs(t[5] ?? "");
|
|
703
|
-
const end = sinexEpochMs(t[6] ?? "");
|
|
706
|
+
const start = sinexEpochMs(t[5] ?? "", -Infinity);
|
|
707
|
+
const end = sinexEpochMs(t[6] ?? "", Infinity);
|
|
704
708
|
const covers = epochMs !== void 0 && epochMs >= start && epochMs < end;
|
|
705
709
|
const prn = t[2];
|
|
706
710
|
const pair = `${t[3]}-${t[4]}`;
|
|
@@ -722,10 +726,6 @@ function parseSinexBiasDcb(text, epochMs) {
|
|
|
722
726
|
}
|
|
723
727
|
return out;
|
|
724
728
|
}
|
|
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
729
|
function applyIonoDcb(iono, satDcb) {
|
|
730
730
|
const missing = [];
|
|
731
731
|
let corrected = 0;
|
|
@@ -789,7 +789,7 @@ function applyIonoDcb(iono, satDcb) {
|
|
|
789
789
|
out.sort((a, b) => a.prn.localeCompare(b.prn));
|
|
790
790
|
let sum = 0;
|
|
791
791
|
let count = 0;
|
|
792
|
-
let maxStec =
|
|
792
|
+
let maxStec = -Infinity;
|
|
793
793
|
for (const s of out) {
|
|
794
794
|
for (const p of s.points) {
|
|
795
795
|
sum += p.stec;
|
|
@@ -798,7 +798,11 @@ function applyIonoDcb(iono, satDcb) {
|
|
|
798
798
|
}
|
|
799
799
|
}
|
|
800
800
|
return {
|
|
801
|
-
result: {
|
|
801
|
+
result: {
|
|
802
|
+
series: out,
|
|
803
|
+
maxStec: count > 0 ? maxStec : 0,
|
|
804
|
+
meanStec: count > 0 ? sum / count : 0
|
|
805
|
+
},
|
|
802
806
|
satellitesCorrected: corrected,
|
|
803
807
|
satellitesMissing: [...new Set(missing)].sort(),
|
|
804
808
|
receiverDcbTecu
|
package/dist/index.cjs
CHANGED
|
@@ -3906,6 +3906,11 @@ function rtcm3Constellation(msgType) {
|
|
|
3906
3906
|
if (msgType >= 1111 && msgType <= 1117) return "QZSS";
|
|
3907
3907
|
if (msgType >= 1121 && msgType <= 1127) return "BeiDou";
|
|
3908
3908
|
if (msgType >= 1131 && msgType <= 1137) return "NavIC";
|
|
3909
|
+
if (msgType >= 1015 && msgType <= 1017) return "GPS";
|
|
3910
|
+
if (msgType === 1030) return "GPS";
|
|
3911
|
+
if (msgType === 1031) return "GLONASS";
|
|
3912
|
+
if (msgType >= 1057 && msgType <= 1062) return "GPS";
|
|
3913
|
+
if (msgType >= 1063 && msgType <= 1068) return "GLONASS";
|
|
3909
3914
|
if (msgType === 1230) return "GLONASS";
|
|
3910
3915
|
return null;
|
|
3911
3916
|
}
|
|
@@ -3945,7 +3950,6 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
3945
3950
|
entry.totalBytes += frame.length + 6;
|
|
3946
3951
|
const msmEpoch = decodeMsmFull(frame);
|
|
3947
3952
|
if (msmEpoch) {
|
|
3948
|
-
const now2 = Date.now();
|
|
3949
3953
|
for (const obs of msmEpoch.observations) {
|
|
3950
3954
|
const signals = [];
|
|
3951
3955
|
let bestCn0 = 0;
|
|
@@ -3960,7 +3964,7 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
3960
3964
|
prn: obs.prn,
|
|
3961
3965
|
system: obs.system,
|
|
3962
3966
|
cn0: bestCn0,
|
|
3963
|
-
lastSeen:
|
|
3967
|
+
lastSeen: now,
|
|
3964
3968
|
signals
|
|
3965
3969
|
});
|
|
3966
3970
|
}
|
|
@@ -4203,20 +4207,10 @@ function invert4x4(m) {
|
|
|
4203
4207
|
return result;
|
|
4204
4208
|
}
|
|
4205
4209
|
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;
|
|
4210
|
+
return selectBest(
|
|
4211
|
+
ephemerides.filter((e) => e.prn === prn),
|
|
4212
|
+
timeMs
|
|
4213
|
+
);
|
|
4220
4214
|
}
|
|
4221
4215
|
function computeSatPosition(eph, timeMs) {
|
|
4222
4216
|
if (eph.system === "R" || eph.system === "S") {
|
|
@@ -4309,8 +4303,9 @@ function selectBest(ephs, timeMs) {
|
|
|
4309
4303
|
return best;
|
|
4310
4304
|
}
|
|
4311
4305
|
var GPS_EPOCH_MS = START_GPS_TIME.getTime();
|
|
4306
|
+
var MS_PER_WEEK2 = 7 * 864e5;
|
|
4312
4307
|
var BDS_EPOCH_MS = START_BDS_TIME.getTime();
|
|
4313
|
-
var GAL_EPOCH_MS = GPS_EPOCH_MS;
|
|
4308
|
+
var GAL_EPOCH_MS = GPS_EPOCH_MS + 1024 * MS_PER_WEEK2;
|
|
4314
4309
|
function ephInfoToEphemeris(info) {
|
|
4315
4310
|
const sys = info.prn.charAt(0);
|
|
4316
4311
|
if (sys === "R") {
|
|
@@ -4354,6 +4349,7 @@ function ephInfoToEphemeris(info) {
|
|
|
4354
4349
|
return null;
|
|
4355
4350
|
}
|
|
4356
4351
|
let epochMs;
|
|
4352
|
+
let week = info.week;
|
|
4357
4353
|
const tocSec = info.toc ?? info.toe;
|
|
4358
4354
|
if (sys === "C") {
|
|
4359
4355
|
epochMs = BDS_EPOCH_MS;
|
|
@@ -4361,8 +4357,10 @@ function ephInfoToEphemeris(info) {
|
|
|
4361
4357
|
epochMs = GAL_EPOCH_MS;
|
|
4362
4358
|
} else {
|
|
4363
4359
|
epochMs = GPS_EPOCH_MS;
|
|
4360
|
+
const weeksNow = (info.lastReceived - GPS_EPOCH_MS) / MS_PER_WEEK2;
|
|
4361
|
+
week += 1024 * Math.round((weeksNow - week) / 1024);
|
|
4364
4362
|
}
|
|
4365
|
-
const tocDate = new Date(epochMs +
|
|
4363
|
+
const tocDate = new Date(epochMs + week * MS_PER_WEEK2 + tocSec * 1e3);
|
|
4366
4364
|
return {
|
|
4367
4365
|
system: sys,
|
|
4368
4366
|
prn: info.prn,
|
|
@@ -4388,7 +4386,7 @@ function ephInfoToEphemeris(info) {
|
|
|
4388
4386
|
omega: info.argPerigee,
|
|
4389
4387
|
omegaDot: info.omegaDot ?? 0,
|
|
4390
4388
|
idot: info.idot ?? 0,
|
|
4391
|
-
week
|
|
4389
|
+
week,
|
|
4392
4390
|
svHealth: info.health,
|
|
4393
4391
|
tgd: 0
|
|
4394
4392
|
};
|
|
@@ -5044,16 +5042,22 @@ async function connectToMountpoint(proxyUrl, info, signal) {
|
|
|
5044
5042
|
};
|
|
5045
5043
|
}
|
|
5046
5044
|
|
|
5047
|
-
// src/analysis/
|
|
5045
|
+
// src/analysis/stats-util.ts
|
|
5048
5046
|
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
5047
|
function median(values) {
|
|
5053
5048
|
const s = [...values].sort((a, b) => a - b);
|
|
5054
5049
|
const m = s.length >> 1;
|
|
5055
5050
|
return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
|
|
5056
5051
|
}
|
|
5052
|
+
function percentile(values, p) {
|
|
5053
|
+
const s = [...values].sort((a, b) => a - b);
|
|
5054
|
+
return s[Math.min(s.length - 1, Math.floor(p * s.length))] ?? 0;
|
|
5055
|
+
}
|
|
5056
|
+
|
|
5057
|
+
// src/analysis/multipath.ts
|
|
5058
|
+
var MP_JUMP_M = 1.25;
|
|
5059
|
+
var MP_JUMP_WINDOW = 5;
|
|
5060
|
+
var MP_EDIT_SIGMA = 3;
|
|
5057
5061
|
var MultipathAccumulator = class {
|
|
5058
5062
|
state = /* @__PURE__ */ new Map();
|
|
5059
5063
|
results = [];
|
|
@@ -5534,12 +5538,6 @@ var CompletenessAccumulator = class {
|
|
|
5534
5538
|
// src/analysis/ionosphere.ts
|
|
5535
5539
|
var TEC_FACTOR = 403e15;
|
|
5536
5540
|
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
5541
|
var IonoAccumulator = class {
|
|
5544
5542
|
state = /* @__PURE__ */ new Map();
|
|
5545
5543
|
closed = /* @__PURE__ */ new Map();
|
|
@@ -5642,8 +5640,8 @@ var IonoAccumulator = class {
|
|
|
5642
5640
|
}
|
|
5643
5641
|
closeArc(prn, pairKey, ps) {
|
|
5644
5642
|
const arc = ps.arc;
|
|
5645
|
-
if (arc.times.length >=
|
|
5646
|
-
const level =
|
|
5643
|
+
if (arc.times.length >= MIN_ARC_LENGTH) {
|
|
5644
|
+
const level = median(arc.l4.map((v, k) => v - arc.p4[k]));
|
|
5647
5645
|
const toTecu = arc.fi * arc.fi / TEC_FACTOR / (arc.gamma - 1);
|
|
5648
5646
|
let satArcs = this.closed.get(prn);
|
|
5649
5647
|
if (!satArcs) {
|
|
@@ -5674,7 +5672,7 @@ var IonoAccumulator = class {
|
|
|
5674
5672
|
const series = [];
|
|
5675
5673
|
let sum = 0;
|
|
5676
5674
|
let count = 0;
|
|
5677
|
-
let maxStec =
|
|
5675
|
+
let maxStec = -Infinity;
|
|
5678
5676
|
for (const [prn, satArcs] of this.closed) {
|
|
5679
5677
|
let bestKey = null;
|
|
5680
5678
|
let bestLen = 0;
|
|
@@ -5705,7 +5703,11 @@ var IonoAccumulator = class {
|
|
|
5705
5703
|
});
|
|
5706
5704
|
}
|
|
5707
5705
|
series.sort((a, b) => a.prn.localeCompare(b.prn));
|
|
5708
|
-
return {
|
|
5706
|
+
return {
|
|
5707
|
+
series,
|
|
5708
|
+
maxStec: count > 0 ? maxStec : 0,
|
|
5709
|
+
meanStec: count > 0 ? sum / count : 0
|
|
5710
|
+
};
|
|
5709
5711
|
}
|
|
5710
5712
|
};
|
|
5711
5713
|
|
|
@@ -5713,9 +5715,9 @@ var IonoAccumulator = class {
|
|
|
5713
5715
|
var PRN_RE = /^[A-Z]\d{2}$/;
|
|
5714
5716
|
var SVN_RE = /^[A-Z]\d{3}$/;
|
|
5715
5717
|
var OBS_RE = /^[CL]\d[A-Z]$/;
|
|
5716
|
-
function sinexEpochMs(s) {
|
|
5718
|
+
function sinexEpochMs(s, openValue) {
|
|
5717
5719
|
const [y, d, sec] = s.split(":").map(Number);
|
|
5718
|
-
if (!y) return
|
|
5720
|
+
if (!y) return openValue;
|
|
5719
5721
|
return Date.UTC(y, 0, 1) + ((d ?? 1) - 1) * 864e5 + (sec ?? 0) * 1e3;
|
|
5720
5722
|
}
|
|
5721
5723
|
function parseSinexBiasDcb(text, epochMs) {
|
|
@@ -5730,8 +5732,8 @@ function parseSinexBiasDcb(text, epochMs) {
|
|
|
5730
5732
|
if (unitIdx < 0 || unitIdx + 1 >= t.length) continue;
|
|
5731
5733
|
const value = parseFloat(t[unitIdx + 1]);
|
|
5732
5734
|
if (!isFinite(value)) continue;
|
|
5733
|
-
const start = sinexEpochMs(t[5] ?? "");
|
|
5734
|
-
const end = sinexEpochMs(t[6] ?? "");
|
|
5735
|
+
const start = sinexEpochMs(t[5] ?? "", -Infinity);
|
|
5736
|
+
const end = sinexEpochMs(t[6] ?? "", Infinity);
|
|
5735
5737
|
const covers = epochMs !== void 0 && epochMs >= start && epochMs < end;
|
|
5736
5738
|
const prn = t[2];
|
|
5737
5739
|
const pair = `${t[3]}-${t[4]}`;
|
|
@@ -5753,10 +5755,6 @@ function parseSinexBiasDcb(text, epochMs) {
|
|
|
5753
5755
|
}
|
|
5754
5756
|
return out;
|
|
5755
5757
|
}
|
|
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
5758
|
function applyIonoDcb(iono, satDcb) {
|
|
5761
5759
|
const missing = [];
|
|
5762
5760
|
let corrected = 0;
|
|
@@ -5820,7 +5818,7 @@ function applyIonoDcb(iono, satDcb) {
|
|
|
5820
5818
|
out.sort((a, b) => a.prn.localeCompare(b.prn));
|
|
5821
5819
|
let sum = 0;
|
|
5822
5820
|
let count = 0;
|
|
5823
|
-
let maxStec =
|
|
5821
|
+
let maxStec = -Infinity;
|
|
5824
5822
|
for (const s of out) {
|
|
5825
5823
|
for (const p of s.points) {
|
|
5826
5824
|
sum += p.stec;
|
|
@@ -5829,7 +5827,11 @@ function applyIonoDcb(iono, satDcb) {
|
|
|
5829
5827
|
}
|
|
5830
5828
|
}
|
|
5831
5829
|
return {
|
|
5832
|
-
result: {
|
|
5830
|
+
result: {
|
|
5831
|
+
series: out,
|
|
5832
|
+
maxStec: count > 0 ? maxStec : 0,
|
|
5833
|
+
meanStec: count > 0 ? sum / count : 0
|
|
5834
|
+
},
|
|
5833
5835
|
satellitesCorrected: corrected,
|
|
5834
5836
|
satellitesMissing: [...new Set(missing)].sort(),
|
|
5835
5837
|
receiverDcbTecu
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
analyzeQuality,
|
|
12
12
|
applyIonoDcb,
|
|
13
13
|
parseSinexBiasDcb
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-GDGHTC3E.js";
|
|
15
15
|
import {
|
|
16
16
|
frequencyLabel,
|
|
17
17
|
parseAntex
|
|
@@ -100,7 +100,7 @@ import {
|
|
|
100
100
|
ionoFree,
|
|
101
101
|
satClockCorrection,
|
|
102
102
|
solveSpp
|
|
103
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-SOJNWF5T.js";
|
|
104
104
|
import {
|
|
105
105
|
computeAllPositions,
|
|
106
106
|
computeDop,
|
|
@@ -113,7 +113,7 @@ import {
|
|
|
113
113
|
keplerPosition,
|
|
114
114
|
navTimesFromEph,
|
|
115
115
|
selectEphemeris
|
|
116
|
-
} from "./chunk-
|
|
116
|
+
} from "./chunk-CD5YSYCG.js";
|
|
117
117
|
import {
|
|
118
118
|
getBdsTime,
|
|
119
119
|
getDateFromBdsTime,
|
|
@@ -199,7 +199,7 @@ import {
|
|
|
199
199
|
setRtcm3DebugHandler,
|
|
200
200
|
updateStationMeta,
|
|
201
201
|
updateStreamStats
|
|
202
|
-
} from "./chunk-
|
|
202
|
+
} from "./chunk-FGRC3PB3.js";
|
|
203
203
|
import {
|
|
204
204
|
DAYS_MJD2000_MJD,
|
|
205
205
|
DAYS_MJD_JULIAN,
|
package/dist/orbit.cjs
CHANGED
|
@@ -372,20 +372,10 @@ function invert4x4(m) {
|
|
|
372
372
|
return result;
|
|
373
373
|
}
|
|
374
374
|
function selectEphemeris(ephemerides, prn, timeMs) {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
const ephTime = eph.tocDate.getTime();
|
|
380
|
-
const dt = Math.abs(timeMs - ephTime);
|
|
381
|
-
const maxAge = eph.system === "R" || eph.system === "S" ? 18e5 : 4 * 36e5;
|
|
382
|
-
if (dt > maxAge) continue;
|
|
383
|
-
if (dt < bestDt) {
|
|
384
|
-
bestDt = dt;
|
|
385
|
-
best = eph;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
return best;
|
|
375
|
+
return selectBest(
|
|
376
|
+
ephemerides.filter((e) => e.prn === prn),
|
|
377
|
+
timeMs
|
|
378
|
+
);
|
|
389
379
|
}
|
|
390
380
|
function computeSatPosition(eph, timeMs) {
|
|
391
381
|
if (eph.system === "R" || eph.system === "S") {
|
|
@@ -478,8 +468,9 @@ function selectBest(ephs, timeMs) {
|
|
|
478
468
|
return best;
|
|
479
469
|
}
|
|
480
470
|
var GPS_EPOCH_MS = START_GPS_TIME.getTime();
|
|
471
|
+
var MS_PER_WEEK = 7 * 864e5;
|
|
481
472
|
var BDS_EPOCH_MS = START_BDS_TIME.getTime();
|
|
482
|
-
var GAL_EPOCH_MS = GPS_EPOCH_MS;
|
|
473
|
+
var GAL_EPOCH_MS = GPS_EPOCH_MS + 1024 * MS_PER_WEEK;
|
|
483
474
|
function ephInfoToEphemeris(info) {
|
|
484
475
|
const sys = info.prn.charAt(0);
|
|
485
476
|
if (sys === "R") {
|
|
@@ -523,6 +514,7 @@ function ephInfoToEphemeris(info) {
|
|
|
523
514
|
return null;
|
|
524
515
|
}
|
|
525
516
|
let epochMs;
|
|
517
|
+
let week = info.week;
|
|
526
518
|
const tocSec = info.toc ?? info.toe;
|
|
527
519
|
if (sys === "C") {
|
|
528
520
|
epochMs = BDS_EPOCH_MS;
|
|
@@ -530,8 +522,10 @@ function ephInfoToEphemeris(info) {
|
|
|
530
522
|
epochMs = GAL_EPOCH_MS;
|
|
531
523
|
} else {
|
|
532
524
|
epochMs = GPS_EPOCH_MS;
|
|
525
|
+
const weeksNow = (info.lastReceived - GPS_EPOCH_MS) / MS_PER_WEEK;
|
|
526
|
+
week += 1024 * Math.round((weeksNow - week) / 1024);
|
|
533
527
|
}
|
|
534
|
-
const tocDate = new Date(epochMs +
|
|
528
|
+
const tocDate = new Date(epochMs + week * MS_PER_WEEK + tocSec * 1e3);
|
|
535
529
|
return {
|
|
536
530
|
system: sys,
|
|
537
531
|
prn: info.prn,
|
|
@@ -557,7 +551,7 @@ function ephInfoToEphemeris(info) {
|
|
|
557
551
|
omega: info.argPerigee,
|
|
558
552
|
omegaDot: info.omegaDot ?? 0,
|
|
559
553
|
idot: info.idot ?? 0,
|
|
560
|
-
week
|
|
554
|
+
week,
|
|
561
555
|
svHealth: info.health,
|
|
562
556
|
tgd: 0
|
|
563
557
|
};
|
package/dist/orbit.d.cts
CHANGED
|
@@ -131,7 +131,7 @@ interface VisibilityPass {
|
|
|
131
131
|
interface VisibilityResult {
|
|
132
132
|
/** Sample epochs (Unix ms). */
|
|
133
133
|
times: number[];
|
|
134
|
-
/** Elevation (radians) per PRN per epoch; null when
|
|
134
|
+
/** Elevation (radians) per PRN per epoch; null when no valid ephemeris. */
|
|
135
135
|
elevation: Record<string, (number | null)[]>;
|
|
136
136
|
/** Number of satellites at or above the mask, per epoch. */
|
|
137
137
|
visibleCount: number[];
|
package/dist/orbit.d.ts
CHANGED
|
@@ -131,7 +131,7 @@ interface VisibilityPass {
|
|
|
131
131
|
interface VisibilityResult {
|
|
132
132
|
/** Sample epochs (Unix ms). */
|
|
133
133
|
times: number[];
|
|
134
|
-
/** Elevation (radians) per PRN per epoch; null when
|
|
134
|
+
/** Elevation (radians) per PRN per epoch; null when no valid ephemeris. */
|
|
135
135
|
elevation: Record<string, (number | null)[]>;
|
|
136
136
|
/** Number of satellites at or above the mask, per epoch. */
|
|
137
137
|
visibleCount: number[];
|
package/dist/orbit.js
CHANGED
package/dist/positioning.cjs
CHANGED
|
@@ -367,7 +367,9 @@ function computeSatPosition(eph, timeMs) {
|
|
|
367
367
|
return keplerPosition(eph, tow);
|
|
368
368
|
}
|
|
369
369
|
var GPS_EPOCH_MS = START_GPS_TIME.getTime();
|
|
370
|
+
var MS_PER_WEEK = 7 * 864e5;
|
|
370
371
|
var BDS_EPOCH_MS = START_BDS_TIME.getTime();
|
|
372
|
+
var GAL_EPOCH_MS = GPS_EPOCH_MS + 1024 * MS_PER_WEEK;
|
|
371
373
|
|
|
372
374
|
// src/positioning/index.ts
|
|
373
375
|
var GM_GPS2 = 3986005e8;
|
package/dist/positioning.js
CHANGED
|
@@ -2,8 +2,8 @@ import {
|
|
|
2
2
|
ionoFree,
|
|
3
3
|
satClockCorrection,
|
|
4
4
|
solveSpp
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-SOJNWF5T.js";
|
|
6
|
+
import "./chunk-CD5YSYCG.js";
|
|
7
7
|
import "./chunk-HVXYFUCB.js";
|
|
8
8
|
import "./chunk-37QNKGTC.js";
|
|
9
9
|
import "./chunk-6FAL6P4G.js";
|
package/dist/rtcm3.cjs
CHANGED
|
@@ -1406,6 +1406,11 @@ function rtcm3Constellation(msgType) {
|
|
|
1406
1406
|
if (msgType >= 1111 && msgType <= 1117) return "QZSS";
|
|
1407
1407
|
if (msgType >= 1121 && msgType <= 1127) return "BeiDou";
|
|
1408
1408
|
if (msgType >= 1131 && msgType <= 1137) return "NavIC";
|
|
1409
|
+
if (msgType >= 1015 && msgType <= 1017) return "GPS";
|
|
1410
|
+
if (msgType === 1030) return "GPS";
|
|
1411
|
+
if (msgType === 1031) return "GLONASS";
|
|
1412
|
+
if (msgType >= 1057 && msgType <= 1062) return "GPS";
|
|
1413
|
+
if (msgType >= 1063 && msgType <= 1068) return "GLONASS";
|
|
1409
1414
|
if (msgType === 1230) return "GLONASS";
|
|
1410
1415
|
return null;
|
|
1411
1416
|
}
|
|
@@ -1445,7 +1450,6 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
1445
1450
|
entry.totalBytes += frame.length + 6;
|
|
1446
1451
|
const msmEpoch = decodeMsmFull(frame);
|
|
1447
1452
|
if (msmEpoch) {
|
|
1448
|
-
const now2 = Date.now();
|
|
1449
1453
|
for (const obs of msmEpoch.observations) {
|
|
1450
1454
|
const signals = [];
|
|
1451
1455
|
let bestCn0 = 0;
|
|
@@ -1460,7 +1464,7 @@ function updateStreamStats(stats, frames, rawBytes) {
|
|
|
1460
1464
|
prn: obs.prn,
|
|
1461
1465
|
system: obs.system,
|
|
1462
1466
|
cn0: bestCn0,
|
|
1463
|
-
lastSeen:
|
|
1467
|
+
lastSeen: now,
|
|
1464
1468
|
signals
|
|
1465
1469
|
});
|
|
1466
1470
|
}
|
package/dist/rtcm3.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gnss-js",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Comprehensive GNSS library for JavaScript — time scales, coordinates, RINEX parsing, RTCM3 decoding, orbit computation, and signal analysis",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -106,10 +106,10 @@
|
|
|
106
106
|
"positioning"
|
|
107
107
|
],
|
|
108
108
|
"author": "Miguel González <work@miguel.es>",
|
|
109
|
-
"license": "AGPL-3.0-only",
|
|
109
|
+
"license": "AGPL-3.0-only OR LicenseRef-Commercial",
|
|
110
110
|
"repository": {
|
|
111
111
|
"type": "git",
|
|
112
|
-
"url": "https://github.com/MiguelPuntoEs/gnss-js"
|
|
112
|
+
"url": "git+https://github.com/MiguelPuntoEs/gnss-js.git"
|
|
113
113
|
},
|
|
114
114
|
"homepage": "https://github.com/MiguelPuntoEs/gnss-js#readme",
|
|
115
115
|
"bugs": {
|