EphCore.TimeSeries (eph_core v0.1.0)

Copy Markdown View Source

Batch position computation for time-grid scanning.

Bypasses the full SnapshotPipeline (no sky positions, no horizon geometry) but reproduces its observer line-of-sight when an :observer is supplied, so the grid and the refinement position_fn share a single coordinate frame.

Computes ecliptic longitudes in the true-of-date ecliptic frame and equatorial declinations from the ICRF vector, optimized for scanning hundreds of timestamps.

Frames

  • Geocentric (no observer): the body's geocentric ICRF vector is converted directly. Use this when parallax does not matter.
  • Topocentric (observer supplied): the observer's WGS84 position is rotated into the inertial (ICRF/J2000) frame via GMST — matching EphCore.SnapshotPipeline.ObserverPosition with earth_orientation: :gmst and precession_nutation: false — then subtracted from the geocentric vector before the ecliptic/declination conversion. This is the same geometry the refinement path produces (SkyPosition.topocentric_ecliptic_longitude with the default ecliptic_frame: :true_of_date), so grid minima and refined exacts agree to within scanning tolerance.

Motion rates are derived via central difference on the longitude array — this reuses already-computed positions rather than making extra SPK calls.

Call add_horizon_geometry/2 after compute/3 to attach MC/ASC, alt/az, LST, and obliquity columns for chart overlay workflows. Refinement calls can use the full EphCore.SnapshotPipeline.observe/4 via a position_fn injection pattern.

Summary

Functions

Augment a position grid with observer horizon geometry for each timestamp.

Compute ecliptic longitudes, equatorial declinations, and motion rates for a batch of timestamps.

Types

grid_data()

@type grid_data() :: %{
  optional(:timestamps) => [DateTime.t()],
  optional(:positions) => %{required(atom()) => [float()]},
  optional(:declinations) => %{required(atom()) => [float()]},
  optional(:motion) => %{required(atom()) => [float()]},
  optional(:axes) => %{mc: [float()], asc: [float()]},
  optional(:altitudes) => %{required(atom()) => [float()]},
  optional(:azimuths) => %{required(atom()) => [float()]},
  optional(:lst) => [float()],
  optional(:obliquity_deg) => [float()],
  optional(:observer_lat) => float()
}

observer()

@type observer() :: %{optional(atom()) => float()}

Functions

add_horizon_geometry(grid_data, observer)

@spec add_horizon_geometry(grid_data(), observer()) :: grid_data()

Augment a position grid with observer horizon geometry for each timestamp.

Adds MC/ASC ecliptic longitudes, LST, obliquity, and per-body altitude/azimuth columns derived from the grid's topocentric ecliptic longitudes. Intended for chart and event-search overlays built on top of a scanned grid.

Arguments

  • grid_data — result of compute/3 (must include :timestamps and :positions)
  • observer%{lat: float, lon: float, height: float} (WGS84)

Returns

The input map extended with:

  • :axes%{mc: [float()], asc: [float()]}
  • :altitudes, :azimuths%{body_atom => [float()]}
  • :lst, :obliquity_deg — parallel arrays
  • :observer_lat — observer latitude in degrees

compute(timestamps, bodies, opts \\ [])

@spec compute([DateTime.t()], [atom()], keyword()) ::
  {:ok, grid_data()} | {:error, term()}

Compute ecliptic longitudes, equatorial declinations, and motion rates for a batch of timestamps.

Arguments

  • timestamps — list of UTC DateTime structs, assumed evenly spaced
  • bodies — list of body atoms (e.g. [:venus, :sun, :moon])
  • opts — keyword list:
    • :observer%{lat: float, lon: float, height: float} (WGS84). When present, longitudes and declinations are topocentric; when absent or nil, they are geocentric.

Returns

{:ok, grid_data} where grid_data has:

  • timestamps — the input list (unchanged)
  • positions%{body_atom => [lon_deg_t0, lon_deg_t1, ...]} (true-of-date ecliptic)
  • declinations%{body_atom => [dec_deg_t0, dec_deg_t1, ...]} (J2000 equatorial)
  • motion%{body_atom => [rate_deg_per_day_t0, ...]}

All arrays are parallel: index i corresponds to timestamps[i]. Motion rates are in degrees/day (positive = direct, negative = retrograde).