chaotic_pfc.comms.receiver

receiver.py

Chaos-synchronisation demodulator. Implements the Receiver protocol — a callable that extracts the original message from a transmitted (and possibly channel-distorted) carrier.

Both receivers rely on the Pecora-Carroll synchronisation principle: running a second copy of the Hénon oscillator driven by the received signal causes it to track the transmitter’s state after a short transient. The recovered message is then extracted as the difference between the driving signal and the local state estimate.

Two receivers are provided, mirroring chaotic_pfc.comms.transmitter:

  • receive() — 2-D Hénon demodulator. The message is recovered via

    \[\hat{m}[n] = \frac{r[n] - y_1[n]}{\mu}\]

    where y_1 is the local 2-D state driven by r.

  • receive_order_n() — higher-order demodulator. Uses the same FIR filter the transmitter used. The carrier is taken from the filtered state y[2][n] and the message follows the same formula with y_1 replaced by v = y[2].

Functions

receive(r[, mu, a, b, y0, z0])

Demodulate the carrier r via 2-D Hénon synchronisation.

receive_order_n(r, fir_coeffs[, mu, a, b, ...])

Demodulate the carrier r via N-th order Hénon synchronisation.

chaotic_pfc.comms.receiver.receive(r, mu=0.01, a=1.4, b=0.3, y0=0.0, z0=0.0)[source]

Demodulate the carrier r via 2-D Hénon synchronisation.

The local oscillator is driven by r itself:

\[\begin{split}y_1[n+1] &= a - r[n]^2 + b \, y_2[n] \\ y_2[n+1] &= y_1[n]\end{split}\]

This is the Pecora-Carroll trick: once y locks onto the transmitter’s state, r[n] - y_1[n] equals the instantaneous modulation and dividing by μ recovers the message.

Parameters:
  • r (ndarray[tuple[Any, ...], dtype[_ScalarT]]) – Received carrier, shape (N,). Usually the output of chaotic_pfc.comms.channel.ideal_channel() or chaotic_pfc.comms.channel.fir_channel().

  • mu (float) – Modulation depth — must match the value used at the transmitter, otherwise the recovered amplitude is rescaled.

  • a (float) – Hénon parameters — must match the transmitter’s.

  • b (float) – Hénon parameters — must match the transmitter’s.

  • y0 (float) – Initial conditions of the local oscillator. A random pair is a safe default; synchronisation converges regardless after a short transient.

  • z0 (float) – Initial conditions of the local oscillator. A random pair is a safe default; synchronisation converges regardless after a short transient.

Returns:

  • ndarray, shape (N,) – Recovered message estimate m̂[n] = (r[n] - y_1[n]) / μ. Transient samples (first few hundred) may differ from the true message while the local oscillator locks in; see chaotic_pfc.config.CommConfig.transient for the default rejection window.

  • Implements (Receiver.)

Return type:

ndarray[tuple[Any, …], dtype[_ScalarT]]

chaotic_pfc.comms.receiver.receive_order_n(r, fir_coeffs, mu=0.01, a=1.4, b=0.3, y0=None, seed=None)[source]

Demodulate the carrier r via N-th order Hénon synchronisation.

Runs a local copy of the N-th order filtered Hénon map driven by r, and recovers the message from the difference between the received sample and the local filtered state v = y[2]:

\[\hat{m}[n] = \frac{r[n] - v[n]}{\mu}\]
Parameters:
  • r (ndarray[tuple[Any, ...], dtype[_ScalarT]]) – Received carrier, shape (N,).

  • fir_coeffs (ndarray[tuple[Any, ...], dtype[_ScalarT]]) – FIR feedback coefficients, shape (Nc,). Must match the ones used at the transmitter — otherwise synchronisation fails.

  • mu (float) – Must match the transmitter’s parameters.

  • a (float) – Must match the transmitter’s parameters.

  • b (float) – Must match the transmitter’s parameters.

  • y0 (ndarray[tuple[Any, ...], dtype[_ScalarT]] | None) – Optional explicit initial state, shape (Nc,). If omitted, a random state is drawn from Uniform(0, 0.5).

  • seed (int | None) – Seed for the RNG used when y0=None. Has no effect when y0 is provided.

Returns:

  • m_hat (ndarray, shape (N,)) – Recovered message estimate.

  • state (ndarray, shape (Nc, N + 1)) – Full state trajectory of the local oscillator. Column 0 holds y0; each subsequent column is the next iterate.

  • Note (this function does NOT implement)

  • Receiver because it returns a

  • (recovered, state) tuple instead of a single ndarray. Use

  • receive() (the 2-D variant) for code that types against the

  • Receiver protocol.

Return type:

tuple[ndarray[tuple[Any, …], dtype[_ScalarT]], ndarray[tuple[Any, …], dtype[_ScalarT]]]