komunikilo 0.1.5

A chaotic communications simulator.
Documentation
#!/usr/bin/env python3
import numpy as np
from math import cos, pi
from typing import Any, Generator, Iterable, List
import matplotlib.pyplot as plt

SAMP_RATE = 80000
SYMB_RATE = 1000
CARRIER_FREQ = 2500
SAMPS_PER_SYMB = SAMP_RATE / SYMB_RATE
T_STEP = 1 / SAMPS_PER_SYMB
# DATA = [False, False, True, False, False, True, False, True, True, True]
DATA = [True, True, False, False, True]

HADAMARD8 = [  # fmt: off
    [True, True, True, True, True, True, True, True],
    [True, False, True, False, True, False, True, False],
    [True, True, False, False, True, True, False, False],
    [True, False, False, True, True, False, False, True],
    [True, True, True, True, False, False, False, False],
    [True, False, True, False, False, True, False, True],
    [True, True, False, False, False, False, True, True],
    [True, False, False, True, False, True, True, False],
]  # fmt: on


def bits_to_nrz(bits: Iterable[bool]) -> List[int]:
    return [1 if bit else -1 for bit in bits]


def tx_bpsk(
    bits: Iterable[bool], sample_rate: int, symbol_rate: int, freq: float
) -> List[float]:
    samps_per_symb: int = int(sample_rate / symbol_rate)
    t_step: float = 1 / samps_per_symb
    return [
        b_i * cos(2 * pi * freq * (i * t_step))
        for (i, b_i) in enumerate(
            i for i in bits_to_nrz(bits) for _ in range(samps_per_symb)
        )
    ]


def tx_baseband_cdma(data: Iterable[bool], key: List[bool]) -> List[bool]:
    return [bit ^ keybit for bit in data for keybit in key]


def tx_cdma_bpsk(
    bits: Iterable[bool],
    sample_rate: int,
    symbol_rate: int,
    freq: float,
    key: List[bool],
) -> List[float]:
    """Seemingly Correct."""
    samps_per_symb: int = int(sample_rate / symbol_rate)
    samps_per_chip: int = int(samps_per_symb / len(key))
    t_step: float = 1 / samps_per_symb

    def loop_list(list: List[Any]) -> Generator[Any, None, None]:
        while True:
            for item in list:
                yield item

    loop_key = lambda key: (
        1 if keybit else -1 for keybit in loop_list(key) for _ in range(samps_per_chip)
    )

    bpsk_data = tx_bpsk(
        bits,
        sample_rate,
        symbol_rate,
        freq,
    )
    # A bit comes out every samples_per_symb.
    # We need len(key) chips within samples_per_symb.
    return [s_i * keybit for s_i, keybit in zip(bpsk_data, loop_key(key))]


def t(s: Iterable[Any], t_step: float) -> List[float]:
    return [t_step * i for i in range(len(s))]


def first_hadamard_code_plot():
    key = HADAMARD8[0]

    data_tx = bits_to_nrz(DATA)
    bpsk_tx = tx_bpsk(DATA, SAMP_RATE, SYMB_RATE, CARRIER_FREQ)
    cdma_baseband = tx_baseband_cdma(DATA, key)
    cdma_tx = tx_cdma_bpsk(DATA, SAMP_RATE, SYMB_RATE, CARRIER_FREQ, key)

    fig, axes = plt.subplots(4)
    axes[0].plot(list(range(1, 6)), data_tx, label="DATA: [1 1 0 0 1]")
    axes[0].legend()
    axes[1].plot(t(bpsk_tx, T_STEP), bpsk_tx, label="BPSK: (2.5kHz, 1kHz Data Rate)")
    axes[1].legend()
    axes[2].plot(
        t(cdma_tx, T_STEP),
        cdma_tx,
        label="CDMA: (2.5kHz, 1kHz Data Rate, 8kHz Chip Rate)",
    )
    axes[2].legend()

    _, _ = plt.psd(bpsk_tx, Fs=SAMP_RATE, Fc=CARRIER_FREQ, label="BPSK")
    _, _ = plt.psd(cdma_tx, Fs=SAMP_RATE, Fc=CARRIER_FREQ, label="CDMA-BPSK")
    plt.legend()
    plt.show()


def cdma_plot():
    key = HADAMARD8[3]

    data_tx = bits_to_nrz(DATA)
    bpsk_tx = tx_bpsk(DATA, SAMP_RATE, SYMB_RATE, CARRIER_FREQ)
    cdma_baseband = tx_baseband_cdma(DATA, key)
    cdma_tx = tx_cdma_bpsk(DATA, SAMP_RATE, SYMB_RATE, CARRIER_FREQ, key)

    # plt.rcParams["figure.figsize"] = [16, 9]
    fig, axes = plt.subplots(4)
    axes[0].plot(list(range(1, 6)), data_tx, label="DATA: [1 1 0 0 1]")
    axes[0].legend()
    axes[1].plot(t(bpsk_tx, T_STEP), bpsk_tx, label="BPSK: (2.5kHz, 1kHz Data Rate)")
    axes[1].legend()
    axes[2].plot(
        t(cdma_tx, T_STEP),
        cdma_tx,
        label="CDMA: (2.5kHz, 1kHz Data Rate, 8kHz Chip Rate)",
    )
    axes[2].legend()

    _, _ = plt.psd(bpsk_tx, Fs=SAMP_RATE, Fc=CARRIER_FREQ, label="BPSK")
    _, _ = plt.psd(cdma_tx, Fs=SAMP_RATE, Fc=CARRIER_FREQ, label="CDMA-BPSK")
    plt.legend()
    # plt.savefig("/tmp/asdf.png", dpi=300)
    fig.set_size_inches(16, 9)
    fig.savefig("/tmp/asdf.png", dpi=300)
    # plt.show()


def rust_plot():
    with open("/tmp/cdma_bpsk.csv") as f:
        import csv

        lines = [i for i in csv.reader(f)]
        tr = [float(line[0]) for line in lines[1:]]
        vr = [float(line[1]) for line in lines[1:]]

    (_, ax) = plt.subplots(2)
    ax[0].plot(t(y5p, T_STEP), y5p)
    ax[1].plot(tr, vr)

    plt.legend()
    plt.show()


if __name__ == "__main__":
    cdma_plot()
    # first_hadamard_code_plot()