{ "cells": [ { "cell_type": "markdown", "id": "7f339a75-6ee9-4230-91d6-54d89841a051", "metadata": {}, "source": [ "Stimulation devices\n", "===================\n", "\n", "Silent substitution requires a stimulation device with at least as many primaries as there are photoreceptors under consideration. This generally means that [5 primaries are needed](./01_background.rst), although 4 primaries may suffice when working in the photopic range as rod photoreceptors are thought to become saturated and incapable of signalling above 300 cd/m$^2$ ([Aguiller and Stiles, 1954](https://doi.org/10.1080/713818657); [Adelson, 1982](https://doi.org/10.1016/0042-6989(82)90143-2); but see [Shapiro, 2002](https://iovs.arvojournals.org/article.aspx?articleid=2200107); [Kremers et al., 2009](https://doi.org/10.1007/s10633-008-9159-0)). \n", "\n", "The primaries should be independantly addressable, additive, and ideally stable over time with a linear gamma function. Peak wavelength and bandwidth are key considerations that will ultimately define the gamut and available contrast ([Evéquoz et al., 2021](https://doi.org/10.1364/josaa.420373)), and the light source will also need to be integrated into an optical setup for stimulus delivery—usually either a Ganzfeld (e.g., [Martin et al., 2021](https://doi.org/10.3758/s13428-021-01759-3)) or Maxwellian (e.g., [Cao et al., 2015](https://doi.org/10.1167/15.1.27)).\n", "\n", "[Conus and Geiser (2020)](https://doi.org/10.3390/photonics7040121) reviewed stimulation devices from a range of silent substitution studies and found that, in most cases, the device had 4 or 5 primaries and was built from scratch using LEDs, optical bench components, and microprocessors, such as Arduino, for pulse width modulation control of intensity. Only a few devices were commercially bought. \n", "\n", "Whatever the device and setup, one must obtain accurate calibration measurements with a spectrometer to characterise the output. If you have a [JETI](https://www.jeti.com/) or [OceanOptics](https://www.oceaninsight.com/) spectrometer, *[PyPlr](https://github.com/PyPlr/cvd_pupillometry)* has some Python interfaces that may help you obtain the spectral measurements.\n", "\n", "Once you have these measurements, you are ready to use *PySilSub*.\n" ] }, { "cell_type": "markdown", "id": "d00b8dfa-4580-4a79-9eaa-b599caf04b34", "metadata": {}, "source": [ "`pysilsub.devices.StimulationDevice`\n", "-----------------------------------\n", "\n", "This class aims to serve as a software model for any multiprimary stimulation device. It can be instantiated as follows:" ] }, { "cell_type": "code", "execution_count": 1, "id": "4849363b-f5fa-412e-a58f-0823327aae3a", "metadata": {}, "outputs": [], "source": [ "from pysilsub.devices import StimulationDevice\n", "\n", "device = StimulationDevice(\n", " calibration='../../pysilsub/data/STLAB_1_York.csv',\n", " calibration_wavelengths=[380, 781, 1],\n", " primary_resolutions=[4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095],\n", " primary_colors=['blueviolet', 'royalblue', 'darkblue', 'blue', 'cyan', 'green', 'lime', 'orange', 'red', 'darkred'],\n", " name='SpectraTuneLab',\n", " config=dict(calibration_units='$\\mu$W/m$^2$/nm')\n", ")\n" ] }, { "cell_type": "markdown", "id": "6a750385-0b97-49b2-b50b-e2cdb3fc4a7d", "metadata": {}, "source": [ "The above example is for a commercial 10-primary device with 12-bit resolution ([STLAB: Ledmotive Technologies LLC](https://ledmotive.com/store/spectratune-lab/)), which means the input is specified with values between 0 and 4095.\n", "\n", "The calibration file is a CSV with accurate spectral measurements of the individual primaries. The first row contains column headers *Primary* and *Setting*, and numbers to describe the wavelength sampling of the measurements. The remaining rows each contain a spectral measurement and corresponding values for *Primary* and *Setting* for identification. \n", "\n", "Note that one must also include a dark measurement where LEDs are turned off (i.e., Setting = 0) to account for ambient light in an experimental setup. \n", "\n", "The calibration data look like this:\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "b784779b-0e7e-4fd6-a33e-49ad57672b19", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | Wavelength | \n", "380 | \n", "381 | \n", "382 | \n", "383 | \n", "384 | \n", "385 | \n", "386 | \n", "387 | \n", "388 | \n", "389 | \n", "... | \n", "771 | \n", "772 | \n", "773 | \n", "774 | \n", "775 | \n", "776 | \n", "777 | \n", "778 | \n", "779 | \n", "780 | \n", "
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Primary | \n", "Setting | \n", "\n", " | \n", " | \n", " | \n", " | \n", " | \n", " | \n", " | \n", " | \n", " | \n", " | \n", " | \n", " | \n", " | \n", " | \n", " | \n", " | \n", " | \n", " | \n", " | \n", " | \n", " |
0 | \n", "0 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000e+00 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "... | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000e+00 | \n", "0.000000e+00 | \n", "0.000000e+00 | \n", "0.000000e+00 | \n", "0.000000e+00 | \n", "
65 | \n", "0.000008 | \n", "0.000009 | \n", "9.745215e-06 | \n", "0.000009 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "0.000005 | \n", "... | \n", "0.000009 | \n", "0.000008 | \n", "0.000011 | \n", "0.000011 | \n", "0.000011 | \n", "4.776394e-06 | \n", "3.671169e-06 | \n", "8.690441e-07 | \n", "2.504634e-07 | \n", "2.539856e-07 | \n", "|
130 | \n", "0.000010 | \n", "0.000011 | \n", "1.202408e-05 | \n", "0.000014 | \n", "0.000022 | \n", "0.000016 | \n", "0.000013 | \n", "0.000012 | \n", "0.000014 | \n", "0.000013 | \n", "... | \n", "0.000003 | \n", "0.000003 | \n", "0.000003 | \n", "0.000002 | \n", "0.000000 | \n", "0.000000e+00 | \n", "0.000000e+00 | \n", "4.140402e-06 | \n", "4.181861e-06 | \n", "4.240670e-06 | \n", "|
195 | \n", "0.000004 | \n", "0.000004 | \n", "6.014049e-07 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "0.000000 | \n", "... | \n", "0.000012 | \n", "0.000013 | \n", "0.000013 | \n", "0.000014 | \n", "0.000014 | \n", "7.684585e-07 | \n", "7.781628e-07 | \n", "1.842077e-07 | \n", "0.000000e+00 | \n", "0.000000e+00 | \n", "|
260 | \n", "0.000023 | \n", "0.000012 | \n", "0.000000e+00 | \n", "0.000004 | \n", "0.000007 | \n", "0.000012 | \n", "0.000011 | \n", "0.000016 | \n", "0.000040 | \n", "0.000049 | \n", "... | \n", "0.000007 | \n", "0.000006 | \n", "0.000006 | \n", "0.000006 | \n", "0.000012 | \n", "1.513954e-05 | \n", "1.252247e-05 | \n", "1.269276e-05 | \n", "1.281985e-05 | \n", "7.991981e-06 | \n", "|
... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
9 | \n", "3835 | \n", "0.001902 | \n", "0.001782 | \n", "1.386320e-03 | \n", "0.001362 | \n", "0.001630 | \n", "0.001647 | \n", "0.001160 | \n", "0.001866 | \n", "0.002541 | \n", "0.002595 | \n", "... | \n", "0.000592 | \n", "0.000573 | \n", "0.000521 | \n", "0.000807 | \n", "0.000618 | \n", "6.720443e-04 | \n", "7.648245e-04 | \n", "7.677751e-04 | \n", "9.100419e-04 | \n", "8.549128e-04 | \n", "
3900 | \n", "0.001471 | \n", "0.001634 | \n", "2.300030e-03 | \n", "0.002383 | \n", "0.002145 | \n", "0.001927 | \n", "0.001556 | \n", "0.001704 | \n", "0.001555 | \n", "0.001717 | \n", "... | \n", "0.000697 | \n", "0.000772 | \n", "0.000568 | \n", "0.000602 | \n", "0.000595 | \n", "5.869208e-04 | \n", "6.342476e-04 | \n", "6.455188e-04 | \n", "6.345751e-04 | \n", "7.664858e-04 | \n", "|
3965 | \n", "0.002061 | \n", "0.002297 | \n", "2.212991e-03 | \n", "0.002499 | \n", "0.002516 | \n", "0.002555 | \n", "0.001571 | \n", "0.001244 | \n", "0.001204 | \n", "0.001470 | \n", "... | \n", "0.001060 | \n", "0.000784 | \n", "0.000770 | \n", "0.000743 | \n", "0.000430 | \n", "4.897906e-04 | \n", "5.161750e-04 | \n", "7.753686e-04 | \n", "8.782367e-04 | \n", "1.083818e-03 | \n", "|
4030 | \n", "0.001751 | \n", "0.001866 | \n", "1.807109e-03 | \n", "0.001662 | \n", "0.001164 | \n", "0.001096 | \n", "0.000952 | \n", "0.001110 | \n", "0.001482 | \n", "0.000940 | \n", "... | \n", "0.000766 | \n", "0.000729 | \n", "0.000841 | \n", "0.000865 | \n", "0.000874 | \n", "6.683831e-04 | \n", "6.569512e-04 | \n", "5.133820e-04 | \n", "6.889034e-04 | \n", "7.533813e-04 | \n", "|
4095 | \n", "0.000900 | \n", "0.001126 | \n", "1.366911e-03 | \n", "0.001139 | \n", "0.001264 | \n", "0.001266 | \n", "0.001387 | \n", "0.001376 | \n", "0.001575 | \n", "0.001608 | \n", "... | \n", "0.000870 | \n", "0.000711 | \n", "0.000722 | \n", "0.000771 | \n", "0.000855 | \n", "9.470399e-04 | \n", "9.109968e-04 | \n", "1.216197e-03 | \n", "1.373307e-03 | \n", "1.450729e-03 | \n", "
640 rows × 401 columns
\n", "\n", " | 0 | \n", "1 | \n", "2 | \n", "3 | \n", "4 | \n", "5 | \n", "6 | \n", "7 | \n", "8 | \n", "9 | \n", "... | \n", "4086 | \n", "4087 | \n", "4088 | \n", "4089 | \n", "4090 | \n", "4091 | \n", "4092 | \n", "4093 | \n", "4094 | \n", "4095 | \n", "
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | \n", "0 | \n", "0 | \n", "1 | \n", "2 | \n", "3 | \n", "4 | \n", "4 | \n", "5 | \n", "6 | \n", "7 | \n", "... | \n", "4084 | \n", "4085 | \n", "4087 | \n", "4089 | \n", "4090 | \n", "4092 | \n", "4094 | \n", "4095 | \n", "4095 | \n", "4095 | \n", "
1 | \n", "0 | \n", "0 | \n", "1 | \n", "2 | \n", "3 | \n", "4 | \n", "5 | \n", "6 | \n", "7 | \n", "8 | \n", "... | \n", "4031 | \n", "4033 | \n", "4035 | \n", "4037 | \n", "4039 | \n", "4041 | \n", "4043 | \n", "4045 | \n", "4047 | \n", "4049 | \n", "
2 | \n", "0 | \n", "0 | \n", "1 | \n", "2 | \n", "3 | \n", "4 | \n", "5 | \n", "6 | \n", "7 | \n", "7 | \n", "... | \n", "4084 | \n", "4085 | \n", "4085 | \n", "4086 | \n", "4086 | \n", "4087 | \n", "4087 | \n", "4088 | \n", "4088 | \n", "4089 | \n", "
3 | \n", "0 | \n", "0 | \n", "1 | \n", "2 | \n", "3 | \n", "4 | \n", "5 | \n", "6 | \n", "7 | \n", "7 | \n", "... | \n", "4008 | \n", "4009 | \n", "4010 | \n", "4012 | \n", "4013 | \n", "4015 | \n", "4016 | \n", "4018 | \n", "4019 | \n", "4021 | \n", "
4 | \n", "0 | \n", "1 | \n", "3 | \n", "4 | \n", "6 | \n", "8 | \n", "9 | \n", "11 | \n", "13 | \n", "14 | \n", "... | \n", "4063 | \n", "4063 | \n", "4064 | \n", "4065 | \n", "4066 | \n", "4066 | \n", "4067 | \n", "4068 | \n", "4069 | \n", "4070 | \n", "
5 | \n", "0 | \n", "1 | \n", "3 | \n", "5 | \n", "6 | \n", "8 | \n", "10 | \n", "11 | \n", "13 | \n", "15 | \n", "... | \n", "4077 | \n", "4078 | \n", "4079 | \n", "4079 | \n", "4080 | \n", "4081 | \n", "4081 | \n", "4082 | \n", "4083 | \n", "4084 | \n", "
6 | \n", "0 | \n", "1 | \n", "3 | \n", "5 | \n", "6 | \n", "8 | \n", "10 | \n", "11 | \n", "13 | \n", "15 | \n", "... | \n", "4053 | \n", "4054 | \n", "4055 | \n", "4056 | \n", "4057 | \n", "4057 | \n", "4058 | \n", "4059 | \n", "4060 | \n", "4061 | \n", "
7 | \n", "0 | \n", "2 | \n", "4 | \n", "7 | \n", "9 | \n", "12 | \n", "14 | \n", "17 | \n", "19 | \n", "22 | \n", "... | \n", "4068 | \n", "4068 | \n", "4069 | \n", "4070 | \n", "4070 | \n", "4071 | \n", "4072 | \n", "4072 | \n", "4073 | \n", "4074 | \n", "
8 | \n", "0 | \n", "0 | \n", "1 | \n", "2 | \n", "3 | \n", "3 | \n", "4 | \n", "5 | \n", "6 | \n", "6 | \n", "... | \n", "4006 | \n", "4008 | \n", "4011 | \n", "4013 | \n", "4016 | \n", "4018 | \n", "4021 | \n", "4023 | \n", "4026 | \n", "4029 | \n", "
9 | \n", "0 | \n", "0 | \n", "1 | \n", "2 | \n", "3 | \n", "4 | \n", "5 | \n", "6 | \n", "7 | \n", "8 | \n", "... | \n", "4018 | \n", "4019 | \n", "4021 | \n", "4022 | \n", "4023 | \n", "4024 | \n", "4026 | \n", "4027 | \n", "4028 | \n", "4030 | \n", "
10 rows × 4096 columns
\n", "