From 9996e607956bbd5142dcbc4f41225a8268b4ba26 Mon Sep 17 00:00:00 2001 From: Oscar Gustafsson <oscar.gustafsson@gmail.com> Date: Mon, 13 Feb 2023 11:44:30 +0100 Subject: [PATCH] Add random signal generators --- b_asic/signal_generator.py | 83 ++++++++++++++++++++++++++++++++++- test/test_signal_generator.py | 36 +++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/b_asic/signal_generator.py b/b_asic/signal_generator.py index 11c7097b..fce18c42 100644 --- a/b_asic/signal_generator.py +++ b/b_asic/signal_generator.py @@ -13,7 +13,9 @@ if you want more information. from math import pi, sin from numbers import Number -from typing import Sequence +from typing import Optional, Sequence + +import numpy as np class SignalGenerator: @@ -187,6 +189,85 @@ class Sinusoid(SignalGenerator): ) +class Gaussian(SignalGenerator): + """ + Signal generator with Gaussian noise. + + See :class:`numpy.random.Generator.normal` for further details. + + Parameters + ---------- + seed : int, optional + The seed of the random number generator. + scale : float, default: 1 + The standard deviation of the noise. + loc : float, default: 0 + The average value of the noise. + """ + + def __init__( + self, seed: Optional[int] = None, loc: float = 0.0, scale: float = 1.0 + ) -> None: + self._rng = np.random.default_rng(seed) + self._seed = seed + self._loc = loc + self._scale = scale + + def __call__(self, time: int) -> complex: + return self._rng.normal(self._loc, self._scale) + + def __repr__(self): + ret_list = [] + if self._seed is not None: + ret_list.append(f"seed={self._seed}") + if self._loc: + ret_list.append(f"loc={self._loc}") + if self._scale != 1.0: + ret_list.append(f"scale={self._scale}") + args = ", ".join(ret_list) + return f"Gaussian({args})" + + +class Uniform(SignalGenerator): + """ + Signal generator with uniform noise. + + See :class:`numpy.random.Generator.normal` for further details. + + + Parameters + ---------- + seed : int, optional + The seed of the random number generator. + low : float, default: -1 + The lower value of the uniform range. + high : float, default: 1 + The upper value of the uniform range. + """ + + def __init__( + self, seed: Optional[int] = None, low: float = -1.0, high: float = 1.0 + ) -> None: + self._rng = np.random.default_rng(seed) + self._seed = seed + self._low = low + self._high = high + + def __call__(self, time: int) -> complex: + return self._rng.uniform(self._low, self._high) + + def __repr__(self): + ret_list = [] + if self._seed is not None: + ret_list.append(f"seed={self._seed}") + if self._low != -1.0: + ret_list.append(f"low={self._low}") + if self._high != 1.0: + ret_list.append(f"high={self._high}") + args = ", ".join(ret_list) + return f"Uniform({args})" + + class _AddGenerator(SignalGenerator): """ Signal generator that adds two signals. diff --git a/test/test_signal_generator.py b/test/test_signal_generator.py index e11423bd..97093a52 100644 --- a/test/test_signal_generator.py +++ b/test/test_signal_generator.py @@ -4,9 +4,11 @@ import pytest from b_asic.signal_generator import ( Constant, + Gaussian, Impulse, Sinusoid, Step, + Uniform, ZeroPad, _AddGenerator, _DivGenerator, @@ -97,6 +99,40 @@ def test_sinusoid(): assert str(g) == "Sinusoid(0.5, 0.25)" +def test_gaussian(): + g = Gaussian(1234) + assert g(0) == pytest.approx(-1.6038368053963015) + assert g(1) == pytest.approx(0.06409991400376411) + + assert str(g) == "Gaussian(seed=1234)" + + # Check same seed gives same sequence + g1 = Gaussian(12345) + g2 = Gaussian(12345) + + for n in range(100): + assert g1(n) == g2(n) + + assert str(Gaussian(1234, 1, 2)) == "Gaussian(seed=1234, loc=1, scale=2)" + + +def test_uniform(): + g = Uniform(1234) + assert g(0) == pytest.approx(0.9533995333962844) + assert g(1) == pytest.approx(-0.23960852996076443) + + assert str(g) == "Uniform(seed=1234)" + + # Check same seed gives same sequence + g1 = Uniform(12345) + g2 = Uniform(12345) + + for n in range(100): + assert g1(n) == g2(n) + + assert str(Uniform(1234, 1, 2)) == "Uniform(seed=1234, low=1, high=2)" + + def test_addition(): g = Impulse() + Impulse(2) assert g(-1) == 0 -- GitLab