Skip to content

Commit 8f833b5

Browse files
committed
shuffle
1 parent 2c1361e commit 8f833b5

File tree

1 file changed

+44
-25
lines changed
  • iblrig_custom_tasks/samuel_tonotopicMapping

1 file changed

+44
-25
lines changed

iblrig_custom_tasks/samuel_tonotopicMapping/task.py

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,38 @@
1-
import json
21

3-
import pandas as pd
4-
import numpy as np
52
import logging
63

7-
from pybpodapi.state_machine import StateMachine
4+
import numpy as np
85

96
from iblrig import sound
107
from iblrig.base_tasks import BaseSession, BpodMixin
118
from iblrig.misc import get_task_arguments
9+
from pybpodapi.state_machine import StateMachine
1210

1311
logger = logging.getLogger('iblrig')
1412

1513

1614
class Session(BpodMixin, BaseSession):
1715
protocol_name = 'samuel_tonotopicMapping'
1816

17+
frequencies: list[int] = []
18+
sequence: list[int] = []
19+
1920
def __init__(self, *args, **kwargs):
2021
super().__init__(*args, **kwargs)
2122

2223
assert self.hardware_settings.device_sound.OUTPUT == 'harp', 'This task requires a Harp sound-card'
2324
assert self.task_params['n_freqs'] <= 31, 'Harp only supports up to 31 individual sounds'
2425

2526
# define frequencies (log spaced from freq_0 to freq_1, rounded to nearest integer)
26-
self.frequencies = np.logspace(
27+
Session.frequencies = np.logspace(
2728
np.log10(self.task_params['freq_0']),
2829
np.log10(self.task_params['freq_1']),
2930
num=self.task_params['n_freqs'],
3031
)
31-
self.frequencies = np.round(self.frequencies).astype(int)
32+
Session.frequencies = np.round(self.frequencies).astype(int)
33+
34+
# repetitions per state machine run (253 states max)
35+
self.repetitions = 253 // len(self.frequencies)
3236

3337
# generate stimuli
3438
self.stimuli = []
@@ -53,43 +57,58 @@ def start_mixin_sound(self):
5357

5458
module = self.bpod.sound_card
5559
module_port = f'Serial{module.serial_port if module is not None else "3"}'
56-
for idx, harp_index in enumerate(self.indices):
57-
bpod_message = [ord("P"), harp_index]
60+
for frequency_idx, harp_idx in enumerate(self.indices):
61+
bpod_message = [ord('P'), harp_idx]
5862
bpod_action = (module_port, self.bpod._define_message(self.bpod.sound_card, bpod_message))
59-
self.bpod.actions.update({f'play_{idx}': bpod_action})
63+
self.bpod.actions.update({f'freq_{frequency_idx}': bpod_action})
64+
65+
self.bpod.softcode_handler_function = Session.softcode_handler
6066

6167
def start_hardware(self):
6268
self.start_mixin_bpod()
6369
self.start_mixin_sound()
6470

65-
def get_state_machine(self, sequence):
71+
@staticmethod
72+
def get_state_name(state_idx: int):
73+
if state_idx < len(Session.sequence):
74+
return f'{state_idx + 1:03d}_{Session.frequencies[Session.sequence[state_idx]]}'
75+
else:
76+
return 'exit'
77+
78+
@staticmethod
79+
def softcode_handler(softcode: int) -> None:
80+
"""log some information about the current state"""
81+
state_index = softcode - 1
82+
frequency_index = Session.sequence[state_index]
83+
frequency = Session.frequencies[frequency_index]
84+
n_states = len(Session.sequence)
85+
logger.info(f'{state_index + 1:03d}/{n_states}: {frequency:5d} Hz')
86+
87+
def get_state_machine(self, seed: int) -> StateMachine:
88+
# generate shuffled sequence, seeded with state machine number
89+
Session.sequence = np.repeat(np.arange(len(self.frequencies)), self.repetitions)
90+
np.random.seed(seed)
91+
np.random.shuffle(Session.sequence)
92+
93+
# build state machine
6694
sma = StateMachine(self.bpod)
67-
# table = self.sequence_table[self.sequence_table['sequence'] == sequence].reindex()
68-
69-
for i, frequency in enumerate(self.frequencies):
95+
for state_idx, frequency_idx in enumerate(Session.sequence):
7096
sma.add_state(
71-
state_name=f"trigger_sound_{i}",
97+
state_name=self.get_state_name(state_idx),
7298
state_timer=self.task_params['d_sound'] + self.task_params['d_pause'],
73-
output_actions=[self.bpod.actions[f'play_{i}']],
74-
state_change_conditions={
75-
"Tup": f"trigger_sound_{i + 1}",
76-
},
99+
output_actions=[self.bpod.actions[f'freq_{frequency_idx}'], ('SoftCode', state_idx + 1)],
100+
state_change_conditions={'Tup': self.get_state_name(state_idx + 1)},
77101
)
78-
sma.add_state(
79-
state_name=f"trigger_sound_{i + 1}",
80-
state_timer=0.0,
81-
state_change_conditions={"Tup": "exit"},
82-
)
83102
return sma
84103

85104
def _run(self):
86-
logger.info("Sending spacers to BNC ports")
105+
logger.info('Sending spacers to BNC ports')
87106
self.send_spacers()
88107

89108
sma = self.get_state_machine(1)
90109
self.bpod.send_state_machine(sma)
91110
self.bpod.run_state_machine(sma)
92-
111+
self.bpod.session.current_trial.export()
93112

94113

95114
if __name__ == '__main__': # pragma: no cover

0 commit comments

Comments
 (0)