-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCircGaussNeurons.m
142 lines (120 loc) · 6.02 KB
/
CircGaussNeurons.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
classdef CircGaussNeurons < Neurons
properties
width = [];
maxRate = [];
backgroundRate = [];
end
methods
function obj = CircGaussNeurons(varargin)
% CIRCGAUSSNEURONS/CIRCGAUSSNEURONS Constructor for CircGaussNeurons object - population of neurons with circular Gaussian tuning curves
% obj = CircGaussNeurons(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.
% CircGaussNeurons accepts 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)
% CIRCGAUSSNEURONS/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')
stims = repmat(stim.ensemble, [obj.popSize 1]);
maxRate = repmat(obj.maxRate, [1 stim.n]);
backgroundRate = repmat(obj.backgroundRate, [1 stim.n]);
centre = repmat(obj.preferredStimulus, [1 stim.n]);
width = repmat(obj.width, [1 stim.n]);
elseif isa(stim, 'double')
stims = repmat(stim(:)', [obj.popSize 1]);
maxRate = repmat(obj.maxRate, [1 length(stim)]);
backgroundRate = repmat(obj.backgroundRate, [1 length(stim)]);
centre = repmat(obj.preferredStimulus, [1 length(stim)]);
width = repmat(obj.width, [1 length(stim)]);
else
error('Invalid stimulus: stim may be a StimulusEnsemble object or vector of stimulus values only')
end
r = maxRate .* exp(-(1.0 ./ degToRad(width).^2) .* (1 - cosd(double(stims - centre)))) + backgroundRate;
end
function dr = dMeanR(obj, stim)
% CIRCGAUSSNEURONS/DMEANR calculates the derivative of the tuning curve
% dr dr = dMeanR(obj, stim)
if isa(stim, 'StimulusEnsemble')
stims = repmat(stim.ensemble, [obj.popSize 1]);
maxRate = repmat(obj.maxRate, [1 stim.n]);
centre = repmat(obj.preferredStimulus, [1 stim.n]);
width = repmat(obj.width, [1 stim.n]);
elseif isa(stim, 'double')
stims = repmat(stim, [obj.popSize 1]);
maxRate = repmat(obj.maxRate, [1 length(stim)]);
centre = repmat(obj.preferredStimulus, [1 length(stim)]);
width = repmat(obj.width, [1 length(stim)]);
else
error('Invalid stimulus: stim may be a StimulusEnsemble object or vector of stimulus values only')
end
beta = 1.0 ./ degToRad(width).^2;
dr = pi/180 .* (-maxRate .* exp(-beta) .* beta .* sind(double(stims - centre)) .* exp(beta .* cosd(double(stims - centre))));
end
function obj = gainadapt(obj, width, amnt, centre)
obj.maxRate = obj.maxRate .* (1 - amnt .* exp(-(1.0 ./ degToRad(width).^2) .* (1 - cosd(double(obj.preferredStimulus - centre)))));
end
function obj = widthadapt(obj, width, amnt, centre)
obj.width = obj.width .* (1 - amnt .* exp(-(1.0 ./ degToRad(width).^2) .* (1 - cosd(double(obj.preferredStimulus - centre)))));
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