Automated pupillometer with STLAB¶
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 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.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os.path as op
from time import sleep
import numpy as np
from pyplr.stlab import SpectraTuneLab
from pyplr.pupil import PupilCore
from pyplr.utils import unpack_data_pandas
from pyplr.preproc import butterworth_series
from pyplr.plr import PLR
from pyplr.protocol import (input_subject_id_gui,
subject_dir,
record_dir)
def main(subject_id=None,
baseline=2.,
duration=8.,
sample_rate=120,
stimulus='./stimuli/PLR-3000-180-mw.dsf',
record=True,
control=False,
config=None):
# Set up subject and recording
if subject_id is None:
subject_id = input_subject_id_gui()
subj_dir = subject_dir(subject_id)
rec_dir = record_dir(subj_dir)
# Set up Pupil Core
p = PupilCore()
# Setup STLAB
d = SpectraTuneLab(password='****************')
d.load_video_file(stimulus)
# Prepare annotation
annotation = p.new_annotation('LIGHT_ON')
if control:
input("Press Enter to administer stimulus...")
if record:
p.command('R {}'.format(rec_dir))
sleep(1.)
# Start light_stamper and pupil_grabber
lst_future = p.light_stamper(
annotation, threshold=15, timeout=6.)
pgr_future = p.pupil_grabber(
topic='pupil.1.3d', seconds=duration+baseline+2)
# Baseline period
sleep(baseline)
# Present Stimulus
d.play_video_file()
# Wait for futures
while lst_future.running() or pgr_future.running():
print('Waiting for futures...')
sleep(1)
if record:
p.command('r')
if not lst_future.result()[0]:
print('light was not detected. Ending program.')
sys.exit(0)
# Retrieve and process pupil data
data = unpack_data_pandas(
pgr_future.result(), cols=['timestamp','diameter_3d'])
data = butterworth_series(
data,
filt_order=3,
cutoff_freq=4/(sample_rate/2),
fields=['diameter_3d'])
# Get light_stamper timestamp
ts = lst_future.result()[1]
# Find the closest timestamp in the pupil data
idx = (np.abs(ts - data.index)).argmin()
# Trim
start = int(idx-(baseline*sample_rate))
end = int(idx+(duration*sample_rate))
data = data.iloc[start:end]
data.reset_index(inplace=True)
# Analyse PLR
plr = PLR(plr=data.diameter_3d.to_numpy(),
sample_rate=sample_rate,
onset_idx=idx,
stim_duration=1)
plr.parameters().to_csv(op.join(rec_dir, 'plr_parameters.csv'))
plr.plot().savefig(op.join(rec_dir, 'plr_plot.png'), bbox_inches='tight')
data.to_csv(op.join(rec_dir, 'raw_data.csv'))
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print('Killed by user')
sys.exit(0)