This commit is contained in:
jupfi 2024-06-01 20:39:21 +02:00
parent 6f7afada51
commit a8c5a93ae5
8 changed files with 121 additions and 49 deletions

View file

@ -0,0 +1 @@
"""The base module for the quackseq pulse programming library."""

View file

@ -1,3 +1,5 @@
"""Event class for the pulse sequence. Every pulse sequence consists of events, that are executed subsequently and have different parameters."""
import logging
from collections import OrderedDict
@ -21,7 +23,9 @@ class Event:
pulse_sequence (PulseSequence): The pulse sequence the event belongs to
"""
def __init__(self, name: str, duration: float | str, pulse_sequence : "PulseSequence") -> None:
def __init__(
self, name: str, duration: float | str, pulse_sequence: "PulseSequence"
) -> None:
"""Initializes the event."""
self.parameters = OrderedDict()
self.name = name
@ -36,9 +40,7 @@ class Event:
pulse_parameters = self.pulse_sequence.pulse_parameter_options
for name, pulse_parameter_class in pulse_parameters.items():
logger.debug("Adding pulse parameter %s to event %s", name, self.name)
self.parameters[name] = pulse_parameter_class(
name
)
self.parameters[name] = pulse_parameter_class(name)
logger.debug(
"Created pulse parameter %s with object id %s",
name,

View file

@ -1,8 +1,11 @@
"""Options for the pulse parameters. Options can be of different types, for example boolean, numeric or function. Generally pulse parameters have different values for the different events in a pulse sequence."""
import logging
from quackseq.functions import Function
logger = logging.getLogger(__name__)
class Option:
"""Defines options for the pulse parameters which can then be set accordingly.
@ -102,6 +105,7 @@ class NumericOption(Option):
is_float (bool): If the value is a float.
min_value: The minimum value of the option.
max_value: The maximum value of the option.
slider (bool): If the option should be displayed as a slider. This is not used for the pulseq module, but visualizations can use this information.
"""
super().__init__(name, value)
self.is_float = is_float

View file

@ -62,7 +62,9 @@ class PulseSequence:
event (Event): The event to add
"""
if event.name in self.get_event_names():
raise ValueError(f"Event with name {event.name} already exists in the pulse sequence")
raise ValueError(
f"Event with name {event.name} already exists in the pulse sequence"
)
self.events.append(event)
@ -78,7 +80,9 @@ class PulseSequence:
"""
event = Event(event_name, duration, self)
if event.name in self.get_event_names():
raise ValueError(f"Event with name {event.name} already exists in the pulse sequence")
raise ValueError(
f"Event with name {event.name} already exists in the pulse sequence"
)
self.events.append(event)
return event
@ -224,7 +228,13 @@ class QuackSequence(PulseSequence):
self.add_pulse_parameter_option(self.RX_READOUT, RXReadout)
def add_blank_event(self, event_name: str, duration: float):
event = self.create_event(event_name, duration)
"""Adds a blank event to the pulse sequence.
Args:
event_name (str): The name of the event
duration (float): The duration of the event with a unit suffix (n, u, m)
"""
_ = self.create_event(event_name, duration)
def add_pulse_event(
self,
@ -234,24 +244,44 @@ class QuackSequence(PulseSequence):
phase: float,
shape: Function = RectFunction(),
):
"""Adds a pulse event to the pulse sequence.
Args:
event_name (str): The name of the event
duration (float): The duration of the event with a unit suffix (n, u, m)
amplitude (float): The amplitude of the transmit pulse in percent
phase (float): The phase of the transmit pulse
shape (Function): The shape of the transmit pulse
"""
event = self.create_event(event_name, duration)
self.set_tx_amplitude(event, amplitude)
self.set_tx_phase(event, phase)
self.set_tx_shape(event, shape)
def add_readout_event(self, event_name: str, duration: float):
"""Adds a readout event to the pulse sequence.
Args:
event_name (str): The name of the event
duration (float): The duration of the event with a unit suffix (n, u, m)
"""
event = self.create_event(event_name, duration)
self.set_rx(event, True)
# TX Specific functions
def set_tx_amplitude(self, event, amplitude: float) -> None:
"""Sets the amplitude of the transmitter.
"""Sets the relative amplitude of the transmit pulse in percent (larger 0 - max 100).
Args:
event (Event): The event to set the amplitude for
amplitude (float): The amplitude of the transmitter
amplitude (float): The amplitude of the transmit pulse in percent
"""
if amplitude <= 0 or amplitude > 100:
raise ValueError(
"Amplitude needs to be larger than 0 and smaller or equal to 100"
)
event.parameters[self.TX_PULSE].get_option_by_name(
TXPulse.RELATIVE_AMPLITUDE
).value = amplitude
@ -268,11 +298,11 @@ class QuackSequence(PulseSequence):
).value = phase
def set_tx_shape(self, event, shape: Function) -> None:
"""Sets the shape of the transmitter.
"""Sets the shape of the transmit pulse.
Args:
event (Event): The event to set the shape for
shape (Any): The shape of the transmitter
shape (Function): The shape of the transmit pulse
"""
event.parameters[self.TX_PULSE].get_option_by_name(
TXPulse.TX_PULSE_SHAPE

View file

@ -1,7 +1,7 @@
from typing import Any
"""The base class for the spectrometer used in quackseq. This class is just a skeleton and should be inherited by all spectrometer implementations."""
class Spectrometer():
class Spectrometer:
"""Base class for spectrometers.
This class should be inherited by all spectrometers.
@ -15,11 +15,10 @@ class Spectrometer():
"""
raise NotImplementedError
def set_frequency(self, value : float):
def set_frequency(self, value: float):
"""Sets the frequency of the spectrometer."""
raise NotImplementedError
def set_averages(self, value : int):
def set_averages(self, value: int):
"""Sets the number of averages."""
raise NotImplementedError

View file

@ -7,7 +7,8 @@ from quackseq.pulsesequence import QuackSequence
logger = logging.getLogger(__name__)
class SpectrometerController():
class SpectrometerController:
"""The base class for all spectrometer controllers."""
def run_sequence(self, sequence):
@ -17,11 +18,11 @@ class SpectrometerController():
"""
raise NotImplementedError
def set_frequency(self, value : float):
def set_frequency(self, value: float):
"""Sets the frequency of the spectrometer."""
raise NotImplementedError
def set_averages(self, value : int):
def set_averages(self, value: int):
"""Sets the number of averages."""
raise NotImplementedError

View file

@ -2,29 +2,54 @@
import logging
from collections import OrderedDict
from typing import Any
from quackseq.spectrometer.spectrometer_settings import Setting
logger = logging.getLogger(__name__)
class QuackSettings(OrderedDict):
"""The Quack settings class makes the different settings of the spectrometer accessible as attributes. Additionally, it provides methods to get the settings by category."""
def __getattr__(self, key):
"""Gets the value of a setting by its key.
Args:
key (str) : The key of the setting
Returns:
The value of the setting
"""
return self[key].value
def __setattr__(self, key, value):
"""Sets the value of a setting by its key.
Args:
key (str) : The key of the setting
value : The value to set
"""
self[key].value = value
@property
def categories(self):
"""The categories of the settings."""
categories = []
for setting in self.values():
if not setting.category in categories:
if setting.category not in categories:
categories.append(setting.category)
return categories
def get_settings_by_category(self, category):
"""Gets the settings by category.
Args:
category (str) : The category of the settings
Returns:
dict : The settings with the specified category
"""
settings = dict()
for key, setting in self.items():
@ -33,7 +58,8 @@ class QuackSettings(OrderedDict):
return settings
class SpectrometerModel():
class SpectrometerModel:
"""The base class for all spectrometer models.
It contains the settings and pulse parameters of the spectrometer.
@ -48,8 +74,7 @@ class SpectrometerModel():
"""Initializes the spectrometer model."""
self.settings = QuackSettings()
def add_setting(self,name: str, setting: Setting) -> None:
def add_setting(self, name: str, setting: Setting) -> None:
"""Adds a setting to the spectrometer.
Args:
@ -75,7 +100,7 @@ class SpectrometerModel():
raise ValueError(f"No setting with name {name} found")
def get_setting_by_display_name(self, display_name : str) -> Setting:
def get_setting_by_display_name(self, display_name: str) -> Setting:
"""Gets a setting by its display name.
Args:

View file

@ -5,7 +5,7 @@ import logging
logger = logging.getLogger(__name__)
class Setting():
class Setting:
"""A setting for the spectrometer is a value that is the same for all events in a pulse sequence.
E.g. the Transmit gain or the number of points in a spectrum.
@ -18,23 +18,27 @@ class Setting():
Attributes:
name (str) : The name of the setting
category (str) : The category of the setting
description (str) : A description of the setting
value : The value of the setting
category (str) : The category of the setting
"""
def __init__(self, name: str, category : str, description: str = None, default=None) -> None:
def __init__(
self, name: str, category: str, description: str = None, default=None
) -> None:
"""Create a new setting.
Args:
name (str): The name of the setting.
category (str): The category of the setting.
description (str): A description of the setting.
default: The default value of the setting.
"""
self.name = name
self.category = category
self.description = description
self.default = default
self.default = default
if default is not None:
self.value = default
# Update the description with the default value
@ -48,7 +52,13 @@ class NumericalSetting(Setting):
"""
def __init__(
self, name: str, category: str, description: str, default, min_value=None, max_value=None
self,
name: str,
category: str,
description: str,
default,
min_value=None,
max_value=None,
) -> None:
"""Create a new numerical setting."""
super().__init__(
@ -104,7 +114,7 @@ class FloatSetting(NumericalSetting):
description: str,
min_value: float = None,
max_value: float = None,
slider = False
slider=False,
) -> None:
"""Create a new float setting."""
super().__init__(name, category, description, default, min_value, max_value)
@ -141,13 +151,12 @@ class IntSetting(NumericalSetting):
description: str,
min_value=None,
max_value=None,
slider = False
slider=False,
) -> None:
"""Create a new int setting."""
super().__init__(name, category, description, default, min_value, max_value)
self.slider = slider
@property
def value(self):
"""The value of the setting. In this case, an int."""
@ -171,11 +180,12 @@ class BooleanSetting(Setting):
description (str) : A description of the setting
"""
def __init__(self, name: str, category : str, default: bool, description: str) -> None:
def __init__(
self, name: str, category: str, default: bool, description: str
) -> None:
"""Create a new boolean setting."""
super().__init__(name, category, description, default)
@property
def value(self):
"""The value of the setting. In this case, a bool."""
@ -189,7 +199,6 @@ class BooleanSetting(Setting):
raise ValueError("Value must be a bool")
class SelectionSetting(Setting):
"""A setting that is a selection from a list of options.
@ -202,7 +211,7 @@ class SelectionSetting(Setting):
"""
def __init__(
self, name: str, category : str, options: list, default: str, description: str
self, name: str, category: str, options: list, default: str, description: str
) -> None:
"""Create a new selection setting."""
super().__init__(name, category, description, default)
@ -212,7 +221,6 @@ class SelectionSetting(Setting):
self.options = options
@property
def value(self):
"""The value of the setting. In this case, a string."""
@ -241,7 +249,9 @@ class StringSetting(Setting):
description (str) : A description of the setting
"""
def __init__(self, name: str, category :str, default: str, description: str) -> None:
def __init__(
self, name: str, category: str, default: str, description: str
) -> None:
"""Create a new string setting."""
super().__init__(name, category, description, default)