touchsim
tutorial¶This notebook demonstrates some basic functionality of the touchsim
package. For more on the in-built plotting options, see touchsim_plotting.ipynb. For a quick guide on overloaded functions see touchsim_shortcuts.ipynb.
import touchsim as ts # import touchsim package
from touchsim.plotting import plot # import in-built plotting function
import numpy as np
import holoviews as hv # import holoviews package for plots and set some parameters
hv.notebook_extension()
%output holomap='scrubber'
import warnings
warnings.simplefilter("ignore")
touchsim
includes a model of the hand surface. Its coordinate system is centered on the distal pad of the index finger. The first axis extends along the index finger towards the base and palm, while the second axis extends orthogonally towards the middle finger. Other spatial layouts can be used via the Surface
class.
%%output size=150
plot(coord=10)
Single afferents belong to the Afferent
class.
a1 = ts.Afferent('SA1',surface=ts.hand_surface) # generate SA1 afferent located at the origin
plot(region='D2') * plot(a1,size=10)
Afferent
objects can be placed anywhere on the skin surface.
# generate PC afferent on distal pad of middle finger
a2 = ts.Afferent('PC',surface=ts.hand_surface,location=ts.hand_surface.centers[ts.hand_surface.tag2idx('D3d')])
plot() * plot(a2,size=10)
Multiple Afferent
objects combine into an AfferentPopulation
object.
a = a1 + a2
print(a)
touchsim
includes several affpop_*
functions that generate commonly used AfferentPopulation
objects. For example affpop_grid
places afferents on a grid. affpop_hand
places afferents on the hand model, in realistic densities. It can be limited to a specific hand region, afferent class, and the overall density can be adjusted.
a_d2 = ts.affpop_hand(region='D2') # limit to digit 2
a_RA = ts.affpop_hand(affclass='RA') # limit to RA afferents
a = ts.affpop_hand(density_multiplier=0.2) # decrease density
plot() * plot(a_d2) + plot() * plot(a_RA) + plot() * plot(a)
Tactile stimuli are represented in touchsim
using Stimulus
objects. These consist of individual pins. Each pin is assigned a location
on the skin surface and its movements orthogonal to the skin surface is described as a time-varying trace
function.
loc = np.zeros((1,2))
trace = 0.1 * np.sin(np.linspace(0.,2.*np.pi*10,5000))
s = ts.Stimulus(location = loc, trace = trace, fs=5000)
plot(s)
A number of commonly used stimuli are implemented as stim_*
functions. These include
stim_ramp
for ramp-hand-hold indentationsstim_sine
for sinusoidal vibrationsstim_noise
for bandpass white noise stimulistim_impulse
for brief "taps" of the skins_ramp = ts.stim_ramp(amp=0.1)
s_sine = ts.stim_sine(amp=0.05,freq=50)
s_noise = ts.stim_noise()
s_impulse = ts.stim_impulse(pad_len = 0.4)
plot(s_ramp) + plot(s_sine) + plot(s_noise) + plot(s_impulse)
Complex stimuli can be generated by combining an object shape, that is a specific spatial pin layout, with a movement trace that is applied to all pins simultaneously. The example below creates a large rounded probe, which is then indented into the skin using a ramp-and-hold pattern. The stim_indent_shape
method is used to combine the spatial pin layout, here created using a shape_*
function, with a movement trace, created using a stim_*
function.
s = ts.stim_indent_shape(ts.shape_circle(hdiff=0.5,pins_per_mm=2,radius=3),ts.stim_ramp(len=0.1,pad_len=0.01))
plot(region='D2d') * plot(s,spatial=True,bin=10)
The response
method of Afferent
and AfferentPopulation
objects calculates the spiking response to any Stimulus
object.
r = a.response(s) # calculate response of a to s.
# Plot response as raster plot and spatially on finger
plot(r) + plot() * plot(r,spatial=True,scaling_factor=0.1)
Responses can be plotted as animations.
plot() * plot(r,spatial=True,bin=5)
Check the docstrings of functions and classes for additional help.
?ts.stim_ramp
Objects can also print information about themselves.
print(r)