Updated to new setting access.

This commit is contained in:
jupfi 2024-05-29 10:22:08 +02:00
parent fe458ed59e
commit 014bf53efd
4 changed files with 108 additions and 150 deletions

View file

@ -15,3 +15,7 @@ class Simulator(Spectrometer):
def set_averages(self, value: int): def set_averages(self, value: int):
self.model.average = value self.model.average = value
@property
def settings(self):
return self.model.settings

View file

@ -48,7 +48,10 @@ class SimulatorController(SpectrometerController):
result = simulation.simulate() result = simulation.simulate()
tdx = ( tdx = (
np.linspace(0, float(self.calculate_simulation_length(sequence)), len(result)) * 1e6 np.linspace(
0, float(self.calculate_simulation_length(sequence)), len(result)
)
* 1e6
) )
rx_begin, rx_stop = self.translate_rx_event(sequence) rx_begin, rx_stop = self.translate_rx_event(sequence)
@ -84,48 +87,18 @@ class SimulatorController(SpectrometerController):
sample_length = None sample_length = None
sample_diameter = None sample_diameter = None
for samplesetting in model.settings[self.model.SAMPLE]: name = model.settings.sample_name
logger.debug("Sample setting: %s", samplesetting.name) density = model.settings.density
molar_mass = model.settings.molar_mass
if samplesetting.name == model.NAME: resonant_frequency = model.settings.resonant_frequency
name = samplesetting.value gamma = model.settings.gamma
elif samplesetting.name == model.DENSITY: nuclear_spin = model.settings.nuclear_spin
density = float(samplesetting.value) spin_factor = model.settings.spin_factor
elif samplesetting.name == model.MOLAR_MASS: powder_factor = model.settings.powder_factor
molar_mass = float(samplesetting.value) filling_factor = model.settings.filling_factor
elif samplesetting.name == model.RESONANT_FREQUENCY: T1 = model.settings.T1
resonant_frequency = float(samplesetting.value) T2 = model.settings.T2
elif samplesetting.name == model.GAMMA: T2_star = model.settings.T2_star
gamma = float(samplesetting.value)
elif samplesetting.name == model.NUCLEAR_SPIN:
nuclear_spin = float(samplesetting.value)
elif samplesetting.name == model.SPIN_FACTOR:
spin_factor = float(samplesetting.value)
elif samplesetting.name == model.POWDER_FACTOR:
powder_factor = float(samplesetting.value)
elif samplesetting.name == model.FILLING_FACTOR:
filling_factor = float(samplesetting.value)
elif samplesetting.name == model.T1:
T1 = float(samplesetting.value)
elif samplesetting.name == model.T2:
T2 = float(samplesetting.value)
elif samplesetting.name == model.T2_STAR:
T2_star = float(samplesetting.value)
elif samplesetting.name == model.ATOM_DENSITY:
atom_density = float(samplesetting.value)
elif samplesetting.name == model.SAMPLE_VOLUME:
sample_volume = float(samplesetting.value)
elif samplesetting.name == model.SAMPLE_LENGTH:
sample_length = float(samplesetting.value)
elif samplesetting.name == model.SAMPLE_DIAMETER:
sample_diameter = float(samplesetting.value)
else:
logger.warning("Unknown sample setting: %s", samplesetting.name)
self.module.nqrduck_signal.emit(
"notification",
["Error", "Unknown sample setting: " + samplesetting.name],
)
return None
sample = Sample( sample = Sample(
name=name, name=name,
@ -147,7 +120,9 @@ class SimulatorController(SpectrometerController):
) )
return sample return sample
def translate_pulse_sequence(self, sequence : QuackSequence, dwell_time: float) -> PulseArray: def translate_pulse_sequence(
self, sequence: QuackSequence, dwell_time: float
) -> PulseArray:
"""This method translates the pulse sequence from the core to a PulseArray object needed for the simulation. """This method translates the pulse sequence from the core to a PulseArray object needed for the simulation.
Args: Args:
@ -221,51 +196,39 @@ class SimulatorController(SpectrometerController):
simulation = Simulation( simulation = Simulation(
sample=sample, sample=sample,
pulse=pulse_array, pulse=pulse_array,
number_isochromats=int( number_isochromats=int(model.settings.number_isochromats),
model.get_setting_by_name(model.NUMBER_ISOCHROMATS).value initial_magnetization=float(model.settings.initial_magnetization),
), gradient=float(model.settings.gradient),
initial_magnetization=float( noise=float(model.settings.noise),
model.get_setting_by_name(model.INITIAL_MAGNETIZATION).value length_coil=float(model.settings.length_coil),
), diameter_coil=float(model.settings.diameter_coil),
gradient=float(model.get_setting_by_name(model.GRADIENT).value), number_turns=float(model.settings.number_turns),
noise=float(model.get_setting_by_name(model.NOISE).value), q_factor_transmit=float(model.settings.q_factor_transmit),
length_coil=float(model.get_setting_by_name(model.LENGTH_COIL).value), q_factor_receive=float(model.settings.q_factor_receive),
diameter_coil=float(model.get_setting_by_name(model.DIAMETER_COIL).value), power_amplifier_power=float(model.settings.power_amplifier_power),
number_turns=float(model.get_setting_by_name(model.NUMBER_TURNS).value), gain=float(model.settings.gain),
q_factor_transmit=float( temperature=float(model.settings.temperature),
model.get_setting_by_name(model.Q_FACTOR_TRANSMIT).value
),
q_factor_receive=float(
model.get_setting_by_name(model.Q_FACTOR_RECEIVE).value
),
power_amplifier_power=float(
model.get_setting_by_name(model.POWER_AMPLIFIER_POWER).value
),
gain=float(model.get_setting_by_name(model.GAIN).value),
temperature=float(model.get_setting_by_name(model.TEMPERATURE).value),
averages=int(model.averages), averages=int(model.averages),
loss_TX=float(model.get_setting_by_name(model.LOSS_TX).value), loss_TX=float(model.settings.loss_tx),
loss_RX=float(model.get_setting_by_name(model.LOSS_RX).value), loss_RX=float(model.settings.loss_rx),
conversion_factor=float( conversion_factor=float(model.settings.conversion_factor),
model.get_setting_by_name(model.CONVERSION_FACTOR).value
),
) )
return simulation return simulation
def calculate_dwelltime(self, sequence : QuackSequence) -> float: def calculate_dwelltime(self, sequence: QuackSequence) -> float:
"""This method calculates the dwell time based on the settings and the pulse sequence. """This method calculates the dwell time based on the settings and the pulse sequence.
Returns: Returns:
float: The dwell time in seconds. float: The dwell time in seconds.
""" """
n_points = int( n_points = int(
self.model.get_setting_by_name(self.model.NUMBER_POINTS).value self.model.get_setting_by_display_name(self.model.NUMBER_POINTS).value
) )
simulation_length = self.calculate_simulation_length(sequence) simulation_length = self.calculate_simulation_length(sequence)
dwell_time = simulation_length / n_points dwell_time = simulation_length / n_points
return dwell_time return dwell_time
def calculate_simulation_length(self, sequence : QuackSequence) -> float: def calculate_simulation_length(self, sequence: QuackSequence) -> float:
"""This method calculates the simulation length based on the settings and the pulse sequence. """This method calculates the simulation length based on the settings and the pulse sequence.
Returns: Returns:
@ -277,14 +240,14 @@ class SimulatorController(SpectrometerController):
simulation_length += event.duration simulation_length += event.duration
return simulation_length return simulation_length
def translate_rx_event(self, sequence : QuackSequence) -> tuple: def translate_rx_event(self, sequence: QuackSequence) -> tuple:
"""This method translates the RX event of the pulse sequence to the limr object. """This method translates the RX event of the pulse sequence to the limr object.
Returns: Returns:
tuple: A tuple containing the start and stop time of the RX event in µs tuple: A tuple containing the start and stop time of the RX event in µs
""" """
# This is a correction factor for the RX event. The offset of the first pulse is 2.2µs longer than from the specified samples. # This is a correction factor for the RX event. The offset of the first pulse is 2.2µs longer than from the specified samples.
events = sequence.events events = sequence.events
previous_events_duration = 0 previous_events_duration = 0
# offset = 0 # offset = 0
@ -314,41 +277,3 @@ class SimulatorController(SpectrometerController):
else: else:
return None, None return None, None
def set_frequency(self, value: str) -> None:
"""This method is called when the set_frequency signal is received from the core.
For the simulator this just prints a warning that the simulator is selected.
Args:
value (str) : The new frequency in MHz.
"""
logger.debug("Setting frequency to: %s", value)
try:
self.module.model.target_frequency = float(value)
logger.debug("Successfully set frequency to: %s", value)
except ValueError:
logger.warning("Could not set frequency to: %s", value)
self.module.nqrduck_signal.emit(
"notification", ["Error", "Could not set frequency to: " + value]
)
self.module.nqrduck_signal.emit("failure_set_frequency", value)
def set_averages(self, value: str) -> None:
"""This method is called when the set_averages signal is received from the core.
It sets the averages in the model used for the simulation.
Args:
value (str): The value to set the averages to.
"""
logger.debug("Setting averages to: %s", value)
try:
self.module.model.averages = int(value)
logger.debug("Successfully set averages to: %s", value)
except ValueError:
logger.warning("Could not set averages to: %s", value)
self.module.nqrduck_signal.emit(
"notification", ["Error", "Could not set averages to: " + value]
)
self.module.nqrduck_signal.emit("failure_set_averages", value)

View file

@ -2,7 +2,11 @@
import logging import logging
from quackseq.spectrometer.spectrometer_model import SpectrometerModel from quackseq.spectrometer.spectrometer_model import SpectrometerModel
from quackseq.spectrometer.spectrometer_settings import IntSetting, FloatSetting, StringSetting from quackseq.spectrometer.spectrometer_settings import (
IntSetting,
FloatSetting,
StringSetting,
)
from quackseq.pulseparameters import TXPulse, RXReadout from quackseq.pulseparameters import TXPulse, RXReadout
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -33,7 +37,7 @@ class SimulatorModel(SpectrometerModel):
CONVERSION_FACTOR = "Conversion factor" CONVERSION_FACTOR = "Conversion factor"
# Sample settings, this will be done in a separate module later on # Sample settings, this will be done in a separate module later on
NAME = "Name" SAMPLE_NAME = "Name"
DENSITY = "Density (g/cm^3)" DENSITY = "Density (g/cm^3)"
MOLAR_MASS = "Molar mass (g/mol)" MOLAR_MASS = "Molar mass (g/mol)"
RESONANT_FREQUENCY = "Resonant freq. (Hz)" RESONANT_FREQUENCY = "Resonant freq. (Hz)"
@ -63,241 +67,264 @@ class SimulatorModel(SpectrometerModel):
# Simulation settings # Simulation settings
number_of_points_setting = IntSetting( number_of_points_setting = IntSetting(
self.NUMBER_POINTS, self.NUMBER_POINTS,
self.SIMULATION,
8192, 8192,
"Number of points used for the simulation. This influences the dwell time in combination with the total event simulation given by the pulse sequence.", "Number of points used for the simulation. This influences the dwell time in combination with the total event simulation given by the pulse sequence.",
min_value=0, min_value=0,
) )
self.add_setting( self.add_setting(
"number_points",
number_of_points_setting, number_of_points_setting,
self.SIMULATION,
) )
number_of_isochromats_setting = IntSetting( number_of_isochromats_setting = IntSetting(
self.NUMBER_ISOCHROMATS, self.NUMBER_ISOCHROMATS,
self.SIMULATION,
1000, 1000,
"Number of isochromats used for the simulation. This influences the computation time.", "Number of isochromats used for the simulation. This influences the computation time.",
min_value=0, min_value=0,
max_value=10000, max_value=10000,
) )
self.add_setting(number_of_isochromats_setting, self.SIMULATION) self.add_setting("number_isochromats", number_of_isochromats_setting)
initial_magnetization_setting = FloatSetting( initial_magnetization_setting = FloatSetting(
self.INITIAL_MAGNETIZATION, self.INITIAL_MAGNETIZATION,
self.SIMULATION,
1, 1,
"Initial magnetization", "Initial magnetization",
min_value=0, min_value=0,
) )
self.add_setting(initial_magnetization_setting, self.SIMULATION) self.add_setting("initial_magnetization", initial_magnetization_setting)
# This doesn't really do anything yet
gradient_setting = FloatSetting( gradient_setting = FloatSetting(
self.GRADIENT, self.GRADIENT,
self.SIMULATION,
1, 1,
"Gradient", "Gradient",
) )
self.add_setting(gradient_setting, self.SIMULATION) self.add_setting("gradient", gradient_setting)
noise_setting = FloatSetting( noise_setting = FloatSetting(
self.NOISE, self.NOISE,
self.SIMULATION,
2, 2,
"Adds a specified level of random noise to the simulation to mimic real-world signal variations.", "Adds a specified level of random noise to the simulation to mimic real-world signal variations.",
min_value=0, min_value=0,
max_value=100, max_value=100,
) )
self.add_setting(noise_setting, self.SIMULATION) self.add_setting("noise", noise_setting)
# Hardware settings # Hardware settings
coil_length_setting = FloatSetting( coil_length_setting = FloatSetting(
self.LENGTH_COIL, self.LENGTH_COIL,
self.HARDWARE,
30e-3, 30e-3,
"The length of the sample coil within the hardware setup.", "The length of the sample coil within the hardware setup.",
min_value=1e-3, min_value=1e-3,
) )
self.add_setting(coil_length_setting, self.HARDWARE) self.add_setting("length_coil", coil_length_setting)
coil_diameter_setting = FloatSetting( coil_diameter_setting = FloatSetting(
self.DIAMETER_COIL, self.DIAMETER_COIL,
self.HARDWARE,
8e-3, 8e-3,
"The diameter of the sample coil.", "The diameter of the sample coil.",
min_value=1e-3, min_value=1e-3,
) )
self.add_setting(coil_diameter_setting, self.HARDWARE) self.add_setting("diameter_coil", coil_diameter_setting)
number_turns_setting = FloatSetting( number_turns_setting = FloatSetting(
self.NUMBER_TURNS, self.NUMBER_TURNS,
self.HARDWARE,
8, 8,
"The total number of turns of the sample coil.", "The total number of turns of the sample coil.",
min_value=1, min_value=1,
) )
self.add_setting(number_turns_setting, self.HARDWARE) self.add_setting("number_turns", number_turns_setting)
q_factor_transmit_setting = FloatSetting( q_factor_transmit_setting = FloatSetting(
self.Q_FACTOR_TRANSMIT, self.Q_FACTOR_TRANSMIT,
self.HARDWARE,
80, 80,
"The quality factor of the transmit path, which has an effect on the field strength for excitation.", "The quality factor of the transmit path, which has an effect on the field strength for excitation.",
min_value=1, min_value=1,
) )
self.add_setting(q_factor_transmit_setting, self.HARDWARE) self.add_setting("q_factor_transmit", q_factor_transmit_setting)
q_factor_receive_setting = FloatSetting( q_factor_receive_setting = FloatSetting(
self.Q_FACTOR_RECEIVE, self.Q_FACTOR_RECEIVE,
self.HARDWARE,
80, 80,
"The quality factor of the receive path, which has an effect on the final SNR.", "The quality factor of the receive path, which has an effect on the final SNR.",
min_value=1, min_value=1,
) )
self.add_setting(q_factor_receive_setting, self.HARDWARE) self.add_setting("q_factor_receive", q_factor_receive_setting)
power_amplifier_power_setting = FloatSetting( power_amplifier_power_setting = FloatSetting(
self.POWER_AMPLIFIER_POWER, self.POWER_AMPLIFIER_POWER,
self.HARDWARE,
110, 110,
"The power output capability of the power amplifier, determines the strength of pulses that can be generated.", "The power output capability of the power amplifier, determines the strength of pulses that can be generated.",
min_value=0.1, min_value=0.1,
) )
self.add_setting(power_amplifier_power_setting, self.HARDWARE) self.add_setting("power_amplifier_power", power_amplifier_power_setting)
gain_setting = FloatSetting( gain_setting = FloatSetting(
self.GAIN, self.GAIN,
self.HARDWARE,
6000, 6000,
"The amplification factor of the receiver chain, impacting the final measured signal amplitude.", "The amplification factor of the receiver chain, impacting the final measured signal amplitude.",
min_value=0.1, min_value=0.1,
) )
self.add_setting(gain_setting, self.HARDWARE) self.add_setting("gain", gain_setting)
temperature_setting = FloatSetting( temperature_setting = FloatSetting(
self.TEMPERATURE, self.TEMPERATURE,
self.EXPERIMENTAL_Setup,
300, 300,
"The absolute temperature during the experiment. This influences the SNR of the measurement.", "The absolute temperature during the experiment. This influences the SNR of the measurement.",
min_value=0.1, min_value=0.1,
max_value=400, max_value=400,
) )
self.add_setting(temperature_setting, self.EXPERIMENTAL_Setup) self.add_setting("temperature", temperature_setting)
loss_tx_setting = FloatSetting( loss_tx_setting = FloatSetting(
self.LOSS_TX, self.LOSS_TX,
self.EXPERIMENTAL_Setup,
25, 25,
"The signal loss occurring in the transmission path, affecting the effective RF pulse power.", "The signal loss occurring in the transmission path, affecting the effective RF pulse power.",
min_value=0.1, min_value=0.1,
max_value=60, max_value=60,
) )
self.add_setting(loss_tx_setting, self.EXPERIMENTAL_Setup) self.add_setting("loss_tx", loss_tx_setting)
loss_rx_setting = FloatSetting( loss_rx_setting = FloatSetting(
self.LOSS_RX, self.LOSS_RX,
self.EXPERIMENTAL_Setup,
25, 25,
"The signal loss in the reception path, which can reduce the signal that is ultimately detected.", "The signal loss in the reception path, which can reduce the signal that is ultimately detected.",
min_value=0.1, min_value=0.1,
max_value=60, max_value=60,
) )
self.add_setting(loss_rx_setting, self.EXPERIMENTAL_Setup) self.add_setting("loss_rx", loss_rx_setting)
conversion_factor_setting = FloatSetting( conversion_factor_setting = FloatSetting(
self.CONVERSION_FACTOR, self.CONVERSION_FACTOR,
self.EXPERIMENTAL_Setup,
2884, 2884,
"Conversion factor (spectrometer units / V)", "Conversion factor (spectrometer units / V)",
) )
self.add_setting( self.add_setting("conversion_factor", conversion_factor_setting) # Conversion factor for the LimeSDR based spectrometer
conversion_factor_setting,
self.EXPERIMENTAL_Setup,
) # Conversion factor for the LimeSDR based spectrometer
# Sample settings # Sample settings
sample_name_setting = StringSetting( sample_name_setting = StringSetting(
self.NAME, self.SAMPLE_NAME,
self.SAMPLE,
"BiPh3", "BiPh3",
"The name of the sample.", "The name of the sample.",
) )
self.add_setting(sample_name_setting, self.SAMPLE) self.add_setting("sample_name", sample_name_setting)
density_setting = FloatSetting( density_setting = FloatSetting(
self.DENSITY, self.DENSITY,
self.SAMPLE,
1.585e6, 1.585e6,
"The density of the sample. This is used to calculate the number of spins in the sample volume.", "The density of the sample. This is used to calculate the number of spins in the sample volume.",
min_value=0.1, min_value=0.1,
) )
self.add_setting(density_setting, self.SAMPLE) self.add_setting("density", density_setting)
molar_mass_setting = FloatSetting( molar_mass_setting = FloatSetting(
self.MOLAR_MASS, self.MOLAR_MASS,
self.SAMPLE,
440.3, 440.3,
"The molar mass of the sample. This is used to calculate the number of spins in the sample volume.", "The molar mass of the sample. This is used to calculate the number of spins in the sample volume.",
min_value=0.1, min_value=0.1,
) )
self.add_setting(molar_mass_setting, self.SAMPLE) self.add_setting("molar_mass", molar_mass_setting)
resonant_frequency_setting = FloatSetting( resonant_frequency_setting = FloatSetting(
self.RESONANT_FREQUENCY, self.RESONANT_FREQUENCY,
self.SAMPLE,
83.56e6, 83.56e6,
"The resonant frequency of the observed transition.", "The resonant frequency of the observed transition.",
min_value=1e5, min_value=1e5,
) )
self.add_setting(resonant_frequency_setting, self.SAMPLE) self.add_setting("resonant_frequency", resonant_frequency_setting)
gamma_setting = FloatSetting( gamma_setting = FloatSetting(
self.GAMMA, self.GAMMA,
self.SAMPLE,
4.342e7, 4.342e7,
"The gyromagnetic ratio of the samples nuclei.", "The gyromagnetic ratio of the samples nuclei.",
min_value=0, min_value=0,
) )
self.add_setting(gamma_setting, self.SAMPLE) self.add_setting("gamma", gamma_setting)
# This could be updated to a selection setting
nuclear_spin_setting = FloatSetting( nuclear_spin_setting = FloatSetting(
self.NUCLEAR_SPIN, self.NUCLEAR_SPIN,
self.SAMPLE,
9 / 2, 9 / 2,
"The nuclear spin of the samples nuclei.", "The nuclear spin of the samples nuclei.",
min_value=0, min_value=0,
) )
self.add_setting(nuclear_spin_setting, self.SAMPLE) self.add_setting("nuclear_spin", nuclear_spin_setting)
spin_factor_setting = FloatSetting( spin_factor_setting = FloatSetting(
self.SPIN_FACTOR, self.SPIN_FACTOR,
self.SAMPLE,
2, 2,
"The spin factor represents the scaling coefficient for observable nuclear spin transitions along the x-axis, derived from the Pauli I x 0 -matrix elements.", "The spin factor represents the scaling coefficient for observable nuclear spin transitions along the x-axis, derived from the Pauli I x 0 -matrix elements.",
min_value=0, min_value=0,
) )
self.add_setting(spin_factor_setting, self.SAMPLE) self.add_setting("spin_factor", spin_factor_setting)
powder_factor_setting = FloatSetting( powder_factor_setting = FloatSetting(
self.POWDER_FACTOR, self.POWDER_FACTOR,
self.SAMPLE,
0.75, 0.75,
"A factor representing the crystallinity of the solid sample. A value of 0.75 corresponds to a powder sample.", "A factor representing the crystallinity of the solid sample. A value of 0.75 corresponds to a powder sample.",
min_value=0, min_value=0,
max_value=1, max_value=1,
) )
self.add_setting(powder_factor_setting, self.SAMPLE) self.add_setting("powder_factor", powder_factor_setting)
filling_factor_setting = FloatSetting( filling_factor_setting = FloatSetting(
self.FILLING_FACTOR, self.FILLING_FACTOR,
self.SAMPLE,
0.7, 0.7,
"The ratio of the sample volume that occupies the coils sensitive volume.", "The ratio of the sample volume that occupies the coils sensitive volume.",
min_value=0, min_value=0,
max_value=1, max_value=1,
) )
self.add_setting(filling_factor_setting, self.SAMPLE) self.add_setting("filling_factor", filling_factor_setting)
t1_setting = FloatSetting( t1_setting = FloatSetting(
self.T1, self.T1,
self.SAMPLE,
83.5e-5, 83.5e-5,
"The longitudinal or spin-lattice relaxation time of the sample, influencing signal recovery between pulses.", "The longitudinal or spin-lattice relaxation time of the sample, influencing signal recovery between pulses.",
min_value=1e-6, min_value=1e-6,
) )
self.add_setting(t1_setting, self.SAMPLE) self.add_setting("T1", t1_setting)
t2_setting = FloatSetting( t2_setting = FloatSetting(
self.T2, self.T2,
self.SAMPLE,
396e-6, 396e-6,
"The transverse or spin-spin relaxation time, determining the rate at which spins dephase and the signal decays in the xy plane", "The transverse or spin-spin relaxation time, determining the rate at which spins dephase and the signal decays in the xy plane",
min_value=1e-6, min_value=1e-6,
) )
self.add_setting(t2_setting, self.SAMPLE) self.add_setting("T2", t2_setting)
t2_star_setting = FloatSetting( t2_star_setting = FloatSetting(
self.T2_STAR, self.T2_STAR,
self.SAMPLE,
50e-6, 50e-6,
"The effective transverse relaxation time, incorporating effects of EFG inhomogeneities and other dephasing factors.", "The effective transverse relaxation time, incorporating effects of EFG inhomogeneities and other dephasing factors.",
min_value=1e-6, min_value=1e-6,
) )
self.add_setting(t2_star_setting, self.SAMPLE) self.add_setting("T2_star", t2_star_setting)
self.averages = 1 self.averages = 1
self.target_frequency = 100e6 self.target_frequency = 100e6

View file

@ -24,6 +24,8 @@ class TestQuackSequence(unittest.TestCase):
sim = Simulator() sim = Simulator()
sim.set_averages(100) sim.set_averages(100)
sim.settings.noise = 0
result = sim.run_sequence(seq) result = sim.run_sequence(seq)
self.assertIsNotNone(result) self.assertIsNotNone(result)
self.assertTrue(hasattr(result, "tdx")) self.assertTrue(hasattr(result, "tdx"))