Change to quackseq structure.

This commit is contained in:
jupfi 2024-05-29 16:03:34 +02:00
parent eb00db8f23
commit 5d5e22d333
5 changed files with 93 additions and 85 deletions

View file

@ -24,6 +24,7 @@ dependencies = [
"matplotlib", "matplotlib",
"pyqt6", "pyqt6",
"nqrduck-spectrometer", "nqrduck-spectrometer",
"quackseq",
] ]
[project.entry-points."nqrduck"] [project.entry-points."nqrduck"]

View file

@ -6,7 +6,7 @@ import decimal
from PyQt6.QtCore import pyqtSlot from PyQt6.QtCore import pyqtSlot
from nqrduck.helpers.serializer import DecimalEncoder from nqrduck.helpers.serializer import DecimalEncoder
from nqrduck.module.module_controller import ModuleController from nqrduck.module.module_controller import ModuleController
from nqrduck_spectrometer.pulsesequence import PulseSequence from quackseq.pulsesequence import PulseSequence
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -17,14 +17,9 @@ class PulseProgrammerController(ModuleController):
This class is responsible for handling the logic of the pulse programmer module. This class is responsible for handling the logic of the pulse programmer module.
""" """
def on_loading(self, pulse_parameter_options: dict) -> None: def on_loading(self) -> None:
"""This method is called when the module is loaded. It sets the pulse parameter options in the model. """This method is called when the module is loaded. It sets the pulse parameter options in the model."""
Args:
pulse_parameter_options (dict): The pulse parameter options.
"""
logger.debug("Pulse programmer controller on loading") logger.debug("Pulse programmer controller on loading")
self.module.model.pulse_parameter_options = pulse_parameter_options
@pyqtSlot(str) @pyqtSlot(str)
def delete_event(self, event_name: str) -> None: def delete_event(self, event_name: str) -> None:

View file

@ -1,10 +1,10 @@
"""Model for the pulse programmer module.""" """Model for the pulse programmer module."""
import logging import logging
from collections import OrderedDict
from PyQt6.QtCore import pyqtSignal from PyQt6.QtCore import pyqtSignal
from nqrduck.module.module_model import ModuleModel from nqrduck.module.module_model import ModuleModel
from nqrduck_spectrometer.pulsesequence import PulseSequence from quackseq.pulsesequence import QuackSequence
from quackseq.event import Event
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -25,7 +25,6 @@ class PulseProgrammerModel(ModuleModel):
FILE_EXTENSION = "quack" FILE_EXTENSION = "quack"
pulse_parameter_options_changed = pyqtSignal()
events_changed = pyqtSignal() events_changed = pyqtSignal()
pulse_sequence_changed = pyqtSignal() pulse_sequence_changed = pyqtSignal()
@ -36,8 +35,7 @@ class PulseProgrammerModel(ModuleModel):
module (Module): The module to which this model belongs. module (Module): The module to which this model belongs.
""" """
super().__init__(module) super().__init__(module)
self.pulse_parameter_options = OrderedDict() self.pulse_sequence = QuackSequence("Untitled pulse sequence")
self.pulse_sequence = PulseSequence("Untitled pulse sequence")
def add_event(self, event_name: str, duration: float = 20): def add_event(self, event_name: str, duration: float = 20):
"""Add a new event to the current pulse sequence. """Add a new event to the current pulse sequence.
@ -46,40 +44,14 @@ class PulseProgrammerModel(ModuleModel):
event_name (str): A human-readable name for the event event_name (str): A human-readable name for the event
duration (float): The duration of the event in µs. Defaults to 20. duration (float): The duration of the event in µs. Defaults to 20.
""" """
self.pulse_sequence.add_event(event_name, duration) logger.debug(f"Adding event {event_name} with duration {duration}")
logger.debug( event = Event(event_name, f"{duration}u", self.pulse_sequence)
"Creating event %s with object id %s", self.pulse_sequence.add_event(event)
event_name,
id(self.pulse_sequence.events[-1]),
)
# Create a default instance of the pulse parameter options and add it to the event
for name, pulse_parameter_class in self.pulse_parameter_options.items():
logger.debug("Adding pulse parameter %s to event %s", name, event_name)
self.pulse_sequence.events[-1].parameters[name] = pulse_parameter_class(
name
)
logger.debug(
"Created pulse parameter %s with object id %s",
name,
id(self.pulse_sequence.events[-1].parameters[name]),
)
logger.debug(self.pulse_sequence.to_json()) logger.debug(self.pulse_sequence.to_json())
self.events_changed.emit() self.events_changed.emit()
@property
def pulse_parameter_options(self):
"""dict: The pulse parameter options."""
return self._pulse_parameter_options
@pulse_parameter_options.setter
def pulse_parameter_options(self, value):
self._pulse_parameter_options = value
logger.debug("Pulse parameter options changed - emitting signal")
self.pulse_parameter_options_changed.emit()
@property @property
def pulse_sequence(self): def pulse_sequence(self):
"""PulseSequence: The pulse sequence.""" """PulseSequence: The pulse sequence."""

View file

@ -21,7 +21,8 @@ from PyQt6.QtCore import pyqtSlot, pyqtSignal
from nqrduck.module.module_view import ModuleView from nqrduck.module.module_view import ModuleView
from nqrduck.assets.icons import Logos from nqrduck.assets.icons import Logos
from nqrduck.helpers.duckwidgets import DuckFloatEdit, DuckEdit from nqrduck.helpers.duckwidgets import DuckFloatEdit, DuckEdit
from nqrduck_spectrometer.pulseparameters import (
from quackseq.pulseparameters import (
BooleanOption, BooleanOption,
NumericOption, NumericOption,
FunctionOption, FunctionOption,
@ -33,6 +34,8 @@ from nqrduck.helpers.formbuilder import (
DuckFormFloatField, DuckFormFloatField,
) )
from .visual_parameter import VisualParameter
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -51,13 +54,6 @@ class PulseProgrammerView(ModuleView):
self.setup_variabletables() self.setup_variabletables()
logger.debug(
"Connecting pulse parameter options changed signal to on_pulse_parameter_options_changed"
)
self.module.model.pulse_parameter_options_changed.connect(
self.on_pulse_parameter_options_changed
)
def setup_variabletables(self) -> None: def setup_variabletables(self) -> None:
"""Setup the table for the variables.""" """Setup the table for the variables."""
pass pass
@ -138,20 +134,6 @@ class PulseProgrammerView(ModuleView):
) )
self.title.setText(f"Pulse Sequence: {self.module.model.pulse_sequence.name}") self.title.setText(f"Pulse Sequence: {self.module.model.pulse_sequence.name}")
@pyqtSlot()
def on_pulse_parameter_options_changed(self) -> None:
"""This method is called whenever the pulse parameter options change. It updates the view to reflect the changes."""
logger.debug(
"Updating pulse parameter options to %s",
self.module.model.pulse_parameter_options.keys(),
)
# We set it to the length of the pulse parameter options + 1 because we want to add a row for the parameter option buttons
self.pulse_table.setRowCount(len(self.module.model.pulse_parameter_options) + 1)
# Move the vertical header labels on row down
pulse_options = [""]
pulse_options.extend(list(self.module.model.pulse_parameter_options.keys()))
self.pulse_table.setVerticalHeaderLabels(pulse_options)
@pyqtSlot() @pyqtSlot()
def on_new_event_button_clicked(self) -> None: def on_new_event_button_clicked(self) -> None:
"""This method is called whenever the new event button is clicked. It creates a new event and adds it to the pulse sequence.""" """This method is called whenever the new event button is clicked. It creates a new event and adds it to the pulse sequence."""
@ -170,6 +152,22 @@ class PulseProgrammerView(ModuleView):
@pyqtSlot() @pyqtSlot()
def on_events_changed(self) -> None: def on_events_changed(self) -> None:
"""This method is called whenever the events in the pulse sequence change. It updates the view to reflect the changes.""" """This method is called whenever the events in the pulse sequence change. It updates the view to reflect the changes."""
pulse_parameter_options = (
self.module.model.pulse_sequence.pulse_parameter_options
)
logger.debug(
"Updating pulse parameter options to %s",
pulse_parameter_options.keys(),
)
# We set it to the length of the pulse parameter options + 1 because we want to add a row for the parameter option buttons
self.pulse_table.setRowCount(len(pulse_parameter_options) + 1)
# Move the vertical header labels on row down
pulse_options = [""]
pulse_options.extend(list(pulse_parameter_options.keys()))
self.pulse_table.setVerticalHeaderLabels(pulse_options)
logger.debug("Updating events to %s", self.module.model.pulse_sequence.events) logger.debug("Updating events to %s", self.module.model.pulse_sequence.events)
# Add label for the event lengths # Add label for the event lengths
@ -198,10 +196,12 @@ class PulseProgrammerView(ModuleView):
def set_parameter_icons(self) -> None: def set_parameter_icons(self) -> None:
"""This method sets the icons for the pulse parameter options.""" """This method sets the icons for the pulse parameter options."""
pulse_parrameter_options = (
self.module.model.pulse_sequence.pulse_parameter_options
)
for column_idx, event in enumerate(self.module.model.pulse_sequence.events): for column_idx, event in enumerate(self.module.model.pulse_sequence.events):
for row_idx, parameter in enumerate( for row_idx, parameter in enumerate(pulse_parrameter_options.keys()):
self.module.model.pulse_parameter_options.keys()
):
if row_idx == 0: if row_idx == 0:
event_options_widget = EventOptionsWidget(event) event_options_widget = EventOptionsWidget(event)
# Connect the delete_event signal to the on_delete_event slot # Connect the delete_event signal to the on_delete_event slot
@ -238,7 +238,8 @@ class PulseProgrammerView(ModuleView):
) )
logger.debug("Parameter object id: %s", id(event.parameters[parameter])) logger.debug("Parameter object id: %s", id(event.parameters[parameter]))
button = QPushButton() button = QPushButton()
icon = event.parameters[parameter].get_pixmap()
icon = VisualParameter(event.parameters[parameter]).get_pixmap()
logger.debug("Icon size: %s", icon.availableSizes()) logger.debug("Icon size: %s", icon.availableSizes())
button.setIcon(icon) button.setIcon(icon)
button.setIconSize(icon.availableSizes()[0]) button.setIconSize(icon.availableSizes()[0])
@ -290,11 +291,8 @@ class PulseProgrammerView(ModuleView):
else: else:
slider = False slider = False
if not slider: if slider:
assert not option.slider, "Setting a slider is not possible without min and max values" slider = option.slider
slider = option.slider
numeric_field = DuckFormFloatField( numeric_field = DuckFormFloatField(
option.name, option.name,
@ -452,7 +450,7 @@ class EventOptionsWidget(QWidget):
dialog = QDialog(self) dialog = QDialog(self)
dialog.setWindowTitle("Edit event") dialog.setWindowTitle("Edit event")
layout = QVBoxLayout() layout = QVBoxLayout()
label = QLabel(f"Edit event {self.event.name}") label = QLabel(f"Edit event: {self.event.name}")
layout.addWidget(label) layout.addWidget(label)
# Create the inputs for event name, duration # Create the inputs for event name, duration
@ -460,15 +458,13 @@ class EventOptionsWidget(QWidget):
name_label = QLabel("Name:") name_label = QLabel("Name:")
name_lineedit = QLineEdit(self.event.name) name_lineedit = QLineEdit(self.event.name)
event_form_layout.addRow(name_label, name_lineedit) event_form_layout.addRow(name_label, name_lineedit)
duration_layout = QHBoxLayout()
duration_label = QLabel("Duration:") duration_label = QLabel("Duration (µs):")
duration_lineedit = QLineEdit() duration_lineedit = QLineEdit()
unit_label = QLabel("µs")
duration_lineedit.setText("%.16g" % (self.event.duration * 1e6)) duration_lineedit.setText("%.16g" % (self.event.duration * 1e6))
duration_layout.addWidget(duration_label)
duration_layout.addWidget(duration_lineedit) event_form_layout.addRow(duration_label, duration_lineedit)
duration_layout.addWidget(unit_label)
event_form_layout.addRow(duration_layout)
layout.addLayout(event_form_layout) layout.addLayout(event_form_layout)
buttons = QDialogButtonBox( buttons = QDialogButtonBox(
@ -543,22 +539,21 @@ class AddEventDialog(QDialog):
self.name_input.validator = self.NameInputValidator(self) self.name_input.validator = self.NameInputValidator(self)
self.name_layout.addWidget(self.label) self.name_layout.addWidget(self.label)
self.name_layout.addStretch(1)
self.name_layout.addWidget(self.name_input) self.name_layout.addWidget(self.name_input)
self.layout.addRow(self.name_layout) self.layout.addRow(self.name_layout)
self.duration_layout = QHBoxLayout() self.duration_layout = QHBoxLayout()
self.duration_label = QLabel("Duration:") self.duration_label = QLabel("Duration (µs):")
self.duration_lineedit = DuckFloatEdit(min_value=0) self.duration_lineedit = DuckFloatEdit(min_value=0)
self.duration_lineedit.setText("20") self.duration_lineedit.setText("20")
self.unit_label = QLabel("µs")
self.duration_layout.addWidget(self.duration_label) self.duration_layout.addWidget(self.duration_label)
self.duration_layout.addStretch(1)
self.duration_layout.addWidget(self.duration_lineedit) self.duration_layout.addWidget(self.duration_lineedit)
self.duration_layout.addWidget(self.unit_label)
self.layout.addRow(self.duration_layout) self.layout.addRow(self.duration_layout)
self.buttons = QDialogButtonBox( self.buttons = QDialogButtonBox(

View file

@ -0,0 +1,45 @@
from nqrduck.assets.icons import PulseParamters
from quackseq.pulseparameters import TXPulse, RXReadout, PulseParameter
from quackseq.functions import Function, RectFunction, SincFunction, GaussianFunction, CustomFunction
class VisualParameter():
def __init__(self, pulse_parameter : PulseParameter):
self.pulse_parameter = pulse_parameter
def get_pixmap(self):
"""Returns the pixmap of the TX Pulse Parameter.
Returns:
QPixmap: The pixmap of the TX Pulse Parameter depending on the relative amplitude.
"""
# Check the instance of the pulse parameter
if isinstance(self.pulse_parameter, TXPulse):
amplitude = self.pulse_parameter.get_option_by_name(TXPulse.RELATIVE_AMPLITUDE).value
if amplitude > 0:
# Get the shape
shape = self.pulse_parameter.get_option_by_name(TXPulse.TX_PULSE_SHAPE).value
if isinstance(shape, RectFunction):
pixmap = PulseParamters.TXRect()
return pixmap
elif isinstance(shape, SincFunction):
pixmap = PulseParamters.TXSinc()
return pixmap
elif isinstance(shape, GaussianFunction):
pixmap = PulseParamters.TXGauss()
return pixmap
else:
pixmap = PulseParamters.TXCustom()
return pixmap
else:
pixmap = PulseParamters.TXOff()
return pixmap
elif isinstance(self.pulse_parameter, RXReadout):
rx = self.pulse_parameter.get_option_by_name(RXReadout.RX).value
if rx:
pixmap = PulseParamters.RXOn()
return pixmap
else:
pixmap = PulseParamters.RXOff()
return pixmap