Source code for ibllib.tests.integration.test_wheel_extraction

import numpy as np

from scipy.signal import butter, filtfilt
import scipy.interpolate
import matplotlib.pyplot as plt

from one.api import ONE
from one.alf.path import get_session_path
from ibllib.io.extractors import training_wheel
from ibllib.pipes.behavior_tasks import ChoiceWorldTrialsNidq

from ibllib.tests import base

DISPLAY = False


[docs] def compare_wheel_fpga_behaviour(session_path, display=DISPLAY): task = ChoiceWorldTrialsNidq(session_path, one=ONE(mode='local'), collection='raw_behavior_data', sync_collection='raw_ephys_data') fpga_trials, _ = task.extract_behaviour(save=False, tmax=None) bpod_trials = task.extractor.bpod_trials fpga_t, fpga_pos = fpga_trials['wheel_timestamps'], fpga_trials['wheel_position'] bpod_t, bpod_pos = bpod_trials['wheel_timestamps'], bpod_trials['wheel_position'] # resample both traces to the same rate and compute correlation coeff bpod_t = task.extractor.bpod2fpga(bpod_t) tmin = max(np.min(fpga_t), np.min(bpod_t)) tmax = min(np.max(fpga_t), np.max(bpod_t)) wheel = {'tscale': np.arange(tmin, tmax, 0.01)} wheel['fpga'] = scipy.interpolate.interp1d( fpga_t, fpga_pos)(wheel['tscale']) wheel['bpod'] = scipy.interpolate.interp1d( bpod_t, bpod_pos)(wheel['tscale']) if display: plt.figure() plt.plot(fpga_t - task.extractor.bpod2fpga(0), fpga_pos, '*') plt.plot(bpod_t - task.extractor.bpod2fpga(0), bpod_pos, '.') raw_wheel = {'fpga_t': fpga_t, 'fpga_pos': fpga_pos, 'bpod_t': bpod_t, 'bpod_pos': bpod_pos} return raw_wheel, wheel
[docs] class TestWheelExtractionSimpleEphys(base.IntegrationTest): required_files = ['wheel/ephys/three_clockwise_revolutions']
[docs] def setUp(self) -> None: super().setUp() self.session_path = \ self.data_path.joinpath('wheel', 'ephys', 'three_clockwise_revolutions') assert self.session_path.exists()
[docs] def test_three_clockwise_revolutions_fpga(self): raw_wheel, wheel = compare_wheel_fpga_behaviour(self.session_path) self.assertTrue(np.all(np.abs(wheel['fpga'] - wheel['bpod']) < 0.1)) # test that the units are in radians: we expect around 9 revolutions clockwise self.assertTrue(0.95 < raw_wheel['fpga_pos'][-1] / -(2 * 3.14 * 9) < 1.05)
[docs] class TestWheelExtractionSessionEphys(base.IntegrationTest): required_files = ['wheel/ephys/sessions']
[docs] def setUp(self) -> None: super().setUp() self.root_path = self.data_path.joinpath('wheel', 'ephys', 'sessions') if not self.root_path.exists(): return self.sessions = [f.parent for f in self.root_path.rglob('raw_behavior_data')]
[docs] def test_wheel_extraction_session(self): for session_path in self.sessions: with self.subTest(msg=session_path): _, wheel = compare_wheel_fpga_behaviour(session_path) # makes sure that the HF component matches b, a = butter(3, 0.0001, btype='high', analog=False) fpga = filtfilt(b, a, wheel['fpga']) bpod = filtfilt(b, a, wheel['bpod']) # plt.figure() # plt.plot(wheel['tscale'], fpga) # plt.plot(wheel['tscale'], bpod) self.assertTrue(np.all(np.abs(fpga - bpod < 0.1)))
[docs] class TestWheelExtractionTraining(base.IntegrationTest): required_files = ['wheel/training']
[docs] def setUp(self) -> None: super().setUp() self.root_path = self.data_path.joinpath('wheel', 'training') assert self.root_path.exists()
[docs] def test_wheel_extraction_training(self): for rbf in self.root_path.rglob('raw_behavior_data'): session_path = get_session_path(rbf) with self.subTest(msg=session_path): bpod_t, _ = training_wheel.get_wheel_position(session_path) self.assertTrue(bpod_t.size)