神经科学实验工具
toon的Python项目详细描述
卡通
说明
神经科学实验的附加工具,包括:
- 在单独进程上轮询输入设备的框架。
- 基于关键帧的动画框架。
一切都应该在windows/mac/linux上运行。
有关依赖项,请参见requirements.txt。
安装
当前版本:
pip install toon
开发版本:
pip install git+https://github.com/aforren1/toon
完整安装(包括设备和演示依赖项):
pip install toon[full]
请参阅setup.py以获取这些依赖项以及特定于设备的子划分的列表。
有关用法示例,请参见demos/文件夹(注意:有些需要psychopy)。
概述
输入
^
我们使用内置的multiprocessing
模块来控制承载设备的单独进程,并与numpy
一起,通过共享内存将数据移动到主进程。似乎在典型情况下,我们可以预期单个read()
操作所需的时间不到500微秒(通常是100微秒)。有关测量用户端读取性能的示例,请参见demos/bench.py。
典型用法如下:
fromtoon.inputimportMpDevicefromtoon.input.mouseimportMousefromtimeitimportdefault_timerdevice=MpDevice(Mouse())withdevice:t1=default_timer()+10whiledefault_timer()<t1:data=device.read()# alternatively, unpack# clicks, pos, scroll = device.read()ifdata.posisnotNone:# N-D array of data (0th dim is time)print(data.pos)# time is 1D array of timestampsprint(data.pos.time)print(data.pos[-1].time)# most recent timestamp
创建自定义设备相对简单,不过有几个复选框要选中。
fromtoon.inputimportBaseDevice,make_obsfromctypesimportc_double# Obs is a class that manages observationsclassMyDevice(BaseDevice):# optional: give a hint for the buffer size (we'll allocate 1s worth of this)sampling_frequency=500# required: each data source gets its own Obs# can have multiple Obs per device# this can either be introduced at the class level, or during __init__# ctype can be a python type, numpy dtype, or ctypePos=make_obs('Pos',shape=(3,),ctype=float)RotMat=make_obs('RotMat',(3,3),c_double)# 2D data# optional. Do not start device communication here, wait until `enter`def__init__(self):pass## Use `enter` and `exit`, rather than `__enter__` and `__exit__`# optional: configure the device, start communicatingdefenter(self):pass# optional: clean up resources, close devicedefexit(self,*args):pass# requireddefread(self):# See demos/ for examples of sharing a time source between the processestime=self.clock()# store new data with a timestamppos=self.Pos(time,(1,2,3))rotmat=self.RotMat(time,[[1,2,3],[4,5,6],[7,8,9]])# can also be explicit, i.e. `self.Returns(pos=pos, rotmat=rotmat)`returnpos,rotmat
然后,可以将此设备传递给toon.input.MpDevice
,它预先分配共享内存并处理其他详细信息。
对于由MpDevice
返回的数据,需要注意的一些事项:
- 如果设备只有一个
Obs
,则MpDevice
返回一个TsArray
(具有time
属性的numpy数组)。否则,MpDevice
返回一个命名的观察元组,其中的名称按字母顺序排序,是预定义的Obs
的小写版本。 - 如果一次读取返回的数据是标量(例如1D力传感器),
MpDevice
将删除第一个维度。 - 如果没有给定观测值的数据,则返回
None
。命名元组有一个同时检查所有成员的方法(data.any()
)。
其他注意事项:
- 返回的数据是数据的本地副本的view。
toon.input.TsArray
s和设备Returns
有一个copy
方法,如果将其附加到列表以供以后连接,则该方法可能很有用。 - 关于:连接,通过
from toon.input import stack
有一个stack
函数可用,它类似于numpy的vstack
,但保持时间属性不变。它还为TsArray
s或Returns
适当地分派。 - 如果在从设备读取数据时接收到成批数据,则可以返回
Returns
的列表(例如,请参见tests/input/mockdevices.py
)。 - 您可以选择使用
device.start()
/device.stop()
而不是上下文管理器。 - 您可以使用
device.check_error()
在任何时候检查远程错误,尽管这在进入上下文管理器和读取时自动发生。 - 除了python类型/dtypes/cTypes之外,
Obs
还可以使用ctypes.Structure
s(参见输入测试或cyberglove示例)。
动画
这仍然是一个正在进行的工作,虽然我认为它有一些实用性。它是Magnum框架中动画组件的一个端口,尽管缺少一些特性(例如轨迹外推、对时间缩放的正确处理)。
示例:
frommathimportsin,pifromtimeimportsleepfromtimeitimportdefault_timerimportmatplotlib.pyplotaspltfromtoon.animimportTrack,Player# see toon/anim/easing.py for all available easingsfromtoon.anim.easingimportlinearclassCircle(object):x=0y=0circle=Circle()# list of (time, value)keyframes=[(0.2,-0.5),(0.5,0),(3,0.5)]x_track=Track(keyframes,easing=linear)# currently, easings can be any function that takes a single# positional argument as input (time normalized to [0, 1]) and returns# a scalar (probably float), generally having a lower asymptote# of 0 and upper asymptote of 1, which is used as the current time# for purposes of interpolationdefelastic_in(x):returnpow(2.0,10.0*(x-1.0))*sin(13.0*pihalf*x)# we can reuse keyframesy_track=Track(keyframes,easing=elastic_in)player=Player(repeats=3)# directly modify an attributeplayer.add(x_track,'x',obj=circle)defy_cb(val,obj):obj.y=val# modify via callbackplayer.add(y_track,y_cb,obj=circle)t0=default_timer()player.start(t0)vals=[]whileplayer.is_playing:player.advance(default_timer())vals.append([circle.x,circle.y])sleep(1/60)plt.plot(vals)plt.show()
其他注意事项:
- 非数字属性,如颜色字符串,也可以在这个框架中修改(宽松被忽略)。
Timeline
类(intoon.anim
)可用于获取帧之间的时间,或自某个起始时间以来的时间,在timeline.start()
处获取。- ^ {CD38>}也可用作MIXIN,在这种情况下,{{CD39>}参数可以从^ {CD40}中省略(参见示例{demos/文件夹)。
- 通过向
player.add()
中输入一个对象列表,可以同时修改多个对象。