gnss-js 1.3.0 → 1.3.2

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/analysis.cjs CHANGED
@@ -215,6 +215,14 @@ var ARC_GAP_FACTOR = 5;
215
215
 
216
216
  // src/analysis/multipath.ts
217
217
  var MIN_ARC_LENGTH = 10;
218
+ var MP_JUMP_M = 1.25;
219
+ var MP_JUMP_WINDOW = 5;
220
+ var MP_EDIT_SIGMA = 3;
221
+ function median(values) {
222
+ const s = [...values].sort((a, b) => a - b);
223
+ const m = s.length >> 1;
224
+ return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
225
+ }
218
226
  var MultipathAccumulator = class {
219
227
  state = /* @__PURE__ */ new Map();
220
228
  results = [];
@@ -271,6 +279,11 @@ var MultipathAccumulator = class {
271
279
  const gap = bandState.lastTime > 0 ? (time - bandState.lastTime) / 1e3 : 0;
272
280
  if (bandState.lastTime > 0 && gap > this.interval * ARC_GAP_FACTOR) {
273
281
  this.closeArc(prn, band, refBand, bandState);
282
+ } else if (bandState.arc.rawMp.length > 0) {
283
+ const recent = bandState.arc.rawMp.slice(-MP_JUMP_WINDOW);
284
+ if (Math.abs(mp - median(recent)) > MP_JUMP_M) {
285
+ this.closeArc(prn, band, refBand, bandState);
286
+ }
274
287
  }
275
288
  bandState.arc.times.push(time);
276
289
  bandState.arc.rawMp.push(mp);
@@ -290,13 +303,25 @@ var MultipathAccumulator = class {
290
303
  closeArc(prn, band, refBand, state) {
291
304
  const arc = state.arc;
292
305
  if (arc.times.length >= MIN_ARC_LENGTH) {
293
- const mean = arc.rawMp.reduce((a, b) => a + b, 0) / arc.rawMp.length;
306
+ let keep = arc.times.map((_, i) => i);
307
+ let mean = 0;
308
+ for (let pass = 0; pass < 3; pass++) {
309
+ mean = keep.reduce((s, i) => s + arc.rawMp[i], 0) / keep.length;
310
+ const sigma = Math.sqrt(
311
+ keep.reduce((s, i) => s + (arc.rawMp[i] - mean) ** 2, 0) / keep.length
312
+ );
313
+ const kept = keep.filter(
314
+ (i) => Math.abs(arc.rawMp[i] - mean) <= MP_EDIT_SIGMA * sigma
315
+ );
316
+ if (kept.length === keep.length || kept.length < MIN_ARC_LENGTH) break;
317
+ keep = kept;
318
+ }
294
319
  const sys = prn[0];
295
320
  const bLabel = BAND_LABELS[sys]?.[band] ?? band;
296
321
  const rLabel = BAND_LABELS[sys]?.[refBand] ?? refBand;
297
322
  const label = `${prn} MP ${bLabel}-${rLabel}`;
298
- const points = arc.times.map((t, i) => ({
299
- time: t,
323
+ const points = keep.map((i) => ({
324
+ time: arc.times[i],
300
325
  mp: arc.rawMp[i] - mean
301
326
  }));
302
327
  const rms = Math.sqrt(
@@ -350,7 +375,7 @@ var MultipathAccumulator = class {
350
375
  refBand,
351
376
  rms,
352
377
  count,
353
- satellites: seriesList.length
378
+ satellites: new Set(seriesList.map((s) => s.prn)).size
354
379
  });
355
380
  }
356
381
  const sysOrder = "GRECIJS";
@@ -1,5 +1,5 @@
1
1
  import { R as RinexHeader } from './parser-JPjjFgeP.cjs';
2
- import { O as OnSlipDetected } from './gnss-BT6ulR17.cjs';
2
+ import { i as OnSlipDetected } from './gnss-BtXrG3zH.cjs';
3
3
 
4
4
  /**
5
5
  * Multipath analysis from RINEX dual-frequency observations.
@@ -1,5 +1,5 @@
1
1
  import { R as RinexHeader } from './parser-JPjjFgeP.js';
2
- import { O as OnSlipDetected } from './gnss-C-tgoYNa.js';
2
+ import { i as OnSlipDetected } from './gnss-DhnEr0Dy.js';
3
3
 
4
4
  /**
5
5
  * Multipath analysis from RINEX dual-frequency observations.
package/dist/analysis.js CHANGED
@@ -3,9 +3,9 @@ import {
3
3
  CycleSlipAccumulator,
4
4
  MultipathAccumulator,
5
5
  analyzeQuality
6
- } from "./chunk-G3N4S3DM.js";
7
- import "./chunk-OZCYOM5D.js";
8
- import "./chunk-W5WKEV7U.js";
6
+ } from "./chunk-AW6BORTZ.js";
7
+ import "./chunk-3U5AX7PY.js";
8
+ import "./chunk-FIEWO4J4.js";
9
9
  export {
10
10
  CompletenessAccumulator,
11
11
  CycleSlipAccumulator,
@@ -4,7 +4,7 @@ import {
4
4
  GLO_F1_STEP,
5
5
  GLO_F2_BASE,
6
6
  GLO_F2_STEP
7
- } from "./chunk-W5WKEV7U.js";
7
+ } from "./chunk-FIEWO4J4.js";
8
8
 
9
9
  // src/signals/definitions.ts
10
10
  var MHz = 1e6;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  SYSTEM_NAMES
3
- } from "./chunk-W5WKEV7U.js";
3
+ } from "./chunk-FIEWO4J4.js";
4
4
 
5
5
  // src/rinex/crx.ts
6
6
  function crxRepair(old, diff) {
@@ -0,0 +1,223 @@
1
+ // src/frames/index.ts
2
+ var H = (t, d, r, tDot, dDot, rDot, epoch) => ({ t, d, r, tDot, dDot, rDot, epoch });
3
+ var Z = [0, 0, 0];
4
+ var FROM_ITRF2020 = {
5
+ ITRF2014: H([-1.4, -0.9, 1.4], -0.42, Z, [0, -0.1, 0.2], 0, Z, 2015),
6
+ ITRF2008: H([0.2, 1, 3.3], -0.29, Z, [0, -0.1, 0.1], 0.03, Z, 2015),
7
+ ITRF2005: H([2.7, 0.1, -1.4], 0.65, Z, [0.3, -0.1, 0.1], 0.03, Z, 2015),
8
+ ITRF2000: H([-0.2, 0.8, -34.2], 2.25, Z, [0.1, 0, -1.7], 0.11, Z, 2015),
9
+ ITRF97: H(
10
+ [6.5, -3.9, -77.9],
11
+ 3.98,
12
+ [0, 0, 0.36],
13
+ [0.1, -0.6, -3.1],
14
+ 0.12,
15
+ [0, 0, 0.02],
16
+ 2015
17
+ ),
18
+ ITRF96: H(
19
+ [6.5, -3.9, -77.9],
20
+ 3.98,
21
+ [0, 0, 0.36],
22
+ [0.1, -0.6, -3.1],
23
+ 0.12,
24
+ [0, 0, 0.02],
25
+ 2015
26
+ ),
27
+ ITRF94: H(
28
+ [6.5, -3.9, -77.9],
29
+ 3.98,
30
+ [0, 0, 0.36],
31
+ [0.1, -0.6, -3.1],
32
+ 0.12,
33
+ [0, 0, 0.02],
34
+ 2015
35
+ ),
36
+ ITRF93: H(
37
+ [-65.8, 1.9, -71.3],
38
+ 4.47,
39
+ [-3.36, -4.33, 0.75],
40
+ [-2.8, -0.2, -2.3],
41
+ 0.12,
42
+ [-0.11, -0.19, 0.07],
43
+ 2015
44
+ ),
45
+ ITRF92: H(
46
+ [14.5, -1.9, -85.9],
47
+ 3.27,
48
+ [0, 0, 0.36],
49
+ [0.1, -0.6, -3.1],
50
+ 0.12,
51
+ [0, 0, 0.02],
52
+ 2015
53
+ ),
54
+ ITRF91: H(
55
+ [26.5, 12.1, -91.9],
56
+ 4.67,
57
+ [0, 0, 0.36],
58
+ [0.1, -0.6, -3.1],
59
+ 0.12,
60
+ [0, 0, 0.02],
61
+ 2015
62
+ ),
63
+ ITRF90: H(
64
+ [24.5, 8.1, -107.9],
65
+ 4.97,
66
+ [0, 0, 0.36],
67
+ [0.1, -0.6, -3.1],
68
+ 0.12,
69
+ [0, 0, 0.02],
70
+ 2015
71
+ ),
72
+ ITRF89: H(
73
+ [29.5, 32.1, -145.9],
74
+ 8.37,
75
+ [0, 0, 0.36],
76
+ [0.1, -0.6, -3.1],
77
+ 0.12,
78
+ [0, 0, 0.02],
79
+ 2015
80
+ ),
81
+ ITRF88: H(
82
+ [24.5, -3.9, -169.9],
83
+ 11.47,
84
+ [0.1, 0, 0.36],
85
+ [0.1, -0.6, -3.1],
86
+ 0.12,
87
+ [0, 0, 0.02],
88
+ 2015
89
+ ),
90
+ /** ITRF2020 → ETRF2020, EPSG:10572 (epoch-1989 variant) */
91
+ ETRF2020: H(Z, 0, Z, Z, 0, [0.086, 0.519, -0.753], 1989)
92
+ };
93
+ var ITRF2014_TO_ETRF2014 = H(Z, 0, Z, Z, 0, [0.085, 0.531, -0.77], 1989);
94
+ var ITRF2014_TO_ETRF2000 = H(
95
+ [54.7, 52.2, -74.1],
96
+ 2.12,
97
+ [1.701, 10.29, -16.632],
98
+ [0.1, 0.1, -1.9],
99
+ 0.11,
100
+ [0.081, 0.49, -0.792],
101
+ 2010
102
+ );
103
+ var ITRF2014_TO_NAD83_2011 = H(
104
+ [1005.3, -1909.21, -541.57],
105
+ 0.36891,
106
+ [-26.78138, 0.42027, -10.93206],
107
+ [0.79, -0.6, -1.44],
108
+ -0.07201,
109
+ [-0.06667, 0.75744, 0.05133],
110
+ 2010
111
+ );
112
+ var MAS_TO_RAD = Math.PI / (180 * 3600 * 1e3);
113
+ function applyHelmert(xyz, p, epoch, inverse = false) {
114
+ const dt = epoch - p.epoch;
115
+ const sign = inverse ? -1 : 1;
116
+ const tx = sign * (p.t[0] + p.tDot[0] * dt) / 1e3;
117
+ const ty = sign * (p.t[1] + p.tDot[1] * dt) / 1e3;
118
+ const tz = sign * (p.t[2] + p.tDot[2] * dt) / 1e3;
119
+ const d = sign * (p.d + p.dDot * dt) * 1e-9;
120
+ const rx = sign * (p.r[0] + p.rDot[0] * dt) * MAS_TO_RAD;
121
+ const ry = sign * (p.r[1] + p.rDot[1] * dt) * MAS_TO_RAD;
122
+ const rz = sign * (p.r[2] + p.rDot[2] * dt) * MAS_TO_RAD;
123
+ const [x, y, z] = xyz;
124
+ return [
125
+ x + tx + d * x - rz * y + ry * z,
126
+ y + ty + rz * x + d * y - rx * z,
127
+ z + tz - ry * x + rx * y + d * z
128
+ ];
129
+ }
130
+ var EDGES = [
131
+ ...Object.entries(FROM_ITRF2020).map(([to, p]) => ({
132
+ from: "ITRF2020",
133
+ to,
134
+ p
135
+ })),
136
+ { from: "ITRF2014", to: "ETRF2014", p: ITRF2014_TO_ETRF2014 },
137
+ { from: "ITRF2014", to: "ETRF2000", p: ITRF2014_TO_ETRF2000 },
138
+ { from: "ITRF2014", to: "NAD83(2011)", p: ITRF2014_TO_NAD83_2011 }
139
+ ];
140
+ var REFERENCE_FRAMES = [
141
+ "WGS84",
142
+ "ITRF2020",
143
+ "ITRF2014",
144
+ "ITRF2008",
145
+ "ITRF2005",
146
+ "ITRF2000",
147
+ "ITRF97",
148
+ "ITRF96",
149
+ "ITRF94",
150
+ "ITRF93",
151
+ "ITRF92",
152
+ "ITRF91",
153
+ "ITRF90",
154
+ "ITRF89",
155
+ "ITRF88",
156
+ "ETRF2020",
157
+ "ETRF2014",
158
+ "ETRF2000",
159
+ "NAD83(2011)"
160
+ ];
161
+ function resolveAlias(f) {
162
+ return f === "WGS84" ? "ITRF2020" : f;
163
+ }
164
+ function findPath(from, to) {
165
+ if (from === to) return [];
166
+ const queue = [from];
167
+ const cameFrom = /* @__PURE__ */ new Map();
168
+ const seen = /* @__PURE__ */ new Set([from]);
169
+ while (queue.length > 0) {
170
+ const cur = queue.shift();
171
+ for (const edge of EDGES) {
172
+ let next = null;
173
+ let inverse = false;
174
+ if (edge.from === cur) {
175
+ next = edge.to;
176
+ } else if (edge.to === cur) {
177
+ next = edge.from;
178
+ inverse = true;
179
+ }
180
+ if (next === null || seen.has(next)) continue;
181
+ seen.add(next);
182
+ cameFrom.set(next, { prev: cur, edge, inverse });
183
+ if (next === to) {
184
+ const path = [];
185
+ let node = to;
186
+ while (node !== from) {
187
+ const step = cameFrom.get(node);
188
+ path.unshift({ edge: step.edge, inverse: step.inverse });
189
+ node = step.prev;
190
+ }
191
+ return path;
192
+ }
193
+ queue.push(next);
194
+ }
195
+ }
196
+ return null;
197
+ }
198
+ function transformFrame(xyz, from, to, epoch) {
199
+ const src = resolveAlias(from);
200
+ const dst = resolveAlias(to);
201
+ const path = findPath(src, dst);
202
+ if (!path) {
203
+ throw new Error(`No transformation path from ${from} to ${to}`);
204
+ }
205
+ let out = [xyz[0], xyz[1], xyz[2]];
206
+ for (const { edge, inverse } of path) {
207
+ out = applyHelmert(out, edge.p, epoch, inverse);
208
+ }
209
+ return out;
210
+ }
211
+ function dateToEpoch(date) {
212
+ const year = date.getUTCFullYear();
213
+ const start = Date.UTC(year, 0, 1);
214
+ const end = Date.UTC(year + 1, 0, 1);
215
+ return year + (date.getTime() - start) / (end - start);
216
+ }
217
+
218
+ export {
219
+ applyHelmert,
220
+ REFERENCE_FRAMES,
221
+ transformFrame,
222
+ dateToEpoch
223
+ };
@@ -10,7 +10,7 @@ import {
10
10
  GLO_F1_STEP,
11
11
  GLO_F2_BASE,
12
12
  GLO_F2_STEP
13
- } from "./chunk-W5WKEV7U.js";
13
+ } from "./chunk-FIEWO4J4.js";
14
14
 
15
15
  // src/rtcm3/decoder.ts
16
16
  var debugHandler = null;
@@ -1258,6 +1258,7 @@ var RTCM3_MESSAGE_NAMES = {
1258
1258
  1031: "GLONASS Network RTK Residual",
1259
1259
  1032: "Physical Reference Station",
1260
1260
  1033: "Receiver+Antenna Descriptor",
1261
+ 1041: "NavIC Ephemeris",
1261
1262
  1042: "BeiDou Ephemeris",
1262
1263
  1043: "SBAS Ephemeris",
1263
1264
  1044: "QZSS Ephemeris",
@@ -1322,6 +1323,8 @@ var RTCM3_MESSAGE_NAMES = {
1322
1323
  1064: "GLONASS SSR Clock",
1323
1324
  1065: "GLONASS SSR Code Bias",
1324
1325
  1066: "GLONASS SSR Orbit+Clock",
1326
+ // Biases
1327
+ 1230: "GLONASS Code-Phase Biases",
1325
1328
  // IGS SSR
1326
1329
  4076: "IGS SSR"
1327
1330
  };
@@ -1330,6 +1333,7 @@ function rtcm3Constellation(msgType) {
1330
1333
  if (msgType >= 1009 && msgType <= 1012) return "GLONASS";
1331
1334
  if (msgType === 1019) return "GPS";
1332
1335
  if (msgType === 1020) return "GLONASS";
1336
+ if (msgType === 1041) return "NavIC";
1333
1337
  if (msgType === 1042) return "BeiDou";
1334
1338
  if (msgType === 1043) return "SBAS";
1335
1339
  if (msgType === 1044) return "QZSS";
@@ -1341,6 +1345,7 @@ function rtcm3Constellation(msgType) {
1341
1345
  if (msgType >= 1111 && msgType <= 1117) return "QZSS";
1342
1346
  if (msgType >= 1121 && msgType <= 1127) return "BeiDou";
1343
1347
  if (msgType >= 1131 && msgType <= 1137) return "NavIC";
1348
+ if (msgType === 1230) return "GLONASS";
1344
1349
  return null;
1345
1350
  }
1346
1351
  function createStreamStats() {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseRinexStream
3
- } from "./chunk-OZCYOM5D.js";
3
+ } from "./chunk-3U5AX7PY.js";
4
4
  import {
5
5
  ARC_GAP_FACTOR,
6
6
  BAND_LABELS,
@@ -11,10 +11,18 @@ import {
11
11
  buildGloChannelMap,
12
12
  buildObsIndices,
13
13
  getFreq
14
- } from "./chunk-W5WKEV7U.js";
14
+ } from "./chunk-FIEWO4J4.js";
15
15
 
16
16
  // src/analysis/multipath.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
+ function median(values) {
22
+ const s = [...values].sort((a, b) => a - b);
23
+ const m = s.length >> 1;
24
+ return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
25
+ }
18
26
  var MultipathAccumulator = class {
19
27
  state = /* @__PURE__ */ new Map();
20
28
  results = [];
@@ -71,6 +79,11 @@ var MultipathAccumulator = class {
71
79
  const gap = bandState.lastTime > 0 ? (time - bandState.lastTime) / 1e3 : 0;
72
80
  if (bandState.lastTime > 0 && gap > this.interval * ARC_GAP_FACTOR) {
73
81
  this.closeArc(prn, band, refBand, bandState);
82
+ } else if (bandState.arc.rawMp.length > 0) {
83
+ const recent = bandState.arc.rawMp.slice(-MP_JUMP_WINDOW);
84
+ if (Math.abs(mp - median(recent)) > MP_JUMP_M) {
85
+ this.closeArc(prn, band, refBand, bandState);
86
+ }
74
87
  }
75
88
  bandState.arc.times.push(time);
76
89
  bandState.arc.rawMp.push(mp);
@@ -90,13 +103,25 @@ var MultipathAccumulator = class {
90
103
  closeArc(prn, band, refBand, state) {
91
104
  const arc = state.arc;
92
105
  if (arc.times.length >= MIN_ARC_LENGTH) {
93
- const mean = arc.rawMp.reduce((a, b) => a + b, 0) / arc.rawMp.length;
106
+ let keep = arc.times.map((_, i) => i);
107
+ let mean = 0;
108
+ for (let pass = 0; pass < 3; pass++) {
109
+ mean = keep.reduce((s, i) => s + arc.rawMp[i], 0) / keep.length;
110
+ const sigma = Math.sqrt(
111
+ keep.reduce((s, i) => s + (arc.rawMp[i] - mean) ** 2, 0) / keep.length
112
+ );
113
+ const kept = keep.filter(
114
+ (i) => Math.abs(arc.rawMp[i] - mean) <= MP_EDIT_SIGMA * sigma
115
+ );
116
+ if (kept.length === keep.length || kept.length < MIN_ARC_LENGTH) break;
117
+ keep = kept;
118
+ }
94
119
  const sys = prn[0];
95
120
  const bLabel = BAND_LABELS[sys]?.[band] ?? band;
96
121
  const rLabel = BAND_LABELS[sys]?.[refBand] ?? refBand;
97
122
  const label = `${prn} MP ${bLabel}-${rLabel}`;
98
- const points = arc.times.map((t, i) => ({
99
- time: t,
123
+ const points = keep.map((i) => ({
124
+ time: arc.times[i],
100
125
  mp: arc.rawMp[i] - mean
101
126
  }));
102
127
  const rms = Math.sqrt(
@@ -150,7 +175,7 @@ var MultipathAccumulator = class {
150
175
  refBand,
151
176
  rms,
152
177
  count,
153
- satellites: seriesList.length
178
+ satellites: new Set(seriesList.map((s) => s.prn)).size
154
179
  });
155
180
  }
156
181
  const sysOrder = "GRECIJS";
@@ -18,6 +18,7 @@ var SYS_SHORT = {
18
18
  S: "SBS"
19
19
  };
20
20
  var C_LIGHT = 299792458;
21
+ var OMEGA_E = 72921151467e-15;
21
22
  var FREQ = {
22
23
  G: { "1": 157542e4, "2": 12276e5, "5": 117645e4 },
23
24
  // R bands 4/6 are the CDMA L1OC/L2OC center frequencies
@@ -249,6 +250,7 @@ export {
249
250
  SYSTEM_NAMES,
250
251
  SYS_SHORT,
251
252
  C_LIGHT,
253
+ OMEGA_E,
252
254
  FREQ,
253
255
  BAND_LABELS,
254
256
  DUAL_FREQ_PAIRS,
@@ -8,13 +8,15 @@ import {
8
8
  START_BDS_TIME,
9
9
  START_GPS_TIME
10
10
  } from "./chunk-LEEU5OIO.js";
11
+ import {
12
+ OMEGA_E
13
+ } from "./chunk-FIEWO4J4.js";
11
14
 
12
15
  // src/orbit/index.ts
13
16
  var GM_GPS = 3986005e8;
14
17
  var GM_GAL = 3986004418e5;
15
18
  var GM_BDS = 3986004418e5;
16
19
  var GM_GLO = 39860044e7;
17
- var OMEGA_E = 72921151467e-15;
18
20
  var BDS_GEO_MAX_INCLINATION_RAD = 0.1;
19
21
  var BDS_GEO_MIN_SEMIMAJOR_AXIS_M = 4e7;
20
22
  var AE_GLO = 6378136;
@@ -223,7 +225,8 @@ function selectEphemeris(ephemerides, prn, timeMs) {
223
225
  if (eph.prn !== prn) continue;
224
226
  const ephTime = eph.tocDate.getTime();
225
227
  const dt = Math.abs(timeMs - ephTime);
226
- if (dt > 4 * 3600 * 1e3) continue;
228
+ const maxAge = eph.system === "R" || eph.system === "S" ? 18e5 : 4 * 36e5;
229
+ if (dt > maxAge) continue;
227
230
  if (dt < bestDt) {
228
231
  bestDt = dt;
229
232
  best = eph;
@@ -331,13 +334,13 @@ function ephInfoToEphemeris(info) {
331
334
  return null;
332
335
  if (info.vx === void 0 || info.vy === void 0 || info.vz === void 0)
333
336
  return null;
334
- const now = new Date(info.lastReceived);
337
+ const moscow = new Date(info.lastReceived + 3 * 3600 * 1e3);
335
338
  const utcMidnight = Date.UTC(
336
- now.getUTCFullYear(),
337
- now.getUTCMonth(),
338
- now.getUTCDate()
339
+ moscow.getUTCFullYear(),
340
+ moscow.getUTCMonth(),
341
+ moscow.getUTCDate()
339
342
  );
340
- const tbSec = (info.tb ?? 0) * 900;
343
+ const tbSec = (info.tb ?? 0) * 60;
341
344
  const moscowOffset = 3 * 3600;
342
345
  const tocMs = utcMidnight + (tbSec - moscowOffset) * 1e3;
343
346
  return {
@@ -509,6 +512,7 @@ export {
509
512
  computeSatPosition,
510
513
  navTimesFromEph,
511
514
  computeAllPositions,
515
+ ephInfoToEphemeris,
512
516
  computeLiveSkyPositions,
513
517
  computeVisibility
514
518
  };