23 Commits

Author SHA1 Message Date
wendtalexander
0113e94625 [dataio/nix] adding comments 2024-11-04 08:04:20 +01:00
wendtalexander
cce7c55fe7 [daq] trying different channels 2024-10-25 18:03:43 +02:00
wendtalexander
6c49f19b43 [dataio/daq] updating log messages 2024-10-25 18:03:23 +02:00
wendtalexander
2ef018ef07 [dataio/daq] making the buffer bigger 2024-10-24 16:35:09 +02:00
wendtalexander
3ab7a33b52 [config] updating config 2024-10-24 11:51:27 +02:00
wendtalexander
acd41302c7 [ui/plots] plotting now two different channels from the buffer 2024-10-24 11:51:17 +02:00
wendtalexander
1fe854b74e [ui] moving creation of nix to nix_file 2024-10-24 11:50:49 +02:00
wendtalexander
a53ff62d96 [dataio/nix] moving creation of nix to nix writer 2024-10-24 11:50:32 +02:00
wendtalexander
3d3d9a0cdd [dataio/daq] writes now two channels in the ringbuffer 2024-10-24 11:50:00 +02:00
wendtalexander
8f6c9b1e5e [ui/structure] updating repros to tab bar with individual plots and nix blocks 2024-10-23 11:09:44 +02:00
wendtalexander
574e9a8110 [ui/plots] fixing error if nothing has been plotted, the gui could not close 2024-10-23 11:08:54 +02:00
wendtalexander
75619cf1c8 [repro/class] provides with repros with args and kwargs 2024-10-23 11:07:55 +02:00
wendtalexander
02911e57f8 [repros] moving to sperate folders 2024-10-23 11:07:19 +02:00
wendtalexander
557535ffa4 [repros] moving to sperate folder, writing run method 2024-10-23 11:06:51 +02:00
wendtalexander
110629dae0 [calibration] moving calibration to own folder, rewriting run method 2024-10-23 11:06:26 +02:00
wendtalexander
7c4b5098c1 [mccdaq] printing exception error 2024-10-23 11:05:41 +02:00
wendtalexander
e2b7ed3a61 [ui] creates a nix file with pressing the record button 2024-10-22 10:11:07 +02:00
wendtalexander
038327bfeb [ui/continously] updating plot to plot the last chunk 2024-10-22 10:10:40 +02:00
wendtalexander
4f7ebbe8c3 [dataio/nix] adding mutex, writing data_array, and the last chunk 2024-10-22 10:10:09 +02:00
wendtalexander
12e82dceee [dataio] adding time sleep for performance 2024-10-21 17:44:02 +02:00
wendtalexander
e4e86cbc49 [ui/plot] updating plot 2024-10-21 10:29:38 +02:00
wendtalexander
e36db5e7b0 [dataio/producer] removing comments 2024-10-21 10:28:46 +02:00
wendtalexander
33f046c072 [dataio/nix] adding sleep while writing 2024-10-21 10:28:25 +02:00
12 changed files with 507 additions and 153 deletions

View File

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

View File

@@ -21,7 +21,6 @@ class DaqProducer:
self.device = device
self.ai_device = self.device.get_ai_device()
self.channels = channels
self.stop = False
def read_analog_continously(
@@ -41,7 +40,7 @@ class DaqProducer:
)
# 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)
log.debug(f"Buffersize for daq {len(data_in)}")
@@ -70,7 +69,12 @@ class DaqProducer:
prev_count = 0
prev_index = 0
while not self.stop:
daq_status, transfer_status = self.ai_device.get_scan_status()
try:
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.
current_index = transfer_status.current_index
# total samples since start of the scan
@@ -79,7 +83,7 @@ class DaqProducer:
channel_samples = transfer_status.current_scan_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 new_data_count > len(data_in):
self.ai_device.scan_stop()
@@ -92,23 +96,54 @@ class DaqProducer:
if prev_index + chunk_size > len(data_in) - 1:
log.debug("Chunk wraps around buffersize")
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])
for i in range(first_chunk)
self.buffer.append(data_first_channel[i], channel=0)
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
data_first_channel = data_in[0:second_chunk:2]
data_second_channel = data_in[1:second_chunk:2]
[
self.buffer.append(data_in[i])
for i in range(second_chunk)
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:
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])
for i in range(chunk_size)
self.buffer.append(data_first_channel[i], channel=0)
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):
self.ai_device.scan_stop()
@@ -124,33 +159,70 @@ class DaqProducer:
self.ai_device.scan_stop()
daq_status, transfer_status = self.ai_device.get_scan_status()
current_index = transfer_status.current_index
log.debug(daq_status)
chunk_size = transfer_status.current_total_count - prev_count
log.debug(transfer_status.current_index)
log.debug(transfer_status.current_total_count)
log.debug(transfer_status.current_scan_count)
log.debug(self.buffer.totalcount())
log.debug(f"DAQ current index {transfer_status.current_index}")
log.debug(f"DAQ total count {transfer_status.current_total_count}")
log.debug(
f"DAQ Samples per channel {transfer_status.current_scan_count}"
)
log.debug("Appending last chunk")
if prev_index + chunk_size > len(data_in) - 1:
log.debug("Chunk wraps around buffersize")
first_chunk = len(data_in) - prev_index
[
self.buffer.append(data_in[prev_index + i])
for i in range(first_chunk)
data_first_channel = data_in[
prev_index : prev_index + first_chunk : 2
]
second_chunk = chunk_size - first_chunk
[self.buffer.append(data_in[i]) for i in range(second_chunk)]
else:
log.debug("Writing chunk to buffer")
[
self.buffer.append(data_in[prev_index + i])
for i in range(chunk_size)
data_second_channel = data_in[
prev_index + 1 : prev_index + first_chunk : 2
]
self.buffer.append(data_in[current_index])
[
self.buffer.append(data_first_channel[i], channel=0)
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
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:
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_first_channel[i], channel=0)
for i in range(int(chunk_size / 2))
]
[
self.buffer.append(data_second_channel[i], channel=1)
for i in range(int(chunk_size / 2))
]
log.info("stopping")
log.debug(self.buffer.totalcount())
log.debug(self.ai_device.get_scan_status())
break
break

View File

@@ -1,4 +1,11 @@
from datetime import datetime
import itertools
import string
import time
from dataclasses import asdict
from IPython import embed
from PyQt6.QtCore import QMutex
import nixio
from pyrelacs.dataio.circbuffer import CircBuffer
@@ -8,34 +15,95 @@ log = config_logging()
class NixWriter:
def __init__(self, buffer: CircBuffer) -> None:
def __init__(self, buffer: CircBuffer, config) -> None:
self.buffer = buffer
self.config = config
def write_nix(self, *args, **kwargs):
self._write_header()
items = 0
chunk = 1000
def write_nix(
self,
data_array: nixio.DataArray,
mutex: QMutex,
channel: int = 0,
chunk_size=1000,
*args,
**kwargs,
):
index = 0
log.debug("Starting the writing")
self.write = True
while self.write:
# log.debug(items)
try:
data, _ = self.buffer.read(items, extend=chunk)
self.data_array.append(data)
except IndexError as e:
# log.debug(f"{e}")
total_count = self.buffer.totalcount(channel=channel)
if total_count - index >= chunk_size:
mutex.lock()
log.debug(index)
try:
_, data = self.buffer.read(
index, extend=chunk_size, channel=channel
)
if index == 0:
data_array.write_direct(data)
else:
data_array.append(data)
index += chunk_size
except IndexError as e:
time.sleep(0.001)
log.debug(f"{e}")
mutex.unlock()
else:
time.sleep(0.001)
continue
items += chunk
total_count = self.buffer.totalcount(channel=channel)
try:
mutex.lock()
_, data = self.buffer.read(
index, extend=total_count - index, channel=channel
)
data_array.append(data)
mutex.unlock()
index += total_count - index
except IndexError as e:
log.error(f"Could not read the last samples, {e}")
log.debug("Stoppint the writing")
log.debug(f"Samples written {items}")
self.nix_file.close()
log.debug(f"Samples written {index}")
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.block = self.nix_file.create_block("recording", "testfile")
self.data_array = self.block.create_data_array(
"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):
self.write = False

View File

@@ -38,12 +38,7 @@ class SinProducer:
log.debug(f"duration sinus {end_time-start_time}")
log.debug(f"Stimulation time {t}")
log.debug(f"{self.buffer.totalcount()}")
# data = self.buffer.get_all()
# log.debug(data.shape[0])
# log.debug(data.shape[0] / self.buffer.samplerate)
# plt.plot(np.arange(data.size) / self.buffer.samplerate, data)
# plt.show()
log.debug(f"Total samples produced {self.buffer.totalcount()}")
def stop_request(self):
self.stop = True

View File

@@ -224,10 +224,10 @@ class MccDaq:
uldaq.AOutListFlag.DEFAULT,
[0, 0],
)
except Exception as e:
log.error("f{e}")
except Exception as er:
log.error(f"{er}")
log.error("disconnection dac")
self.disconnect_daq()
# self.disconnect_daq()
def digital_trigger(self, ch: int = 0) -> None:
"""

View File

@@ -6,6 +6,8 @@ import uldaq
from IPython import embed
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import welch, find_peaks
import pyqtgraph as pg
from pyrelacs.devices.mccdaq import MccDaq
from pyrelacs.util.logging import config_logging
@@ -15,40 +17,50 @@ log = config_logging()
faulthandler.enable()
class Calibration(MccDaq):
def __init__(self) -> None:
super().__init__()
class Calibration:
def __init__(self, config, mccdaq: MccDaq) -> None:
self.config = config
self.mccdaq = mccdaq
self.SAMPLERATE = 40_000.0
self.DURATION = 5
self.AMPLITUDE = 1
self.SINFREQ = 750
@staticmethod
def run(nix_file: nix.File):
calb = Calibration()
calb.check_beat(nix_file)
def run(*args, **kwargs):
nix_block = args[0]
figure = args[1]
mccdaq = args[2]
config = args[3]
calb = Calibration(config, mccdaq)
calb.check_beat(nix_block)
calb.plot(figure, nix_block)
return "finished"
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.mccdaq.set_attenuation_level(db_channel1=0.0, db_channel2=0.0)
# write to ananlog 1
t = np.arange(0, self.DURATION, 1 / self.SAMPLERATE)
data = self.AMPLITUDE * np.sin(2 * np.pi * self.SINFREQ * t)
fig, ax = plt.subplots()
for i, db_value in enumerate(db_values):
self.set_attenuation_level(db_channel1=db_value, db_channel2=db_value)
self.mccdaq.set_attenuation_level(
db_channel1=db_value, db_channel2=db_value
)
log.debug(f"{db_value}")
stim = self.write_analog(
stim = self.mccdaq.write_analog(
data,
[0, 0],
self.SAMPLERATE,
ScanOption=uldaq.ScanOption.EXTTRIGGER,
)
data_channel_one = self.read_analog(
data_channel_one = self.mccdaq.read_analog(
[0, 0],
self.DURATION,
self.SAMPLERATE,
@@ -57,21 +69,21 @@ class Calibration(MccDaq):
time.sleep(1)
log.debug("Starting the Scan")
self.digital_trigger()
self.mccdaq.digital_trigger()
try:
self.ao_device.scan_wait(uldaq.WaitType.WAIT_UNTIL_DONE, 15)
self.mccdaq.ao_device.scan_wait(uldaq.WaitType.WAIT_UNTIL_DONE, 15)
log.debug("Scan finished")
self.write_bit(channel=0, bit=0)
self.mccdaq.write_bit(channel=0, bit=0)
time.sleep(1)
self.set_analog_to_zero()
self.mccdaq.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)
self.mccdaq.write_bit(channel=0, bit=0)
time.sleep(1)
self.set_analog_to_zero()
self.disconnect_daq()
self.mccdaq.set_analog_to_zero()
# self.mccdaq.disconnect_daq()
if i == 0:
ax.plot(t, stim, label=f"Input_{db_value}", color=colors[i])
@@ -80,34 +92,33 @@ class Calibration(MccDaq):
ax.legend()
plt.show()
self.disconnect_daq()
# self.mccdaq.disconnect_daq()
def check_beat(self, nix_file: nix.File):
self.set_attenuation_level(db_channel1=-10.0, db_channel2=0.0)
def check_beat(self, nix_block: nix.Block):
self.mccdaq.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"]
block = nix_file.create_block("Calibration", "data")
# 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(
self.mccdaq.set_attenuation_level(db_channel1=db_value)
stim = self.mccdaq.write_analog(
data,
[0, 0],
self.SAMPLERATE,
ScanOption=uldaq.ScanOption.EXTTRIGGER,
)
readout = self.read_analog(
readout = self.mccdaq.read_analog(
[0, 1],
self.DURATION,
self.SAMPLERATE,
ScanOption=uldaq.ScanOption.EXTTRIGGER,
)
self.digital_trigger()
log.info(self.ao_device)
self.mccdaq.digital_trigger()
log.info(self.mccdaq.ao_device)
ai_status = uldaq.ScanStatus.RUNNING
ao_status = uldaq.ScanStatus.RUNNING
@@ -119,10 +130,10 @@ class Calibration(MccDaq):
):
# log.debug("Scanning")
time.time_ns()
ai_status = self.ai_device.get_scan_status()[0]
ao_status = self.ao_device.get_scan_status()[0]
ai_status = self.mccdaq.ai_device.get_scan_status()[0]
ao_status = self.mccdaq.ao_device.get_scan_status()[0]
self.write_bit(channel=0, bit=0)
self.mccdaq.write_bit(channel=0, bit=0)
log.debug(
f"Status Analog_output {ao_status}\n, Status Analog_input {ai_status}"
)
@@ -130,7 +141,7 @@ class Calibration(MccDaq):
channel1 = np.array(readout[::2])
channel2 = np.array(readout[1::2])
stim_data = block.create_data_array(
stim_data = nix_block.create_data_array(
f"stimulus_{db_value}",
"nix.regular_sampled",
shape=data.shape,
@@ -143,7 +154,7 @@ class Calibration(MccDaq):
label="time",
unit="s",
)
fish_data = block.create_data_array(
fish_data = nix_block.create_data_array(
f"fish_{db_value}",
"Array",
shape=data.shape,
@@ -157,7 +168,72 @@ class Calibration(MccDaq):
unit="s",
)
self.set_analog_to_zero()
time.time_ns()
self.mccdaq.set_analog_to_zero()
def plot(self, figure, block):
self.figure = figure
self.figure.setBackground("w")
self.beat_plot = self.figure.addPlot(row=0, col=0)
self.power_plot = self.figure.addPlot(row=1, col=0)
self.beat_plot.addLegend()
self.power_plot.addLegend()
# self.power_plot.setLogMode(x=False, y=True)
colors = ["red", "green", "blue", "black", "yellow"]
for i, (stim, fish) in enumerate(
zip(list(block.data_arrays)[::2], list(block.data_arrays)[1::2])
):
f_stim, stim_power = welch(
stim[:],
fs=40_000.0,
window="flattop",
nperseg=100_000,
)
stim_power = decibel(stim_power)
stim_max_power_index = np.argmax(stim_power)
freq_stim = f_stim[stim_max_power_index]
f_fish, fish_power = welch(
fish[:],
fs=40_000.0,
window="flattop",
nperseg=100_000,
)
fish_power = decibel(fish_power)
fish_max_power_index = np.argmax(fish_power)
freq_fish = f_fish[fish_max_power_index]
beat_frequency = np.abs(freq_fish - freq_stim)
beat = stim[:] + fish[:]
beat_squared = beat**2
f, powerspec = welch(
beat_squared,
window="flattop",
fs=40_000.0,
nperseg=100_000,
)
powerspec = decibel(powerspec)
padding = 20
integration_window = powerspec[
(f > beat_frequency - padding) & (f < beat_frequency + padding)
]
peaks = find_peaks(powerspec, prominence=40)[0]
pen = pg.mkPen(colors[i])
self.beat_plot.plot(
np.arange(0, len(beat)) / 40_000.0,
beat,
pen=pen,
name=stim.name,
)
self.power_plot.plot(f, powerspec, pen=pen, name=stim.name)
self.power_plot.plot(f[peaks], powerspec[peaks], pen=None, symbol="x")
def decibel(power, ref_power=1.0, min_power=1e-20):

View File

View File

@@ -22,9 +22,7 @@ class Repro:
def __init__(self) -> None:
pass
def run_repro(
self, nix_file: nix.File, name: str, file: pathlib.Path, *args, **kwargs
) -> None:
def run_repro(self, name: str, file: pathlib.Path, *args, **kwargs) -> None:
spec = importlib.util.spec_from_file_location("rep", file)
if not spec:
log.error("Could not load the file")
@@ -40,7 +38,7 @@ class Repro:
log.error(f"{spec.loader} is None")
if hasattr(module, name):
rep_class = getattr(module, name)
rep_class.run(nix_file)
rep_class.run(*args, **kwargs)
else:
raise AttributeError(f"{file.name} has no {name} class")

View File

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

View File

@@ -0,0 +1,17 @@
import nixio
from pyrelacs.util.logging import config_logging
log = config_logging()
class Sinus:
def __init__(self) -> None:
pass
@staticmethod
def run(config, mccdaq, nix_block: nixio.Block, figure) -> None:
log.debug(config)
log.debug(mccdaq)
log.debug(nix_block)
log.debug(figure)

View File

@@ -1,10 +1,14 @@
import time
from pathlib import Path as path
from datetime import datetime
from dataclasses import asdict
from PyQt6.QtGui import QAction, QIcon, QKeySequence
from PyQt6.QtCore import Qt, QSize, QThreadPool, QMutex
from PyQt6.QtWidgets import (
QGridLayout,
QPushButton,
QTabWidget,
QToolBar,
QWidget,
QMainWindow,
@@ -13,8 +17,8 @@ from PyQt6.QtWidgets import (
QStatusBar,
)
import uldaq
import nixio as nix
import nixio
import pyqtgraph as pg
import quantities as pq
@@ -45,11 +49,15 @@ class PyRelacs(QMainWindow):
super().__init__()
# loaded config
self.config = config
# check if daq is connencted else None
if self.config.settings.daq:
start = time.time()
self.mccdaq = MccDaq()
end = time.time()
log.debug(f"Connection to DAQ took {end - start}")
else:
self.mccdaq = None
self.repros = Repro()
@@ -67,19 +75,6 @@ class PyRelacs(QMainWindow):
self.text = QPlainTextEdit()
self.text.setReadOnly(True)
self.setMenuBar(QMenuBar(self))
self.setStatusBar(QStatusBar(self))
self.create_actions()
self.create_toolbars()
layout = QGridLayout()
layout.addWidget(self.figure, 0, 0, 2, 2)
layout.addWidget(self.text, 2, 0, 1, 2)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
SAMPLERATE = pq.Quantity(
self.config.pyrelacs.data.input.inputsamplerate,
self.config.pyrelacs.data.input.inputsamplerateunit,
@@ -97,19 +92,34 @@ class PyRelacs(QMainWindow):
self.buffer = CircBuffer(
size=int(BUFFERSIZE.base),
samplerate=float(SAMPLERATE.base),
channels=2,
mutex=self.mutex,
)
self.continously_plot = Continously(self.figure, self.buffer)
self.continously_plot.plot()
# self.continously_plot.plot()
if self.config.settings.daq:
if self.mccdaq:
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")
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):
self._rlx_exitaction = QAction(QIcon(":/icons/exit.png"), "Exit", self)
@@ -125,7 +135,7 @@ class PyRelacs(QMainWindow):
self._daq_connectaction = QAction(
QIcon(":icons/connect.png"), "Connect DAQ", self
)
if self.config.settings.daq:
if self.mccdaq:
self._daq_connectaction.setStatusTip("Connect to daq device")
# self._daq_connectaction.setShortcut(QKeySequence("Alt+d"))
self._daq_connectaction.triggered.connect(self.mccdaq.connect_dac)
@@ -144,7 +154,7 @@ class PyRelacs(QMainWindow):
# # self._daq_calibaction.setShortcut(QKeySequence("Alt+d"))
# self._daq_calibaction.triggered.connect(self.calibration_plot.plot)
self._run_action = QAction(QIcon(":/icons/record.png"), "Run", self)
self._run_action = QAction(QIcon(":/icons/record.png"), "RunDAQ", self)
self._run_action.triggered.connect(self.run_daq)
self._run_sinus_action = QAction(QIcon(":/icons/record.png"), "Sinus", self)
@@ -209,18 +219,53 @@ class PyRelacs(QMainWindow):
daq_toolbar.addAction(self._record)
self.addToolBar(Qt.ToolBarArea.TopToolBarArea, daq_toolbar)
repro_toolbar = QToolBar("Repros")
def create_repros_tabs(self):
repro_names, file_names = self.repros.names_of_repros(
include_repros=self.config.settings.repros
)
figures_repros = {rep: pg.GraphicsLayoutWidget() for rep in repro_names}
for rep, fn in zip(repro_names, file_names):
repro_action = QAction(rep, self)
repro_action.setStatusTip(rep)
repro_action.triggered.connect(
lambda checked, n=rep, f=fn: self.run_repro(n, f)
tab = QWidget()
tab_layout = QGridLayout()
run_repro_button = QPushButton(f"Run {rep}")
run_repro_button.setCheckable(True)
run_repro_button.clicked.connect(
lambda checked, n=rep, f=fn: self.run_repro(
n,
f,
figures_repros,
self.mccdaq,
self.config,
)
)
repro_toolbar.addAction(repro_action)
self.addToolBar(Qt.ToolBarArea.BottomToolBarArea, repro_toolbar)
tab_layout.addWidget(run_repro_button, 0, 0, 1, 0)
tab_layout.addWidget(figures_repros[rep], 1, 0, 1, 1)
tab.setLayout(tab_layout)
self.repro_tabs.addTab(tab, f"{rep}")
def run_repro(
self,
name_of_repro: str,
file_of_repro: str,
figures,
*args,
):
self.text.appendPlainText(f"started Repro {name_of_repro}, {file_of_repro}")
figure_repro = figures[name_of_repro]
worker = Worker(
self.repros.run_repro,
name_of_repro,
file_of_repro,
figure_repro,
*args[-1:],
)
worker.signals.result.connect(self.print_output)
worker.signals.finished.connect(self.thread_complete)
worker.signals.progress.connect(self.progress_fn)
self.threadpool.start(worker)
def recenter_continously_plot(self):
self.continously_plot.refresh()
@@ -251,12 +296,35 @@ class PyRelacs(QMainWindow):
self.continously_plot.plot()
def record(self):
nix_writer = Worker(self.nix_writer.write_nix)
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")
nix_writer = Worker(
self.nix_writer.write_nix,
data_array=self.data_array_analog1,
mutex=self.mutex,
channel=0,
chunk_size=1000,
)
nix_writer.signals.result.connect(self.print_output)
nix_writer.signals.finished.connect(self.thread_complete)
nix_writer.signals.progress.connect(self.progress_fn)
self.threadpool.start(nix_writer)
nix_writer2 = Worker(
self.nix_writer.write_nix,
data_array=self.data_array_analog2,
mutex=self.mutex,
channel=0,
chunk_size=1000,
)
nix_writer2.signals.result.connect(self.print_output)
nix_writer2.signals.finished.connect(self.thread_complete)
nix_writer2.signals.progress.connect(self.progress_fn)
self.threadpool.start(nix_writer2)
def stop_recording(self):
self.add_to_textfield("Stopping the recording")
self.continously_plot.stop_plotting()
@@ -269,19 +337,10 @@ class PyRelacs(QMainWindow):
except AttributeError:
log.debug("Did not generate Sinus")
if hasattr(PyRelacs, "daq_device"):
if self.config.settings.daq:
log.debug("Stopping DAQ")
self.daq_producer.stop_aquisition()
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)
worker.signals.result.connect(self.print_output)
worker.signals.finished.connect(self.thread_complete)
worker.signals.progress.connect(self.progress_fn)
self.threadpool.start(worker)
def add_to_textfield(self, s: str):
self.text.appendPlainText(s)
@@ -289,7 +348,7 @@ class PyRelacs(QMainWindow):
log.info("exit button!")
self.stop_recording()
self.add_to_textfield("exiting")
if self.config.settings.daq:
if self.mccdaq:
self.mccdaq.disconnect_daq()
log.info("closing GUI")
self.close()

View File

@@ -15,6 +15,9 @@ class Continously:
def __init__(self, figure: pg.GraphicsLayoutWidget, buffer: CircBuffer):
self.figure = figure
self.buffer = buffer
self.last_plotted_index_analog_in_0 = 0
self.last_plotted_index_analog_in_1 = 0
self.timer = QTimer()
def plot(self, *args, **kwargs):
self.figure.setBackground("w")
@@ -22,44 +25,91 @@ class Continously:
prev_plot = self.figure.getItem(row=0, col=0)
if 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")
self.time = np.zeros(self.buffer.size)
self.data = np.empty(self.buffer.size)
self.line = self.continous_ax.plot(
self.time,
self.data,
self.time_analog_in_0 = np.zeros(self.buffer.size)
self.data_analog_in_0 = np.empty(self.buffer.size)
self.line_analog_in_0 = self.analog_in_0.plot(
self.time_analog_in_0,
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,
# symbol="o",
)
# self.plot_index = 0
self.timer = QTimer()
self.CHUNK_PLOT = int(self.buffer.samplerate / 6)
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_1)
self.timer.start()
def update_plot(self):
current_index = self.buffer.write_index()
total_count = self.buffer.totalcount()
total_count = self.buffer.totalcount(channel=0)
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.time,
self.data,
)
self.last_plotted_index += self.CHUNK_PLOT
if total_count - self.last_plotted_index_analog_in_0 >= self.CHUNK_PLOT:
try:
times, items = self.buffer.read(
self.last_plotted_index_analog_in_0,
extend=self.CHUNK_PLOT,
channel=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.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:
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:
@@ -67,6 +117,26 @@ class Continously:
def stop_plotting(self):
self.timer.stop()
if self.last_plotted_index_analog_in_0 > 0:
total_count = self.buffer.totalcount()
times, items = self.buffer.read(
self.last_plotted_index_analog_in_0,
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.last_plotted_index_analog_in_0 += (
total_count - self.last_plotted_index_analog_in_0
)
def refresh(self):
self.continous_ax.enableAutoRange()
self.analog_in_0.enableAutoRange()
self.analog_in_1.enableAutoRange()