-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathPulsePal_post_timing.m
236 lines (181 loc) · 13.2 KB
/
PulsePal_post_timing.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
%% PulsePal stimulus control script
%% Program details: adjust these to generate desired trial characteristics
% The following five properties allow for entering multiple values,
% generating more unique trials:
whisk_delays = [1]; % Whisk stimulus delays in s
whisk_wave_freq = [50]; % Whisker stimulus velocity (frequency of WAVEFORM in Hz)
%% IMPORTANT CHANGES 2018_01_31:
multiple_whisks = false; % if 'true' then it will trigger the whisker multiple times according to the frequency and duration specified
whisk_trig_freq = [10]; % !!! Values must be LOWER THAN every 'whisk_wave_freq' value !!! Whisker stimulus triggering frequency (frequency of successive stimuli in HZ)
total_whisk_duration = [2]; % whisker stimulation duration in seconds
%% END IMPORTANT CHANGES
led_delays = [1.05 1.1 1.15 1.2 1.25 1.3 1.5 2.5]; % LED stimulus delays in s
led_durations = [.025]; % LED stimulus durations
% These parameters currently only allow a single value per experiment:
n_repeats = 15; % How many repeats of each parameter combination?
n_stimulators = 2; % 1 or 2, depending on whether we are using one or two piezos
trial_length = 3; % How long is each trial (for trial TTL)
trial_spacing = 5; % Space between TRIGGERS for successive trials; NOTE - trial spacing incorporates time of trial execution;
amplitudes = [1]; % Amplitude as proportions of v_max_1 & v_max_2 below
LED_powers = [1]; % Power as proportion of max (max = 1000 mA)
%% Advanced whisker stim parameters
v_max_1 = 10; % Maximum voltage for whisking waveform (CAREFUL - it can't deal with negative voltages...)
v_max_2 = 5;
stim_sample_duration = [0.0002]; %
sync_sample_duration = 0.002; % duration of each sample / pulse in the trial + whisk sync channel (total can't exceed 5000)
%% Output channel assignment
whisk_wave_channel = 1; % Which channel provides the whisking waveform for the amplifier
trial_whisk_ttl_channel = 2; % Which channel 4provides the TTL signal for when the whisker is on
led_ttl_channel = 3; % Which channel provides the TTL trigger for the LED module
stim_switch_channel = 4; % Which channel provides the signal that determines which stimulator to use
%% Pulsepal startup and initialisation (reconnect to avoid trigger failures)
if exist('PulsePalSystem','var')
EndPulsePal;
end
disp('Re-initialising PulsePal...')
pause(5) % give this some time to complete in PulsePal system
PulsePal; % Initialises PulsePal connection if none exists already; will give notification if PulsePal already connected
% Prerequisite: Pre-assigned PulsePalmatrix with default values
disp('Retrieving default stimulus properties')
load('DefaultPulsePalMatrix.mat');
disp('Sending to PulsePal...')
ProgramPulsePal(DefaultMatrix);
disp('complete.')
pause(0.2)
%% Generate a matrix of one 'block' containing all possible combinations of trials once
block_mat = [];
counter = 0;
for a = 1:length(whisk_delays) % for all whisk_delays...
for b = 1:length(whisk_wave_freq) % for all whisk_wave_freq...
for c = 1:length(whisk_trig_freq) % for all whisk_trig_freq...
for d = 1:length(led_delays) % for all led_delays...
for e = 1:length(led_durations) % for all led_durations...
for f = 1:n_stimulators % for each stimulator (currently 1 or 2)
for g = 1:length(amplitudes) % for all whisking amplitudes
for h = 1:length(LED_powers) % for all LED powers
counter = counter + 1; % increment trial counter to keep track of number of unique trials...
block_mat(counter,:) = [whisk_delays(a) whisk_wave_freq(b) whisk_trig_freq(c) led_delays(d) led_durations(e) f amplitudes(g) LED_powers(h)]; % ...and generate a trial, appending it to the block.
end
end
end
end
end
end
end
end
%% Now generate a trial matrix block by block (using n_repeats * blocks), randomising the trial order of each block
trial_mat = [];
for a = 1:n_repeats
trial_mat = [trial_mat; block_mat(randperm(counter),:)];
end
%% Program execution
n_stims = size(trial_mat,1); % work out how many trials we are executing
total_seconds = n_stims * trial_spacing;
disp(' ')
disp(['Starting protocol totaling ' num2str(n_stims) ' trials...'])
disp(['Total execution time will be ' num2str(total_seconds / 60) ' minutes.'])
tic % start timer
for a = 1:n_stims
disp(' ')
disp(['Trial ' num2str(a) ' of ' num2str(n_stims) '...']);
this_whisk_delay = trial_mat(a,1); % obtain whisking delay for this trial
this_whisk_wave_freq = trial_mat(a,2); % obtain whisking stimulus waveform frequency (i.e. velocity) for this trial
this_whisk_trig_freq = trial_mat(a,3); % obtain whisking trigger frequency (i.e. rate) for this trial
this_led_delay = trial_mat(a,4); % obtain LED onset delay for this trial
this_led_duration = trial_mat(a,5); % obtain LED duration for this trial
this_whisk_stim = trial_mat(a,6); % obtain stimulator ID for this trial
this_amplitude = trial_mat(a,7); % obtain whisk stim amplitude for this trial
this_led_power = trial_mat(a,8); % obtain LED power for this trial
% Display stimulus properties for this trial (also useful for debugging)
disp([...
'Whisk @ ' num2str(this_whisk_delay) 's; '...
'Speed ' num2str(this_whisk_wave_freq) 'Hz; '...
'Freq ' num2str(this_whisk_trig_freq) 'Hz; '...
'LED @ ' num2str(this_led_delay) 's '...
'for ' num2str(this_led_duration) 's; '...
'stim ' num2str(this_whisk_stim) '; ' ...
'amplitude ' num2str(this_amplitude) '; ' ...
'LED ' num2str(this_led_power*1000) 'mA.' ...
]);
% whisker stimulus programming
stim_duration = 1 / this_whisk_wave_freq; % how long does this wave stimulus last?
loop_duration = 1 / this_whisk_trig_freq;
if multiple_whisks
n_whisk_stims = total_whisk_duration / loop_duration;
else
n_whisk_stims = 1;
end
% how long should 1 stimulus loop (waveform + wait for next trigger) last?
stim_burst_duration = loop_duration * n_whisk_stims; % how long should the entire stimulus burst last?
n_samples = stim_duration / stim_sample_duration; % Calculate how many 1 ms samples the waveform needs to last
% stimulus waveform generation
waveform_volts = ((1 - cos([0:2*pi/n_samples:2*pi])) / 2); % generates a [n_samples]-sample sinusoidal waveform, from 0 to 1 to 0.
if this_whisk_stim == 1
this_whisk_wave = waveform_volts * v_max_1; % multiply waveform by target max voltage
elseif this_whisk_stim == 2
this_whisk_wave = waveform_volts * v_max_2;
end
this_whisk_wave = this_whisk_wave * this_amplitude;
% append zero values to whisk_waveform to make it last until the next
% whisker stimulation is due
append_duration = loop_duration - stim_duration; % how much waiting time should be appended
append_number = round(append_duration / stim_sample_duration);% how many zero samples should be appended
append_zeros = zeros(1,append_number); % create a vector of the appropriate nr of zeros to append
this_whisk_wave = [this_whisk_wave append_zeros]; % append the zero values
if length(this_whisk_wave) > 5000
error(['Number of samples for whisking waveform exceeds PulsePal 2 maximum (5000) - offending number of samples: ' num2str(length(this_whisk_wave)) '; adjust trigger frequency or whisk sample rate'])
end
prepend_zeros = zeros(1,this_whisk_delay / sync_sample_duration); % part of trial before whisker stim
whisk_stim_on = repmat(this_whisk_wave,1,n_whisk_stims) ~= 0; % representation of whenever whisk is happening based on whisker waveform above, but at wrong sample rate
whisk_stim_inds = 1:(sync_sample_duration/stim_sample_duration):length(whisk_stim_on);
whisk_stim_on = whisk_stim_on(whisk_stim_inds); % resample to correspond to sync_sample_rate
append_zeros = zeros(1,(trial_length / sync_sample_duration) - (length(prepend_zeros) + length(whisk_stim_on))); % find out how many samples need to be appended to complete the trial
sync_pulse_wave = [prepend_zeros whisk_stim_on append_zeros]; % string all parts of the sync signal together
sync_pulse_wave = ((sync_pulse_wave * this_amplitude) + 1) * 2.5; % set waveform to go from 2.5V (trial onset) to 5V (whisker stims)
if length(sync_pulse_wave) > 5000
error(['Number of samples for syncing waveform exceeds PulsePal 2 maximum (5000) - offending number of samples: ' num2str(length(this_whisk_wave)) '; adjust trial length or sync sample rate'])
end
% Now start populating the PulsePal parameter matrix
stim_matrix = DefaultMatrix; % copy default matrix for trial-specific editing
% programming whisker waveform channel
stim_matrix{15,whisk_wave_channel+1} = 1; % 15: 'CustomTrainID'
stim_matrix{17,whisk_wave_channel+1} = 1; % 17: 'CustomTrainLoop'
stim_matrix{12,whisk_wave_channel+1} = this_whisk_delay; % 12: 'PulseTrainDelay'
stim_matrix{11,whisk_wave_channel+1} = stim_burst_duration; % 11: 'PulseTrainDuration'
stim_matrix{5,whisk_wave_channel+1} = stim_sample_duration; % 5: 'Phase1Duration'
% programming trial and whisk sync channel (trial = 2.5V, trial & whisk = 5V)
stim_matrix{15,trial_whisk_ttl_channel+1} = 2; % 15: 'CustomTrainID'
stim_matrix{17,trial_whisk_ttl_channel+1} = 1; % 17: 'CustomTrainLoop'
stim_matrix{12,trial_whisk_ttl_channel+1} = 0; % 12: 'PulseTrainDelay' - Delay
stim_matrix{11,trial_whisk_ttl_channel+1} = trial_length; % 11: 'PulseTrainDuration' - Duration of total nr of TTLs
stim_matrix{5,trial_whisk_ttl_channel+1} = sync_sample_duration; % 5: 'Phase1Duration' - duration of each sample in pulse train (?)
% programming LED TTL channel
stim_matrix{12,led_ttl_channel+1} = this_led_delay; % 12: 'PulseTrainDelay' - Delay
stim_matrix{5,led_ttl_channel+1} = this_led_duration; % 5: 'Phase1Duration' - Duration of TTL up
stim_matrix{11,led_ttl_channel+1} = this_led_duration; % 11: 'PulseTrainDuration' - Duration of total nr of TTLs
stim_matrix{3,led_ttl_channel+1} = this_led_power * 5; % 3: 'Phase1Voltage' - Output voltage when 'high' (5V = max input for LED box, triggering a 1mA LED pulse)
% programming stim_switch TTL channel
stim_matrix{12,stim_switch_channel+1} = 0; % 12: 'PulseTrainDelay' - Delay
stim_matrix{5,stim_switch_channel+1} = trial_length; % 5: 'Phase1Duration' - Duration of TTL up
stim_matrix{11,stim_switch_channel+1} = trial_length; % 11: 'PulseTrainDuration' - Duration of total nr of TTLs
stim_matrix{3,stim_switch_channel+1} = (this_whisk_stim - 1) * 5; % 3: Phase1Voltage; 0V (low) for stimulator 1, 5V (high) for stimulator 2.
% send the edited stimulus matrix to PulsePal
ProgramPulsePal(stim_matrix);
% Send the custom waveform to custom waveform slot nr. 1
success1 = SendCustomWaveform(1, stim_sample_duration, this_whisk_wave); % send waveform to PulsePal; use 'stim_sample_duration' to set sample rate
success2 = SendCustomWaveform(2, sync_sample_duration, sync_pulse_wave); % send trial synchronisation waveform to PulsePal; use 'stim_sample_duration' to set sample rate
% All stimulus parameters are uploaded; start fast loop to monitor for
% elapsed time
while toc < trial_spacing
end
% Now trigger all channels at the same time
TriggerPulsePal('1111');
tic % start timer until next trigger event
% Report trial number
disp(['Trial ' num2str(a) ' triggered']);
disp(['Time remaining: ~ ' num2str((n_stims-a)*trial_spacing/60) ' minutes.'])
disp(' ')
pause(trial_length) % IMPORTANT! If you upload next trial parameters while the current trial is still running, it messes with the current trial
end
disp('Trial execution completed.')
EndPulsePal;