Merge branch 'main' of github.com:nqrduck/nqrduck-spectrometer

This commit is contained in:
jupfi 2023-07-30 12:44:23 +02:00
commit 44b8b84823
2 changed files with 99 additions and 14 deletions

View file

@ -1,6 +1,7 @@
import logging
import numpy as np
import sympy
from decimal import Decimal
from pathlib import Path
from PyQt6.QtGui import QPixmap
from nqrduck.contrib.mplwidget import MplWidget
@ -14,34 +15,30 @@ class Function:
name: str
parameters: list
expression: str | sympy.Expr
resolution: float
resolution: Decimal
start_x: float
end_x: float
def __init__(self, expr) -> None:
self.parameters = []
self.expr = expr
self.resolution = 1/30.72e6
self.resolution = Decimal(1/30.72e6)
self.start_x = -1
self.end_x = 1
def get_time_points(self, pulse_length: float) -> np.ndarray:
def get_time_points(self, pulse_length: Decimal) -> np.ndarray:
"""Returns the time domain points for the function with the given pulse length."""
# Get the time domain points
n = int(pulse_length / self.resolution)
t = np.linspace(0, pulse_length, n)
t = np.linspace(0, float(pulse_length), n)
return t
def evaluate(self, pulse_length: float) -> np.ndarray:
def evaluate(self, pulse_length: Decimal) -> np.ndarray:
"""Evaluates the function for the given pulse length."""
n = int(pulse_length / self.resolution)
t = np.linspace(self.start_x, self.end_x, n)
x = sympy.symbols("x")
# If the expression is a string, convert it to a sympy expression
if isinstance(self.expr, str):
self.expr = sympy.sympify(self.expr)
found_variables = dict()
# Create a dictionary of the parameters and their values
for parameter in self.parameters:
@ -56,7 +53,7 @@ class Function:
return f(t)
def frequency_domain_plot(self, pulse_length: float) -> MplWidget:
def frequency_domain_plot(self, pulse_length: Decimal) -> MplWidget:
mpl_widget = MplWidget()
td = self.get_time_points(pulse_length)
yd = self.evaluate(pulse_length)
@ -64,17 +61,19 @@ class Function:
mpl_widget.canvas.ax.plot(xdf, ydf)
mpl_widget.canvas.ax.set_xlabel("Frequency in Hz")
mpl_widget.canvas.ax.set_ylabel("Magnitude")
mpl_widget.canvas.ax.grid(True)
return mpl_widget
def time_domain_plot(self, pulse_length: float) -> MplWidget:
def time_domain_plot(self, pulse_length: Decimal) -> MplWidget:
mpl_widget = MplWidget()
td = self.get_time_points(pulse_length)
mpl_widget.canvas.ax.plot(td, abs(self.evaluate(pulse_length)))
mpl_widget.canvas.ax.set_xlabel("Time in s")
mpl_widget.canvas.ax.set_ylabel("Magnitude")
mpl_widget.canvas.ax.grid(True)
return mpl_widget
def get_pulse_amplitude(self, pulse_length: float) -> np.array:
def get_pulse_amplitude(self, pulse_length: Decimal) -> np.array:
"""Returns the pulse amplitude in the time domain."""
return self.evaluate(pulse_length)
@ -110,6 +109,61 @@ class Function:
obj.add_parameter(Function.Parameter.from_json(parameter))
return obj
@property
def expr(self):
return self._expr
@expr.setter
def expr(self, expr):
if isinstance(expr, str):
try:
self._expr = sympy.sympify(expr)
except:
logger.error("Could not convert %s to a sympy expression", expr)
raise SyntaxError("Could not convert %s to a sympy expression" % expr)
elif isinstance(expr, sympy.Expr):
self._expr = expr
@property
def resolution(self):
""" The resolution of the function in seconds."""
return self._resolution
@resolution.setter
def resolution(self, resolution):
try:
self._resolution = Decimal(resolution)
except:
logger.error("Could not convert %s to a decimal", resolution)
raise SyntaxError("Could not convert %s to a decimal" % resolution)
@property
def start_x(self):
""" The x value where the evalution of the function starts."""
return self._start_x
@start_x.setter
def start_x(self, start_x):
try:
self._start_x = float(start_x)
except:
logger.error("Could not convert %s to a float", start_x)
raise SyntaxError("Could not convert %s to a float" % start_x)
@property
def end_x(self):
""" The x value where the evalution of the function ends."""
return self._end_x
@end_x.setter
def end_x(self, end_x):
try:
self._end_x = float(end_x)
except:
logger.error("Could not convert %s to a float", end_x)
raise SyntaxError("Could not convert %s to a float" % end_x)
class Parameter:
def __init__(self, name: str, symbol: str, value: float) -> None:

View file

@ -1,5 +1,6 @@
import logging
from collections import OrderedDict
from nqrduck.helpers.unitconverter import UnitConverter
from nqrduck_spectrometer.pulseparameters import Option
logger = logging.getLogger(__name__)
@ -18,7 +19,7 @@ class PulseSequence:
class Event:
"""An event is a part of a pulse sequence. It has a name and a duration and different parameters that have to be set."""
def __init__(self, name: str, duration: float) -> None:
def __init__(self, name: str, duration: str) -> None:
self.parameters = OrderedDict()
self.name = name
self.duration = duration
@ -26,7 +27,7 @@ class PulseSequence:
def add_parameter(self, parameter) -> None:
self.parameters.append(parameter)
def on_duration_changed(self, duration: float) -> None:
def on_duration_changed(self, duration: str) -> None:
logger.debug("Duration of event %s changed to %s", self.name, duration)
self.duration = duration
@ -62,6 +63,23 @@ class PulseSequence:
)
return obj
@property
def duration(self):
return self._duration
@duration.setter
def duration(self, duration : str):
# Duration needs to be a positive number
try:
duration = UnitConverter.to_decimal(duration)
except ValueError:
raise ValueError("Duration needs to be a number")
if duration < 0:
raise ValueError("Duration needs to be a positive number")
self._duration = duration
def to_json(self):
"""Returns a dict with all the data in the pulse sequence
@ -102,3 +120,16 @@ class PulseSequence:
obj.events.append(cls.Event.load_event(event_data, pulse_parameter_options))
return obj
class Variable:
""" A variable is a parameter that can be used within a pulsesequence as a placeholder.
For example the event duration a Variable with name a can be set. This variable can then be set to a list of different values.
On execution of the pulse sequence the event duration will be set to the first value in the list.
Then the pulse sequence will be executed with the second value of the list. This is repeated until the pulse sequence has
been executed with all values in the list."""
pass
class VariableGroup:
""" Variables can be grouped together.
If we have groups a and b the pulse sequence will be executed for all combinations of variables in a and b."""
pass