Compare commits

...

12 Commits

12 changed files with 107 additions and 104 deletions

View File

@ -1,5 +1,8 @@
settings:
repros: [calibration, sinus]
# If true daq should be used, else starts without daq
daq: False
# class names of the repros to run
repros: [Calibration, Sinus]
path: ~/projects/pyrelacs/test/
metadata:
@ -16,9 +19,11 @@ pyrelacs:
data:
input:
inputsamplerate : 20
# Unit is rescaled to Hz
inputsamplerateunit : kHz
# BufferSize
inputtracecapacity : 600
# Unit is rescaled to s
inputtracecapacityunit : s
inputunipolar : false
inputtraceid : [ V-1, EOD, LocalEOD-1, GlobalEFieldStimulus ]
@ -56,8 +61,8 @@ pyrelacs:
devices:
DAQFlexCore:
analogoutputpins : [0,1]
analoginputpinshigh : [0,1,2,3,4,5,6,7]
analogoutputpins : [0, 1]
analoginputpinshigh : [0, 1, 2, 3,4,5,6,7]
analoginputpinslow : [1,2]
digitalpins : [0,1,2,3]

View File

@ -21,6 +21,7 @@ class ValueUnit:
@dataclass
class Settings:
daq: bool
repros: list[str]
path: str

View File

@ -9,7 +9,7 @@ class CircBuffer:
self,
size: int,
channels: int = 1,
samplerate: int = 40_000,
samplerate: float = 40_000.0,
mutex: QMutex = QMutex(),
):
self.__size = size

View File

@ -41,7 +41,7 @@ class DaqProducer:
)
# let the buffer for the daq device hold 5 seconds of data
daq_buffer_size = self.buffer.samplerate * 5
daq_buffer_size = int(self.buffer.samplerate * 5)
data_in = uldaq.create_float_buffer(channel_range.size, daq_buffer_size)
log.debug(f"Buffersize for daq {len(data_in)}")

View File

@ -18,12 +18,12 @@ class NixWriter:
log.debug("Starting the writing")
self.write = True
while self.write:
log.debug(items)
# log.debug(items)
try:
data, _ = self.buffer.read(items, extend=chunk)
self.data_array.append(data)
except IndexError as e:
log.debug(f"{e}")
# log.debug(f"{e}")
continue
items += chunk
log.debug("Stoppint the writing")

View File

@ -8,7 +8,6 @@ from pyrelacs.util.logging import config_logging
log = config_logging()
# stopbutton: QAction
class SinProducer:
def __init__(
self,

View File

@ -41,13 +41,16 @@ class MccDaq:
try:
self.daq_device.connect()
except uldaq.ul_exception.ULException:
self.disconnect_dac()
self.disconnect_daq()
self.connect_dac()
self.ai_device = self.daq_device.get_ai_device()
self.ao_device = self.daq_device.get_ao_device()
self.dio_device = self.daq_device.get_dio_device()
log.debug("Connected")
log.debug("Connected to MccDaq")
log.debug("Activating the Attenuator")
self.activate_attenuator()
def connect_dac(self):
"""
@ -194,7 +197,7 @@ class MccDaq:
except Exception as e:
print(f"{e}")
self.set_analog_to_zero()
self.disconnect_dac()
self.disconnect_daq()
return data_analog_output
@ -224,7 +227,7 @@ class MccDaq:
except Exception as e:
log.error("f{e}")
log.error("disconnection dac")
self.disconnect_dac()
self.disconnect_daq()
def digital_trigger(self, ch: int = 0) -> None:
"""
@ -281,7 +284,9 @@ class MccDaq:
bit = self.dio_device.d_bit_in(uldaq.DigitalPortType.AUXPORT, channel)
return bit
def disconnect_dac(self):
def disconnect_daq(self):
log.debug("Disconnecting DAQ")
self.deactivate_attenuator()
self.daq_device.disconnect()
self.daq_device.release()
@ -329,12 +334,12 @@ class MccDaq:
except uldaq.ul_exception.ULException:
log.debug("Operation timed out")
self.write_bit(channel=0, bit=0)
self.disconnect_dac()
self.disconnect_daq()
self.connect_dac()
self.set_analog_to_zero()
finally:
self.write_bit(channel=0, bit=0)
self.disconnect_dac()
self.disconnect_daq()
self.connect_dac()
self.set_analog_to_zero()

View File

@ -71,7 +71,7 @@ class Calibration(MccDaq):
self.write_bit(channel=0, bit=0)
time.sleep(1)
self.set_analog_to_zero()
self.disconnect_dac()
self.disconnect_daq()
if i == 0:
ax.plot(t, stim, label=f"Input_{db_value}", color=colors[i])
@ -80,7 +80,7 @@ class Calibration(MccDaq):
ax.legend()
plt.show()
self.disconnect_dac()
self.disconnect_daq()
def check_beat(self, nix_file: nix.File):
self.set_attenuation_level(db_channel1=-10.0, db_channel2=0.0)

View File

@ -44,10 +44,15 @@ class Repro:
else:
raise AttributeError(f"{file.name} has no {name} class")
def names_of_repros(self) -> Tuple[list, list]:
def names_of_repros(self, include_repros: list[str]) -> Tuple[list, list]:
"""
Searches for class names in the repro folder in all python files
Parameters
----------
include_repros : list[str]
List of repros to include in the pyrelacs instance
Returns
-------
Tuple[list, list]
@ -73,4 +78,7 @@ class Repro:
repro_names.extend(class_name)
file_names.append(python_file)
file.close()
repro_names = [r for r in repro_names if r in include_repros]
file_names = [f for r, f in zip(repro_names, file_names) if r in include_repros]
return repro_names, file_names

3
pyrelacs/repros/sinus.py Normal file
View File

@ -0,0 +1,3 @@
class Sinus:
def __init__(self) -> None:
pass

View File

@ -2,7 +2,7 @@ import time
from pathlib import Path as path
from PyQt6.QtGui import QAction, QIcon, QKeySequence
from PyQt6.QtCore import Qt, QSize, QThreadPool, QMutex, QTimer
from PyQt6.QtCore import Qt, QSize, QThreadPool, QMutex
from PyQt6.QtWidgets import (
QGridLayout,
QToolBar,
@ -16,16 +16,17 @@ from PyQt6.QtWidgets import (
import uldaq
import nixio as nix
import pyqtgraph as pg
import numpy as np
import quantities as pq
from pyrelacs.devices.mccdaq import MccDaq
from pyrelacs.dataio.circbuffer import CircBuffer
from pyrelacs.dataio.daq_producer import DaqProducer
from pyrelacs.dataio.nix_writer import NixWriter
from pyrelacs.dataio.sin_producer import SinProducer
from pyrelacs.worker import Worker
from pyrelacs.repros.repros import Repro
from pyrelacs.dataio.circbuffer import CircBuffer
from pyrelacs.ui.about import AboutDialog
from pyrelacs.ui.plots.calibration import CalibrationPlot
@ -42,28 +43,26 @@ from IPython import embed
class PyRelacs(QMainWindow):
def __init__(self, config):
super().__init__()
# loaded config
self.config = config
if self.config.settings.daq:
start = time.time()
self.mccdaq = MccDaq()
end = time.time()
log.debug(f"Connection to DAQ took {end - start}")
self.repros = Repro()
self.setToolButtonStyle(
Qt.ToolButtonStyle.ToolButtonTextBesideIcon
) # Ensure icons are displayed with text
self.setWindowTitle("PyRelacs")
self.mutex = QMutex()
self.timer = QTimer(self)
self.timer.setInterval(200)
self.figure = pg.GraphicsLayoutWidget()
# filename = path.joinpath(path.cwd(), "data.nix")
# if filename.exists():
# self.nix_file = nix.File.open(str(filename), nix.FileMode.ReadOnly)
# filename = path.joinpath(path.cwd(), "calibration.nix")
# self.nix_file = nix.File.open(str(filename), nix.FileMode.Overwrite)
#
# self.calibration_plot = CalibrationPlot(self.figure, self.nix_file)
# self.nix_file.close()
self.threadpool = QThreadPool()
self.repros = Repro()
self.text = QPlainTextEdit()
self.text.setReadOnly(True)
@ -84,33 +83,31 @@ class PyRelacs(QMainWindow):
SAMPLERATE = pq.Quantity(
self.config.pyrelacs.data.input.inputsamplerate,
self.config.pyrelacs.data.input.inputsamplerateunit,
)
).rescale("Hz")
INPUTTRACECAPACITY = pq.Quantity(
self.config.pyrelacs.data.input.inputtracecapacity,
self.config.pyrelacs.data.input.inputtracecapacityunit,
)
).rescale("s")
start = time.time()
BUFFERSIZE = (SAMPLERATE * INPUTTRACECAPACITY).simplified
end = time.time()
log.debug(f"Buffer allocation took {end - start}")
self.buffer = CircBuffer(
size=BUFFERSIZE, samplerate=SAMPLERATE, mutex=self.mutex
size=int(BUFFERSIZE.base),
samplerate=float(SAMPLERATE.base),
mutex=self.mutex,
)
self.continously_plot = Continously(self.figure, self.buffer)
self.continously_plot.plot()
start = time.time()
self.connect_dac()
end = time.time()
log.debug(f"Connection to DAQ took {end - start}")
if hasattr(PyRelacs, "daq_device"):
if self.config.settings.daq:
log.debug("Creating Daq Generator")
self.daq_producer = DaqProducer(self.buffer, self.daq_device, [1, 1])
else:
log.debug("Creating Sinus Generator")
self.sinus_producer = SinProducer(self.buffer)
self.daq_producer = DaqProducer(self.buffer, self.mccdaq.daq_device, [1, 1])
log.debug("Creating Sinus Generator")
self.sinus_producer = SinProducer(self.buffer)
self.nix_writer = NixWriter(self.buffer)
@ -128,16 +125,17 @@ class PyRelacs(QMainWindow):
self._daq_connectaction = QAction(
QIcon(":icons/connect.png"), "Connect DAQ", self
)
self._daq_connectaction.setStatusTip("Connect to daq device")
# self._daq_connectaction.setShortcut(QKeySequence("Alt+d"))
self._daq_connectaction.triggered.connect(self.connect_dac)
if self.config.settings.daq:
self._daq_connectaction.setStatusTip("Connect to daq device")
# self._daq_connectaction.setShortcut(QKeySequence("Alt+d"))
self._daq_connectaction.triggered.connect(self.mccdaq.connect_dac)
self._daq_disconnectaction = QAction(
QIcon(":/icons/disconnect.png"), "Disconnect DAQ", self
)
self._daq_disconnectaction.setStatusTip("Disconnect the DAQ device")
# self._daq_connectaction.setShortcut(QKeySequence("Alt+d"))
self._daq_disconnectaction.triggered.connect(self.disconnect_dac)
self._daq_disconnectaction = QAction(
QIcon(":/icons/disconnect.png"), "Disconnect DAQ", self
)
self._daq_disconnectaction.setStatusTip("Disconnect the DAQ device")
# self._daq_connectaction.setShortcut(QKeySequence("Alt+d"))
self._daq_disconnectaction.triggered.connect(self.mccdaq.disconnect_daq)
# self._daq_calibaction = QAction(
# QIcon(":/icons/calibration.png"), "Plot calibration", self
@ -176,8 +174,9 @@ class PyRelacs(QMainWindow):
file_menu.addAction(self._rlx_aboutaction)
if device_menu is not None:
device_menu.addAction(self._daq_connectaction)
device_menu.addAction(self._daq_disconnectaction)
if self.config.settings.daq:
device_menu.addAction(self._daq_connectaction)
device_menu.addAction(self._daq_disconnectaction)
device_menu.addSeparator()
# device_menu.addAction(self._daq_calibaction)
device_menu.addAction(self._run_action)
@ -198,8 +197,9 @@ class PyRelacs(QMainWindow):
self.addToolBar(Qt.ToolBarArea.TopToolBarArea, rlx_toolbar)
daq_toolbar = QToolBar("DAQ")
daq_toolbar.addAction(self._daq_connectaction)
daq_toolbar.addAction(self._daq_disconnectaction)
if self.config.settings.daq:
daq_toolbar.addAction(self._daq_connectaction)
daq_toolbar.addAction(self._daq_disconnectaction)
# daq_toolbar.addAction(self._daq_calibaction)
daq_toolbar.addAction(self._run_action)
daq_toolbar.addAction(self._run_sinus_action)
@ -210,7 +210,9 @@ class PyRelacs(QMainWindow):
self.addToolBar(Qt.ToolBarArea.TopToolBarArea, daq_toolbar)
repro_toolbar = QToolBar("Repros")
repro_names, file_names = self.repros.names_of_repros()
repro_names, file_names = self.repros.names_of_repros(
include_repros=self.config.settings.repros
)
for rep, fn in zip(repro_names, file_names):
repro_action = QAction(rep, self)
repro_action.setStatusTip(rep)
@ -271,24 +273,6 @@ class PyRelacs(QMainWindow):
log.debug("Stopping DAQ")
self.daq_producer.stop_aquisition()
def connect_dac(self):
devices = uldaq.get_daq_device_inventory(uldaq.InterfaceType.USB)
try:
self.daq_device = uldaq.DaqDevice(devices[0])
log.debug(f"Found daq devices {len(devices)}, connecting to the first one")
self.daq_device.connect()
log.debug("connected")
except IndexError:
log.info("DAQ is not connected")
log.info("Please connect a DAQ device to the system")
def disconnect_dac(self):
try:
self.daq_device.disconnect()
self.daq_device.release()
except AttributeError:
log.debug("DAQ was not connected")
def run_repro(self, n, fn):
self.text.appendPlainText(f"started Repro {n}, {fn}")
worker = Worker(self.repros.run_repro, self.nix_calibration, n, fn)
@ -305,7 +289,8 @@ class PyRelacs(QMainWindow):
log.info("exit button!")
self.stop_recording()
self.add_to_textfield("exiting")
self.disconnect_dac()
if self.config.settings.daq:
self.mccdaq.disconnect_daq()
log.info("closing GUI")
self.close()

View File

@ -1,3 +1,5 @@
import time
import pyqtgraph as pg
from IPython import embed
import numpy as np
@ -24,7 +26,7 @@ class Continously:
pen = pg.mkPen("red")
self.time = np.zeros(self.buffer.size)
self.data = np.zeros(self.buffer.size)
self.data = np.empty(self.buffer.size)
self.line = self.continous_ax.plot(
self.time,
self.data,
@ -34,37 +36,32 @@ class Continously:
# self.plot_index = 0
self.timer = QTimer()
self.CHUNK_PLOT = 10_000
self.timer.setInterval(200)
self.CHUNK_PLOT = 500
self.PLOT_HISTORY = 500_000 # The amount of data you want to keep on screen
self.last_plotted_index = 0
self.timer.setInterval(150)
self.timer.timeout.connect(self.update_plot)
self.timer.start()
def update_plot(self):
# log.debug(self.buffer.totalcount())
if self.buffer.totalcount() > self.CHUNK_PLOT:
log.debug(self.buffer.totalcount())
try:
times, items = self.buffer.read(
self.buffer.write_index() - self.CHUNK_PLOT - 1_000,
extend=self.CHUNK_PLOT,
)
except IndexError as e:
items = np.zeros(self.CHUNK_PLOT)
times = np.zeros(self.CHUNK_PLOT)
log.debug("No Data Available")
log.debug(f"Index Error {e}")
# self.time = np.roll(self.time, -len(items))
# self.data = np.roll(self.data, -len(items))
#
# self.time[-len(times) :] = times
# self.data[-len(items) :] = items
current_index = self.buffer.write_index()
total_count = self.buffer.totalcount()
start_time = time.time()
if total_count - self.last_plotted_index >= self.CHUNK_PLOT:
times, items = self.buffer.read(
self.last_plotted_index,
extend=self.CHUNK_PLOT,
)
self.time = np.concatenate((self.time, times))[-self.PLOT_HISTORY :]
self.data = np.concatenate((self.data, items))[-self.PLOT_HISTORY :]
self.line.setData(
times,
items,
self.time,
self.data,
)
# self.plot_index += len(items)
self.last_plotted_index += self.CHUNK_PLOT
end_time = time.time()
log.debug(f"total time for plotting {end_time - start_time}")
else:
pass