Compare commits

...

12 Commits

12 changed files with 107 additions and 104 deletions

View File

@ -1,5 +1,8 @@
settings: 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/ path: ~/projects/pyrelacs/test/
metadata: metadata:
@ -16,9 +19,11 @@ pyrelacs:
data: data:
input: input:
inputsamplerate : 20 inputsamplerate : 20
# Unit is rescaled to Hz
inputsamplerateunit : kHz inputsamplerateunit : kHz
# BufferSize # BufferSize
inputtracecapacity : 600 inputtracecapacity : 600
# Unit is rescaled to s
inputtracecapacityunit : s inputtracecapacityunit : s
inputunipolar : false inputunipolar : false
inputtraceid : [ V-1, EOD, LocalEOD-1, GlobalEFieldStimulus ] inputtraceid : [ V-1, EOD, LocalEOD-1, GlobalEFieldStimulus ]
@ -56,8 +61,8 @@ pyrelacs:
devices: devices:
DAQFlexCore: DAQFlexCore:
analogoutputpins : [0,1] analogoutputpins : [0, 1]
analoginputpinshigh : [0,1,2,3,4,5,6,7] analoginputpinshigh : [0, 1, 2, 3,4,5,6,7]
analoginputpinslow : [1,2] analoginputpinslow : [1,2]
digitalpins : [0,1,2,3] digitalpins : [0,1,2,3]

View File

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

View File

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

View File

@ -41,7 +41,7 @@ class DaqProducer:
) )
# let the buffer for the daq device hold 5 seconds of data # 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) data_in = uldaq.create_float_buffer(channel_range.size, daq_buffer_size)
log.debug(f"Buffersize for daq {len(data_in)}") log.debug(f"Buffersize for daq {len(data_in)}")

View File

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

View File

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

View File

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

View File

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

View File

@ -44,10 +44,15 @@ class Repro:
else: else:
raise AttributeError(f"{file.name} has no {name} class") 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 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 Returns
------- -------
Tuple[list, list] Tuple[list, list]
@ -73,4 +78,7 @@ class Repro:
repro_names.extend(class_name) repro_names.extend(class_name)
file_names.append(python_file) file_names.append(python_file)
file.close() 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 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 pathlib import Path as path
from PyQt6.QtGui import QAction, QIcon, QKeySequence 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 ( from PyQt6.QtWidgets import (
QGridLayout, QGridLayout,
QToolBar, QToolBar,
@ -16,16 +16,17 @@ from PyQt6.QtWidgets import (
import uldaq import uldaq
import nixio as nix import nixio as nix
import pyqtgraph as pg import pyqtgraph as pg
import numpy as np
import quantities as pq 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.daq_producer import DaqProducer
from pyrelacs.dataio.nix_writer import NixWriter from pyrelacs.dataio.nix_writer import NixWriter
from pyrelacs.dataio.sin_producer import SinProducer from pyrelacs.dataio.sin_producer import SinProducer
from pyrelacs.worker import Worker from pyrelacs.worker import Worker
from pyrelacs.repros.repros import Repro from pyrelacs.repros.repros import Repro
from pyrelacs.dataio.circbuffer import CircBuffer
from pyrelacs.ui.about import AboutDialog from pyrelacs.ui.about import AboutDialog
from pyrelacs.ui.plots.calibration import CalibrationPlot from pyrelacs.ui.plots.calibration import CalibrationPlot
@ -42,28 +43,26 @@ from IPython import embed
class PyRelacs(QMainWindow): class PyRelacs(QMainWindow):
def __init__(self, config): def __init__(self, config):
super().__init__() super().__init__()
# loaded config
self.config = 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( self.setToolButtonStyle(
Qt.ToolButtonStyle.ToolButtonTextBesideIcon Qt.ToolButtonStyle.ToolButtonTextBesideIcon
) # Ensure icons are displayed with text ) # Ensure icons are displayed with text
self.setWindowTitle("PyRelacs") self.setWindowTitle("PyRelacs")
self.mutex = QMutex() self.mutex = QMutex()
self.timer = QTimer(self)
self.timer.setInterval(200)
self.figure = pg.GraphicsLayoutWidget() 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.threadpool = QThreadPool()
self.repros = Repro()
self.text = QPlainTextEdit() self.text = QPlainTextEdit()
self.text.setReadOnly(True) self.text.setReadOnly(True)
@ -84,33 +83,31 @@ class PyRelacs(QMainWindow):
SAMPLERATE = pq.Quantity( SAMPLERATE = pq.Quantity(
self.config.pyrelacs.data.input.inputsamplerate, self.config.pyrelacs.data.input.inputsamplerate,
self.config.pyrelacs.data.input.inputsamplerateunit, self.config.pyrelacs.data.input.inputsamplerateunit,
) ).rescale("Hz")
INPUTTRACECAPACITY = pq.Quantity( INPUTTRACECAPACITY = pq.Quantity(
self.config.pyrelacs.data.input.inputtracecapacity, self.config.pyrelacs.data.input.inputtracecapacity,
self.config.pyrelacs.data.input.inputtracecapacityunit, self.config.pyrelacs.data.input.inputtracecapacityunit,
) ).rescale("s")
start = time.time() start = time.time()
BUFFERSIZE = (SAMPLERATE * INPUTTRACECAPACITY).simplified BUFFERSIZE = (SAMPLERATE * INPUTTRACECAPACITY).simplified
end = time.time() end = time.time()
log.debug(f"Buffer allocation took {end - start}") log.debug(f"Buffer allocation took {end - start}")
self.buffer = CircBuffer( 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 = Continously(self.figure, self.buffer)
self.continously_plot.plot() self.continously_plot.plot()
start = time.time() if self.config.settings.daq:
self.connect_dac()
end = time.time()
log.debug(f"Connection to DAQ took {end - start}")
if hasattr(PyRelacs, "daq_device"):
log.debug("Creating Daq Generator") log.debug("Creating Daq Generator")
self.daq_producer = DaqProducer(self.buffer, self.daq_device, [1, 1]) self.daq_producer = DaqProducer(self.buffer, self.mccdaq.daq_device, [1, 1])
else:
log.debug("Creating Sinus Generator") log.debug("Creating Sinus Generator")
self.sinus_producer = SinProducer(self.buffer) self.sinus_producer = SinProducer(self.buffer)
self.nix_writer = NixWriter(self.buffer) self.nix_writer = NixWriter(self.buffer)
@ -128,16 +125,17 @@ class PyRelacs(QMainWindow):
self._daq_connectaction = QAction( self._daq_connectaction = QAction(
QIcon(":icons/connect.png"), "Connect DAQ", self QIcon(":icons/connect.png"), "Connect DAQ", self
) )
self._daq_connectaction.setStatusTip("Connect to daq device") if self.config.settings.daq:
# self._daq_connectaction.setShortcut(QKeySequence("Alt+d")) self._daq_connectaction.setStatusTip("Connect to daq device")
self._daq_connectaction.triggered.connect(self.connect_dac) # self._daq_connectaction.setShortcut(QKeySequence("Alt+d"))
self._daq_connectaction.triggered.connect(self.mccdaq.connect_dac)
self._daq_disconnectaction = QAction( self._daq_disconnectaction = QAction(
QIcon(":/icons/disconnect.png"), "Disconnect DAQ", self QIcon(":/icons/disconnect.png"), "Disconnect DAQ", self
) )
self._daq_disconnectaction.setStatusTip("Disconnect the DAQ device") self._daq_disconnectaction.setStatusTip("Disconnect the DAQ device")
# self._daq_connectaction.setShortcut(QKeySequence("Alt+d")) # self._daq_connectaction.setShortcut(QKeySequence("Alt+d"))
self._daq_disconnectaction.triggered.connect(self.disconnect_dac) self._daq_disconnectaction.triggered.connect(self.mccdaq.disconnect_daq)
# self._daq_calibaction = QAction( # self._daq_calibaction = QAction(
# QIcon(":/icons/calibration.png"), "Plot calibration", self # QIcon(":/icons/calibration.png"), "Plot calibration", self
@ -176,8 +174,9 @@ class PyRelacs(QMainWindow):
file_menu.addAction(self._rlx_aboutaction) file_menu.addAction(self._rlx_aboutaction)
if device_menu is not None: if device_menu is not None:
device_menu.addAction(self._daq_connectaction) if self.config.settings.daq:
device_menu.addAction(self._daq_disconnectaction) device_menu.addAction(self._daq_connectaction)
device_menu.addAction(self._daq_disconnectaction)
device_menu.addSeparator() device_menu.addSeparator()
# device_menu.addAction(self._daq_calibaction) # device_menu.addAction(self._daq_calibaction)
device_menu.addAction(self._run_action) device_menu.addAction(self._run_action)
@ -198,8 +197,9 @@ class PyRelacs(QMainWindow):
self.addToolBar(Qt.ToolBarArea.TopToolBarArea, rlx_toolbar) self.addToolBar(Qt.ToolBarArea.TopToolBarArea, rlx_toolbar)
daq_toolbar = QToolBar("DAQ") daq_toolbar = QToolBar("DAQ")
daq_toolbar.addAction(self._daq_connectaction) if self.config.settings.daq:
daq_toolbar.addAction(self._daq_disconnectaction) daq_toolbar.addAction(self._daq_connectaction)
daq_toolbar.addAction(self._daq_disconnectaction)
# daq_toolbar.addAction(self._daq_calibaction) # daq_toolbar.addAction(self._daq_calibaction)
daq_toolbar.addAction(self._run_action) daq_toolbar.addAction(self._run_action)
daq_toolbar.addAction(self._run_sinus_action) daq_toolbar.addAction(self._run_sinus_action)
@ -210,7 +210,9 @@ class PyRelacs(QMainWindow):
self.addToolBar(Qt.ToolBarArea.TopToolBarArea, daq_toolbar) self.addToolBar(Qt.ToolBarArea.TopToolBarArea, daq_toolbar)
repro_toolbar = QToolBar("Repros") 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): for rep, fn in zip(repro_names, file_names):
repro_action = QAction(rep, self) repro_action = QAction(rep, self)
repro_action.setStatusTip(rep) repro_action.setStatusTip(rep)
@ -271,24 +273,6 @@ class PyRelacs(QMainWindow):
log.debug("Stopping DAQ") log.debug("Stopping DAQ")
self.daq_producer.stop_aquisition() 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): def run_repro(self, n, fn):
self.text.appendPlainText(f"started Repro {n}, {fn}") self.text.appendPlainText(f"started Repro {n}, {fn}")
worker = Worker(self.repros.run_repro, self.nix_calibration, n, fn) worker = Worker(self.repros.run_repro, self.nix_calibration, n, fn)
@ -305,7 +289,8 @@ class PyRelacs(QMainWindow):
log.info("exit button!") log.info("exit button!")
self.stop_recording() self.stop_recording()
self.add_to_textfield("exiting") self.add_to_textfield("exiting")
self.disconnect_dac() if self.config.settings.daq:
self.mccdaq.disconnect_daq()
log.info("closing GUI") log.info("closing GUI")
self.close() self.close()

View File

@ -1,3 +1,5 @@
import time
import pyqtgraph as pg import pyqtgraph as pg
from IPython import embed from IPython import embed
import numpy as np import numpy as np
@ -24,7 +26,7 @@ class Continously:
pen = pg.mkPen("red") pen = pg.mkPen("red")
self.time = np.zeros(self.buffer.size) 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.line = self.continous_ax.plot(
self.time, self.time,
self.data, self.data,
@ -34,37 +36,32 @@ class Continously:
# self.plot_index = 0 # self.plot_index = 0
self.timer = QTimer() self.timer = QTimer()
self.CHUNK_PLOT = 10_000 self.CHUNK_PLOT = 500
self.timer.setInterval(200) 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.timeout.connect(self.update_plot)
self.timer.start() self.timer.start()
def update_plot(self): def update_plot(self):
# log.debug(self.buffer.totalcount()) current_index = self.buffer.write_index()
if self.buffer.totalcount() > self.CHUNK_PLOT: total_count = self.buffer.totalcount()
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
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( self.line.setData(
times, self.time,
items, 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: else:
pass pass