diff --git a/sw/test/test_utility.py b/sw/test/test_utility.py index 7a07b65..0e5a204 100644 --- a/sw/test/test_utility.py +++ b/sw/test/test_utility.py @@ -28,16 +28,19 @@ class NoiseAmpFromSNRTestCase(unittest.TestCase): def test_get_noise_amp_from_SNR(self): SNR1 = 0 - SNR2 = 6 + SNR2 = 3 SNR3 = 20 SNR4 = -20 - SNR5 = 60 - self.assertEqual(noise.get_noise_amp_from_SNR(SNR1, signal_amp=1), 1) - self.assertAlmostEqual(noise.get_noise_amp_from_SNR(SNR2, signal_amp=1), 0.5, places=2) - self.assertEqual(noise.get_noise_amp_from_SNR(SNR3, signal_amp=1), 0.1) - self.assertEqual(noise.get_noise_amp_from_SNR(SNR4, signal_amp=1), 10) - self.assertEqual(noise.get_noise_amp_from_SNR(SNR5, signal_amp=2), 0.002) + var1 = noise.get_noise_variance_from_SNR(SNR1, n=8, k=8) + var2 = noise.get_noise_variance_from_SNR(SNR2, n=8, k=8) + var3 = noise.get_noise_variance_from_SNR(SNR3, n=8, k=8) + var4 = noise.get_noise_variance_from_SNR(SNR4, n=8, k=8) + + self.assertEqual(var1, 1 * 0.5) + self.assertAlmostEqual(var2, 0.5 * 0.5, places=2) + self.assertEqual(var3, 0.01 * 0.5) + self.assertEqual(var4, 100 * 0.5) class CodesTestCase(unittest.TestCase): diff --git a/sw/utility/noise.py b/sw/utility/noise.py index 992b4e8..d11acb1 100644 --- a/sw/utility/noise.py +++ b/sw/utility/noise.py @@ -4,31 +4,32 @@ import numpy as np -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. +def get_noise_variance_from_SNR(SNR: float, n: int, k: int) -> float: + """Calculate the variance 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) + :param SNR: Signal-to-Noise-Ratio in dB (E_b/N_0) + :param n: Length of a codeword of the used code + :param k: Length of a dataword of the used code + :return: Variance of the noise """ + # noise_amp = (1 / np.sqrt(SNR_linear)) * signal_amp + SNR_linear = 10 ** (SNR / 10) - noise_amp = (1 / np.sqrt(SNR_linear)) * signal_amp + variance = 1 / (2 * (k/n) * SNR_linear) - # TODO: Fix noise amp calculation - # sigma**2 = 1 / (2 * (k/n) * (E_b/N_0)) - - return noise_amp + return variance -def add_awgn(c: np.array, SNR: float, signal_amp: float = 1) -> np.array: +def add_awgn(c: np.array, SNR: float, n: int, k: int) -> 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 - :param signal_amp: Amplitude of the signal. Used for the noise amplitude calculation + :param n: Length of a codeword of the used code + :param k: Length of a dataword of the used code :return: Data vector with added noise """ - noise_amp = get_noise_amp_from_SNR(SNR, signal_amp=signal_amp) - y = c + np.random.normal(scale=noise_amp, size=c.size) + noise_var = get_noise_variance_from_SNR(SNR, n, k) + y = c + np.sqrt(noise_var) * np.random.normal(size=c.size) return y diff --git a/sw/utility/simulations.py b/sw/utility/simulations.py index 419c404..aca6d84 100644 --- a/sw/utility/simulations.py +++ b/sw/utility/simulations.py @@ -52,14 +52,14 @@ def test_decoder(n: int, total_bits = 0 total_frame_errors = 0 - for n in tqdm(range(N_max), + for i in tqdm(range(N_max), desc=f"Simulating for SNR = {SNR} dB", position=2, leave=False, bar_format="{l_bar}{bar}| {n_fmt}/{total_fmt}"): # Simulate channel - y = noise.add_awgn(x_bpsk, SNR, signal_amp=np.sqrt(2)) + y = noise.add_awgn(x_bpsk, SNR, n, k) # Decode received frame x_hat = decoder.decode(y)