Skip to content

Commit

Permalink
Better frame timing and more optimized plotting
Browse files Browse the repository at this point in the history
  • Loading branch information
Neverhorst committed Sep 6, 2019
1 parent 990d686 commit 675e877
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 34 deletions.
49 changes: 38 additions & 11 deletions gui/time_series_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from core.module import Connector
from gui.colordefs import QudiPalettePale as palette
from gui.guibase import GUIBase
from qtpy import QtCore
from qtpy import QtCore, QtGui
from qtpy import QtWidgets
from qtpy import uic

Expand Down Expand Up @@ -90,20 +90,35 @@ def on_activate(self):

self._pw.setLabel('left', 'Fluorescence', units='counts/s')
self._pw.setLabel('bottom', 'Time', units='s')
# self._pw.disableAutoRange()
self._pw.disableAutoRange()
self._pw.setMouseEnabled(x=False, y=False)
self._pw.setMouseTracking(False)
self._pw.setMenuEnabled(False)
self._pw.hideButtons()

self.curves = list()

for i, ch in enumerate(self._time_series_logic.channel_names):
if i % 2 == 0:
self.curves.append(pg.PlotDataItem(pen={'color': palette.c2, 'width': 4}, symbol=None))
self.curves.append(pg.PlotCurveItem(pen={'color': palette.c2, 'width': 4},
clipToView=True,
downsampleMethod='subsample',
autoDownsample=True))
self._pw.addItem(self.curves[-1])
self.curves.append(pg.PlotDataItem(pen={'color': palette.c1, 'width': 2}, symbol=None))
self.curves.append(pg.PlotCurveItem(pen={'color': palette.c1, 'width': 2},
clipToView=True,
downsampleMethod='subsample',
autoDownsample=True))
self._pw.addItem(self.curves[-1])
else:
self.curves.append(pg.PlotDataItem(pen={'color': palette.c4, 'width': 4}, symbol=None))
self.curves.append(pg.PlotCurveItem(pen={'color': palette.c4, 'width': 4},
clipToView=True,
downsampleMethod='subsample',
autoDownsample=True))
self._pw.addItem(self.curves[-1])
self.curves.append(pg.PlotDataItem(pen={'color': palette.c3, 'width': 2}, symbol=None))
self.curves.append(pg.PlotCurveItem(pen={'color': palette.c3, 'width': 2},
clipToView=True,
downsampleMethod='subsample',
autoDownsample=True))
self._pw.addItem(self.curves[-1])

# setting the x axis length correctly
Expand Down Expand Up @@ -186,10 +201,18 @@ def update_data(self):
"""
start = time.perf_counter()
data = self._time_series_logic.trace_data
data_time = self._time_series_logic.trace_time_axis
smooth_data = self._time_series_logic.trace_data_averaged
smooth_time = self._time_series_logic.averaged_trace_time_axis

# curr_x_min, curr_x_max = self.curves[0].dataBounds(0)
# x_min, x_max = data_time.min(), data_time.max()
# if curr_x_max < x_max or curr_x_min > x_min:
# self._pw.setLimits(xMin=x_min - 0.01 * np.abs(x_min), xMax=x_max + 0.01 * np.abs(x_max))

# x_min, x_max = x_vals.min(), x_vals.max()
# y_min, y_max = data.min(), data.max()
x_min, x_max = data_time.min(), data_time.max()
y_min, y_max = data.min(), data.max()
self._pw.setRange(xRange=(x_min, x_max), yRange=(y_min, y_max), update=False)
# view_range = self._pw.visibleRange()
# if view_range.left() > x_min or view_range.right() < x_max:
# self._pw.setXRange(x_min, x_max)
Expand All @@ -201,9 +224,13 @@ def update_data(self):
# elif view_range.height() > (y_max - y_min) * 0.7:
# self._pw.setYRange(y_min, y_max)

# if update_all:
for i, ch in enumerate(self._time_series_logic.channel_names):
self.curves[2 * i].setData(y=self._time_series_logic.trace_data[i], x=self._time_series_logic.trace_time_axis)
self.curves[2 * i + 1].setData(y=self._time_series_logic.trace_data_averaged[i], x=self._time_series_logic.averaged_trace_time_axis)
self.curves[2 * i].setData(y=data[i], x=data_time)
self.curves[2 * i + 1].setData(y=smooth_data[i], x=smooth_time)

# QtWidgets.QApplication.processEvents()
# self._pw.autoRange()
print('Plot time: {0:.3e}s'.format(time.perf_counter() - start))
return 0

Expand Down
33 changes: 10 additions & 23 deletions logic/time_series_reader_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ class TimeSeriesReaderLogic(GenericLogic):
sigDataChanged = QtCore.Signal()
sigStatusChanged = QtCore.Signal(bool, bool)
sigSettingsChanged = QtCore.Signal(dict)
_sigStartFrameTimer = QtCore.Signal()
_sigStopFrameTimer = QtCore.Signal()
_sigNextDataFrame = QtCore.Signal()

# declare connectors
_streamer_con = Connector(interface='DataInStreamInterface')
Expand All @@ -67,7 +66,7 @@ def __init__(self, *args, **kwargs):

# locking for thread safety
self.threadlock = Mutex()
self.__frame_timer = None
self._samples_per_frame = None
self._stop_requested = True

# Data arrays
Expand Down Expand Up @@ -95,6 +94,7 @@ def on_activate(self):
self._stop_requested = True
self._data_recording_active = False
self._record_start_time = None
self._samples_per_frame = int(round(self._data_rate / self._max_frame_rate))

# Check for odd moving averaging window
if self._moving_average_width % 2 == 0:
Expand All @@ -104,12 +104,7 @@ def on_activate(self):
self._moving_average_width += 1

# set up timer
self.__frame_timer = QtCore.QTimer()
self.__frame_timer.setInterval(1000 / self._max_frame_rate)
self.__frame_timer.setSingleShot(False)
self.__frame_timer.timeout.connect(self.acquire_data_block)
self._sigStartFrameTimer.connect(self.__frame_timer.start)
self._sigStopFrameTimer.connect(self.__frame_timer.stop)
self._sigNextDataFrame.connect(self.acquire_data_block, QtCore.Qt.QueuedConnection)
return

def on_deactivate(self):
Expand All @@ -119,9 +114,7 @@ def on_deactivate(self):
if self.module_state() == 'locked':
self._stop_reader_wait()

self.__frame_timer.timeout.disconnect()
self._sigStartFrameTimer.disconnect()
self._sigStopFrameTimer.disconnect()
self._sigNextDataFrame.disconnect()
return

def _init_data_arrays(self):
Expand Down Expand Up @@ -357,6 +350,7 @@ def configure_settings(self, settings_dict=None, **kwargs):
data_points = self._moving_average_width
self._trace_window_size = new_val

self._samples_per_frame = int(round(self._data_rate / self._max_frame_rate))
self._init_data_arrays()
settings = self.all_settings
self.sigSettingsChanged.emit(settings)
Expand Down Expand Up @@ -402,7 +396,7 @@ def start_reading(self):
self.sigStatusChanged.emit(False, False)
return -1

self._sigStartFrameTimer.emit()
self._sigNextDataFrame.emit()
return 0

def stop_reading(self):
Expand All @@ -411,9 +405,7 @@ def stop_reading(self):
@return int: error code (0: OK, -1: error)
"""
print('Stop called')
with self.threadlock:
print('Stop in lock')
if self.module_state() == 'locked':
self._stop_requested = True
return 0
Expand All @@ -428,8 +420,6 @@ def acquire_data_block(self):
if self.module_state() == 'locked':
# check for break condition
if self._stop_requested:
# Stop QTimer
self._sigStopFrameTimer.emit()
# terminate the hardware streaming
if self._streamer.stop_stream() < 0:
self.log.error(
Expand All @@ -442,10 +432,10 @@ def acquire_data_block(self):
self.sigStatusChanged.emit(False, False)
return

start = time.perf_counter()
samples_to_read = self._streamer.available_samples
samples_to_read = max(self._streamer.available_samples, self._samples_per_frame)
samples_to_read -= samples_to_read % self._oversampling_factor
if samples_to_read < 1:
self._sigNextDataFrame.emit()
return

# read the current counter values
Expand All @@ -455,20 +445,19 @@ def acquire_data_block(self):
'killing the stream with next data frame.')
self._stop_requested = True
return
print('data read time: {0:.3e}s'.format(time.perf_counter() - start))

# Process data
self._process_trace_data(data)

# Emit update signal
self.sigDataChanged.emit()
self._sigNextDataFrame.emit()
return

def _process_trace_data(self, data):
"""
Processes raw data from the streaming device
"""
start = time.perf_counter()
# Down-sample and average according to oversampling factor
if self._oversampling_factor > 1:
if data.shape[1] % self._oversampling_factor != 0:
Expand Down Expand Up @@ -501,7 +490,6 @@ def _process_trace_data(self, data):
cumsum = np.cumsum(self._trace_data, axis=1)
n = self._moving_average_width
self.trace_data_averaged = (cumsum[:, n:] - cumsum[:, :-n]) / n
print('data processing time: {0:.3e}s'.format(time.perf_counter() - start))
return

def start_recording(self):
Expand Down Expand Up @@ -672,7 +660,6 @@ def _stop_reader_wait(self):
"""
with self.threadlock:
self._stop_requested = True
self._sigStopFrameTimer.emit()
# terminate the hardware streaming
if self._streamer.stop_stream() < 0:
self.log.error(
Expand Down

0 comments on commit 675e877

Please sign in to comment.