Revision 38:c2204b18f4a2 userProgramsTim

View differences:

userProgramsTim/IPIHextract.m
1
function [iih,IPIhisttime,IPIhistweight]=IPIHextract(IFRAN_pattern, sfreq)
2
% 
3
% tracks the formants according to an analysis proposed in Secker-Walker
4
% JASA 1990, section V.A
5
% Tim J?rgens, February 2011, code from Guy Brown included
6
% 
7
% input:  IFRAN_pattern: pattern of the auditory model (dependend on the number of modules used)
8
%                        first dimension: frequency channel, 
9
%                        second dimension: time (samples)
10
%         sfreq:         sampling frequency
11
% output: iih:           interpeak-interval histogram, matrix very similar
12
%                        the plot 5 in the Secker-Walker paper
13
%
14
%
15
%
16

  
17

  
18
time_axis = 0:1/sfreq:(size(IFRAN_pattern,2)-1)/sfreq;
19

  
20
%find how many samples of AN_pattern are 10ms and 3ms
21
%one_sample_is_a_time_of = time_axis(2);
22
[tmp, start_time_index] = min(abs(0-time_axis));
23
[tmp, stop20_time_index] = min(abs(0.020-time_axis));
24
number_of_samples20ms = stop20_time_index - start_time_index;
25

  
26
[tmp, stop10_time_index] = min(abs(0.010-time_axis));
27
number_of_samples10ms = stop10_time_index - start_time_index;
28
every_10ms = 1:number_of_samples10ms:size(IFRAN_pattern,2)-number_of_samples20ms;
29

  
30
hamm_window = hamming(11);
31
halfHamming = (length(hamm_window)-1)/2;
32

  
33
% window normalization
34

  
35
norm = conv(ones(1,number_of_samples20ms),hamm_window);
36
norm = norm(5+1:end-5)';
37
win_size = number_of_samples20ms;
38
half_win_size = floor(win_size/2);
39
hop_size = number_of_samples10ms;
40

  
41
%parameters of the autocorrelation
42
params.acfTau=0.1;
43
params.lags=[0:1/sfreq:0.02-1/sfreq];
44
sampledacf = runningACF(IFRAN_pattern,sfreq,params);
45
sampledacf(sampledacf<0)=0;
46
sampledacf = sqrt(sampledacf);
47

  
48

  
49
%pre-allocation due to speed
50
%Acorr = zeros(size(IFRAN_pattern,1),size(every_3ms,2),number_of_samples10ms*2+1);
51
%RAcorr = zeros(size(IFRAN_pattern,1),size(every_3ms,2),number_of_samples10ms*2+1);
52
%SRAcorr = zeros(size(IFRAN_pattern,1),size(every_3ms,2),number_of_samples10ms*2+1-10);
53
IPIhisttime = zeros(size(IFRAN_pattern,1),size(every_10ms,2),3);
54
IPIhistweight = zeros(size(IFRAN_pattern,1),size(every_10ms,2),3);  %maximum 3 peaks from the SRA
55
iih = zeros(half_win_size,size(sampledacf,1));
56

  
57

  
58

  
59

  
60

  
61
for iCounter = 1:size(sampledacf,2) %each channel
62
    fprintf('Channel No. %i\n',iCounter);
63
    %time_counter = 1;
64
    %for jCounter = every_3ms %every 3ms time segment
65
                    
66
    for frame=1:size(sampledacf,1)
67
        
68
        %%debug
69
        %if iCounter == 130
70
        %    disp('here');
71
        %end
72
        
73
        
74
        sra = conv(squeeze(sampledacf(frame,iCounter,:)),hamm_window);
75
        sra = sra(halfHamming+1:end-halfHamming)./norm;
76
        df = [0 ; diff(sra)];
77
        idx = find((df(1:end-1)>=0)&(df(2:end)<0));
78
        % interpolate
79
        a=df(idx);
80
        b=df(idx+1);
81
        idx = (idx-1+a./(a-b));
82
        % get rid of a zero peak, if it exists
83
        idx = idx(idx>1);
84
        %include the zeroth peak
85
        idx = [1 idx']';
86
        % peak values corresponding to these intervals
87
        amp = interp1(1:length(sra),sra,idx,'linear');
88
        % if required, remove peaks that lie below the mean sra
89
        % note that we disregard the value at zero delay
90
        %if (params.removePeaksBelowMean)
91
        valid = find(amp>1.2*mean(sra(1:floor(length(sra)/2))));
92
        %valid = find(amp>mean(sra));
93
        %just take the mean of the first half of the sra as a comparison
94
        idx = idx(valid);
95
        amp = amp(valid);
96
        %end
97
        % only use the first four peaks (three intervals)
98
        idx = idx(1:min(4,length(idx)));
99
        % find the intervals
100
        interval = diff(idx);
101
        % now histogram the intervals
102
        if (~isempty(interval))
103
            for k=1:length(interval)
104
                if interval(k)<=half_win_size
105
                    iih(round(interval(k)),frame) = iih(round(interval(k)),frame)+amp(k);
106
                    IPIhisttime(iCounter,frame,k) = interval(k)/sfreq;
107
                    IPIhistweight(iCounter,frame,k) = amp(k);
108
                end
109
            end
110
        end
111
        
112
    end
113
    
114
    
115
    
116
    
117
    %% end Guy's code
118
    
119
    
120
    %         %take the autocorrelation (ACF) of a 10ms-segment of each channel
121
    %         Acorr(iCounter,time_counter,:) = xcorr(IFRAN_pattern(iCounter,jCounter:number_of_samples10ms+jCounter),'biased'); %biased scales the ACF by the reciprocal of the length of the segment
122
    %         %root calculation
123
    %         RAcorr(iCounter,time_counter,:) = sqrt(abs(Acorr(iCounter,time_counter,:)));
124
    %
125
    %         %smoothing using the 11-point hamming window
126
    %         for kCounter = 6:size(RAcorr(iCounter,time_counter,:),3)-5 %start with 6 and end with 5 samples
127
    %             %less the length of time_axis not to get in conflict with the length of
128
    %             %the hamm_window
129
    %             SRAcorr(iCounter,time_counter,kCounter-5) = ...
130
    %                 squeeze(RAcorr(iCounter,time_counter,(kCounter-5):(kCounter+5)))'*hamm_window./sum(hamm_window);
131
    %         end
132
    %
133
    %         %mean value of actual SRA
134
    %         SRA_mean = mean(SRAcorr(iCounter,time_counter,:));
135
    %
136
    %         %find signed zero-crossings of the first derivative (=difference)
137
    %         z_crossings_indices = find(diff(sign(diff(squeeze(SRAcorr(iCounter,time_counter,:))))) < 0)+1; %+1 is necessary, because diff shortens vector by 1
138
    %         middle_index = ceil(size(SRAcorr(iCounter,time_counter,:),3)/2);
139
    %
140
    %         validCounter = 1;
141
    %         valid_z_crossings_indices = [];
142
    %         %find valid zero-crossings (peak higher than meanvalue and within first 5 ms of SRA)
143
    %         for lCounter = 1:length(z_crossings_indices)
144
    %             if (SRAcorr(iCounter,time_counter,z_crossings_indices(lCounter)) > SRA_mean) && ...
145
    %                     (abs(z_crossings_indices(lCounter)-middle_index) < round(number_of_samples10ms/2));
146
    %                 valid_z_crossings_indices(validCounter) = z_crossings_indices(lCounter);
147
    %                 validCounter = validCounter+1;
148
    %             end
149
    %         end
150
    %
151
    %         %find main peak in the ACF
152
    %         [tmp,index_of_z_crossings_main_index] = min(abs(middle_index-valid_z_crossings_indices));
153
    %         if ~tmp == 0
154
    %             disp('middle peak not appropriately found');
155
    %         end
156
    %
157
    %         %%% for debugging
158
    % %         if iCounter == 130
159
    % %             disp('here');
160
    % %             figure, plot(squeeze(SRAcorr(iCounter,time_counter,:)));
161
    % %             hold on, plot([1 length(squeeze(SRAcorr(iCounter,time_counter,:)))],[SRA_mean SRA_mean],'r-');
162
    % %         end
163
    %         %%%
164
    %
165
    %         %generate IPI-histogram: take the first 3 intervals of SRAcorr
166
    %         %(positive delay) in the first 5 ms
167
    %         histcounter = 1;
168
    %         for lCounter = index_of_z_crossings_main_index+1:min([length(valid_z_crossings_indices(index_of_z_crossings_main_index+1:end)) 3])+index_of_z_crossings_main_index
169
    %             sampledifference = abs(valid_z_crossings_indices(lCounter)-valid_z_crossings_indices(lCounter-1));
170
    %             %the difference between two adjacent peaks in the SRA is taken
171
    %             %as IPI estimate
172
    %             IPIhisttime(iCounter,time_counter,histcounter) = sampledifference*one_sample_is_a_time_of;
173
    %             %the amplitude of the SRA at the start of the SRA interval is
174
    %             %taken as the IPIweight
175
    %             IPIhistweight(iCounter,time_counter,histcounter) = SRAcorr(iCounter,time_counter,valid_z_crossings_indices(lCounter-1));
176
    %             histcounter = histcounter + 1;
177
    %         end
178
    
179
    %time_counter = time_counter+1;
180
end
181

  
userProgramsTim/MAP1_14_olde_version_dont_use.m
1
function  MAP1_14(inputSignal, sampleRate, BFlist, MAPparamsName, ...
2
    AN_spikesOrProbability, paramChanges)
3
% To test this function use test_MAP1_14 in this folder
4
%
5
% example:
6
% <navigate to 'MAP1_14\MAP'>
7
%  [inputSignal FS] = wavread('../wavFileStore/twister_44kHz');
8
%  MAP1_14(inputSignal, FS, -1, 'Normal', 'probability', [])
9
%
10
% All arguments are mandatory.
11
%
12
%  BFlist is a vector of BFs but can be '-1' to allow MAPparams to choose
13
%  MAPparamsName='Normal';          % source of model parameters
14
%  AN_spikesOrProbability='spikes'; % or 'probability'
15
%  paramChanges is a cell array of strings that can be used to make last
16
%   minute parameter changes, e.g., to simulate OHC loss
17
%  e.g.  paramChanges{1}= 'DRNLParams.a=0;'; % disable OHCs
18
%  e.g.  paramchanges={};                    % no changes
19
% The model parameters are established in the MAPparams<***> file
20
%  and stored as global
21

  
22
restorePath=path;
23
addpath (['..' filesep 'parameterStore'])
24

  
25
global OMEParams DRNLParams IHC_cilia_RPParams IHCpreSynapseParams
26
global AN_IHCsynapseParams MacGregorParams MacGregorMultiParams
27

  
28
% All of the results of this function are stored as global
29
global dt ANdt  savedBFlist saveAN_spikesOrProbability saveMAPparamsName...
30
    savedInputSignal OMEextEarPressure TMoutput OMEoutput ARattenuation ...
31
    DRNLoutput IHC_cilia_output IHCrestingCiliaCond IHCrestingV...
32
    IHCoutput ANprobRateOutput ANoutput savePavailable ANtauCas  ...
33
    CNtauGk CNoutput  ICoutput ICmembraneOutput ICfiberTypeRates ...
34
    MOCattenuation
35

  
36
% Normally only ICoutput(logical spike matrix) or ANprobRateOutput will be
37
% needed by the user; so the following will suffice
38
%   global ANdt ICoutput ANprobRateOutput
39

  
40
% Note that sampleRate has not changed from the original function call and
41
%  ANprobRateOutput is sampled at this rate
42
% However ANoutput, CNoutput and IC output are stored as logical
43
%  'spike' matrices using a lower sample rate (see ANdt).
44

  
45
% When AN_spikesOrProbability is set to probability,
46
%  no spike matrices are computed.
47
% When AN_spikesOrProbability is set to 'spikes',
48
%  no probability output is computed
49

  
50
% Efferent control variables are ARattenuation and MOCattenuation
51
%  These are scalars between 1 (no attenuation) and 0.
52
%  They are represented with dt=1/sampleRate (not ANdt)
53
%  They are computed using either AN probability rate output
54
%   or IC (spikes) output as approrpriate.
55
% AR is computed using across channel activity
56
% MOC is computed on a within-channel basis.
57

  
58
if nargin<1
59
    error(' MAP1_14 is not a script but a function that must be called')
60
end
61

  
62
if nargin<6
63
    paramChanges=[];
64
end
65
% Read parameters from MAPparams<***> file in 'parameterStore' folder
66
% Beware, 'BFlist=-1' is a legitimate argument for MAPparams<>
67
%  It means that the calling program allows MAPparams to specify the list
68
cmd=['method=MAPparams' MAPparamsName ...
69
    '(BFlist, sampleRate, 0, paramChanges);'];
70
eval(cmd);
71
BFlist=DRNLParams.nonlinCFs;
72

  
73
% save as global for later plotting if required
74
savedBFlist=BFlist;
75
saveAN_spikesOrProbability=AN_spikesOrProbability;
76
saveMAPparamsName=MAPparamsName;
77

  
78
dt=1/sampleRate;
79
duration=length(inputSignal)/sampleRate;
80
% segmentDuration is specified in parameter file (must be >efferent delay)
81
segmentDuration=method.segmentDuration;
82
segmentLength=round(segmentDuration/ dt);
83
segmentTime=dt*(1:segmentLength); % used in debugging plots
84

  
85
% all spiking activity is computed using longer epochs
86
ANspeedUpFactor=AN_IHCsynapseParams.ANspeedUpFactor;  % e.g.5 times
87

  
88
% inputSignal must be  row vector
89
[r c]=size(inputSignal);
90
if r>c, inputSignal=inputSignal'; end       % transpose
91
% ignore stereo signals
92
inputSignal=inputSignal(1,:);               % drop any second channel
93
savedInputSignal=inputSignal;
94

  
95
% Segment the signal
96
% The sgment length is given but the signal length must be adjusted to be a
97
% multiple of both the segment length and the reduced segmentlength
98
[nSignalRows signalLength]=size(inputSignal);
99
segmentLength=ceil(segmentLength/ANspeedUpFactor)*ANspeedUpFactor;
100
% Make the signal length a whole multiple of the segment length
101
nSignalSegments=ceil(signalLength/segmentLength);
102
padSize=nSignalSegments*segmentLength-signalLength;
103
pad=zeros(nSignalRows,padSize);
104
inputSignal=[inputSignal pad];
105
[ignore signalLength]=size(inputSignal);
106

  
107
% AN (spikes) is computed at a lower sample rate when spikes required
108
%  so it has a reduced segment length (see 'ANspeeUpFactor' above)
109
% AN CN and IC all use this sample interval
110
ANdt=dt*ANspeedUpFactor;
111
reducedSegmentLength=round(segmentLength/ANspeedUpFactor);
112
reducedSignalLength= round(signalLength/ANspeedUpFactor);
113

  
114
%% Initialise with respect to each stage before computing
115
%  by allocating memory,
116
%  by computing constants
117
%  by establishing easy to read variable names
118
% The computations are made in segments and boundary conditions must
119
%  be established and stored. These are found in variables with
120
%  'boundary' or 'bndry' in the name
121

  
122
%% OME ---
123
% external ear resonances
124
OMEexternalResonanceFilters=OMEParams.externalResonanceFilters;
125
[nOMEExtFilters c]=size(OMEexternalResonanceFilters);
126
% details of external (outer ear) resonances
127
OMEgaindBs=OMEexternalResonanceFilters(:,1);
128
OMEgainScalars=10.^(OMEgaindBs/20);
129
OMEfilterOrder=OMEexternalResonanceFilters(:,2);
130
OMElowerCutOff=OMEexternalResonanceFilters(:,3);
131
OMEupperCutOff=OMEexternalResonanceFilters(:,4);
132
% external resonance coefficients
133
ExtFilter_b=cell(nOMEExtFilters,1);
134
ExtFilter_a=cell(nOMEExtFilters,1);
135
for idx=1:nOMEExtFilters
136
    Nyquist=sampleRate/2;
137
    [b, a] = butter(OMEfilterOrder(idx), ...
138
        [OMElowerCutOff(idx) OMEupperCutOff(idx)]...
139
        /Nyquist);
140
    ExtFilter_b{idx}=b;
141
    ExtFilter_a{idx}=a;
142
end
143
OMEExtFilterBndry=cell(2,1);
144
OMEextEarPressure=zeros(1,signalLength); % pressure at tympanic membrane
145

  
146
% pressure to velocity conversion using smoothing filter (50 Hz cutoff)
147
tau=1/(2*pi*50);
148
a1=dt/tau-1; a0=1;
149
b0=1+ a1;
150
TMdisp_b=b0; TMdisp_a=[a0 a1];
151
% figure(9), freqz(TMdisp_b, TMdisp_a)
152
OME_TMdisplacementBndry=[];
153

  
154
% OME high pass (simulates poor low frequency stapes response)
155
OMEhighPassHighCutOff=OMEParams.OMEstapesLPcutoff;
156
Nyquist=sampleRate/2;
157
[stapesDisp_b,stapesDisp_a] = butter(1, OMEhighPassHighCutOff/Nyquist, 'high');
158
% figure(10), freqz(stapesDisp_b, stapesDisp_a)
159

  
160
OMEhighPassBndry=[];
161

  
162
% OMEampStapes might be reducdant (use OMEParams.stapesScalar)
163
stapesScalar= OMEParams.stapesScalar;
164

  
165
% Acoustic reflex
166
efferentDelayPts=round(OMEParams.ARdelay/dt);
167
% smoothing filter
168
a1=dt/OMEParams.ARtau-1; a0=1;
169
b0=1+ a1;
170
ARfilt_b=b0; ARfilt_a=[a0 a1];
171

  
172
ARattenuation=ones(1,signalLength);
173
ARrateThreshold=OMEParams.ARrateThreshold; % may not be used
174
ARrateToAttenuationFactor=OMEParams.rateToAttenuationFactor;
175
ARrateToAttenuationFactorProb=OMEParams.rateToAttenuationFactorProb;
176
ARboundary=[];
177
ARboundaryProb=0;
178

  
179
% save complete OME record (stapes displacement)
180
OMEoutput=zeros(1,signalLength);
181
TMoutput=zeros(1,signalLength);
182

  
183
%% BM ---
184
% BM is represented as a list of locations identified by BF
185
DRNL_BFs=BFlist;
186
nBFs= length(DRNL_BFs);
187

  
188
% DRNLchannelParameters=DRNLParams.channelParameters;
189
DRNLresponse= zeros(nBFs, segmentLength);
190

  
191
MOCrateToAttenuationFactor=DRNLParams.rateToAttenuationFactor;
192
rateToAttenuationFactorProb=DRNLParams.rateToAttenuationFactorProb;
193
MOCrateThresholdProb=DRNLParams.MOCrateThresholdProb;
194

  
195
% smoothing filter for MOC
196
a1=dt/DRNLParams.MOCtau-1; a0=1;
197
b0=1+ a1;
198
MOCfilt_b=b0; MOCfilt_a=[a0 a1];
199
% figure(9), freqz(stapesDisp_b, stapesDisp_a)
200
MOCboundary=cell(nBFs,1);
201
MOCprobBoundary=cell(nBFs,1);
202

  
203
MOCattSegment=zeros(nBFs,reducedSegmentLength);
204
MOCattenuation=ones(nBFs,signalLength);
205

  
206
% if DRNLParams.a>0
207
%     DRNLcompressionThreshold=10^((1/(1-DRNLParams.c))* ...
208
%     log10(DRNLParams.b/DRNLParams.a));
209
% else
210
%     DRNLcompressionThreshold=inf;
211
% end
212
DRNLcompressionThreshold=DRNLParams.cTh;
213
DRNLlinearOrder= DRNLParams.linOrder;
214
DRNLnonlinearOrder= DRNLParams.nonlinOrder;
215

  
216
DRNLa=DRNLParams.a;
217
DRNLb=DRNLParams.b;
218
DRNLc=DRNLParams.c;
219
linGAIN=DRNLParams.g;
220
%
221
% gammatone filter coefficients for linear pathway
222
bw=DRNLParams.linBWs';
223
phi = 2 * pi * bw * dt;
224
cf=DRNLParams.linCFs';
225
theta = 2 * pi * cf * dt;
226
cos_theta = cos(theta);
227
sin_theta = sin(theta);
228
alpha = -exp(-phi).* cos_theta;
229
b0 = ones(nBFs,1);
230
b1 = 2 * alpha;
231
b2 = exp(-2 * phi);
232
z1 = (1 + alpha .* cos_theta) - (alpha .* sin_theta) * i;
233
z2 = (1 + b1 .* cos_theta) - (b1 .* sin_theta) * i;
234
z3 = (b2 .* cos(2 * theta)) - (b2 .* sin(2 * theta)) * i;
235
tf = (z2 + z3) ./ z1;
236
a0 = abs(tf);
237
a1 = alpha .* a0;
238
GTlin_a = [b0, b1, b2];
239
GTlin_b = [a0, a1];
240
GTlinOrder=DRNLlinearOrder;
241
GTlinBdry=cell(nBFs,GTlinOrder);
242

  
243
% nonlinear gammatone filter coefficients 
244
bw=DRNLParams.nlBWs';
245
phi = 2 * pi * bw * dt;
246
cf=DRNLParams.nonlinCFs';
247
theta = 2 * pi * cf * dt;
248
cos_theta = cos(theta);
249
sin_theta = sin(theta);
250
alpha = -exp(-phi).* cos_theta;
251
b0 = ones(nBFs,1);
252
b1 = 2 * alpha;
253
b2 = exp(-2 * phi);
254
z1 = (1 + alpha .* cos_theta) - (alpha .* sin_theta) * i;
255
z2 = (1 + b1 .* cos_theta) - (b1 .* sin_theta) * i;
256
z3 = (b2 .* cos(2 * theta)) - (b2 .* sin(2 * theta)) * i;
257
tf = (z2 + z3) ./ z1;
258
a0 = abs(tf);
259
a1 = alpha .* a0;
260
GTnonlin_a = [b0, b1, b2];
261
GTnonlin_b = [a0, a1];
262
GTnonlinOrder=DRNLnonlinearOrder;
263
GTnonlinBdry1=cell(nBFs, GTnonlinOrder);
264
GTnonlinBdry2=cell(nBFs, GTnonlinOrder);
265

  
266
% complete BM record (BM displacement)
267
DRNLoutput=zeros(nBFs, signalLength);
268

  
269

  
270
%% IHC ---
271
% IHC cilia activity and receptor potential
272
% viscous coupling between BM and stereocilia displacement
273
% Nyquist=sampleRate/2;
274
% IHCcutoff=1/(2*pi*IHC_cilia_RPParams.tc);
275
% [IHCciliaFilter_b,IHCciliaFilter_a]=...
276
%     butter(1, IHCcutoff/Nyquist, 'high');
277
a1=dt/IHC_cilia_RPParams.tc-1; a0=1;
278
b0=1+ a1;
279
% high pass (i.e. low pass reversed)
280
IHCciliaFilter_b=[a0 a1]; IHCciliaFilter_a=b0;
281
% figure(9), freqz(IHCciliaFilter_b, IHCciliaFilter_a)
282

  
283
IHCciliaBndry=cell(nBFs,1);
284

  
285
% IHC apical conductance (Boltzman function)
286
IHC_C= IHC_cilia_RPParams.C;
287
IHCu0= IHC_cilia_RPParams.u0;
288
IHCu1= IHC_cilia_RPParams.u1;
289
IHCs0= IHC_cilia_RPParams.s0;
290
IHCs1= IHC_cilia_RPParams.s1;
291
IHCGmax= IHC_cilia_RPParams.Gmax;
292
IHCGa= IHC_cilia_RPParams.Ga; % (leakage)
293

  
294
IHCGu0 = IHCGa+IHCGmax./(1+exp(IHCu0/IHCs0).*(1+exp(IHCu1/IHCs1)));
295
IHCrestingCiliaCond=IHCGu0;
296

  
297
% Receptor potential
298
IHC_Cab= IHC_cilia_RPParams.Cab;
299
IHC_Gk= IHC_cilia_RPParams.Gk;
300
IHC_Et= IHC_cilia_RPParams.Et;
301
IHC_Ek= IHC_cilia_RPParams.Ek;
302
IHC_Ekp= IHC_Ek+IHC_Et*IHC_cilia_RPParams.Rpc;
303

  
304
IHCrestingV= (IHC_Gk*IHC_Ekp+IHCGu0*IHC_Et)/(IHCGu0+IHC_Gk);
305

  
306
IHC_Vnow= IHCrestingV*ones(nBFs,1); % initial voltage
307
IHC_RP= zeros(nBFs,segmentLength);
308

  
309
% complete record of IHC receptor potential (V)
310
IHCciliaDisplacement= zeros(nBFs,segmentLength);
311
IHCoutput= zeros(nBFs,signalLength);
312
IHC_cilia_output= zeros(nBFs,signalLength);
313

  
314

  
315
%% pre-synapse ---
316
% Each BF is replicated using a different fiber type to make a 'channel'
317
% The number of channels is nBFs x nANfiberTypes
318
% Fiber types are specified in terms of tauCa
319
nANfiberTypes= length(IHCpreSynapseParams.tauCa);
320
ANtauCas= IHCpreSynapseParams.tauCa;
321
nANchannels= nANfiberTypes*nBFs;
322
synapticCa= zeros(nANchannels,segmentLength);
323

  
324
% Calcium control (more calcium, greater release rate)
325
ECa=IHCpreSynapseParams.ECa;
326
gamma=IHCpreSynapseParams.gamma;
327
beta=IHCpreSynapseParams.beta;
328
tauM=IHCpreSynapseParams.tauM;
329
mICa=zeros(nANchannels,segmentLength);
330
GmaxCa=IHCpreSynapseParams.GmaxCa;
331
synapse_z= IHCpreSynapseParams.z;
332
synapse_power=IHCpreSynapseParams.power;
333

  
334
% tauCa vector is established across channels to allow vectorization
335
%  (one tauCa per channel). Do not confuse with ANtauCas (one pre fiber type)
336
tauCa=repmat(ANtauCas, nBFs,1);
337
tauCa=reshape(tauCa, nANchannels, 1);
338

  
339
% presynapse startup values (vectors, length:nANchannels)
340
% proportion (0 - 1) of Ca channels open at IHCrestingV
341
mICaCurrent=((1+beta^-1 * exp(-gamma*IHCrestingV))^-1)...
342
    *ones(nBFs*nANfiberTypes,1);
343
% corresponding startup currents
344
ICaCurrent= (GmaxCa*mICaCurrent.^3) * (IHCrestingV-ECa);
345
CaCurrent= ICaCurrent.*tauCa;
346

  
347
% vesicle release rate at startup (one per channel)
348
% kt0 is used only at initialisation
349
kt0= -synapse_z * CaCurrent.^synapse_power;
350

  
351

  
352
%% AN ---
353
% each row of the AN matrices represents one AN fiber
354
% The results computed either for probabiities *or* for spikes (not both)
355
% Spikes are necessary if CN and IC are to be computed
356
nFibersPerChannel= AN_IHCsynapseParams.numFibers;
357
nANfibers= nANchannels*nFibersPerChannel;
358
AN_refractory_period= AN_IHCsynapseParams.refractory_period;
359

  
360
y=AN_IHCsynapseParams.y;
361
l=AN_IHCsynapseParams.l;
362
x=AN_IHCsynapseParams.x;
363
r=AN_IHCsynapseParams.r;
364
M=round(AN_IHCsynapseParams.M);
365

  
366
% probability            (NB initial 'P' on everything)
367
PAN_ydt = repmat(AN_IHCsynapseParams.y*dt, nANchannels,1);
368
PAN_ldt = repmat(AN_IHCsynapseParams.l*dt, nANchannels,1);
369
PAN_xdt = repmat(AN_IHCsynapseParams.x*dt, nANchannels,1);
370
PAN_rdt = repmat(AN_IHCsynapseParams.r*dt, nANchannels,1);
371
PAN_rdt_plus_ldt = PAN_rdt + PAN_ldt;
372
PAN_M=round(AN_IHCsynapseParams.M);
373

  
374
% compute starting values
375
Pcleft    = kt0* y* M ./ (y*(l+r)+ kt0* l);
376
Pavailable    = Pcleft*(l+r)./kt0;
377
Preprocess    = Pcleft*r/x; % canbe fractional
378

  
379
ANprobability=zeros(nANchannels,segmentLength);
380
ANprobRateOutput=zeros(nANchannels,signalLength);
381
lengthAbsRefractoryP= round(AN_refractory_period/dt);
382
cumANnotFireProb=ones(nANchannels,signalLength);
383
% special variables for monitoring synaptic cleft (specialists only)
384
savePavailableSeg=zeros(nANchannels,segmentLength);
385
savePavailable=zeros(nANchannels,signalLength);
386

  
387
% spikes     % !  !  !    ! !        !   !  !
388
lengthAbsRefractory= round(AN_refractory_period/ANdt);
389

  
390
AN_ydt= repmat(AN_IHCsynapseParams.y*ANdt, nANfibers,1);
391
AN_ldt= repmat(AN_IHCsynapseParams.l*ANdt, nANfibers,1);
392
AN_xdt= repmat(AN_IHCsynapseParams.x*ANdt, nANfibers,1);
393
AN_rdt= repmat(AN_IHCsynapseParams.r*ANdt, nANfibers,1);
394
AN_rdt_plus_ldt= AN_rdt + AN_ldt;
395
AN_M= round(AN_IHCsynapseParams.M);
396

  
397
% kt0  is initial release rate
398
% Establish as a vector (length=channel x number of fibers)
399
kt0= repmat(kt0', nFibersPerChannel, 1);
400
kt0=reshape(kt0, nANfibers,1);
401

  
402
% starting values for reservoirs
403
AN_cleft    = kt0* y* M ./ (y*(l+r)+ kt0* l);
404
AN_available    = round(AN_cleft*(l+r)./kt0); %must be integer
405
AN_reprocess    = AN_cleft*r/x;
406

  
407
% output is in a logical array spikes = 1/ 0.
408
ANspikes= false(nANfibers,reducedSegmentLength);
409
ANoutput= false(nANfibers,reducedSignalLength);
410

  
411

  
412
%% CN (first brain stem nucleus - could be any subdivision of CN)
413
% Input to a CN neuorn is a random selection of AN fibers within a channel
414
%  The number of AN fibers used is ANfibersFanInToCN
415
% CNtauGk (Potassium time constant) determines the rate of firing of
416
%  the unit when driven hard by a DC input (not normally >350 sp/s)
417
% If there is more than one value, everything is replicated accordingly
418

  
419
ANavailableFibersPerChan=AN_IHCsynapseParams.numFibers;
420
ANfibersFanInToCN=MacGregorMultiParams.fibersPerNeuron;
421

  
422
CNtauGk=MacGregorMultiParams.tauGk; % row vector of CN types (by tauGk)
423
nCNtauGk=length(CNtauGk);
424

  
425
% the total number of 'channels' is now greater
426
% 'channel' is defined as collections of units with the same parameters
427
%  i.e. same BF, same ANtau, same CNtauGk
428
nCNchannels=nANchannels*nCNtauGk;
429

  
430
nCNneuronsPerChannel=MacGregorMultiParams.nNeuronsPerBF;
431
tauGk=repmat(CNtauGk, nCNneuronsPerChannel,1);
432
tauGk=reshape(tauGk,nCNneuronsPerChannel*nCNtauGk,1);
433

  
434
% Now the number of neurons has been increased
435
nCNneurons=nCNneuronsPerChannel*nCNchannels;
436
CNmembranePotential=zeros(nCNneurons,reducedSegmentLength);
437

  
438
% establish which ANfibers (by name) feed into which CN nuerons
439
CNinputfiberLists=zeros(nANchannels*nCNneuronsPerChannel, ANfibersFanInToCN);
440
unitNo=1;
441
for ch=1:nANchannels
442
    % Each channel contains a number of units =length(listOfFanInValues)
443
    for idx=1:nCNneuronsPerChannel
444
        for idx2=1:nCNtauGk
445
            fibersUsed=(ch-1)*ANavailableFibersPerChan + ...
446
                ceil(rand(1,ANfibersFanInToCN)* ANavailableFibersPerChan);
447
            CNinputfiberLists(unitNo,:)=fibersUsed;
448
            unitNo=unitNo+1;
449
        end
450
    end
451
end
452

  
453
% input to CN units
454
AN_PSTH=zeros(nCNneurons,reducedSegmentLength);
455

  
456
% Generate CNalphaFunction function
457
%  by which spikes are converted to post-synaptic currents
458
CNdendriteLPfreq= MacGregorMultiParams.dendriteLPfreq;
459
CNcurrentPerSpike=MacGregorMultiParams.currentPerSpike;
460
CNspikeToCurrentTau=1/(2*pi*CNdendriteLPfreq);
461
t=ANdt:ANdt:5*CNspikeToCurrentTau;
462
CNalphaFunction= (1 / ...
463
    CNspikeToCurrentTau)*t.*exp(-t /CNspikeToCurrentTau);
464
CNalphaFunction=CNalphaFunction*CNcurrentPerSpike;
465

  
466
% figure(98), plot(t,CNalphaFunction)
467
% working memory for implementing convolution
468

  
469
CNcurrentTemp=...
470
    zeros(nCNneurons,reducedSegmentLength+length(CNalphaFunction)-1);
471
% trailing alphas are parts of humps carried forward to the next segment
472
CNtrailingAlphas=zeros(nCNneurons,length(CNalphaFunction));
473

  
474
CN_tauM=MacGregorMultiParams.tauM;
475
CN_tauTh=MacGregorMultiParams.tauTh;
476
CN_cap=MacGregorMultiParams.Cap;
477
CN_c=MacGregorMultiParams.c;
478
CN_b=MacGregorMultiParams.dGkSpike;
479
CN_Ek=MacGregorMultiParams.Ek;
480
CN_Eb= MacGregorMultiParams.Eb;
481
CN_Er=MacGregorMultiParams.Er;
482
CN_Th0= MacGregorMultiParams.Th0;
483
CN_E= zeros(nCNneurons,1);
484
CN_Gk= zeros(nCNneurons,1);
485
CN_Th= MacGregorMultiParams.Th0*ones(nCNneurons,1);
486
CN_Eb=CN_Eb.*ones(nCNneurons,1);
487
CN_Er=CN_Er.*ones(nCNneurons,1);
488
CNtimeSinceLastSpike=zeros(nCNneurons,1);
489
% tauGk is the main distinction between neurons
490
%  in fact they are all the same in the standard model
491
tauGk=repmat(tauGk,nANchannels,1);
492

  
493
CNoutput=false(nCNneurons,reducedSignalLength);
494

  
495

  
496
%% MacGregor (IC - second nucleus) --------
497
nICcells=nANchannels*nCNtauGk;  % one cell per channel
498
CN_PSTH=zeros(nICcells ,reducedSegmentLength);
499

  
500
% ICspikeWidth=0.00015;   % this may need revisiting
501
% epochsPerSpike=round(ICspikeWidth/ANdt);
502
% if epochsPerSpike<1
503
%     error(['MacGregorMulti: sample rate too low to support ' ...
504
%         num2str(ICspikeWidth*1e6) '  microsec spikes']);
505
% end
506

  
507
% short names
508
IC_tauM=MacGregorParams.tauM;
509
IC_tauGk=MacGregorParams.tauGk;
510
IC_tauTh=MacGregorParams.tauTh;
511
IC_cap=MacGregorParams.Cap;
512
IC_c=MacGregorParams.c;
513
IC_b=MacGregorParams.dGkSpike;
514
IC_Th0=MacGregorParams.Th0;
515
IC_Ek=MacGregorParams.Ek;
516
IC_Eb= MacGregorParams.Eb;
517
IC_Er=MacGregorParams.Er;
518

  
519
IC_E=zeros(nICcells,1);
520
IC_Gk=zeros(nICcells,1);
521
IC_Th=IC_Th0*ones(nICcells,1);
522

  
523
% Dendritic filtering, all spikes are replaced by CNalphaFunction functions
524
ICdendriteLPfreq= MacGregorParams.dendriteLPfreq;
525
ICcurrentPerSpike=MacGregorParams.currentPerSpike;
526
ICspikeToCurrentTau=1/(2*pi*ICdendriteLPfreq);
527
t=ANdt:ANdt:3*ICspikeToCurrentTau;
528
IC_CNalphaFunction= (ICcurrentPerSpike / ...
529
    ICspikeToCurrentTau)*t.*exp(-t / ICspikeToCurrentTau);
530
% figure(98), plot(t,IC_CNalphaFunction)
531

  
532
% working space for implementing alpha function
533
ICcurrentTemp=...
534
    zeros(nICcells,reducedSegmentLength+length(IC_CNalphaFunction)-1);
535
ICtrailingAlphas=zeros(nICcells, length(IC_CNalphaFunction));
536

  
537
ICfiberTypeRates=zeros(nANfiberTypes,reducedSignalLength);
538
ICoutput=false(nICcells,reducedSignalLength);
539

  
540
ICmembranePotential=zeros(nICcells,reducedSegmentLength);
541
ICmembraneOutput=zeros(nICcells,signalLength);
542

  
543

  
544
%% Main program %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%
545

  
546
%  Compute the entire model for each segment
547
segmentStartPTR=1;
548
reducedSegmentPTR=1; % when sampling rate is reduced
549
while segmentStartPTR<signalLength
550
    segmentEndPTR=segmentStartPTR+segmentLength-1;
551
    % shorter segments after speed up.
552
    shorterSegmentEndPTR=reducedSegmentPTR+reducedSegmentLength-1;
553

  
554
    inputPressureSegment=inputSignal...
555
        (:,segmentStartPTR:segmentStartPTR+segmentLength-1);
556

  
557
    % segment debugging plots
558
    % figure(98)
559
    % plot(segmentTime,inputPressureSegment), title('signalSegment')
560

  
561

  
562
    % OME ----------------------
563

  
564
    % OME Stage 1: external resonances. Add to inputSignal pressure wave
565
    y=inputPressureSegment;
566
    for n=1:nOMEExtFilters
567
        % any number of resonances can be used
568
        [x  OMEExtFilterBndry{n}] = ...
569
            filter(ExtFilter_b{n},ExtFilter_a{n},...
570
            inputPressureSegment, OMEExtFilterBndry{n});
571
        x= x* OMEgainScalars(n);
572
        % This is a parallel resonance so add it
573
        y=y+x;
574
    end
575
    inputPressureSegment=y;
576
    OMEextEarPressure(segmentStartPTR:segmentEndPTR)= inputPressureSegment;
577
    
578
    % OME stage 2: convert input pressure (velocity) to
579
    %  tympanic membrane(TM) displacement using low pass filter
580
    [TMdisplacementSegment  OME_TMdisplacementBndry] = ...
581
        filter(TMdisp_b,TMdisp_a,inputPressureSegment, ...
582
        OME_TMdisplacementBndry);
583
    % and save it
584
    TMoutput(segmentStartPTR:segmentEndPTR)= TMdisplacementSegment;
585

  
586
    % OME stage 3: middle ear high pass effect to simulate stapes inertia
587
    [stapesDisplacement  OMEhighPassBndry] = ...
588
        filter(stapesDisp_b,stapesDisp_a,TMdisplacementSegment, ...
589
        OMEhighPassBndry);
590

  
591
    % OME stage 4:  apply stapes scalar
592
    stapesDisplacement=stapesDisplacement*stapesScalar;
593

  
594
    % OME stage 5:    acoustic reflex stapes attenuation
595
    %  Attenuate the TM response using feedback from LSR fiber activity
596
    if segmentStartPTR>efferentDelayPts
597
        stapesDisplacement= stapesDisplacement.*...
598
            ARattenuation(segmentStartPTR-efferentDelayPts:...
599
            segmentEndPTR-efferentDelayPts);
600
    end
601

  
602
    % segment debugging plots
603
    % figure(98)
604
    % plot(segmentTime, stapesDisplacement), title ('stapesDisplacement')
605

  
606
    % and save
607
    OMEoutput(segmentStartPTR:segmentEndPTR)= stapesDisplacement;
608

  
609

  
610
    %% BM ------------------------------
611
    % Each location is computed separately
612
    for BFno=1:nBFs
613

  
614
        %            *linear* path
615
        linOutput = stapesDisplacement * linGAIN;  % linear gain
616
       
617
        for order = 1 : GTlinOrder
618
            [linOutput GTlinBdry{BFno,order}] = ...
619
                filter(GTlin_b(BFno,:), GTlin_a(BFno,:), linOutput, ...
620
                GTlinBdry{BFno,order});
621
        end
622

  
623
        %           *nonLinear* path
624
        % efferent attenuation (0 <> 1)
625
        if segmentStartPTR>efferentDelayPts
626
            MOC=MOCattenuation(BFno, segmentStartPTR-efferentDelayPts:...
627
                segmentEndPTR-efferentDelayPts);
628
        else    % no MOC available yet
629
            MOC=ones(1, segmentLength);
630
        end
631
        % apply MOC to nonlinear input function       
632
        nonlinOutput=stapesDisplacement.* MOC;
633

  
634
        %       first gammatone filter (nonlin path)
635
        for order = 1 : GTnonlinOrder
636
            [nonlinOutput GTnonlinBdry1{BFno,order}] = ...
637
                filter(GTnonlin_b(BFno,:), GTnonlin_a(BFno,:), ...
638
                nonlinOutput, GTnonlinBdry1{BFno,order});
639
        end
640
        
641
%         %    original   broken stick instantaneous compression
642
%         y= nonlinOutput.* DRNLa;  % linear section.
643
%         % compress parts of the signal above the compression threshold
644
%         abs_x = abs(nonlinOutput);
645
%         idx=find(abs_x>DRNLcompressionThreshold);
646
%         if ~isempty(idx)>0
647
%             y(idx)=sign(y(idx)).* (DRNLb*abs_x(idx).^DRNLc);
648
%         end
649
%         nonlinOutput=y;
650

  
651
        
652
        %   new broken stick instantaneous compression
653
        y= nonlinOutput.* DRNLa;  % linear section attenuation/gain.
654
        % compress parts of the signal above the compression threshold
655
%         holdY=y;
656
        abs_y = abs(y);
657
        idx=find(abs_y>DRNLcompressionThreshold);
658
        if ~isempty(idx)>0
659
%             y(idx)=sign(y(idx)).* (DRNLcompressionThreshold + ...
660
%                 (abs_y(idx)-DRNLcompressionThreshold).^DRNLc);
661
            y(idx)=sign(y(idx)).* (DRNLcompressionThreshold + ...
662
                (abs_y(idx)-DRNLcompressionThreshold)*DRNLc);
663
        end
664
        nonlinOutput=y;
665
       
666
% % Boltzmann compression
667
% y=(nonlinOutput * DRNLa*100000);
668
% holdY=y;
669
% y=abs(y);
670
% s=10; u=0.0;
671
% x=1./(1+exp(-(y-u)/s))-0.5;
672
% nonlinOutput=sign(nonlinOutput).*x/10000;
673

  
674

  
675
%         if segmentStartPTR==10*segmentLength+1
676
%             figure(90)
677
%         plot(holdY,'b'), hold on
678
%         plot(nonlinOutput, 'r'), hold off
679
%         ylim([-1e-5 1e-5])
680
%         pause(1)
681
%         end
682

  
683
        %       second filter removes distortion products
684
        for order = 1 : GTnonlinOrder
685
            [ nonlinOutput GTnonlinBdry2{BFno,order}] = ...
686
                filter(GTnonlin_b(BFno,:), GTnonlin_a(BFno,:), ...
687
                nonlinOutput, GTnonlinBdry2{BFno,order});
688
        end
689

  
690
        %  combine the two paths to give the DRNL displacement
691
        DRNLresponse(BFno,:)=linOutput+nonlinOutput;
692
%         disp(num2str(max(linOutput)))
693
    end % BF
694

  
695
    % segment debugging plots
696
    % figure(98)
697
    %     if size(DRNLresponse,1)>3
698
    %         imagesc(DRNLresponse)  % matrix display
699
    %         title('DRNLresponse'); % single or double channel response
700
    %     else
701
    %         plot(segmentTime, DRNLresponse)
702
    %     end
703

  
704
    % and save it
705
    DRNLoutput(:, segmentStartPTR:segmentEndPTR)= DRNLresponse;
706

  
707

  
708
    %% IHC ------------------------------------
709
    %  BM displacement to IHCciliaDisplacement is  a high-pass filter
710
    %   because of viscous coupling
711
    for idx=1:nBFs
712
        [IHCciliaDisplacement(idx,:)  IHCciliaBndry{idx}] = ...
713
            filter(IHCciliaFilter_b,IHCciliaFilter_a, ...
714
            DRNLresponse(idx,:), IHCciliaBndry{idx});
715
    end
716
    
717
    % apply scalar
718
    IHCciliaDisplacement=IHCciliaDisplacement* IHC_C;
719

  
720
    % and save it
721
    IHC_cilia_output(:,segmentStartPTR:segmentStartPTR+segmentLength-1)=...
722
        IHCciliaDisplacement;
723

  
724
    % compute apical conductance
725
    G=IHCGmax./(1+exp(-(IHCciliaDisplacement-IHCu0)/IHCs0).*...
726
        (1+exp(-(IHCciliaDisplacement-IHCu1)/IHCs1)));
727
    Gu=G + IHCGa;
728

  
729
    % Compute receptor potential
730
    for idx=1:segmentLength
731
        IHC_Vnow=IHC_Vnow+ (-Gu(:, idx).*(IHC_Vnow-IHC_Et)-...
732
            IHC_Gk*(IHC_Vnow-IHC_Ekp))*  dt/IHC_Cab;
733
        IHC_RP(:,idx)=IHC_Vnow;
734
    end
735

  
736
    % segment debugging plots
737
    %     if size(IHC_RP,1)>3
738
    %         surf(IHC_RP), shading interp, title('IHC_RP')
739
    %     else
740
    %         plot(segmentTime, IHC_RP)
741
    %     end
742

  
743
    % and save it
744
    IHCoutput(:, segmentStartPTR:segmentStartPTR+segmentLength-1)=IHC_RP;
745

  
746

  
747
    %% synapse -----------------------------
748
    % Compute the vesicle release rate for each fiber type at each BF
749
    % replicate IHC_RP for each fiber type
750
    Vsynapse=repmat(IHC_RP, nANfiberTypes,1);
751

  
752
    % look-up table of target fraction channels open for a given IHC_RP
753
    mICaINF=    1./( 1 + exp(-gamma  * Vsynapse)  /beta);
754
    % fraction of channel open - apply time constant
755
    for idx=1:segmentLength
756
        % mICaINF is the current 'target' value of mICa
757
        mICaCurrent=mICaCurrent+(mICaINF(:,idx)-mICaCurrent)*dt./tauM;
758
        mICa(:,idx)=mICaCurrent;
759
    end
760

  
761
    ICa=   (GmaxCa* mICa.^3) .* (Vsynapse- ECa);
762

  
763
    for idx=1:segmentLength
764
        CaCurrent=CaCurrent +  ICa(:,idx)*dt - CaCurrent*dt./tauCa;
765
        synapticCa(:,idx)=CaCurrent;
766
    end
767
    synapticCa=-synapticCa; % treat synapticCa as positive substance
768

  
769
    % NB vesicleReleaseRate is /s and is independent of dt
770
    vesicleReleaseRate = synapse_z * synapticCa.^synapse_power; % rate
771

  
772
    % segment debugging plots
773
    %     if size(vesicleReleaseRate,1)>3
774
    %         surf(vesicleReleaseRate), shading interp, title('vesicleReleaseRate')
775
    %     else
776
    %         plot(segmentTime, vesicleReleaseRate)
777
    %     end
778

  
779

  
780
    %% AN
781
    switch AN_spikesOrProbability
782
        case 'probability'
783
            % No refractory effect is applied
784
            for t = 1:segmentLength;
785
                M_Pq=PAN_M-Pavailable;
786
                M_Pq(M_Pq<0)=0;
787
                Preplenish = M_Pq .* PAN_ydt;
788
                Pejected = Pavailable.* vesicleReleaseRate(:,t)*dt;
789
                Preprocessed = M_Pq.*Preprocess.* PAN_xdt;
790

  
791
                ANprobability(:,t)= min(Pejected,1);
792
                reuptakeandlost= PAN_rdt_plus_ldt .* Pcleft;
793
                reuptake= PAN_rdt.* Pcleft;
794

  
795
                Pavailable= Pavailable+ Preplenish- Pejected+ Preprocessed;
796
                Pcleft= Pcleft + Pejected - reuptakeandlost;
797
                Preprocess= Preprocess + reuptake - Preprocessed;
798
                Pavailable(Pavailable<0)=0;
799
                savePavailableSeg(:,t)=Pavailable;    % synapse tracking
800
                
801
            end
802

  
803
            % and save it as *rate*
804
            ANrate=ANprobability/dt;
805
            ANprobRateOutput(:, segmentStartPTR:...
806
                segmentStartPTR+segmentLength-1)=  ANrate;
807
            % monitor synapse contents (only sometimes used)
808
            savePavailable(:, segmentStartPTR:segmentStartPTR+segmentLength-1)=...
809
                savePavailableSeg;
810
            
811
            %% Apply refractory effect
812
               % the probability of a spike's occurring in the preceding
813
               %  refractory window (t= tnow-refractory period to tnow-)
814
               %    pFired= 1 - II(1-p(t)),
815
               % we need a running account of cumProb=II(1-p(t))
816
               %   cumProb(t)= cumProb(t-1)*(1-p(t))/(1-p(t-refracPeriod))
817
               %   cumProb(0)=0
818
               %   pFired(t)= 1-cumProb(t)
819
               % This gives the fraction of firing events that must be 
820
               %  discounted because of a firing event in the refractory
821
               %  period
822
               %   p(t)= ANprobOutput(t) * pFired(t)
823
               % where ANprobOutput is the uncorrected firing probability
824
               %  based on vesicle release rate
825
               % NB this covers only the absoute refractory period
826
               % not the relative refractory period. To approximate this it
827
               % is necessary to extend the refractory period by 50%
828

  
829

  
830
                for t = segmentStartPTR:segmentEndPTR;
831
                    if t>1
832
                    ANprobRateOutput(:,t)= ANprobRateOutput(:,t)...
833
                        .* cumANnotFireProb(:,t-1);
834
                    end
835
                    % add recent and remove distant probabilities
836
                    refrac=round(lengthAbsRefractoryP * 1.5);
837
                    if t>refrac
838
                        cumANnotFireProb(:,t)= cumANnotFireProb(:,t-1)...
839
                            .*(1-ANprobRateOutput(:,t)*dt)...
840
                            ./(1-ANprobRateOutput(:,t-refrac)*dt);
841
                    end
842
                end
843
%                 figure(88), plot(cumANnotFireProb'), title('cumNotFire')
844
%                 figure(89), plot(ANprobRateOutput'), title('ANprobRateOutput')
845

  
846
            %% Estimate efferent effects. ARattenuation (0 <> 1)
847
            %  acoustic reflex
848
            [r c]=size(ANrate);
849
            if r>nBFs % Only if LSR fibers are computed
850
                ARAttSeg=mean(ANrate(1:nBFs,:),1); %LSR channels are 1:nBF
851
                % smooth
852
                [ARAttSeg, ARboundaryProb] = ...
853
                    filter(ARfilt_b, ARfilt_a, ARAttSeg, ARboundaryProb);
854
                ARAttSeg=ARAttSeg-ARrateThreshold;
855
                ARAttSeg(ARAttSeg<0)=0;   % prevent negative strengths
856
                ARattenuation(segmentStartPTR:segmentEndPTR)=...
857
                    (1-ARrateToAttenuationFactorProb.* ARAttSeg);
858
            end
859
            %             plot(ARattenuation)
860

  
861
            % MOC attenuation based on within-channel HSR fiber activity
862
            HSRbegins=nBFs*(nANfiberTypes-1)+1;
863
            rates=ANrate(HSRbegins:end,:);
864
            if rateToAttenuationFactorProb<0
865
                % negative factor implies a fixed attenuation
866
                MOCattenuation(:,segmentStartPTR:segmentEndPTR)= ...
867
                    ones(size(rates))* -rateToAttenuationFactorProb;
868
            else
869
                for idx=1:nBFs
870
                    [smoothedRates, MOCprobBoundary{idx}] = ...
871
                        filter(MOCfilt_b, MOCfilt_a, rates(idx,:), ...
872
                        MOCprobBoundary{idx});
873
                    smoothedRates=smoothedRates-MOCrateThresholdProb;
874
                    smoothedRates=max(smoothedRates, 0);
875
                    
876
                    x=(1- smoothedRates* rateToAttenuationFactorProb);
877
                    x=max(x, 10^(-30/20));
878
                    MOCattenuation(idx,segmentStartPTR:segmentEndPTR)= x;
879
                end
880
            end
881
            MOCattenuation(MOCattenuation<0)=0.001;
882

  
883
            %             plot(MOCattenuation)
884

  
885

  
886
        case 'spikes'
887
            ANtimeCount=0;
888
            % implement speed upt
889
            for t = ANspeedUpFactor:ANspeedUpFactor:segmentLength;
890
                ANtimeCount=ANtimeCount+1;
891
                % convert release rate to probabilities
892
                releaseProb=vesicleReleaseRate(:,t)*ANdt;
893
                % releaseProb is the release probability per channel
894
                %  but each channel has many synapses
895
                releaseProb=repmat(releaseProb',nFibersPerChannel,1);
896
                releaseProb=reshape(releaseProb, nFibersPerChannel*nANchannels,1);
897

  
898
                % AN_available=round(AN_available); % vesicles must be integer, (?needed)
899
                M_q=AN_M- AN_available;     % number of missing vesicles
900
                M_q(M_q<0)= 0;              % cannot be less than 0
901

  
902
                % AN_N1 converts probability to discrete events
903
                %   it considers each event that might occur
904
                %   (how many vesicles might be released)
905
                %   and returns a count of how many were released
906

  
907
                % slow line
908
%                 probabilities= 1-(1-releaseProb).^AN_available;
909
                probabilities= 1-intpow((1-releaseProb), AN_available);
910
                ejected= probabilities> rand(length(AN_available),1);
911

  
912
                reuptakeandlost = AN_rdt_plus_ldt .* AN_cleft;
913
                reuptake = AN_rdt.* AN_cleft;
914

  
915
                % slow line
916
%                 probabilities= 1-(1-AN_reprocess.*AN_xdt).^M_q;
917
                probabilities= 1-intpow((1-AN_reprocess.*AN_xdt), M_q);
918
                reprocessed= probabilities>rand(length(M_q),1);
919

  
920
                % slow line
921
%                 probabilities= 1-(1-AN_ydt).^M_q;
922
                 probabilities= 1-intpow((1-AN_ydt), M_q);
923

  
924
                replenish= probabilities>rand(length(M_q),1);
925

  
926
                AN_available = AN_available + replenish - ejected ...
927
                    + reprocessed;
928
                AN_cleft = AN_cleft + ejected - reuptakeandlost;
929
                AN_reprocess = AN_reprocess + reuptake - reprocessed;
930

  
931
                % ANspikes is logical record of vesicle release events>0
932
                ANspikes(:, ANtimeCount)= ejected;
933
            end % t
934

  
935
            % zero any events that are preceded by release events ...
936
            %  within the refractory period
937
            % The refractory period consist of two periods
938
            %  1) the absolute period where no spikes occur
939
            %  2) a relative period where a spike may occur. This relative
940
            %     period is realised as a variable length interval
941
            %     where the length is chosen at random
942
            %     (esentially a linear ramp up)
943

  
944
            % Andreas has a fix for this
945
            for t = 1:ANtimeCount-2*lengthAbsRefractory;
946
                % identify all spikes across fiber array at time (t)
947
                % idx is a list of channels where spikes occurred
948
                % ?? try sparse matrices?
949
                idx=find(ANspikes(:,t));
950
                for j=idx  % consider each spike
951
                    % specify variable refractory period
952
                    %  between abs and 2*abs refractory period
953
                    nPointsRefractory=lengthAbsRefractory+...
954
                        round(rand*lengthAbsRefractory);
955
                    % disable spike potential for refractory period
956
                    % set all values in this range to 0
957
                    ANspikes(j,t+1:t+nPointsRefractory)=0;
958
                end
959
            end  %t
960

  
961
            % segment debugging
962
            % plotInstructions.figureNo=98;
963
            % plotInstructions.displaydt=ANdt;
964
            %  plotInstructions.numPlots=1;
965
            %  plotInstructions.subPlotNo=1;
966
            % UTIL_plotMatrix(ANspikes, plotInstructions);
967

  
968
            % and save it. NB, AN is now on 'speedUp' time
969
            ANoutput(:, reducedSegmentPTR: shorterSegmentEndPTR)=ANspikes;
970

  
971

  
972
            %% CN Macgregor first neucleus -------------------------------
973
            % input is from AN so ANdt is used throughout
974
            % Each CNneuron has a unique set of input fibers selected
975
            %  at random from the available AN fibers (CNinputfiberLists)
976

  
977
            % Create the dendritic current for that neuron
978
            % First get input spikes to this neuron
979
            synapseNo=1;
980
            for ch=1:nCNchannels
981
                for idx=1:nCNneuronsPerChannel
982
                    % determine candidate fibers for this unit
983
                    fibersUsed=CNinputfiberLists(synapseNo,:);
984
                    % ANpsth has a bin width of ANdt
985
                    %  (just a simple sum across fibers)
986
                    AN_PSTH(synapseNo,:) = ...
987
                        sum(ANspikes(fibersUsed,:), 1);
988
                    synapseNo=synapseNo+1;
989
                end
990
            end
991

  
992
            % One alpha function per spike
993
            [alphaRows alphaCols]=size(CNtrailingAlphas);
994

  
995
            for unitNo=1:nCNneurons
996
                CNcurrentTemp(unitNo,:)= ...
997
                    conv2(AN_PSTH(unitNo,:),CNalphaFunction);
998
            end
999
%             disp(['sum(AN_PSTH)= ' num2str(sum(AN_PSTH(1,:)))])
1000
            % add post-synaptic current  left over from previous segment
1001
            CNcurrentTemp(:,1:alphaCols)=...
1002
                CNcurrentTemp(:,1:alphaCols)+ CNtrailingAlphas;
1003

  
1004
            % take post-synaptic current for this segment
1005
            CNcurrentInput= CNcurrentTemp(:, 1:reducedSegmentLength);
1006
%                 disp(['mean(CNcurrentInput)= ' num2str(mean(CNcurrentInput(1,:)))])
1007

  
1008
            % trailingalphas are the ends of the alpha functions that
1009
            % spill over into the next segment
1010
            CNtrailingAlphas= ...
1011
                CNcurrentTemp(:, reducedSegmentLength+1:end);
1012

  
1013
            if CN_c>0
1014
                % variable threshold condition (slow)
1015
                for t=1:reducedSegmentLength
1016
                    CNtimeSinceLastSpike=CNtimeSinceLastSpike-ANdt;
1017
                    s=CN_E>CN_Th & CNtimeSinceLastSpike<0 ;
1018
                    CNtimeSinceLastSpike(s)=0.0005;         % 0.5 ms for sodium spike
1019
                    dE =(-CN_E/CN_tauM + ...
1020
                        CNcurrentInput(:,t)/CN_cap+(...
1021
                        CN_Gk/CN_cap).*(CN_Ek-CN_E))*ANdt;
1022
                    dGk=-CN_Gk*ANdt./tauGk + CN_b*s;
1023
                    dTh=-(CN_Th-CN_Th0)*ANdt/CN_tauTh + CN_c*s;
1024
                    CN_E=CN_E+dE;
1025
                    CN_Gk=CN_Gk+dGk;
1026
                    CN_Th=CN_Th+dTh;
1027
                    CNmembranePotential(:,t)=CN_E+s.*(CN_Eb-CN_E)+CN_Er;
1028
                end
1029
            else
1030
                % static threshold (faster)
1031
                E=zeros(1,reducedSegmentLength);
1032
                Gk=zeros(1,reducedSegmentLength);
1033
                ss=zeros(1,reducedSegmentLength);
1034
                for t=1:reducedSegmentLength
1035
                    % time of previous spike moves back in time
1036
                    CNtimeSinceLastSpike=CNtimeSinceLastSpike-ANdt;
1037
                    % action potential if E>threshold
1038
                    %  allow time for s to reset between events
1039
                    s=CN_E>CN_Th0 & CNtimeSinceLastSpike<0 ;  
1040
                    ss(t)=s(1);
1041
                    CNtimeSinceLastSpike(s)=0.0005; % 0.5 ms for sodium spike
1042
                    dE = (-CN_E/CN_tauM + ...
1043
                        CNcurrentInput(:,t)/CN_cap +...
1044
                        (CN_Gk/CN_cap).*(CN_Ek-CN_E))*ANdt;
1045
                    dGk=-CN_Gk*ANdt./tauGk +CN_b*s;
1046
                    CN_E=CN_E+dE;
1047
                    CN_Gk=CN_Gk+dGk;
1048
                    E(t)=CN_E(1);
1049
                    Gk(t)=CN_Gk(1);
1050
                    % add spike to CN_E and add resting potential (-60 mV)
1051
                    CNmembranePotential(:,t)=CN_E +s.*(CN_Eb-CN_E)+CN_Er;
1052
                end
1053
            end
1054
%             disp(['CN_E= ' num2str(sum(CN_E(1,:)))])
1055
%             disp(['CN_Gk= ' num2str(sum(CN_Gk(1,:)))])
1056
%             disp(['CNmembranePotential= ' num2str(sum(CNmembranePotential(1,:)))])
1057
%             plot(CNmembranePotential(1,:))
1058

  
1059

  
1060
            % extract spikes.  A spike is a substantial upswing in voltage
1061
            CN_spikes=CNmembranePotential> -0.02;
1062
%             disp(['CNspikesbefore= ' num2str(sum(sum(CN_spikes)))])
1063

  
1064
            % now remove any spike that is immediately followed by a spike
1065
            % NB 'find' works on columns (whence the transposing)
1066
            % for each spike put a zero in the next epoch
1067
            CN_spikes=CN_spikes';
1068
            idx=find(CN_spikes);
1069
            idx=idx(1:end-1);
1070
            CN_spikes(idx+1)=0;
1071
            CN_spikes=CN_spikes';
1072
%             disp(['CNspikes= ' num2str(sum(sum(CN_spikes)))])
1073

  
1074
            % segment debugging
1075
            % plotInstructions.figureNo=98;
1076
            % plotInstructions.displaydt=ANdt;
1077
            %  plotInstructions.numPlots=1;
1078
            %  plotInstructions.subPlotNo=1;
1079
            % UTIL_plotMatrix(CN_spikes, plotInstructions);
1080

  
1081
            % and save it
1082
            CNoutput(:, reducedSegmentPTR:shorterSegmentEndPTR)=...
1083
                CN_spikes;
1084

  
1085

  
1086
            %% IC ----------------------------------------------
1087
                %  MacGregor or some other second order neurons
1088

  
1089
                % combine CN neurons in same channel (BF x AN tau x CNtau) 
1090
                %  i.e. same BF, same tauCa, same CNtau
1091
                %  to generate inputs to single IC unit
1092
                channelNo=0;
1093
                for idx=1:nCNneuronsPerChannel: ...
1094
                        nCNneurons-nCNneuronsPerChannel+1;
1095
                    channelNo=channelNo+1;
1096
                    CN_PSTH(channelNo,:)=...
1097
                        sum(CN_spikes(idx:idx+nCNneuronsPerChannel-1,:));
1098
                end
1099

  
1100
                [alphaRows alphaCols]=size(ICtrailingAlphas);
1101
                for ICneuronNo=1:nICcells
1102
                    ICcurrentTemp(ICneuronNo,:)= ...
1103
                        conv2(CN_PSTH(ICneuronNo,:),  IC_CNalphaFunction);
1104
                end
1105

  
1106
                % add the unused current from the previous convolution
1107
                ICcurrentTemp(:,1:alphaCols)=ICcurrentTemp(:,1:alphaCols)...
1108
                    + ICtrailingAlphas;
1109
                % take what is required and keep the trailing part for next time
1110
                inputCurrent=ICcurrentTemp(:, 1:reducedSegmentLength);
1111
                ICtrailingAlphas=ICcurrentTemp(:, reducedSegmentLength+1:end);
1112

  
1113
                if IC_c==0
1114
                    % faster computation when threshold is stable (c==0)
1115
                    for t=1:reducedSegmentLength
1116
                        s=IC_E>IC_Th0;
1117
                        dE = (-IC_E/IC_tauM + inputCurrent(:,t)/IC_cap +...
1118
                            (IC_Gk/IC_cap).*(IC_Ek-IC_E))*ANdt;
1119
                        dGk=-IC_Gk*ANdt/IC_tauGk +IC_b*s;
1120
                        IC_E=IC_E+dE;
1121
                        IC_Gk=IC_Gk+dGk;
1122
                        ICmembranePotential(:,t)=IC_E+s.*(IC_Eb-IC_E)+IC_Er;
1123
                    end
1124
                else
1125
                    %  threshold is changing (IC_c>0; e.g. bushy cell)
1126
                    for t=1:reducedSegmentLength
1127
                        dE = (-IC_E/IC_tauM + ...
1128
                            inputCurrent(:,t)/IC_cap + (IC_Gk/IC_cap)...
1129
                            .*(IC_Ek-IC_E))*ANdt;
1130
                        IC_E=IC_E+dE;
1131
                        s=IC_E>IC_Th;
1132
                        ICmembranePotential(:,t)=IC_E+s.*(IC_Eb-IC_E)+IC_Er;
1133
                        dGk=-IC_Gk*ANdt/IC_tauGk +IC_b*s;
1134
                        IC_Gk=IC_Gk+dGk;
1135

  
1136
                        % After a spike, the threshold is raised
1137
                        % otherwise it settles to its baseline
1138
                        dTh=-(IC_Th-Th0)*ANdt/IC_tauTh +s*IC_c;
1139
                        IC_Th=IC_Th+dTh;
1140
                    end
1141
                end
1142

  
1143
                ICspikes=ICmembranePotential> -0.01;
1144
                % now remove any spike that is immediately followed by a spike
1145
                % NB 'find' works on columns (whence the transposing)
1146
                ICspikes=ICspikes';
1147
                idx=find(ICspikes);
1148
                idx=idx(1:end-1);
1149
                ICspikes(idx+1)=0;
1150
                ICspikes=ICspikes';
1151

  
1152
                nCellsPerTau= nICcells/nANfiberTypes;
1153
                firstCell=1;
1154
                lastCell=nCellsPerTau;
1155
                for tauCount=1:nANfiberTypes
1156
                    % separate rates according to fiber types
1157
                    % currently only the last segment is saved
1158
                    ICfiberTypeRates(tauCount, ...
1159
                        reducedSegmentPTR:shorterSegmentEndPTR)=...
1160
                        sum(ICspikes(firstCell:lastCell, :))...
1161
                        /(nCellsPerTau*ANdt);
1162
                    firstCell=firstCell+nCellsPerTau;
1163
                    lastCell=lastCell+nCellsPerTau;
1164
                end
1165
                
1166
                ICoutput(:,reducedSegmentPTR:shorterSegmentEndPTR)=ICspikes;
1167
                
1168
                % store membrane output on original dt scale
1169
                % do this for single channel models only 
1170
                % and only for the HSR-driven IC cells
1171
                if round(nICcells/length(ANtauCas))==1  % single channel
1172
                    % select HSR driven cells
1173
                    x= ICmembranePotential(length(ANtauCas),:);
1174
                    % restore original dt
1175
                    x= repmat(x, ANspeedUpFactor,1);
1176
                    x= reshape(x,1,segmentLength);
1177
                    if nANfiberTypes>1  % save HSR and LSR
1178
                        y=repmat(ICmembranePotential(end,:),...
1179
                            ANspeedUpFactor,1);
1180
                        y= reshape(y,1,segmentLength);
1181
                        x=[x; y];
1182
                    end
1183
                    ICmembraneOutput(:, segmentStartPTR:segmentEndPTR)= x;
1184
                end
1185

  
1186
                % estimate efferent effects.
1187
                % ARis based on LSR units. LSR channels are 1:nBF
1188
                if nANfiberTypes>1  % AR is multi-channel only
1189
                    ARAttSeg=sum(ICspikes(1:nBFs,:),1)/ANdt;
1190
                    [ARAttSeg, ARboundary] = ...
1191
                        filter(ARfilt_b, ARfilt_a, ARAttSeg, ARboundary);
1192
                    ARAttSeg=ARAttSeg-ARrateThreshold;
1193
                    ARAttSeg(ARAttSeg<0)=0;   % prevent negative strengths
1194
                    % scale up to dt from ANdt
1195
                    x=    repmat(ARAttSeg, ANspeedUpFactor,1);
1196
                    x=reshape(x,1,segmentLength);
1197
                    ARattenuation(segmentStartPTR:segmentEndPTR)=...
1198
                        (1-ARrateToAttenuationFactor* x);
1199
                    ARattenuation(ARattenuation<0)=0.001;
1200
                else
1201
                    % single channel model; disable AR
1202
                    ARattenuation(segmentStartPTR:segmentEndPTR)=...
1203
                        ones(1,segmentLength);
1204
                end
1205

  
1206
                % MOC attenuation using HSR response only
1207
                % Separate MOC effect for each BF
1208
                HSRbegins=nBFs*(nANfiberTypes-1)+1;
1209
                rates=ICspikes(HSRbegins:end,:)/ANdt;
1210
                for idx=1:nBFs
1211
                    [smoothedRates, MOCboundary{idx}] = ...
1212
                        filter(MOCfilt_b, MOCfilt_a, rates(idx,:), ...
1213
                        MOCboundary{idx});
1214
                    % spont 'rates' is zero for IC
1215
                    MOCattSegment(idx,:)=smoothedRates;
1216
                    % expand timescale back to model dt from ANdt
1217
                    x= repmat(MOCattSegment(idx,:), ANspeedUpFactor,1);
1218
                    x= reshape(x,1,segmentLength);
1219
                    MOCattenuation(idx,segmentStartPTR:segmentEndPTR)= ...
1220
                        (1- MOCrateToAttenuationFactor*  x);
1221
                end
1222
                MOCattenuation(MOCattenuation<0)=0.04;
1223
                % segment debugging
1224
                % plotInstructions.figureNo=98;
1225
                % plotInstructions.displaydt=ANdt;
1226
                %  plotInstructions.numPlots=1;
1227
                %  plotInstructions.subPlotNo=1;
1228
                % UTIL_plotMatrix(ICspikes, plotInstructions);
1229

  
1230
    end     % AN_spikesOrProbability
1231
    segmentStartPTR=segmentStartPTR+segmentLength;
1232
    reducedSegmentPTR=reducedSegmentPTR+reducedSegmentLength;
1233

  
1234

  
1235
end  % segment
1236

  
1237
%% apply refractory correction to spike probabilities
1238

  
1239
% the probability of a spike's having occurred in the preceding 
1240
%  refractory window 
1241
%    pFired= 1 - II(1-p(t)), t= tnow-refractory period: tnow-1
1242
% we need a running account of cumProb=II(1-p(t))
1243
%   cumProb(t)= cumProb(t-1)*(1-p(t-1))/(1-p(t-refracPeriod))
1244
%   cumProb(0)=0
1245
%   pFired(t)= 1-cumProb(t)
1246
% whence
1247
%   p(t)= ANprobOutput(t) * pFired(t)
1248
% where ANprobOutput is the uncorrected probability
1249

  
1250

  
1251
% switch AN_spikesOrProbability
1252
%     case 'probability'
1253
%         ANprobOutput=ANprobRateOutput*dt;
1254
%         [r nEpochs]=size(ANprobOutput);
1255
%         % find probability of no spikes in refractory period
1256
%         pNoSpikesInRefrac=ones(size(ANprobOutput));
1257
%         pSpike=zeros(size(ANprobOutput));
1258
%         for epochNo=lengthAbsRefractoryP+2:nEpochs
1259
%             pNoSpikesInRefrac(:,epochNo)=...
1260
%                 pNoSpikesInRefrac(:,epochNo-2)...
1261
%                 .*(1-pSpike(:,epochNo-1))...
1262
%                 ./(1-pSpike(:,epochNo-lengthAbsRefractoryP-1));
1263
%             pSpike(:,epochNo)= ANprobOutput(:,epochNo)...
1264
%                 .*pNoSpikesInRefrac(:,epochNo);
1265
%         end
1266
%         ANprobRateOutput=pSpike/dt;
1267
% end
1268

  
1269
path(restorePath)
userProgramsTim/Pavel_MAP1_14.m
1
function Pavel_MAP1_14
2
% test_MAP1_14 is a general purpose test routine that can be adjusted to
3
% test a number of different applications of MAP1_14
4
%
5
% A range of options are supplied in the early part of the program
6
%
7
% One use of the function is to create demonstrations; filenames <demoxx>
8
%  to illustrate particular features
9
%
10
% #1
11
% Identify the file (in 'MAPparamsName') containing the model parameters
12
%
13
% #2
14
% Identify the kind of model required (in 'AN_spikesOrProbability').
15
%  A full brainstem model (spikes) can be computed or a shorter model
16
%  (probability) that computes only so far as the auditory nerve
17
%
18
% #3
19
% Choose between a tone signal or file input (in 'signalType')
20
%
21
% #4
22
% Set the signal rms level (in leveldBSPL)
23
%
24
% #5
25
% Identify the channels in terms of their best frequencies in the vector
26
%  BFlist.
27
%
28
% Last minute changes to the parameters fetched earlier can be made using
29
%  the cell array of strings 'paramChanges'.
30
%  Each string must have the same format as the corresponding line in the
31
%  file identified in 'MAPparamsName'
32
%
33
% When the demonstration is satisfactory, freeze it by renaming it <demoxx>
34

  
35
restorePath=path;
36
addpath (['..' filesep 'MAP'],    ['..' filesep 'wavFileStore'], ...
37
    ['..' filesep 'utilities'])
38

  
39
%%  #1 parameter file name
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff