Packages

Space Dust is an astrodynamics library written in Elixir.

Current section

Files

Jump to
space_dust lib state keplerian_elements.ex
Raw

lib/state/keplerian_elements.ex

defmodule SpaceDust.State.KeplerianElements do
@moduledoc """
Classical Keplerian orbital elements.
Represents an orbit using the six classical orbital elements:
- Semi-major axis (a): Size of the orbit
- Eccentricity (e): Shape of the orbit (0 = circular, 0-1 = elliptical)
- Inclination (i): Tilt relative to the equatorial plane
- RAAN (Ω): Right Ascension of the Ascending Node
- Argument of perigee (ω): Orientation of the orbit in its plane
- True anomaly (ν): Position along the orbit
All angles are in radians. Semi-major axis is in kilometers.
"""
@enforce_keys [:semi_major_axis, :eccentricity, :inclination, :raan, :arg_perigee, :true_anomaly]
defstruct [:epoch, :semi_major_axis, :eccentricity, :inclination, :raan, :arg_perigee, :true_anomaly, :mu]
@type t :: %__MODULE__{
epoch: DateTime.t() | nil,
semi_major_axis: float(),
eccentricity: float(),
inclination: float(),
raan: float(),
arg_perigee: float(),
true_anomaly: float(),
mu: float() | nil
}
# Earth's gravitational parameter in km^3/s^2
@earth_mu 398600.4418
@doc """
Create new Keplerian elements.
## Parameters
- semi_major_axis: Semi-major axis in kilometers
- eccentricity: Orbital eccentricity (0 to < 1 for elliptical)
- inclination: Inclination in radians
- raan: Right Ascension of Ascending Node in radians
- arg_perigee: Argument of perigee in radians
- true_anomaly: True anomaly in radians
- opts: Optional parameters
- :epoch - DateTime for the elements
- :mu - Gravitational parameter (defaults to Earth)
"""
@spec new(float(), float(), float(), float(), float(), float(), keyword()) :: t()
def new(semi_major_axis, eccentricity, inclination, raan, arg_perigee, true_anomaly, opts \\ []) do
%__MODULE__{
epoch: Keyword.get(opts, :epoch),
semi_major_axis: semi_major_axis,
eccentricity: eccentricity,
inclination: inclination,
raan: raan,
arg_perigee: arg_perigee,
true_anomaly: true_anomaly,
mu: Keyword.get(opts, :mu, @earth_mu)
}
end
@doc """
Calculate orbital period in seconds.
"""
@spec period(t()) :: float()
def period(%__MODULE__{semi_major_axis: a, mu: mu}) do
mu = mu || @earth_mu
2.0 * :math.pi() * :math.sqrt(a * a * a / mu)
end
@doc """
Calculate mean motion in radians per second.
"""
@spec mean_motion(t()) :: float()
def mean_motion(%__MODULE__{} = elements) do
2.0 * :math.pi() / period(elements)
end
@doc """
Calculate apoapsis radius in kilometers.
"""
@spec apoapsis(t()) :: float()
def apoapsis(%__MODULE__{semi_major_axis: a, eccentricity: e}) do
a * (1.0 + e)
end
@doc """
Calculate periapsis radius in kilometers.
"""
@spec periapsis(t()) :: float()
def periapsis(%__MODULE__{semi_major_axis: a, eccentricity: e}) do
a * (1.0 - e)
end
@doc """
Calculate specific orbital energy in km^2/s^2.
"""
@spec specific_energy(t()) :: float()
def specific_energy(%__MODULE__{semi_major_axis: a, mu: mu}) do
mu = mu || @earth_mu
-mu / (2.0 * a)
end
@doc """
Calculate specific angular momentum magnitude in km^2/s.
"""
@spec angular_momentum(t()) :: float()
def angular_momentum(%__MODULE__{semi_major_axis: a, eccentricity: e, mu: mu}) do
mu = mu || @earth_mu
:math.sqrt(mu * a * (1.0 - e * e))
end
@doc """
Convert true anomaly to eccentric anomaly.
"""
@spec true_to_eccentric_anomaly(t()) :: float()
def true_to_eccentric_anomaly(%__MODULE__{eccentricity: e, true_anomaly: nu}) do
:math.atan2(
:math.sqrt(1.0 - e * e) * :math.sin(nu),
e + :math.cos(nu)
)
end
@doc """
Convert true anomaly to mean anomaly.
"""
@spec true_to_mean_anomaly(t()) :: float()
def true_to_mean_anomaly(%__MODULE__{eccentricity: e} = elements) do
ea = true_to_eccentric_anomaly(elements)
ea - e * :math.sin(ea)
end
@doc """
Convert Keplerian elements to Nx tensor representation.
Returns tensor of shape {6}: [a, e, i, Ω, ω, ν]
"""
@spec to_tensor(t()) :: Nx.Tensor.t()
def to_tensor(%__MODULE__{
semi_major_axis: a,
eccentricity: e,
inclination: i,
raan: raan,
arg_perigee: w,
true_anomaly: nu
}) do
Nx.tensor([a, e, i, raan, w, nu], type: :f64)
end
@doc """
Create Keplerian elements from Nx tensor.
"""
@spec from_tensor(Nx.Tensor.t(), keyword()) :: t()
def from_tensor(tensor, opts \\ []) do
[a, e, i, raan, w, nu] = Nx.to_flat_list(tensor)
new(a, e, i, raan, w, nu, opts)
end
end