forked from rorygt/NeuroPattToolbox
-
Notifications
You must be signed in to change notification settings - Fork 13
/
setNeuroPattParams.m
217 lines (197 loc) · 7.96 KB
/
setNeuroPattParams.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
function params = setNeuroPattParams(params, name, value, fs)
% SETNEUROPATTPARAMS Sets all parameters in the NeuroPatt toolbox
% PARAMS = SETPATTERNPARAMS(FS) sets all parameters in the PARAMS
% structure using parameter values listed below using sampling frequency
% FS (in Hz)
%
% PARAMS = SETPATTERNPARAMS(PARAMS, NAME, VALUE, FS) updates existing
% parameter structure PARAMS by changing the parameter called NAME to be
% set to VALUE, using sampling frequency FS. If PARAMS input is empty,
% parameters apart from NAME will be filled by the default values listed
% below.
%
% Rory Townsend, Aug 2018
%% Parse inputs
if nargin==1 && isnumeric(params)
% If only sampling frequency is defined, set all parameters based on
% values below
fs = params;
setAllParams = true;
name = '';
params = [];
elseif nargin==4 && (isempty(params) || isstruct(params)) && ...
ischar(name) && isnumeric(fs)
if isempty(params)
setAllParams = true;
else
setAllParams = false;
end
else
error('Invalid input format! Inputs must be setPatternParams(FS) or setPatternParams(PARAMS,NAME,VALUE,FS).')
end
if setAllParams
%% Preprocessing parameters
% Temporal downsampling scale after filtering for faster optical flow and
% pattern detection calculations (default 1, corresponding to no
% downsampling)
downsampleScale = 5;
% Flag to de-mean all channels before processing (default true)
subtractBaseline = true;
% Flag to z-score all channels before processing (default false)
zscoreChannels = false;
%% Filtering parameters
% Flag to filter data, otherwise raw unfiltered data will be used (default
% true)
filterData = true;
% Flag to use the Hilbert transform for filtering, otherwise Morlet
% wavelets will be used (default false)
useHilbert = false;
% Morlet transform parameters
% Centre frequency (in Hz)
morletCfreq = 6;
% Morlet wavelet scale parameter: higher values have better frequency
% resolution but lower temporal resolution (default 5)
morletParam = 5;
% Hilbert transform parameters
% Frequency limits of band-pass filter (in Hz)
hilbFreqLow = 1;
hilbFreqHigh = 4;
%% Optical flow parameters
% Smoothing parameter: higher values will give a smoother velocity field
% (typically 0<OPALPHA<5, default 0.5).
opAlpha = 0.5;
% Non-linearity penalty parameter: close to zero will be highly non-linear,
% large values will be approximately linear, resulting in faster
% computations but possibly less accurate flow fields (default 1)
opBeta = 1;
% Flag to calculate amplitude velocity fields rather than phase (default
% false)
useAmplitude = false;
%% Singular value decomposition parameters
% Flag to perform SVD on velocity fields to extract spatiotemporal modes,
% otherwise this will be skipped (default true)
performSVD = true;
% Flag to perform a complex decomposition, allowing spatial modes that can
% rotate over time. Otherwise, real decomposition will be used (default
% false)
useComplexSVD = false;
% Number of modes to plot (default 6)
nSVDmodes = 6;
%% Pattern parameters
% Minimum order parameter for a plane wave to be detected (default 0.85)
planeWaveThreshold = 0.85;
% Maximum velocity field magnitude for synchrony to be detected (default
% 0.85)
synchronyThreshold = 0.85;
% Minimum duration of a pattern for it to be stored (in seconds, default 0)
minDurationSecs = 0.02;
% Maximum duration between critical points (or synchrony/plane waves) for
% them to be counted as the same pattern (in seconds, default 0)
maxTimeGapSecs = 0.005;
% Maxiumum displacement between critical points between time steps for them
% to be counted as the same pattern (measured in grid spaces, default 1)
maxDisplacement = 1;
% Minimum spatial radius for a critical point to occupy for it to be
% counted, quantified by the winding number (measured in grid spaces,
% default 2)
minCritRadius = 2;
% Minimum distance from the edge of the system (in grid spaces, default 2)
minEdgeDistance = 2;
% Boolean paramter to combine node and focus type critical points (default
% false)
combineNodeFocus = false;
% Boolean parameter to combine stable and unstable critical points (default
% false)
combineStableUnstable = false;
else
% Add in a temporary value for this minimum frequency so that the
% maximum frequency can be compared against it
hilbFreqLow = params.hilbFreqLow;
end
%% Verify parameters and add to output structure
% Generate cell array with all parameter names and limitations
% Format: Name, Flag for logical, Minimum value, Maximum value
allParams = {...
'downsampleScale', false, 1-eps, []; ... % Pre-processing parameters
'subtractBaseline', true, [], []; ...
'zscoreChannels', true, [], []; ...
'filterData', true, [], []; ... % Filtering parameters
'useHilbert', true, [], []; ...
'morletCfreq', false, 0, []; ...
'morletParam', false, 0, []; ...
'hilbFreqLow', false, 0, []; ...
'hilbFreqHigh', false, hilbFreqLow-eps, []; ...
'opAlpha', false, 0, []; ... % Optical flow parameters
'opBeta', false, 0, []; ...
'useAmplitude', true, [], []; ...
'performSVD', true, [], []; ... % SVD parameters
'useComplexSVD', true, [], []; ...
'nSVDmodes', false, 0, 20; ...
'planeWaveThreshold', false, 0-eps, 1+eps; ... % Pattern detection parameters
'synchronyThreshold', false, 0-eps, 1+eps; ...
'minDurationSecs', false, 0-eps, []; ...
'maxTimeGapSecs', false, 0-eps, []; ...
'maxDisplacement', false, 0-eps, []; ...
'minCritRadius', false, 0-eps, []; ...
'minEdgeDistance', false, 0-eps, []; ...
'combineNodeFocus', true, [], []; ...
'combineStableUnstable', true, [], [] ...
};
% If only changing one parameter, find it in the list
if ~setAllParams
allParams = allParams(cellfun(@(x) strcmp(x,name), allParams(:,1)), :);
end
% Loop over all parameters in the list
for iparam = 1:size(allParams, 1)
[pname, logicalFlag, minVal, maxVal] = allParams{iparam, :};
% Choose default or user input value
if strcmp(pname, name)
ivalue = value;
else
ivalue = eval(pname);
end
% Test if parameter value is valid and add to output structure
if logicalFlag == 1
params.(pname) = testLogical(ivalue, pname);
else
params.(pname) = testNumeric(ivalue, pname, minVal, maxVal);
end
end
% Set secondary parameters that are defined by the sampling frequency
params.maxTimeGapSteps = floor(params.maxTimeGapSecs * fs / params.downsampleScale);
params.minDurationSteps = max(1, round(params.minDurationSecs * fs / params.downsampleScale));
end
function value = testNumeric(value, varName, minval, maxval)
% Subfunction to test numeric values for variable VARNAME with an
% optional minimum of MINVAL and maximum of MAXVAL, throwing an error
% if invalid
if ~isnumeric(value) || ~isscalar(value) || ...
(nargin>=3 && ~isempty(minval) && value<=minval) || ...
(nargin>=4 && ~isempty(maxval) && value>=maxval)
% Construct error message to show the limitations on the parameter
if nargin>=4 && ~isempty(minval) && ~isempty(maxval)
errorMsgEnd = sprintf(' and must be greater than %0.1f and less than %0.1f.', ...
minval, maxval);
elseif nargin>=4 && ~isempty(maxval)
errorMsgEnd = sprintf(' and must be less than %0.1f.', maxval);
elseif nargin>=3 && ~isempty(minval)
errorMsgEnd = sprintf(' and must be greater than %0.1f.', minval);
else
errorMsgEnd = '.';
end
error('Invalid value for parameter %s. Value must be a numeric scalar%s', ...
varName, errorMsgEnd)
end
end
function value = testLogical(value, varName)
% Subfunction to test logical values for variable VARNAME, throwing an
% error if invalid
if isscalar(value) && value
value = true;
elseif isscalar(value) && ~value
value = false;
else
error('Invalid value for parameter %s. Value must resolve to a logical expression.', varName)
end
end