# `Sidereon.GNSS.Fusion`
[🔗](https://github.com/neilberkman/sidereon-ex/blob/main/lib/sidereon/gnss/fusion.ex#L1)

Stateful GNSS/INS fusion filters.

The filter is an opaque native resource. Calls mutate the native filter and
return snapshots, update reports, or versioned state bytes.

# `filter_config`

```elixir
@type filter_config() :: map()
```

Fusion filter configuration map.

# `filter_state`

```elixir
@type filter_state() :: map()
```

Initial closed-loop INS state and covariance.

# `imu_sample`

```elixir
@type imu_sample() :: Sidereon.GNSS.Fusion.ImuSample.t() | map()
```

IMU sample accepted by `propagate/2`.

# `imu_spec`

```elixir
@type imu_spec() :: map() | :mems | :tactical | :navigation
```

IMU specification map accepted by `filter_config/2`.

# `loose_measurement`

```elixir
@type loose_measurement() :: Sidereon.GNSS.Fusion.GnssFixMeasurement.t() | map()
```

Loose GNSS position or position-velocity fix.

# `mat3`

```elixir
@type mat3() :: [vec3()]
```

Three-by-three row-major matrix.

# `tight_epoch`

```elixir
@type tight_epoch() :: Sidereon.GNSS.Fusion.TightGnssEpoch.t() | map()
```

Tight GNSS raw-observation epoch.

# `vec3`

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

Three-vector in ECEF or body axes, depending on field name.

# `velocity_match_state`

```elixir
@type velocity_match_state() :: Sidereon.GNSS.Fusion.VelocityMatchState.t() | map()
```

One position and velocity sample used by outage velocity matching.

# `configure_time_sync`

```elixir
@spec configure_time_sync(Sidereon.GNSS.Fusion.Filter.t(), keyword() | map()) ::
  {:ok, map()} | {:error, term()}
```

Configure retained IMU samples and GNSS checkpoints for time synchronization.

# `configure_time_sync_history`

```elixir
@spec configure_time_sync_history(
  Sidereon.GNSS.Fusion.Filter.t(),
  Sidereon.GNSS.Fusion.TimeSyncHistoryConfig.t() | keyword() | map()
) :: {:ok, map()} | {:error, term()}
```

Alias for `configure_time_sync/2` matching Python's retained-history name.

# `encode_state`

```elixir
@spec encode_state(Sidereon.GNSS.Fusion.Filter.t()) ::
  {:ok, binary()} | {:error, term()}
```

Encode the current filter state and retained time-sync history as bytes.

# `filter_config`

```elixir
@spec filter_config(imu_spec(), keyword() | map()) :: filter_config()
```

Build a fusion filter config from an IMU spec and options.

Options include `:filter_kind` (`:ekf` or `:ukf`), `:mechanization`,
`:loose`, `:tight`, `:imu_model`, `:imu_to_body_dcm`, and
`:ukf_update_options`. Loose config may include `:fix_status_weighting`,
`:measurement_reweighting`, `:prediction_adaptation`, `:stationary_updates`,
and `:non_holonomic`.

# `from_encoded_state`

```elixir
@spec from_encoded_state(binary(), filter_config()) ::
  {:ok, Sidereon.GNSS.Fusion.Filter.t()} | {:error, term()}
```

Alias for `from_state_bytes/2` matching Python's encoded-state constructor.

# `from_state_bytes`

```elixir
@spec from_state_bytes(binary(), filter_config()) ::
  {:ok, Sidereon.GNSS.Fusion.Filter.t()} | {:error, term()}
```

Restore a new stateful filter from versioned fusion state bytes.

# `gnss_fix_status_weighting`

```elixir
@spec gnss_fix_status_weighting(keyword() | map()) :: map()
```

Return per-fix-status sigma multipliers for loose GNSS updates.

# `igg_iii_measurement_reweighting`

```elixir
@spec igg_iii_measurement_reweighting(keyword() | map()) :: map()
```

Return standard IGG-III measurement reweighting settings for loose updates.

# `imu_spec`

```elixir
@spec imu_spec(imu_spec()) :: map()
```

Return an IMU stochastic specification.

Presets are `:mems`, `:tactical`, and `:navigation`. A map is passed through
after numeric normalization.

# `new`

```elixir
@spec new(filter_state(), filter_config()) ::
  {:ok, Sidereon.GNSS.Fusion.Filter.t()} | {:error, term()}
```

Build a new stateful filter.

# `non_holonomic_constraint_config`

```elixir
@spec non_holonomic_constraint_config(keyword() | map()) :: map()
```

Return wheeled-vehicle lateral and vertical velocity constraint settings.

# `propagate`

```elixir
@spec propagate(Sidereon.GNSS.Fusion.Filter.t(), imu_sample()) ::
  {:ok, map()} | {:error, term()}
```

Propagate the filter by one IMU sample.

# `propagate_recorded`

```elixir
@spec propagate_recorded(
  Sidereon.GNSS.Fusion.Filter.t(),
  imu_sample(),
  Sidereon.GNSS.Fusion.FusionRtsHistoryBuilder.t()
) :: {:ok, map()} | {:error, term()}
```

Propagate the filter by one IMU sample and record the transition for RTS smoothing.

# `restore_encoded_state`

```elixir
@spec restore_encoded_state(Sidereon.GNSS.Fusion.Filter.t(), binary()) ::
  {:ok, map()} | {:error, term()}
```

Alias for `restore_state/2` matching Python's encoded-state restore method.

# `restore_state`

```elixir
@spec restore_state(Sidereon.GNSS.Fusion.Filter.t(), binary()) ::
  {:ok, map()} | {:error, term()}
```

Restore an existing filter from bytes produced by `encode_state/1`.

# `smooth_fusion_rts`

```elixir
@spec smooth_fusion_rts(Sidereon.GNSS.Fusion.FusionRtsHistory.t()) ::
  {:ok, Sidereon.GNSS.Fusion.SmoothedFusionTrajectory.t()} | {:error, term()}
```

Apply fixed-interval RTS smoothing to recorded GNSS/INS fusion history.

# `state`

```elixir
@spec state(Sidereon.GNSS.Fusion.Filter.t()) :: {:ok, map()} | {:error, term()}
```

Return the current closed-loop filter state.

# `stationary_detector_config`

```elixir
@spec stationary_detector_config(keyword() | map()) :: map()
```

Return windowed IMU thresholds for stationary update detection.

# `stationary_update_config`

```elixir
@spec stationary_update_config(keyword() | map()) :: map()
```

Return zero-velocity and zero-angular-rate stationary update settings.

# `strapdown_config`

```elixir
@spec strapdown_config(keyword() | map()) :: map()
```

Return a strapdown mechanization config.

The current core surface exposes `:off` coning correction.

# `tight_clock_state`

```elixir
@spec tight_clock_state(Sidereon.GNSS.Fusion.Filter.t()) ::
  {:ok, map()} | {:error, term()}
```

Return the tight receiver-clock state.

# `time_sync_history_status`

```elixir
@spec time_sync_history_status(Sidereon.GNSS.Fusion.Filter.t()) ::
  {:ok, map()} | {:error, term()}
```

Alias for `time_sync_status/1` matching Python's retained-history name.

# `time_sync_status`

```elixir
@spec time_sync_status(Sidereon.GNSS.Fusion.Filter.t()) ::
  {:ok, map()} | {:error, term()}
```

Return retained-history occupancy for time synchronization.

# `update_loose`

```elixir
@spec update_loose(Sidereon.GNSS.Fusion.Filter.t(), loose_measurement()) ::
  {:ok, map()} | {:error, term()}
```

Apply a loose GNSS position or position-velocity fix at the current filter epoch.

# `update_loose_recorded`

```elixir
@spec update_loose_recorded(
  Sidereon.GNSS.Fusion.Filter.t(),
  loose_measurement(),
  Sidereon.GNSS.Fusion.FusionRtsHistoryBuilder.t()
) :: {:ok, map()} | {:error, term()}
```

Apply a loose GNSS fix and record before/after checkpoints for RTS smoothing.

# `update_loose_time_sync`

```elixir
@spec update_loose_time_sync(Sidereon.GNSS.Fusion.Filter.t(), loose_measurement()) ::
  {:ok, map()} | {:error, term()}
```

Apply a time-synchronized loose GNSS fix, replaying retained history if needed.

# `update_non_holonomic`

```elixir
@spec update_non_holonomic(Sidereon.GNSS.Fusion.Filter.t()) ::
  {:ok, map() | nil} | {:error, term()}
```

Apply configured non-holonomic vehicle constraints.

# `update_non_holonomic_recorded`

```elixir
@spec update_non_holonomic_recorded(
  Sidereon.GNSS.Fusion.Filter.t(),
  Sidereon.GNSS.Fusion.FusionRtsHistoryBuilder.t()
) :: {:ok, map() | nil} | {:error, term()}
```

Apply configured non-holonomic constraints and record checkpoints when applied.

# `update_stationary`

```elixir
@spec update_stationary(Sidereon.GNSS.Fusion.Filter.t()) ::
  {:ok, map() | nil} | {:error, term()}
```

Apply configured stationary zero-velocity and zero-angular-rate constraints.

# `update_stationary_recorded`

```elixir
@spec update_stationary_recorded(
  Sidereon.GNSS.Fusion.Filter.t(),
  Sidereon.GNSS.Fusion.FusionRtsHistoryBuilder.t()
) :: {:ok, map() | nil} | {:error, term()}
```

Apply configured stationary constraints and record checkpoints when applied.

# `update_tight`

```elixir
@spec update_tight(
  Sidereon.GNSS.Fusion.Filter.t(),
  Sidereon.GNSS.SP3.t() | Sidereon.GNSS.Broadcast.t(),
  tight_epoch()
) :: {:ok, map()} | {:error, term()}
```

Apply a tight raw GNSS epoch at the current filter epoch.

The ephemeris source must be an existing SP3 or broadcast resource.

# `update_tight_recorded`

```elixir
@spec update_tight_recorded(
  Sidereon.GNSS.Fusion.Filter.t(),
  Sidereon.GNSS.SP3.t() | Sidereon.GNSS.Broadcast.t(),
  tight_epoch(),
  Sidereon.GNSS.Fusion.FusionRtsHistoryBuilder.t()
) :: {:ok, map()} | {:error, term()}
```

Apply a tight raw GNSS epoch and record before/after checkpoints for RTS smoothing.

# `update_tight_time_sync`

```elixir
@spec update_tight_time_sync(
  Sidereon.GNSS.Fusion.Filter.t(),
  Sidereon.GNSS.SP3.t() | Sidereon.GNSS.Broadcast.t(),
  tight_epoch()
) :: {:ok, map()} | {:error, term()}
```

Apply a time-synchronized tight raw GNSS epoch.

# `velocity_match_outage`

```elixir
@spec velocity_match_outage(
  [velocity_match_state()],
  loose_measurement(),
  keyword() | map()
) ::
  {:ok, map()} | {:error, term()}
```

Blend a first good post-outage position/velocity fix back over an outage span.

# `velocity_matching_config`

```elixir
@spec velocity_matching_config(keyword() | map()) :: map()
```

Return endpoint velocity matching settings for one GNSS outage.

# `with_config`

```elixir
@spec with_config(filter_state(), filter_config()) ::
  {:ok, Sidereon.GNSS.Fusion.Filter.t()} | {:error, term()}
```

Alias for `new/2` matching the Python `InertialFilter.with_config` constructor.

# `yang_prediction_adaptive_factor`

```elixir
@spec yang_prediction_adaptive_factor(keyword() | map()) :: map()
```

Return standard Yang predicted-covariance adaptation settings for loose updates.

---

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