.. _topics-implants: ================= Visual Prostheses ================= Objects in the :py:mod:`~pulse2percept.implants` module are organized into the following categories: * :ref:`Electrodes ` are objects whose behavior is dictated by the :py:class:`~pulse2percept.implants.Electrode` base class. * :ref:`Electrode arrays ` are collections of :py:class:`~pulse2percept.implants.Electrode` objects whose behavior is dictated by the :py:class:`~pulse2percept.implants.ElectrodeArray` class. * :ref:`Prosthesis systems ` (aka 'implants', aka 'bionic eye') are comprised of an :py:class:`~pulse2percept.implants.ElectrodeArray` object and (optionally) a :py:class:`~pulse2percept.stimuli.Stimulus` object. Their behavior is dictated by the :py:class:`~pulse2percept.implants.ProsthesisSystem` base class. .. _topics-implants-prosthesis-system: Prosthesis systems ------------------ pulse2percept provides the following prosthesis systems (aka *'implants', 'bionic eyes', 'neuroprostheses'*): =========== ============== ================== ================================= **Implant** **Location** **Num Electrodes** **Manufacturer** ----------- -------------- ------------------ --------------------------------- `ArgusI` epiretinal 16 Second Sight Medical Products Inc `ArgusII` epiretinal 60 Second Sight Medical Products Inc `IMIE` epiretinal 256 IntelliMicro Medical Co., Ltd `AlphaIMS` subretinal 1500 Retina Implant AG `AlphaAMS` subretinal 1600 Retina Implant AG `PRIMA` subretinal 378 Pixium Vision SA `PRIMA75` subretinal 142 Pixium Vision SA `PRIMA55` subretinal 273(?) Pixium Vision SA `PRIMA40` subretinal 532(?) Pixium Vision SA `BVT24` suprachoroidal 24 Bionic Vision Technologies `BVT44` suprachoroidal 44 Bionic Vision Technologies `Orion` cortical 60 Cortigent Inc `Cortivis` cortical 96 Biomedical Technologies `ICVP` cortical 16 Sigenics Inc `Neuralink` cortical 32 / thread Neuralink Corp =========== ============== ================== ================================= Stimuli can be assigned to the various electrodes in the electrode array, who will deliver them to the retina (see :ref:`Electrical Stimuli `). A mathematical model is then used to compute the neural stimulus response and predict the resulting visual percept (see :ref:`Computational Models `). Understanding the coordinate system (Retina) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The easiest way to understand the coordinate system is to look at the organization of the optic fiber layer: .. ipython:: python from pulse2percept.models import AxonMapModel @savefig axonmap.png align=center AxonMapModel(eye='RE').plot() Here you can see that: * the coordinate system is centered on the fovea * in a right eye, positive :math:`x` values correspond to the nasal retina * in a right eye, positive :math:`y` values correspond to the superior retina Positive :math:`z` values move an electrode away from the retina into the vitreous humor (:math:`z` is sometimes called electrode-retina distance). Analogously, negative :math:`z` values move an electrode through the different retinal layers towards the outer retina. Understanding the ProsthesisSystem class ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The :py:class:`~pulse2percept.implants.ProsthesisSystem` base class provides a template for all prosthesis systems. It is comprised of: * :py:class:`~pulse2percept.implants.ElectrodeArray`: as mentioned above, * :py:class:`~pulse2percept.stimuli.Stimulus`: as mentioned above, * :py:class:`~pulse2percept.implants.ProsthesisSystem.check_stim`: a method that quality-checks the stimulus. By default this method does nothing, but its behavior might depend on the actual system, such as :py:class:`~pulse2percept.implants.ArgusII` or :py:class:`~pulse2percept.implants.AlphaIMS`, * :py:attr:`~pulse2percept.implants.ProsthesisSystem.eye`: a string indicating whether the system is implanted in the left or right eye, * a means to access and iterate over electrodes in the array. Accessing electrodes ^^^^^^^^^^^^^^^^^^^^ You can access individual electrodes in a prosthesis system either by integer index or by electrode name. For example, the first electrode in :py:class:`~pulse2percept.implants.AlphaAMS` can be accessed as follows: .. ipython:: python from pulse2percept.implants import AlphaAMS implant = AlphaAMS() # Access by index: implant[0] # Access by name: implant['A1'] The simplest way to iterate over all electrodes is to pretend that the prosthesis system is a Python dictionary: .. ipython:: python from pulse2percept.implants import ArgusI for name, electrode in ArgusI().electrodes.items(): print(name, electrode) Creating your own prosthesis system ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ You can quickly create a prosthesis system from an :py:class:`~pulse2percept.implants.ElectrodeArray` (or even a single :py:class:`~pulse2percept.implants.Electrode`) by wrapping it in a :py:class:`~pulse2percept.implants.ProsthesisSystem` container: .. ipython:: python from pulse2percept.implants import ElectrodeGrid, ProsthesisSystem ProsthesisSystem(earray=ElectrodeGrid((10, 10), 200)) To create a more advanced prosthesis system, you will need to subclass the base class: .. code-block:: python import numpy as np from pulse2percept.implants import ElectrodeGrid, ProsthesisSystem class MyFovealElectrodeGrid(ProsthesisSystem): """An ElectrodeGrid implant centered over the fovea""" def __init__(self, stim=None, eye='RE'): self.earray = ElectrodeGrid((3, 3), x=0, y=0, z=0, rot=0, r=100, spacing=500, names=('A', '1')) self.stim = stim self.eye = eye def check_stim(self, stim): """Make sure the stimulus is charge-balanced""" if stim.time is not None: for s in stim: assert np.isclose(np.sum(s), 0) .. .. minigallery:: pulse2percept.implants.ProsthesisSystem .. :add-heading: Examples using ``ProsthesisSystem`` .. :heading-level: ~ .. _topics-implants-electrode-array: Electrode arrays ---------------- **Electrode arrays** are collections of :py:class:`~pulse2percept.implants.Electrode` objects whose behavior is dictated by the :py:class:`~pulse2percept.implants.ElectrodeArray` base class. .. seealso:: * :py:class:`~pulse2percept.implants.ElectrodeGrid` Understanding the ElectrodeArray class ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The :py:class:`~pulse2percept.implants.ElectrodeArray` base provides: * :py:attr:`~pulse2percept.implants.ElectrodeArray.electrodes`: an ordered dictionary of electrode objects (meaning it will remember the order in which electrodes were added), * :py:attr:`~pulse2percept.implants.ElectrodeArray.n_electrodes`: a property returning the number of electrodes in the array. * :py:meth:`~pulse2percept.implants.ElectrodeArray.add_electrode`: a method to add a single electrode to the collection, * :py:meth:`~pulse2percept.implants.ElectrodeArray.add_electrodes`: a method to add a multiple electrodes to the collection at once, * a way to access a single electrode either by index or by name, * a way to iterate over all electrodes in the array. Accessing electrodes ^^^^^^^^^^^^^^^^^^^^ You can access individual electrodes in an electrode array either by integer index or by electrode name. The syntax is exactly the same as for the prosthesis system. Creating your own electrode array ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ You can create your own electrode array by starting with an empty :py:class:`~pulse2percept.implants.ElectrodeArray`, and adding the desired electrodes one by one: .. ipython:: python from pulse2percept.implants import DiskElectrode, ElectrodeArray earray = ElectrodeArray([]) earray.add_electrode(0, DiskElectrode(0, 0, 0, 50)) earray.add_electrode(1, DiskElectrode(100, 100, 0, 150)) earray To create a more advanced electrode array, you will need to subclass the base class. In the constructor, make sure to initialize ``self.electrodes`` with an ordered dictionary (``OrderedDict``): .. code-block:: python from collections import OrderedDict from pulse2percept.implants import ElectrodeArray class MyElectrodeArray(ElectrodeArray): """Array with a single disk electrode""" def __init__(self, name): self.electrodes = OrderedDict() self.add_electrode(name, DiskElectrode(0, 0, 0, 100)) .. .. minigallery:: pulse2percept.implants.ElectrodeArray .. :add-heading: Examples using ``ElectrodeArray`` .. :heading-level: ~ .. _topics-implants-electrode: Electrodes ---------- **Electrodes** are objects whose behavior is dictated by the :py:class:`~pulse2percept.implants.Electrode` base class. They are located at a particular 3D location and provide a method to calculate the electric potential at arbitrary 3D locations. .. seealso:: * :py:class:`~pulse2percept.implants.PointSource` * :py:class:`~pulse2percept.implants.DiskElectrode` * :py:class:`~pulse2percept.implants.SquareElectrode` * :py:class:`~pulse2percept.implants.HexElectrode` Understanding the Electrode class ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The base class provides: * the 3D coordinates of the center of the electrode. In addition, a custom electrode object must implement: * a method called :py:meth:`~pulse2percept.implants.Electrode.electric_potential` that returns the electric potential at a point (x, y, z). Creating your own electrode ^^^^^^^^^^^^^^^^^^^^^^^^^^^ To create a new electrode type, you will need to subclass the base class. Make sure to specify an ``electric_potential`` method for your class: .. code-block:: python from pulse2percept.implants import Electrode class MyElectrode(Electrode): """Named electrode with electric potential 0 everywhere""" def __init__(self, x, y, z, name): # Note: If you don't plan on adding any new variables, you can # omit the constructor entirely. In that case, your object will # inherit the constructor of the base class. self.x = x self.y = y self.z = z self.name = name def electric_potential(self, x, y, z): return 0.0 .. .. minigallery:: pulse2percept.implants.Electrode .. :add-heading: Examples using ``Electrode`` .. :heading-level: ~