Skip to content
Snippets Groups Projects
signal_generator_input.py 9.01 KiB
Newer Older
  • Learn to ignore specific revisions
  • # -*- coding: utf-8 -*-
    
    from qtpy.QtWidgets import (
        QFileDialog,
        QGridLayout,
        QLabel,
        QLineEdit,
        QPushButton,
        QSpinBox,
    )
    
    
    from b_asic.signal_generator import (
        Constant,
    
        FromFile,
    
        Gaussian,
        Impulse,
        SignalGenerator,
        Sinusoid,
        Step,
        Uniform,
        ZeroPad,
    )
    
    
    class SignalGeneratorInput(QGridLayout):
        """Abstract class for graphically configuring and generating signal generators."""
    
        def __init__(self, logger, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self._logger = logger
    
        def get_generator(self) -> SignalGenerator:
            """Return the SignalGenerator based on the graphical input."""
            raise NotImplementedError
    
    
    class DelayInput(SignalGeneratorInput):
        """
        Abstract class for graphically configuring and generating signal generators that
        have a single delay parameter.
        """
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.delay_label = QLabel("Delay")
            self.addWidget(self.delay_label, 0, 0)
            self.delay_spin_box = QSpinBox()
            self.delay_spin_box.setRange(0, 2147483647)
            self.addWidget(self.delay_spin_box, 0, 1)
    
        def get_generator(self) -> SignalGenerator:
            raise NotImplementedError
    
    
    class ImpulseInput(DelayInput):
        """
        Class for graphically configuring and generating a
        :class:`~b_asic.signal_generators.Impulse` signal generator.
        """
    
        def get_generator(self) -> SignalGenerator:
            return Impulse(self.delay_spin_box.value())
    
    
    class StepInput(DelayInput):
        """
        Class for graphically configuring and generating a
        :class:`~b_asic.signal_generators.Step` signal generator.
        """
    
        def get_generator(self) -> SignalGenerator:
            return Step(self.delay_spin_box.value())
    
    
    class ZeroPadInput(SignalGeneratorInput):
        """
        Class for graphically configuring and generating a
        :class:`~b_asic.signal_generators.ZeroPad` signal generator.
        """
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.input_label = QLabel("Input")
            self.addWidget(self.input_label, 0, 0)
            self.input_sequence = QLineEdit()
            self.addWidget(self.input_sequence, 0, 1)
    
        def get_generator(self) -> SignalGenerator:
            input_values = []
            for val in self.input_sequence.text().split(","):
                val = val.strip()
                try:
                    if not val:
                        val = 0
    
                    val = complex(val)
                except ValueError:
                    self._logger.warning(f"Skipping value: {val}, not a digit.")
                    continue
    
                input_values.append(val)
    
            return ZeroPad(input_values)
    
    
    
    class FromFileInput(SignalGeneratorInput):
        """
        Class for graphically configuring and generating a
        :class:`~b_asic.signal_generators.FromFile` signal generator.
        """
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.file_label = QLabel("Browse")
            self.addWidget(self.file_label, 0, 0)
            self.file_browser = QPushButton("No file selected")
            self.file_browser.clicked.connect(
                lambda i: self.get_input_file(i, self.file_browser)
            )
            self.addWidget(self.file_browser, 0, 1)
    
        def get_generator(self) -> SignalGenerator:
            return FromFile(self.file_browser.text())
    
        def get_input_file(self, i, file_browser):
            module, accepted = QFileDialog().getOpenFileName()
            file_browser.setText(module)
            return
    
    
    
    class SinusoidInput(SignalGeneratorInput):
        """
        Class for graphically configuring and generating a
        :class:`~b_asic.signal_generators.Sinusoid` signal generator.
        """
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.frequency_label = QLabel("Frequency")
            self.addWidget(self.frequency_label, 0, 0)
            self.frequency_input = QLineEdit()
            self.addWidget(self.frequency_input, 0, 1)
    
            self.phase_label = QLabel("Phase")
            self.addWidget(self.phase_label, 1, 0)
            self.phase_input = QLineEdit()
            self.addWidget(self.phase_input, 1, 1)
    
        def get_generator(self) -> SignalGenerator:
            frequency = self.frequency_input.text().strip()
            try:
                if not frequency:
                    frequency = 0.1
    
                frequency = float(frequency)
            except ValueError:
                self._logger.warning(f"Cannot parse frequency: {frequency} not a number.")
                frequency = 0.1
    
            phase = self.phase_input.text().strip()
            try:
                if not phase:
                    phase = 0
    
                phase = float(phase)
            except ValueError:
                self._logger.warning(f"Cannot parse phase: {phase} not a number.")
                phase = 0
    
            return Sinusoid(frequency, phase)
    
    
    class GaussianInput(SignalGeneratorInput):
        """
        Class for graphically configuring and generating a
        :class:`~b_asic.signal_generators.Gaussian` signal generator.
        """
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.scale_label = QLabel("Standard deviation")
            self.addWidget(self.scale_label, 0, 0)
            self.scale_input = QLineEdit()
            self.scale_input.setText("1.0")
            self.addWidget(self.scale_input, 0, 1)
    
            self.loc_label = QLabel("Average value")
            self.addWidget(self.loc_label, 1, 0)
            self.loc_input = QLineEdit()
            self.loc_input.setText("0.0")
            self.addWidget(self.loc_input, 1, 1)
    
            self.seed_label = QLabel("Seed")
            self.addWidget(self.seed_label, 2, 0)
            self.seed_spin_box = QSpinBox()
            self.seed_spin_box.setRange(0, 2147483647)
            self.addWidget(self.seed_spin_box, 2, 1)
    
        def get_generator(self) -> SignalGenerator:
            scale = self.scale_input.text().strip()
            try:
                if not scale:
                    scale = 1
    
                scale = float(scale)
            except ValueError:
                self._logger.warning(f"Cannot parse scale: {scale} not a number.")
                scale = 1
    
            loc = self.loc_input.text().strip()
            try:
                if not loc:
                    loc = 0
    
                loc = float(loc)
            except ValueError:
                self._logger.warning(f"Cannot parse loc: {loc} not a number.")
                loc = 0
    
            return Gaussian(self.seed_spin_box.value(), loc, scale)
    
    
    class UniformInput(SignalGeneratorInput):
        """
        Class for graphically configuring and generating a
        :class:`~b_asic.signal_generators.Uniform` signal generator.
        """
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.low_label = QLabel("Lower bound")
            self.addWidget(self.low_label, 0, 0)
            self.low_input = QLineEdit()
            self.low_input.setText("-1.0")
            self.addWidget(self.low_input, 0, 1)
    
            self.high_label = QLabel("Upper bound")
            self.addWidget(self.high_label, 1, 0)
            self.high_input = QLineEdit()
            self.high_input.setText("1.0")
            self.addWidget(self.high_input, 1, 1)
    
            self.seed_label = QLabel("Seed")
            self.addWidget(self.seed_label, 2, 0)
            self.seed_spin_box = QSpinBox()
            self.seed_spin_box.setRange(0, 2147483647)
            self.addWidget(self.seed_spin_box, 2, 1)
    
        def get_generator(self) -> SignalGenerator:
            low = self.low_input.text().strip()
            try:
                if not low:
                    low = -1.0
    
                low = float(low)
            except ValueError:
                self._logger.warning(f"Cannot parse low: {low} not a number.")
                low = -1.0
    
            high = self.high_input.text().strip()
            try:
                if not high:
                    high = 1.0
    
                high = float(high)
            except ValueError:
                self._logger.warning(f"Cannot parse high: {high} not a number.")
                high = 1.0
    
            return Uniform(self.seed_spin_box.value(), low, high)
    
    
    class ConstantInput(SignalGeneratorInput):
        """
        Class for graphically configuring and generating a
        :class:`~b_asic.signal_generators.Constant` signal generator.
        """
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.constant_label = QLabel("Constant")
            self.addWidget(self.constant_label, 0, 0)
            self.constant_input = QLineEdit()
            self.constant_input.setText("1.0")
            self.addWidget(self.constant_input, 0, 1)
    
        def get_generator(self) -> SignalGenerator:
            constant = self.constant_input.text().strip()
            try:
                if not constant:
                    constant = 1.0
    
                constant = complex(constant)
            except ValueError:
                self._logger.warning(f"Cannot parse constant: {constant} not a number.")
                constant = 0.0
    
            return Constant(constant)
    
    
    _GENERATOR_MAPPING = {
        "Constant": ConstantInput,
        "Gaussian": GaussianInput,
        "Impulse": ImpulseInput,
        "Sinusoid": SinusoidInput,
        "Step": StepInput,
        "Uniform": UniformInput,
        "ZeroPad": ZeroPadInput,
    
        "FromFile": FromFileInput,