计时器不能从另一个线程停止(带有 nidaqmx-python 和回调的简短示例)
Timers cannot be stopped from another thread (short example with nidaqmx-python and callbacks)
我在这个论坛上看到了关于这个主题的其他问题,但是 none 帮助我理解了如何处理这个问题。在我看来,它们中的大多数也是相当复杂和冗长的代码。我相信我正在做一些相当简单的事情/想做一些相当简单的事情。我希望有人能帮帮忙!下面是广泛的解释,然后是我当前的代码。
注意:请不要删除这个问题。我对以下内容进行了很多思考,并且仔细阅读了相关主题,但无济于事。我也相信 post 这很有意义,因为它与一个更通用的问题部分相关:如何在后台进行回调 运行ning 时实时绘图(参见摘要end),这可以概括为我的总体目标。
设置和目标: National Instruments 采集模块(这很重要)NI cDAQ9178,通过 nidaqmx-python
接口,由 NI 维护并带有文档的软件包 here.那里输入了一些模拟信号,目标是在实时绘制信号的同时以一定的采样率(大约 1000 Hz)连续采集它(直到我决定停止采集)。几乎不需要如此频繁地刷新绘图(10Hz 的刷新率甚至可以)。我在 conda 虚拟环境中使用 Windows 10 和 Python 3.7,编辑是在 PyCharm 中完成的。理想情况下,事情应该在 PyCharm 和任何终端上都有效。
情况: nidaqmx-python
提供高级功能,允许注册回调(根据需要定义),每次调用一定数量的回调样本(在我的例子中是 100,但这并不严格)填充了 PC 缓冲区。这个想法是下面定义的回调在那个时候读取缓冲区,并做一些事情(在我的例子中是一些低通滤波,为了简洁我已经去掉了,一些存储到全局变量 data
,也许是密谋——见下文)。
问题:我一直在胡闹,将实时绘制的数据包含在回调中,但是对于 matplotlib 来说这是一场噩梦,因为回调使用其他线程比主要的,而且 matplotlib 不喜欢从主线程之外的任何地方调用。我在谷歌上搜索了其他为实时绘图优化的库(而且,我在想,希望线程安全)但这并不容易:我无法让 vispy 工作,我什至无法安装 pyqtgraph,只是为了给你一些例子。然后我在互联网上看到几个 post 人实际上使用 matplotlib 管理相当不错的实时动画,尽管它是在考虑发布而不是这些应用程序的情况下开发的;所以我想让我们试一试。
我的看法: 因为我不能让 matplotlib 从回调内部完成工作,所以我做了以下(这是你在下面看到的代码):回调之后和在使用 task.start()
(特定于 nidaqmx-python
)开始任务后,我只是创建了一个 while
循环来绘制全局变量 buffer
。我认为这是一个很好的技巧:看,buffer
每 0.1 秒左右(无关紧要)由回调更新(称之为),并且,while
循环正在绘制buffer
变量一遍又一遍,每次都在绘图前擦除,有效地产生了一个实时的绘图。
注意:我完全清楚绘图部分并不像它可以制作的那样好(我可能应该使用 matplotlib 的斧头 API 和 subplots
,更不用说动画了), 但我暂时不在乎。我稍后会处理它并对其进行改进以使其更有效率。
我想要的: 这实际上是我想要的......除了,为了阻止它,我引入了 try:
和 except:
while
循环周围的语句,如您在下面的代码中所见。自然地,按 CTRL+C
确实会打破循环……但它也会打破整个 运行ning 脚本并给我留下以下错误:forrtl: error (200): program aborting due to control-C event
,在 PyCharm,以及来自终端的 运行 时的以下精度:
Image PC Routine Line Source
libifcoremd.dll 00007FFECF413B58 Unknown Unknown Unknown
KERNELBASE.dll 00007FFF219F60A3 Unknown Unknown Unknown
KERNEL32.DLL 00007FFF23847BD4 Unknown Unknown Unknown
ntdll.dll 00007FFF240CCED1 Unknown Unknown Unknown
QObject::~QObject: Timers cannot be stopped from another thread
不方便的是,我别无选择,只能关闭python shell(又想PyCharm),而且我无法访问我宝贵的变量data
,包含……好吧,我的数据。
猜测:显然,回调不喜欢在这种情况下停止。 nidaqmx_python
任务应该用 task.stop()
停止。我尝试将 task.stop()
紧跟在 KeyboardInterrupt except:
之后,但这并没有帮助,因为 CTRL+C
停止了顶部的脚本/而不是中断 while 循环。我相信需要一些更复杂的方法来停止我的任务。几天来我一直在考虑这个问题,但想不出一种同时拥有这两种东西的方法:一个我可以停止的任务,同时实时绘图。请注意,如果没有绘图,很容易在 ENTER
按键时停止任务:只需在末尾写
input('Press ENTER to stop task')
task.stop()
当然,仅仅执行上述操作并不能包含实时绘图部分。
总结:我无法从连续读取数据的回调中调用matplotlib,所以我在一个单独的块中写了一个while
循环用于实时绘图,但是后来我发现没有办法在不出现上述错误的情况下停止 while
循环(我认为它抱怨回调是从另一个线程停止的)。
我希望我说清楚了,如果不清楚,请务必提问!
代码: 我已经清理它以使其尽可能接近显示问题的 MWE,当然我知道你们中的大多数人都不知道没有 NI daq 可以玩和连接以便能够 运行 这个。无论如何...在这里:
import matplotlib.pyplot as plt
import numpy as np
import nidaqmx
from nidaqmx import stream_readers
from nidaqmx import constants
sfreq = 1000
bufsize = 100
with nidaqmx.Task() as task:
# Here we set up the task ... nevermind
task.ai_channels.add_ai_voltage_chan("cDAQ2Mod1/ai1")
task.timing.cfg_samp_clk_timing(rate=sfreq, sample_mode=constants.AcquisitionType.CONTINUOUS,
samps_per_chan=bufsize)
# Here we define a stream to be read continuously
stream = stream_readers.AnalogMultiChannelReader(task.in_stream)
data = np.zeros((1, 0)) # initializing an empty numpy array for my total data
buffer = np.zeros((1, bufsize)) # defined so that global buffer can be written to by the callback
# This is my callback to read data continuously
def reading_task_callback(task_idx, event_type, num_samples, callback_data): # bufsize is passed to num_samples when this is called
global data
global buffer
buffer = np.zeros((1, num_samples))
# This is the reading part
stream.read_many_sample(buffer, num_samples, timeout=constants.WAIT_INFINITELY)
data = np.append(data, buffer, axis=1) # appends buffered data to variable data
return 0 # Absolutely needed for this callback to be well defined (see nidaqmx doc).
# Here is the heavy lifting I believe: the above callback is registered
task.register_every_n_samples_acquired_into_buffer_event(bufsize, reading_task_callback)
task.start() # The task is started (callback called periodically)
print('Acquiring sensor data. Press CTRL+C to stop the run.\n') # This should work ...
fig = plt.figure()
try:
while True:
# Poor's man plot updating
plt.clf()
plt.plot(buffer.T)
plt.show()
plt.pause(0.01) # 100 Hz refresh rate
except KeyboardInterrupt: # stop loop with CTRL+C ... or so I thought :-(
plt.close(fig)
pass
task.stop() # I believe I never get to this part after pressing CTRL+C ...
# Some prints at the end ... nevermind
print('Total number of acquired samples: ', len(data.T),'\n')
print('Sampling frequency: ', sfreq, 'Hz\n')
print('Buffer size: ', bufsize, '\n')
print('Acquisition duration: ', len(data.T)/sfreq, 's\n')
如有任何意见,我们将不胜感激。提前谢谢大家!
编辑:在下面接受答案后,我重写了上面的代码并得出了以下代码,现在可以按预期工作了(抱歉,这次我没有清理它,有些行与现在的问题):
# Stream read from a task that is set up to read continuously
import matplotlib.pyplot as plt
import numpy as np
import nidaqmx
from nidaqmx import stream_readers
from nidaqmx import constants
from scipy import signal
import threading
running = True
sfreq = 1000
bufsize = 100
bufsizeb = 100
global task
def askUser(): # it might be better to put this outside of task
global running
input("Press return to stop.")
running = False
def main():
global running
global data
global buffer
global data_filt
global buffer_filt
global b
global z
print('Acquiring sensor data...')
with nidaqmx.Task() as task: # maybe we can use target as above
thread = threading.Thread(target=askUser)
thread.start()
task.ai_channels.add_ai_voltage_chan("cDAQ2Mod1/ai1")
task.timing.cfg_samp_clk_timing(rate=sfreq, sample_mode=constants.AcquisitionType.CONTINUOUS,
samps_per_chan=bufsize)
# unclear samps_per_chan is needed here above or why it would be different than bufsize
stream = stream_readers.AnalogMultiChannelReader(task.in_stream)
data = np.zeros((1, 0)) # probably not the most elegant way of initializing an empty numpy array
buffer = np.zeros((1, bufsizeb)) # defined so that global buffer can be written in the callback
data_filt = np.zeros((1, 0)) # probably not the most elegant way of initializing an empty numpy array
buffer_filt = np.zeros((1, bufsizeb)) # defined so that global buffer can be written in the callback
b = signal.firwin(150, 0.004)
z = signal.lfilter_zi(b, 1)
def reading_task_callback(task_idx, event_type, num_samples, callback_data): # bufsizeb is passed to num_samples
global data
global buffer
global data_filt
global buffer_filt
global z
global b
if running:
# It may be wiser to read slightly more than num_samples here, to make sure one does not miss any sample,
# see: https://documentation.help/NI-DAQmx-Key-Concepts/contCAcqGen.html
buffer = np.zeros((1, num_samples))
stream.read_many_sample(buffer, num_samples, timeout=constants.WAIT_INFINITELY)
data = np.append(data, buffer, axis=1) # appends buffered data to variable data
# IIR Filtering, low-pass
buffer_filt = np.zeros((1, num_samples))
for i, x in enumerate(np.squeeze(buffer)): # squeeze required for x to be just a scalar (which lfilter likes)
buffer_filt[0,i], z = signal.lfilter(b, 1, [x], zi=z)
data_filt = np.append(data_filt, buffer_filt, axis=1) # appends buffered filtered data to variable data_filt
return 0 # Absolutely needed for this callback to be well defined (see nidaqmx doc).
task.register_every_n_samples_acquired_into_buffer_event(bufsizeb, reading_task_callback) # bufsizeb instead
task.start()
while running: # this is perfect: it "stops" the console just like sleep in a way that the task does not stop
plt.clf()
plt.plot(buffer.T)
plt.draw()
plt.pause(0.01) # 100 Hz refresh rate
# plt.close(fig) # maybe no need to close it for now
# task.join() # this is for threads I guess ... (seems useless to my case?)
# Some prints at the end ...
print('Total number of acquired samples:', len(data.T))
print('Sampling frequency:', sfreq, 'Hz')
print('Buffer size:', bufsize)
print('Acquisition duration:', len(data.T)/sfreq, 's')
if __name__ == '__main__':
main()
请注意,毕竟我不需要 task.stop()
,因为连续获取任务使用此包的方式是读取 task.start()
之后的任何代码行,这不是 sleep
或类似的东西使任务停止(至少这是我的理解)。
我做的第一件事就是摆脱键盘中断循环。我用一个全局变量 running
替换了它,另一个线程在返回时将变量设置为 False
。
def askUser():
global running
input("Press return to stop.")
running = False
然后,在 while loop
之前,创建了一个将执行此函数的新线程。
askUserThread = threading.Thread(target=askUser)
askUserThread.start()
对于 while 循环,去掉 try
catch
语句:
while running:
plt.clf()
plt.plot(buffer.T)
plt.draw() # Note: this got changed because .show wasn't working.
plt.pause(0.01)
这对我来说仍然不起作用,因为我必须关闭情节 window 才能出现新情节。所以从this answer,我把它从.show
改成了.draw
。
我的结束代码有点不同(因为我对随机数据进行了采样)但就是这样。
# sampling.py
# by Preston Hager
import matplotlib.pyplot as plt
import numpy as np
import threading
sfreq = 1000
bufsize = 100
running = True
data = np.zeros((1, 0)) # initializing an empty numpy array for my total data
buffer = np.zeros((1, bufsize)) # defined so that global buffer can be written to by the callback
def askUser():
global running
input("Press return to stop.")
running = False
def readingTask():
global data
global buffer
while running:
buffer = np.random.rand(1, bufsize)
# This is the reading part
data = np.append(data, buffer, axis=1) # appends buffered data to variable data
def main():
global running
print('Acquiring sensor data.')
thread = threading.Thread(target=askUser)
thread.start()
task = threading.Thread(target=readingTask)
task.start()
fig = plt.figure()
while running:
# Poor's man plot updating
plt.clf()
plt.plot(buffer.T)
plt.draw()
plt.pause(0.01) # 100 Hz refresh rate
plt.close(fig)
task.join()
# Some prints at the end ... nevermind
print('Total number of acquired samples:', len(data.T))
print('Sampling frequency:', sfreq, 'Hz')
print('Buffer size:', bufsize)
print('Acquisition duration:', len(data.T)/sfreq, 's')
if __name__ == '__main__':
main()
我在这个论坛上看到了关于这个主题的其他问题,但是 none 帮助我理解了如何处理这个问题。在我看来,它们中的大多数也是相当复杂和冗长的代码。我相信我正在做一些相当简单的事情/想做一些相当简单的事情。我希望有人能帮帮忙!下面是广泛的解释,然后是我当前的代码。
注意:请不要删除这个问题。我对以下内容进行了很多思考,并且仔细阅读了相关主题,但无济于事。我也相信 post 这很有意义,因为它与一个更通用的问题部分相关:如何在后台进行回调 运行ning 时实时绘图(参见摘要end),这可以概括为我的总体目标。
设置和目标: National Instruments 采集模块(这很重要)NI cDAQ9178,通过 nidaqmx-python
接口,由 NI 维护并带有文档的软件包 here.那里输入了一些模拟信号,目标是在实时绘制信号的同时以一定的采样率(大约 1000 Hz)连续采集它(直到我决定停止采集)。几乎不需要如此频繁地刷新绘图(10Hz 的刷新率甚至可以)。我在 conda 虚拟环境中使用 Windows 10 和 Python 3.7,编辑是在 PyCharm 中完成的。理想情况下,事情应该在 PyCharm 和任何终端上都有效。
情况: nidaqmx-python
提供高级功能,允许注册回调(根据需要定义),每次调用一定数量的回调样本(在我的例子中是 100,但这并不严格)填充了 PC 缓冲区。这个想法是下面定义的回调在那个时候读取缓冲区,并做一些事情(在我的例子中是一些低通滤波,为了简洁我已经去掉了,一些存储到全局变量 data
,也许是密谋——见下文)。
问题:我一直在胡闹,将实时绘制的数据包含在回调中,但是对于 matplotlib 来说这是一场噩梦,因为回调使用其他线程比主要的,而且 matplotlib 不喜欢从主线程之外的任何地方调用。我在谷歌上搜索了其他为实时绘图优化的库(而且,我在想,希望线程安全)但这并不容易:我无法让 vispy 工作,我什至无法安装 pyqtgraph,只是为了给你一些例子。然后我在互联网上看到几个 post 人实际上使用 matplotlib 管理相当不错的实时动画,尽管它是在考虑发布而不是这些应用程序的情况下开发的;所以我想让我们试一试。
我的看法: 因为我不能让 matplotlib 从回调内部完成工作,所以我做了以下(这是你在下面看到的代码):回调之后和在使用 task.start()
(特定于 nidaqmx-python
)开始任务后,我只是创建了一个 while
循环来绘制全局变量 buffer
。我认为这是一个很好的技巧:看,buffer
每 0.1 秒左右(无关紧要)由回调更新(称之为),并且,while
循环正在绘制buffer
变量一遍又一遍,每次都在绘图前擦除,有效地产生了一个实时的绘图。
注意:我完全清楚绘图部分并不像它可以制作的那样好(我可能应该使用 matplotlib 的斧头 API 和 subplots
,更不用说动画了), 但我暂时不在乎。我稍后会处理它并对其进行改进以使其更有效率。
我想要的: 这实际上是我想要的......除了,为了阻止它,我引入了 try:
和 except:
while
循环周围的语句,如您在下面的代码中所见。自然地,按 CTRL+C
确实会打破循环……但它也会打破整个 运行ning 脚本并给我留下以下错误:forrtl: error (200): program aborting due to control-C event
,在 PyCharm,以及来自终端的 运行 时的以下精度:
Image PC Routine Line Source
libifcoremd.dll 00007FFECF413B58 Unknown Unknown Unknown
KERNELBASE.dll 00007FFF219F60A3 Unknown Unknown Unknown
KERNEL32.DLL 00007FFF23847BD4 Unknown Unknown Unknown
ntdll.dll 00007FFF240CCED1 Unknown Unknown Unknown
QObject::~QObject: Timers cannot be stopped from another thread
不方便的是,我别无选择,只能关闭python shell(又想PyCharm),而且我无法访问我宝贵的变量data
,包含……好吧,我的数据。
猜测:显然,回调不喜欢在这种情况下停止。 nidaqmx_python
任务应该用 task.stop()
停止。我尝试将 task.stop()
紧跟在 KeyboardInterrupt except:
之后,但这并没有帮助,因为 CTRL+C
停止了顶部的脚本/而不是中断 while 循环。我相信需要一些更复杂的方法来停止我的任务。几天来我一直在考虑这个问题,但想不出一种同时拥有这两种东西的方法:一个我可以停止的任务,同时实时绘图。请注意,如果没有绘图,很容易在 ENTER
按键时停止任务:只需在末尾写
input('Press ENTER to stop task')
task.stop()
当然,仅仅执行上述操作并不能包含实时绘图部分。
总结:我无法从连续读取数据的回调中调用matplotlib,所以我在一个单独的块中写了一个while
循环用于实时绘图,但是后来我发现没有办法在不出现上述错误的情况下停止 while
循环(我认为它抱怨回调是从另一个线程停止的)。
我希望我说清楚了,如果不清楚,请务必提问!
代码: 我已经清理它以使其尽可能接近显示问题的 MWE,当然我知道你们中的大多数人都不知道没有 NI daq 可以玩和连接以便能够 运行 这个。无论如何...在这里:
import matplotlib.pyplot as plt
import numpy as np
import nidaqmx
from nidaqmx import stream_readers
from nidaqmx import constants
sfreq = 1000
bufsize = 100
with nidaqmx.Task() as task:
# Here we set up the task ... nevermind
task.ai_channels.add_ai_voltage_chan("cDAQ2Mod1/ai1")
task.timing.cfg_samp_clk_timing(rate=sfreq, sample_mode=constants.AcquisitionType.CONTINUOUS,
samps_per_chan=bufsize)
# Here we define a stream to be read continuously
stream = stream_readers.AnalogMultiChannelReader(task.in_stream)
data = np.zeros((1, 0)) # initializing an empty numpy array for my total data
buffer = np.zeros((1, bufsize)) # defined so that global buffer can be written to by the callback
# This is my callback to read data continuously
def reading_task_callback(task_idx, event_type, num_samples, callback_data): # bufsize is passed to num_samples when this is called
global data
global buffer
buffer = np.zeros((1, num_samples))
# This is the reading part
stream.read_many_sample(buffer, num_samples, timeout=constants.WAIT_INFINITELY)
data = np.append(data, buffer, axis=1) # appends buffered data to variable data
return 0 # Absolutely needed for this callback to be well defined (see nidaqmx doc).
# Here is the heavy lifting I believe: the above callback is registered
task.register_every_n_samples_acquired_into_buffer_event(bufsize, reading_task_callback)
task.start() # The task is started (callback called periodically)
print('Acquiring sensor data. Press CTRL+C to stop the run.\n') # This should work ...
fig = plt.figure()
try:
while True:
# Poor's man plot updating
plt.clf()
plt.plot(buffer.T)
plt.show()
plt.pause(0.01) # 100 Hz refresh rate
except KeyboardInterrupt: # stop loop with CTRL+C ... or so I thought :-(
plt.close(fig)
pass
task.stop() # I believe I never get to this part after pressing CTRL+C ...
# Some prints at the end ... nevermind
print('Total number of acquired samples: ', len(data.T),'\n')
print('Sampling frequency: ', sfreq, 'Hz\n')
print('Buffer size: ', bufsize, '\n')
print('Acquisition duration: ', len(data.T)/sfreq, 's\n')
如有任何意见,我们将不胜感激。提前谢谢大家!
编辑:在下面接受答案后,我重写了上面的代码并得出了以下代码,现在可以按预期工作了(抱歉,这次我没有清理它,有些行与现在的问题):
# Stream read from a task that is set up to read continuously
import matplotlib.pyplot as plt
import numpy as np
import nidaqmx
from nidaqmx import stream_readers
from nidaqmx import constants
from scipy import signal
import threading
running = True
sfreq = 1000
bufsize = 100
bufsizeb = 100
global task
def askUser(): # it might be better to put this outside of task
global running
input("Press return to stop.")
running = False
def main():
global running
global data
global buffer
global data_filt
global buffer_filt
global b
global z
print('Acquiring sensor data...')
with nidaqmx.Task() as task: # maybe we can use target as above
thread = threading.Thread(target=askUser)
thread.start()
task.ai_channels.add_ai_voltage_chan("cDAQ2Mod1/ai1")
task.timing.cfg_samp_clk_timing(rate=sfreq, sample_mode=constants.AcquisitionType.CONTINUOUS,
samps_per_chan=bufsize)
# unclear samps_per_chan is needed here above or why it would be different than bufsize
stream = stream_readers.AnalogMultiChannelReader(task.in_stream)
data = np.zeros((1, 0)) # probably not the most elegant way of initializing an empty numpy array
buffer = np.zeros((1, bufsizeb)) # defined so that global buffer can be written in the callback
data_filt = np.zeros((1, 0)) # probably not the most elegant way of initializing an empty numpy array
buffer_filt = np.zeros((1, bufsizeb)) # defined so that global buffer can be written in the callback
b = signal.firwin(150, 0.004)
z = signal.lfilter_zi(b, 1)
def reading_task_callback(task_idx, event_type, num_samples, callback_data): # bufsizeb is passed to num_samples
global data
global buffer
global data_filt
global buffer_filt
global z
global b
if running:
# It may be wiser to read slightly more than num_samples here, to make sure one does not miss any sample,
# see: https://documentation.help/NI-DAQmx-Key-Concepts/contCAcqGen.html
buffer = np.zeros((1, num_samples))
stream.read_many_sample(buffer, num_samples, timeout=constants.WAIT_INFINITELY)
data = np.append(data, buffer, axis=1) # appends buffered data to variable data
# IIR Filtering, low-pass
buffer_filt = np.zeros((1, num_samples))
for i, x in enumerate(np.squeeze(buffer)): # squeeze required for x to be just a scalar (which lfilter likes)
buffer_filt[0,i], z = signal.lfilter(b, 1, [x], zi=z)
data_filt = np.append(data_filt, buffer_filt, axis=1) # appends buffered filtered data to variable data_filt
return 0 # Absolutely needed for this callback to be well defined (see nidaqmx doc).
task.register_every_n_samples_acquired_into_buffer_event(bufsizeb, reading_task_callback) # bufsizeb instead
task.start()
while running: # this is perfect: it "stops" the console just like sleep in a way that the task does not stop
plt.clf()
plt.plot(buffer.T)
plt.draw()
plt.pause(0.01) # 100 Hz refresh rate
# plt.close(fig) # maybe no need to close it for now
# task.join() # this is for threads I guess ... (seems useless to my case?)
# Some prints at the end ...
print('Total number of acquired samples:', len(data.T))
print('Sampling frequency:', sfreq, 'Hz')
print('Buffer size:', bufsize)
print('Acquisition duration:', len(data.T)/sfreq, 's')
if __name__ == '__main__':
main()
请注意,毕竟我不需要 task.stop()
,因为连续获取任务使用此包的方式是读取 task.start()
之后的任何代码行,这不是 sleep
或类似的东西使任务停止(至少这是我的理解)。
我做的第一件事就是摆脱键盘中断循环。我用一个全局变量 running
替换了它,另一个线程在返回时将变量设置为 False
。
def askUser():
global running
input("Press return to stop.")
running = False
然后,在 while loop
之前,创建了一个将执行此函数的新线程。
askUserThread = threading.Thread(target=askUser)
askUserThread.start()
对于 while 循环,去掉 try
catch
语句:
while running:
plt.clf()
plt.plot(buffer.T)
plt.draw() # Note: this got changed because .show wasn't working.
plt.pause(0.01)
这对我来说仍然不起作用,因为我必须关闭情节 window 才能出现新情节。所以从this answer,我把它从.show
改成了.draw
。
我的结束代码有点不同(因为我对随机数据进行了采样)但就是这样。
# sampling.py
# by Preston Hager
import matplotlib.pyplot as plt
import numpy as np
import threading
sfreq = 1000
bufsize = 100
running = True
data = np.zeros((1, 0)) # initializing an empty numpy array for my total data
buffer = np.zeros((1, bufsize)) # defined so that global buffer can be written to by the callback
def askUser():
global running
input("Press return to stop.")
running = False
def readingTask():
global data
global buffer
while running:
buffer = np.random.rand(1, bufsize)
# This is the reading part
data = np.append(data, buffer, axis=1) # appends buffered data to variable data
def main():
global running
print('Acquiring sensor data.')
thread = threading.Thread(target=askUser)
thread.start()
task = threading.Thread(target=readingTask)
task.start()
fig = plt.figure()
while running:
# Poor's man plot updating
plt.clf()
plt.plot(buffer.T)
plt.draw()
plt.pause(0.01) # 100 Hz refresh rate
plt.close(fig)
task.join()
# Some prints at the end ... nevermind
print('Total number of acquired samples:', len(data.T))
print('Sampling frequency:', sfreq, 'Hz')
print('Buffer size:', bufsize)
print('Acquisition duration:', len(data.T)/sfreq, 's')
if __name__ == '__main__':
main()