To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

The primary repository for this project is hosted at git://github.com/rmeddis/MAP.git .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Revision:

root / MAP / MAP1_14.m @ 0:f233164f4c86

History | View | Annotate | Download (41.7 KB)

1

    
2
function  MAP1_14(inputSignal, sampleRate, BFlist, MAPparamsName, ...
3
    AN_spikesOrProbability, paramChanges)
4
% To test this function use test_MAP1_14 in this folder
5
%
6
% All arguments are mandatory.
7
%
8
% BFlist is a list of BFs but can be '-1' to allow MAPparams to choose
9
%
10

    
11
%  MAPparamsName='Normal'; % source of model parameters
12
%  AN_spikesOrProbability='spikes'; % or 'probability'
13
%  paramChanges is a cell array of strings that can be used to make last
14
%   minute parameter changes, e.g., to simulate OHC loss
15
%   paramChanges{1}= 'DRNLParams.a=0;';
16

    
17
% The model parameters are established in the MAPparams<***> file
18
%  and stored as global
19

    
20
restorePath=path;
21
addpath (['..' filesep 'parameterStore'])
22

    
23
global OMEParams DRNLParams IHC_cilia_RPParams IHCpreSynapseParams
24
global AN_IHCsynapseParams MacGregorParams MacGregorMultiParams
25

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

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

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

    
42
% When AN_spikesOrProbability is set to probability,
43
%  no spike matrices are computed.
44
% When AN_spikesOrProbability is set to 'spikes',
45
%  no probability output is computed
46

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

    
55

    
56
% save as global for later plotting if required
57
savedBFlist=BFlist;
58
saveAN_spikesOrProbability=AN_spikesOrProbability;
59
saveMAPparamsName=MAPparamsName;
60

    
61
% Read parameters from MAPparams<***> file in 'parameterStore' folder
62
cmd=['method=MAPparams' MAPparamsName ...
63
    '(BFlist, sampleRate, 0);'];
64
eval(cmd);
65

    
66
% Beware, 'BFlist=-1' is a legitimate argument for MAPparams<>
67
%  if the calling program allows MAPparams to specify the list
68
BFlist=DRNLParams.nonlinCFs;
69

    
70
% now accept last mintue parameter changes required by the calling program
71
if nargin>5 && ~isempty(paramChanges)
72
    nChanges=length(paramChanges);
73
    for idx=1:nChanges
74
        eval(paramChanges{idx})
75
    end
76
end
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=5;  % 5 times longer
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
% Nyquist=(1/ANdt)/2;
169
% [ARfilt_b,ARfilt_a] = butter(1, (1/(2*pi*OMEParams.ARtau))/Nyquist, 'low');
170
a1=dt/OMEParams.ARtau-1; a0=1;
171
b0=1+ a1;
172
ARfilt_b=b0; ARfilt_a=[a0 a1];
173

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

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

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

    
190
% DRNLchannelParameters=DRNLParams.channelParameters;
191
DRNLresponse= zeros(nBFs, segmentLength);
192

    
193
MOCrateToAttenuationFactor=DRNLParams.rateToAttenuationFactor;
194
rateToAttenuationFactorProb=DRNLParams.rateToAttenuationFactorProb;
195
MOCrateThreshold=DRNLParams.MOCrateThreshold;
196

    
197
% smoothing filter for MOC
198
% Nyquist=(1/ANdt)/2;
199
% [MOCfilt_b,MOCfilt_a] = ...
200
%     butter(1, (1/(2*pi*DRNLParams.MOCtau))/Nyquist, 'low');
201
% figure(10), freqz(stapesDisp_b, stapesDisp_a)
202
a1=dt/DRNLParams.MOCtau-1; a0=1;
203
b0=1+ a1;
204
MOCfilt_b=b0; MOCfilt_a=[a0 a1];
205
% figure(9), freqz(stapesDisp_b, stapesDisp_a)
206
MOCboundary=cell(nBFs,1);
207
MOCprobBoundary=cell(nBFs,1);
208

    
209
MOCattSegment=zeros(nBFs,reducedSegmentLength);
210
MOCattenuation=ones(nBFs,signalLength);
211

    
212
if DRNLParams.a>0
213
    DRNLcompressionThreshold=10^((1/(1-DRNLParams.c))* ...
214
    log10(DRNLParams.b/DRNLParams.a));
215
else
216
    DRNLcompressionThreshold=inf;
217
end
218

    
219
DRNLlinearOrder= DRNLParams.linOrder;
220
DRNLnonlinearOrder= DRNLParams.nonlinOrder;
221

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

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

    
272
% complete BM record (BM displacement)
273
DRNLoutput=zeros(nBFs, signalLength);
274

    
275

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

    
289
IHCciliaBndry=cell(nBFs,1);
290

    
291
% IHC apical conductance (Boltzman function)
292
IHC_C= IHC_cilia_RPParams.C;
293
IHCu0= IHC_cilia_RPParams.u0;
294
IHCu1= IHC_cilia_RPParams.u1;
295
IHCs0= IHC_cilia_RPParams.s0;
296
IHCs1= IHC_cilia_RPParams.s1;
297
IHCGmax= IHC_cilia_RPParams.Gmax;
298
IHCGu0= IHC_cilia_RPParams.Gu0; % (leakage)
299
IHCGa= IHCGmax./(1+exp(-(0-IHCu0)/IHCs0).*(1+exp(-(0-IHCu1)/IHCs1)));
300
IHCrestingCiliaCond=IHCGa+IHCGu0;
301

    
302
% Receptor potential
303
IHC_Cab= IHC_cilia_RPParams.Cab;
304
IHC_Gk= IHC_cilia_RPParams.Gk;
305
IHC_Et= IHC_cilia_RPParams.Et;
306
IHC_Ek= IHC_cilia_RPParams.Ek;
307
IHC_Ekp= IHC_Ek+IHC_Et*IHC_cilia_RPParams.Rpc;
308

    
309
IHCrestingV= -0.06;
310
IHC_Vnow= IHCrestingV*ones(nBFs,1); % initial voltage
311
IHC_RP= zeros(nBFs,segmentLength);
312

    
313
% complete record of IHC receptor potential (V)
314
IHCciliaDisplacement= zeros(nBFs,segmentLength);
315
IHCoutput= zeros(nBFs,signalLength);
316
IHC_cilia_output= zeros(nBFs,signalLength);
317

    
318

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

    
328
% Calcium control (more calcium, greater release rate)
329
ECa=IHCpreSynapseParams.ECa;
330
gamma=IHCpreSynapseParams.gamma;
331
beta=IHCpreSynapseParams.beta;
332
tauM=IHCpreSynapseParams.tauM;
333
mICa=zeros(nChannels,segmentLength);
334
GmaxCa=IHCpreSynapseParams.GmaxCa;
335
synapse_z= IHCpreSynapseParams.z;
336
synapse_power=IHCpreSynapseParams.power;
337

    
338
% tauCa vector is established across channels to allow vectorization
339
%  (one tauCa per channel). Do not confuse with tauCas (one pre fiber type)
340
tauCa=repmat(tauCas, nBFs,1);
341
tauCa=reshape(tauCa, nChannels, 1);
342

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

    
351
% vesicle release rate at startup (one per channel)
352
% kt0 is used only at initialisation
353
kt0= -synapse_z * CaCurrent.^synapse_power;
354

    
355

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

    
363
y=AN_IHCsynapseParams.y;
364
l=AN_IHCsynapseParams.l;
365
x=AN_IHCsynapseParams.x;
366
r=AN_IHCsynapseParams.r;
367
M=round(AN_IHCsynapseParams.M);
368

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

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

    
382
ANprobability=zeros(nChannels,segmentLength);
383
ANprobRateOutput=zeros(nChannels,signalLength);
384
% special variables for monitoring synaptic cleft (specialists only)
385
savePavailableSeg=zeros(nChannels,segmentLength);
386
savePavailable=zeros(nChannels,signalLength);
387

    
388
% spikes     % !  !  !    ! !        !   !  !
389
AN_refractory_period= AN_IHCsynapseParams.refractory_period;
390
lengthAbsRefractory= round(AN_refractory_period/ANdt);
391

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

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

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

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

    
413

    
414
%% CN (first brain stem nucleus - could be any subdivision of CN)
415
% Input to a CN neuorn is a random selection of AN fibers within a channel
416
%  The number of AN fibers used is ANfibersFanInToCN
417
ANfibersFanInToCN=MacGregorMultiParams.fibersPerNeuron;
418
nCNneuronsPerChannel=MacGregorMultiParams.nNeuronsPerBF;
419
% CNtauGk (Potassium time constant) determines the rate of firing of
420
%  the unit when driven hard by a DC input (not normally >350 sp/s)
421
CNtauGk=MacGregorMultiParams.tauGk;
422
ANavailableFibersPerChan=AN_IHCsynapseParams.numFibers;
423
nCNneurons=nCNneuronsPerChannel*nChannels;
424
% nCNneuronsPerFiberType= nCNneurons/nANfiberTypes;
425

    
426
CNmembranePotential=zeros(nCNneurons,reducedSegmentLength);
427

    
428
% establish which ANfibers (by name) feed into which CN nuerons
429
CNinputfiberLists=zeros(nChannels*nCNneuronsPerChannel, ANfibersFanInToCN);
430
unitNo=1;
431
for ch=1:nChannels
432
    % Each channel contains a number of units =length(listOfFanInValues)
433
    for idx=1:nCNneuronsPerChannel
434
        fibersUsed=(ch-1)*ANavailableFibersPerChan + ...
435
            ceil(rand(1,ANfibersFanInToCN)* ANavailableFibersPerChan);
436
        CNinputfiberLists(unitNo,:)=fibersUsed;
437
        unitNo=unitNo+1;
438
    end
439
end
440

    
441
% input to CN units
442
AN_PSTH=zeros(nCNneurons,reducedSegmentLength);
443

    
444
% Generate CNalphaFunction function
445
%  by which spikes are converted to post-synaptic currents
446
CNdendriteLPfreq= MacGregorMultiParams.dendriteLPfreq;
447
CNcurrentPerSpike=MacGregorMultiParams.currentPerSpike;
448
CNspikeToCurrentTau=1/(2*pi*CNdendriteLPfreq);
449
t=ANdt:ANdt:5*CNspikeToCurrentTau;
450
CNalphaFunction=...
451
    (CNcurrentPerSpike/CNspikeToCurrentTau)*t.*exp(-t/CNspikeToCurrentTau);
452
% figure(98), plot(t,CNalphaFunction)
453
% working memory for implementing convolution
454
CNcurrentTemp=...
455
    zeros(nCNneurons,reducedSegmentLength+length(CNalphaFunction)-1);
456
% trailing alphas are parts of humps carried forward to the next segment
457
CNtrailingAlphas=zeros(nCNneurons,length(CNalphaFunction));
458

    
459
CN_tauM=MacGregorMultiParams.tauM;
460
CN_tauTh=MacGregorMultiParams.tauTh;
461
CN_cap=MacGregorMultiParams.Cap;
462
CN_c=MacGregorMultiParams.c;
463
CN_b=MacGregorMultiParams.dGkSpike;
464
CN_Ek=MacGregorMultiParams.Ek;
465
CN_Eb= MacGregorMultiParams.Eb;
466
CN_Er=MacGregorMultiParams.Er;
467
CN_Th0= MacGregorMultiParams.Th0;
468
CN_E= zeros(nCNneurons,1);
469
CN_Gk= zeros(nCNneurons,1);
470
CN_Th= MacGregorMultiParams.Th0*ones(nCNneurons,1);
471
CN_Eb=CN_Eb.*ones(nCNneurons,1);
472
CN_Er=CN_Er.*ones(nCNneurons,1);
473
CNtimeSinceLastSpike=zeros(nCNneurons,1);
474
% tauGk is the main distinction between neurons
475
%  in fact they are all the same in the standard model
476
tauGk=repmat(CNtauGk,nChannels*nCNneuronsPerChannel,1);
477

    
478
CN_PSTH=zeros(nChannels,reducedSegmentLength);
479
CNoutput=false(nCNneurons,reducedSignalLength);
480

    
481

    
482
%% MacGregor (IC - second nucleus) --------
483
nICcells=nChannels;  % one cell per channel
484

    
485
ICspikeWidth=0.00015;   % this may need revisiting
486
epochsPerSpike=round(ICspikeWidth/ANdt);
487
if epochsPerSpike<1
488
    error(['MacGregorMulti: sample rate too low to support ' ...
489
        num2str(ICspikeWidth*1e6) '  microsec spikes']);
490
end
491

    
492
% short names
493
IC_tauM=MacGregorParams.tauM;
494
IC_tauGk=MacGregorParams.tauGk;
495
IC_tauTh=MacGregorParams.tauTh;
496
IC_cap=MacGregorParams.Cap;
497
IC_c=MacGregorParams.c;
498
IC_b=MacGregorParams.dGkSpike;
499
IC_Th0=MacGregorParams.Th0;
500
IC_Ek=MacGregorParams.Ek;
501
IC_Eb= MacGregorParams.Eb;
502
IC_Er=MacGregorParams.Er;
503

    
504
IC_E=zeros(nICcells,1);
505
IC_Gk=zeros(nICcells,1);
506
IC_Th=IC_Th0*ones(nICcells,1);
507

    
508
% Dendritic filtering, all spikes are replaced by CNalphaFunction functions
509
ICdendriteLPfreq= MacGregorParams.dendriteLPfreq;
510
ICcurrentPerSpike=MacGregorParams.currentPerSpike;
511
ICspikeToCurrentTau=1/(2*pi*ICdendriteLPfreq);
512
t=ANdt:ANdt:3*ICspikeToCurrentTau;
513
IC_CNalphaFunction= (ICcurrentPerSpike / ...
514
    ICspikeToCurrentTau)*t.*exp(-t / ICspikeToCurrentTau);
515
% figure(98), plot(t,IC_CNalphaFunction)
516

    
517
% working space for implementing alpha function
518
ICcurrentTemp=...
519
    zeros(nICcells,reducedSegmentLength+length(IC_CNalphaFunction)-1);
520
ICtrailingAlphas=zeros(nICcells, length(IC_CNalphaFunction));
521

    
522
ICfiberTypeRates=zeros(nANfiberTypes,reducedSignalLength);
523
ICoutput=false(nChannels,reducedSignalLength);
524

    
525
ICmembranePotential=zeros(nICcells,reducedSegmentLength);
526
ICmembraneOutput=zeros(nICcells,signalLength);
527

    
528

    
529
%% Main program %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%
530

    
531
%  Compute the entire model for each segment
532
segmentStartPTR=1;
533
reducedSegmentPTR=1; % when sampling rate is reduced
534
while segmentStartPTR<signalLength
535
    segmentEndPTR=segmentStartPTR+segmentLength-1;
536
    % shorter segments after speed up.
537
    shorterSegmentEndPTR=reducedSegmentPTR+reducedSegmentLength-1;
538

    
539
    iputPressureSegment=inputSignal...
540
        (:,segmentStartPTR:segmentStartPTR+segmentLength-1);
541

    
542
    % segment debugging plots
543
    % figure(98)
544
    % plot(segmentTime,iputPressureSegment), title('signalSegment')
545

    
546

    
547
    % OME ----------------------
548

    
549
    % OME Stage 1: external resonances. Add to inputSignal pressure wave
550
    y=iputPressureSegment;
551
    for n=1:nOMEExtFilters
552
        % any number of resonances can be used
553
        [x  OMEExtFilterBndry{n}] = ...
554
            filter(ExtFilter_b{n},ExtFilter_a{n},...
555
            iputPressureSegment, OMEExtFilterBndry{n});
556
        x= x* OMEgainScalars(n);
557
        % This is a parallel resonance so add it
558
        y=y+x;
559
    end
560
    iputPressureSegment=y;
561
    OMEextEarPressure(segmentStartPTR:segmentEndPTR)= iputPressureSegment;
562
    
563
    % OME stage 2: convert input pressure (velocity) to
564
    %  tympanic membrane(TM) displacement using low pass filter
565
    [TMdisplacementSegment  OME_TMdisplacementBndry] = ...
566
        filter(TMdisp_b,TMdisp_a,iputPressureSegment, ...
567
        OME_TMdisplacementBndry);
568
    % and save it
569
    TMoutput(segmentStartPTR:segmentEndPTR)= TMdisplacementSegment;
570

    
571
    % OME stage 3: middle ear high pass effect to simulate stapes inertia
572
    [stapesDisplacement  OMEhighPassBndry] = ...
573
        filter(stapesDisp_b,stapesDisp_a,TMdisplacementSegment, ...
574
        OMEhighPassBndry);
575

    
576
    % OME stage 4:  apply stapes scalar
577
    stapesDisplacement=stapesDisplacement*stapesScalar;
578

    
579
    % OME stage 5:    acoustic reflex stapes attenuation
580
    %  Attenuate the TM response using feedback from LSR fiber activity
581
    if segmentStartPTR>efferentDelayPts
582
        stapesDisplacement= stapesDisplacement.*...
583
            ARattenuation(segmentStartPTR-efferentDelayPts:...
584
            segmentEndPTR-efferentDelayPts);
585
    end
586

    
587
    % segment debugging plots
588
    % figure(98)
589
    % plot(segmentTime, stapesDisplacement), title ('stapesDisplacement')
590

    
591
    % and save
592
    OMEoutput(segmentStartPTR:segmentEndPTR)= stapesDisplacement;
593

    
594

    
595
    %% BM ------------------------------
596
    % Each location is computed separately
597
    for BFno=1:nBFs
598

    
599
        %            *linear* path
600
        linOutput = stapesDisplacement * linGAIN;  % linear gain
601
        for order = 1 : GTlinOrder
602
            [linOutput GTlinBdry{BFno,order}] = ...
603
                filter(GTlin_b(BFno,:), GTlin_a(BFno,:), linOutput, GTlinBdry{BFno,order});
604
        end
605

    
606
        %           *nonLinear* path
607
        % efferent attenuation (0 <> 1)
608
        if segmentStartPTR>efferentDelayPts
609
            MOC=MOCattenuation(BFno, segmentStartPTR-efferentDelayPts:...
610
                segmentEndPTR-efferentDelayPts);
611
        else    % no MOC available yet
612
            MOC=ones(1, segmentLength);
613
        end
614

    
615
        %       first gammatone filter
616
        for order = 1 : GTnonlinOrder
617
            [nonlinOutput GTnonlinBdry1{BFno,order}] = ...
618
                filter(GTnonlin_b(BFno,:), GTnonlin_a(BFno,:), ...
619
                stapesDisplacement, GTnonlinBdry1{BFno,order});
620
        end
621

    
622
        %       broken stick instantaneous compression
623
        % nonlinear gain is weakend by MOC before applied to BM response
624
        y= nonlinOutput.*(MOC* DRNLa);  % linear section.
625
        % compress those parts of the signal above the compression
626
        % threshold
627
        abs_x = abs(nonlinOutput);
628
        idx=find(abs_x>DRNLcompressionThreshold);
629
        if ~isempty(idx)>0
630
            y(idx)=sign(nonlinOutput(idx)).*...
631
                (DRNLb*abs_x(idx).^DRNLc);
632
        end
633
        nonlinOutput=y;
634

    
635
        %       second filter removes distortion products
636
        for order = 1 : GTnonlinOrder
637
            [ nonlinOutput GTnonlinBdry2{BFno,order}] = ...
638
                filter(GTnonlin_b(BFno,:), GTnonlin_a(BFno,:), nonlinOutput, GTnonlinBdry2{BFno,order});
639
        end
640

    
641
        %  combine the two paths to give the DRNL displacement
642
        DRNLresponse(BFno,:)=linOutput+nonlinOutput;
643
    end % BF
644

    
645
    % segment debugging plots
646
    % figure(98)
647
    %     if size(DRNLresponse,1)>3
648
    %         imagesc(DRNLresponse)  % matrix display
649
    %         title('DRNLresponse'); % single or double channel response
650
    %     else
651
    %         plot(segmentTime, DRNLresponse)
652
    %     end
653

    
654
    % and save it
655
    DRNLoutput(:, segmentStartPTR:segmentEndPTR)= DRNLresponse;
656

    
657

    
658
    %% IHC ------------------------------------
659
    %  BM displacement to IHCciliaDisplacement is  a high-pass filter
660
    %   because of viscous coupling
661
    for idx=1:nBFs
662
        [IHCciliaDisplacement(idx,:)  IHCciliaBndry{idx}] = ...
663
            filter(IHCciliaFilter_b,IHCciliaFilter_a, ...
664
            DRNLresponse(idx,:), IHCciliaBndry{idx});
665
    end
666
    
667
    % apply scalar
668
    IHCciliaDisplacement=IHCciliaDisplacement* IHC_C;
669

    
670
    % and save it
671
    IHC_cilia_output(:,segmentStartPTR:segmentStartPTR+segmentLength-1)=...
672
        IHCciliaDisplacement;
673

    
674
    % compute apical conductance
675
    G=1./(1+exp(-(IHCciliaDisplacement-IHCu0)/IHCs0).*...
676
        (1+exp(-(IHCciliaDisplacement-IHCu1)/IHCs1)));
677
    Gu=IHCGmax*G;
678
    % add resting conductance to give apical conductance
679
    Gu= Gu+IHCGu0;
680

    
681
    % Compute receptor potential
682
    for idx=1:segmentLength
683
        IHC_Vnow=IHC_Vnow+ (-Gu(:, idx).*(IHC_Vnow-IHC_Et)-...
684
            IHC_Gk*(IHC_Vnow-IHC_Ekp))*  dt/IHC_Cab;
685
        IHC_RP(:,idx)=IHC_Vnow;
686
    end
687

    
688
    % segment debugging plots
689
    %     if size(IHC_RP,1)>3
690
    %         surf(IHC_RP), shading interp, title('IHC_RP')
691
    %     else
692
    %         plot(segmentTime, IHC_RP)
693
    %     end
694

    
695
    % and save it
696
    IHCoutput(:, segmentStartPTR:segmentStartPTR+segmentLength-1)=IHC_RP;
697

    
698

    
699
    %% synapse -----------------------------
700
    % Compute the vesicle release rate for each fiber type at each BF
701
    % replicate IHC_RP for each fiber type
702
    Vsynapse=repmat(IHC_RP, nANfiberTypes,1);
703

    
704
    % look-up table of target fraction channels open for a given IHC_RP
705
    mICaINF=    1./( 1 + exp(-gamma  * Vsynapse)  /beta);
706
    % fraction of channel open - apply time constant
707
    for idx=1:segmentLength
708
        % mICaINF is the current 'target' value of mICa
709
        mICaCurrent=mICaCurrent+(mICaINF(:,idx)-mICaCurrent)*dt./tauM;
710
        mICa(:,idx)=mICaCurrent;
711
    end
712

    
713
    ICa=   (GmaxCa* mICa.^3) .* (Vsynapse- ECa);
714

    
715
    for idx=1:segmentLength
716
        CaCurrent=CaCurrent +  ICa(:,idx)*dt - CaCurrent*dt./tauCa;
717
        synapticCa(:,idx)=CaCurrent;
718
    end
719
    synapticCa=-synapticCa; % treat IHCpreSynapseParams as positive substance
720

    
721
    % NB vesicleReleaseRate is /s and is independent of dt
722
    vesicleReleaseRate = synapse_z * synapticCa.^synapse_power; % rate
723

    
724
    % segment debugging plots
725
    %     if size(vesicleReleaseRate,1)>3
726
    %         surf(vesicleReleaseRate), shading interp, title('vesicleReleaseRate')
727
    %     else
728
    %         plot(segmentTime, vesicleReleaseRate)
729
    %     end
730

    
731

    
732
    %% AN
733
    switch AN_spikesOrProbability
734
        case 'probability'
735
            % No refractory effect is applied
736
            for t = 1:segmentLength;
737
                M_Pq=PAN_M-Pavailable;
738
                M_Pq(M_Pq<0)=0;
739
                Preplenish = M_Pq .* PAN_ydt;
740
                Pejected = Pavailable.* vesicleReleaseRate(:,t)*dt;
741
                Preprocessed = M_Pq.*Preprocess.* PAN_xdt;
742

    
743
                ANprobability(:,t)= min(Pejected,1);
744
                reuptakeandlost= PAN_rdt_plus_ldt .* Pcleft;
745
                reuptake= PAN_rdt.* Pcleft;
746

    
747
                Pavailable= Pavailable+ Preplenish- Pejected+ Preprocessed;
748
                Pcleft= Pcleft + Pejected - reuptakeandlost;
749
                Preprocess= Preprocess + reuptake - Preprocessed;
750
                Pavailable(Pavailable<0)=0;
751
                savePavailableSeg(:,t)=Pavailable;    % synapse tracking
752
            end
753
            % and save it as *rate*
754
            ANrate=ANprobability/dt;
755
            ANprobRateOutput(:, segmentStartPTR:...
756
                segmentStartPTR+segmentLength-1)=  ANrate;
757
            % monitor synapse contents (only sometimes used)
758
            savePavailable(:, segmentStartPTR:segmentStartPTR+segmentLength-1)=...
759
                savePavailableSeg;
760

    
761
            % Estimate efferent effects. ARattenuation (0 <> 1)
762
            %  acoustic reflex
763
            ARAttSeg=mean(ANrate(1:nBFs,:),1); %LSR channels are 1:nBF
764
            % smooth
765
            [ARAttSeg, ARboundaryProb] = ...
766
                filter(ARfilt_b, ARfilt_a, ARAttSeg, ARboundaryProb);
767
            ARAttSeg=ARAttSeg-ARrateThreshold;
768
            ARAttSeg(ARAttSeg<0)=0;   % prevent negative strengths
769
            ARattenuation(segmentStartPTR:segmentEndPTR)=...
770
                (1-ARrateToAttenuationFactorProb.* ARAttSeg);
771

    
772
            % MOC attenuation
773
            % within-channel HSR response only
774
            HSRbegins=nBFs*(nANfiberTypes-1)+1;
775
            rates=ANrate(HSRbegins:end,:);
776
            for idx=1:nBFs
777
                [smoothedRates, MOCprobBoundary{idx}] = ...
778
                    filter(MOCfilt_b, MOCfilt_a, rates(idx,:), ...
779
                    MOCprobBoundary{idx});
780
                smoothedRates=smoothedRates-MOCrateThreshold;
781
                smoothedRates(smoothedRates<0)=0;
782
                MOCattenuation(idx,segmentStartPTR:segmentEndPTR)= ...
783
                    (1- smoothedRates* rateToAttenuationFactorProb);
784
            end
785
            MOCattenuation(MOCattenuation<0)=0.001;
786

    
787

    
788
        case 'spikes'
789
            ANtimeCount=0;
790
            % implement speed upt
791
            for t = ANspeedUpFactor:ANspeedUpFactor:segmentLength;
792
                ANtimeCount=ANtimeCount+1;
793
                % convert release rate to probabilities
794
                releaseProb=vesicleReleaseRate(:,t)*ANdt;
795
                % releaseProb is the release probability per channel
796
                %  but each channel has many synapses
797
                releaseProb=repmat(releaseProb',nFibersPerChannel,1);
798
                releaseProb=reshape(releaseProb, nFibersPerChannel*nChannels,1);
799

    
800
                % AN_available=round(AN_available); % vesicles must be integer, (?needed)
801
                M_q=AN_M- AN_available;     % number of missing vesicles
802
                M_q(M_q<0)= 0;              % cannot be less than 0
803

    
804
                % AN_N1 converts probability to discrete events
805
                %   it considers each event that might occur
806
                %   (how many vesicles might be released)
807
                %   and returns a count of how many were released
808

    
809
                % slow line
810
%                 probabilities= 1-(1-releaseProb).^AN_available;
811
                probabilities= 1-intpow((1-releaseProb), AN_available);
812
                ejected= probabilities> rand(length(AN_available),1);
813

    
814
                reuptakeandlost = AN_rdt_plus_ldt .* AN_cleft;
815
                reuptake = AN_rdt.* AN_cleft;
816

    
817
                % slow line
818
%                 probabilities= 1-(1-AN_reprocess.*AN_xdt).^M_q;
819
                probabilities= 1-intpow((1-AN_reprocess.*AN_xdt), M_q);
820
                reprocessed= probabilities>rand(length(M_q),1);
821

    
822
                % slow line
823
%                 probabilities= 1-(1-AN_ydt).^M_q;
824
                 probabilities= 1-intpow((1-AN_ydt), M_q);
825

    
826
                replenish= probabilities>rand(length(M_q),1);
827

    
828
                AN_available = AN_available + replenish - ejected ...
829
                    + reprocessed;
830
                AN_cleft = AN_cleft + ejected - reuptakeandlost;
831
                AN_reprocess = AN_reprocess + reuptake - reprocessed;
832

    
833
                % ANspikes is logical record of vesicle release events>0
834
                ANspikes(:, ANtimeCount)= ejected;
835
            end % t
836

    
837
            % zero any events that are preceded by release events ...
838
            %  within the refractory period
839
            % The refractory period consist of two periods
840
            %  1) the absolute period where no spikes occur
841
            %  2) a relative period where a spike may occur. This relative
842
            %     period is realised as a variable length interval
843
            %     where the length is chosen at random
844
            %     (esentially a linear ramp up)
845

    
846
            % Andreas has a fix for this
847
            for t = 1:ANtimeCount-2*lengthAbsRefractory;
848
                % identify all spikes across fiber array at time (t)
849
                % idx is a list of channels where spikes occurred
850
                % ?? try sparse matrices?
851
                idx=find(ANspikes(:,t));
852
                for j=idx  % consider each spike
853
                    % specify variable refractory period
854
                    %  between abs and 2*abs refractory period
855
                    nPointsRefractory=lengthAbsRefractory+...
856
                        round(rand*lengthAbsRefractory);
857
                    % disable spike potential for refractory period
858
                    % set all values in this range to 0
859
                    ANspikes(j,t+1:t+nPointsRefractory)=0;
860
                end
861
            end  %t
862

    
863
            % segment debugging
864
            % plotInstructions.figureNo=98;
865
            % plotInstructions.displaydt=ANdt;
866
            %  plotInstructions.numPlots=1;
867
            %  plotInstructions.subPlotNo=1;
868
            % UTIL_plotMatrix(ANspikes, plotInstructions);
869

    
870
            % and save it. NB, AN is now on 'speedUp' time
871
            ANoutput(:, reducedSegmentPTR: shorterSegmentEndPTR)=ANspikes;
872

    
873

    
874
            %% CN Macgregor first neucleus -------------------------------
875
            % input is from AN so ANdt is used throughout
876
            % Each CNneuron has a unique set of input fibers selected
877
            %  at random from the available AN fibers (CNinputfiberLists)
878

    
879
            % Create the dendritic current for that neuron
880
            % First get input spikes to this neuron
881
            synapseNo=1;
882
            for ch=1:nChannels
883
                for idx=1:nCNneuronsPerChannel
884
                    % determine candidate fibers for this unit
885
                    fibersUsed=CNinputfiberLists(synapseNo,:);
886
                    % ANpsth has a bin width of dt
887
                    %  (just a simple sum across fibers)
888
                    AN_PSTH(synapseNo,:) = ...
889
                        sum(ANspikes(fibersUsed,:), 1);
890
                    synapseNo=synapseNo+1;
891
                end
892
            end
893

    
894
            % One alpha function per spike
895
            [alphaRows alphaCols]=size(CNtrailingAlphas);
896

    
897
            for unitNo=1:nCNneurons
898
                CNcurrentTemp(unitNo,:)= ...
899
                    conv(AN_PSTH(unitNo,:),CNalphaFunction);
900
            end
901
            % add post-synaptic current  left over from previous segment
902
            CNcurrentTemp(:,1:alphaCols)=...
903
                CNcurrentTemp(:,1:alphaCols)+ CNtrailingAlphas;
904

    
905
            % take post-synaptic current for this segment
906
            CNcurrentInput= CNcurrentTemp(:, 1:reducedSegmentLength);
907

    
908
            % trailingalphas are the ends of the alpha functions that
909
            % spill over into the next segment
910
            CNtrailingAlphas= ...
911
                CNcurrentTemp(:, reducedSegmentLength+1:end);
912

    
913
            if CN_c>0
914
                % variable threshold condition (slow)
915
                for t=1:reducedSegmentLength
916
                    CNtimeSinceLastSpike=CNtimeSinceLastSpike-dts;
917
                    s=CN_E>CN_Th & CNtimeSinceLastSpike<0 ;
918
                    CNtimeSinceLastSpike(s)=0.0005;         % 0.5 ms for sodium spike
919
                    dE =(-CN_E/CN_tauM + ...
920
                        CNcurrentInput(:,t)/CN_cap+(CN_Gk/CN_cap).*(CN_Ek-CN_E))*dt;
921
                    dGk=-CN_Gk*dt./tauGk + CN_b*s;
922
                    dTh=-(CN_Th-CN_Th0)*dt/CN_tauTh + CN_c*s;
923
                    CN_E=CN_E+dE;
924
                    CN_Gk=CN_Gk+dGk;
925
                    CN_Th=CN_Th+dTh;
926
                    CNmembranePotential(:,t)=CN_E+s.*(CN_Eb-CN_E)+CN_Er;
927
                end
928
            else
929
                % static threshold (faster)
930
                for t=1:reducedSegmentLength
931
                    CNtimeSinceLastSpike=CNtimeSinceLastSpike-dt;
932
                    s=CN_E>CN_Th0 & CNtimeSinceLastSpike<0 ;  % =1 if both conditions met
933
                    CNtimeSinceLastSpike(s)=0.0005;          % 0.5 ms for sodium spike
934
                    dE = (-CN_E/CN_tauM + ...
935
                        CNcurrentInput(:,t)/CN_cap+(CN_Gk/CN_cap).*(CN_Ek-CN_E))*dt;
936
                    dGk=-CN_Gk*dt./tauGk +CN_b*s;
937
                    CN_E=CN_E+dE;
938
                    CN_Gk=CN_Gk+dGk;
939
                    % add spike to CN_E and add resting potential (-60 mV)
940
                    CNmembranePotential(:,t)=CN_E+s.*(CN_Eb-CN_E)+CN_Er;
941
                end
942
            end
943

    
944
            % extract spikes.  A spike is a substantial upswing in voltage
945
            CN_spikes=CNmembranePotential> -0.01;
946

    
947
            % now remove any spike that is immediately followed by a spike
948
            % NB 'find' works on columns (whence the transposing)
949
            CN_spikes=CN_spikes';
950
            idx=find(CN_spikes);
951
            idx=idx(1:end-1);
952
            CN_spikes(idx+1)=0;
953
            CN_spikes=CN_spikes';
954

    
955
            % segment debugging
956
            % plotInstructions.figureNo=98;
957
            % plotInstructions.displaydt=ANdt;
958
            %  plotInstructions.numPlots=1;
959
            %  plotInstructions.subPlotNo=1;
960
            % UTIL_plotMatrix(CN_spikes, plotInstructions);
961

    
962
            % and save it
963
            CNoutput(:, reducedSegmentPTR:shorterSegmentEndPTR)=...
964
                CN_spikes;
965

    
966

    
967
            %% IC ----------------------------------------------
968
                %  MacGregor or some other second order neurons
969

    
970
                % combine CN neurons in same channel, i.e. same BF & same tauCa
971
                %  to generate inputs to single IC unit
972
                channelNo=0;
973
                for idx=1:nCNneuronsPerChannel:nCNneurons-nCNneuronsPerChannel+1;
974
                    channelNo=channelNo+1;
975
                    CN_PSTH(channelNo,:)=...
976
                        sum(CN_spikes(idx:idx+nCNneuronsPerChannel-1,:));
977
                end
978

    
979
                [alphaRows alphaCols]=size(ICtrailingAlphas);
980
                for ICneuronNo=1:nICcells
981
                    ICcurrentTemp(ICneuronNo,:)= ...
982
                        conv(CN_PSTH(ICneuronNo,:),  IC_CNalphaFunction);
983
                end
984

    
985
                % add the unused current from the previous convolution
986
                ICcurrentTemp(:,1:alphaCols)=ICcurrentTemp(:,1:alphaCols)...
987
                    + ICtrailingAlphas;
988
                % take what is required and keep the trailing part for next time
989
                inputCurrent=ICcurrentTemp(:, 1:reducedSegmentLength);
990
                ICtrailingAlphas=ICcurrentTemp(:, reducedSegmentLength+1:end);
991

    
992
                if IC_c==0
993
                    % faster computation when threshold is stable (C==0)
994
                    for t=1:reducedSegmentLength
995
                        s=IC_E>IC_Th0;
996
                        dE = (-IC_E/IC_tauM + inputCurrent(:,t)/IC_cap +...
997
                            (IC_Gk/IC_cap).*(IC_Ek-IC_E))*dt;
998
                        dGk=-IC_Gk*dt/IC_tauGk +IC_b*s;
999
                        IC_E=IC_E+dE;
1000
                        IC_Gk=IC_Gk+dGk;
1001
                        ICmembranePotential(:,t)=IC_E+s.*(IC_Eb-IC_E)+IC_Er;
1002
                    end
1003
                else
1004
                    %  threshold is changing (IC_c>0; e.g. bushy cell)
1005
                    for t=1:reducedSegmentLength
1006
                        dE = (-IC_E/IC_tauM + ...
1007
                            inputCurrent(:,t)/IC_cap + (IC_Gk/IC_cap)...
1008
                            .*(IC_Ek-IC_E))*dt;
1009
                        IC_E=IC_E+dE;
1010
                        s=IC_E>IC_Th;
1011
                        ICmembranePotential(:,t)=IC_E+s.*(IC_Eb-IC_E)+IC_Er;
1012
                        dGk=-IC_Gk*dt/IC_tauGk +IC_b*s;
1013
                        IC_Gk=IC_Gk+dGk;
1014

    
1015
                        % After a spike, the threshold is raised
1016
                        % otherwise it settles to its baseline
1017
                        dTh=-(IC_Th-Th0)*dt/IC_tauTh +s*IC_c;
1018
                        IC_Th=IC_Th+dTh;
1019
                    end
1020
                end
1021

    
1022
                ICspikes=ICmembranePotential> -0.01;
1023
                % now remove any spike that is immediately followed by a spike
1024
                % NB 'find' works on columns (whence the transposing)
1025
                ICspikes=ICspikes';
1026
                idx=find(ICspikes);
1027
                idx=idx(1:end-1);
1028
                ICspikes(idx+1)=0;
1029
                ICspikes=ICspikes';
1030

    
1031
                nCellsPerTau= nICcells/nANfiberTypes;
1032
                firstCell=1;
1033
                lastCell=nCellsPerTau;
1034
                for tauCount=1:nANfiberTypes
1035
                    % separate rates according to fiber types
1036
                    ICfiberTypeRates(tauCount, ...
1037
                        reducedSegmentPTR:shorterSegmentEndPTR)=...
1038
                        sum(ICspikes(firstCell:lastCell, :))...
1039
                        /(nCellsPerTau*ANdt);
1040
                    firstCell=firstCell+nCellsPerTau;
1041
                    lastCell=lastCell+nCellsPerTau;
1042
                end
1043
                ICoutput(:, reducedSegmentPTR:shorterSegmentEndPTR)=ICspikes;
1044

    
1045
                if nBFs==1  % single channel
1046
                    x= repmat(ICmembranePotential(1,:), ANspeedUpFactor,1);
1047
                    x= reshape(x,1,segmentLength);
1048
                    if nANfiberTypes>1  % save HSR and LSR
1049
                        y= repmat(ICmembranePotential(end,:), ANspeedUpFactor,1);
1050
                        y= reshape(y,1,segmentLength);
1051
                        x=[x; y];
1052
                    end
1053
                    ICmembraneOutput(:, segmentStartPTR:segmentEndPTR)= x;
1054
                end
1055

    
1056
                % estimate efferent effects.
1057
                % ARis based on LSR units. LSR channels are 1:nBF
1058
                if nANfiberTypes>1  % AR is multi-channel only
1059
                    ARAttSeg=sum(ICspikes(1:nBFs,:),1)/ANdt;
1060
                    [ARAttSeg, ARboundary] = ...
1061
                        filter(ARfilt_b, ARfilt_a, ARAttSeg, ARboundary);
1062
                    ARAttSeg=ARAttSeg-ARrateThreshold;
1063
                    ARAttSeg(ARAttSeg<0)=0;   % prevent negative strengths
1064
                    % scale up to dt from ANdt
1065
                    x=    repmat(ARAttSeg, ANspeedUpFactor,1);
1066
                    x=reshape(x,1,segmentLength);
1067
                    ARattenuation(segmentStartPTR:segmentEndPTR)=...
1068
                        (1-ARrateToAttenuationFactor* x);
1069
                    ARattenuation(ARattenuation<0)=0.001;
1070
                else
1071
                    % single channel model; disable AR
1072
                    ARattenuation(segmentStartPTR:segmentEndPTR)=...
1073
                        ones(1,segmentLength);
1074
                end
1075

    
1076
                % MOC attenuation using HSR response only
1077
                % Separate MOC effect for each BF
1078
                HSRbegins=nBFs*(nANfiberTypes-1)+1;
1079
                rates=ICspikes(HSRbegins:end,:)/ANdt;
1080
                for idx=1:nBFs
1081
                    [smoothedRates, MOCboundary{idx}] = ...
1082
                        filter(MOCfilt_b, MOCfilt_a, rates(idx,:), ...
1083
                        MOCboundary{idx});
1084
                    MOCattSegment(idx,:)=smoothedRates;
1085
                    % expand timescale back to model dt from ANdt
1086
                    x= repmat(MOCattSegment(idx,:), ANspeedUpFactor,1);
1087
                    x= reshape(x,1,segmentLength);
1088
                    MOCattenuation(idx,segmentStartPTR:segmentEndPTR)= ...
1089
                        (1- MOCrateToAttenuationFactor*  x);
1090
                end
1091
                MOCattenuation(MOCattenuation<0)=0.04;
1092
                % segment debugging
1093
                % plotInstructions.figureNo=98;
1094
                % plotInstructions.displaydt=ANdt;
1095
                %  plotInstructions.numPlots=1;
1096
                %  plotInstructions.subPlotNo=1;
1097
                % UTIL_plotMatrix(ICspikes, plotInstructions);
1098

    
1099
    end     % AN_spikesOrProbability
1100
    segmentStartPTR=segmentStartPTR+segmentLength;
1101
    reducedSegmentPTR=reducedSegmentPTR+reducedSegmentLength;
1102

    
1103

    
1104
end  % segment
1105

    
1106
path(restorePath)