Compare commits

..

3 Commits

4 changed files with 227 additions and 31 deletions

52
poetry.lock generated
View File

@ -704,6 +704,56 @@ pygments = ">=2.13.0,<3.0.0"
[package.extras] [package.extras]
jupyter = ["ipywidgets (>=7.5.1,<9)"] jupyter = ["ipywidgets (>=7.5.1,<9)"]
[[package]]
name = "scipy"
version = "1.14.1"
description = "Fundamental algorithms for scientific computing in Python"
optional = false
python-versions = ">=3.10"
files = [
{file = "scipy-1.14.1-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:b28d2ca4add7ac16ae8bb6632a3c86e4b9e4d52d3e34267f6e1b0c1f8d87e389"},
{file = "scipy-1.14.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d0d2821003174de06b69e58cef2316a6622b60ee613121199cb2852a873f8cf3"},
{file = "scipy-1.14.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8bddf15838ba768bb5f5083c1ea012d64c9a444e16192762bd858f1e126196d0"},
{file = "scipy-1.14.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:97c5dddd5932bd2a1a31c927ba5e1463a53b87ca96b5c9bdf5dfd6096e27efc3"},
{file = "scipy-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ff0a7e01e422c15739ecd64432743cf7aae2b03f3084288f399affcefe5222d"},
{file = "scipy-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e32dced201274bf96899e6491d9ba3e9a5f6b336708656466ad0522d8528f69"},
{file = "scipy-1.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8426251ad1e4ad903a4514712d2fa8fdd5382c978010d1c6f5f37ef286a713ad"},
{file = "scipy-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:a49f6ed96f83966f576b33a44257d869756df6cf1ef4934f59dd58b25e0327e5"},
{file = "scipy-1.14.1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:2da0469a4ef0ecd3693761acbdc20f2fdeafb69e6819cc081308cc978153c675"},
{file = "scipy-1.14.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:c0ee987efa6737242745f347835da2cc5bb9f1b42996a4d97d5c7ff7928cb6f2"},
{file = "scipy-1.14.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3a1b111fac6baec1c1d92f27e76511c9e7218f1695d61b59e05e0fe04dc59617"},
{file = "scipy-1.14.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8475230e55549ab3f207bff11ebfc91c805dc3463ef62eda3ccf593254524ce8"},
{file = "scipy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:278266012eb69f4a720827bdd2dc54b2271c97d84255b2faaa8f161a158c3b37"},
{file = "scipy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fef8c87f8abfb884dac04e97824b61299880c43f4ce675dd2cbeadd3c9b466d2"},
{file = "scipy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b05d43735bb2f07d689f56f7b474788a13ed8adc484a85aa65c0fd931cf9ccd2"},
{file = "scipy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:716e389b694c4bb564b4fc0c51bc84d381735e0d39d3f26ec1af2556ec6aad94"},
{file = "scipy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:631f07b3734d34aced009aaf6fedfd0eb3498a97e581c3b1e5f14a04164a456d"},
{file = "scipy-1.14.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:af29a935803cc707ab2ed7791c44288a682f9c8107bc00f0eccc4f92c08d6e07"},
{file = "scipy-1.14.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2843f2d527d9eebec9a43e6b406fb7266f3af25a751aa91d62ff416f54170bc5"},
{file = "scipy-1.14.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:eb58ca0abd96911932f688528977858681a59d61a7ce908ffd355957f7025cfc"},
{file = "scipy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30ac8812c1d2aab7131a79ba62933a2a76f582d5dbbc695192453dae67ad6310"},
{file = "scipy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f9ea80f2e65bdaa0b7627fb00cbeb2daf163caa015e59b7516395fe3bd1e066"},
{file = "scipy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:edaf02b82cd7639db00dbff629995ef185c8df4c3ffa71a5562a595765a06ce1"},
{file = "scipy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2ff38e22128e6c03ff73b6bb0f85f897d2362f8c052e3b8ad00532198fbdae3f"},
{file = "scipy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1729560c906963fc8389f6aac023739ff3983e727b1a4d87696b7bf108316a79"},
{file = "scipy-1.14.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:4079b90df244709e675cdc8b93bfd8a395d59af40b72e339c2287c91860deb8e"},
{file = "scipy-1.14.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e0cf28db0f24a38b2a0ca33a85a54852586e43cf6fd876365c86e0657cfe7d73"},
{file = "scipy-1.14.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0c2f95de3b04e26f5f3ad5bb05e74ba7f68b837133a4492414b3afd79dfe540e"},
{file = "scipy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b99722ea48b7ea25e8e015e8341ae74624f72e5f21fc2abd45f3a93266de4c5d"},
{file = "scipy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5149e3fd2d686e42144a093b206aef01932a0059c2a33ddfa67f5f035bdfe13e"},
{file = "scipy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4f5a7c49323533f9103d4dacf4e4f07078f360743dec7f7596949149efeec06"},
{file = "scipy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:baff393942b550823bfce952bb62270ee17504d02a1801d7fd0719534dfb9c84"},
{file = "scipy-1.14.1.tar.gz", hash = "sha256:5a275584e726026a5699459aa72f828a610821006228e841b94275c4a7c08417"},
]
[package.dependencies]
numpy = ">=1.23.5,<2.3"
[package.extras]
dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"]
doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.13.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<=7.3.7)", "sphinx-design (>=0.4.0)"]
test = ["Cython", "array-api-strict (>=2.0)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"]
[[package]] [[package]]
name = "shellingham" name = "shellingham"
version = "1.5.4" version = "1.5.4"
@ -779,4 +829,4 @@ files = [
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.12" python-versions = "^3.12"
content-hash = "6b680c385942c0a2c0eef934f3fb37fdc3d2e1dc058a7f2d891d4f2f0607d9c6" content-hash = "477748fbc18bde095d13dea548108541c1b584242099398155787361b1dc31fe"

View File

@ -13,6 +13,7 @@ matplotlib = "^3.9.2"
numpy = "^2.1.1" numpy = "^2.1.1"
pyqt6 = "^6.7.1" pyqt6 = "^6.7.1"
tomli = "^2.0.1" tomli = "^2.0.1"
scipy = "^1.14.1"
[build-system] [build-system]

View File

@ -1,12 +1,14 @@
import ctypes import signal
import sys
import faulthandler import faulthandler
import time import time
import uldaq import uldaq
from IPython import embed from IPython import embed
import numpy as np import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from scipy.signal import peak_widths, welch, csd
from scipy.signal import find_peaks
from pyrelacs.repros.mccdac import MccDac from pyrelacs.repros.mccdac import MccDac
from pyrelacs.util.logging import config_logging from pyrelacs.util.logging import config_logging
@ -19,13 +21,67 @@ class Calibration(MccDac):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
def segfault_handler(self, signum, frame):
print(f"Segmentation fault caught! Signal number: {signum}")
self.disconnect_dac()
sys.exit(1) # Gracefully exit the program
def check_amplitude(self): def check_amplitude(self):
db_values = [0.0, -5.0, -10.0, -20.0, -50.0]
colors = ["red", "green", "blue", "black", "yellow"]
self.set_attenuation_level(db_channel1=0.0, db_channel2=0.0) self.set_attenuation_level(db_channel1=0.0, db_channel2=0.0)
# write to ananlog 1 # write to ananlog 1
t = np.arange(0, DURATION, 1 / SAMPLERATE) t = np.arange(0, DURATION, 1 / SAMPLERATE)
data = AMPLITUDE * np.sin(2 * np.pi * SINFREQ * t) data = AMPLITUDE * np.sin(2 * np.pi * SINFREQ * t)
data_channels = np.zeros(2 * len(data)) fig, ax = plt.subplots()
# c = [(i,for i,j in zip(data, data)]
for i, db_value in enumerate(db_values):
self.set_attenuation_level(db_channel1=db_value, db_channel2=db_value)
log.debug(f"{db_value}")
stim = self.write_analog(
data,
[0, 0],
SAMPLERATE,
ScanOption=uldaq.ScanOption.EXTTRIGGER,
)
data_channel_one = self.read_analog(
[0, 0], DURATION, SAMPLERATE, ScanOption=uldaq.ScanOption.EXTTRIGGER
)
time.sleep(1)
log.debug("Starting the Scan")
self.diggital_trigger()
try:
self.ao_device.scan_wait(uldaq.WaitType.WAIT_UNTIL_DONE, 15)
log.debug("Scan finished")
self.write_bit(channel=0, bit=0)
time.sleep(1)
self.set_analog_to_zero()
except uldaq.ul_exception.ULException:
log.debug("Operation timed out")
# reset the diggital trigger
self.write_bit(channel=0, bit=0)
time.sleep(1)
self.set_analog_to_zero()
self.disconnect_dac()
if i == 0:
ax.plot(t, stim, label=f"Input_{db_value}", color=colors[i])
ax.plot(t, data_channel_one, label=f"Reaout {db_value}", color=colors[i])
ax.legend()
plt.show()
self.disconnect_dac()
def check_beat(self):
self.set_attenuation_level(db_channel1=-10.0, db_channel2=0.0)
t = np.arange(0, DURATION, 1 / SAMPLERATE)
data = AMPLITUDE * np.sin(2 * np.pi * SINFREQ * t)
# data = np.concatenate((data, data))
stim = self.write_analog( stim = self.write_analog(
data, data,
@ -33,35 +89,119 @@ class Calibration(MccDac):
SAMPLERATE, SAMPLERATE,
ScanOption=uldaq.ScanOption.EXTTRIGGER, ScanOption=uldaq.ScanOption.EXTTRIGGER,
) )
data_channel_one = self.read_analog( readout = self.read_analog(
[0, 0], DURATION, SAMPLERATE, ScanOption=uldaq.ScanOption.EXTTRIGGER [0, 1],
DURATION,
SAMPLERATE,
ScanOption=uldaq.ScanOption.EXTTRIGGER,
) )
time.sleep(1)
self.diggital_trigger() self.diggital_trigger()
signal.signal(signal.SIGSEGV, self.segfault_handler)
log.info(self.ao_device)
ai_status = uldaq.ScanStatus.RUNNING
ao_status = uldaq.ScanStatus.RUNNING
try: log.debug(
self.ai_device.scan_wait(uldaq.WaitType.WAIT_UNTIL_DONE, 15) f"Status Analog_output {ao_status}\n, Status Analog_input {ai_status}"
self.write_bit(channel=0, bit=0) )
time.sleep(1) while (ai_status != uldaq.ScanStatus.IDLE) and (
self.set_analog_to_zero() ao_status != uldaq.ScanStatus.IDLE
except uldaq.ul_exception.ULException: ):
log.debug("Operation timed out") log.debug("Scanning")
# reset the diggital trigger time.sleep(0.5)
self.write_bit(channel=0, bit=0) ai_status = self.ai_device.get_scan_status()[0]
time.sleep(1) ao_status = self.ao_device.get_scan_status()[0]
self.set_analog_to_zero()
self.disconnect_dac() log.debug(
f"Status Analog_output {ao_status}\n, Status Analog_input {ai_status}"
)
fig, axes = plt.subplots(2, 2, sharex="col")
channel1 = np.array(readout[::2])
channel2 = np.array(readout[1::2])
beat = channel1 + channel2
beat_square = beat**2
f, powerspec = welch(beat, fs=SAMPLERATE)
powerspec = decibel(powerspec)
f_sq, powerspec_sq = welch(beat_square, fs=SAMPLERATE)
powerspec_sq = decibel(powerspec_sq)
peaks = find_peaks(powerspec_sq, prominence=20)[0]
f_stim, powerspec_stim = welch(channel1, fs=SAMPLERATE)
powerspec_stim = decibel(powerspec_stim)
f_in, powerspec_in = welch(channel2, fs=SAMPLERATE)
powerspec_in = decibel(powerspec_in)
axes[0, 0].plot(t, channel1, label="Readout Channel0")
axes[0, 0].plot(t, channel2, label="Readout Channel1")
axes[0, 1].plot(f_stim, powerspec_stim, label="powerspec Channel0")
axes[0, 1].plot(f_in, powerspec_in, label="powerspec Channel2")
axes[0, 1].set_xlabel("Freq [HZ]")
axes[0, 1].set_ylabel("dB")
axes[1, 0].plot(t, beat, label="Beat")
axes[1, 0].plot(t, beat**2, label="Beat squared")
axes[1, 0].legend()
axes[1, 1].plot(f, powerspec)
axes[1, 1].plot(f_sq, powerspec_sq)
axes[1, 1].scatter(f_sq[peaks], powerspec_sq[peaks])
axes[1, 1].set_xlabel("Freq [HZ]")
axes[1, 1].set_ylabel("dB")
axes[0, 0].legend()
embed() embed()
exit() exit()
def decibel(power, ref_power=1.0, min_power=1e-20):
"""Transform power to decibel relative to ref_power.
\\[ decibel = 10 \\cdot \\log_{10}(power/ref\\_power) \\]
Power values smaller than `min_power` are set to `-np.inf`.
Parameters
----------
power: float or array
Power values, for example from a power spectrum or spectrogram.
ref_power: float or None or 'peak'
Reference power for computing decibel.
If set to `None` or 'peak', the maximum power is used.
min_power: float
Power values smaller than `min_power` are set to `-np.inf`.
Returns
-------
decibel_psd: array
Power values in decibel relative to `ref_power`.
"""
if np.isscalar(power):
tmp_power = np.array([power])
decibel_psd = np.array([power])
else:
tmp_power = power
decibel_psd = power.copy()
if ref_power is None or ref_power == "peak":
ref_power = np.max(decibel_psd)
decibel_psd[tmp_power <= min_power] = float("-inf")
decibel_psd[tmp_power > min_power] = 10.0 * np.log10(
decibel_psd[tmp_power > min_power] / ref_power
)
if np.isscalar(power):
return decibel_psd[0]
else:
return decibel_psd
if __name__ == "__main__": if __name__ == "__main__":
SAMPLERATE = 40_000.0 SAMPLERATE = 40_000.0
DURATION = 5 DURATION = 5
AMPLITUDE = 0.5 AMPLITUDE = 1
SINFREQ = 10 SINFREQ = 1000
cal = Calibration() cal = Calibration()
# cal.ccheck_attenuator() # cal.check_attenuator()
cal.check_amplitude() # cal.check_amplitude()
cal.check_beat()

View File

@ -19,7 +19,11 @@ class MccDac:
log.error("Did not found daq devices, please connect one") log.error("Did not found daq devices, please connect one")
exit(1) exit(1)
self.daq_device = uldaq.DaqDevice(devices[0]) self.daq_device = uldaq.DaqDevice(devices[0])
self.daq_device.connect() try:
self.daq_device.connect()
except uldaq.ul_exception.ULException:
self.disconnect_dac()
self.connect_dac()
self.ai_device = self.daq_device.get_ai_device() self.ai_device = self.daq_device.get_ai_device()
self.ao_device = self.daq_device.get_ao_device() self.ao_device = self.daq_device.get_ao_device()
self.dio_device = self.daq_device.get_dio_device() self.dio_device = self.daq_device.get_dio_device()
@ -85,8 +89,8 @@ class MccDac:
buffer = c_double * len(data) buffer = c_double * len(data)
data_analog_output = buffer(*data) data_analog_output = buffer(*data)
log.debug(f"Created C_double data {data_analog_output}") log.debug(f"Created C_double data {data_analog_output}")
try: try:
err = self.ao_device.a_out_scan( err = self.ao_device.a_out_scan(
channels[0], channels[0],
@ -123,12 +127,13 @@ class MccDac:
self.disconnect_dac() self.disconnect_dac()
def diggital_trigger(self) -> None: def diggital_trigger(self) -> None:
if not self.read_bit(channel=0): data = self.read_bit(channel=0)
self.write_bit(channel=0, bit=1) if data:
else:
self.write_bit(channel=0, bit=0) self.write_bit(channel=0, bit=0)
time.time_ns() time.time_ns()
self.write_bit(channel=0, bit=1) self.write_bit(channel=0, bit=1)
else:
self.write_bit(channel=0, bit=1)
def write_bit(self, channel: int = 0, bit: int = 1) -> None: def write_bit(self, channel: int = 0, bit: int = 1) -> None:
self.dio_device.d_config_bit( self.dio_device.d_config_bit(
@ -266,7 +271,7 @@ class MccDac:
log.info("Muting channel one") log.info("Muting channel one")
binary_db2 = "00000000" binary_db2 = "00000000"
channels_db = binary_db1 + binary_db2 channels_db = binary_db2 + binary_db1
self.write_bit(channel=4, bit=0) self.write_bit(channel=4, bit=0)
for b in channels_db: for b in channels_db:
self.write_bit(channel=5, bit=int(b)) self.write_bit(channel=5, bit=int(b))