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

RINEX observation convenience entry points for GNSS single-point positioning.

This module exposes the RINEX OBS plus broadcast NAV helpers from the core
facade. It assembles each usable observation epoch into the same SPP inputs
consumed by `Sidereon.GNSS.Positioning`, and can serially solve every assembled
epoch in one native call.

# `rinex_option`

```elixir
@type rinex_option() ::
  {:codes, %{required(String.t()) =&gt; [String.t()]}}
  | {:ionosphere, boolean()}
  | {:troposphere, boolean()}
  | {:initial_guess, {number(), number(), number(), number()} | [number()]}
  | {:satellites, [String.t()]}
  | {:pressure_hpa, number()}
  | {:temperature_k, number()}
  | {:relative_humidity, number()}
  | {:huber, boolean()}
  | {:huber_k, number()}
  | {:huber_sigma, number()}
  | {:huber_max_iter, pos_integer()}
```

Options used while assembling RINEX observation epochs into SPP inputs.

# `solve_option`

```elixir
@type solve_option() ::
  rinex_option()
  | {:with_geodetic, boolean()}
  | {:max_pdop, number()}
  | {:coarse_search_seeds, pos_integer()}
```

Solve policy options for `solve_spp_from_rinex_obs/3`.

# `solve_spp_from_rinex_obs`

```elixir
@spec solve_spp_from_rinex_obs(
  Sidereon.GNSS.Broadcast.t(),
  Sidereon.GNSS.RINEX.Observations.t(),
  [
    solve_option()
  ]
) :: {:ok, [Sidereon.GNSS.SPP.EpochSolution.t()]} | {:error, term()}
```

Assemble RINEX OBS epochs and solve each epoch serially with SPP.

The source and RINEX observation arguments match `spp_inputs_from_rinex_obs/3`.
Per-epoch solve failures are retained in the returned list as
`%EpochSolution{solution: {:error, reason}}`.

Additional solve options:

  * `:with_geodetic` - include geodetic output in successful solutions,
    default `true`.
  * `:max_pdop` - optional positive PDOP ceiling.
  * `:coarse_search_seeds` - optional positive cold-start search seed count.

# `spp_inputs_from_rinex_obs`

```elixir
@spec spp_inputs_from_rinex_obs(
  Sidereon.GNSS.Broadcast.t(),
  Sidereon.GNSS.RINEX.Observations.t(),
  [
    rinex_option()
  ]
) :: {:ok, [Sidereon.GNSS.SPP.EpochInputs.t()]} | {:error, term()}
```

Assemble usable RINEX OBS epochs into SPP inputs using a broadcast NAV product.

`source` is a parsed `Sidereon.GNSS.Broadcast` product and `obs` is a parsed
`Sidereon.GNSS.RINEX.Observations` product. The returned list has one element
per usable non-event RINEX epoch with at least one selected pseudorange.

Options:

  * `:codes` - per-system pseudorange code policy, e.g. `%{"G" => ["C1C"]}`;
    omitted means the core default for the RINEX version.
  * `:ionosphere` / `:troposphere` - requested corrections, both default `true`.
  * `:initial_guess` - optional `{x_m, y_m, z_m, b_m}`; omitted uses the RINEX
    `APPROX POSITION XYZ` with zero clock.
  * `:satellites` - optional satellite id allow-list.
  * `:pressure_hpa`, `:temperature_k`, `:relative_humidity` - surface met
    values for the troposphere model.
  * `:huber` plus `:huber_k`, `:huber_sigma`, `:huber_max_iter` - optional
    robust reweighting for each assembled solve.

---

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