gnss-js 0.1.2 → 1.0.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.
Files changed (87) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +171 -5
  3. package/dist/analysis.cjs +1488 -0
  4. package/dist/analysis.d.cts +211 -0
  5. package/dist/analysis.d.ts +211 -0
  6. package/dist/analysis.js +14 -0
  7. package/dist/antex.cjs +239 -0
  8. package/dist/antex.d.cts +77 -0
  9. package/dist/antex.d.ts +77 -0
  10. package/dist/antex.js +8 -0
  11. package/dist/chunk-37QNKGTC.js +65 -0
  12. package/dist/chunk-4YN353Q7.js +440 -0
  13. package/dist/chunk-5CMSYIYM.js +214 -0
  14. package/dist/chunk-5S5MONFK.js +0 -0
  15. package/dist/chunk-6FAL6P4G.js +12 -0
  16. package/dist/chunk-7NOFXKET.js +433 -0
  17. package/dist/chunk-BJHTBYNG.js +154 -0
  18. package/dist/chunk-HBLU2EJ4.js +802 -0
  19. package/dist/chunk-HKN3PUGN.js +800 -0
  20. package/dist/chunk-LEEU5OIO.js +75 -0
  21. package/dist/chunk-LWNTWBHB.js +268 -0
  22. package/dist/chunk-MIIM4LDY.js +239 -0
  23. package/dist/chunk-SO3POWWR.js +502 -0
  24. package/dist/chunk-W4YMQKWH.js +622 -0
  25. package/dist/chunk-WP2JFDLA.js +1475 -0
  26. package/dist/chunk-YDMYO3YK.js +220 -0
  27. package/dist/constants.cjs +423 -0
  28. package/dist/constants.d.cts +14 -0
  29. package/dist/constants.d.ts +14 -0
  30. package/dist/constants.js +103 -0
  31. package/dist/coordinates.cjs +337 -0
  32. package/dist/coordinates.d.cts +81 -0
  33. package/dist/coordinates.d.ts +81 -0
  34. package/dist/coordinates.js +39 -0
  35. package/dist/ecef-CF0uAysr.d.cts +40 -0
  36. package/dist/ecef-CF0uAysr.d.ts +40 -0
  37. package/dist/ephemeris-C10stHhM.d.cts +114 -0
  38. package/dist/ephemeris-C10stHhM.d.ts +114 -0
  39. package/dist/gnss-BT6ulR17.d.cts +56 -0
  40. package/dist/gnss-C-tgoYNa.d.ts +56 -0
  41. package/dist/index.cjs +5940 -78
  42. package/dist/index.d.cts +17 -96
  43. package/dist/index.d.ts +17 -96
  44. package/dist/index.js +352 -415
  45. package/dist/nav-BAI1a9vK.d.cts +108 -0
  46. package/dist/nav-BAI1a9vK.d.ts +108 -0
  47. package/dist/nmea.cjs +247 -0
  48. package/dist/nmea.d.cts +37 -0
  49. package/dist/nmea.d.ts +37 -0
  50. package/dist/nmea.js +12 -0
  51. package/dist/ntrip.cjs +180 -0
  52. package/dist/ntrip.d.cts +98 -0
  53. package/dist/ntrip.d.ts +98 -0
  54. package/dist/ntrip.js +10 -0
  55. package/dist/orbit.cjs +511 -0
  56. package/dist/orbit.d.cts +117 -0
  57. package/dist/orbit.d.ts +117 -0
  58. package/dist/orbit.js +29 -0
  59. package/dist/parser-JPjjFgeP.d.cts +73 -0
  60. package/dist/parser-JPjjFgeP.d.ts +73 -0
  61. package/dist/rinex.cjs +1469 -0
  62. package/dist/rinex.d.cts +116 -0
  63. package/dist/rinex.d.ts +116 -0
  64. package/dist/rinex.js +37 -0
  65. package/dist/rtcm3.cjs +1512 -0
  66. package/dist/rtcm3.d.cts +143 -0
  67. package/dist/rtcm3.d.ts +143 -0
  68. package/dist/rtcm3.js +31 -0
  69. package/dist/signals.cjs +858 -0
  70. package/dist/signals.d.cts +93 -0
  71. package/dist/signals.d.ts +93 -0
  72. package/dist/signals.js +70 -0
  73. package/dist/time-DnI1VpE8.d.cts +33 -0
  74. package/dist/time-DnI1VpE8.d.ts +33 -0
  75. package/dist/time.cjs +585 -0
  76. package/dist/time.d.cts +307 -0
  77. package/dist/time.d.ts +307 -0
  78. package/dist/time.js +154 -0
  79. package/package.json +112 -14
  80. package/.prettierrc +0 -5
  81. package/jest.config.ts +0 -9
  82. package/test/functions.test.ts +0 -63
  83. package/test/gnss-scales.test.ts +0 -95
  84. package/test/julian.test.ts +0 -145
  85. package/test/rinex.test.ts +0 -11
  86. package/test/test.ts +0 -10
  87. package/test/utc.test.ts +0 -25
package/dist/rtcm3.cjs ADDED
@@ -0,0 +1,1512 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/rtcm3/index.ts
21
+ var rtcm3_exports = {};
22
+ __export(rtcm3_exports, {
23
+ BitReader: () => BitReader,
24
+ RTCM3_MESSAGE_NAMES: () => RTCM3_MESSAGE_NAMES,
25
+ Rtcm3Decoder: () => Rtcm3Decoder,
26
+ createStationMeta: () => createStationMeta,
27
+ createStreamStats: () => createStreamStats,
28
+ decodeEphemeris: () => decodeEphemeris,
29
+ decodeMsmFull: () => decodeMsmFull,
30
+ msmEpochToDate: () => msmEpochToDate,
31
+ readString: () => readString,
32
+ resetGloFreqCache: () => resetGloFreqCache,
33
+ rtcm3Constellation: () => rtcm3Constellation,
34
+ updateStationMeta: () => updateStationMeta,
35
+ updateStreamStats: () => updateStreamStats
36
+ });
37
+ module.exports = __toCommonJS(rtcm3_exports);
38
+
39
+ // src/rtcm3/decoder.ts
40
+ var BitReader = class {
41
+ data;
42
+ bitPos = 0;
43
+ constructor(data) {
44
+ this.data = data;
45
+ }
46
+ /** Read `n` bits as unsigned integer (max 53). */
47
+ readU(n) {
48
+ if (n === 0) return 0;
49
+ let val = 0;
50
+ for (let i = 0; i < n; i++) {
51
+ const byteIdx = this.bitPos + i >> 3;
52
+ const bitIdx = 7 - (this.bitPos + i & 7);
53
+ const bit = byteIdx < this.data.length ? this.data[byteIdx] >> bitIdx & 1 : 0;
54
+ val = val * 2 + bit;
55
+ }
56
+ this.bitPos += n;
57
+ return val;
58
+ }
59
+ /** Read `n` bits as signed (two's complement) integer. */
60
+ readS(n) {
61
+ const val = this.readU(n);
62
+ const half = 2 ** (n - 1);
63
+ return val >= half ? val - 2 ** n : val;
64
+ }
65
+ /** Read `n` bits as sign-magnitude integer (MSB = sign, rest = magnitude). */
66
+ readSM(n) {
67
+ const val = this.readU(n);
68
+ const half = 2 ** (n - 1);
69
+ const mag = val % half;
70
+ return val >= half ? -mag : mag;
71
+ }
72
+ /** Skip `n` bits. */
73
+ skip(n) {
74
+ this.bitPos += n;
75
+ }
76
+ get bitsLeft() {
77
+ return this.data.length * 8 - this.bitPos;
78
+ }
79
+ };
80
+ function crc24q(data, length) {
81
+ let crc = 0;
82
+ for (let i = 0; i < length; i++) {
83
+ crc ^= data[i] << 16;
84
+ for (let j = 0; j < 8; j++) {
85
+ crc <<= 1;
86
+ if (crc & 16777216) crc ^= 25578747;
87
+ }
88
+ }
89
+ return crc & 16777215;
90
+ }
91
+ var Rtcm3Decoder = class {
92
+ buffer = new Uint8Array(0);
93
+ /** Feed raw bytes and extract any complete RTCM3 frames. */
94
+ decode(data) {
95
+ const combined = new Uint8Array(this.buffer.length + data.length);
96
+ combined.set(this.buffer);
97
+ combined.set(data, this.buffer.length);
98
+ this.buffer = combined;
99
+ const frames = [];
100
+ while (this.buffer.length >= 6) {
101
+ const syncIdx = this.buffer.indexOf(211);
102
+ if (syncIdx === -1) {
103
+ this.buffer = new Uint8Array(0);
104
+ break;
105
+ }
106
+ if (syncIdx > 0) {
107
+ this.buffer = this.buffer.slice(syncIdx);
108
+ }
109
+ if (this.buffer.length < 3) break;
110
+ const reservedBits = this.buffer[1] >> 2 & 63;
111
+ if (reservedBits !== 0) {
112
+ this.buffer = this.buffer.slice(1);
113
+ continue;
114
+ }
115
+ const length = (this.buffer[1] & 3) << 8 | this.buffer[2];
116
+ if (length > 1023) {
117
+ this.buffer = this.buffer.slice(1);
118
+ continue;
119
+ }
120
+ const frameSize = 3 + length + 3;
121
+ if (this.buffer.length < frameSize) break;
122
+ const crcComputed = crc24q(this.buffer, 3 + length);
123
+ const crcReceived = this.buffer[3 + length] << 16 | this.buffer[3 + length + 1] << 8 | this.buffer[3 + length + 2];
124
+ if (crcComputed !== crcReceived) {
125
+ this.buffer = this.buffer.slice(1);
126
+ continue;
127
+ }
128
+ const payload = this.buffer.slice(3, 3 + length);
129
+ if (length >= 2) {
130
+ const messageType = payload[0] << 4 | payload[1] >> 4;
131
+ frames.push({ messageType, length, payload });
132
+ }
133
+ this.buffer = this.buffer.slice(frameSize);
134
+ }
135
+ if (this.buffer.length > 16384) {
136
+ const nextSync = this.buffer.indexOf(211, 1);
137
+ this.buffer = nextSync !== -1 ? this.buffer.slice(nextSync) : new Uint8Array(0);
138
+ }
139
+ return frames;
140
+ }
141
+ reset() {
142
+ this.buffer = new Uint8Array(0);
143
+ }
144
+ };
145
+
146
+ // src/rtcm3/ephemeris.ts
147
+ var PI = Math.PI;
148
+ function readString(r, nChars) {
149
+ const bytes = [];
150
+ for (let i = 0; i < nChars; i++) bytes.push(r.readU(8));
151
+ return String.fromCharCode(...bytes).replace(/\0+$/, "").trim();
152
+ }
153
+ function decodeGpsEphemeris(payload) {
154
+ if (payload.length < 60) return null;
155
+ const r = new BitReader(payload);
156
+ r.skip(12);
157
+ const svId = r.readU(6);
158
+ const week = r.readU(10);
159
+ const ura = r.readU(4);
160
+ const l2Codes = r.readU(2);
161
+ const idot = r.readS(14) * 2 ** -43 * PI;
162
+ const iode = r.readU(8);
163
+ const toc = r.readU(16) * 16;
164
+ const af2 = r.readS(8) * 2 ** -55;
165
+ const af1 = r.readS(16) * 2 ** -43;
166
+ const af0 = r.readS(22) * 2 ** -31;
167
+ const iodc = r.readU(10);
168
+ const crs = r.readS(16) * 2 ** -5;
169
+ const deltaN = r.readS(16) * 2 ** -43 * PI;
170
+ const m0 = r.readS(32) * 2 ** -31 * PI;
171
+ const cuc = r.readS(16) * 2 ** -29;
172
+ const e = r.readU(32) * 2 ** -33;
173
+ const cus = r.readS(16) * 2 ** -29;
174
+ const sqrtA = r.readU(32) * 2 ** -19;
175
+ const toe = r.readU(16) * 16;
176
+ const cic = r.readS(16) * 2 ** -29;
177
+ const omega0 = r.readS(32) * 2 ** -31 * PI;
178
+ const cis = r.readS(16) * 2 ** -29;
179
+ const i0 = r.readS(32) * 2 ** -31 * PI;
180
+ const crc = r.readS(16) * 2 ** -5;
181
+ const argPerigee = r.readS(32) * 2 ** -31 * PI;
182
+ const omegaDot = r.readS(24) * 2 ** -43 * PI;
183
+ const tgd = r.readS(8) * 2 ** -31;
184
+ const health = r.readU(6);
185
+ const l2PFlag = r.readU(1);
186
+ const fitInterval = r.readU(1);
187
+ return {
188
+ prn: `G${String(svId).padStart(2, "0")}`,
189
+ constellation: "GPS",
190
+ health,
191
+ lastReceived: Date.now(),
192
+ messageType: 1019,
193
+ week,
194
+ ura,
195
+ toc,
196
+ toe,
197
+ sqrtA,
198
+ eccentricity: e,
199
+ inclination: i0,
200
+ omega0,
201
+ omegaDot,
202
+ argPerigee,
203
+ meanAnomaly: m0,
204
+ deltaN,
205
+ idot,
206
+ crs,
207
+ crc,
208
+ cuc,
209
+ cus,
210
+ cic,
211
+ cis,
212
+ af0,
213
+ af1,
214
+ af2,
215
+ iode,
216
+ iodc,
217
+ tgd,
218
+ l2Codes,
219
+ l2PFlag,
220
+ fitInterval
221
+ };
222
+ }
223
+ function decodeGlonassEphemeris(payload) {
224
+ if (payload.length < 43) return null;
225
+ const r = new BitReader(payload);
226
+ r.skip(12);
227
+ const slot = r.readU(6);
228
+ const freqChannel = r.readU(5) - 7;
229
+ r.skip(1 + 1 + 2);
230
+ const tkHours = r.readU(5);
231
+ const tkMins = r.readU(6);
232
+ const tk30s = r.readU(1);
233
+ const tkMoscow = tkHours * 3600 + tkMins * 60 + tk30s * 30;
234
+ const tk = ((tkMoscow - 3 * 3600) % 86400 + 86400) % 86400;
235
+ const healthBn = r.readU(1);
236
+ r.skip(1);
237
+ const tb = r.readU(7) * 15;
238
+ const vx = r.readSM(24) * 2 ** -20;
239
+ const x = r.readSM(27) * 2 ** -11;
240
+ const ax = r.readSM(5) * 2 ** -30;
241
+ const vy = r.readSM(24) * 2 ** -20;
242
+ const y = r.readSM(27) * 2 ** -11;
243
+ const ay = r.readSM(5) * 2 ** -30;
244
+ const vz = r.readSM(24) * 2 ** -20;
245
+ const z = r.readSM(27) * 2 ** -11;
246
+ const azz = r.readSM(5) * 2 ** -30;
247
+ r.skip(1);
248
+ const gammaN = r.readSM(11) * 2 ** -40;
249
+ r.skip(2);
250
+ r.skip(1);
251
+ const tauN = r.readSM(22) * 2 ** -30;
252
+ const deltaTauN = r.readSM(5) * 2 ** -30;
253
+ const en = r.readU(5);
254
+ const p4 = r.readU(1);
255
+ const ft = r.readU(4);
256
+ const nt = r.readU(11);
257
+ const satType = r.readU(2);
258
+ const additionalData = r.readU(1);
259
+ const tauC = additionalData ? r.readSM(32) * 2 ** -31 : void 0;
260
+ const n4 = additionalData ? r.readU(5) : void 0;
261
+ const tauGPS = additionalData ? r.readSM(22) * 2 ** -30 : void 0;
262
+ return {
263
+ prn: `R${String(slot).padStart(2, "0")}`,
264
+ constellation: "GLONASS",
265
+ health: healthBn,
266
+ lastReceived: Date.now(),
267
+ messageType: 1020,
268
+ freqChannel,
269
+ tk,
270
+ x,
271
+ y,
272
+ z,
273
+ vx,
274
+ vy,
275
+ vz,
276
+ ax,
277
+ ay,
278
+ az: azz,
279
+ tb,
280
+ gammaN,
281
+ af0: tauN,
282
+ deltaTauN,
283
+ en,
284
+ p4,
285
+ ft,
286
+ nt,
287
+ satType,
288
+ tauC,
289
+ n4,
290
+ tauGPS
291
+ };
292
+ }
293
+ function decodeGalileoEphemeris(payload, msgType) {
294
+ if (payload.length < 62) return null;
295
+ const r = new BitReader(payload);
296
+ r.skip(12);
297
+ const svId = r.readU(6);
298
+ const week = r.readU(12);
299
+ const iode = r.readU(10);
300
+ const sisa = r.readU(8);
301
+ const idot = r.readS(14) * 2 ** -43 * PI;
302
+ const toc = r.readU(14) * 60;
303
+ const af2 = r.readS(6) * 2 ** -59;
304
+ const af1 = r.readS(21) * 2 ** -46;
305
+ const af0 = r.readS(31) * 2 ** -34;
306
+ const crs = r.readS(16) * 2 ** -5;
307
+ const deltaN = r.readS(16) * 2 ** -43 * PI;
308
+ const m0 = r.readS(32) * 2 ** -31 * PI;
309
+ const cuc = r.readS(16) * 2 ** -29;
310
+ const e = r.readU(32) * 2 ** -33;
311
+ const cus = r.readS(16) * 2 ** -29;
312
+ const sqrtA = r.readU(32) * 2 ** -19;
313
+ const toe = r.readU(14) * 60;
314
+ const cic = r.readS(16) * 2 ** -29;
315
+ const omega0 = r.readS(32) * 2 ** -31 * PI;
316
+ const cis = r.readS(16) * 2 ** -29;
317
+ const i0 = r.readS(32) * 2 ** -31 * PI;
318
+ const crc = r.readS(16) * 2 ** -5;
319
+ const argPerigee = r.readS(32) * 2 ** -31 * PI;
320
+ const omegaDot = r.readS(24) * 2 ** -43 * PI;
321
+ const bgdE5aE1 = r.readS(10) * 2 ** -32;
322
+ let health;
323
+ let bgdE5bE1;
324
+ let e5aDataInvalid;
325
+ let e5bDataInvalid;
326
+ let e1bHealth;
327
+ let e1bDataInvalid;
328
+ if (msgType === 1045) {
329
+ health = r.readU(2);
330
+ e5aDataInvalid = r.readU(1);
331
+ } else {
332
+ bgdE5bE1 = r.readS(10) * 2 ** -32;
333
+ health = r.readU(2);
334
+ e5bDataInvalid = r.readU(1);
335
+ e1bHealth = r.readU(2);
336
+ e1bDataInvalid = r.readU(1);
337
+ }
338
+ return {
339
+ prn: `E${String(svId).padStart(2, "0")}`,
340
+ constellation: "Galileo",
341
+ health,
342
+ lastReceived: Date.now(),
343
+ messageType: msgType,
344
+ week,
345
+ ura: sisa,
346
+ toc,
347
+ toe,
348
+ sqrtA,
349
+ eccentricity: e,
350
+ inclination: i0,
351
+ omega0,
352
+ omegaDot,
353
+ argPerigee,
354
+ meanAnomaly: m0,
355
+ deltaN,
356
+ idot,
357
+ crs,
358
+ crc,
359
+ cuc,
360
+ cus,
361
+ cic,
362
+ cis,
363
+ af0,
364
+ af1,
365
+ af2,
366
+ iode,
367
+ bgdE5aE1,
368
+ bgdE5bE1,
369
+ e5aDataInvalid,
370
+ e5bDataInvalid,
371
+ e1bHealth,
372
+ e1bDataInvalid
373
+ };
374
+ }
375
+ function decodeBdsEphemeris(payload) {
376
+ if (payload.length < 63) return null;
377
+ const r = new BitReader(payload);
378
+ r.skip(12);
379
+ const svId = r.readU(6);
380
+ const week = r.readU(13);
381
+ const ura = r.readU(4);
382
+ const idot = r.readS(14) * 2 ** -43 * PI;
383
+ const iode = r.readU(5);
384
+ const toc = r.readU(17) * 8;
385
+ const af2 = r.readS(11) * 2 ** -66;
386
+ const af1 = r.readS(22) * 2 ** -50;
387
+ const af0 = r.readS(24) * 2 ** -33;
388
+ const aodc = r.readU(5);
389
+ const crs = r.readS(18) * 2 ** -6;
390
+ const deltaN = r.readS(16) * 2 ** -43 * PI;
391
+ const m0 = r.readS(32) * 2 ** -31 * PI;
392
+ const cuc = r.readS(18) * 2 ** -31;
393
+ const e = r.readU(32) * 2 ** -33;
394
+ const cus = r.readS(18) * 2 ** -31;
395
+ const sqrtA = r.readU(32) * 2 ** -19;
396
+ const toe = r.readU(17) * 8;
397
+ const cic = r.readS(18) * 2 ** -31;
398
+ const omega0 = r.readS(32) * 2 ** -31 * PI;
399
+ const cis = r.readS(18) * 2 ** -31;
400
+ const i0 = r.readS(32) * 2 ** -31 * PI;
401
+ const crc = r.readS(18) * 2 ** -6;
402
+ const argPerigee = r.readS(32) * 2 ** -31 * PI;
403
+ const omegaDot = r.readS(24) * 2 ** -43 * PI;
404
+ const tgd1 = r.readS(10) * 1e-10;
405
+ const tgd2 = r.readS(10) * 1e-10;
406
+ const health = r.readU(1);
407
+ return {
408
+ prn: `C${String(svId).padStart(2, "0")}`,
409
+ constellation: "BeiDou",
410
+ health,
411
+ lastReceived: Date.now(),
412
+ messageType: 1042,
413
+ week,
414
+ ura,
415
+ toc,
416
+ toe,
417
+ sqrtA,
418
+ eccentricity: e,
419
+ inclination: i0,
420
+ omega0,
421
+ omegaDot,
422
+ argPerigee,
423
+ meanAnomaly: m0,
424
+ deltaN,
425
+ idot,
426
+ crs,
427
+ crc,
428
+ cuc,
429
+ cus,
430
+ cic,
431
+ cis,
432
+ af0,
433
+ af1,
434
+ af2,
435
+ iode,
436
+ aodc,
437
+ tgd1,
438
+ tgd2
439
+ };
440
+ }
441
+ function decodeSbasEphemeris(payload) {
442
+ if (payload.length < 29) return null;
443
+ const r = new BitReader(payload);
444
+ r.skip(12);
445
+ const svId = r.readU(6);
446
+ const iodn = r.readU(8);
447
+ const t0 = r.readU(13) * 16;
448
+ const ura = r.readU(4);
449
+ const xg = r.readS(30) * 0.08;
450
+ const yg = r.readS(30) * 0.08;
451
+ const zg = r.readS(25) * 0.4;
452
+ const dxg = r.readS(17) * 625e-6;
453
+ const dyg = r.readS(17) * 625e-6;
454
+ const dzg = r.readS(18) * 4e-3;
455
+ const ddxg = r.readS(10) * 125e-7;
456
+ const ddyg = r.readS(10) * 125e-7;
457
+ const ddzg = r.readS(10) * 625e-7;
458
+ const af0 = r.readS(12) * 2 ** -31;
459
+ const af1 = r.readS(8) * 2 ** -40;
460
+ const prn = 120 + svId;
461
+ return {
462
+ prn: `S${String(prn).padStart(3, "0")}`,
463
+ constellation: "SBAS",
464
+ health: 0,
465
+ // SBAS 1043 has no explicit health bit
466
+ lastReceived: Date.now(),
467
+ messageType: 1043,
468
+ iode: iodn,
469
+ toc: t0,
470
+ ura,
471
+ // Store SBAS geo position as GLONASS-like state vector (km, km/s, km/s²)
472
+ x: xg / 1e3,
473
+ y: yg / 1e3,
474
+ z: zg / 1e3,
475
+ vx: dxg / 1e3,
476
+ vy: dyg / 1e3,
477
+ vz: dzg / 1e3,
478
+ ax: ddxg / 1e3,
479
+ ay: ddyg / 1e3,
480
+ az: ddzg / 1e3,
481
+ af0,
482
+ af1
483
+ };
484
+ }
485
+ function decodeQzssEphemeris(payload) {
486
+ if (payload.length < 60) return null;
487
+ const r = new BitReader(payload);
488
+ r.skip(12);
489
+ const svId = r.readU(4);
490
+ if (svId < 1 || svId > 10) return null;
491
+ const toc = r.readU(16) * 16;
492
+ const af2 = r.readS(8) * 2 ** -55;
493
+ const af1 = r.readS(16) * 2 ** -43;
494
+ const af0 = r.readS(22) * 2 ** -31;
495
+ const iode = r.readU(8);
496
+ const crs = r.readS(16) * 2 ** -5;
497
+ const deltaN = r.readS(16) * 2 ** -43 * PI;
498
+ const m0 = r.readS(32) * 2 ** -31 * PI;
499
+ const cuc = r.readS(16) * 2 ** -29;
500
+ const e = r.readU(32) * 2 ** -33;
501
+ const cus = r.readS(16) * 2 ** -29;
502
+ const sqrtA = r.readU(32) * 2 ** -19;
503
+ const toe = r.readU(16) * 16;
504
+ const cic = r.readS(16) * 2 ** -29;
505
+ const omega0 = r.readS(32) * 2 ** -31 * PI;
506
+ const cis = r.readS(16) * 2 ** -29;
507
+ const i0 = r.readS(32) * 2 ** -31 * PI;
508
+ const crc = r.readS(16) * 2 ** -5;
509
+ const argPerigee = r.readS(32) * 2 ** -31 * PI;
510
+ const omegaDot = r.readS(24) * 2 ** -43 * PI;
511
+ const idot = r.readS(14) * 2 ** -43 * PI;
512
+ const l2Codes = r.readU(2);
513
+ const week = r.readU(10);
514
+ const ura = r.readU(4);
515
+ const health = r.readU(6);
516
+ const tgd = r.readS(8) * 2 ** -31;
517
+ const iodc = r.readU(10);
518
+ const fitInterval = r.readU(1);
519
+ return {
520
+ prn: `J${String(svId).padStart(2, "0")}`,
521
+ constellation: "QZSS",
522
+ health,
523
+ lastReceived: Date.now(),
524
+ messageType: 1044,
525
+ week,
526
+ ura,
527
+ toc,
528
+ toe,
529
+ sqrtA,
530
+ eccentricity: e,
531
+ inclination: i0,
532
+ omega0,
533
+ omegaDot,
534
+ argPerigee,
535
+ meanAnomaly: m0,
536
+ deltaN,
537
+ idot,
538
+ crs,
539
+ crc,
540
+ cuc,
541
+ cus,
542
+ cic,
543
+ cis,
544
+ af0,
545
+ af1,
546
+ af2,
547
+ iode,
548
+ iodc,
549
+ tgd,
550
+ l2Codes,
551
+ fitInterval
552
+ };
553
+ }
554
+ function decodeEphemeris(frame) {
555
+ try {
556
+ switch (frame.messageType) {
557
+ case 1019:
558
+ return decodeGpsEphemeris(frame.payload);
559
+ case 1020:
560
+ return decodeGlonassEphemeris(frame.payload);
561
+ case 1042:
562
+ return decodeBdsEphemeris(frame.payload);
563
+ case 1043:
564
+ return decodeSbasEphemeris(frame.payload);
565
+ case 1044:
566
+ return decodeQzssEphemeris(frame.payload);
567
+ case 1045:
568
+ return decodeGalileoEphemeris(frame.payload, 1045);
569
+ case 1046:
570
+ return decodeGalileoEphemeris(frame.payload, 1046);
571
+ default:
572
+ return null;
573
+ }
574
+ } catch {
575
+ return null;
576
+ }
577
+ }
578
+
579
+ // src/constants/gnss.ts
580
+ var C_LIGHT = 299792458;
581
+ var GLO_F1_BASE = 1602e6;
582
+ var GLO_F1_STEP = 562500;
583
+ var GLO_F2_BASE = 1246e6;
584
+ var GLO_F2_STEP = 437500;
585
+
586
+ // src/rtcm3/msm.ts
587
+ var GPS_L1 = 157542e4;
588
+ var GPS_L2 = 12276e5;
589
+ var GPS_L5 = 117645e4;
590
+ var GLO_L1a = 1600995e3;
591
+ var GLO_L2a = 124806e4;
592
+ var GLO_L3 = 1202025e3;
593
+ var GAL_E1 = 157542e4;
594
+ var GAL_E5a = 117645e4;
595
+ var GAL_E5b = 120714e4;
596
+ var GAL_E5 = 1191795e3;
597
+ var GAL_E6 = 127875e4;
598
+ var BDS_B1 = 1561098e3;
599
+ var BDS_B3 = 126852e4;
600
+ var BDS_B2 = 120714e4;
601
+ var BDS_B1C = 157542e4;
602
+ var BDS_B2a = 117645e4;
603
+ var BDS_B2b = 120714e4;
604
+ var QZSS_L6 = 127875e4;
605
+ var NAVIC_S = 2492028e3;
606
+ var EMPTY = { code: "", freq: 0 };
607
+ function sd(code, freq) {
608
+ return { code, freq };
609
+ }
610
+ var GPS_SIGNALS = [
611
+ EMPTY,
612
+ sd("1C", GPS_L1),
613
+ sd("1P", GPS_L1),
614
+ sd("1W", GPS_L1),
615
+ // 1-3
616
+ EMPTY,
617
+ EMPTY,
618
+ EMPTY,
619
+ // 4-6
620
+ sd("2C", GPS_L2),
621
+ sd("2P", GPS_L2),
622
+ sd("2W", GPS_L2),
623
+ // 7-9
624
+ EMPTY,
625
+ EMPTY,
626
+ EMPTY,
627
+ EMPTY,
628
+ // 10-13
629
+ sd("2S", GPS_L2),
630
+ sd("2L", GPS_L2),
631
+ sd("2X", GPS_L2),
632
+ // 14-16
633
+ EMPTY,
634
+ EMPTY,
635
+ EMPTY,
636
+ EMPTY,
637
+ // 17-20
638
+ sd("5I", GPS_L5),
639
+ sd("5Q", GPS_L5),
640
+ sd("5X", GPS_L5),
641
+ // 21-23
642
+ EMPTY,
643
+ EMPTY,
644
+ EMPTY,
645
+ EMPTY,
646
+ EMPTY,
647
+ // 24-28
648
+ sd("1S", GPS_L1),
649
+ sd("1L", GPS_L1),
650
+ sd("1X", GPS_L1)
651
+ // 29-31
652
+ ];
653
+ var GLO_SIGNALS = [
654
+ EMPTY,
655
+ sd("1C", 0),
656
+ sd("1P", 0),
657
+ EMPTY,
658
+ // 1-3 (L1, freq per-sat)
659
+ EMPTY,
660
+ EMPTY,
661
+ EMPTY,
662
+ // 4-6
663
+ sd("2C", 1),
664
+ sd("2P", 1),
665
+ // 7-8 (L2, marker=1)
666
+ sd("4A", GLO_L1a),
667
+ sd("4B", GLO_L1a),
668
+ sd("4X", GLO_L1a),
669
+ // 9-11
670
+ sd("6A", GLO_L2a),
671
+ sd("6B", GLO_L2a),
672
+ sd("6X", GLO_L2a),
673
+ // 12-14
674
+ sd("3I", GLO_L3),
675
+ sd("3Q", GLO_L3),
676
+ sd("3X", GLO_L3),
677
+ // 15-17
678
+ EMPTY,
679
+ EMPTY,
680
+ EMPTY,
681
+ EMPTY,
682
+ EMPTY,
683
+ EMPTY,
684
+ EMPTY,
685
+ // 18-24
686
+ EMPTY,
687
+ EMPTY,
688
+ EMPTY,
689
+ EMPTY,
690
+ EMPTY,
691
+ EMPTY,
692
+ EMPTY
693
+ // 25-31
694
+ ];
695
+ var GAL_SIGNALS = [
696
+ EMPTY,
697
+ sd("1C", GAL_E1),
698
+ sd("1A", GAL_E1),
699
+ sd("1B", GAL_E1),
700
+ // 1-3
701
+ sd("1X", GAL_E1),
702
+ sd("1Z", GAL_E1),
703
+ EMPTY,
704
+ // 4-6
705
+ sd("6C", GAL_E6),
706
+ sd("6A", GAL_E6),
707
+ sd("6B", GAL_E6),
708
+ // 7-9
709
+ sd("6X", GAL_E6),
710
+ sd("6Z", GAL_E6),
711
+ EMPTY,
712
+ // 10-12
713
+ sd("7I", GAL_E5b),
714
+ sd("7Q", GAL_E5b),
715
+ sd("7X", GAL_E5b),
716
+ // 13-15
717
+ EMPTY,
718
+ // 16
719
+ sd("8I", GAL_E5),
720
+ sd("8Q", GAL_E5),
721
+ sd("8X", GAL_E5),
722
+ // 17-19
723
+ EMPTY,
724
+ // 20
725
+ sd("5I", GAL_E5a),
726
+ sd("5Q", GAL_E5a),
727
+ sd("5X", GAL_E5a),
728
+ // 21-23
729
+ EMPTY,
730
+ EMPTY,
731
+ EMPTY,
732
+ EMPTY,
733
+ EMPTY,
734
+ EMPTY,
735
+ EMPTY,
736
+ EMPTY
737
+ // 24-31
738
+ ];
739
+ var BDS_SIGNALS = [
740
+ EMPTY,
741
+ sd("2I", BDS_B1),
742
+ sd("2Q", BDS_B1),
743
+ sd("2X", BDS_B1),
744
+ // 1-3
745
+ EMPTY,
746
+ EMPTY,
747
+ EMPTY,
748
+ // 4-6
749
+ sd("6I", BDS_B3),
750
+ sd("6Q", BDS_B3),
751
+ sd("6X", BDS_B3),
752
+ // 7-9
753
+ EMPTY,
754
+ EMPTY,
755
+ EMPTY,
756
+ // 10-12
757
+ sd("7I", BDS_B2),
758
+ sd("7Q", BDS_B2),
759
+ sd("7X", BDS_B2),
760
+ // 13-15
761
+ EMPTY,
762
+ EMPTY,
763
+ EMPTY,
764
+ EMPTY,
765
+ EMPTY,
766
+ // 16-20
767
+ sd("5D", BDS_B2a),
768
+ sd("5P", BDS_B2a),
769
+ sd("5X", BDS_B2a),
770
+ // 21-23
771
+ sd("7D", BDS_B2b),
772
+ // 24
773
+ EMPTY,
774
+ EMPTY,
775
+ EMPTY,
776
+ EMPTY,
777
+ // 25-28
778
+ sd("1D", BDS_B1C),
779
+ sd("1P", BDS_B1C),
780
+ sd("1X", BDS_B1C)
781
+ // 29-31
782
+ ];
783
+ var QZSS_SIGNALS = [
784
+ EMPTY,
785
+ sd("1C", GPS_L1),
786
+ EMPTY,
787
+ EMPTY,
788
+ EMPTY,
789
+ EMPTY,
790
+ EMPTY,
791
+ // 1-6
792
+ EMPTY,
793
+ sd("6S", QZSS_L6),
794
+ sd("6L", QZSS_L6),
795
+ sd("6X", QZSS_L6),
796
+ // 8-10
797
+ EMPTY,
798
+ EMPTY,
799
+ EMPTY,
800
+ // 11-13
801
+ sd("2S", GPS_L2),
802
+ sd("2L", GPS_L2),
803
+ sd("2X", GPS_L2),
804
+ // 14-16
805
+ EMPTY,
806
+ EMPTY,
807
+ EMPTY,
808
+ EMPTY,
809
+ // 17-20
810
+ sd("5I", GPS_L5),
811
+ sd("5Q", GPS_L5),
812
+ sd("5X", GPS_L5),
813
+ // 21-23
814
+ EMPTY,
815
+ EMPTY,
816
+ EMPTY,
817
+ EMPTY,
818
+ EMPTY,
819
+ // 24-28
820
+ sd("1S", GPS_L1),
821
+ sd("1L", GPS_L1),
822
+ sd("1X", GPS_L1)
823
+ // 29-31
824
+ ];
825
+ var NAVIC_SIGNALS = [
826
+ EMPTY,
827
+ EMPTY,
828
+ EMPTY,
829
+ EMPTY,
830
+ EMPTY,
831
+ EMPTY,
832
+ EMPTY,
833
+ sd("9A", NAVIC_S),
834
+ ...Array.from({ length: 24 }, () => EMPTY)
835
+ ];
836
+ var SBAS_SIGNALS = GPS_SIGNALS;
837
+ function signalTable(sys) {
838
+ switch (sys) {
839
+ case "G":
840
+ return GPS_SIGNALS;
841
+ case "R":
842
+ return GLO_SIGNALS;
843
+ case "E":
844
+ return GAL_SIGNALS;
845
+ case "C":
846
+ return BDS_SIGNALS;
847
+ case "J":
848
+ return QZSS_SIGNALS;
849
+ case "I":
850
+ return NAVIC_SIGNALS;
851
+ case "S":
852
+ return SBAS_SIGNALS;
853
+ default:
854
+ return GPS_SIGNALS;
855
+ }
856
+ }
857
+ var BitReader2 = class {
858
+ data;
859
+ pos;
860
+ constructor(data, startBit = 0) {
861
+ this.data = data;
862
+ this.pos = startBit;
863
+ }
864
+ /** Read unsigned value of numBits bits (max 53) */
865
+ u(numBits) {
866
+ let val = 0;
867
+ for (let i = 0; i < numBits; i++) {
868
+ const byteIdx = this.pos + i >>> 3;
869
+ const bitIdx = 7 - (this.pos + i & 7);
870
+ const bit = byteIdx < this.data.length ? this.data[byteIdx] >>> bitIdx & 1 : 0;
871
+ val = val * 2 + bit;
872
+ }
873
+ this.pos += numBits;
874
+ return val;
875
+ }
876
+ /** Read signed value (two's complement) */
877
+ s(numBits) {
878
+ const raw = this.u(numBits);
879
+ const half = 2 ** (numBits - 1);
880
+ return raw >= half ? raw - 2 ** numBits : raw;
881
+ }
882
+ /** Skip bits */
883
+ skip(n) {
884
+ this.pos += n;
885
+ }
886
+ /** Current bit position */
887
+ get position() {
888
+ return this.pos;
889
+ }
890
+ };
891
+ var gloFreqNum = new Int8Array(64).fill(-128);
892
+ function gloWavelength(satIdx, freqMarker) {
893
+ const k = gloFreqNum[satIdx];
894
+ if (k === -128) return 0;
895
+ if (freqMarker === 0) {
896
+ return C_LIGHT / (GLO_F1_BASE + k * GLO_F1_STEP);
897
+ } else if (freqMarker === 1) {
898
+ return C_LIGHT / (GLO_F2_BASE + k * GLO_F2_STEP);
899
+ }
900
+ return freqMarker > 0 ? C_LIGHT / freqMarker : 0;
901
+ }
902
+ var LTI_TABLE_4BIT = [
903
+ 0,
904
+ 0.032,
905
+ 0.064,
906
+ 0.128,
907
+ 0.256,
908
+ 0.512,
909
+ 1.024,
910
+ 2.048,
911
+ 4.096,
912
+ 8.192,
913
+ 16.384,
914
+ 32.768,
915
+ 65.536,
916
+ 131.072,
917
+ 262.144,
918
+ 524.288
919
+ ];
920
+ function lockTimeSec(msmType, lti) {
921
+ const variant = msmType % 10;
922
+ if (variant <= 5) {
923
+ return LTI_TABLE_4BIT[lti] ?? 0;
924
+ }
925
+ if (lti < 64) return lti;
926
+ if (lti < 96) return (lti - 64) * 2 + 64;
927
+ if (lti < 128) return (lti - 96) * 4 + 128;
928
+ if (lti < 160) return (lti - 128) * 8 + 256;
929
+ if (lti < 192) return (lti - 160) * 16 + 512;
930
+ if (lti < 224) return (lti - 192) * 32 + 1024;
931
+ if (lti < 256) return (lti - 224) * 64 + 2048;
932
+ if (lti < 288) return (lti - 256) * 128 + 4096;
933
+ if (lti < 320) return (lti - 288) * 256 + 8192;
934
+ if (lti < 352) return (lti - 320) * 512 + 16384;
935
+ if (lti < 384) return (lti - 352) * 1024 + 32768;
936
+ if (lti < 416) return (lti - 384) * 2048 + 65536;
937
+ if (lti < 448) return (lti - 416) * 4096 + 131072;
938
+ if (lti < 480) return (lti - 448) * 8192 + 262144;
939
+ if (lti < 512) return (lti - 480) * 16384 + 524288;
940
+ if (lti < 544) return (lti - 512) * 32768 + 1048576;
941
+ if (lti < 576) return (lti - 544) * 65536 + 2097152;
942
+ if (lti < 608) return (lti - 576) * 131072 + 4194304;
943
+ if (lti < 640) return (lti - 608) * 262144 + 8388608;
944
+ if (lti < 672) return (lti - 640) * 524288 + 16777216;
945
+ if (lti < 704) return (lti - 672) * 1048576 + 33554432;
946
+ return (lti - 704) * 2097152 + 67108864;
947
+ }
948
+ function msmSystem(type) {
949
+ if (type >= 1071 && type <= 1077) return "G";
950
+ if (type >= 1081 && type <= 1087) return "R";
951
+ if (type >= 1091 && type <= 1097) return "E";
952
+ if (type >= 1101 && type <= 1107) return "S";
953
+ if (type >= 1111 && type <= 1117) return "J";
954
+ if (type >= 1121 && type <= 1127) return "C";
955
+ if (type >= 1131 && type <= 1137) return "I";
956
+ return "";
957
+ }
958
+ function satPrn(sys, satIdx1) {
959
+ const prefix = sys === "S" ? "S" : sys;
960
+ const num = sys === "S" ? satIdx1 + 119 : satIdx1;
961
+ return `${prefix}${String(num).padStart(2, "0")}`;
962
+ }
963
+ function decodeMsmFull(frame) {
964
+ const type = frame.messageType;
965
+ const sys = msmSystem(type);
966
+ if (!sys) return null;
967
+ const variant = type % 10;
968
+ if (variant < 4 || variant > 7) return null;
969
+ const payload = frame.payload;
970
+ if (!payload || payload.length < 10) return null;
971
+ try {
972
+ const bits = new BitReader2(payload);
973
+ bits.skip(12);
974
+ bits.skip(12);
975
+ const epochMs = bits.u(30);
976
+ bits.skip(1);
977
+ bits.skip(3);
978
+ bits.skip(7);
979
+ bits.skip(2);
980
+ bits.skip(2);
981
+ bits.skip(1);
982
+ bits.skip(3);
983
+ const satMaskHi = bits.u(32) >>> 0;
984
+ const satMaskLo = bits.u(32) >>> 0;
985
+ const satIndices = [];
986
+ for (let i = 0; i < 32; i++) {
987
+ if (satMaskHi & 1 << 31 - i) satIndices.push(i + 1);
988
+ }
989
+ for (let i = 0; i < 32; i++) {
990
+ if (satMaskLo & 1 << 31 - i) satIndices.push(i + 33);
991
+ }
992
+ const numSat = satIndices.length;
993
+ if (numSat === 0) return null;
994
+ const sigMask = bits.u(32) >>> 0;
995
+ const sigIndices = [];
996
+ for (let i = 0; i < 32; i++) {
997
+ if (sigMask & 1 << 31 - i) sigIndices.push(i);
998
+ }
999
+ const numSig = sigIndices.length;
1000
+ if (numSig === 0) return null;
1001
+ const numCells = numSat * numSig;
1002
+ const cellMask = [];
1003
+ for (let i = 0; i < numCells; i++) {
1004
+ cellMask.push(bits.u(1) === 1);
1005
+ }
1006
+ let activeCells = 0;
1007
+ for (const c of cellMask) if (c) activeCells++;
1008
+ if (activeCells === 0) return null;
1009
+ const rrint = new Float64Array(numSat);
1010
+ const rrmod = new Float64Array(numSat);
1011
+ const extsat = new Int8Array(numSat);
1012
+ const rdop = new Float64Array(numSat);
1013
+ if (variant === 4 || variant === 6) {
1014
+ for (let j = 0; j < numSat; j++) rrint[j] = bits.u(8);
1015
+ for (let j = 0; j < numSat; j++) rrmod[j] = bits.u(10) / 1024;
1016
+ } else {
1017
+ for (let j = 0; j < numSat; j++) rrint[j] = bits.u(8);
1018
+ for (let j = 0; j < numSat; j++) extsat[j] = bits.u(4);
1019
+ for (let j = 0; j < numSat; j++) rrmod[j] = bits.u(10) / 1024;
1020
+ for (let j = 0; j < numSat; j++) rdop[j] = bits.s(14) * 1;
1021
+ }
1022
+ if (sys === "R") {
1023
+ for (let j = 0; j < numSat; j++) {
1024
+ const slot = satIndices[j];
1025
+ if (extsat[j] !== 0) {
1026
+ gloFreqNum[slot - 1] = extsat[j] - 7;
1027
+ }
1028
+ }
1029
+ }
1030
+ const psr = new Float64Array(activeCells);
1031
+ const cp = new Float64Array(activeCells);
1032
+ const ll = new Uint16Array(activeCells);
1033
+ const hc = new Uint8Array(activeCells);
1034
+ const cnr = new Float64Array(activeCells);
1035
+ const dop = new Float64Array(activeCells);
1036
+ psr.fill(-1e30);
1037
+ cp.fill(-1e30);
1038
+ dop.fill(-1e30);
1039
+ if (variant === 4) {
1040
+ for (let i = 0; i < activeCells; i++) psr[i] = bits.s(15) / 2 ** 24;
1041
+ for (let i = 0; i < activeCells; i++) cp[i] = bits.s(22) / 2 ** 29;
1042
+ for (let i = 0; i < activeCells; i++) ll[i] = bits.u(4);
1043
+ for (let i = 0; i < activeCells; i++) hc[i] = bits.u(1);
1044
+ for (let i = 0; i < activeCells; i++) cnr[i] = bits.u(6);
1045
+ } else if (variant === 5) {
1046
+ for (let i = 0; i < activeCells; i++) psr[i] = bits.s(15) / 2 ** 24;
1047
+ for (let i = 0; i < activeCells; i++) cp[i] = bits.s(22) / 2 ** 29;
1048
+ for (let i = 0; i < activeCells; i++) ll[i] = bits.u(4);
1049
+ for (let i = 0; i < activeCells; i++) hc[i] = bits.u(1);
1050
+ for (let i = 0; i < activeCells; i++) cnr[i] = bits.u(6);
1051
+ for (let i = 0; i < activeCells; i++) dop[i] = bits.s(15) * 1e-4;
1052
+ } else if (variant === 6) {
1053
+ for (let i = 0; i < activeCells; i++) psr[i] = bits.s(20) / 2 ** 29;
1054
+ for (let i = 0; i < activeCells; i++) cp[i] = bits.s(24) / 2 ** 31;
1055
+ for (let i = 0; i < activeCells; i++) ll[i] = bits.u(10);
1056
+ for (let i = 0; i < activeCells; i++) hc[i] = bits.u(1);
1057
+ for (let i = 0; i < activeCells; i++) cnr[i] = bits.u(10) / 16;
1058
+ } else {
1059
+ for (let i = 0; i < activeCells; i++) psr[i] = bits.s(20) / 2 ** 29;
1060
+ for (let i = 0; i < activeCells; i++) cp[i] = bits.s(24) / 2 ** 31;
1061
+ for (let i = 0; i < activeCells; i++) ll[i] = bits.u(10);
1062
+ for (let i = 0; i < activeCells; i++) hc[i] = bits.u(1);
1063
+ for (let i = 0; i < activeCells; i++) cnr[i] = bits.u(10) / 16;
1064
+ for (let i = 0; i < activeCells; i++) dop[i] = bits.s(15) * 1e-4;
1065
+ }
1066
+ const sigTable = signalTable(sys);
1067
+ const observations = [];
1068
+ let cellIdx = 0;
1069
+ for (let s = 0; s < numSat; s++) {
1070
+ const satIdx1 = satIndices[s];
1071
+ const prn = satPrn(sys, satIdx1);
1072
+ const roughRange_ms = rrint[s] + rrmod[s];
1073
+ const roughRange_m = roughRange_ms * C_LIGHT / 1e3;
1074
+ const roughRate_ms = rdop[s];
1075
+ const signals = [];
1076
+ for (let g = 0; g < numSig; g++) {
1077
+ const maskIdx = s * numSig + g;
1078
+ if (!cellMask[maskIdx]) continue;
1079
+ const sigIdx = sigIndices[g];
1080
+ const sigDef = sigTable[sigIdx] ?? EMPTY;
1081
+ if (!sigDef.code) {
1082
+ cellIdx++;
1083
+ continue;
1084
+ }
1085
+ let wavelength;
1086
+ if (sys === "R" && (sigDef.freq === 0 || sigDef.freq === 1)) {
1087
+ wavelength = gloWavelength(satIdx1 - 1, sigDef.freq);
1088
+ } else if (sigDef.freq > 0) {
1089
+ wavelength = C_LIGHT / sigDef.freq;
1090
+ } else {
1091
+ wavelength = 0;
1092
+ }
1093
+ const signal = {
1094
+ rinexCode: sigDef.code,
1095
+ wavelength
1096
+ };
1097
+ const psrVal = psr[cellIdx];
1098
+ if (psrVal > -1 / (1 << 10)) {
1099
+ signal.pseudorange = psrVal * C_LIGHT / 1e3 + roughRange_m;
1100
+ }
1101
+ const cpVal = cp[cellIdx];
1102
+ if (cpVal > -1 / (1 << 8) && wavelength > 0) {
1103
+ signal.phase = cpVal * C_LIGHT / 1e3 / wavelength + roughRange_m / wavelength;
1104
+ }
1105
+ if (variant === 5 || variant === 7) {
1106
+ const dopVal = dop[cellIdx];
1107
+ if (dopVal > -1.6384 && wavelength > 0) {
1108
+ signal.doppler = -(dopVal + roughRate_ms) / wavelength;
1109
+ }
1110
+ }
1111
+ const cnrVal = cnr[cellIdx];
1112
+ if (cnrVal > 0) {
1113
+ signal.cn0 = cnrVal;
1114
+ }
1115
+ signal.lockTime = lockTimeSec(type, ll[cellIdx]);
1116
+ signal.halfCycle = hc[cellIdx] === 1;
1117
+ signals.push(signal);
1118
+ cellIdx++;
1119
+ }
1120
+ if (signals.length > 0) {
1121
+ observations.push({ prn, system: sys, signals });
1122
+ }
1123
+ }
1124
+ return {
1125
+ messageType: type,
1126
+ epochMs,
1127
+ system: sys,
1128
+ observations
1129
+ };
1130
+ } catch {
1131
+ return null;
1132
+ }
1133
+ }
1134
+ var GPS_EPOCH = Date.UTC(1980, 0, 6);
1135
+ var MS_PER_WEEK = 6048e5;
1136
+ function msmEpochToDate(sys, epochMs, refTime = /* @__PURE__ */ new Date()) {
1137
+ const refMs = refTime.getTime();
1138
+ if (sys === "R") {
1139
+ const dayOfWeek = epochMs >>> 27 & 7;
1140
+ const msOfDay = epochMs & 134217727;
1141
+ const utcDay = new Date(refMs).getUTCDay();
1142
+ const diff = dayOfWeek - utcDay;
1143
+ const dayMs = 864e5;
1144
+ let t2 = refMs - refMs % dayMs + diff * dayMs + msOfDay - 3 * 36e5;
1145
+ while (t2 - refMs > 3 * dayMs) t2 -= 7 * dayMs;
1146
+ while (refMs - t2 > 3 * dayMs) t2 += 7 * dayMs;
1147
+ return new Date(t2);
1148
+ }
1149
+ if (sys === "C") {
1150
+ const BDS_EPOCH = Date.UTC(2006, 0, 1) - 14e3;
1151
+ const weeksSinceEpoch2 = Math.floor((refMs - BDS_EPOCH) / MS_PER_WEEK);
1152
+ let t2 = BDS_EPOCH + weeksSinceEpoch2 * MS_PER_WEEK + epochMs;
1153
+ if (t2 - refMs > MS_PER_WEEK / 2) t2 -= MS_PER_WEEK;
1154
+ else if (refMs - t2 > MS_PER_WEEK / 2) t2 += MS_PER_WEEK;
1155
+ return new Date(t2);
1156
+ }
1157
+ const weeksSinceEpoch = Math.floor((refMs - GPS_EPOCH) / MS_PER_WEEK);
1158
+ let t = GPS_EPOCH + weeksSinceEpoch * MS_PER_WEEK + epochMs;
1159
+ if (t - refMs > MS_PER_WEEK / 2) t -= MS_PER_WEEK;
1160
+ else if (refMs - t > MS_PER_WEEK / 2) t += MS_PER_WEEK;
1161
+ t -= 18e3;
1162
+ return new Date(t);
1163
+ }
1164
+ function resetGloFreqCache() {
1165
+ gloFreqNum.fill(-128);
1166
+ }
1167
+
1168
+ // src/rtcm3/station.ts
1169
+ function createStationMeta() {
1170
+ return {
1171
+ stationId: null,
1172
+ itrf: null,
1173
+ position: null,
1174
+ antennaHeight: null,
1175
+ antennaType: null,
1176
+ antennaSerial: null,
1177
+ antennaSetupId: null,
1178
+ receiverType: null,
1179
+ receiverFirmware: null,
1180
+ receiverSerial: null,
1181
+ description: null
1182
+ };
1183
+ }
1184
+ function decodeStationARP(payload, msgType, meta) {
1185
+ if (payload.length < 19) return;
1186
+ const r = new BitReader(payload);
1187
+ r.skip(12);
1188
+ meta.stationId = r.readU(12);
1189
+ meta.itrf = r.readU(6);
1190
+ r.skip(4);
1191
+ const x = r.readS(38) * 1e-4;
1192
+ r.skip(1);
1193
+ r.skip(1);
1194
+ const y = r.readS(38) * 1e-4;
1195
+ r.skip(2);
1196
+ const z = r.readS(38) * 1e-4;
1197
+ if (x !== 0 || y !== 0 || z !== 0) {
1198
+ meta.position = [x, y, z];
1199
+ }
1200
+ if (msgType === 1006) {
1201
+ meta.antennaHeight = r.readU(16) * 1e-4;
1202
+ }
1203
+ }
1204
+ function decodeAntennaDescriptor(payload, msgType, meta) {
1205
+ if (payload.length < 5) return;
1206
+ const r = new BitReader(payload);
1207
+ r.skip(12);
1208
+ meta.stationId = r.readU(12);
1209
+ const descLen = r.readU(8);
1210
+ if (descLen > 0 && descLen <= 31) {
1211
+ meta.antennaType = readString(r, descLen);
1212
+ }
1213
+ meta.antennaSetupId = r.readU(8);
1214
+ if (msgType === 1008) {
1215
+ const serialLen = r.readU(8);
1216
+ if (serialLen > 0 && serialLen <= 31) {
1217
+ meta.antennaSerial = readString(r, serialLen);
1218
+ }
1219
+ }
1220
+ }
1221
+ function decodeReceiverAntennaDescriptor(payload, meta) {
1222
+ if (payload.length < 8) return;
1223
+ const r = new BitReader(payload);
1224
+ r.skip(12);
1225
+ meta.stationId = r.readU(12);
1226
+ const antDescLen = r.readU(8);
1227
+ if (antDescLen > 0 && antDescLen <= 31) {
1228
+ meta.antennaType = readString(r, antDescLen);
1229
+ } else {
1230
+ r.skip(antDescLen * 8);
1231
+ }
1232
+ meta.antennaSetupId = r.readU(8);
1233
+ const antSerLen = r.readU(8);
1234
+ if (antSerLen > 0 && antSerLen <= 31) {
1235
+ meta.antennaSerial = readString(r, antSerLen);
1236
+ } else {
1237
+ r.skip(antSerLen * 8);
1238
+ }
1239
+ const rcvTypeLen = r.readU(8);
1240
+ if (rcvTypeLen > 0 && rcvTypeLen <= 31) {
1241
+ meta.receiverType = readString(r, rcvTypeLen);
1242
+ } else {
1243
+ r.skip(rcvTypeLen * 8);
1244
+ }
1245
+ const rcvFwLen = r.readU(8);
1246
+ if (rcvFwLen > 0 && rcvFwLen <= 31) {
1247
+ meta.receiverFirmware = readString(r, rcvFwLen);
1248
+ } else {
1249
+ r.skip(rcvFwLen * 8);
1250
+ }
1251
+ const rcvSerLen = r.readU(8);
1252
+ if (rcvSerLen > 0 && rcvSerLen <= 31) {
1253
+ meta.receiverSerial = readString(r, rcvSerLen);
1254
+ } else {
1255
+ r.skip(rcvSerLen * 8);
1256
+ }
1257
+ }
1258
+ function decodeTextString(payload, meta) {
1259
+ if (payload.length < 6) return;
1260
+ const r = new BitReader(payload);
1261
+ r.skip(12);
1262
+ meta.stationId = r.readU(12);
1263
+ r.skip(16);
1264
+ r.skip(17);
1265
+ r.skip(7);
1266
+ const nBytes = r.readU(8);
1267
+ if (nBytes > 0 && nBytes <= 127) {
1268
+ const bytes = [];
1269
+ for (let i = 0; i < nBytes; i++) bytes.push(r.readU(8));
1270
+ try {
1271
+ meta.description = new TextDecoder("utf-8").decode(new Uint8Array(bytes)).trim();
1272
+ } catch {
1273
+ meta.description = String.fromCharCode(...bytes).trim();
1274
+ }
1275
+ }
1276
+ }
1277
+ function updateStationMeta(meta, frame) {
1278
+ try {
1279
+ switch (frame.messageType) {
1280
+ case 1005:
1281
+ case 1006:
1282
+ decodeStationARP(frame.payload, frame.messageType, meta);
1283
+ return true;
1284
+ case 1007:
1285
+ case 1008:
1286
+ decodeAntennaDescriptor(frame.payload, frame.messageType, meta);
1287
+ return true;
1288
+ case 1033:
1289
+ decodeReceiverAntennaDescriptor(frame.payload, meta);
1290
+ return true;
1291
+ case 1029:
1292
+ decodeTextString(frame.payload, meta);
1293
+ return true;
1294
+ default:
1295
+ return false;
1296
+ }
1297
+ } catch {
1298
+ return false;
1299
+ }
1300
+ }
1301
+
1302
+ // src/rtcm3/stats.ts
1303
+ var RTCM3_MESSAGE_NAMES = {
1304
+ // GPS
1305
+ 1001: "GPS L1 Code",
1306
+ 1002: "GPS L1 Code+Phase",
1307
+ 1003: "GPS L1/L2 Code",
1308
+ 1004: "GPS L1/L2 Code+Phase",
1309
+ 1005: "Station ARP (no height)",
1310
+ 1006: "Station ARP (with height)",
1311
+ 1007: "Antenna Descriptor",
1312
+ 1008: "Antenna Descriptor+Serial",
1313
+ 1009: "GLONASS L1 Code",
1314
+ 1010: "GLONASS L1 Code+Phase",
1315
+ 1011: "GLONASS L1/L2 Code",
1316
+ 1012: "GLONASS L1/L2 Code+Phase",
1317
+ 1013: "System Parameters",
1318
+ 1014: "Network Aux Station Data",
1319
+ 1015: "GPS Ionospheric Corrections",
1320
+ 1016: "GPS Geometric Corrections",
1321
+ 1017: "GPS Combined Corrections",
1322
+ 1019: "GPS Ephemeris",
1323
+ 1020: "GLONASS Ephemeris",
1324
+ 1029: "Unicode Text String",
1325
+ 1030: "GPS Network RTK Residual",
1326
+ 1031: "GLONASS Network RTK Residual",
1327
+ 1032: "Physical Reference Station",
1328
+ 1033: "Receiver+Antenna Descriptor",
1329
+ 1042: "BeiDou Ephemeris",
1330
+ 1043: "SBAS Ephemeris",
1331
+ 1044: "QZSS Ephemeris",
1332
+ 1045: "Galileo F/NAV Ephemeris",
1333
+ 1046: "Galileo I/NAV Ephemeris",
1334
+ // MSM
1335
+ 1071: "GPS MSM1",
1336
+ 1072: "GPS MSM2",
1337
+ 1073: "GPS MSM3",
1338
+ 1074: "GPS MSM4",
1339
+ 1075: "GPS MSM5",
1340
+ 1076: "GPS MSM6",
1341
+ 1077: "GPS MSM7",
1342
+ 1081: "GLONASS MSM1",
1343
+ 1082: "GLONASS MSM2",
1344
+ 1083: "GLONASS MSM3",
1345
+ 1084: "GLONASS MSM4",
1346
+ 1085: "GLONASS MSM5",
1347
+ 1086: "GLONASS MSM6",
1348
+ 1087: "GLONASS MSM7",
1349
+ 1091: "Galileo MSM1",
1350
+ 1092: "Galileo MSM2",
1351
+ 1093: "Galileo MSM3",
1352
+ 1094: "Galileo MSM4",
1353
+ 1095: "Galileo MSM5",
1354
+ 1096: "Galileo MSM6",
1355
+ 1097: "Galileo MSM7",
1356
+ 1101: "SBAS MSM1",
1357
+ 1102: "SBAS MSM2",
1358
+ 1103: "SBAS MSM3",
1359
+ 1104: "SBAS MSM4",
1360
+ 1105: "SBAS MSM5",
1361
+ 1106: "SBAS MSM6",
1362
+ 1107: "SBAS MSM7",
1363
+ 1111: "QZSS MSM1",
1364
+ 1112: "QZSS MSM2",
1365
+ 1113: "QZSS MSM3",
1366
+ 1114: "QZSS MSM4",
1367
+ 1115: "QZSS MSM5",
1368
+ 1116: "QZSS MSM6",
1369
+ 1117: "QZSS MSM7",
1370
+ 1121: "BeiDou MSM1",
1371
+ 1122: "BeiDou MSM2",
1372
+ 1123: "BeiDou MSM3",
1373
+ 1124: "BeiDou MSM4",
1374
+ 1125: "BeiDou MSM5",
1375
+ 1126: "BeiDou MSM6",
1376
+ 1127: "BeiDou MSM7",
1377
+ 1131: "NavIC MSM1",
1378
+ 1132: "NavIC MSM2",
1379
+ 1133: "NavIC MSM3",
1380
+ 1134: "NavIC MSM4",
1381
+ 1135: "NavIC MSM5",
1382
+ 1136: "NavIC MSM6",
1383
+ 1137: "NavIC MSM7",
1384
+ // SSR
1385
+ 1057: "GPS SSR Orbit",
1386
+ 1058: "GPS SSR Clock",
1387
+ 1059: "GPS SSR Code Bias",
1388
+ 1060: "GPS SSR Orbit+Clock",
1389
+ 1063: "GLONASS SSR Orbit",
1390
+ 1064: "GLONASS SSR Clock",
1391
+ 1065: "GLONASS SSR Code Bias",
1392
+ 1066: "GLONASS SSR Orbit+Clock",
1393
+ // IGS SSR
1394
+ 4076: "IGS SSR"
1395
+ };
1396
+ function rtcm3Constellation(msgType) {
1397
+ if (msgType >= 1001 && msgType <= 1004) return "GPS";
1398
+ if (msgType >= 1009 && msgType <= 1012) return "GLONASS";
1399
+ if (msgType === 1019) return "GPS";
1400
+ if (msgType === 1020) return "GLONASS";
1401
+ if (msgType === 1042) return "BeiDou";
1402
+ if (msgType === 1043) return "SBAS";
1403
+ if (msgType === 1044) return "QZSS";
1404
+ if (msgType === 1045 || msgType === 1046) return "Galileo";
1405
+ if (msgType >= 1071 && msgType <= 1077) return "GPS";
1406
+ if (msgType >= 1081 && msgType <= 1087) return "GLONASS";
1407
+ if (msgType >= 1091 && msgType <= 1097) return "Galileo";
1408
+ if (msgType >= 1101 && msgType <= 1107) return "SBAS";
1409
+ if (msgType >= 1111 && msgType <= 1117) return "QZSS";
1410
+ if (msgType >= 1121 && msgType <= 1127) return "BeiDou";
1411
+ if (msgType >= 1131 && msgType <= 1137) return "NavIC";
1412
+ return null;
1413
+ }
1414
+ function createStreamStats() {
1415
+ return {
1416
+ totalBytes: 0,
1417
+ totalFrames: 0,
1418
+ startTime: Date.now(),
1419
+ messageTypes: /* @__PURE__ */ new Map(),
1420
+ bytesPerSecond: 0,
1421
+ framesPerSecond: 0,
1422
+ satellites: /* @__PURE__ */ new Map(),
1423
+ ephemerides: /* @__PURE__ */ new Map(),
1424
+ obsTypes: {},
1425
+ stationMeta: createStationMeta()
1426
+ };
1427
+ }
1428
+ function updateStreamStats(stats, frames, rawBytes) {
1429
+ const now = Date.now();
1430
+ stats.totalBytes += rawBytes;
1431
+ stats.totalFrames += frames.length;
1432
+ for (const frame of frames) {
1433
+ let entry = stats.messageTypes.get(frame.messageType);
1434
+ if (!entry) {
1435
+ entry = {
1436
+ messageType: frame.messageType,
1437
+ name: RTCM3_MESSAGE_NAMES[frame.messageType] ?? `Unknown (${frame.messageType})`,
1438
+ count: 0,
1439
+ lastSeen: now,
1440
+ constellation: rtcm3Constellation(frame.messageType),
1441
+ totalBytes: 0
1442
+ };
1443
+ stats.messageTypes.set(frame.messageType, entry);
1444
+ }
1445
+ entry.count++;
1446
+ entry.lastSeen = now;
1447
+ entry.totalBytes += frame.length + 6;
1448
+ const msmEpoch = decodeMsmFull(frame);
1449
+ if (msmEpoch) {
1450
+ const now2 = Date.now();
1451
+ for (const obs of msmEpoch.observations) {
1452
+ const signals = [];
1453
+ let bestCn0 = 0;
1454
+ for (const sig of obs.signals) {
1455
+ if (sig.cn0 !== void 0 && sig.cn0 > 0) {
1456
+ signals.push({ code: sig.rinexCode, cn0: sig.cn0 });
1457
+ if (sig.cn0 > bestCn0) bestCn0 = sig.cn0;
1458
+ }
1459
+ }
1460
+ if (signals.length > 0) {
1461
+ stats.satellites.set(obs.prn, {
1462
+ prn: obs.prn,
1463
+ system: obs.system,
1464
+ cn0: bestCn0,
1465
+ lastSeen: now2,
1466
+ signals
1467
+ });
1468
+ }
1469
+ let sysSet = stats.obsTypes[obs.system];
1470
+ if (!sysSet) {
1471
+ sysSet = /* @__PURE__ */ new Set();
1472
+ stats.obsTypes[obs.system] = sysSet;
1473
+ }
1474
+ for (const sig of obs.signals) {
1475
+ if (sig.pseudorange !== void 0) sysSet.add(`C${sig.rinexCode}`);
1476
+ if (sig.phase !== void 0) sysSet.add(`L${sig.rinexCode}`);
1477
+ if (sig.doppler !== void 0) sysSet.add(`D${sig.rinexCode}`);
1478
+ if (sig.cn0 !== void 0) sysSet.add(`S${sig.rinexCode}`);
1479
+ }
1480
+ }
1481
+ }
1482
+ const eph = decodeEphemeris(frame);
1483
+ if (eph) {
1484
+ stats.ephemerides.set(eph.prn, eph);
1485
+ }
1486
+ updateStationMeta(stats.stationMeta, frame);
1487
+ }
1488
+ for (const [prn, sat] of stats.satellites) {
1489
+ if (now - sat.lastSeen > 3e4) stats.satellites.delete(prn);
1490
+ }
1491
+ const elapsed = (now - stats.startTime) / 1e3;
1492
+ if (elapsed > 0) {
1493
+ stats.bytesPerSecond = stats.totalBytes / elapsed;
1494
+ stats.framesPerSecond = stats.totalFrames / elapsed;
1495
+ }
1496
+ }
1497
+ // Annotate the CommonJS export names for ESM import in node:
1498
+ 0 && (module.exports = {
1499
+ BitReader,
1500
+ RTCM3_MESSAGE_NAMES,
1501
+ Rtcm3Decoder,
1502
+ createStationMeta,
1503
+ createStreamStats,
1504
+ decodeEphemeris,
1505
+ decodeMsmFull,
1506
+ msmEpochToDate,
1507
+ readString,
1508
+ resetGloFreqCache,
1509
+ rtcm3Constellation,
1510
+ updateStationMeta,
1511
+ updateStreamStats
1512
+ });