# `Sidereon.Estimation.TrackFilter`
[🔗](https://github.com/neilberkman/sidereon-ex/blob/main/lib/sidereon/estimation.ex#L494)

Stateful no-IMU constant-velocity track filter.

The native handle is mutated by prediction and update calls. Each call returns
the corresponding state, innovation, update, or gating report as Elixir
structs.

# `t`

```elixir
@type t() :: %Sidereon.Estimation.TrackFilter{handle: reference()}
```

# `acceleration_variance_spectral_density_m2_s3`

```elixir
@spec acceleration_variance_spectral_density_m2_s3(t()) ::
  {:ok, float()} | {:error, term()}
```

Return the white acceleration variance spectral density in `m^2 / s^3`.

# `dimension`

```elixir
@spec dimension(t()) :: {:ok, pos_integer()} | {:error, term()}
```

Return the position dimension.

# `from_position`

```elixir
@spec from_position(keyword() | map()) :: {:ok, t()} | {:error, term()}
```

Build a filter from a position fix and uncertain zero initial velocity.

# `new`

```elixir
@spec new(Sidereon.Estimation.TrackFilterConfig.t()) :: {:ok, t()} | {:error, term()}
```

Build a stateful track filter from a validated config.

# `position_innovation`

```elixir
@spec position_innovation(t(), [number()] | tuple(), [[number()]]) ::
  {:ok, Sidereon.Estimation.TrackInnovation.t()} | {:error, term()}
```

Compute the position-only innovation without applying the observation.

# `predict`

```elixir
@spec predict(t(), number()) ::
  {:ok, Sidereon.Estimation.TrackPrediction.t()} | {:error, term()}
```

Predict the filter forward by `dt_s`.

# `predict_recorded`

```elixir
@spec predict_recorded(t(), number(), Sidereon.Estimation.TrackRtsHistoryBuilder.t()) ::
  {:ok, Sidereon.Estimation.TrackPrediction.t()} | {:error, term()}
```

Predict forward and record the interval for RTS smoothing.

# `record_prediction_only`

```elixir
@spec record_prediction_only(t(), Sidereon.Estimation.TrackRtsHistoryBuilder.t()) ::
  :ok | {:error, term()}
```

Record the current predicted state as an epoch without a measurement update.

# `state`

```elixir
@spec state(t()) :: {:ok, Sidereon.Estimation.TrackState.t()} | {:error, term()}
```

Return the current filter state.

# `state_innovation`

```elixir
@spec state_innovation(t(), [number()] | tuple(), [[number()]]) ::
  {:ok, Sidereon.Estimation.TrackInnovation.t()} | {:error, term()}
```

Compute the full state innovation without applying the observation.

# `update_position`

```elixir
@spec update_position(t(), [number()] | tuple(), [[number()]]) ::
  {:ok, Sidereon.Estimation.TrackUpdate.t()} | {:error, term()}
```

Apply a position-only observation with covariance weighting.

# `update_position_gated`

```elixir
@spec update_position_gated(t(), [number()] | tuple(), [[number()]], number()) ::
  {:ok, Sidereon.Estimation.TrackGatedUpdate.t()} | {:error, term()}
```

Apply a position-only observation only when it passes the NIS gate.

# `update_position_gated_recorded`

```elixir
@spec update_position_gated_recorded(
  t(),
  [number()] | tuple(),
  [[number()]],
  number(),
  Sidereon.Estimation.TrackRtsHistoryBuilder.t()
) :: {:ok, Sidereon.Estimation.TrackGatedUpdate.t()} | {:error, term()}
```

Apply a gated position-only update and record accepted or rejected epochs.

# `update_position_recorded`

```elixir
@spec update_position_recorded(
  t(),
  [number()] | tuple(),
  [[number()]],
  Sidereon.Estimation.TrackRtsHistoryBuilder.t()
) :: {:ok, Sidereon.Estimation.TrackUpdate.t()} | {:error, term()}
```

Apply a position-only update and record the epoch for RTS smoothing.

# `update_state`

```elixir
@spec update_state(t(), [number()] | tuple(), [[number()]]) ::
  {:ok, Sidereon.Estimation.TrackUpdate.t()} | {:error, term()}
```

Apply a position-and-velocity observation with covariance weighting.

---

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