gnss-js 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -110,6 +110,7 @@ __export(src_exports, {
110
110
  computePsdDb: () => computePsdDb,
111
111
  computeSatPosition: () => computeSatPosition,
112
112
  computeStats: () => computeStats2,
113
+ computeVisibility: () => computeVisibility,
113
114
  connectToMountpoint: () => connectToMountpoint,
114
115
  createStationMeta: () => createStationMeta,
115
116
  createStreamStats: () => createStreamStats,
@@ -4201,7 +4202,8 @@ function selectEphemeris(ephemerides, prn, timeMs) {
4201
4202
  }
4202
4203
  function computeSatPosition(eph, timeMs) {
4203
4204
  if (eph.system === "R" || eph.system === "S") {
4204
- return glonassPosition(eph, timeMs / 1e3);
4205
+ const leapMs = getGpsLeap(new Date(timeMs)) * 1e3;
4206
+ return glonassPosition(eph, (timeMs - leapMs) / 1e3);
4205
4207
  }
4206
4208
  const GPS_EPOCH2 = START_GPS_TIME.getTime();
4207
4209
  const gpsSeconds = (timeMs - GPS_EPOCH2) / 1e3;
@@ -4374,7 +4376,7 @@ function ephInfoToEphemeris(info) {
4374
4376
  };
4375
4377
  }
4376
4378
  function computeLiveSkyPositions(ephemerides, rxPos, cn0Map) {
4377
- const now = Date.now();
4379
+ const now = Date.now() + getGpsLeap(/* @__PURE__ */ new Date()) * 1e3;
4378
4380
  const result = [];
4379
4381
  const [rxX, rxY, rxZ] = rxPos;
4380
4382
  const [rxLat, rxLon] = ecefToGeodetic(rxX, rxY, rxZ);
@@ -4407,6 +4409,65 @@ function computeLiveSkyPositions(ephemerides, rxPos, cn0Map) {
4407
4409
  }
4408
4410
  return result;
4409
4411
  }
4412
+ function computeVisibility(ephemerides, rxPos, startMs, endMs, stepSec = 300, elevationMaskDeg = 10) {
4413
+ const stepMs = stepSec * 1e3;
4414
+ const times = [];
4415
+ for (let t = startMs; t <= endMs; t += stepMs) times.push(t);
4416
+ const maskRad = elevationMaskDeg * Math.PI / 180;
4417
+ const all = computeAllPositions(ephemerides, times, rxPos);
4418
+ const elevation = {};
4419
+ const visibleCount = new Array(times.length).fill(0);
4420
+ const pdop = new Array(times.length).fill(null);
4421
+ const visiblePerEpoch = times.map(() => []);
4422
+ for (const prn of all.prns) {
4423
+ const series = all.positions[prn];
4424
+ elevation[prn] = series.map((p) => p ? p.el : null);
4425
+ for (let i = 0; i < series.length; i++) {
4426
+ const p = series[i];
4427
+ if (p && p.el >= maskRad) {
4428
+ visibleCount[i]++;
4429
+ visiblePerEpoch[i].push({ az: p.az, el: p.el });
4430
+ }
4431
+ }
4432
+ }
4433
+ for (let i = 0; i < times.length; i++) {
4434
+ const dop = computeDop(visiblePerEpoch[i]);
4435
+ pdop[i] = dop ? dop.pdop : null;
4436
+ }
4437
+ const passes = [];
4438
+ for (const prn of all.prns) {
4439
+ const els = elevation[prn];
4440
+ let start = -1;
4441
+ let peakEl = -Infinity;
4442
+ let peakTime = 0;
4443
+ for (let i = 0; i <= els.length; i++) {
4444
+ const el = i < els.length ? els[i] : null;
4445
+ const above = el !== null && el !== void 0 && el >= maskRad;
4446
+ if (above) {
4447
+ if (start === -1) {
4448
+ start = i;
4449
+ peakEl = -Infinity;
4450
+ }
4451
+ if (el > peakEl) {
4452
+ peakEl = el;
4453
+ peakTime = times[i];
4454
+ }
4455
+ } else if (start !== -1) {
4456
+ passes.push({
4457
+ prn,
4458
+ system: prn[0],
4459
+ rise: times[start],
4460
+ set: times[i - 1],
4461
+ peakTime,
4462
+ peakEl
4463
+ });
4464
+ start = -1;
4465
+ }
4466
+ }
4467
+ }
4468
+ passes.sort((a, b) => a.rise - b.rise);
4469
+ return { times, elevation, visibleCount, pdop, passes };
4470
+ }
4410
4471
 
4411
4472
  // src/ntrip/index.ts
4412
4473
  function parseStreamEntry(fields) {
@@ -6319,6 +6380,7 @@ function computePsdDb(centerMHz, halfSpanChips, numPoints, psdFn, f0 = 1023e3, f
6319
6380
  computePsdDb,
6320
6381
  computeSatPosition,
6321
6382
  computeStats,
6383
+ computeVisibility,
6322
6384
  connectToMountpoint,
6323
6385
  createStationMeta,
6324
6386
  createStreamStats,
package/dist/index.d.cts CHANGED
@@ -9,7 +9,7 @@ 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, glonassPosition, keplerPosition, navTimesFromEph, selectEphemeris } from './orbit.cjs';
13
13
  export { NtripCaster, NtripConnectionInfo, NtripNetwork, NtripStream, NtripStreamConnection, NtripVersion, Sourcetable, SourcetableEntry, connectToMountpoint, fetchSourcetable, parseSourcetable } from './ntrip.cjs';
14
14
  export { CompleteSatSignal, CompleteSignalStats, CompletenessAccumulator, CompletenessResult, CycleSlipAccumulator, CycleSlipEvent, CycleSlipResult, CycleSlipSignalStats, MultipathAccumulator, MultipathPoint, MultipathResult, MultipathSeries, MultipathSignalStat, QualityResult, analyzeQuality } from './analysis.cjs';
15
15
  export { AntennaEntry, AntexFile, FrequencyData, frequencyLabel, parseAntex } from './antex.cjs';
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ 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, glonassPosition, keplerPosition, navTimesFromEph, selectEphemeris } from './orbit.js';
13
13
  export { NtripCaster, NtripConnectionInfo, NtripNetwork, NtripStream, NtripStreamConnection, NtripVersion, Sourcetable, SourcetableEntry, connectToMountpoint, fetchSourcetable, parseSourcetable } from './ntrip.js';
14
14
  export { CompleteSatSignal, CompleteSignalStats, CompletenessAccumulator, CompletenessResult, CycleSlipAccumulator, CycleSlipEvent, CycleSlipResult, CycleSlipSignalStats, MultipathAccumulator, MultipathPoint, MultipathResult, MultipathSeries, MultipathSignalStat, QualityResult, analyzeQuality } from './analysis.js';
15
15
  export { AntennaEntry, AntexFile, FrequencyData, frequencyLabel, parseAntex } from './antex.js';
package/dist/index.js CHANGED
@@ -1,3 +1,8 @@
1
+ import {
2
+ connectToMountpoint,
3
+ fetchSourcetable,
4
+ parseSourcetable
5
+ } from "./chunk-BJHTBYNG.js";
1
6
  import {
2
7
  CompletenessAccumulator,
3
8
  CycleSlipAccumulator,
@@ -51,40 +56,69 @@ import {
51
56
  } from "./chunk-5SPJH4MG.js";
52
57
  import {
53
58
  Scale,
54
- getBdsTime,
55
- getDateFromBdsTime,
56
59
  getDateFromDayOfWeek,
57
60
  getDateFromDayOfYear,
58
- getDateFromGalTime,
59
- getDateFromGloN,
60
- getDateFromGpsData,
61
- getDateFromGpsTime,
62
61
  getDateFromHourCode,
63
62
  getDateFromJulianDate,
64
63
  getDateFromMJD,
65
64
  getDateFromMJD2000,
66
65
  getDateFromRINEX,
67
- getDateFromTai,
68
66
  getDateFromTimeOfDay,
67
+ getDayOfWeek,
68
+ getDayOfYear,
69
+ getHourCode,
70
+ getJulianDate,
71
+ getMJD,
72
+ getMJD2000,
73
+ getRINEX,
74
+ getTimeOfDay,
75
+ getWeekOfYear
76
+ } from "./chunk-L5OUUNLT.js";
77
+ import {
78
+ deg2dms,
79
+ deg2rad,
80
+ euclidean3D,
81
+ geodeticToGeohash,
82
+ geodeticToMaidenhead,
83
+ geodeticToUtm,
84
+ greatCircleMidpoint,
85
+ horizonDistance,
86
+ rad2deg,
87
+ rhumbLine,
88
+ vincenty
89
+ } from "./chunk-MIIM4LDY.js";
90
+ import {
91
+ computeAllPositions,
92
+ computeDop,
93
+ computeLiveSkyPositions,
94
+ computeSatPosition,
95
+ computeVisibility,
96
+ ecefToAzEl,
97
+ glonassPosition,
98
+ keplerPosition,
99
+ navTimesFromEph,
100
+ selectEphemeris
101
+ } from "./chunk-ZCNXERQ2.js";
102
+ import {
103
+ getBdsTime,
104
+ getDateFromBdsTime,
105
+ getDateFromGalTime,
106
+ getDateFromGloN,
107
+ getDateFromGpsData,
108
+ getDateFromGpsTime,
109
+ getDateFromTai,
69
110
  getDateFromTt,
70
111
  getDateFromUnixTime,
71
112
  getDateFromUtc,
72
- getDayOfWeek,
73
- getDayOfYear,
74
113
  getGalTime,
75
114
  getGloN4,
76
115
  getGloNA,
77
116
  getGpsLeap,
78
117
  getGpsTime,
79
- getHourCode,
80
118
  getHoursFromTimeDifference,
81
- getJulianDate,
82
119
  getLeap,
83
- getMJD,
84
- getMJD2000,
85
120
  getMinutesFromTimeDifference,
86
121
  getNtpTime,
87
- getRINEX,
88
122
  getSecondsFromTimeDifference,
89
123
  getTaiDate,
90
124
  getTimeDifference,
@@ -93,29 +127,27 @@ import {
93
127
  getTimeDifferenceFromMinutes,
94
128
  getTimeDifferenceFromObject,
95
129
  getTimeDifferenceFromSeconds,
96
- getTimeOfDay,
97
130
  getTimeOfWeek,
98
131
  getTotalDaysFromTimeDifference,
99
132
  getTtDate,
100
133
  getUnixTime,
101
134
  getUtcDate,
102
- getWeekNumber,
103
- getWeekOfYear
104
- } from "./chunk-7NOFXKET.js";
135
+ getWeekNumber
136
+ } from "./chunk-HVXYFUCB.js";
105
137
  import {
106
- deg2dms,
107
- deg2rad,
108
- euclidean3D,
109
- geodeticToGeohash,
110
- geodeticToMaidenhead,
111
- geodeticToUtm,
112
- greatCircleMidpoint,
113
- horizonDistance,
114
- rad2deg,
115
- rhumbLine,
116
- vincenty
117
- } from "./chunk-MIIM4LDY.js";
138
+ clampUnit,
139
+ ecefToGeodetic,
140
+ geodeticToEcef,
141
+ getAer,
142
+ getEnuDifference
143
+ } from "./chunk-37QNKGTC.js";
118
144
  import "./chunk-5S5MONFK.js";
145
+ import {
146
+ WGS84_ECCENTRICITY_SQUARED,
147
+ WGS84_FLATTENING,
148
+ WGS84_SEMI_MAJOR_AXIS,
149
+ WGS84_SEMI_MINOR_AXIS
150
+ } from "./chunk-6FAL6P4G.js";
119
151
  import {
120
152
  EMPTY_WARNINGS,
121
153
  WarningAccumulator,
@@ -152,53 +184,7 @@ import {
152
184
  setRtcm3DebugHandler,
153
185
  updateStationMeta,
154
186
  updateStreamStats
155
- } from "./chunk-JDO3LEPC.js";
156
- import {
157
- ARC_GAP_FACTOR,
158
- BAND_LABELS,
159
- BDS_SATELLITES,
160
- C_LIGHT,
161
- DEFAULT_ELEV_MASK_DEG,
162
- DUAL_FREQ_PAIRS,
163
- FREQ,
164
- GLO_CHANNEL_FALLBACK,
165
- GLO_F1_BASE,
166
- GLO_F1_STEP,
167
- GLO_F2_BASE,
168
- GLO_F2_STEP,
169
- GLO_F3,
170
- SYSTEM_NAMES,
171
- SYS_SHORT,
172
- buildGloChannelMap,
173
- buildObsIndices,
174
- formatUTCTime,
175
- getFreq,
176
- gloFreq
177
- } from "./chunk-W5WKEV7U.js";
178
- import {
179
- computeAllPositions,
180
- computeDop,
181
- computeLiveSkyPositions,
182
- computeSatPosition,
183
- ecefToAzEl,
184
- glonassPosition,
185
- keplerPosition,
186
- navTimesFromEph,
187
- selectEphemeris
188
- } from "./chunk-PGHDJFQK.js";
189
- import {
190
- clampUnit,
191
- ecefToGeodetic,
192
- geodeticToEcef,
193
- getAer,
194
- getEnuDifference
195
- } from "./chunk-37QNKGTC.js";
196
- import {
197
- WGS84_ECCENTRICITY_SQUARED,
198
- WGS84_FLATTENING,
199
- WGS84_SEMI_MAJOR_AXIS,
200
- WGS84_SEMI_MINOR_AXIS
201
- } from "./chunk-6FAL6P4G.js";
187
+ } from "./chunk-7EEWQ5DU.js";
202
188
  import {
203
189
  DAYS_MJD2000_MJD,
204
190
  DAYS_MJD_JULIAN,
@@ -225,10 +211,27 @@ import {
225
211
  START_UNIX_TIME
226
212
  } from "./chunk-LEEU5OIO.js";
227
213
  import {
228
- connectToMountpoint,
229
- fetchSourcetable,
230
- parseSourcetable
231
- } from "./chunk-BJHTBYNG.js";
214
+ ARC_GAP_FACTOR,
215
+ BAND_LABELS,
216
+ BDS_SATELLITES,
217
+ C_LIGHT,
218
+ DEFAULT_ELEV_MASK_DEG,
219
+ DUAL_FREQ_PAIRS,
220
+ FREQ,
221
+ GLO_CHANNEL_FALLBACK,
222
+ GLO_F1_BASE,
223
+ GLO_F1_STEP,
224
+ GLO_F2_BASE,
225
+ GLO_F2_STEP,
226
+ GLO_F3,
227
+ SYSTEM_NAMES,
228
+ SYS_SHORT,
229
+ buildGloChannelMap,
230
+ buildObsIndices,
231
+ formatUTCTime,
232
+ getFreq,
233
+ gloFreq
234
+ } from "./chunk-W5WKEV7U.js";
232
235
  export {
233
236
  ARC_GAP_FACTOR,
234
237
  BAND_LABELS,
@@ -320,6 +323,7 @@ export {
320
323
  computePsdDb,
321
324
  computeSatPosition,
322
325
  computeStats,
326
+ computeVisibility,
323
327
  connectToMountpoint,
324
328
  createStationMeta,
325
329
  createStreamStats,
package/dist/orbit.cjs CHANGED
@@ -24,6 +24,7 @@ __export(orbit_exports, {
24
24
  computeDop: () => computeDop,
25
25
  computeLiveSkyPositions: () => computeLiveSkyPositions,
26
26
  computeSatPosition: () => computeSatPosition,
27
+ computeVisibility: () => computeVisibility,
27
28
  ecefToAzEl: () => ecefToAzEl,
28
29
  ecefToGeodetic: () => ecefToGeodetic,
29
30
  geodeticToEcef: () => geodeticToEcef,
@@ -72,8 +73,93 @@ function ecefToGeodetic(x, y, z) {
72
73
  }
73
74
 
74
75
  // src/constants/time.ts
76
+ var MILLISECONDS_IN_SECOND = 1e3;
77
+ var MILLISECONDS_GPS_TAI = 19e3;
75
78
  var START_GPS_TIME = /* @__PURE__ */ new Date("1980-01-06T00:00:00Z");
76
79
  var START_BDS_TIME = /* @__PURE__ */ new Date("2006-01-01T00:00:14Z");
80
+ var START_NTP_TIME = /* @__PURE__ */ new Date("1900-01-01T00:00:00Z");
81
+
82
+ // src/time/gnss.ts
83
+ function getTaiDate(date) {
84
+ return new Date(date.getTime() + MILLISECONDS_GPS_TAI);
85
+ }
86
+ function getNtpTime(date) {
87
+ return getTaiDate(date).getTime() - START_NTP_TIME.getTime();
88
+ }
89
+
90
+ // src/time/utc.ts
91
+ var LEAP_SECONDS_TABLE = [
92
+ [3692217600, 37],
93
+ // 1 Jan 2017
94
+ [3644697600, 36],
95
+ // 1 Jul 2015
96
+ [3550089600, 35],
97
+ // 1 Jul 2012
98
+ [3439756800, 34],
99
+ // 1 Jan 2009
100
+ [3345062400, 33],
101
+ // 1 Jan 2006
102
+ [3124137600, 32],
103
+ // 1 Jan 1999
104
+ [3076704e3, 31],
105
+ // 1 Jul 1997
106
+ [3029443200, 30],
107
+ // 1 Jan 1996
108
+ [2982009600, 29],
109
+ // 1 Jul 1994
110
+ [2950473600, 28],
111
+ // 1 Jul 1993
112
+ [2918937600, 27],
113
+ // 1 Jul 1992
114
+ [2871676800, 26],
115
+ // 1 Jan 1991
116
+ [2840140800, 25],
117
+ // 1 Jan 1990
118
+ [2776982400, 24],
119
+ // 1 Jan 1988
120
+ [2698012800, 23],
121
+ // 1 Jul 1985
122
+ [2634854400, 22],
123
+ // 1 Jul 1983
124
+ [2603318400, 21],
125
+ // 1 Jul 1982
126
+ [2571782400, 20],
127
+ // 1 Jul 1981
128
+ [2524521600, 19],
129
+ // 1 Jan 1980
130
+ [2492985600, 18],
131
+ // 1 Jan 1979
132
+ [2461449600, 17],
133
+ // 1 Jan 1978
134
+ [2429913600, 16],
135
+ // 1 Jan 1977
136
+ [2398291200, 15],
137
+ // 1 Jan 1976
138
+ [2366755200, 14],
139
+ // 1 Jan 1975
140
+ [2335219200, 13],
141
+ // 1 Jan 1974
142
+ [2303683200, 12],
143
+ // 1 Jan 1973
144
+ [2287785600, 11],
145
+ // 1 Jul 1972
146
+ [2272060800, 10]
147
+ // 1 Jan 1972
148
+ ];
149
+ function getLeap(date) {
150
+ const ntp_time = getNtpTime(date);
151
+ for (const [timestamp, leapSeconds] of LEAP_SECONDS_TABLE) {
152
+ if (ntp_time / MILLISECONDS_IN_SECOND - leapSeconds >= timestamp) {
153
+ return leapSeconds;
154
+ }
155
+ }
156
+ return 8;
157
+ }
158
+ function getGpsLeap(date) {
159
+ const leap_seconds = getLeap(date);
160
+ if (leap_seconds < 0) return 0;
161
+ return leap_seconds - 19;
162
+ }
77
163
 
78
164
  // src/orbit/index.ts
79
165
  var GM_GPS = 3986005e8;
@@ -299,7 +385,8 @@ function selectEphemeris(ephemerides, prn, timeMs) {
299
385
  }
300
386
  function computeSatPosition(eph, timeMs) {
301
387
  if (eph.system === "R" || eph.system === "S") {
302
- return glonassPosition(eph, timeMs / 1e3);
388
+ const leapMs = getGpsLeap(new Date(timeMs)) * 1e3;
389
+ return glonassPosition(eph, (timeMs - leapMs) / 1e3);
303
390
  }
304
391
  const GPS_EPOCH = START_GPS_TIME.getTime();
305
392
  const gpsSeconds = (timeMs - GPS_EPOCH) / 1e3;
@@ -472,7 +559,7 @@ function ephInfoToEphemeris(info) {
472
559
  };
473
560
  }
474
561
  function computeLiveSkyPositions(ephemerides, rxPos, cn0Map) {
475
- const now = Date.now();
562
+ const now = Date.now() + getGpsLeap(/* @__PURE__ */ new Date()) * 1e3;
476
563
  const result = [];
477
564
  const [rxX, rxY, rxZ] = rxPos;
478
565
  const [rxLat, rxLon] = ecefToGeodetic(rxX, rxY, rxZ);
@@ -505,12 +592,72 @@ function computeLiveSkyPositions(ephemerides, rxPos, cn0Map) {
505
592
  }
506
593
  return result;
507
594
  }
595
+ function computeVisibility(ephemerides, rxPos, startMs, endMs, stepSec = 300, elevationMaskDeg = 10) {
596
+ const stepMs = stepSec * 1e3;
597
+ const times = [];
598
+ for (let t = startMs; t <= endMs; t += stepMs) times.push(t);
599
+ const maskRad = elevationMaskDeg * Math.PI / 180;
600
+ const all = computeAllPositions(ephemerides, times, rxPos);
601
+ const elevation = {};
602
+ const visibleCount = new Array(times.length).fill(0);
603
+ const pdop = new Array(times.length).fill(null);
604
+ const visiblePerEpoch = times.map(() => []);
605
+ for (const prn of all.prns) {
606
+ const series = all.positions[prn];
607
+ elevation[prn] = series.map((p) => p ? p.el : null);
608
+ for (let i = 0; i < series.length; i++) {
609
+ const p = series[i];
610
+ if (p && p.el >= maskRad) {
611
+ visibleCount[i]++;
612
+ visiblePerEpoch[i].push({ az: p.az, el: p.el });
613
+ }
614
+ }
615
+ }
616
+ for (let i = 0; i < times.length; i++) {
617
+ const dop = computeDop(visiblePerEpoch[i]);
618
+ pdop[i] = dop ? dop.pdop : null;
619
+ }
620
+ const passes = [];
621
+ for (const prn of all.prns) {
622
+ const els = elevation[prn];
623
+ let start = -1;
624
+ let peakEl = -Infinity;
625
+ let peakTime = 0;
626
+ for (let i = 0; i <= els.length; i++) {
627
+ const el = i < els.length ? els[i] : null;
628
+ const above = el !== null && el !== void 0 && el >= maskRad;
629
+ if (above) {
630
+ if (start === -1) {
631
+ start = i;
632
+ peakEl = -Infinity;
633
+ }
634
+ if (el > peakEl) {
635
+ peakEl = el;
636
+ peakTime = times[i];
637
+ }
638
+ } else if (start !== -1) {
639
+ passes.push({
640
+ prn,
641
+ system: prn[0],
642
+ rise: times[start],
643
+ set: times[i - 1],
644
+ peakTime,
645
+ peakEl
646
+ });
647
+ start = -1;
648
+ }
649
+ }
650
+ }
651
+ passes.sort((a, b) => a.rise - b.rise);
652
+ return { times, elevation, visibleCount, pdop, passes };
653
+ }
508
654
  // Annotate the CommonJS export names for ESM import in node:
509
655
  0 && (module.exports = {
510
656
  computeAllPositions,
511
657
  computeDop,
512
658
  computeLiveSkyPositions,
513
659
  computeSatPosition,
660
+ computeVisibility,
514
661
  ecefToAzEl,
515
662
  ecefToGeodetic,
516
663
  geodeticToEcef,
package/dist/orbit.d.cts CHANGED
@@ -113,5 +113,42 @@ declare function computeAllPositions(ephemerides: Ephemeris[], times: number[],
113
113
  * Returns array of SatAzEl for all satellites with valid ephemeris.
114
114
  */
115
115
  declare function computeLiveSkyPositions(ephemerides: Map<string, EphemerisInfo>, rxPos: [number, number, number], cn0Map?: Map<string, number>): SatAzEl[];
116
+ /** A single above-mask visibility interval for one satellite. */
117
+ interface VisibilityPass {
118
+ prn: string;
119
+ system: string;
120
+ /** Rise time (Unix ms) — first sample at or above the mask. */
121
+ rise: number;
122
+ /** Set time (Unix ms) — last sample at or above the mask. */
123
+ set: number;
124
+ /** Time of peak elevation (Unix ms). */
125
+ peakTime: number;
126
+ /** Peak elevation (radians). */
127
+ peakEl: number;
128
+ }
129
+ interface VisibilityResult {
130
+ /** Sample epochs (Unix ms). */
131
+ times: number[];
132
+ /** Elevation (radians) per PRN per epoch; null when below −0.05 rad / no eph. */
133
+ elevation: Record<string, (number | null)[]>;
134
+ /** Number of satellites at or above the mask, per epoch. */
135
+ visibleCount: number[];
136
+ /** PDOP per epoch (null when < 4 satellites above the mask). */
137
+ pdop: (number | null)[];
138
+ /** Discrete above-mask passes, sorted by rise time. */
139
+ passes: VisibilityPass[];
140
+ }
141
+ /**
142
+ * Predict satellite visibility and DOP over a time window for a fixed
143
+ * receiver location.
144
+ *
145
+ * @param ephemerides Broadcast ephemerides covering the window.
146
+ * @param rxPos Receiver ECEF position (meters).
147
+ * @param startMs Window start (Unix ms).
148
+ * @param endMs Window end (Unix ms).
149
+ * @param stepSec Sample spacing in seconds (default 300).
150
+ * @param elevationMaskDeg Elevation mask in degrees (default 10).
151
+ */
152
+ declare function computeVisibility(ephemerides: Ephemeris[], rxPos: [number, number, number], startMs: number, endMs: number, stepSec?: number, elevationMaskDeg?: number): VisibilityResult;
116
153
 
117
- export { type AllPositionsData, type DopValues, type EpochSkyData, type SatAzEl, type SatPoint, type SatPosition, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, ecefToAzEl, glonassPosition, keplerPosition, navTimesFromEph, selectEphemeris };
154
+ export { type AllPositionsData, type DopValues, type EpochSkyData, type SatAzEl, type SatPoint, type SatPosition, type VisibilityPass, type VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, ecefToAzEl, glonassPosition, keplerPosition, navTimesFromEph, selectEphemeris };
package/dist/orbit.d.ts CHANGED
@@ -113,5 +113,42 @@ declare function computeAllPositions(ephemerides: Ephemeris[], times: number[],
113
113
  * Returns array of SatAzEl for all satellites with valid ephemeris.
114
114
  */
115
115
  declare function computeLiveSkyPositions(ephemerides: Map<string, EphemerisInfo>, rxPos: [number, number, number], cn0Map?: Map<string, number>): SatAzEl[];
116
+ /** A single above-mask visibility interval for one satellite. */
117
+ interface VisibilityPass {
118
+ prn: string;
119
+ system: string;
120
+ /** Rise time (Unix ms) — first sample at or above the mask. */
121
+ rise: number;
122
+ /** Set time (Unix ms) — last sample at or above the mask. */
123
+ set: number;
124
+ /** Time of peak elevation (Unix ms). */
125
+ peakTime: number;
126
+ /** Peak elevation (radians). */
127
+ peakEl: number;
128
+ }
129
+ interface VisibilityResult {
130
+ /** Sample epochs (Unix ms). */
131
+ times: number[];
132
+ /** Elevation (radians) per PRN per epoch; null when below −0.05 rad / no eph. */
133
+ elevation: Record<string, (number | null)[]>;
134
+ /** Number of satellites at or above the mask, per epoch. */
135
+ visibleCount: number[];
136
+ /** PDOP per epoch (null when < 4 satellites above the mask). */
137
+ pdop: (number | null)[];
138
+ /** Discrete above-mask passes, sorted by rise time. */
139
+ passes: VisibilityPass[];
140
+ }
141
+ /**
142
+ * Predict satellite visibility and DOP over a time window for a fixed
143
+ * receiver location.
144
+ *
145
+ * @param ephemerides Broadcast ephemerides covering the window.
146
+ * @param rxPos Receiver ECEF position (meters).
147
+ * @param startMs Window start (Unix ms).
148
+ * @param endMs Window end (Unix ms).
149
+ * @param stepSec Sample spacing in seconds (default 300).
150
+ * @param elevationMaskDeg Elevation mask in degrees (default 10).
151
+ */
152
+ declare function computeVisibility(ephemerides: Ephemeris[], rxPos: [number, number, number], startMs: number, endMs: number, stepSec?: number, elevationMaskDeg?: number): VisibilityResult;
116
153
 
117
- export { type AllPositionsData, type DopValues, type EpochSkyData, type SatAzEl, type SatPoint, type SatPosition, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, ecefToAzEl, glonassPosition, keplerPosition, navTimesFromEph, selectEphemeris };
154
+ export { type AllPositionsData, type DopValues, type EpochSkyData, type SatAzEl, type SatPoint, type SatPosition, type VisibilityPass, type VisibilityResult, computeAllPositions, computeDop, computeLiveSkyPositions, computeSatPosition, computeVisibility, ecefToAzEl, glonassPosition, keplerPosition, navTimesFromEph, selectEphemeris };
package/dist/orbit.js CHANGED
@@ -3,12 +3,14 @@ import {
3
3
  computeDop,
4
4
  computeLiveSkyPositions,
5
5
  computeSatPosition,
6
+ computeVisibility,
6
7
  ecefToAzEl,
7
8
  glonassPosition,
8
9
  keplerPosition,
9
10
  navTimesFromEph,
10
11
  selectEphemeris
11
- } from "./chunk-PGHDJFQK.js";
12
+ } from "./chunk-ZCNXERQ2.js";
13
+ import "./chunk-HVXYFUCB.js";
12
14
  import {
13
15
  ecefToGeodetic,
14
16
  geodeticToEcef
@@ -20,6 +22,7 @@ export {
20
22
  computeDop,
21
23
  computeLiveSkyPositions,
22
24
  computeSatPosition,
25
+ computeVisibility,
23
26
  ecefToAzEl,
24
27
  ecefToGeodetic,
25
28
  geodeticToEcef,