{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Automated pupillometer with STLAB\n", "=================================\n", "\n", "Automated pupillometers are the standard instruments for measuring the PLR. These handheld devices are aimed at a person's eye to deliver a light stimulus and use infrared video recording and internal algorithms to provide an instant readout of the PLR and its associated parameters. Our own [NeurOptics PLR-3000](https://neuroptics.com/plr-3000-hand-held/) is one such device, and it does an absolutely fantastic job. The STLAB-integrating sphere rig is no match for its compactness, portability and ease of use, but we figured at least that we could make it function in a similar way.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```Python\n", "#!/usr/bin/env python\n", "# -*- coding: utf-8 -*-\n", "\n", "import sys\n", "import os.path as op\n", "from time import sleep\n", "\n", "import numpy as np\n", " \n", "from pyplr.stlab import SpectraTuneLab\n", "from pyplr.pupil import PupilCore\n", "from pyplr.utils import unpack_data_pandas\n", "from pyplr.preproc import butterworth_series\n", "from pyplr.plr import PLR\n", "from pyplr.protocol import (input_subject_id_gui, \n", " subject_dir, \n", " record_dir) \n", "def main(subject_id=None, \n", " baseline=2., \n", " duration=8.,\n", " sample_rate=120,\n", " stimulus='./stimuli/PLR-3000-180-mw.dsf',\n", " record=True, \n", " control=False,\n", " config=None):\n", " \n", " # Set up subject and recording\n", " if subject_id is None:\n", " subject_id = input_subject_id_gui()\n", " subj_dir = subject_dir(subject_id)\n", " rec_dir = record_dir(subj_dir)\n", " \n", " # Set up Pupil Core\n", " p = PupilCore()\n", " \n", " # Setup STLAB\n", " d = SpectraTuneLab(password='****************')\n", " d.load_video_file(stimulus)\n", "\n", " # Prepare annotation\n", " annotation = p.new_annotation('LIGHT_ON')\n", " \n", " if control:\n", " input(\"Press Enter to administer stimulus...\")\n", " \n", " if record:\n", " p.command('R {}'.format(rec_dir))\n", " sleep(1.)\n", " \n", " # Start light_stamper and pupil_grabber\n", " lst_future = p.light_stamper(\n", " annotation, threshold=15, timeout=6.)\n", " pgr_future = p.pupil_grabber(\n", " topic='pupil.1.3d', seconds=duration+baseline+2)\n", " \n", " # Baseline period\n", " sleep(baseline)\n", " \n", " # Present Stimulus\n", " d.play_video_file()\n", " \n", " # Wait for futures\n", " while lst_future.running() or pgr_future.running():\n", " print('Waiting for futures...')\n", " sleep(1)\n", " \n", " if record:\n", " p.command('r')\n", " \n", " if not lst_future.result()[0]:\n", " print('light was not detected. Ending program.')\n", " sys.exit(0)\n", " \n", " # Retrieve and process pupil data\n", " data = unpack_data_pandas(\n", " pgr_future.result(), cols=['timestamp','diameter_3d'])\n", " data = butterworth_series(\n", " data, \n", " filt_order=3, \n", " cutoff_freq=4/(sample_rate/2), \n", " fields=['diameter_3d'])\n", " \n", " # Get light_stamper timestamp\n", " ts = lst_future.result()[1]\n", " \n", " # Find the closest timestamp in the pupil data\n", " idx = (np.abs(ts - data.index)).argmin()\n", " \n", " # Trim\n", " start = int(idx-(baseline*sample_rate))\n", " end = int(idx+(duration*sample_rate))\n", " data = data.iloc[start:end]\n", " data.reset_index(inplace=True)\n", " \n", " # Analyse PLR\n", " plr = PLR(plr=data.diameter_3d.to_numpy(),\n", " sample_rate=sample_rate, \n", " onset_idx=idx,\n", " stim_duration=1)\n", " plr.parameters().to_csv(op.join(rec_dir, 'plr_parameters.csv'))\n", " plr.plot().savefig(op.join(rec_dir, 'plr_plot.png'), bbox_inches='tight')\n", " data.to_csv(op.join(rec_dir, 'raw_data.csv'))\n", " \n", "if __name__ == '__main__': \n", " try:\n", " main()\n", " except KeyboardInterrupt:\n", " print('Killed by user')\n", " sys.exit(0)\n", "``` " ] } ], "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.7" } }, "nbformat": 4, "nbformat_minor": 4 }