gnss-js 1.2.0 → 1.3.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 +10 -0
- package/dist/chunk-4KOXMHUW.js +223 -0
- package/dist/{chunk-VANVV4F7.js → chunk-CC2R4JGS.js} +69 -7
- package/dist/chunk-USHP4IND.js +206 -0
- package/dist/frames.js +6 -216
- package/dist/index.cjs +496 -9
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +23 -1
- package/dist/orbit.cjs +70 -6
- package/dist/orbit.d.cts +40 -1
- package/dist/orbit.d.ts +40 -1
- package/dist/orbit.js +5 -1
- package/dist/positioning.cjs +6 -3
- package/dist/positioning.d.cts +11 -3
- package/dist/positioning.d.ts +11 -3
- package/dist/positioning.js +6 -196
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -75,6 +75,7 @@ __export(src_exports, {
|
|
|
75
75
|
MILLISECONDS_IN_WEEK: () => MILLISECONDS_IN_WEEK,
|
|
76
76
|
MILLISECONDS_TT_TAI: () => MILLISECONDS_TT_TAI,
|
|
77
77
|
MultipathAccumulator: () => MultipathAccumulator,
|
|
78
|
+
REFERENCE_FRAMES: () => REFERENCE_FRAMES,
|
|
78
79
|
RINEX_CODES: () => RINEX_CODES,
|
|
79
80
|
RTCM3_MESSAGE_NAMES: () => RTCM3_MESSAGE_NAMES,
|
|
80
81
|
Rtcm3Decoder: () => Rtcm3Decoder,
|
|
@@ -101,6 +102,7 @@ __export(src_exports, {
|
|
|
101
102
|
WGS84_SEMI_MINOR_AXIS: () => WGS84_SEMI_MINOR_AXIS,
|
|
102
103
|
WarningAccumulator: () => WarningAccumulator,
|
|
103
104
|
analyzeQuality: () => analyzeQuality,
|
|
105
|
+
applyHelmert: () => applyHelmert,
|
|
104
106
|
buildGloChannelMap: () => buildGloChannelMap,
|
|
105
107
|
buildObsIndices: () => buildObsIndices,
|
|
106
108
|
clampUnit: () => clampUnit,
|
|
@@ -110,17 +112,20 @@ __export(src_exports, {
|
|
|
110
112
|
computePsdDb: () => computePsdDb,
|
|
111
113
|
computeSatPosition: () => computeSatPosition,
|
|
112
114
|
computeStats: () => computeStats2,
|
|
115
|
+
computeVisibility: () => computeVisibility,
|
|
113
116
|
connectToMountpoint: () => connectToMountpoint,
|
|
114
117
|
createStationMeta: () => createStationMeta,
|
|
115
118
|
createStreamStats: () => createStreamStats,
|
|
116
119
|
crxDecompress: () => crxDecompress,
|
|
117
120
|
crxRepair: () => crxRepair,
|
|
121
|
+
dateToEpoch: () => dateToEpoch,
|
|
118
122
|
decodeEphemeris: () => decodeEphemeris,
|
|
119
123
|
decodeMsmFull: () => decodeMsmFull,
|
|
120
124
|
deg2dms: () => deg2dms,
|
|
121
125
|
deg2rad: () => deg2rad,
|
|
122
126
|
ecefToAzEl: () => ecefToAzEl,
|
|
123
127
|
ecefToGeodetic: () => ecefToGeodetic,
|
|
128
|
+
ephInfoToEphemeris: () => ephInfoToEphemeris,
|
|
124
129
|
euclidean3D: () => euclidean3D,
|
|
125
130
|
fetchSourcetable: () => fetchSourcetable,
|
|
126
131
|
fmtF: () => fmtF,
|
|
@@ -188,6 +193,7 @@ __export(src_exports, {
|
|
|
188
193
|
greatCircleMidpoint: () => greatCircleMidpoint,
|
|
189
194
|
hdrLine: () => hdrLine,
|
|
190
195
|
horizonDistance: () => horizonDistance,
|
|
196
|
+
ionoFree: () => ionoFree,
|
|
191
197
|
keplerPosition: () => keplerPosition,
|
|
192
198
|
msmEpochToDate: () => msmEpochToDate,
|
|
193
199
|
navTimesFromEph: () => navTimesFromEph,
|
|
@@ -210,11 +216,14 @@ __export(src_exports, {
|
|
|
210
216
|
resetGloFreqCache: () => resetGloFreqCache,
|
|
211
217
|
rhumbLine: () => rhumbLine,
|
|
212
218
|
rtcm3Constellation: () => rtcm3Constellation,
|
|
219
|
+
satClockCorrection: () => satClockCorrection,
|
|
213
220
|
selectEphemeris: () => selectEphemeris,
|
|
214
221
|
setGloFreqNumber: () => setGloFreqNumber,
|
|
215
222
|
setRtcm3DebugHandler: () => setRtcm3DebugHandler,
|
|
223
|
+
solveSpp: () => solveSpp,
|
|
216
224
|
systemCmp: () => systemCmp,
|
|
217
225
|
systemName: () => systemName,
|
|
226
|
+
transformFrame: () => transformFrame,
|
|
218
227
|
updateStationMeta: () => updateStationMeta,
|
|
219
228
|
updateStreamStats: () => updateStreamStats,
|
|
220
229
|
verifyChecksum: () => verifyChecksum,
|
|
@@ -4128,17 +4137,17 @@ function ecefToAzEl(rxX, rxY, rxZ, satX, satY, satZ) {
|
|
|
4128
4137
|
function computeDop(satAzEls) {
|
|
4129
4138
|
const n = satAzEls.length;
|
|
4130
4139
|
if (n < 4) return null;
|
|
4131
|
-
const
|
|
4140
|
+
const H2 = [];
|
|
4132
4141
|
for (const { az, el } of satAzEls) {
|
|
4133
4142
|
const cosEl = Math.cos(el);
|
|
4134
|
-
|
|
4143
|
+
H2.push([cosEl * Math.sin(az), cosEl * Math.cos(az), Math.sin(el), 1]);
|
|
4135
4144
|
}
|
|
4136
4145
|
const HtH = Array.from({ length: 4 }, () => new Array(4).fill(0));
|
|
4137
4146
|
for (let i = 0; i < 4; i++) {
|
|
4138
4147
|
for (let j = 0; j < 4; j++) {
|
|
4139
4148
|
let sum = 0;
|
|
4140
4149
|
for (let k = 0; k < n; k++) {
|
|
4141
|
-
sum +=
|
|
4150
|
+
sum += H2[k][i] * H2[k][j];
|
|
4142
4151
|
}
|
|
4143
4152
|
HtH[i][j] = sum;
|
|
4144
4153
|
}
|
|
@@ -4191,7 +4200,8 @@ function selectEphemeris(ephemerides, prn, timeMs) {
|
|
|
4191
4200
|
if (eph.prn !== prn) continue;
|
|
4192
4201
|
const ephTime = eph.tocDate.getTime();
|
|
4193
4202
|
const dt = Math.abs(timeMs - ephTime);
|
|
4194
|
-
|
|
4203
|
+
const maxAge = eph.system === "R" || eph.system === "S" ? 18e5 : 4 * 36e5;
|
|
4204
|
+
if (dt > maxAge) continue;
|
|
4195
4205
|
if (dt < bestDt) {
|
|
4196
4206
|
bestDt = dt;
|
|
4197
4207
|
best = eph;
|
|
@@ -4299,13 +4309,13 @@ function ephInfoToEphemeris(info) {
|
|
|
4299
4309
|
return null;
|
|
4300
4310
|
if (info.vx === void 0 || info.vy === void 0 || info.vz === void 0)
|
|
4301
4311
|
return null;
|
|
4302
|
-
const
|
|
4312
|
+
const moscow = new Date(info.lastReceived + 3 * 3600 * 1e3);
|
|
4303
4313
|
const utcMidnight = Date.UTC(
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4314
|
+
moscow.getUTCFullYear(),
|
|
4315
|
+
moscow.getUTCMonth(),
|
|
4316
|
+
moscow.getUTCDate()
|
|
4307
4317
|
);
|
|
4308
|
-
const tbSec = (info.tb ?? 0) *
|
|
4318
|
+
const tbSec = (info.tb ?? 0) * 60;
|
|
4309
4319
|
const moscowOffset = 3 * 3600;
|
|
4310
4320
|
const tocMs = utcMidnight + (tbSec - moscowOffset) * 1e3;
|
|
4311
4321
|
return {
|
|
@@ -4408,6 +4418,474 @@ function computeLiveSkyPositions(ephemerides, rxPos, cn0Map) {
|
|
|
4408
4418
|
}
|
|
4409
4419
|
return result;
|
|
4410
4420
|
}
|
|
4421
|
+
function computeVisibility(ephemerides, rxPos, startMs, endMs, stepSec = 300, elevationMaskDeg = 10) {
|
|
4422
|
+
const stepMs = stepSec * 1e3;
|
|
4423
|
+
const times = [];
|
|
4424
|
+
for (let t = startMs; t <= endMs; t += stepMs) times.push(t);
|
|
4425
|
+
const maskRad = elevationMaskDeg * Math.PI / 180;
|
|
4426
|
+
const all = computeAllPositions(ephemerides, times, rxPos);
|
|
4427
|
+
const elevation = {};
|
|
4428
|
+
const visibleCount = new Array(times.length).fill(0);
|
|
4429
|
+
const pdop = new Array(times.length).fill(null);
|
|
4430
|
+
const visiblePerEpoch = times.map(() => []);
|
|
4431
|
+
for (const prn of all.prns) {
|
|
4432
|
+
const series = all.positions[prn];
|
|
4433
|
+
elevation[prn] = series.map((p) => p ? p.el : null);
|
|
4434
|
+
for (let i = 0; i < series.length; i++) {
|
|
4435
|
+
const p = series[i];
|
|
4436
|
+
if (p && p.el >= maskRad) {
|
|
4437
|
+
visibleCount[i]++;
|
|
4438
|
+
visiblePerEpoch[i].push({ az: p.az, el: p.el });
|
|
4439
|
+
}
|
|
4440
|
+
}
|
|
4441
|
+
}
|
|
4442
|
+
for (let i = 0; i < times.length; i++) {
|
|
4443
|
+
const dop = computeDop(visiblePerEpoch[i]);
|
|
4444
|
+
pdop[i] = dop ? dop.pdop : null;
|
|
4445
|
+
}
|
|
4446
|
+
const passes = [];
|
|
4447
|
+
for (const prn of all.prns) {
|
|
4448
|
+
const els = elevation[prn];
|
|
4449
|
+
let start = -1;
|
|
4450
|
+
let peakEl = -Infinity;
|
|
4451
|
+
let peakTime = 0;
|
|
4452
|
+
for (let i = 0; i <= els.length; i++) {
|
|
4453
|
+
const el = i < els.length ? els[i] : null;
|
|
4454
|
+
const above = el !== null && el !== void 0 && el >= maskRad;
|
|
4455
|
+
if (above) {
|
|
4456
|
+
if (start === -1) {
|
|
4457
|
+
start = i;
|
|
4458
|
+
peakEl = -Infinity;
|
|
4459
|
+
}
|
|
4460
|
+
if (el > peakEl) {
|
|
4461
|
+
peakEl = el;
|
|
4462
|
+
peakTime = times[i];
|
|
4463
|
+
}
|
|
4464
|
+
} else if (start !== -1) {
|
|
4465
|
+
passes.push({
|
|
4466
|
+
prn,
|
|
4467
|
+
system: prn[0],
|
|
4468
|
+
rise: times[start],
|
|
4469
|
+
set: times[i - 1],
|
|
4470
|
+
peakTime,
|
|
4471
|
+
peakEl
|
|
4472
|
+
});
|
|
4473
|
+
start = -1;
|
|
4474
|
+
}
|
|
4475
|
+
}
|
|
4476
|
+
}
|
|
4477
|
+
passes.sort((a, b) => a.rise - b.rise);
|
|
4478
|
+
return { times, elevation, visibleCount, pdop, passes };
|
|
4479
|
+
}
|
|
4480
|
+
|
|
4481
|
+
// src/frames/index.ts
|
|
4482
|
+
var H = (t, d, r, tDot, dDot, rDot, epoch) => ({ t, d, r, tDot, dDot, rDot, epoch });
|
|
4483
|
+
var Z = [0, 0, 0];
|
|
4484
|
+
var FROM_ITRF2020 = {
|
|
4485
|
+
ITRF2014: H([-1.4, -0.9, 1.4], -0.42, Z, [0, -0.1, 0.2], 0, Z, 2015),
|
|
4486
|
+
ITRF2008: H([0.2, 1, 3.3], -0.29, Z, [0, -0.1, 0.1], 0.03, Z, 2015),
|
|
4487
|
+
ITRF2005: H([2.7, 0.1, -1.4], 0.65, Z, [0.3, -0.1, 0.1], 0.03, Z, 2015),
|
|
4488
|
+
ITRF2000: H([-0.2, 0.8, -34.2], 2.25, Z, [0.1, 0, -1.7], 0.11, Z, 2015),
|
|
4489
|
+
ITRF97: H(
|
|
4490
|
+
[6.5, -3.9, -77.9],
|
|
4491
|
+
3.98,
|
|
4492
|
+
[0, 0, 0.36],
|
|
4493
|
+
[0.1, -0.6, -3.1],
|
|
4494
|
+
0.12,
|
|
4495
|
+
[0, 0, 0.02],
|
|
4496
|
+
2015
|
|
4497
|
+
),
|
|
4498
|
+
ITRF96: H(
|
|
4499
|
+
[6.5, -3.9, -77.9],
|
|
4500
|
+
3.98,
|
|
4501
|
+
[0, 0, 0.36],
|
|
4502
|
+
[0.1, -0.6, -3.1],
|
|
4503
|
+
0.12,
|
|
4504
|
+
[0, 0, 0.02],
|
|
4505
|
+
2015
|
|
4506
|
+
),
|
|
4507
|
+
ITRF94: H(
|
|
4508
|
+
[6.5, -3.9, -77.9],
|
|
4509
|
+
3.98,
|
|
4510
|
+
[0, 0, 0.36],
|
|
4511
|
+
[0.1, -0.6, -3.1],
|
|
4512
|
+
0.12,
|
|
4513
|
+
[0, 0, 0.02],
|
|
4514
|
+
2015
|
|
4515
|
+
),
|
|
4516
|
+
ITRF93: H(
|
|
4517
|
+
[-65.8, 1.9, -71.3],
|
|
4518
|
+
4.47,
|
|
4519
|
+
[-3.36, -4.33, 0.75],
|
|
4520
|
+
[-2.8, -0.2, -2.3],
|
|
4521
|
+
0.12,
|
|
4522
|
+
[-0.11, -0.19, 0.07],
|
|
4523
|
+
2015
|
|
4524
|
+
),
|
|
4525
|
+
ITRF92: H(
|
|
4526
|
+
[14.5, -1.9, -85.9],
|
|
4527
|
+
3.27,
|
|
4528
|
+
[0, 0, 0.36],
|
|
4529
|
+
[0.1, -0.6, -3.1],
|
|
4530
|
+
0.12,
|
|
4531
|
+
[0, 0, 0.02],
|
|
4532
|
+
2015
|
|
4533
|
+
),
|
|
4534
|
+
ITRF91: H(
|
|
4535
|
+
[26.5, 12.1, -91.9],
|
|
4536
|
+
4.67,
|
|
4537
|
+
[0, 0, 0.36],
|
|
4538
|
+
[0.1, -0.6, -3.1],
|
|
4539
|
+
0.12,
|
|
4540
|
+
[0, 0, 0.02],
|
|
4541
|
+
2015
|
|
4542
|
+
),
|
|
4543
|
+
ITRF90: H(
|
|
4544
|
+
[24.5, 8.1, -107.9],
|
|
4545
|
+
4.97,
|
|
4546
|
+
[0, 0, 0.36],
|
|
4547
|
+
[0.1, -0.6, -3.1],
|
|
4548
|
+
0.12,
|
|
4549
|
+
[0, 0, 0.02],
|
|
4550
|
+
2015
|
|
4551
|
+
),
|
|
4552
|
+
ITRF89: H(
|
|
4553
|
+
[29.5, 32.1, -145.9],
|
|
4554
|
+
8.37,
|
|
4555
|
+
[0, 0, 0.36],
|
|
4556
|
+
[0.1, -0.6, -3.1],
|
|
4557
|
+
0.12,
|
|
4558
|
+
[0, 0, 0.02],
|
|
4559
|
+
2015
|
|
4560
|
+
),
|
|
4561
|
+
ITRF88: H(
|
|
4562
|
+
[24.5, -3.9, -169.9],
|
|
4563
|
+
11.47,
|
|
4564
|
+
[0.1, 0, 0.36],
|
|
4565
|
+
[0.1, -0.6, -3.1],
|
|
4566
|
+
0.12,
|
|
4567
|
+
[0, 0, 0.02],
|
|
4568
|
+
2015
|
|
4569
|
+
),
|
|
4570
|
+
/** ITRF2020 → ETRF2020, EPSG:10572 (epoch-1989 variant) */
|
|
4571
|
+
ETRF2020: H(Z, 0, Z, Z, 0, [0.086, 0.519, -0.753], 1989)
|
|
4572
|
+
};
|
|
4573
|
+
var ITRF2014_TO_ETRF2014 = H(Z, 0, Z, Z, 0, [0.085, 0.531, -0.77], 1989);
|
|
4574
|
+
var ITRF2014_TO_ETRF2000 = H(
|
|
4575
|
+
[54.7, 52.2, -74.1],
|
|
4576
|
+
2.12,
|
|
4577
|
+
[1.701, 10.29, -16.632],
|
|
4578
|
+
[0.1, 0.1, -1.9],
|
|
4579
|
+
0.11,
|
|
4580
|
+
[0.081, 0.49, -0.792],
|
|
4581
|
+
2010
|
|
4582
|
+
);
|
|
4583
|
+
var ITRF2014_TO_NAD83_2011 = H(
|
|
4584
|
+
[1005.3, -1909.21, -541.57],
|
|
4585
|
+
0.36891,
|
|
4586
|
+
[-26.78138, 0.42027, -10.93206],
|
|
4587
|
+
[0.79, -0.6, -1.44],
|
|
4588
|
+
-0.07201,
|
|
4589
|
+
[-0.06667, 0.75744, 0.05133],
|
|
4590
|
+
2010
|
|
4591
|
+
);
|
|
4592
|
+
var MAS_TO_RAD = Math.PI / (180 * 3600 * 1e3);
|
|
4593
|
+
function applyHelmert(xyz, p, epoch, inverse = false) {
|
|
4594
|
+
const dt = epoch - p.epoch;
|
|
4595
|
+
const sign = inverse ? -1 : 1;
|
|
4596
|
+
const tx = sign * (p.t[0] + p.tDot[0] * dt) / 1e3;
|
|
4597
|
+
const ty = sign * (p.t[1] + p.tDot[1] * dt) / 1e3;
|
|
4598
|
+
const tz = sign * (p.t[2] + p.tDot[2] * dt) / 1e3;
|
|
4599
|
+
const d = sign * (p.d + p.dDot * dt) * 1e-9;
|
|
4600
|
+
const rx = sign * (p.r[0] + p.rDot[0] * dt) * MAS_TO_RAD;
|
|
4601
|
+
const ry = sign * (p.r[1] + p.rDot[1] * dt) * MAS_TO_RAD;
|
|
4602
|
+
const rz = sign * (p.r[2] + p.rDot[2] * dt) * MAS_TO_RAD;
|
|
4603
|
+
const [x, y, z] = xyz;
|
|
4604
|
+
return [
|
|
4605
|
+
x + tx + d * x - rz * y + ry * z,
|
|
4606
|
+
y + ty + rz * x + d * y - rx * z,
|
|
4607
|
+
z + tz - ry * x + rx * y + d * z
|
|
4608
|
+
];
|
|
4609
|
+
}
|
|
4610
|
+
var EDGES = [
|
|
4611
|
+
...Object.entries(FROM_ITRF2020).map(([to, p]) => ({
|
|
4612
|
+
from: "ITRF2020",
|
|
4613
|
+
to,
|
|
4614
|
+
p
|
|
4615
|
+
})),
|
|
4616
|
+
{ from: "ITRF2014", to: "ETRF2014", p: ITRF2014_TO_ETRF2014 },
|
|
4617
|
+
{ from: "ITRF2014", to: "ETRF2000", p: ITRF2014_TO_ETRF2000 },
|
|
4618
|
+
{ from: "ITRF2014", to: "NAD83(2011)", p: ITRF2014_TO_NAD83_2011 }
|
|
4619
|
+
];
|
|
4620
|
+
var REFERENCE_FRAMES = [
|
|
4621
|
+
"WGS84",
|
|
4622
|
+
"ITRF2020",
|
|
4623
|
+
"ITRF2014",
|
|
4624
|
+
"ITRF2008",
|
|
4625
|
+
"ITRF2005",
|
|
4626
|
+
"ITRF2000",
|
|
4627
|
+
"ITRF97",
|
|
4628
|
+
"ITRF96",
|
|
4629
|
+
"ITRF94",
|
|
4630
|
+
"ITRF93",
|
|
4631
|
+
"ITRF92",
|
|
4632
|
+
"ITRF91",
|
|
4633
|
+
"ITRF90",
|
|
4634
|
+
"ITRF89",
|
|
4635
|
+
"ITRF88",
|
|
4636
|
+
"ETRF2020",
|
|
4637
|
+
"ETRF2014",
|
|
4638
|
+
"ETRF2000",
|
|
4639
|
+
"NAD83(2011)"
|
|
4640
|
+
];
|
|
4641
|
+
function resolveAlias(f) {
|
|
4642
|
+
return f === "WGS84" ? "ITRF2020" : f;
|
|
4643
|
+
}
|
|
4644
|
+
function findPath(from, to) {
|
|
4645
|
+
if (from === to) return [];
|
|
4646
|
+
const queue = [from];
|
|
4647
|
+
const cameFrom = /* @__PURE__ */ new Map();
|
|
4648
|
+
const seen = /* @__PURE__ */ new Set([from]);
|
|
4649
|
+
while (queue.length > 0) {
|
|
4650
|
+
const cur = queue.shift();
|
|
4651
|
+
for (const edge of EDGES) {
|
|
4652
|
+
let next = null;
|
|
4653
|
+
let inverse = false;
|
|
4654
|
+
if (edge.from === cur) {
|
|
4655
|
+
next = edge.to;
|
|
4656
|
+
} else if (edge.to === cur) {
|
|
4657
|
+
next = edge.from;
|
|
4658
|
+
inverse = true;
|
|
4659
|
+
}
|
|
4660
|
+
if (next === null || seen.has(next)) continue;
|
|
4661
|
+
seen.add(next);
|
|
4662
|
+
cameFrom.set(next, { prev: cur, edge, inverse });
|
|
4663
|
+
if (next === to) {
|
|
4664
|
+
const path = [];
|
|
4665
|
+
let node = to;
|
|
4666
|
+
while (node !== from) {
|
|
4667
|
+
const step = cameFrom.get(node);
|
|
4668
|
+
path.unshift({ edge: step.edge, inverse: step.inverse });
|
|
4669
|
+
node = step.prev;
|
|
4670
|
+
}
|
|
4671
|
+
return path;
|
|
4672
|
+
}
|
|
4673
|
+
queue.push(next);
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
return null;
|
|
4677
|
+
}
|
|
4678
|
+
function transformFrame(xyz, from, to, epoch) {
|
|
4679
|
+
const src = resolveAlias(from);
|
|
4680
|
+
const dst = resolveAlias(to);
|
|
4681
|
+
const path = findPath(src, dst);
|
|
4682
|
+
if (!path) {
|
|
4683
|
+
throw new Error(`No transformation path from ${from} to ${to}`);
|
|
4684
|
+
}
|
|
4685
|
+
let out = [xyz[0], xyz[1], xyz[2]];
|
|
4686
|
+
for (const { edge, inverse } of path) {
|
|
4687
|
+
out = applyHelmert(out, edge.p, epoch, inverse);
|
|
4688
|
+
}
|
|
4689
|
+
return out;
|
|
4690
|
+
}
|
|
4691
|
+
function dateToEpoch(date) {
|
|
4692
|
+
const year = date.getUTCFullYear();
|
|
4693
|
+
const start = Date.UTC(year, 0, 1);
|
|
4694
|
+
const end = Date.UTC(year + 1, 0, 1);
|
|
4695
|
+
return year + (date.getTime() - start) / (end - start);
|
|
4696
|
+
}
|
|
4697
|
+
|
|
4698
|
+
// src/positioning/index.ts
|
|
4699
|
+
var GM_GPS2 = 3986005e8;
|
|
4700
|
+
var F_REL = -4442807633e-19;
|
|
4701
|
+
function satClockCorrection(eph, tMs) {
|
|
4702
|
+
if (eph.system === "R" || eph.system === "S") {
|
|
4703
|
+
const dt2 = (tMs - eph.tocDate.getTime()) / 1e3;
|
|
4704
|
+
return eph.tauN + eph.gammaN * dt2;
|
|
4705
|
+
}
|
|
4706
|
+
const k = eph;
|
|
4707
|
+
const dt = (tMs - k.tocDate.getTime()) / 1e3;
|
|
4708
|
+
const poly = k.af0 + k.af1 * dt + k.af2 * dt * dt;
|
|
4709
|
+
const a = k.sqrtA * k.sqrtA;
|
|
4710
|
+
const n = Math.sqrt(GM_GPS2 / (a * a * a)) + k.deltaN;
|
|
4711
|
+
const tk = dt;
|
|
4712
|
+
const Mk = k.m0 + n * tk;
|
|
4713
|
+
let Ek = Mk;
|
|
4714
|
+
for (let i = 0; i < 8; i++) {
|
|
4715
|
+
Ek = Mk + k.e * Math.sin(Ek);
|
|
4716
|
+
}
|
|
4717
|
+
const rel = F_REL * k.e * k.sqrtA * Math.sin(Ek);
|
|
4718
|
+
return poly + rel;
|
|
4719
|
+
}
|
|
4720
|
+
function ionoFree(p1, p2, f1, f2) {
|
|
4721
|
+
const g = f1 * f1 / (f1 * f1 - f2 * f2);
|
|
4722
|
+
return g * p1 - (g - 1) * p2;
|
|
4723
|
+
}
|
|
4724
|
+
function tropoDelay(elevationRad) {
|
|
4725
|
+
const sinEl = Math.sin(elevationRad);
|
|
4726
|
+
return 2.47 / (sinEl + 0.0121);
|
|
4727
|
+
}
|
|
4728
|
+
function sagnac(pos, travelTimeS) {
|
|
4729
|
+
const OMEGA_E2 = 72921151467e-15;
|
|
4730
|
+
const theta = OMEGA_E2 * travelTimeS;
|
|
4731
|
+
const c = Math.cos(theta);
|
|
4732
|
+
const s = Math.sin(theta);
|
|
4733
|
+
return [pos.x * c + pos.y * s, -pos.x * s + pos.y * c, pos.z];
|
|
4734
|
+
}
|
|
4735
|
+
function solveLinear(A, b) {
|
|
4736
|
+
const n = b.length;
|
|
4737
|
+
const M = A.map((row, i) => [...row, b[i]]);
|
|
4738
|
+
for (let col = 0; col < n; col++) {
|
|
4739
|
+
let pivot = col;
|
|
4740
|
+
for (let r = col + 1; r < n; r++) {
|
|
4741
|
+
if (Math.abs(M[r][col]) > Math.abs(M[pivot][col])) pivot = r;
|
|
4742
|
+
}
|
|
4743
|
+
if (Math.abs(M[pivot][col]) < 1e-12) return null;
|
|
4744
|
+
[M[col], M[pivot]] = [M[pivot], M[col]];
|
|
4745
|
+
for (let r = 0; r < n; r++) {
|
|
4746
|
+
if (r === col) continue;
|
|
4747
|
+
const f = M[r][col] / M[col][col];
|
|
4748
|
+
for (let c = col; c <= n; c++) M[r][c] -= f * M[col][c];
|
|
4749
|
+
}
|
|
4750
|
+
}
|
|
4751
|
+
return M.map((row, i) => row[n] / M[i][i]);
|
|
4752
|
+
}
|
|
4753
|
+
function solveSpp(pseudoranges, ephemerides, timeMs, opts = {}) {
|
|
4754
|
+
const {
|
|
4755
|
+
elevationMaskDeg = 10,
|
|
4756
|
+
troposphere = true,
|
|
4757
|
+
maxIterations = 15,
|
|
4758
|
+
convergenceM = 1e-4,
|
|
4759
|
+
tgd = true
|
|
4760
|
+
} = opts;
|
|
4761
|
+
const all = [...pseudoranges.keys()].filter((p) => ephemerides.has(p));
|
|
4762
|
+
const minSats = (list) => 3 + new Set(list.map((p) => p[0])).size;
|
|
4763
|
+
if (all.length < minSats(all)) return null;
|
|
4764
|
+
const gaussNewton = (prns) => {
|
|
4765
|
+
const systems = [...new Set(prns.map((p) => p[0]))].sort();
|
|
4766
|
+
const dim = 3 + systems.length;
|
|
4767
|
+
const sysIndex = new Map(systems.map((s, i) => [s, 3 + i]));
|
|
4768
|
+
let x2 = 0;
|
|
4769
|
+
let y2 = 0;
|
|
4770
|
+
let z2 = 0;
|
|
4771
|
+
const clock2 = new Map(systems.map((s) => [s, 0]));
|
|
4772
|
+
const residuals2 = {};
|
|
4773
|
+
let iterations2 = 0;
|
|
4774
|
+
let converged2 = false;
|
|
4775
|
+
for (let iter = 0; iter < maxIterations; iter++) {
|
|
4776
|
+
iterations2 = iter + 1;
|
|
4777
|
+
const HtH = Array.from(
|
|
4778
|
+
{ length: dim },
|
|
4779
|
+
() => new Array(dim).fill(0)
|
|
4780
|
+
);
|
|
4781
|
+
const Htv = new Array(dim).fill(0);
|
|
4782
|
+
let rows = 0;
|
|
4783
|
+
for (const k of Object.keys(residuals2)) delete residuals2[k];
|
|
4784
|
+
for (const prn of prns) {
|
|
4785
|
+
const psr = pseudoranges.get(prn);
|
|
4786
|
+
const eph = ephemerides.get(prn);
|
|
4787
|
+
const sys = prn[0];
|
|
4788
|
+
const clk = clock2.get(sys);
|
|
4789
|
+
const tTx = timeMs - psr / C_LIGHT * 1e3;
|
|
4790
|
+
const dtsClock = satClockCorrection(eph, tTx);
|
|
4791
|
+
const sat = computeSatPosition(eph, tTx - dtsClock * 1e3);
|
|
4792
|
+
if (!Number.isFinite(sat.x)) continue;
|
|
4793
|
+
const isKepler2 = eph.system !== "R" && eph.system !== "S";
|
|
4794
|
+
const dts = dtsClock - (tgd && isKepler2 ? eph.tgd : 0);
|
|
4795
|
+
const travel = Math.hypot(sat.x - x2, sat.y - y2, sat.z - z2) / C_LIGHT;
|
|
4796
|
+
const [sx, sy, sz] = sagnac(sat, travel);
|
|
4797
|
+
const rho = Math.hypot(sx - x2, sy - y2, sz - z2);
|
|
4798
|
+
const ux = (x2 - sx) / rho;
|
|
4799
|
+
const uy = (y2 - sy) / rho;
|
|
4800
|
+
const uz = (z2 - sz) / rho;
|
|
4801
|
+
let elev = Math.PI / 2;
|
|
4802
|
+
let weight = 1;
|
|
4803
|
+
const positionSane = x2 * x2 + y2 * y2 + z2 * z2 > 1e12;
|
|
4804
|
+
if (positionSane) {
|
|
4805
|
+
const azel = ecefToAzEl(x2, y2, z2, sx, sy, sz);
|
|
4806
|
+
elev = azel.el;
|
|
4807
|
+
if (iter >= 2 && elev < elevationMaskDeg * Math.PI / 180) continue;
|
|
4808
|
+
const sinEl = Math.max(Math.sin(elev), 0.1);
|
|
4809
|
+
weight = sinEl * sinEl;
|
|
4810
|
+
}
|
|
4811
|
+
const tropo = troposphere && positionSane ? tropoDelay(elev) : 0;
|
|
4812
|
+
const predicted = rho + clk - C_LIGHT * dts + tropo;
|
|
4813
|
+
const v = psr - predicted;
|
|
4814
|
+
const h = new Array(dim).fill(0);
|
|
4815
|
+
h[0] = ux;
|
|
4816
|
+
h[1] = uy;
|
|
4817
|
+
h[2] = uz;
|
|
4818
|
+
h[sysIndex.get(sys)] = 1;
|
|
4819
|
+
for (let i = 0; i < dim; i++) {
|
|
4820
|
+
for (let j = 0; j < dim; j++) HtH[i][j] += weight * h[i] * h[j];
|
|
4821
|
+
Htv[i] += weight * h[i] * v;
|
|
4822
|
+
}
|
|
4823
|
+
residuals2[prn] = v;
|
|
4824
|
+
rows++;
|
|
4825
|
+
}
|
|
4826
|
+
if (rows < dim) return null;
|
|
4827
|
+
const dx = solveLinear(HtH, Htv);
|
|
4828
|
+
if (!dx) return null;
|
|
4829
|
+
x2 += dx[0];
|
|
4830
|
+
y2 += dx[1];
|
|
4831
|
+
z2 += dx[2];
|
|
4832
|
+
for (const s of systems)
|
|
4833
|
+
clock2.set(s, clock2.get(s) + dx[sysIndex.get(s)]);
|
|
4834
|
+
if (Math.hypot(dx[0], dx[1], dx[2]) < convergenceM) {
|
|
4835
|
+
converged2 = true;
|
|
4836
|
+
break;
|
|
4837
|
+
}
|
|
4838
|
+
}
|
|
4839
|
+
return { x: x2, y: y2, z: z2, clock: clock2, residuals: residuals2, iterations: iterations2, converged: converged2 };
|
|
4840
|
+
};
|
|
4841
|
+
const REJECT_THRESHOLD_M = 50;
|
|
4842
|
+
let candidates = all;
|
|
4843
|
+
const rejected = [];
|
|
4844
|
+
let inner = null;
|
|
4845
|
+
for (let round = 0; round <= all.length; round++) {
|
|
4846
|
+
inner = gaussNewton(candidates);
|
|
4847
|
+
if (!inner) return null;
|
|
4848
|
+
const vals = Object.entries(inner.residuals);
|
|
4849
|
+
let worst = null;
|
|
4850
|
+
let worstAbs = REJECT_THRESHOLD_M;
|
|
4851
|
+
for (const [prn, v] of vals) {
|
|
4852
|
+
if (Math.abs(v) > worstAbs) {
|
|
4853
|
+
worstAbs = Math.abs(v);
|
|
4854
|
+
worst = prn;
|
|
4855
|
+
}
|
|
4856
|
+
}
|
|
4857
|
+
if (!worst) break;
|
|
4858
|
+
const remaining = candidates.filter((p) => p !== worst);
|
|
4859
|
+
if (remaining.length < minSats(remaining)) break;
|
|
4860
|
+
rejected.push(worst);
|
|
4861
|
+
candidates = remaining;
|
|
4862
|
+
}
|
|
4863
|
+
if (!inner) return null;
|
|
4864
|
+
const { x, y, z, clock, residuals, iterations, converged } = inner;
|
|
4865
|
+
const used = [];
|
|
4866
|
+
const azels = [];
|
|
4867
|
+
for (const prn of candidates) {
|
|
4868
|
+
if (!(prn in residuals)) continue;
|
|
4869
|
+
const eph = ephemerides.get(prn);
|
|
4870
|
+
const sat = computeSatPosition(eph, timeMs);
|
|
4871
|
+
if (!Number.isFinite(sat.x)) continue;
|
|
4872
|
+
const azel = ecefToAzEl(x, y, z, sat.x, sat.y, sat.z);
|
|
4873
|
+
if (azel.el >= elevationMaskDeg * Math.PI / 180) {
|
|
4874
|
+
used.push(prn);
|
|
4875
|
+
azels.push(azel);
|
|
4876
|
+
}
|
|
4877
|
+
}
|
|
4878
|
+
return {
|
|
4879
|
+
position: [x, y, z],
|
|
4880
|
+
clockBias: Object.fromEntries(clock),
|
|
4881
|
+
usedSatellites: used,
|
|
4882
|
+
rejectedSatellites: rejected,
|
|
4883
|
+
residuals,
|
|
4884
|
+
dop: computeDop(azels),
|
|
4885
|
+
iterations,
|
|
4886
|
+
converged
|
|
4887
|
+
};
|
|
4888
|
+
}
|
|
4411
4889
|
|
|
4412
4890
|
// src/ntrip/index.ts
|
|
4413
4891
|
function parseStreamEntry(fields) {
|
|
@@ -6285,6 +6763,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
6285
6763
|
MILLISECONDS_IN_WEEK,
|
|
6286
6764
|
MILLISECONDS_TT_TAI,
|
|
6287
6765
|
MultipathAccumulator,
|
|
6766
|
+
REFERENCE_FRAMES,
|
|
6288
6767
|
RINEX_CODES,
|
|
6289
6768
|
RTCM3_MESSAGE_NAMES,
|
|
6290
6769
|
Rtcm3Decoder,
|
|
@@ -6311,6 +6790,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
6311
6790
|
WGS84_SEMI_MINOR_AXIS,
|
|
6312
6791
|
WarningAccumulator,
|
|
6313
6792
|
analyzeQuality,
|
|
6793
|
+
applyHelmert,
|
|
6314
6794
|
buildGloChannelMap,
|
|
6315
6795
|
buildObsIndices,
|
|
6316
6796
|
clampUnit,
|
|
@@ -6320,17 +6800,20 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
6320
6800
|
computePsdDb,
|
|
6321
6801
|
computeSatPosition,
|
|
6322
6802
|
computeStats,
|
|
6803
|
+
computeVisibility,
|
|
6323
6804
|
connectToMountpoint,
|
|
6324
6805
|
createStationMeta,
|
|
6325
6806
|
createStreamStats,
|
|
6326
6807
|
crxDecompress,
|
|
6327
6808
|
crxRepair,
|
|
6809
|
+
dateToEpoch,
|
|
6328
6810
|
decodeEphemeris,
|
|
6329
6811
|
decodeMsmFull,
|
|
6330
6812
|
deg2dms,
|
|
6331
6813
|
deg2rad,
|
|
6332
6814
|
ecefToAzEl,
|
|
6333
6815
|
ecefToGeodetic,
|
|
6816
|
+
ephInfoToEphemeris,
|
|
6334
6817
|
euclidean3D,
|
|
6335
6818
|
fetchSourcetable,
|
|
6336
6819
|
fmtF,
|
|
@@ -6398,6 +6881,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
6398
6881
|
greatCircleMidpoint,
|
|
6399
6882
|
hdrLine,
|
|
6400
6883
|
horizonDistance,
|
|
6884
|
+
ionoFree,
|
|
6401
6885
|
keplerPosition,
|
|
6402
6886
|
msmEpochToDate,
|
|
6403
6887
|
navTimesFromEph,
|
|
@@ -6420,11 +6904,14 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
|
|
|
6420
6904
|
resetGloFreqCache,
|
|
6421
6905
|
rhumbLine,
|
|
6422
6906
|
rtcm3Constellation,
|
|
6907
|
+
satClockCorrection,
|
|
6423
6908
|
selectEphemeris,
|
|
6424
6909
|
setGloFreqNumber,
|
|
6425
6910
|
setRtcm3DebugHandler,
|
|
6911
|
+
solveSpp,
|
|
6426
6912
|
systemCmp,
|
|
6427
6913
|
systemName,
|
|
6914
|
+
transformFrame,
|
|
6428
6915
|
updateStationMeta,
|
|
6429
6916
|
updateStreamStats,
|
|
6430
6917
|
verifyChecksum,
|
package/dist/index.d.cts
CHANGED
|
@@ -9,7 +9,9 @@ export { E as EpochSummary, P as ParseOptions, R as RinexHeader, a as RinexResul
|
|
|
9
9
|
export { E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHeader, a as NavResult, p as parseNavFile } from './nav-BAI1a9vK.cjs';
|
|
10
10
|
export { B as BitReader, E as EphemerisInfo, R as Rtcm3DebugHandler, a as Rtcm3Decoder, b as Rtcm3Frame, d as decodeEphemeris, r as readString, c as reportDecodeError, s as setRtcm3DebugHandler } from './ephemeris-Ohl6NAfw.cjs';
|
|
11
11
|
export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.cjs';
|
|
12
|
-
export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, ecefToAzEl, glonassPosition, keplerPosition, navTimesFromEph, selectEphemeris } from './orbit.cjs';
|
|
12
|
+
export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, ecefToAzEl, ephInfoToEphemeris, glonassPosition, keplerPosition, navTimesFromEph, selectEphemeris } from './orbit.cjs';
|
|
13
|
+
export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.cjs';
|
|
14
|
+
export { SppOptions, SppSolution, ionoFree, satClockCorrection, solveSpp } from './positioning.cjs';
|
|
13
15
|
export { NtripCaster, NtripConnectionInfo, NtripNetwork, NtripStream, NtripStreamConnection, NtripVersion, Sourcetable, SourcetableEntry, connectToMountpoint, fetchSourcetable, parseSourcetable } from './ntrip.cjs';
|
|
14
16
|
export { CompleteSatSignal, CompleteSignalStats, CompletenessAccumulator, CompletenessResult, CycleSlipAccumulator, CycleSlipEvent, CycleSlipResult, CycleSlipSignalStats, MultipathAccumulator, MultipathPoint, MultipathResult, MultipathSeries, MultipathSignalStat, QualityResult, analyzeQuality } from './analysis.cjs';
|
|
15
17
|
export { AntennaEntry, AntexFile, FrequencyData, frequencyLabel, parseAntex } from './antex.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,9 @@ export { E as EpochSummary, P as ParseOptions, R as RinexHeader, a as RinexResul
|
|
|
9
9
|
export { E as Ephemeris, G as GlonassEphemeris, K as KeplerEphemeris, N as NavHeader, a as NavResult, p as parseNavFile } from './nav-BAI1a9vK.js';
|
|
10
10
|
export { B as BitReader, E as EphemerisInfo, R as Rtcm3DebugHandler, a as Rtcm3Decoder, b as Rtcm3Frame, d as decodeEphemeris, r as readString, c as reportDecodeError, s as setRtcm3DebugHandler } from './ephemeris-Ohl6NAfw.js';
|
|
11
11
|
export { MessageTypeStats, MsmEpoch, MsmSatObs, MsmSignal, RTCM3_MESSAGE_NAMES, SatCn0, SignalCn0, StationMeta, StreamStats, createStationMeta, createStreamStats, decodeMsmFull, msmEpochToDate, resetGloFreqCache, rtcm3Constellation, setGloFreqNumber, updateStationMeta, updateStreamStats } from './rtcm3.js';
|
|
12
|
-
export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, ecefToAzEl, glonassPosition, keplerPosition, navTimesFromEph, selectEphemeris } from './orbit.js';
|
|
12
|
+
export { AllPositionsData, DopValues, EpochSkyData, SatAzEl, SatPoint, SatPosition, VisibilityPass, VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, ecefToAzEl, ephInfoToEphemeris, glonassPosition, keplerPosition, navTimesFromEph, selectEphemeris } from './orbit.js';
|
|
13
|
+
export { Helmert14, REFERENCE_FRAMES, ReferenceFrame, applyHelmert, dateToEpoch, transformFrame } from './frames.js';
|
|
14
|
+
export { SppOptions, SppSolution, ionoFree, satClockCorrection, solveSpp } from './positioning.js';
|
|
13
15
|
export { NtripCaster, NtripConnectionInfo, NtripNetwork, NtripStream, NtripStreamConnection, NtripVersion, Sourcetable, SourcetableEntry, connectToMountpoint, fetchSourcetable, parseSourcetable } from './ntrip.js';
|
|
14
16
|
export { CompleteSatSignal, CompleteSignalStats, CompletenessAccumulator, CompletenessResult, CycleSlipAccumulator, CycleSlipEvent, CycleSlipResult, CycleSlipSignalStats, MultipathAccumulator, MultipathPoint, MultipathResult, MultipathSeries, MultipathSignalStat, QualityResult, analyzeQuality } from './analysis.js';
|
|
15
17
|
export { AntennaEntry, AntexFile, FrequencyData, frequencyLabel, parseAntex } from './antex.js';
|