ba-thesis/sw/decoders/utility.py

81 lines
2.6 KiB
Python

"""This file contains various utility functions that can be used in combination with the decoders.
"""
import numpy as np
import typing
from tqdm import tqdm
def _get_noise_amp_from_SNR(SNR: float, signal_amp: float = 1) -> float:
"""Calculate the amplitude of the noise from an SNR and the signal amplitude
:param SNR: Signal-to-Noise-Ratio in dB
:param signal_amp: Signal Amplitude (linear)
:return: Noise Amplitude (linear)
"""
SNR_linear = 10 ** (SNR / 10)
noise_amp = (1 / np.sqrt(SNR_linear)) * signal_amp
return noise_amp
def add_awgn(c: np.array, SNR: float) -> np.array:
"""Add Additive White Gaussian Noise to a data vector. As this function adds random noise to the input,
the output changes, even if it is called multiple times with the same input.
:param c: Binary vector representing the data to be transmitted
:param SNR: Signal-to-Noise-Ratio in dB
:return: Data vector with added noise
"""
noise_amp = _get_noise_amp_from_SNR(SNR, signal_amp=1)
y = c + np.random.normal(scale=noise_amp, size=c.size)
return y
def count_bit_errors(d: np.array, d_hat: np.array) -> int:
"""Count the number of wrong bits in a decoded codeword.
:param d: Originally sent data
:param d_hat: Received data
:return: Number of bit errors
"""
return np.sum(d != d_hat)
def test_decoder(decoder: typing.Any,
c: np.array,
SNRs: typing.Sequence[float] = np.linspace(1, 4, 7),
N=10000) \
-> typing.Tuple[np.array, np.array]:
"""Calculate the Bit Error Rate (BER) for a given decoder for a number of SNRs.
This function prints it's progress to stdout
:param decoder: Instance of the decoder to be tested
:param c: Codeword whose transmission is to be simulated
:param SNRs: List of SNRs for which the BER should be calculated
:param N: Number of iterations to perform for each SNR
:return: Tuple of numpy arrays of the form (SNRs, BERs)
"""
BERs = []
for SNR in tqdm(SNRs, desc="Calculating Bit-Error-Rates",
position=0,
bar_format="{l_bar}{bar}| {n_fmt}/{total_fmt}"):
total_bit_errors = 0
for n in tqdm(range(N), desc=f"Simulating for SNR = {SNR} dB",
position=1,
leave=False,
bar_format="{l_bar}{bar}| {n_fmt}/{total_fmt}"):
y = add_awgn(c, SNR)
y_hat = decoder.decode(y)
total_bit_errors += count_bit_errors(c, y_hat)
total_bits = c.size * N
BERs.append(total_bit_errors / total_bits)
return np.array(SNRs), np.array(BERs)