-
Notifications
You must be signed in to change notification settings - Fork 0
/
GaussNeurons.m
135 lines (117 loc) · 5.79 KB
/
GaussNeurons.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
classdef GaussNeurons < Neurons
properties
width = [];
maxRate = [];
backgroundRate = [];
end
methods
function obj = GaussNeurons(varargin)
% GAUSSNEURONS/GAUSSNEURONS Constructor for GaussNeurons object - population of neurons with Gaussian tuning curves
% obj = GaussNeurons(preferredStimuli, width, maxRate, backgroundRate, integrationTime, variabilityScheme, variabilityOpts)
%
% preferredStimuli - preferred stimulus value
% width - tuning curve width (this would be the variance if the curve was a probability distribution)
% maxRate - maximum firing rate (Hz)
% backgroundRate - background (spontaneous) firing rate (Hz)
% integrationTime - spike counting time per trial
% variabilityScheme - type of variability model
% variabilityOpts - vector of options
%
% preferredStimulus, width, maxFiringRate and backgroundFiringRate can be scalars or vectors of length popSize.
% GaussNeurons accept only 1-D stimuli at present.
switch nargin
case 7
preferredStimuli = varargin{1};
widthIn = varargin{2};
maxRateIn = varargin{3};
backgroundRateIn = varargin{4};
integrationTime = varargin{5};
variabilityScheme = varargin{6};
variabilityOpts = varargin{7};
otherwise
error('Wrong number of inputs')
end
% Superclass constructor
obj = obj@Neurons(1, preferredStimuli, integrationTime, variabilityScheme, variabilityOpts);
if isscalar(widthIn) && isnumeric(widthIn)
obj.width = double(widthIn(ones(obj.popSize, 1)));
elseif length(widthIn) == obj.popSize && isvector(widthIn) && isnumeric(widthIn)
obj.width = reshape(double(widthIn), obj.popSize, 1);
else
error('Invalid width value or vector for population size %n', obj.popSize)
end
if isscalar(maxRateIn) && isnumeric(maxRateIn)
obj.maxRate = double(maxRateIn(ones(obj.popSize, 1)));
elseif length(maxRateIn) == obj.popSize && isvector(maxRateIn) && isnumeric(maxRateIn)
obj.maxRate = reshape(double(maxRateIn), obj.popSize, 1);
else
error('Invalid max firing rate value or vector for population size %n', obj.popSize)
end
if isscalar(backgroundRateIn) && isnumeric(backgroundRateIn)
obj.backgroundRate = double(backgroundRateIn(ones(obj.popSize, 1)));
elseif length(backgroundRateIn) == obj.popSize && isvector(backgroundRateIn) && isnumeric(backgroundRateIn)
obj.backgroundRate = reshape(double(backgroundRateIn), obj.popSize, 1);
else
error('Invalid background firing rate value or vector for population size %n', obj.popSize)
end
end
function r = meanR(obj, stim)
% MEANR calculates mean responses to a set of stimuli
% r = meanR(obj, stimulusEnsemble)
%
% r = maxRate * exp(-((stimulus - preferredStimulus)^2 / (2 * width^2))) + backgroundRate
if isa(stim, 'StimulusEnsemble')
assert(stim.dimensionality == 1, 'SigmoidNeurons only supports 1-D stimuli at present')
stims = repmat(stim.ensemble, [obj.popSize 1]);
maxRates = repmat(obj.maxRate, [1 stim.n]);
backgroundRates = repmat(obj.backgroundRate, [1 stim.n]);
centres = repmat(obj.preferredStimulus, [1 stim.n]);
widths = repmat(obj.width, [1 stim.n]);
elseif isa(stim, 'double')
stims = repmat(stim(:)', [obj.popSize 1]);
maxRates = repmat(obj.maxRate, [1 length(stim)]);
backgroundRates = repmat(obj.backgroundRate, [1 length(stim)]);
centres = repmat(obj.preferredStimulus, [1 length(stim)]);
widths = repmat(obj.width, [1 length(stim)]);
else
error('Invalid stimulus: stim may be a StimulusEnsemble object or vector of stimulus values only')
end
r = maxRates .* exp(-((stims - centres).^2) ./ (2.0 .* widths.^2)) + backgroundRates;
nullStim = isnan(stims);
r(nullStim) = backgroundRates(nullStim);
end
function dr = dMeanR(obj, stim)
% DMEANR calculates the derivative of the tuning curve
% dr = dMeanR(obj, stim)
if isa(stim, 'StimulusEnsemble')
assert(stim.dimensionality == 1, 'SigmoidNeurons only supports 1-D stimuli at present')
stims = repmat(stim.ensemble, [obj.popSize 1]);
maxRates = repmat(obj.maxRate, [1 stim.n]);
centres = repmat(obj.preferredStimulus, [1 stim.n]);
widths = repmat(obj.width, [1 stim.n]);
elseif isa(stim, 'double')
stims = repmat(stim(:)', [obj.popSize 1]);
maxRates = repmat(obj.maxRate, [1 length(stim)]);
centres = repmat(obj.preferredStimulus, [1 length(stim)]);
widths = repmat(obj.width, [1 length(stim)]);
else
error('Invalid stimulus: stim may be a StimulusEnsemble object or vector of stimulus values only')
end
dr = maxRates .* (centres - stims) ./ widths.^2 .* exp(-(centres - stims).^2 ./ (2 .* widths.^2));
end
function obj = remove(obj, nMarg)
% Call superclass method
[obj, margMask] = remove@Neurons(obj, nMarg);
% Deal with subclass properties
if length(obj.width) > 1
obj.width = obj.width(margMask);
end
if length(obj.maxRate) > 1
obj.maxRate = obj.maxRate(margMask);
end
if length(obj.backgroundRate) > 1
obj.backgroundRate = obj.backgroundRate(margMask);
end
end
end
end