From c2a9e42b295dab2e8959a14abebe6b5298099c21 Mon Sep 17 00:00:00 2001 From: Oscar Gustafsson <oscar.gustafsson@gmail.com> Date: Fri, 3 Feb 2023 22:49:50 +0100 Subject: [PATCH] Add initial support for signal generators --- b_asic/signal_generator.py | 139 +++++++++++++++++++++++++++ docs_sphinx/api/index.rst | 1 + docs_sphinx/api/signal_generator.rst | 6 ++ test/test_signal_generator.py | 84 ++++++++++++++++ 4 files changed, 230 insertions(+) create mode 100644 b_asic/signal_generator.py create mode 100644 docs_sphinx/api/signal_generator.rst create mode 100644 test/test_signal_generator.py diff --git a/b_asic/signal_generator.py b/b_asic/signal_generator.py new file mode 100644 index 00000000..549c0efd --- /dev/null +++ b/b_asic/signal_generator.py @@ -0,0 +1,139 @@ +""" +B-ASIC signal generators + +These can be used as input to Simulation to algorithmically provide signal values. +""" + +from numbers import Number +from typing import Callable + + +class SignalGenerator: + def __call__(self, time: int) -> complex: + raise NotImplementedError + + def __add__(self, other) -> "AddGenerator": + if isinstance(other, Number): + return AddGenerator(self, Constant(other)) + return AddGenerator(self, other) + + def __radd__(self, other) -> "AddGenerator": + if isinstance(other, Number): + return AddGenerator(self, Constant(other)) + return AddGenerator(self, other) + + def __sub__(self, other) -> "SubGenerator": + if isinstance(other, Number): + return SubGenerator(self, Constant(other)) + return SubGenerator(self, other) + + def __rsub__(self, other) -> "SubGenerator": + if isinstance(other, Number): + return SubGenerator(Constant(other), self) + return SubGenerator(other, self) + + def __mul__(self, other) -> "MulGenerator": + if isinstance(other, Number): + return MultGenerator(self, Constant(other)) + return MultGenerator(self, other) + + def __rmul__(self, other) -> "MulGenerator": + if isinstance(other, Number): + return MultGenerator(self, Constant(other)) + return MultGenerator(self, other) + + +class Impulse(SignalGenerator): + """ + Signal generator that creates an impulse at a given delay. + + Parameters + ---------- + delay : int, default: 0 + The delay before the signal goes to 1 for one sample. + """ + + def __init__(self, delay: int = 0) -> Callable[[int], complex]: + self._delay = delay + + def __call__(self, time: int) -> complex: + return 1 if time == self._delay else 0 + + +class Step(SignalGenerator): + """ + Signal generator that creates a step at a given delay. + + Parameters + ---------- + delay : int, default: 0 + The delay before the signal goes to 1. + """ + + def __init__(self, delay: int = 0) -> Callable[[int], complex]: + self._delay = delay + + def __call__(self, time: int) -> complex: + return 1 if time >= self._delay else 0 + + +class Constant(SignalGenerator): + """ + Signal generator that outputs a constant value. + + Parameters + ---------- + constant : complex, default: 1.0 + The constant. + """ + + def __init__(self, constant: complex = 1.0) -> Callable[[int], complex]: + self._constant = constant + + def __call__(self, time: int) -> complex: + return self._constant + + +class AddGenerator: + """ + Signal generator that adds two signals. + """ + + def __init__( + self, a: SignalGenerator, b: SignalGenerator + ) -> Callable[[int], complex]: + self._a = a + self._b = b + + def __call__(self, time: int) -> complex: + return self._a(time) + self._b(time) + + +class SubGenerator: + """ + Signal generator that subtracts two signals. + """ + + def __init__( + self, a: SignalGenerator, b: SignalGenerator + ) -> Callable[[int], complex]: + self._a = a + self._b = b + + def __call__(self, time: int) -> complex: + return self._a(time) - self._b(time) + + +class MultGenerator: + """ + Signal generator that multiplies two signals. + """ + + def __init__( + self, a: SignalGenerator, b: SignalGenerator + ) -> Callable[[int], complex]: + self._a = a + self._b = b + + def __call__(self, time: int) -> complex: + return self._a(time) * self._b(time) diff --git a/docs_sphinx/api/index.rst b/docs_sphinx/api/index.rst index f6492835..a36b3efc 100644 --- a/docs_sphinx/api/index.rst +++ b/docs_sphinx/api/index.rst @@ -14,5 +14,6 @@ API sfg_generator.rst signal.rst signal_flow_graph.rst + signal_generator.rst simulation.rst special_operations.rst diff --git a/docs_sphinx/api/signal_generator.rst b/docs_sphinx/api/signal_generator.rst new file mode 100644 index 00000000..0ca472ce --- /dev/null +++ b/docs_sphinx/api/signal_generator.rst @@ -0,0 +1,6 @@ +*************************** +``b_asic.signal_generator`` +*************************** + +.. automodule:: b_asic.signal_generator + :members: diff --git a/test/test_signal_generator.py b/test/test_signal_generator.py new file mode 100644 index 00000000..ad07861e --- /dev/null +++ b/test/test_signal_generator.py @@ -0,0 +1,84 @@ +from b_asic.signal_generator import Constant, Impulse, Step + + +def test_impulse(): + g = Impulse() + assert g(0) == 1 + assert g(1) == 0 + assert g(2) == 0 + + g = Impulse(1) + assert g(0) == 0 + assert g(1) == 1 + assert g(2) == 0 + + +def test_step(): + g = Step() + assert g(0) == 1 + assert g(1) == 1 + assert g(2) == 1 + + g = Step(1) + assert g(0) == 0 + assert g(1) == 1 + assert g(2) == 1 + + +def test_constant(): + g = Constant() + assert g(0) == 1 + assert g(1) == 1 + assert g(2) == 1 + + g = Constant(0.5) + assert g(0) == 0.5 + assert g(1) == 0.5 + assert g(2) == 0.5 + + +def test_addition(): + g = Impulse() + Impulse(2) + assert g(0) == 1 + assert g(1) == 0 + assert g(2) == 1 + assert g(3) == 0 + + g = 1 + Impulse(2) + assert g(0) == 1 + assert g(1) == 1 + assert g(2) == 2 + assert g(3) == 1 + + g = Impulse(1) + 1 + assert g(0) == 1 + assert g(1) == 2 + assert g(2) == 1 + assert g(3) == 1 + + +def test_subtraction(): + g = Impulse() - Impulse(2) + assert g(0) == 1 + assert g(1) == 0 + assert g(2) == -1 + assert g(3) == 0 + + g = 1 - Impulse(2) + assert g(0) == 1 + assert g(1) == 1 + assert g(2) == 0 + assert g(3) == 1 + + g = Impulse(2) - 1 + assert g(0) == -1 + assert g(1) == -1 + assert g(2) == 0 + assert g(3) == -1 + + +def test_multiplication(): + g = Impulse() * 0.5 + assert g(0) == 0.5 + assert g(1) == 0 + assert g(2) == 0 -- GitLab