# `Sidereon.Doppler`
[🔗](https://github.com/neilberkman/sidereon-ex/blob/main/lib/sidereon/doppler.ex#L1)

Doppler shift calculation for satellite-ground links.

Given a satellite's GCRS state vector (position and velocity), a ground
station, and a carrier frequency, computes the radial velocity (range rate)
and the resulting Doppler shift.

# `datetime`

```elixir
@type datetime() ::
  DateTime.t()
  | {{integer(), integer(), integer()}, {integer(), integer(), integer()}}
```

# `gcrs_state`

```elixir
@type gcrs_state() :: %{position: vec3(), velocity: vec3()}
```

# `ground_station`

```elixir
@type ground_station() :: %{
  latitude: number(),
  longitude: number(),
  altitude_m: number()
}
```

# `result`

```elixir
@type result() :: %{
  range_rate_km_s: float(),
  doppler_hz: float(),
  doppler_ratio: float()
}
```

# `vec3`

```elixir
@type vec3() :: {number(), number(), number()}
```

# `shift`

```elixir
@spec shift(gcrs_state(), datetime(), ground_station(), number()) :: result()
```

Compute Doppler shift for a satellite-ground link.

## Parameters

  - `gcrs_state` - map with `:position` `{x, y, z}` (km) and `:velocity`
    `{vx, vy, vz}` (km/s) in GCRS
  - `datetime` - observation time (`DateTime` or `{{y,m,d},{h,m,s}}` tuple)
  - `ground_station` - `%{latitude: deg, longitude: deg, altitude_m: meters}`
  - `frequency_hz` - carrier frequency in Hz

## Returns

A map with:
  - `:range_rate_km_s` - radial velocity in km/s (positive = approaching)
  - `:doppler_hz` - Doppler shift in Hz (positive = frequency increase)
  - `:doppler_ratio` - dimensionless Doppler ratio (-range_rate / c)

## Example

    gcrs = Sidereon.teme_to_gcrs(teme, datetime)
    station = %{latitude: 40.0, longitude: -74.0, altitude_m: 0.0}
    result = Sidereon.Doppler.shift(gcrs, datetime, station, 437.0e6)
    result.doppler_hz  # => ~10_000.0 (for typical LEO pass)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
