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",
"pyqt6",
"nqrduck-spectrometer",
"quackseq",
]
[project.entry-points."nqrduck"]

View file

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

View file

@ -1,10 +1,10 @@
"""Model for the pulse programmer module."""
import logging
from collections import OrderedDict
from PyQt6.QtCore import pyqtSignal
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__)
@ -25,7 +25,6 @@ class PulseProgrammerModel(ModuleModel):
FILE_EXTENSION = "quack"
pulse_parameter_options_changed = pyqtSignal()
events_changed = pyqtSignal()
pulse_sequence_changed = pyqtSignal()
@ -36,8 +35,7 @@ class PulseProgrammerModel(ModuleModel):
module (Module): The module to which this model belongs.
"""
super().__init__(module)
self.pulse_parameter_options = OrderedDict()
self.pulse_sequence = PulseSequence("Untitled pulse sequence")
self.pulse_sequence = QuackSequence("Untitled pulse sequence")
def add_event(self, event_name: str, duration: float = 20):
"""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
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(
"Creating event %s with object id %s",
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]),
)
event = Event(event_name, f"{duration}u", self.pulse_sequence)
self.pulse_sequence.add_event(event)
logger.debug(self.pulse_sequence.to_json())
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
def pulse_sequence(self):
"""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.assets.icons import Logos
from nqrduck.helpers.duckwidgets import DuckFloatEdit, DuckEdit
from nqrduck_spectrometer.pulseparameters import (
from quackseq.pulseparameters import (
BooleanOption,
NumericOption,
FunctionOption,
@ -33,6 +34,8 @@ from nqrduck.helpers.formbuilder import (
DuckFormFloatField,
)
from .visual_parameter import VisualParameter
logger = logging.getLogger(__name__)
@ -51,13 +54,6 @@ class PulseProgrammerView(ModuleView):
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:
"""Setup the table for the variables."""
pass
@ -138,20 +134,6 @@ class PulseProgrammerView(ModuleView):
)
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()
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."""
@ -170,6 +152,22 @@ class PulseProgrammerView(ModuleView):
@pyqtSlot()
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."""
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)
# Add label for the event lengths
@ -198,10 +196,12 @@ class PulseProgrammerView(ModuleView):
def set_parameter_icons(self) -> None:
"""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 row_idx, parameter in enumerate(
self.module.model.pulse_parameter_options.keys()
):
for row_idx, parameter in enumerate(pulse_parrameter_options.keys()):
if row_idx == 0:
event_options_widget = EventOptionsWidget(event)
# 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]))
button = QPushButton()
icon = event.parameters[parameter].get_pixmap()
icon = VisualParameter(event.parameters[parameter]).get_pixmap()
logger.debug("Icon size: %s", icon.availableSizes())
button.setIcon(icon)
button.setIconSize(icon.availableSizes()[0])
@ -290,11 +291,8 @@ class PulseProgrammerView(ModuleView):
else:
slider = False
if not slider:
assert not option.slider, "Setting a slider is not possible without min and max values"
slider = option.slider
if slider:
slider = option.slider
numeric_field = DuckFormFloatField(
option.name,
@ -452,7 +450,7 @@ class EventOptionsWidget(QWidget):
dialog = QDialog(self)
dialog.setWindowTitle("Edit event")
layout = QVBoxLayout()
label = QLabel(f"Edit event {self.event.name}")
label = QLabel(f"Edit event: {self.event.name}")
layout.addWidget(label)
# Create the inputs for event name, duration
@ -460,15 +458,13 @@ class EventOptionsWidget(QWidget):
name_label = QLabel("Name:")
name_lineedit = QLineEdit(self.event.name)
event_form_layout.addRow(name_label, name_lineedit)
duration_layout = QHBoxLayout()
duration_label = QLabel("Duration:")
duration_label = QLabel("Duration (µs):")
duration_lineedit = QLineEdit()
unit_label = QLabel("µs")
duration_lineedit.setText("%.16g" % (self.event.duration * 1e6))
duration_layout.addWidget(duration_label)
duration_layout.addWidget(duration_lineedit)
duration_layout.addWidget(unit_label)
event_form_layout.addRow(duration_layout)
event_form_layout.addRow(duration_label, duration_lineedit)
layout.addLayout(event_form_layout)
buttons = QDialogButtonBox(
@ -543,22 +539,21 @@ class AddEventDialog(QDialog):
self.name_input.validator = self.NameInputValidator(self)
self.name_layout.addWidget(self.label)
self.name_layout.addStretch(1)
self.name_layout.addWidget(self.name_input)
self.layout.addRow(self.name_layout)
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.setText("20")
self.unit_label = QLabel("µs")
self.duration_layout.addWidget(self.duration_label)
self.duration_layout.addStretch(1)
self.duration_layout.addWidget(self.duration_lineedit)
self.duration_layout.addWidget(self.unit_label)
self.layout.addRow(self.duration_layout)
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