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

GPS L1 coarse/acquisition (C/A) code generation and correlation.

The C/A code is the family of 1023-chip Gold codes broadcast by GPS
satellites on the L1 carrier. Each satellite's code is the modulo-2 sum
(XOR) of two 10-stage maximal-length linear feedback shift registers (LFSRs),
G1 and G2, as defined in IS-GPS-200 (Section 3.3.2.3 and Figure 3-9):

  * G1 uses the polynomial `1 + x^3 + x^10` (feedback from stages 3 and 10).
  * G2 uses the polynomial `1 + x^2 + x^3 + x^6 + x^8 + x^9 + x^10`
    (feedback from stages 2, 3, 6, 8, 9, and 10).

Both registers are initialized to the all-ones state and clocked at the
1.023 Mcps chipping rate; the sequence repeats every 1023 chips (1 ms).

The per-satellite code is `G1 XOR G2i`, where `G2i` is a delayed copy of the
G2 sequence formed by the modulo-2 sum of two G2 register stages. The
stage pair is fixed per PRN by the IS-GPS-200 Table 3-I code-phase-selection
table (PRN 1 selects stages 2 and 6, PRN 2 selects 3 and 7, and so on);
selecting a stage pair is equivalent to an integer cyclic delay of the G2
m-sequence.

## Chip mapping (BPSK)

Binary chips are mapped to bipolar `±1` values using the standard BPSK
convention:

  * binary `0` maps to `+1`
  * binary `1` maps to `-1`

With this mapping a code's circular autocorrelation peaks at `+1023` at zero
lag, and the codes are nearly balanced (512 chips of `-1` and 511 of `+1`,
so the chip sum is `-1`).

Supported PRNs are the 32 GPS space-vehicle assignments, PRN 1 through 32.

## Examples

    iex> Sidereon.GNSS.Signal.CA.code_length()
    1023

    iex> Sidereon.GNSS.Signal.CA.chip_rate_hz()
    1_023_000

    iex> {:ok, chips} = Sidereon.GNSS.Signal.CA.code(1)
    iex> length(chips)
    1023

    iex> Sidereon.GNSS.Signal.CA.chip(1, 0)
    {:ok, -1}

    iex> Sidereon.GNSS.Signal.CA.code(33)
    {:error, {:unsupported_prn, 33}}

# `autocorrelation`

```elixir
@spec autocorrelation([integer()]) :: [integer()]
```

Circular autocorrelation of a bipolar code over all 1023 lags.

The result is the integer-valued sequence whose element at lag `k` is the
sum of `code[i] * code[i + k mod n]`. For a C/A code the zero-lag value is
1023 and every other value is one of `{-65, -1, 63}`.

## Examples

    iex> {:ok, code} = Sidereon.GNSS.Signal.CA.code(1)
    iex> [peak | _] = Sidereon.GNSS.Signal.CA.autocorrelation(code)
    iex> peak
    1023

# `chip`

```elixir
@spec chip(integer(), integer()) ::
  {:ok, integer()} | {:error, {:unsupported_prn, integer()}}
```

Returns the single bipolar (`±1`) chip at a 0-based, wrapping index.

The index is taken modulo 1023, so negative indices and indices at or beyond
the code length wrap around the period. Returns
`{:error, {:unsupported_prn, prn}}` for any PRN outside 1..32.

## Examples

    iex> Sidereon.GNSS.Signal.CA.chip(1, 0)
    {:ok, -1}

    iex> Sidereon.GNSS.Signal.CA.chip(1, 1023)
    {:ok, -1}

# `chip_rate_hz`

```elixir
@spec chip_rate_hz() :: 1_023_000
```

Returns the C/A chipping rate in hertz (1.023 Mcps).

## Examples

    iex> Sidereon.GNSS.Signal.CA.chip_rate_hz()
    1_023_000

# `code`

```elixir
@spec code(integer()) :: {:ok, [integer()]} | {:error, {:unsupported_prn, integer()}}
```

Returns the 1023 bipolar (`±1`) C/A chips for a PRN.

Binary `0` maps to `+1` and binary `1` maps to `-1`. Returns
`{:error, {:unsupported_prn, prn}}` for any PRN outside 1..32.

## Examples

    iex> {:ok, chips} = Sidereon.GNSS.Signal.CA.code(1)
    iex> length(chips)
    1023
    iex> Enum.take(chips, 4)
    [-1, -1, 1, 1]

# `code_length`

```elixir
@spec code_length() :: 1023
```

Returns the number of chips in one C/A code period.

## Examples

    iex> Sidereon.GNSS.Signal.CA.code_length()
    1023

# `correlation_at`

```elixir
@spec correlation_at([integer()], [integer()], integer()) :: integer()
```

Single-lag circular correlation of two equal-length bipolar codes.

Returns the integer sum of `code_a[i] * code_b[i + lag mod n]`.

# `cross_correlation`

```elixir
@spec cross_correlation([integer()], [integer()]) :: [integer()]
```

Circular cross-correlation of two equal-length bipolar codes over all lags.

The element at lag `k` is the sum of `code_a[i] * code_b[i + k mod n]`. For
two distinct C/A codes every value is one of `{-65, -1, 63}`.

---

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