EphCore.Ephemeris.Kernels.SPK.Type21 (eph_core v0.1.0)

Copy Markdown View Source

SPK Type 21 (Extended Modified Difference Arrays) segment parsing.

Type 21 is the default format produced by JPL's Horizons system for small-body ephemerides. It uses Modified Difference Arrays (MDA) to represent trajectories, the same mathematical basis as Type 1 but with larger, higher-degree tables.

Segment layout (DAF double addresses, 1-indexed)

Record 0..N-1 (each DLSIZE doubles) Epoch table (N doubles — final epoch of each record, TDB seconds past J2000) Epoch dir (floor(N/100) doubles — every 100th epoch, for fast lookup) MAXDIM (1 double — penultimate element; NOT DLSIZE despite NAIF docs) N (1 double — last element)

DLSIZE = 4 * MAXDIM + 11

Record layout (0-indexed within record, M = MAXDIM)

[0] TL — reference epoch (TDB seconds past J2000) [1..M] G — stepsize vector (M values) [M+1] REFPOS_X [M+2] REFVEL_X [M+3] REFPOS_Y [M+4] REFVEL_Y [M+5] REFPOS_Z [M+6] REFVEL_Z [M+7..4M+6] DT — difference table, 3×M column-major (X col, Y col, Z col) [4M+7] KQMAX1 — max integration order + 1 [4M+8] KQ_X — integration order for X [4M+9] KQ_Y [4M+10] KQ_Z

Summary

Types

record()

@type record() :: %{
  tl: float(),
  g: [float()],
  refpos: {float(), float(), float()},
  refvel: {float(), float(), float()},
  dt: {[float()], [float()], [float()]},
  kqmax1: integer(),
  kq: {integer(), integer(), integer()}
}

t()

@type t() :: %EphCore.Ephemeris.Kernels.SPK.Type21{
  dlsize: integer(),
  epoch_table: [float()],
  maxdim: integer(),
  n: integer()
}

Functions

find_record_index(type21, epoch)

@spec find_record_index(t(), float()) :: integer()

Find the 0-based index of the record that covers epoch.

Returns the index of the first record whose final epoch is strictly greater than the query epoch. Falls back to the last record if epoch is at or past the last final epoch (matches spktype21 Python behavior).

parse_all_records(file, segment, type21, endian)

@spec parse_all_records(
  File.io_device(),
  EphCore.Ephemeris.Kernels.SPK.Segment.t(),
  t(),
  :little | :big
) :: {:ok, [record()]} | {:error, term()}

parse_directory(file, segment, endian)

@spec parse_directory(
  File.io_device(),
  EphCore.Ephemeris.Kernels.SPK.Segment.t(),
  :little | :big
) ::
  {:ok, t()} | {:error, term()}

parse_record(file, segment, type21, index, endian)

@spec parse_record(
  File.io_device(),
  EphCore.Ephemeris.Kernels.SPK.Segment.t(),
  t(),
  integer(),
  :little | :big
) :: {:ok, record()} | {:error, term()}