{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Generating a sinusoidal pulse train\n\n*This example shows how to build a sinusoidal pulse train from scratch.*\n\nIn addition to built-in stimuli such as\n:py:class:`~pulse2percept.stimuli.BiphasicPulse` and\n:py:class:`~pulse2percept.stimuli.BiphasicPulseTrain`, you can also create your\nown :py:class:`~pulse2percept.stimuli.Stimulus` by manually specifying the\nvalues for the ``data`` container and ``time`` axis.\n\nConsider a sine wave:\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "from pulse2percept.utils.constants import DT\nfrom pulse2percept.stimuli import Stimulus\nimport numpy as np\nimport matplotlib.pyplot as plt\nplt.style.use('ggplot')\n\n\nt = np.linspace(0, 2 * np.pi, 100)\nx = np.sin(t)\nplt.plot(t, x)\nplt.xlabel('Time (ms)')\nplt.ylabel('Amplitude')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "To turn this sine wave into a stimulus feasible for a retinal implant, it\nwill have to be discretized to a number of different amplitude levels.\n\nThe following code turns the sine wave into 5 different amplitude levels:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "levels = np.linspace(-1, 1, num=5)\ndata = levels[np.argmin(np.abs(x[:, np.newaxis] - levels), axis=1)]\n\nplt.plot(t, data, label='discretized')\nplt.plot(t, x, label='original')\nplt.xlabel('Time (ms)')\nplt.ylabel('Amplitude')\nplt.legend()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We can turn this signal into a :py:class:`~pulse2percept.stimuli.Stimulus`\nobject as follows:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "stim = Stimulus(10 * data.reshape((1, -1)), time=t)\nstim.plot()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Alternatively, we can automate this process by creating a new class\n``SinusoidalPulse`` that inherits from ``Stimulus``:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "class SinusoidalPulse(Stimulus):\n\n    def __init__(self, amp, freq, phase, stim_dur, n_levels=5, dt=DT):\n        \"\"\"Sinusoidal pulse\n\n        Parameters\n        ----------\n        amp : float\n            Maximum stimulus amplitude (uA)\n        freq : float\n            Ordinary frequency of the sine wave (Hz)\n        phase : float\n            Phase of the sine wave (rad)\n        stim_dur : float\n            Stimulus duration (ms)\n        n_levels : int, optional, default: 5\n            Number of discretization levels\n        dt : float, optional, default: 0.001\n            Smallest time step (ms)\n        \"\"\"\n        # Create the sine wave:\n        t = np.arange(0, stim_dur + dt / 2, dt)\n        x = np.sin(2 * np.pi * freq * t + phase)\n        # Discretize it:\n        levels = np.linspace(-1, 1, num=n_levels)\n        data = levels[np.argmin(np.abs(x[:, np.newaxis] - levels), axis=1)]\n        # Reshape data to 1xM so it is interpreted as M data points for a\n        # single electrode:\n        data = amp * data.reshape((1, -1))\n        # Call the Stimulus constructor:\n        super(SinusoidalPulse, self).__init__(data, time=t, compress=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Then we can create a new pulse as follows:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "sine = SinusoidalPulse(26, 0.25, -np.pi / 4, 20)\nsine.plot()"
      ]
    }
  ],
  "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.7.9"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}