Compare commits

...

9 Commits

5 changed files with 241 additions and 98 deletions

View File

@ -1,9 +1,11 @@
settings: settings:
# If true daq should be used, else starts without daq # If true daq should be used, else starts without daq
daq: False daq: True
# class names of the repros to run # class names of the repros to run
repros: [Calibration, Sinus] repros: [Calibration, Sinus]
path: ~/projects/pyrelacs/test/ path: ~/projects/pyrelacs/test/
# string to append after the file name
postappend: ehpys
metadata: metadata:
SetupName : Setup1 SetupName : Setup1

View File

@ -21,7 +21,6 @@ class DaqProducer:
self.device = device self.device = device
self.ai_device = self.device.get_ai_device() self.ai_device = self.device.get_ai_device()
self.channels = channels self.channels = channels
self.stop = False self.stop = False
def read_analog_continously( def read_analog_continously(
@ -41,7 +40,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 = int(self.buffer.samplerate * 5) daq_buffer_size = int(self.buffer.samplerate * 30)
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)}")
@ -70,7 +69,12 @@ class DaqProducer:
prev_count = 0 prev_count = 0
prev_index = 0 prev_index = 0
while not self.stop: while not self.stop:
try:
daq_status, transfer_status = self.ai_device.get_scan_status() daq_status, transfer_status = self.ai_device.get_scan_status()
except uldaq.ul_exception.ULException as e:
log.error("Could not get the scan status")
log.error("Stopping writting")
break
# The index into the data buffer immediately following the last sample transferred. # The index into the data buffer immediately following the last sample transferred.
current_index = transfer_status.current_index current_index = transfer_status.current_index
# total samples since start of the scan # total samples since start of the scan
@ -79,7 +83,7 @@ class DaqProducer:
channel_samples = transfer_status.current_scan_count channel_samples = transfer_status.current_scan_count
new_data_count = total_samples - prev_count new_data_count = total_samples - prev_count
# check if counts if new data is bigger than the buffer # check if new data is bigger than the buffer
# if that happends stop the acquisition # if that happends stop the acquisition
if new_data_count > len(data_in): if new_data_count > len(data_in):
self.ai_device.scan_stop() self.ai_device.scan_stop()
@ -92,23 +96,54 @@ class DaqProducer:
if prev_index + chunk_size > len(data_in) - 1: if prev_index + chunk_size > len(data_in) - 1:
log.debug("Chunk wraps around buffersize") log.debug("Chunk wraps around buffersize")
first_chunk = len(data_in) - prev_index first_chunk = len(data_in) - prev_index
data_first_channel = data_in[
prev_index : prev_index + first_chunk : 2
]
data_second_channel = data_in[
prev_index + 1 : prev_index + first_chunk : 2
]
[ [
self.buffer.append(data_in[prev_index + i]) self.buffer.append(data_first_channel[i], channel=0)
for i in range(first_chunk) for i in range(int(first_chunk / 2))
]
[
self.buffer.append(data_second_channel[i], channel=1)
for i in range(int(first_chunk / 2))
] ]
second_chunk = chunk_size - first_chunk second_chunk = chunk_size - first_chunk
data_first_channel = data_in[0:second_chunk:2]
data_second_channel = data_in[1:second_chunk:2]
[ [
self.buffer.append(data_in[i]) self.buffer.append(data_first_channel[i], channel=0)
for i in range(second_chunk) for i in range(int(second_chunk / 2))
]
[
self.buffer.append(data_second_channel[i], channel=1)
for i in range(int(second_chunk / 2))
] ]
else: else:
log.debug("Writing chunk to buffer") log.debug("Writing chunk to buffer")
# appending to the first channel
data_first_channel = data_in[
prev_index : prev_index + chunk_size : 2
]
data_second_channel = data_in[
prev_index + 1 : prev_index + chunk_size : 2
]
[ [
self.buffer.append(data_in[prev_index + i]) self.buffer.append(data_first_channel[i], channel=0)
for i in range(chunk_size) for i in range(int(chunk_size / 2))
] ]
self.buffer.append(data_in[current_index]) [
self.buffer.append(data_second_channel[i], channel=1)
for i in range(int(chunk_size / 2))
]
if total_samples - prev_count > len(data_in): if total_samples - prev_count > len(data_in):
self.ai_device.scan_stop() self.ai_device.scan_stop()
@ -124,33 +159,70 @@ class DaqProducer:
self.ai_device.scan_stop() self.ai_device.scan_stop()
daq_status, transfer_status = self.ai_device.get_scan_status() daq_status, transfer_status = self.ai_device.get_scan_status()
current_index = transfer_status.current_index
log.debug(daq_status) log.debug(daq_status)
chunk_size = transfer_status.current_total_count - prev_count
log.debug(transfer_status.current_index) log.debug(f"DAQ current index {transfer_status.current_index}")
log.debug(transfer_status.current_total_count) log.debug(f"DAQ total count {transfer_status.current_total_count}")
log.debug(transfer_status.current_scan_count) log.debug(
log.debug(self.buffer.totalcount()) f"DAQ Samples per channel {transfer_status.current_scan_count}"
)
log.debug("Appending last chunk") log.debug("Appending last chunk")
if prev_index + chunk_size > len(data_in) - 1: if prev_index + chunk_size > len(data_in) - 1:
log.debug("Chunk wraps around buffersize") log.debug("Chunk wraps around buffersize")
first_chunk = len(data_in) - prev_index first_chunk = len(data_in) - prev_index
data_first_channel = data_in[
prev_index : prev_index + first_chunk : 2
]
data_second_channel = data_in[
prev_index + 1 : prev_index + first_chunk : 2
]
[ [
self.buffer.append(data_in[prev_index + i]) self.buffer.append(data_first_channel[i], channel=0)
for i in range(first_chunk) for i in range(int(first_chunk / 2))
]
[
self.buffer.append(data_second_channel[i], channel=1)
for i in range(int(first_chunk / 2))
] ]
second_chunk = chunk_size - first_chunk second_chunk = chunk_size - first_chunk
[self.buffer.append(data_in[i]) for i in range(second_chunk)] data_first_channel = data_in[0:second_chunk:2]
data_second_channel = data_in[1:second_chunk:2]
[
self.buffer.append(data_first_channel[i], channel=0)
for i in range(int(second_chunk / 2))
]
[
self.buffer.append(data_second_channel[i], channel=1)
for i in range(int(second_chunk / 2))
]
else: else:
log.debug("Writing chunk to buffer") log.debug("Writing chunk to buffer")
# appending to the first channel
data_first_channel = data_in[
prev_index : prev_index + chunk_size : 2
]
data_second_channel = data_in[
prev_index + 1 : prev_index + chunk_size : 2
]
[ [
self.buffer.append(data_in[prev_index + i]) self.buffer.append(data_first_channel[i], channel=0)
for i in range(chunk_size) for i in range(int(chunk_size / 2))
] ]
self.buffer.append(data_in[current_index]) [
self.buffer.append(data_second_channel[i], channel=1)
for i in range(int(chunk_size / 2))
]
log.info("stopping") log.info("stopping")
log.debug(self.buffer.totalcount())
log.debug(self.ai_device.get_scan_status())
break break
break break

View File

@ -1,4 +1,9 @@
from datetime import datetime
import itertools
import string
import time import time
from dataclasses import asdict
from IPython import embed from IPython import embed
from PyQt6.QtCore import QMutex from PyQt6.QtCore import QMutex
import nixio import nixio
@ -10,8 +15,9 @@ log = config_logging()
class NixWriter: class NixWriter:
def __init__(self, buffer: CircBuffer) -> None: def __init__(self, buffer: CircBuffer, config) -> None:
self.buffer = buffer self.buffer = buffer
self.config = config
def write_nix( def write_nix(
self, self,
@ -62,11 +68,42 @@ class NixWriter:
log.debug(f"Samples written {index}") log.debug(f"Samples written {index}")
def _write_header(self): def _write_header(self):
"""
Writing the header of the nix file
"""
self.nix_file = nixio.File.open(path="data.nix", mode=nixio.FileMode.Overwrite) self.nix_file = nixio.File.open(path="data.nix", mode=nixio.FileMode.Overwrite)
self.block = self.nix_file.create_block("recording", "testfile") self.block = self.nix_file.create_block("recording", "testfile")
self.data_array = self.block.create_data_array( self.data_array = self.block.create_data_array(
"Analog1", "ndarray", shape=(1000,), dtype=nixio.DataType.Double "Analog1", "ndarray", shape=(1000,), dtype=nixio.DataType.Double
) )
def generate_letter_sequence(self):
alphabet = string.ascii_lowercase
for size in range(2, 3):
for combo in itertools.product(alphabet, repeat=size):
yield "".join(combo)
def create_nix_file(self, file_path, metadata):
data_time = datetime.now().strftime("%Y-%m-%t_%H-%M-%S")
sequence_generator = self.generate_letter_sequence()
sequence = next(sequence_generator)
self.nix_file = nixio.File.open(
path=f"{file_path}/{data_time}_{sequence}.nix",
mode=nixio.FileMode.Overwrite,
)
self.block = self.nix_file.create_block("recording", "testfile")
self.section = self.nix_file.create_section("metadata", "config.yaml")
for key, value in asdict(metadata).items():
self.section[key] = value
self.data_array_analog1 = self.block.create_data_array(
"Analog1", "ndarray", shape=(1000,), dtype=nixio.DataType.Double
)
self.data_array_analog2 = self.block.create_data_array(
"Analog2", "ndarray", shape=(1000,), dtype=nixio.DataType.Double
)
return self.data_array_analog1, self.data_array_analog2
def stop_writing(self): def stop_writing(self):
self.write = False self.write = False

View File

@ -10,7 +10,6 @@ from PyQt6.QtWidgets import (
QPushButton, QPushButton,
QTabWidget, QTabWidget,
QToolBar, QToolBar,
QVBoxLayout,
QWidget, QWidget,
QMainWindow, QMainWindow,
QPlainTextEdit, QPlainTextEdit,
@ -50,6 +49,8 @@ class PyRelacs(QMainWindow):
super().__init__() super().__init__()
# loaded config # loaded config
self.config = config self.config = config
# check if daq is connencted else None
if self.config.settings.daq: if self.config.settings.daq:
start = time.time() start = time.time()
self.mccdaq = MccDaq() self.mccdaq = MccDaq()
@ -65,8 +66,6 @@ class PyRelacs(QMainWindow):
) # Ensure icons are displayed with text ) # Ensure icons are displayed with text
self.setWindowTitle("PyRelacs") self.setWindowTitle("PyRelacs")
self.create_nix_file(f"{_root}/test.nix", self.config.metadata)
self.mutex = QMutex() self.mutex = QMutex()
self.figure = pg.GraphicsLayoutWidget() self.figure = pg.GraphicsLayoutWidget()
@ -76,22 +75,6 @@ class PyRelacs(QMainWindow):
self.text = QPlainTextEdit() self.text = QPlainTextEdit()
self.text.setReadOnly(True) self.text.setReadOnly(True)
self.setMenuBar(QMenuBar(self))
self.setStatusBar(QStatusBar(self))
self.create_actions()
self.create_toolbars()
self.repro_tabs = QTabWidget()
self.create_repros_tabs()
layout = QGridLayout()
layout.addWidget(self.figure, 0, 0, 2, 2)
layout.addWidget(self.repro_tabs, 2, 0, 2, 2)
layout.addWidget(self.text, 4, 0, 1, 1)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
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,
@ -109,6 +92,7 @@ class PyRelacs(QMainWindow):
self.buffer = CircBuffer( self.buffer = CircBuffer(
size=int(BUFFERSIZE.base), size=int(BUFFERSIZE.base),
samplerate=float(SAMPLERATE.base), samplerate=float(SAMPLERATE.base),
channels=2,
mutex=self.mutex, mutex=self.mutex,
) )
self.continously_plot = Continously(self.figure, self.buffer) self.continously_plot = Continously(self.figure, self.buffer)
@ -116,11 +100,26 @@ class PyRelacs(QMainWindow):
if self.mccdaq: if self.mccdaq:
log.debug("Creating Daq Generator") log.debug("Creating Daq Generator")
self.daq_producer = DaqProducer(self.buffer, self.mccdaq.daq_device, [1, 1]) self.daq_producer = DaqProducer(self.buffer, self.mccdaq.daq_device, [4, 5])
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, self.config)
self.setMenuBar(QMenuBar(self))
self.setStatusBar(QStatusBar(self))
self.create_actions()
self.create_toolbars()
self.repro_tabs = QTabWidget()
self.create_repros_tabs()
layout = QGridLayout()
layout.addWidget(self.figure, 0, 0, 2, 2)
layout.addWidget(self.repro_tabs, 2, 0, 2, 2)
layout.addWidget(self.text, 4, 0, 1, 1)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
def create_actions(self): def create_actions(self):
self._rlx_exitaction = QAction(QIcon(":/icons/exit.png"), "Exit", self) self._rlx_exitaction = QAction(QIcon(":/icons/exit.png"), "Exit", self)
@ -224,10 +223,6 @@ class PyRelacs(QMainWindow):
repro_names, file_names = self.repros.names_of_repros( repro_names, file_names = self.repros.names_of_repros(
include_repros=self.config.settings.repros include_repros=self.config.settings.repros
) )
nix_blocks = {
rep: self.nix_file.create_block(f"{rep}", "Data Repro")
for rep in repro_names
}
figures_repros = {rep: pg.GraphicsLayoutWidget() for rep in repro_names} figures_repros = {rep: pg.GraphicsLayoutWidget() for rep in repro_names}
for rep, fn in zip(repro_names, file_names): for rep, fn in zip(repro_names, file_names):
tab = QWidget() tab = QWidget()
@ -239,7 +234,6 @@ class PyRelacs(QMainWindow):
lambda checked, n=rep, f=fn: self.run_repro( lambda checked, n=rep, f=fn: self.run_repro(
n, n,
f, f,
nix_blocks,
figures_repros, figures_repros,
self.mccdaq, self.mccdaq,
self.config, self.config,
@ -254,20 +248,18 @@ class PyRelacs(QMainWindow):
self, self,
name_of_repro: str, name_of_repro: str,
file_of_repro: str, file_of_repro: str,
nix_block,
figures, figures,
*args, *args,
): ):
self.text.appendPlainText(f"started Repro {name_of_repro}, {file_of_repro}") self.text.appendPlainText(f"started Repro {name_of_repro}, {file_of_repro}")
nix_block_repro = nix_block[name_of_repro]
figure_repro = figures[name_of_repro] figure_repro = figures[name_of_repro]
worker = Worker( worker = Worker(
self.repros.run_repro, self.repros.run_repro,
name_of_repro, name_of_repro,
file_of_repro, file_of_repro,
nix_block_repro,
figure_repro, figure_repro,
*args[-2:], *args[-1:],
) )
worker.signals.result.connect(self.print_output) worker.signals.result.connect(self.print_output)
worker.signals.finished.connect(self.thread_complete) worker.signals.finished.connect(self.thread_complete)
@ -275,22 +267,6 @@ class PyRelacs(QMainWindow):
self.threadpool.start(worker) self.threadpool.start(worker)
def create_nix_file(self, file_path, metadata):
self.nix_file = nixio.File.open(
path=f"{file_path}", mode=nixio.FileMode.Overwrite
)
self.block = self.nix_file.create_block("recording", "testfile")
self.section = self.nix_file.create_section("metadata", "config.yaml")
for key, value in asdict(metadata).items():
self.section[key] = value
self.data_array_analog1 = self.block.create_data_array(
"Analog1", "ndarray", shape=(1000,), dtype=nixio.DataType.Double
)
self.data_array_analog2 = self.block.create_data_array(
"Analog2", "ndarray", shape=(1000,), dtype=nixio.DataType.Double
)
def recenter_continously_plot(self): def recenter_continously_plot(self):
self.continously_plot.refresh() self.continously_plot.refresh()
@ -320,7 +296,9 @@ class PyRelacs(QMainWindow):
self.continously_plot.plot() self.continously_plot.plot()
def record(self): def record(self):
self.create_nix_file("test.nix", self.config.metadata) self.data_array_analog1, self.data_array_analog2 = (
self.nix_writer.create_nix_file(f"{_root}/test/", self.config.metadata)
)
log.debug("Created nix file") log.debug("Created nix file")
nix_writer = Worker( nix_writer = Worker(
@ -359,7 +337,7 @@ class PyRelacs(QMainWindow):
except AttributeError: except AttributeError:
log.debug("Did not generate Sinus") log.debug("Did not generate Sinus")
if hasattr(PyRelacs, "daq_device"): if self.config.settings.daq:
log.debug("Stopping DAQ") log.debug("Stopping DAQ")
self.daq_producer.stop_aquisition() self.daq_producer.stop_aquisition()

View File

@ -15,7 +15,8 @@ class Continously:
def __init__(self, figure: pg.GraphicsLayoutWidget, buffer: CircBuffer): def __init__(self, figure: pg.GraphicsLayoutWidget, buffer: CircBuffer):
self.figure = figure self.figure = figure
self.buffer = buffer self.buffer = buffer
self.last_plotted_index = 0 self.last_plotted_index_analog_in_0 = 0
self.last_plotted_index_analog_in_1 = 0
self.timer = QTimer() self.timer = QTimer()
def plot(self, *args, **kwargs): def plot(self, *args, **kwargs):
@ -24,14 +25,25 @@ class Continously:
prev_plot = self.figure.getItem(row=0, col=0) prev_plot = self.figure.getItem(row=0, col=0)
if prev_plot: if prev_plot:
self.figure.removeItem(prev_plot) self.figure.removeItem(prev_plot)
self.continous_ax = self.figure.addPlot(row=0, col=0) self.analog_in_0 = self.figure.addPlot(row=0, col=0)
self.analog_in_1 = self.figure.addPlot(row=1, col=0)
pen = pg.mkPen("red") pen = pg.mkPen("red")
self.time = np.zeros(self.buffer.size) self.time_analog_in_0 = np.zeros(self.buffer.size)
self.data = np.empty(self.buffer.size) self.data_analog_in_0 = np.empty(self.buffer.size)
self.line = self.continous_ax.plot( self.line_analog_in_0 = self.analog_in_0.plot(
self.time, self.time_analog_in_0,
self.data, self.data_analog_in_0,
pen=pen,
# symbol="o",
)
pen = pg.mkPen("red")
self.time_analog_in_1 = np.zeros(self.buffer.size)
self.data_analog_in_1 = np.empty(self.buffer.size)
self.line_analog_in_1 = self.analog_in_1.plot(
self.time_analog_in_1,
self.data_analog_in_1,
pen=pen, pen=pen,
# symbol="o", # symbol="o",
) )
@ -41,26 +53,61 @@ class Continously:
self.PLOT_HISTORY = 500_000 # The amount of data you want to keep on screen self.PLOT_HISTORY = 500_000 # The amount of data you want to keep on screen
self.timer.setInterval(150) self.timer.setInterval(150)
self.timer.timeout.connect(self.update_plot) self.timer.timeout.connect(self.update_plot)
self.timer.timeout.connect(self.update_plot_1)
self.timer.start() self.timer.start()
def update_plot(self): def update_plot(self):
current_index = self.buffer.write_index() current_index = self.buffer.write_index()
total_count = self.buffer.totalcount() total_count = self.buffer.totalcount(channel=0)
start_time = time.time() start_time = time.time()
if total_count - self.last_plotted_index >= self.CHUNK_PLOT: if total_count - self.last_plotted_index_analog_in_0 >= self.CHUNK_PLOT:
try: try:
times, items = self.buffer.read( times, items = self.buffer.read(
self.last_plotted_index, self.last_plotted_index_analog_in_0,
extend=self.CHUNK_PLOT, extend=self.CHUNK_PLOT,
channel=0,
) )
self.time = np.concatenate((self.time, times))[-self.PLOT_HISTORY :] self.time_analog_in_0 = np.concatenate((self.time_analog_in_0, times))[
self.data = np.concatenate((self.data, items))[-self.PLOT_HISTORY :] -self.PLOT_HISTORY :
self.line.setData( ]
self.time, self.data_analog_in_0 = np.concatenate((self.data_analog_in_0, items))[
self.data, -self.PLOT_HISTORY :
]
self.line_analog_in_0.setData(
self.time_analog_in_0,
self.data_analog_in_0,
) )
self.last_plotted_index += self.CHUNK_PLOT self.last_plotted_index_analog_in_0 += self.CHUNK_PLOT
except IndexError:
log.error("Could not acces the data from the buffer for plotting")
end_time = time.time()
log.debug(f"total time for plotting {end_time - start_time}")
else:
pass
def update_plot_1(self):
total_count = self.buffer.totalcount(channel=1)
start_time = time.time()
if total_count - self.last_plotted_index_analog_in_1 >= self.CHUNK_PLOT:
try:
times, items = self.buffer.read(
self.last_plotted_index_analog_in_1,
extend=self.CHUNK_PLOT,
channel=1,
)
self.time_analog_in_1 = np.concatenate((self.time_analog_in_0, times))[
-self.PLOT_HISTORY :
]
self.data_analog_in_1 = np.concatenate((self.data_analog_in_0, items))[
-self.PLOT_HISTORY :
]
self.line_analog_in_1.setData(
self.time_analog_in_1,
self.data_analog_in_1,
)
self.last_plotted_index_analog_in_1 += self.CHUNK_PLOT
except IndexError: except IndexError:
log.error("Could not acces the data from the buffer for plotting") log.error("Could not acces the data from the buffer for plotting")
end_time = time.time() end_time = time.time()
@ -70,19 +117,26 @@ class Continously:
def stop_plotting(self): def stop_plotting(self):
self.timer.stop() self.timer.stop()
if self.last_plotted_index > 0: if self.last_plotted_index_analog_in_0 > 0:
total_count = self.buffer.totalcount() total_count = self.buffer.totalcount()
times, items = self.buffer.read( times, items = self.buffer.read(
self.last_plotted_index, self.last_plotted_index_analog_in_0,
extend=total_count - self.last_plotted_index, extend=total_count - self.last_plotted_index_analog_in_0,
)
self.time_analog_in_0 = np.concatenate((self.time_analog_in_0, times))[
-self.PLOT_HISTORY :
]
self.data_analog_in_0 = np.concatenate((self.data_analog_in_0, items))[
-self.PLOT_HISTORY :
]
self.line_analog_in_0.setData(
self.time_analog_in_0,
self.data_analog_in_0,
) )
self.time = np.concatenate((self.time, times))[-self.PLOT_HISTORY :] self.last_plotted_index_analog_in_0 += (
self.data = np.concatenate((self.data, items))[-self.PLOT_HISTORY :] total_count - self.last_plotted_index_analog_in_0
self.line.setData(
self.time,
self.data,
) )
self.last_plotted_index += total_count - self.last_plotted_index
def refresh(self): def refresh(self):
self.continous_ax.enableAutoRange() self.analog_in_0.enableAutoRange()
self.analog_in_1.enableAutoRange()