
.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "examples\models\plot_granley2021_biphasic.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_examples_models_plot_granley2021_biphasic.py>`
        to download the full example code.

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_examples_models_plot_granley2021_biphasic.py:


===============================================================================
Granley et al. (2021): Pulse parameters shape phosphene appearance
===============================================================================

The axon map model of [Beyeler2019]_ predicts one phosphene shape per
electrode, regardless of the pulse train. [Granley2021]_ adds three scaling
factors, fit to psychophysical and electrophysiological data: amplitude,
frequency, and phase duration modulate
brightness (:math:`F_\mathrm{bright}`), spatial extent
(:math:`F_\mathrm{size}`, scaling :math:`\rho`), and streak length
(:math:`F_\mathrm{streak}`, scaling :math:`\lambda`).

This example qualitatively recreates Fig. 3 of [Granley2021]_. Each row
sweeps one pulse parameter on one Argus II electrode:

* **amplitude** makes the phosphene brighter *and* larger,
* **frequency** makes it brighter but not larger,
* **phase duration** shortens the axonal streak.

.. GENERATED FROM PYTHON SOURCE LINES 22-29

.. code-block:: Python

    import matplotlib.pyplot as plt

    from pulse2percept.implants.retina import ArgusII
    from pulse2percept.models.retina import BiphasicAxonMapModel
    from pulse2percept.stimuli import BiphasicPulseTrain
    from pulse2percept.units import xTh








.. GENERATED FROM PYTHON SOURCE LINES 30-37

One electrode, one model
------------------------

``rho`` and ``lam`` (um) are the baseline spread across and along axons.
``lam = 800`` um (longer than in the paper) elongates the baseline phosphene
to about 2.5:1, so the streak effect in the bottom row is visible. The grid
covers the region electrode A4 of a right-eye Argus II projects to.

.. GENERATED FROM PYTHON SOURCE LINES 37-54

.. code-block:: Python


    ELECTRODE = 'A4'
    BASE_FREQ = 5     # Hz
    BASE_AMP = 1      # xTh
    BASE_PDUR = 0.45  # ms

    model = BiphasicAxonMapModel(implant=ArgusII(), rho=200, lam=800,
                                 xrange=(-10.5, 1.5), yrange=(-2, 10), step=0.1)
    model.build()


    def predict(freq, amp, pdur):
        """Brightest frame of the percept for one biphasic pulse train"""
        train = BiphasicPulseTrain(freq, amp * xTh, pdur)
        return model.predict_percept({ELECTRODE: train}).data[..., 0]









.. GENERATED FROM PYTHON SOURCE LINES 55-66

The three sweeps
----------------

Amplitude is in multiples of perceptual threshold (``xTh``), defined at
0.45 ms phase duration.

In this model, threshold falls as phase duration grows (``a0 * pdur + a1``,
Eq. 3): a fixed ``1 xTh`` at 100 ms would be ~200x the threshold-scaled
amplitude at 0.45 ms and saturate. The phase-duration row therefore divides
amplitude by the same factor, so phase duration acts only through
:math:`F_\mathrm{streak}`.

.. GENERATED FROM PYTHON SOURCE LINES 66-86

.. code-block:: Python


    AMPS = [1, 2, 3, 4, 5, 6]              # xTh, at 5 Hz / 0.45 ms
    FREQS = [5, 10, 20, 40, 80, 120]       # Hz, at 1 xTh / 0.45 ms
    PDURS = [0.1, 1, 5, 25, 50, 100]       # ms, at 5 Hz, amplitude compensated

    scale = model.spatial.bright_model.scale_threshold
    pdur_amps = [BASE_AMP * scale(BASE_PDUR) / scale(pdur) for pdur in PDURS]

    rows = [
        ('Increasing amplitude',
         [f'{a:g}' + r'$\times$Th' for a in AMPS],
         [predict(BASE_FREQ, a, BASE_PDUR) for a in AMPS]),
        ('Increasing frequency',
         [f'{f:g} Hz' for f in FREQS],
         [predict(f, BASE_AMP, BASE_PDUR) for f in FREQS]),
        ('Increasing phase duration',
         [f'{t:g} ms' for t in PDURS],
         [predict(BASE_FREQ, a, t) for a, t in zip(pdur_amps, PDURS)]),
    ]








.. GENERATED FROM PYTHON SOURCE LINES 87-90

All 18 panels share one gray scale, ``[0, vmax]``, with ``vmax`` the
brightest pixel in the figure (the 120 Hz panel, ~9x the 5 Hz reference).
Per-panel autoscaling would make every panel equally bright.

.. GENERATED FROM PYTHON SOURCE LINES 90-103

.. code-block:: Python


    vmax = max(frame.max() for _, _, frames in rows for frame in frames)

    fig, axes = plt.subplots(3, 6, figsize=(11, 6.5), facecolor='k')
    for row_axes, (label, titles, frames) in zip(axes, rows):
        for ax, title, frame in zip(row_axes, titles, frames):
            ax.imshow(frame, cmap='gray', vmin=0, vmax=vmax)
            ax.set_title(title, color='w', fontsize=10, pad=4)
            ax.set_xticks([])
            ax.set_yticks([])
        row_axes[0].set_ylabel(label, color='w', fontsize=11)
    fig.tight_layout()




.. image-sg:: /examples/models/images/sphx_glr_plot_granley2021_biphasic_001.png
   :alt: 1$\times$Th, 2$\times$Th, 3$\times$Th, 4$\times$Th, 5$\times$Th, 6$\times$Th, 5 Hz, 10 Hz, 20 Hz, 40 Hz, 80 Hz, 120 Hz, 0.1 ms, 1 ms, 5 ms, 25 ms, 50 ms, 100 ms
   :srcset: /examples/models/images/sphx_glr_plot_granley2021_biphasic_001.png
   :class: sphx-glr-single-img





.. GENERATED FROM PYTHON SOURCE LINES 104-122

Amplitude (top) increases size and brightness. Frequency (middle) increases
brightness only; the outline is identical across the row. Phase duration
(bottom), with brightness and width held fixed, shortens the streak by about
half between 0.1 and 100 ms.

What this does not establish
----------------------------

* The three factors are phenomenological fits to a few Argus I/II subjects,
  not a biophysical model. They are linear or single power laws and
  extrapolate poorly beyond the ranges swept here.
* v0.11 uses an Argus II refit of the [Horsager2009]_ phase-duration
  threshold relation, so the bottom row does not exactly reproduce the
  published panel. The compensating amplitudes come from the model's own
  ``scale_threshold``.
* Brightness is in arbitrary units; compare only within this figure.
* With several electrodes active, the model sums linearly; real
  multi-electrode percepts do not.


.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (0 minutes 2.343 seconds)


.. _sphx_glr_download_examples_models_plot_granley2021_biphasic.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: plot_granley2021_biphasic.ipynb <plot_granley2021_biphasic.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: plot_granley2021_biphasic.py <plot_granley2021_biphasic.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: plot_granley2021_biphasic.zip <plot_granley2021_biphasic.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_
