@neilberkman/sidereon 0.12.0 → 0.13.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.
@@ -305,6 +305,25 @@ export class BroadcastEphemeris {
305
305
  * J2000 seconds. Returns `undefined` when no usable record covers the query.
306
306
  */
307
307
  evaluate(satellite: string, t_j2000_s: number): BroadcastStoreEvaluation | undefined;
308
+ /**
309
+ * Query ECEF position and clock for parallel satellite and epoch arrays
310
+ * against this parsed broadcast ephemeris store.
311
+ *
312
+ * `satellites[i]` is evaluated at `epochsJ2000S[i]`, where epochs are
313
+ * seconds since J2000 in GPST for GNSS broadcast records. The returned
314
+ * plain object has aligned `positionsEcefM`, `clocksS`, `statuses`, and
315
+ * `elementResults` arrays.
316
+ */
317
+ observableStatesAtJ2000S(satellites: any, epochs_j2000_s: any): any;
318
+ /**
319
+ * Query ECEF position and clock for many satellites at one epoch against
320
+ * this parsed broadcast ephemeris store.
321
+ *
322
+ * `epochJ2000S` is seconds since J2000 in GPST. The returned object follows
323
+ * the same contract as
324
+ * [`observableStatesAtJ2000S`](Self::observable_states_at_j2000_s).
325
+ */
326
+ observableStatesAtSharedJ2000S(satellites: any, epoch_j2000_s: number): any;
308
327
  /**
309
328
  * Solve a receiver position from broadcast ephemeris ALONE: the supported
310
329
  * real-time / offline single-point-positioning mode. `request` is the same
@@ -4179,6 +4198,80 @@ export class PppFloatSolution {
4179
4198
  readonly ztdResidualM: number | undefined;
4180
4199
  }
4181
4200
 
4201
+ /**
4202
+ * A reusable precise-ephemeris interpolant with cached per-satellite nodes.
4203
+ *
4204
+ * Build this handle once from a parsed [`Sp3`] product, raw precise samples, or
4205
+ * a [`PreciseEphemerisSampleSource`], then reuse it for many state or range
4206
+ * queries. The handle delegates to
4207
+ * `sidereon_core::ephemeris::PreciseEphemerisInterpolant`; ECEF positions are
4208
+ * metres, clocks are seconds, and query epochs are seconds since J2000 in the
4209
+ * source time scale.
4210
+ */
4211
+ export class PreciseEphemerisInterpolant {
4212
+ private constructor();
4213
+ free(): void;
4214
+ [Symbol.dispose](): void;
4215
+ /**
4216
+ * Build a cached interpolant from an existing sample-backed precise source.
4217
+ */
4218
+ static fromPreciseEphemerisSamples(source: PreciseEphemerisSampleSource): PreciseEphemerisInterpolant;
4219
+ /**
4220
+ * Build a cached interpolant directly from precise samples.
4221
+ *
4222
+ * `samples` is the same array accepted by
4223
+ * [`preciseEphemerisSamplesFromSamples`]: each item has `{ sat, epoch,
4224
+ * positionEcefM, clockS?, clockEvent? }`, with epochs in seconds since
4225
+ * J2000 and positions in ECEF metres. Throws a `TypeError` for malformed
4226
+ * JS input and a `RangeError` for sample validation failures.
4227
+ */
4228
+ static fromSamples(samples: any): PreciseEphemerisInterpolant;
4229
+ /**
4230
+ * Build a cached interpolant from a parsed SP3 precise product.
4231
+ *
4232
+ * Nodes are copied from the product's native SP3 records. Query epochs are
4233
+ * seconds since J2000 in the SP3 product time scale.
4234
+ */
4235
+ static fromSp3(sp3: Sp3): PreciseEphemerisInterpolant;
4236
+ /**
4237
+ * Query ECEF position and optional clock for parallel satellite and epoch
4238
+ * arrays using this cached interpolant.
4239
+ *
4240
+ * `satellites[i]` is evaluated at `epochsJ2000S[i]`, where epochs are
4241
+ * seconds since J2000 on this handle's time scale. The returned plain
4242
+ * object has aligned `positionsEcefM`, `clocksS`, `statuses`, and
4243
+ * `elementResults` arrays.
4244
+ */
4245
+ observableStatesAtJ2000S(satellites: any, epochs_j2000_s: any): any;
4246
+ /**
4247
+ * Query ECEF position and optional clock for many satellites at one epoch
4248
+ * using this cached interpolant.
4249
+ *
4250
+ * `epochJ2000S` is seconds since J2000 on this handle's time scale. The
4251
+ * returned object follows the same contract as
4252
+ * [`observableStatesAtJ2000S`](Self::observable_states_at_j2000_s).
4253
+ */
4254
+ observableStatesAtSharedJ2000S(satellites: any, epoch_j2000_s: number): any;
4255
+ /**
4256
+ * Predict geometric ranges for many `(satellite, receiver, epoch)`
4257
+ * requests using this cached interpolant.
4258
+ *
4259
+ * `requests` is an array of `{ sat, receiverEcefM, tRxJ2000S }` objects.
4260
+ * Positions are ECEF metres and epochs are seconds since J2000 on this
4261
+ * handle's time scale. The output matches [`Sp3.predictRanges`].
4262
+ */
4263
+ predictRanges(requests: any, options: any): any;
4264
+ /**
4265
+ * Satellite tokens this handle can interpolate, ascending.
4266
+ */
4267
+ readonly satellites: string[];
4268
+ /**
4269
+ * Source time-scale abbreviation used by this handle's J2000-second axis,
4270
+ * such as `"GPST"`.
4271
+ */
4272
+ readonly timeScale: string;
4273
+ }
4274
+
4182
4275
  /**
4183
4276
  * A precise-ephemeris source built from samples rather than parsed SP3 text.
4184
4277
  *
@@ -4190,6 +4283,26 @@ export class PreciseEphemerisSampleSource {
4190
4283
  private constructor();
4191
4284
  free(): void;
4192
4285
  [Symbol.dispose](): void;
4286
+ /**
4287
+ * Query ECEF position and optional clock for parallel satellite and epoch
4288
+ * arrays against this sample-backed precise source.
4289
+ *
4290
+ * `satellites[i]` is evaluated at `epochsJ2000S[i]`, where epochs are
4291
+ * seconds since J2000 on the source time scale. The returned plain object
4292
+ * has aligned `positionsEcefM`, `clocksS`, `statuses`, and
4293
+ * `elementResults` arrays. Failed elements use the core missing-position
4294
+ * sentinel and carry the scalar engine error in `elementResults[i].error`.
4295
+ */
4296
+ observableStatesAtJ2000S(satellites: any, epochs_j2000_s: any): any;
4297
+ /**
4298
+ * Query ECEF position and optional clock for many satellites at one epoch
4299
+ * against this sample-backed precise source.
4300
+ *
4301
+ * `epochJ2000S` is seconds since J2000 on the source time scale. The
4302
+ * returned plain object follows the same contract as
4303
+ * [`observableStatesAtJ2000S`](Self::observable_states_at_j2000_s).
4304
+ */
4305
+ observableStatesAtSharedJ2000S(satellites: any, epoch_j2000_s: number): any;
4193
4306
  /**
4194
4307
  * Predict geometric ranges for many requests in one call. See the shared
4195
4308
  * [`predictRanges`](crate::precise_samples::predict_ranges_over) contract;
@@ -4994,6 +5107,26 @@ export class Sp3 {
4994
5107
  * coverage gap (the engine refuses to extrapolate).
4995
5108
  */
4996
5109
  interpolate(satellite: string, j2000_seconds: Float64Array): Sp3Interpolation;
5110
+ /**
5111
+ * Query ECEF position and optional clock for parallel satellite and epoch
5112
+ * arrays against this parsed SP3 product.
5113
+ *
5114
+ * `satellites[i]` is evaluated at `epochsJ2000S[i]`, where epochs are
5115
+ * seconds since J2000 in the product time scale. The returned plain object
5116
+ * has aligned `positionsEcefM`, `clocksS`, `statuses`, and
5117
+ * `elementResults` arrays. Failed elements use the core missing-position
5118
+ * sentinel and carry the scalar engine error in `elementResults[i].error`.
5119
+ */
5120
+ observableStatesAtJ2000S(satellites: any, epochs_j2000_s: any): any;
5121
+ /**
5122
+ * Query ECEF position and optional clock for many satellites at one epoch
5123
+ * against this parsed SP3 product.
5124
+ *
5125
+ * `epochJ2000S` is seconds since J2000 in the product time scale. The
5126
+ * returned object follows the same contract as
5127
+ * [`observableStatesAtJ2000S`](Self::observable_states_at_j2000_s).
5128
+ */
5129
+ observableStatesAtSharedJ2000S(satellites: any, epoch_j2000_s: number): any;
4997
5130
  /**
4998
5131
  * Predict geometric ranges for many `(satellite, receiver, epoch)` requests
4999
5132
  * against this ephemeris in one call. `requests` is an array of
@@ -6120,6 +6253,39 @@ export function acquire(samples: Float64Array, prn: bigint, options: any): Acqui
6120
6253
  */
6121
6254
  export function allanDeviation(series: any, tau0_s: number, averaging_factors: any): any;
6122
6255
 
6256
+ /**
6257
+ * Alpha-beta measurement update applied to a predicted scalar state.
6258
+ *
6259
+ * `predicted` is `{ level, rate }`, `measurement` has the same unit as
6260
+ * `level`, `dt` is seconds, and `gains` is `{ alpha, beta }`.
6261
+ */
6262
+ export function alphaBetaApplyMeasurement(predicted: any, measurement: number, dt: number, gains: any): any;
6263
+
6264
+ /**
6265
+ * Run one alpha-beta predict and measurement update.
6266
+ *
6267
+ * `state` is `{ level, rate }`, `measurement` has the same unit as `level`,
6268
+ * `dt` is seconds, and `gains` is `{ alpha, beta }`. Returns `{ predicted,
6269
+ * updated, innovation }`.
6270
+ */
6271
+ export function alphaBetaFilterStep(state: any, measurement: number, dt: number, gains: any): any;
6272
+
6273
+ /**
6274
+ * Alpha-beta constant-rate prediction.
6275
+ *
6276
+ * `state` is `{ level, rate }` and `dt` is the positive propagation interval in
6277
+ * seconds. Returns the predicted `{ level, rate }`.
6278
+ */
6279
+ export function alphaBetaPredict(state: any, dt: number): any;
6280
+
6281
+ /**
6282
+ * Steady-state alpha-beta gains from a positive tracking index.
6283
+ *
6284
+ * Returns `{ alpha, beta }`, where `alpha` is the level gain and `beta` maps
6285
+ * innovation to rate through `beta * innovation / dt`.
6286
+ */
6287
+ export function alphaBetaSteadyStateGains(tracking_index: number): any;
6288
+
6123
6289
  /**
6124
6290
  * On-sky angle in degrees between two direction vectors.
6125
6291
  */
@@ -6226,6 +6392,38 @@ export function carrierBandName(band: CarrierBand): string;
6226
6392
  */
6227
6393
  export function carrierFrequencyHz(system: GnssSystem, band: CarrierBand): number | undefined;
6228
6394
 
6395
+ /**
6396
+ * CA-CFAR false alarm probability from searched-cell count, absolute
6397
+ * threshold, and mean noise level.
6398
+ */
6399
+ export function cfarCaFalseAlarmProbability(searched_cells: number, threshold: number, noise_level: number): number;
6400
+
6401
+ /**
6402
+ * CA-CFAR threshold multiplier from searched-cell count and target false alarm
6403
+ * probability.
6404
+ */
6405
+ export function cfarCaMultiplierFromPfa(searched_cells: number, false_alarm_probability: number): number;
6406
+
6407
+ /**
6408
+ * CA-CFAR false alarm probability from searched-cell count and multiplier.
6409
+ */
6410
+ export function cfarCaPfaFromMultiplier(searched_cells: number, multiplier: number): number;
6411
+
6412
+ /**
6413
+ * CA-CFAR absolute threshold from searched-cell count, target false alarm
6414
+ * probability, and mean noise level.
6415
+ */
6416
+ export function cfarCaThreshold(searched_cells: number, false_alarm_probability: number, noise_level: number): number;
6417
+
6418
+ /**
6419
+ * Compute the closed-form Chan-Ho seed used by [`locateSource`].
6420
+ *
6421
+ * `mode` is `"toa"`, `"tdoa"`, or `{ mode: "tdoa", referenceSensor }`.
6422
+ * Per-sensor speed overrides are not used by the closed-form equations, but
6423
+ * they are used by [`locateSource`] during iterative refinement.
6424
+ */
6425
+ export function chanHoInitialGuess(sensors: any, arrival_times_s: any, propagation_speed_m_s: number, mode: any): any;
6426
+
6229
6427
  /**
6230
6428
  * Returns `true` when a diff has any findings.
6231
6429
  */
@@ -6633,6 +6831,19 @@ export function estimateDecay(drag: DragForce, request: any): any;
6633
6831
  */
6634
6832
  export function estimateDecayWithSpaceWeather(drag: DragForce, table: SpaceWeatherTable, request: any): any;
6635
6833
 
6834
+ /**
6835
+ * Exponentially weighted moving-average update.
6836
+ *
6837
+ * `alpha` must be in `[0, 1]`; the returned value is
6838
+ * `previous + alpha * (sample - previous)`.
6839
+ */
6840
+ export function ewmaUpdate(previous: number, sample: number, alpha: number): number;
6841
+
6842
+ /**
6843
+ * EWMA update with `alpha = 1 / 2^shift`.
6844
+ */
6845
+ export function ewmaUpdatePowerOfTwo(previous: number, sample: number, shift: number): number;
6846
+
6636
6847
  /**
6637
6848
  * Find Moon elevation threshold crossings (moonrise / moonset) over a UTC
6638
6849
  * window.
@@ -7074,6 +7285,15 @@ export function j2000SecondsToCivil(seconds: bigint): CivilDateTime;
7074
7285
  */
7075
7286
  export function jarqueBera(x: Float64Array): any;
7076
7287
 
7288
+ /**
7289
+ * Steady-state gains for a scalar constant-velocity Kalman filter.
7290
+ *
7291
+ * `trackingIndex`, `dt`, and `measurementVariance` must be positive. Returns
7292
+ * `{ positionGain, rateGain }`; `rateGain * dt` equals the alpha-beta `beta`
7293
+ * gain for the same tracking index.
7294
+ */
7295
+ export function kalmanCvSteadyStateGains(tracking_index: number, dt: number, measurement_variance: number): any;
7296
+
7077
7297
  /**
7078
7298
  * GPS broadcast Klobuchar ionospheric group delay in the model's native units
7079
7299
  * (positive metres).
@@ -7286,12 +7506,38 @@ export function loadRinexObs(bytes: Uint8Array): RinexObs;
7286
7506
  */
7287
7507
  export function loadSp3(bytes: Uint8Array): Sp3;
7288
7508
 
7509
+ /**
7510
+ * Locate a source from sensor arrival times.
7511
+ *
7512
+ * `sensors` is an array of `{ positionM, propagationSpeedMS? }`; each
7513
+ * `positionM` is a 2D or 3D Cartesian metre vector and all sensors must share
7514
+ * the same dimension. `arrivalTimesS` is an aligned seconds array,
7515
+ * `propagationSpeedMS` is the call-level speed in metres per second, and
7516
+ * `options` may include `mode`, `referenceSensor`, `timingSigmaS`, `loss`,
7517
+ * `fScaleS`, `ftol`, `xtol`, `gtol`, and `maxNfev`.
7518
+ */
7519
+ export function locateSource(sensors: any, arrival_times_s: any, propagation_speed_m_s: number, options: any): any;
7520
+
7289
7521
  export function lunarSolarEclipses(start_unix_us: bigint, end_unix_us: bigint, step_s: number, tolerance_s: number): any;
7290
7522
 
7291
7523
  export function lunarSolarEclipsesSpk(spk: Spk, start_unix_us: bigint, end_unix_us: bigint, step_s: number, tolerance_s: number): any;
7292
7524
 
7293
7525
  export function lvlhRotation(position_km: Float64Array, velocity_km_s: Float64Array): Float64Array;
7294
7526
 
7527
+ /**
7528
+ * Gaussian consistency factor applied by [`madSpread`].
7529
+ */
7530
+ export function madGaussianConsistency(): number;
7531
+
7532
+ /**
7533
+ * Median absolute deviation spread estimate.
7534
+ *
7535
+ * `values` is a JS number array. The returned spread is
7536
+ * `MAD_GAUSSIAN_CONSISTENCY * median(abs(value - median(values)))`, floored by
7537
+ * `scaleFloor`.
7538
+ */
7539
+ export function madSpread(values: any, scale_floor: number): number;
7540
+
7295
7541
  export function meanMotionCircular(radius_km: number): number;
7296
7542
 
7297
7543
  export function meanMotionFromState(position_km: Float64Array, velocity_km_s: Float64Array): number;
@@ -7425,6 +7671,28 @@ export function nequickGDelayM(_eval: any, frequency_hz: number): number;
7425
7671
  */
7426
7672
  export function nequickGStecTecu(_eval: any): number;
7427
7673
 
7674
+ /**
7675
+ * Scalar normalized innovation squared statistic.
7676
+ */
7677
+ export function nis(innovation: number, innovation_variance: number): number;
7678
+
7679
+ /**
7680
+ * Bar-Shalom expected NIS value for `dof` measurement degrees of freedom.
7681
+ */
7682
+ export function nisExpectedValue(dof: number): number;
7683
+
7684
+ /**
7685
+ * Test a scalar innovation against a chi-square NIS gate.
7686
+ *
7687
+ * Returns `{ nis, threshold, inGate, dof }`, with `confidence` in `(0, 1)`.
7688
+ */
7689
+ export function nisGate(innovation: number, innovation_variance: number, dof: number, confidence: number): any;
7690
+
7691
+ /**
7692
+ * Chi-square NIS gate threshold for `dof` and confidence probability.
7693
+ */
7694
+ export function nisGateThreshold(dof: number, confidence: number): number;
7695
+
7428
7696
  /**
7429
7697
  * Parse bytes and return grouped epoch snapshots directly.
7430
7698
  */
@@ -7455,11 +7723,26 @@ export function noiseAmplification(f1_hz: number, f2_hz: number): number;
7455
7723
  */
7456
7724
  export function normalCovariance(jacobian: Float64Array, m: number, n: number, variance_scale: number): Float64Array;
7457
7725
 
7726
+ /**
7727
+ * Scalar normalized innovation `innovation / sqrt(innovationVariance)`.
7728
+ */
7729
+ export function normalizedInnovation(innovation: number, innovation_variance: number): number;
7730
+
7458
7731
  /**
7459
7732
  * Build the NTRIP connection request bytes for a config object.
7460
7733
  */
7461
7734
  export function ntripRequestBytes(config: any): Uint8Array;
7462
7735
 
7736
+ /**
7737
+ * Missing-position sentinel used in failed observable-state batch elements.
7738
+ *
7739
+ * The returned JS value is `[NaN, NaN, NaN]`, matching
7740
+ * `sidereon_core::ephemeris::OBSERVABLE_STATE_MISSING_POSITION_ECEF_M`. Always
7741
+ * check `elementResults[i].ok` or `statuses[i]` before using
7742
+ * `positionsEcefM[i]`.
7743
+ */
7744
+ export function observableStateMissingPositionEcefM(): any;
7745
+
7463
7746
  /**
7464
7747
  * Predict observables for one satellite from a broadcast ephemeris store.
7465
7748
  * Delegates to `sidereon_core::observables::predict`.
@@ -8209,6 +8492,33 @@ export function solveVelocityBroadcast(broadcast: BroadcastEphemeris, observatio
8209
8492
  */
8210
8493
  export function solveWithFallback(precise: Sp3[], broadcast: BroadcastEphemeris, request: any, policy: any): SourcedSolution;
8211
8494
 
8495
+ /**
8496
+ * Compute the timing Cramer-Rao lower bound for a proposed source position.
8497
+ *
8498
+ * The covariance is `(H^T H)^-1 * timingSigmaS^2`; position blocks are square
8499
+ * metres and origin-time variance is square seconds.
8500
+ */
8501
+ export function sourceCrlb(sensors: any, source_position_m: any, propagation_speed_m_s: number, timing_sigma_s: number): any;
8502
+
8503
+ /**
8504
+ * Compute timing DOP for a proposed source position.
8505
+ *
8506
+ * `sourcePositionM` is a 2D or 3D Cartesian metre vector in the same frame as
8507
+ * the sensors. The returned DOP values multiply timing sigma in seconds to
8508
+ * produce metres in the caller's Cartesian axes.
8509
+ */
8510
+ export function sourceDop(sensors: any, source_position_m: any, propagation_speed_m_s: number): any;
8511
+
8512
+ /**
8513
+ * Return the plain mode object for TDOA solves against `referenceSensor`.
8514
+ */
8515
+ export function sourceSolveModeTdoa(reference_sensor: number): any;
8516
+
8517
+ /**
8518
+ * Return the plain mode value for absolute time-of-arrival solves.
8519
+ */
8520
+ export function sourceSolveModeToa(): string;
8521
+
8212
8522
  /**
8213
8523
  * Extract a parsed SP3 product as the canonical precise-ephemeris samples, one
8214
8524
  * per real position record in ascending epoch order.