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

Closed-form GNSS signal spectrum and tracking metrics.

This module is a thin Elixir boundary over the core signal-analysis formulas.
Modulations are plain maps built by the constructor functions; metric calls
return `{:ok, value}` or `{:error, reason}`.

# `dll_options`

```elixir
@type dll_options() ::
  Sidereon.GNSS.Signal.Analysis.DllTrackingOptions.t()
  | %{
      cn0_db_hz: number(),
      loop_bandwidth_hz: number(),
      integration_time_s: number(),
      correlator_spacing_chips: number(),
      receiver_bandwidth_hz: number()
    }
```

DLL thermal-noise options.

# `jitter`

```elixir
@type jitter() :: %{
  seconds: float(),
  chips: float(),
  meters: float(),
  squaring_loss: float()
}
```

DLL jitter result.

# `modulation`

```elixir
@type modulation() ::
  %{kind: :bpsk, order: number()}
  | %{kind: :boc_sine, m: number(), n: number()}
  | %{kind: :boc_cosine, m: number(), n: number()}
  | %{kind: :mboc_6_1_1_over_11}
  | %{kind: :tmboc_6_1_4_over_33}
```

Navigation-signal modulation descriptor.

# `multipath_options`

```elixir
@type multipath_options() ::
  Sidereon.GNSS.Signal.Analysis.MultipathOptions.t()
  | %{
      multipath_to_direct_ratio: number(),
      correlator_spacing_chips: number(),
      receiver_bandwidth_hz: number()
    }
```

Multipath-envelope options.

# `multipath_point`

```elixir
@type multipath_point() :: %{
  delay_chips: float(),
  delay_s: float(),
  in_phase_chips: float(),
  in_phase_s: float(),
  in_phase_m: float(),
  anti_phase_chips: float(),
  anti_phase_s: float(),
  anti_phase_m: float(),
  running_average_chips: float(),
  running_average_s: float(),
  running_average_m: float()
}
```

One multipath-envelope point.

# `boc_cosine`

```elixir
@spec boc_cosine(number(), number()) :: modulation()
```

Build a cosine-phased BOC(m,n) modulation descriptor.

# `boc_sine`

```elixir
@spec boc_sine(number(), number()) :: modulation()
```

Build a sine-phased BOC(m,n) modulation descriptor.

# `bpsk1`

```elixir
@spec bpsk1() :: modulation()
```

Build the BPSK(1) modulation descriptor.

# `bpsk`

```elixir
@spec bpsk(number()) :: modulation()
```

Build a BPSK(n) modulation descriptor.

# `code_rate_hz`

```elixir
@spec code_rate_hz(modulation()) :: {:ok, float()} | {:error, term()}
```

Return the code rate in hertz when the modulation has one unambiguous rate.

# `dll_jitter`

```elixir
@spec dll_jitter(modulation(), dll_options(), :coherent | :non_coherent) ::
  {:ok, jitter()} | {:error, term()}
```

Return early-late DLL thermal-noise jitter.

`processing` is `:coherent` or `:non_coherent`.

# `dll_lower_bound`

```elixir
@spec dll_lower_bound(modulation(), dll_options()) ::
  {:ok, jitter()} | {:error, term()}
```

Return the DLL lower bound for code-delay tracking jitter.

# `effective_cn0_degradation`

```elixir
@spec effective_cn0_degradation(modulation(), number(), number(), [map()]) ::
  {:ok,
   %{
     effective_cn0_hz: float(),
     effective_cn0_db_hz: float(),
     degradation_db: float()
   }}
  | {:error, term()}
```

Return effective C/N0 after finite-band interference terms.

Each interference is a map with `:modulation` and
`:power_ratio_to_carrier`.

# `fraction_power`

```elixir
@spec fraction_power(modulation(), number()) :: {:ok, float()} | {:error, term()}
```

Return the fraction of total signal power inside a two-sided receiver bandwidth.

# `label`

```elixir
@spec label(modulation()) :: {:ok, String.t()} | {:error, term()}
```

Return the stable core label for a modulation descriptor.

# `mboc_6_1_1_over_11`

```elixir
@spec mboc_6_1_1_over_11() :: modulation()
```

Build the normalized MBOC(6,1,1/11) modulation descriptor.

# `multipath_envelope`

```elixir
@spec multipath_envelope(modulation(), multipath_options(), [number()]) ::
  {:ok, [multipath_point()]} | {:error, term()}
```

Return a one-path early-late multipath envelope on the supplied delay grid.

# `power_in_band`

```elixir
@spec power_in_band(modulation(), number()) :: {:ok, float()} | {:error, term()}
```

Return signal power inside a two-sided receiver bandwidth.

# `psd_hz`

```elixir
@spec psd_hz(modulation(), number() | [number()]) ::
  {:ok, float() | [float()]} | {:error, term()}
```

Return normalized PSD values in `1/Hz` at one offset or a list of offsets.

# `rms_bandwidth_hz`

```elixir
@spec rms_bandwidth_hz(modulation(), number()) :: {:ok, float()} | {:error, term()}
```

Return RMS bandwidth over a two-sided receiver bandwidth, in hertz.

# `signal_betz_l1_receiver_bandwidth_hz`

```elixir
@spec signal_betz_l1_receiver_bandwidth_hz() :: float()
```

Return the receiver bandwidth used by the Betz L1 SSC fixture, in hertz.

# `signal_dll_lower_bound`

```elixir
@spec signal_dll_lower_bound(modulation(), dll_options()) ::
  {:ok, jitter()} | {:error, term()}
```

Alias for `dll_lower_bound/2` matching the Python module-level helper name.

# `signal_dll_thermal_noise_jitter`

```elixir
@spec signal_dll_thermal_noise_jitter(
  modulation(),
  dll_options(),
  :coherent | :non_coherent
) ::
  {:ok, jitter()} | {:error, term()}
```

Alias for `dll_jitter/3` matching the Python module-level helper name.

# `signal_effective_cn0_degradation`

```elixir
@spec signal_effective_cn0_degradation(modulation(), number(), number(), [
  map() | Sidereon.GNSS.Signal.Analysis.InterferenceTerm.t()
]) ::
  {:ok,
   %{
     effective_cn0_hz: float(),
     effective_cn0_db_hz: float(),
     degradation_db: float()
   }}
  | {:error, term()}
```

Alias for `effective_cn0_degradation/4` matching the Python module-level helper name.

# `signal_fraction_power_in_band`

```elixir
@spec signal_fraction_power_in_band(modulation(), number()) ::
  {:ok, float()} | {:error, term()}
```

Alias for `fraction_power/2` matching the Python module-level helper name.

# `signal_multipath_error_envelope`

```elixir
@spec signal_multipath_error_envelope(modulation(), multipath_options(), [number()]) ::
  {:ok, [multipath_point()]} | {:error, term()}
```

Alias for `multipath_envelope/3` matching the Python module-level helper name.

# `signal_power_in_band`

```elixir
@spec signal_power_in_band(modulation(), number()) ::
  {:ok, float()} | {:error, term()}
```

Alias for `power_in_band/2` matching the Python module-level helper name.

# `signal_psd`

```elixir
@spec signal_psd(modulation(), [number()]) :: {:ok, [float()]} | {:error, term()}
```

Alias for vector PSD evaluation matching the Python module-level helper name.

# `signal_psd_hz`

```elixir
@spec signal_psd_hz(modulation(), number()) :: {:ok, float()} | {:error, term()}
```

Alias for `psd_hz/2` matching the Python module-level helper name.

# `signal_reference_chip_rate_hz`

```elixir
@spec signal_reference_chip_rate_hz() :: float()
```

Return the reference chipping-rate unit used by BPSK and BOC, in hertz.

# `signal_rms_bandwidth_hz`

```elixir
@spec signal_rms_bandwidth_hz(modulation(), number()) ::
  {:ok, float()} | {:error, term()}
```

Alias for `rms_bandwidth_hz/2` matching the Python module-level helper name.

# `signal_spectral_separation_coefficient_db_hz`

```elixir
@spec signal_spectral_separation_coefficient_db_hz(
  modulation(),
  modulation(),
  number()
) ::
  {:ok, float()} | {:error, term()}
```

Alias for `ssc_db_hz/3` matching the Python module-level helper name.

# `signal_spectral_separation_coefficient_hz`

```elixir
@spec signal_spectral_separation_coefficient_hz(modulation(), modulation(), number()) ::
  {:ok, float()} | {:error, term()}
```

Alias for `ssc_hz/3` matching the Python module-level helper name.

# `signal_white_noise_spectral_separation_hz`

```elixir
@spec signal_white_noise_spectral_separation_hz(modulation(), number()) ::
  {:ok, float()} | {:error, term()}
```

Alias for `white_noise_spectral_separation_hz/2` matching the Python module-level helper name.

# `ssc_db_hz`

```elixir
@spec ssc_db_hz(modulation(), modulation(), number()) ::
  {:ok, float()} | {:error, term()}
```

Return spectral separation coefficient in decibel-hertz.

# `ssc_hz`

```elixir
@spec ssc_hz(modulation(), modulation(), number()) ::
  {:ok, float()} | {:error, term()}
```

Return spectral separation coefficient in hertz.

# `tmboc_6_1_4_over_33`

```elixir
@spec tmboc_6_1_4_over_33() :: modulation()
```

Build the GPS L1C pilot TMBOC(6,1,4/33) modulation descriptor.

# `white_noise_spectral_separation_hz`

```elixir
@spec white_noise_spectral_separation_hz(modulation(), number()) ::
  {:ok, float()} | {:error, term()}
```

Return the spectral separation coefficient against white interference.

---

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