-
Notifications
You must be signed in to change notification settings - Fork 1
/
compute_all_pulse_responses.m
executable file
·234 lines (208 loc) · 10.1 KB
/
compute_all_pulse_responses.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
function [tVecAll, respAll, stimAll, featuresAll] = ...
compute_all_pulse_responses (fileName, responseType, varargin)
%% Filter and extract all pulse response and compute features
% Usage: [tVecAll, respAll, stimAll, featuresAll] = ...
% compute_all_pulse_responses (fileName, responseType, varargin)
% Explanation:
% TODO
% Example(s):
% TODO
% Outputs:
% tVecAll - time vector for each response
% specified as a numeric column vector
% respAll - pulse response vector(s)
% specified as a numeric column vector
% or a cell array of column vectors
% stimAll - stimulation pulse vector(s)
% specified as a numeric column vector
% or a cell array of column vectors
% featuresAll - computed features of the average pulse response,
% a table with variables:
% those returned by parse_pulse_response.m,
% labels: labels for respAll and stimAll, respectively
% specified as a table of 1 row
% Arguments:
% fileName - file name could be either the full path or
% a relative path in current directory
% .abf is not needed (e.g. 'B20160908_0004')
% must be a string scalar or a character vector
% responseType- the channel type for the pulse response
% must be an unambiguous, case-insensitive match to one of:
% 'Voltage' - voltage
% 'Current' - current
% 'Conductance' - conductance
% 'Other' - other un-identified types
% varargin - 'MinRowNumber': minimum row number for featuresAll
% must be a positive integer scalar
% default = 1
% - 'LowPassFrequency': frequency of lowpass filter in Hz
% must be empty or a positive scalar
% default = []
% - 'MedFiltWindow': window of median filter in ms
% must be empty or a positive scalar
% default = []
% - 'SmoothWindow': window of moving average filter in ms
% must be empty or a positive scalar
% default = []
% - 'ResponseLengthMs': length of the pulse response
% after pulse endpoint in ms
% must be a nonnegative scalar
% default = 20 ms
% - 'BaselineLengthMs': length of the pulse response
% before pulse start in ms
% must be a nonnegative scalar
% default = 5 ms
% - 'MinPeakDelayMs': minimum peak delay (ms)
% after the end of the pulse
% must be a positive scalar
% default == 0 ms
% - 'PeakDirection': direction of expected peak
% must be an unambiguous, case-insensitive match to one of:
% 'Downward' - downward peaks (e.g., EPSCs)
% 'Upward' - upward peaks (e.g., IPSCs)
% 'Auto' - no preference (whichever is largest)
% default = 'Auto'
% - 'ChannelTypes': the channel types
% must be a cellstr with nChannels elements
% each being one of the following:
% 'Voltage'
% 'Current'
% 'Conductance'
% 'Other'
% default == detected with identify_channels()
% - 'ParsedParams': parsed parameters returned by parse_abf.m
% must be a scalar structure
% default == what the file provides
% - 'ParsedData': parsed data returned by parse_abf.m
% must be a scalar structure
% default == what the file provides
% - 'SaveFlag': whether to save the pulse train series
% must be numeric/logical 1 (true) or 0 (false)
% default == true
%
% Requires:
% cd/compute_sampling_interval.m
% cd/count_vectors.m
% cd/create_labels_from_numbers.m
% cd/parse_pulse_response.m
%
% Used by:
% cd/compute_and_plot_all_responses.m
% File History:
% 2018-12-15 Modified from compute_average_pulse_response.m
% 2018-12-17 Now uses create_labels_from_numbers.m
% TODO: save table if SaveFlag is true
%
%% Hard-coded parameters
validChannelTypes = {'Voltage', 'Current', 'Conductance', 'Other'};
validPeakDirections = {'upward', 'downward', 'auto'};
%% Default values for optional arguments
minRowNumberDefault = 1; % row number to start counting at is 1
lowPassFrequencyDefault = []; % do not lowpass filter by default
medFiltWindowDefault = []; % do not median filter by default
smoothWindowDefault = []; % do not moving average filter by default
responseLengthMsDefault = 20; % a response of 20 ms by default
baselineLengthMsDefault = 5; % a baseline of 5 ms by default
minPeakDelayMsDefault = 0; % no minimum peak delay by default
channelTypesDefault = {}; % set later
channelUnitsDefault = {}; % set later
channelLabelsDefault = {}; % set later
parsedParamsDefault = []; % set later
parsedDataDefault = []; % set later
saveFlagDefault = true; % save the pulse train series by default
peakDirectionDefault = 'auto'; % automatically detect largest peak by default
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Deal with arguments
% Check number of required arguments
if nargin < 2
error(create_error_for_nargin(mfilename));
end
% Set up Input Parser Scheme
iP = inputParser;
iP.FunctionName = mfilename;
iP.KeepUnmatched = true; % allow extraneous options
% Add required inputs to the Input Parser
addRequired(iP, 'fileName', ...
@(x) validateattributes(x, {'char', 'string'}, {'scalartext'}));
addRequired(iP, 'responseType', ...
@(x) any(validatestring(x, validChannelTypes)));
% Add parameter-value pairs to the Input Parser
addParameter(iP, 'MinRowNumber', minRowNumberDefault, ...
@(x) validateattributes(x, {'numeric'}, {'positive', 'integer', 'scalar'}));
addParameter(iP, 'LowPassFrequency', lowPassFrequencyDefault, ...
@(x) isempty(x) || ispositivescalar(x));
addParameter(iP, 'MedFiltWindow', medFiltWindowDefault, ...
@(x) isempty(x) || ispositivescalar(x));
addParameter(iP, 'SmoothWindow', smoothWindowDefault, ...
@(x) isempty(x) || ispositivescalar(x));
addParameter(iP, 'ResponseLengthMs', responseLengthMsDefault, ...
@(x) validateattributes(x, {'numeric'}, {'nonnegative', 'scalar'}));
addParameter(iP, 'BaselineLengthMs', baselineLengthMsDefault, ...
@(x) validateattributes(x, {'numeric'}, {'nonnegative', 'scalar'}));
addParameter(iP, 'MinPeakDelayMs', minPeakDelayMsDefault, ...
@(x) validateattributes(x, {'numeric'}, {'positive', 'scalar'}));
addParameter(iP, 'ChannelTypes', channelTypesDefault, ...
@(x) isempty(x) || isstring(x) || iscellstr(x));
addParameter(iP, 'ChannelUnits', channelUnitsDefault, ...
@(x) isempty(x) || isstring(x) || iscellstr(x));
addParameter(iP, 'ChannelLabels', channelLabelsDefault, ...
@(x) isempty(x) || isstring(x) || iscellstr(x));
addParameter(iP, 'ParsedParams', parsedParamsDefault, ...
@(x) isempty(x) || isstruct(x));
addParameter(iP, 'ParsedData', parsedDataDefault, ...
@(x) isempty(x) || isstruct(x));
addParameter(iP, 'SaveFlag', saveFlagDefault, ...
@(x) validateattributes(x, {'logical', 'numeric'}, {'binary'}));
addParameter(iP, 'PeakDirection', peakDirectionDefault, ...
@(x) any(validatestring(x, validPeakDirections)));
% Read from the Input Parser
parse(iP, fileName, responseType, varargin{:});
minRowNumber = iP.Results.MinRowNumber;
baselineLengthMs = iP.Results.BaselineLengthMs;
minPeakDelayMs = iP.Results.MinPeakDelayMs;
peakDirection = validatestring(iP.Results.PeakDirection, validPeakDirections);
saveFlag = iP.Results.SaveFlag;
%% Filter and extract pulse response(s)
[tVecAll, respAll, stimAll, labels] = ...
filter_and_extract_pulse_response(fileName, responseType, varargin{:});
%% Compute features of the average pulse response
% Compute the sampling interval(s)
siMs = compute_sampling_interval(tVecAll);
% Count the number of vectors
nVectors = count_vectors(tVecAll);
% Parse the average pulse response vector
featuresAll = parse_pulse_response(respAll, siMs, ...
'PulseVectors', stimAll, ...
'SameAsPulse', true, ...
'MeanValueWindowMs', baselineLengthMs, ...
'MinPeakDelayMs', minPeakDelayMs, ...
'PeakDirection', peakDirection);
% Add labels to each row
labels = repmat({labels}, [nVectors, 1]);
featuresAll = addvars(featuresAll, labels);
% Construct sweep names
sweepName = create_labels_from_numbers(1:nVectors, 'Prefix', 'Swp', ...
'ForceColumnOutput', true);
% Repeat the file names
filePath = repmat({fileName}, [nVectors, 1]);
% Insert the sweep name before the first column of featuresAll
featuresAll = addvars(featuresAll, sweepName, 'Before', 1);
% Insert the file path before the sweep name of featuresAll
featuresAll = addvars(featuresAll, filePath, 'Before', 1);
%% Save the features table
% if saveFlag
% writetable(featuresAll, sheetPath);
% end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%{
OLD CODE:
% Insert before the second column of featuresAll the median time
if iscell(tVecAll)
siMs = tVecAll{1}(2) - tVecAll{1}(1);
else
siMs = tVecAll(2) - tVecAll(1);
end
sweepName = arrayfun(@(x) ['Swp', num2str(x)], ...
transpose(1:nVectors), 'UniformOutput', false);
%}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%