{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# `touchsim` tutorial\n", "This notebook demonstrates some basic functionality of the `touchsim` package. For more on the in-built plotting options, see [touchsim_plotting.ipynb](./touchsim_plotting.ipynb). For a quick guide on overloaded functions see [touchsim_shortcuts.ipynb](./touchsim_shortcuts.ipynb)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import touchsim as ts # import touchsim package\n", "from touchsim.plotting import plot # import in-built plotting function\n", "import numpy as np\n", "import holoviews as hv # import holoviews package for plots and set some parameters\n", "hv.notebook_extension()\n", "%output holomap='scrubber'\n", "\n", "import warnings\n", "warnings.simplefilter(\"ignore\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Hand regions and the coordinate system\n", "`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." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%output size=150\n", "plot(coord=10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Generating individual afferents and populations\n", "Single afferents belong to the `Afferent` class." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a1 = ts.Afferent('SA1',surface=ts.hand_surface) # generate SA1 afferent located at the origin\n", "\n", "plot(region='D2') * plot(a1,size=10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Afferent` objects can be placed anywhere on the skin surface." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# generate PC afferent on distal pad of middle finger\n", "a2 = ts.Afferent('PC',surface=ts.hand_surface,location=ts.hand_surface.centers[ts.hand_surface.tag2idx('D3d')])\n", "\n", "plot() * plot(a2,size=10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Multiple `Afferent` objects combine into an `AfferentPopulation` object." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = a1 + a2\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`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." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a_d2 = ts.affpop_hand(region='D2') # limit to digit 2\n", "a_RA = ts.affpop_hand(affclass='RA') # limit to RA afferents\n", "a = ts.affpop_hand(density_multiplier=0.2) # decrease density\n", "\n", "plot() * plot(a_d2) + plot() * plot(a_RA) + plot() * plot(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Generating touch stimuli\n", "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." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "loc = np.zeros((1,2))\n", "trace = 0.1 * np.sin(np.linspace(0.,2.*np.pi*10,5000))\n", "s = ts.Stimulus(location = loc, trace = trace, fs=5000)\n", "\n", "plot(s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Generating simple stimuli\n", "A number of commonly used stimuli are implemented as `stim_*` functions. These include\n", "* `stim_ramp` for ramp-hand-hold indentations\n", "* `stim_sine` for sinusoidal vibrations\n", "* `stim_noise` for bandpass white noise stimuli\n", "* `stim_impulse` for brief \"taps\" of the skin" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s_ramp = ts.stim_ramp(amp=0.1)\n", "s_sine = ts.stim_sine(amp=0.05,freq=50)\n", "s_noise = ts.stim_noise()\n", "s_impulse = ts.stim_impulse(pad_len = 0.4)\n", "\n", "plot(s_ramp) + plot(s_sine) + plot(s_noise) + plot(s_impulse)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Generating complex stimuli\n", "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." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "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))\n", "\n", "plot(region='D2d') * plot(s,spatial=True,bin=10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Calculating responses\n", "The `response` method of `Afferent` and `AfferentPopulation` objects calculates the spiking response to any `Stimulus` object." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "r = a.response(s) # calculate response of a to s.\n", "\n", "# Plot response as raster plot and spatially on finger\n", "plot(r) + plot() * plot(r,spatial=True,scaling_factor=0.1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Responses can be plotted as animations." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plot() * plot(r,spatial=True,bin=5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Getting help\n", "Check the docstrings of functions and classes for additional help." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "?ts.stim_ramp" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Objects can also print information about themselves." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(r)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.10" } }, "nbformat": 4, "nbformat_minor": 4 }