move to a more standard python packaging structure
Build Debian Packages / build (bookworm, debian12) (push) Successful in 13m3s
Build Debian Packages / build (trixie, debian13) (push) Successful in 13m46s
Build Debian Packages / build (bullseye, debian11) (push) Has been cancelled

This commit is contained in:
2026-04-07 17:09:10 +02:00
parent 1322fd3835
commit 6abb338c4a
43 changed files with 245 additions and 83 deletions
+1 -28
View File
@@ -13,36 +13,9 @@ DAMARIS documentation
:maxdepth: 3 :maxdepth: 3
:caption: Contents: :caption: Contents:
api_reference
manual manual
devel devel
#############
API Reference
#############
This API reference is generated from the source code.
***********
Experiments
***********
.. automodule:: damaris.experiments.Experiment
:members:
:undoc-members:
************
Data Objects
************
.. automodule:: damaris.data.Accumulation
:members:
:undoc-members:
.. automodule:: damaris.data.ADC_Result
:members:
:undoc-members:
.. automodule:: damaris.data.DamarisFFT
:members:
:undoc-members:
+3 -16
View File
@@ -35,27 +35,14 @@ maintainers = [
[project.scripts] [project.scripts]
DAMARIS3 = "damaris.__main__:main" DAMARIS3 = "damaris.__main__:main"
[tool.setuptools] [tool.setuptools.packages.find]
packages = [ where = ["src"]
"damaris",
"damaris.data",
"damaris.experiments",
"damaris.gui",
"damaris.tools"
]
[tool.setuptools.package-dir]
"damaris" = "src"
"damaris.data" = "src/data"
"damaris.experiments" = "src/experiments"
"damaris.gui" = "src/gui"
"damaris.tools" = "src/tools"
[tool.setuptools.package-data] [tool.setuptools.package-data]
"damaris.gui" = ["DAMARIS3.png", "DAMARIS3.ico", "damaris.xml", "python.xml"] "damaris.gui" = ["DAMARIS3.png", "DAMARIS3.ico", "damaris.xml", "python.xml"]
[tool.setuptools.data-files] [tool.setuptools.data-files]
"share/python3-damaris/images" = ["src/gui/DAMARIS3.png", "src/gui/DAMARIS3.ico"] "share/python3-damaris/images" = ["src/damaris/gui/DAMARIS3.png", "src/damaris/gui/DAMARIS3.ico"]
#"share/python3-damaris/doc" = ["doc/index.html"] #"share/python3-damaris/doc" = ["doc/index.html"]
#"share/python3-damaris/doc/reference-html" = ["doc/reference-html/*"] #"share/python3-damaris/doc/reference-html" = ["doc/reference-html/*"]
#"share/python3-damaris/doc/tutorial-html" = ["doc/tutorial-html/*"] #"share/python3-damaris/doc/tutorial-html" = ["doc/tutorial-html/*"]
@@ -107,12 +107,40 @@ class Experiment:
def ttl_pulse(self, length, channel = None, value = None): def ttl_pulse(self, length, channel = None, value = None):
""" """
Creates a state with length **length** and switches Creates a state with length **length** and switches requested bits of the pulse programmer to HIGH.
requested bits of the pulse programmer to HIGH:
:param float length: pulse length in seconds This command generates a TTL pulse with the specified duration on a specific channel or multiple channels.
:param int channel: selects a single channel (No. 1 - 24)
:param int value: lines to set (integer) for example value=3 selects channels 0 and 1 (2**0 + 2**1) Parameters:
-----------
length : float
Pulse length in seconds.
channel : int, optional
Selects a single channel (No. 1 - 24). If provided, the value is calculated as 2^channel.
value : int, optional
Lines to set (integer). For example, value=3 selects channels 0 and 1 (2**0 + 2**1).
If both channel and value are None, the pulse is set to 0.
Examples:
---------
>>> e.ttl_pulse(length=5e-6, channel=1)
Creates a 5 microsecond pulse on channel 1.
>>> e.ttl_pulse(length=3e-6, value=3)
Creates a 3 microsecond pulse on channels 0 and 1.
>>> e.ttl_pulse(length=1e-6, value=0xffffff)
Creates a 1 microsecond pulse on all channels.
Notes:
------
Hexadecimal representation (number starts with *0x*) is convenient as the numbers are shorter.
To set all channels, value would be in decimal 16777215 and in hexadecimal 0xffffff.
One letter in hexadecimal represents four bits.
See Also:
---------
ttls : Same as ttl_pulse, but no channel keyword.
""" """
the_value=0 the_value=0
if value is not None: if value is not None:
@@ -176,12 +204,43 @@ class Experiment:
def wait(self, time, ttls=None, gating=False): def wait(self, time, ttls=None, gating=False):
""" """
Wait specified **time** doing nothing. Waits for a specified amount of time without performing any actions.
This command inserts a delay in the pulse sequence, allowing time for relaxation,
or synchronization with other events.
Parameters:
-----------
time : float
Time to wait in seconds.
The minimum time is 90 ns, and the maximum is essentially unlimited (years).
The backend driver circumvents the limit imposed by the pulse programmer by adding loops.
ttls : int, optional
Additional TTL lines to set (integer) during the wait period.
Allows simultaneous control of TTL lines while waiting.
For example, ttls=3 activates channels 0 and 1 (2^0 + 2^1).
gating : bool, optional
If True, reduces the wait time by the gating time (typically 2 µs).
This is useful for waiting in front of an rf_pulse to account for gating delays.
Default is False.
Returns:
--------
None
Examples:
---------
>>> e.wait(time=2e-3)
Waits for 2 milliseconds.
>>> e.wait(time=1e-6, ttls=3)
Waits for 1 microsecond while activating TTL channels 0 and 1.
>>> e.wait(time=5e-6, gating=True)
Waits for 5 microseconds, reduced by the gating time for rf_pulse synchronization.
:param float time: seconds to wait
:param int ttls: lines to set (integer)
:param bool gating: reduce time by gating, i.e. wait in front of rf_pulse
:return:
""" """
if gating: if gating:
time -= self.gating time -= self.gating
@@ -196,16 +255,70 @@ class Experiment:
def record(self, samples, frequency, timelength=None, sensitivity = None, ttls=None, channels = 3, offset = None, impedance = None): def record(self, samples, frequency, timelength=None, sensitivity = None, ttls=None, channels = 3, offset = None, impedance = None):
""" """
Records data with a given number of samples, sampling frequency and sensitivity. Records data with a given number of samples, sampling frequency, and sensitivity.
Optionally, the time length of this state can be specified. If not specified, **timelength** is This command starts data acquisition from the ADC (Analog-to-Digital Converter).
deduced from **samples**/**frequency**:
Parameters:
-----------
samples : int
Number of samples to record. This determines the number of data points in the resulting signal.
frequency : float
Sampling frequency in Hz. This determines how often samples are taken from the analog signal.
The maximum sampling frequency is 20 MHz.
timelength : float, optional
Length of this state in seconds. If not specified (None), it is calculated automatically as samples/frequency.
This parameter allows overriding the automatic calculation for special timing requirements.
sensitivity : float or list, optional
Sensitivity in U_MAX/V. Specifies the input voltage range for the ADC.
Accepted values are 0.2, 0.5, 1, 2, 5, and 10 V.
Can be a single value (applied to all channels) or a list of values (one per channel).
ttls : int, optional
Additional TTL lines to set (integer) during recording. Allows simultaneous control of TTL lines.
For example, ttls=3 activates channels 0 and 1 (2^0 + 2^1).
channels : int, optional
Channels to activate. Default is 3 (channels 0 and 1).
Accepted values are 1 (channel 0), 3 (channels 0 and 1), 5 (channels 0, 1, and 2), and 15 (all 4 channels).
offset : int or list, optional
Voltage offset for the ADC input. Can be a single integer value (applied to all channels)
or a list of values (one per channel).
Normally not used.
impedance : float or list, optional
Input impedance for the ADC. Can be a single number (applied to all channels)
or a list of values (one per channel).
Normally set in the backend config and not changeable.
Returns:
--------
None
Examples:
---------
>>> e.record(samples=1024, frequency=2e6, sensitivity=2)
Records a signal with 1024 data points and 2 MHz sampling frequency.
The sensitivity will be ±2 V, providing a resolution of 0.2 mV with a 14-bit ADC card.
>>> e.record(samples=4096, frequency=10e6, sensitivity=[1, 2], channels=3)
Records a signal with 4096 data points and 10 MHz sampling frequency.
Channel 0 uses 1 V sensitivity, and channel 1 uses 2 V sensitivity.
>>> e.record(samples=2048, frequency=5e6, ttls=3)
Records a signal with 2048 data points and 5 MHz sampling frequency.
Simultaneously activates TTL channels 0 and 1.
Notes:
------
- Multiple record statements can be in a single scan (gated sampling) or in a loop.
- The onboard memory can hold 8M samples shared by all channels (depends on the board).
- The sensitivity setting affects the resolution of the ADC.
- The actual timing may vary slightly due to hardware limitationslike pre- and post-trigger delays.
:param int samples: Number of samples to record
:param float frequency: Sampling frequency / Hz
:param float timelength: Length of this state, per default calculated automatically
:param float sensitivity: Sensitivity in U_MAX/V
:param int ttls: additional ttl lines to set (integer)
:param int channels: channels to activate, default=3 (0+1)
""" """
attributes='s="%d" f="%d"'%(samples,frequency)#%g attributes='s="%d" f="%d"'%(samples,frequency)#%g
if channels != 1 and channels != 3 and channels != 5 and channels != 15: if channels != 1 and channels != 3 and channels != 5 and channels != 15:
@@ -371,17 +484,51 @@ class Experiment:
def set_dac(self, dac_value, dac_id=1, length=None, is_seq=False, ttls=0): def set_dac(self, dac_value, dac_id=1, length=None, is_seq=False, ttls=0):
""" """
This sets the value for the DAC and if given additional ttl lines. Sets the value for the DAC (Digital-to-Analog Converter) and optionally additional TTL lines.
It also sets it back to zero automatically when is_seq=False. This command is used to control analog output signals, such as pulsed field gradients.
If you don't wish to set the value back to zero (i.e. line shapes) set is_seq=True
The state length is at least 3.78 µs (is_seq=1) or 7.28µs (is_seq=0). Parameters:
-----------
dac_value : int
DAC value, between -2**19-1 (-524287) and +2**19 (524288).
This value determines the analog output voltage.
:param int dac_value: DAC value, between -2**19-1 and +2**19 dac_id : int, optional
:param int dac_id: default=1, which DAC to control Specifies which DAC to control. Default is 1.
:param float length: default=None, length of this state in seconds. If *None* length=42*90ns=3.78µs This allows control of multiple DAC channels if available.
:param bool is_seq: default=False, do not reset DAC to 0 (zero) if True
:param int ttls: default=0, lines to set (integer) length : float, optional
Length of this state in seconds. Default is None, which sets the length to 42*90ns=3.78µs.
If is_seq is False, the total length is doubled due to the automatic reset to zero.
is_seq : bool, optional
If True, the DAC value is not reset to zero after the pulse. Default is False.
Use is_seq=True for creating line shapes or sequential pulses.
ttls : int, optional
Lines to set (integer) for TTL output. Default is 0.
Allows simultaneous control of TTL lines along with the DAC.
Returns:
--------
None
Examples:
---------
>>> e.set_dac(dac_value=15040, dac_id=1, length=1e-3)
Sets DAC channel 1 to value 15040 for 1 millisecond and then resets to zero.
>>> e.set_dac(dac_value=10000, is_seq=True)
Sets DAC to value 10000 for 3.78µs without resetting to zero.
>>> e.set_dac(dac_value=20000, ttls=3)
Sets DAC to value 20000 and activates TTL channel 1 (2^1 + 2^0 = 3).
Notes:
------
- The minimum state length is 3.78 µs when is_seq=True.
- When is_seq=False, the DAC is automatically reset to zero, adding another 3.78 µs to the total length.
- The actual length may be longer than specified if additional time is required for DAC settling.
""" """
if length==None: if length==None:
@@ -401,13 +548,40 @@ class Experiment:
def set_phase(self, phase, ttls=0): def set_phase(self, phase, ttls=0):
""" """
Sets the phase of the RF source to this value. Sets the phase of the RF source to the specified value.
Note: This is relative to the phase at the beginnig of the experiment.
The state length is 0.5 µs, but the stabilisation time is RF source dependent. Typical
values for PTS310 is 2 µs.
:param float phase: phase to set This command changes the phase of the frequency source. The phase is given in degrees and is
:param int ttls: default=0, lines to set (integer) relative to the phase at the beginning of the experiment.
Parameters:
-----------
phase : float
Phase to set in degrees. This value determines the phase of the RF signal.
ttls : int, optional
Lines to set (integer) for TTL output. Default is 0.
Allows simultaneous control of TTL lines along with setting the phase.
Returns:
--------
None
Examples:
---------
>>> e.set_phase(phase=90)
Sets the receiver phase to 90 degrees.
>>> e.set_phase(phase=180, ttls=3)
Sets the phase to 180 degrees and activates TTL channels 0 and 1.
>>> e.set_phase(phase=45)
Sets the phase to 45 degrees.
Notes:
------
- The state length for this command is 0.5 µs.
- The stabilization time for the phase change is RF source dependent. A typical value for PTS310 is 2 µs.
- The phase is relative to the initial phase set at start of the experiment.
""" """
s_content = '<analogout phase="%f" />' % (phase) s_content = '<analogout phase="%f" />' % (phase)
if ttls!=0: if ttls!=0:
@@ -418,12 +592,40 @@ class Experiment:
def set_description(self, key, value): def set_description(self, key, value):
"""Sets a description which is carried via the back end result """
file to the result script in the front end. In the result script Sets a description key-value pair in the experiment description dictionary.
you can extract the description with get_description
:param str key: the key This command creates an entry with the specified key and value in the description dictionary.
:param value: the value, its type is saved. In case of data being stored in a HDF5 file, this dictionary is stored as well, allowing
parameter passing between the experiment script and the result script.
Parameters:
-----------
key : str
The key identifier for the description entry. This will be used to retrieve the value later.
value : any
The value to be associated with the key. Can be of any type (string, number, list, etc.).
Returns:
--------
None
Examples:
---------
>>> e.set_description(key="tau", value=2e-3)
Sets the description entry with key "tau" to the value 0.002 seconds.
>>> e.set_description(key="temperature", value=298.15)
Sets the description entry with key "temperature" to the value 298.15 Kelvin.
>>> e.set_description(key="pulse_sequence", value="CPMG")
Sets the description entry with key "pulse_sequence" to the string "CPMG".
Notes:
------
If the key already exists in the description dictionary, a warning message will be printed
indicating that the existing value will be overwritten.
""" """
if key in list(self.description.keys()): if key in list(self.description.keys()):
print('Warning: Overwriting existing description "%s" = "%s" with "%s"' % (key, self.description[key], value)) print('Warning: Overwriting existing description "%s" = "%s" with "%s"' % (key, self.description[key], value))

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before

Width:  |  Height:  |  Size: 664 B

After

Width:  |  Height:  |  Size: 664 B