Compare commits
7 Commits
e2b7ed3a61
...
8f6c9b1e5e
Author | SHA1 | Date | |
---|---|---|---|
8f6c9b1e5e | |||
574e9a8110 | |||
75619cf1c8 | |||
02911e57f8 | |||
557535ffa4 | |||
110629dae0 | |||
7c4b5098c1 |
@ -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:
|
||||
"""
|
||||
|
@ -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):
|
0
pyrelacs/repros/calibration/config.yaml
Normal file
0
pyrelacs/repros/calibration/config.yaml
Normal 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")
|
||||
|
||||
|
@ -1,3 +0,0 @@
|
||||
class Sinus:
|
||||
def __init__(self) -> None:
|
||||
pass
|
17
pyrelacs/repros/sinus/sinus.py
Normal file
17
pyrelacs/repros/sinus/sinus.py
Normal 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)
|
@ -7,7 +7,10 @@ from PyQt6.QtGui import QAction, QIcon, QKeySequence
|
||||
from PyQt6.QtCore import Qt, QSize, QThreadPool, QMutex
|
||||
from PyQt6.QtWidgets import (
|
||||
QGridLayout,
|
||||
QPushButton,
|
||||
QTabWidget,
|
||||
QToolBar,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
QMainWindow,
|
||||
QPlainTextEdit,
|
||||
@ -52,6 +55,8 @@ class PyRelacs(QMainWindow):
|
||||
self.mccdaq = MccDaq()
|
||||
end = time.time()
|
||||
log.debug(f"Connection to DAQ took {end - start}")
|
||||
else:
|
||||
self.mccdaq = None
|
||||
|
||||
self.repros = Repro()
|
||||
|
||||
@ -60,6 +65,8 @@ class PyRelacs(QMainWindow):
|
||||
) # Ensure icons are displayed with text
|
||||
self.setWindowTitle("PyRelacs")
|
||||
|
||||
self.create_nix_file(f"{_root}/test.nix", self.config.metadata)
|
||||
|
||||
self.mutex = QMutex()
|
||||
|
||||
self.figure = pg.GraphicsLayoutWidget()
|
||||
@ -73,10 +80,13 @@ class PyRelacs(QMainWindow):
|
||||
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.text, 2, 0, 1, 2)
|
||||
layout.addWidget(self.repro_tabs, 2, 0, 2, 2)
|
||||
layout.addWidget(self.text, 4, 0, 1, 1)
|
||||
|
||||
widget = QWidget()
|
||||
widget.setLayout(layout)
|
||||
@ -104,14 +114,13 @@ class PyRelacs(QMainWindow):
|
||||
self.continously_plot = Continously(self.figure, self.buffer)
|
||||
# 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])
|
||||
log.debug("Creating Sinus Generator")
|
||||
self.sinus_producer = SinProducer(self.buffer)
|
||||
|
||||
self.nix_writer = NixWriter(self.buffer)
|
||||
self.create_nix_file(f"{_root}/test.nix", self.config.metadata)
|
||||
|
||||
def create_actions(self):
|
||||
self._rlx_exitaction = QAction(QIcon(":/icons/exit.png"), "Exit", self)
|
||||
@ -127,7 +136,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)
|
||||
@ -146,7 +155,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)
|
||||
@ -211,18 +220,60 @@ 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
|
||||
)
|
||||
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}
|
||||
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,
|
||||
nix_blocks,
|
||||
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,
|
||||
nix_block,
|
||||
figures,
|
||||
*args,
|
||||
):
|
||||
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]
|
||||
worker = Worker(
|
||||
self.repros.run_repro,
|
||||
name_of_repro,
|
||||
file_of_repro,
|
||||
nix_block_repro,
|
||||
figure_repro,
|
||||
*args[-2:],
|
||||
)
|
||||
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 create_nix_file(self, file_path, metadata):
|
||||
self.nix_file = nixio.File.open(
|
||||
@ -311,17 +362,6 @@ class PyRelacs(QMainWindow):
|
||||
if hasattr(PyRelacs, "daq_device"):
|
||||
log.debug("Stopping DAQ")
|
||||
self.daq_producer.stop_aquisition()
|
||||
embed()
|
||||
exit()
|
||||
|
||||
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)
|
||||
@ -330,7 +370,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()
|
||||
|
@ -16,6 +16,7 @@ class Continously:
|
||||
self.figure = figure
|
||||
self.buffer = buffer
|
||||
self.last_plotted_index = 0
|
||||
self.timer = QTimer()
|
||||
|
||||
def plot(self, *args, **kwargs):
|
||||
self.figure.setBackground("w")
|
||||
@ -36,7 +37,6 @@ class Continously:
|
||||
)
|
||||
|
||||
# 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.timer.setInterval(150)
|
||||
@ -70,18 +70,19 @@ class Continously:
|
||||
|
||||
def stop_plotting(self):
|
||||
self.timer.stop()
|
||||
total_count = self.buffer.totalcount()
|
||||
times, items = self.buffer.read(
|
||||
self.last_plotted_index,
|
||||
extend=total_count - self.last_plotted_index,
|
||||
)
|
||||
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 += total_count - self.last_plotted_index
|
||||
if self.last_plotted_index > 0:
|
||||
total_count = self.buffer.totalcount()
|
||||
times, items = self.buffer.read(
|
||||
self.last_plotted_index,
|
||||
extend=total_count - self.last_plotted_index,
|
||||
)
|
||||
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 += total_count - self.last_plotted_index
|
||||
|
||||
def refresh(self):
|
||||
self.continous_ax.enableAutoRange()
|
||||
|
Loading…
Reference in New Issue
Block a user