2
0
forked from awendt/pyrelacs
This commit is contained in:
Jan Grewe 2024-09-27 09:17:34 +02:00
commit 291ed8859c
11 changed files with 406 additions and 243 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

@ -27,6 +27,7 @@ numpy = "^2.1.1"
pyqt6 = "^6.7.1" pyqt6 = "^6.7.1"
tomli = "^2.0.1" tomli = "^2.0.1"
tomlkit = "^0.13.2" tomlkit = "^0.13.2"
scipy = "^1.14.1"
[tool.poetry.scripts] [tool.poetry.scripts]
pyrelacs = "pyrelacs.app:main" pyrelacs = "pyrelacs.app:main"

View File

@ -1,7 +1,6 @@
from PyQt6.QtGui import QAction from PyQt6.QtGui import QAction
import sys import sys
import pathlib import pathlib
import ctypes
from PyQt6.QtCore import QProcess, QSize, QThreadPool, Qt, QSettings from PyQt6.QtCore import QProcess, QSize, QThreadPool, Qt, QSettings
from PyQt6.QtWidgets import ( from PyQt6.QtWidgets import (
@ -13,13 +12,14 @@ from PyQt6.QtWidgets import (
QMainWindow, QMainWindow,
QPlainTextEdit, QPlainTextEdit,
) )
import tomli
import uldaq import uldaq
from IPython import embed from IPython import embed
import numpy as np import numpy as np
from pyrelacs.util.logging import config_logging from pyrelacs.util.logging import config_logging
import pyrelacs.info as info import pyrelacs.info as info
from pyrelacs.worker import Worker
from pyrelacs.repros.repros import Repro
log = config_logging() log = config_logging()
@ -31,8 +31,7 @@ class PyRelacs(QMainWindow):
self.setMinimumSize(1000, 1000) self.setMinimumSize(1000, 1000)
self.threadpool = QThreadPool() self.threadpool = QThreadPool()
# for starting a Qprocess self.repros = Repro()
self.p = None
self.daq_connect_button = QPushButton("Connect Daq") self.daq_connect_button = QPushButton("Connect Daq")
self.daq_connect_button.setCheckable(True) self.daq_connect_button.setCheckable(True)
@ -52,7 +51,7 @@ class PyRelacs(QMainWindow):
self.toolbar = QToolBar("Repros") self.toolbar = QToolBar("Repros")
self.addToolBar(self.toolbar) self.addToolBar(self.toolbar)
self.repro() self.repros_to_toolbar()
self.setFixedSize(QSize(400, 300)) self.setFixedSize(QSize(400, 300))
widget = QWidget() widget = QWidget()
@ -82,60 +81,18 @@ class PyRelacs(QMainWindow):
except AttributeError: except AttributeError:
log.debug("DAQ was not connected") log.debug("DAQ was not connected")
def repro(self): def repros_to_toolbar(self):
repos_path = pathlib.Path(__file__).parent / "repros" repro_names, file_names = self.repros.names_of_repros()
repos_names = list(repos_path.glob("*.py")) for rep, fn in zip(repro_names, file_names):
# exclude the repos.py file
repos_names = [
f.with_suffix("").name for f in repos_names if not f.name == "repos.py"
]
for rep in repos_names:
individual_repro_button = QAction(rep, self) individual_repro_button = QAction(rep, self)
individual_repro_button.setStatusTip("Button") individual_repro_button.setStatusTip("Button")
individual_repro_button.triggered.connect( individual_repro_button.triggered.connect(
lambda checked, n=rep: self.run_repro(n) lambda checked, n=rep, f=fn: self.run_repro(n, f)
) )
self.toolbar.addAction(individual_repro_button) self.toolbar.addAction(individual_repro_button)
def message(self, s): def run_repro(self, n, fn):
self.text.appendPlainText(s) self.text.appendPlainText(f"started Repro {n}, {fn}")
def run_repro(self, name_of_repo):
if self.p is None:
self.message(f"Executing process {name_of_repo}")
self.p = QProcess()
self.p.setWorkingDirectory(str(pathlib.Path(__file__).parent / "repros/"))
# log.debug(pathlib.Path(__file__).parent / "repos")
self.p.readyReadStandardOutput.connect(self.handle_stdout)
self.p.readyReadStandardError.connect(self.handle_stderr)
self.p.stateChanged.connect(self.handle_state)
self.p.finished.connect(self.process_finished)
self.p.start("python3", [f"{name_of_repo}" + ".py"])
def handle_stderr(self):
if self.p is not None:
data = self.p.readAllStandardError()
stderr = bytes(data).decode("utf8")
self.message(stderr)
def handle_stdout(self):
if self.p is not None:
data = self.p.readAllStandardOutput()
stdout = bytes(data).decode("utf8")
self.message(stdout)
def handle_state(self, state):
states = {
QProcess.ProcessState.NotRunning: "Not running",
QProcess.ProcessState.Starting: "Starting",
QProcess.ProcessState.Running: "Running",
}
state_name = states[state]
self.message(f"State changed: {state_name}")
def process_finished(self):
self.text.appendPlainText("Process finished")
self.p = None
def main(): def main():

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))

View File

View File

@ -1,14 +1,16 @@
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 welch, csd
from scipy.signal import find_peaks
from pyrelacs.repros.mccdac import MccDac from pyrelacs.devices.mccdac import MccDac
from pyrelacs.util.logging import config_logging from pyrelacs.util.logging import config_logging
log = config_logging() log = config_logging()
@ -18,50 +20,232 @@ faulthandler.enable()
class Calibration(MccDac): class Calibration(MccDac):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
self.SAMPLERATE = 40_000.0
self.DURATION = 5
self.AMPLITUDE = 1
self.SINFREQ = 750
def run(self):
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, self.DURATION, 1 / self.SAMPLERATE)
data = AMPLITUDE * np.sin(2 * np.pi * SINFREQ * t) data = self.AMPLITUDE * np.sin(2 * np.pi * self.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):
stim = self.write_analog( self.set_attenuation_level(db_channel1=db_value, db_channel2=db_value)
data, log.debug(f"{db_value}")
[0, 0],
SAMPLERATE, stim = self.write_analog(
ScanOption=uldaq.ScanOption.EXTTRIGGER, data,
) [0, 0],
data_channel_one = self.read_analog( self.SAMPLERATE,
[0, 0], DURATION, SAMPLERATE, ScanOption=uldaq.ScanOption.EXTTRIGGER ScanOption=uldaq.ScanOption.EXTTRIGGER,
) )
time.sleep(1)
data_channel_one = self.read_analog(
self.diggital_trigger() [0, 0], self.DURATION, self.SAMPLERATE, ScanOption=uldaq.ScanOption.EXTTRIGGER
)
try:
self.ai_device.scan_wait(uldaq.WaitType.WAIT_UNTIL_DONE, 15)
self.write_bit(channel=0, bit=0)
time.sleep(1) time.sleep(1)
self.set_analog_to_zero()
except uldaq.ul_exception.ULException: log.debug("Starting the Scan")
log.debug("Operation timed out") self.diggital_trigger()
# reset the 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, self.DURATION, 1 / self.SAMPLERATE)
data = self.AMPLITUDE * np.sin(2 * np.pi * self.SINFREQ * t)
# data = np.concatenate((data, data))
db_values = [0.0, -5.0, -8.5, -10.0]
colors = ["red", "blue", "black", "green"]
colors_in = ["lightcoral", "lightblue", "grey", "lightgreen"]
fig, axes = plt.subplots(2, 2, sharex="col")
for i, db_value in enumerate(db_values):
self.set_attenuation_level(db_channel1=db_value)
stim = self.write_analog(
data,
[0, 0],
self.SAMPLERATE,
ScanOption=uldaq.ScanOption.EXTTRIGGER,
)
readout = self.read_analog(
[0, 1],
self.DURATION,
self.SAMPLERATE,
ScanOption=uldaq.ScanOption.EXTTRIGGER,
)
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
log.debug(
f"Status Analog_output {ao_status}\n, Status Analog_input {ai_status}"
)
while (ai_status != uldaq.ScanStatus.IDLE) and (
ao_status != uldaq.ScanStatus.IDLE
):
# log.debug("Scanning")
time.time_ns()
ai_status = self.ai_device.get_scan_status()[0]
ao_status = self.ao_device.get_scan_status()[0]
self.write_bit(channel=0, bit=0) self.write_bit(channel=0, bit=0)
time.sleep(1) log.debug(
self.set_analog_to_zero() f"Status Analog_output {ao_status}\n, Status Analog_input {ai_status}"
self.disconnect_dac() )
embed() channel1 = np.array(readout[::2])
exit() channel2 = np.array(readout[1::2])
beat = channel1 + channel2
beat_square = beat**2
f, powerspec = welch(beat, fs=self.SAMPLERATE)
powerspec = decibel(powerspec)
f_sq, powerspec_sq = welch(beat_square, fs=self.SAMPLERATE)
powerspec_sq = decibel(powerspec_sq)
peaks = find_peaks(powerspec_sq, prominence=20)[0]
f_stim, powerspec_stim = welch(channel1, fs=self.SAMPLERATE)
powerspec_stim = decibel(powerspec_stim)
f_in, powerspec_in = welch(channel2, fs=self.SAMPLERATE)
powerspec_in = decibel(powerspec_in)
axes[0, 0].plot(
t,
channel1,
label=f"{db_value} Readout Channel0",
color=colors[i],
)
axes[0, 0].plot(
t,
channel2,
label=f"{db_value} Readout Channel1",
color=colors_in[i],
)
axes[0, 1].plot(
f_stim,
powerspec_stim,
label=f"{db_value} powerspec Channel0",
color=colors[i],
)
axes[0, 1].plot(
f_in,
powerspec_in,
label=f"{db_value} powerspec Channel2",
color=colors_in[i],
)
axes[0, 1].set_xlabel("Freq [HZ]")
axes[0, 1].set_ylabel("dB")
axes[1, 0].plot(
t,
beat,
label="Beat",
color=colors[i],
)
axes[1, 0].plot(
t,
beat**2,
label="Beat squared",
color=colors_in[i],
)
axes[1, 0].legend()
axes[1, 1].plot(
f,
powerspec,
color=colors[i],
)
axes[1, 1].plot(
f_sq,
powerspec_sq,
color=colors_in[i],
label=f"dB {db_value}, first peak {np.min(f_sq[peaks])}",
)
axes[1, 1].scatter(
f_sq[peaks],
powerspec_sq[peaks],
color="maroon",
)
axes[1, 1].set_xlabel("Freq [HZ]")
axes[1, 1].set_ylabel("dB")
axes[0, 0].legend()
axes[1, 1].legend()
plt.show()
self.set_analog_to_zero()
self.disconnect_dac()
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`.
if __name__ == "__main__": Parameters
SAMPLERATE = 40_000.0 ----------
DURATION = 5 power: float or array
AMPLITUDE = 0.5 Power values, for example from a power spectrum or spectrogram.
SINFREQ = 10 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`.
cal = Calibration() Returns
# cal.ccheck_attenuator() -------
cal.check_amplitude() 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

View File

@ -1,86 +0,0 @@
import ctypes
import uldaq
from IPython import embed
import matplotlib.pyplot as plt
import numpy as np
from pyrelacs.util.logging import config_logging
log = config_logging()
class ReadWrite:
def __init__(self) -> None:
devices = uldaq.get_daq_device_inventory(uldaq.InterfaceType.USB)
log.debug(f"Found daq devices {len(devices)}, connecting to the first one")
self.daq_device = uldaq.DaqDevice(devices[0])
self.daq_device.connect()
log.debug("Connected")
# self.daq_device.enable_event(
# uldaq.DaqEventType.ON_DATA_AVAILABLE,
# 1,
# self.read_write,
# (uldaq.DaqEventType.ON_DATA_AVAILABLE, 1, 1),
# )
def read_write(self) -> None:
# event_type = callback_args.event_type
# event_data = callback_args.event_data
# user_data = callback_args.user_data
FS = 30_000.0
DURATION = 10
FREQUENCY = 100
time = np.arange(0, DURATION, 1 / FS)
data = 2 * np.sin(2 * np.pi * FREQUENCY * time)
buffer = ctypes.c_double * len(time)
data_c = buffer(*data)
buf = uldaq.create_float_buffer(1, len(time))
# Get the Ananlog In device and Analog Info
ai_device = self.daq_device.get_ai_device()
ai_info = ai_device.get_info()
# Get the Analog Out device
ao_device = self.daq_device.get_ao_device()
ao_info = ao_device.get_info()
er_ao = ao_device.a_out_scan(
0,
0,
uldaq.Range.BIP10VOLTS,
int(len(data)),
30_000.0,
uldaq.ScanOption.DEFAULTIO,
uldaq.AOutScanFlag.DEFAULT,
data_c,
)
er_ai = ai_device.a_in_scan(
1,
1,
uldaq.AiInputMode.SINGLE_ENDED,
uldaq.Range.BIP10VOLTS,
len(time),
FS,
uldaq.ScanOption.DEFAULTIO,
uldaq.AInScanFlag.DEFAULT,
data=buf,
)
ai_device.scan_wait(uldaq.WaitType.WAIT_UNTIL_DONE, timeout=-1)
log.debug("Scanning")
self.daq_device.disconnect()
self.daq_device.release()
plt.plot(buf)
plt.plot(data_c)
plt.show()
if __name__ == "__main__":
daq_input = ReadWrite()
daq_input.read_write()

View File

@ -1,28 +0,0 @@
import uldaq
import matplotlib.pyplot as plt
from pyrelacs.util.logging import config_logging
from .repos import MccDac
log = config_logging()
class ReadData(MccDac):
def __init__(self) -> None:
super().__init__()
def analog_in(self) -> None:
# Get the Ananlog In device and Analog Info
data = self.read_analog_daq(
[0, 0],
10,
3000.0,
)
plt.plot(data)
plt.show()
self.disconnect_dac()
if __name__ == "__main__":
daq_input = ReadData()
daq_input.analog_in()

View File

@ -1,28 +0,0 @@
import ctypes
import uldaq
from IPython import embed
from pyrelacs.repros.repos import MccDac
from pyrelacs.util.logging import config_logging
import numpy as np
import matplotlib.pyplot as plt
log = config_logging()
class Output_daq(MccDac):
def __init__(self) -> None:
super().__init__()
def write_daq(self):
log.debug("running repro")
time = np.arange(0, 10, 1 / 30_000.0)
data = 1 * np.sin(2 * np.pi * 1 * time)
self.write_analog(data, [0, 0], 30_000, ScanOption=uldaq.ScanOption.EXTTRIGGER)
self.diggital_trigger()
if __name__ == "__main__":
daq_input = Output_daq()
daq_input.write_daq()
# daq_input.trigger()

33
pyrelacs/repros/repros.py Normal file
View File

@ -0,0 +1,33 @@
import ast
import pathlib
from IPython import embed
class Repro:
def __init__(self) -> None:
pass
def run_repro(self, name: str, *args, **kwargs) -> None:
pass
def names_of_repros(self):
file_path_cur = pathlib.Path(__file__).parent
python_files = list(file_path_cur.glob("**/*.py"))
exclude_files = ["repros.py", "__init__.py"]
python_files = [f for f in python_files if f.name not in exclude_files]
repro_names = []
file_names = []
for python_file in python_files:
with open(python_file, "r") as file:
file_content = file.read()
tree = ast.parse(file_content)
class_name = [
node.name
for node in ast.walk(tree)
if isinstance(node, ast.ClassDef)
]
repro_names.extend(class_name)
file_names.append(python_file)
file.close()
return repro_names, file_names

75
pyrelacs/worker.py Normal file
View File

@ -0,0 +1,75 @@
import sys
import traceback
from PyQt6.QtCore import QRunnable, pyqtSlot, QObject, pyqtSignal
class WorkerSignals(QObject):
"""
Defines the signals available from a running worker thread.
Supported signals are:
finished
No data
error
tuple (exctype, value, traceback.format_exc() )
result
object data returned from processing, anything
progress
int indicating % progress
"""
finished = pyqtSignal()
error = pyqtSignal(tuple)
result = pyqtSignal(object)
progress = pyqtSignal(int)
class Worker(QRunnable):
"""
Worker thread
Inherits from QRunnable to handler worker thread setup, signals and wrap-up.
:param callback: The function callback to run on this worker thread. Supplied args and
kwargs will be passed through to the runner.
:type callback: function
:param args: Arguments to pass to the callback function
:param kwargs: Keywords to pass to the callback function
"""
def __init__(self, fn, *args, **kwargs):
super(Worker, self).__init__()
# Store constructor arguments (re-used for processing)
self.fn = fn
self.args = args
self.kwargs = kwargs
self.signals = WorkerSignals()
# Add the callback to our kwargs
self.kwargs["progress_callback"] = self.signals.progress
@pyqtSlot()
def run(self):
"""
Initialise the runner function with passed args, kwargs.
"""
# Retrieve args/kwargs here; and fire processing using them
try:
result = self.fn(*self.args, **self.kwargs)
except:
traceback.print_exc()
exctype, value = sys.exc_info()[:2]
self.signals.error.emit((exctype, value, traceback.format_exc()))
else:
self.signals.result.emit(result) # Return the result of the processing
finally:
self.signals.finished.emit() # Done