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 / temp.m @ 30:1a502830d462

History | View | Annotate | Download (42.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=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
MOCrateThreshold=DRNLParams.MOCrateThreshold;
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

    
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
tauCas= IHCpreSynapseParams.tauCa;
321
nChannels= nANfiberTypes*nBFs;
322
synapticCa= zeros(nChannels,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(nChannels,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 tauCas (one pre fiber type)
336
tauCa=repmat(tauCas, nBFs,1);
337
tauCa=reshape(tauCa, nChannels, 1);
338

    
339
% presynapse startup values (vectors, length:nChannels)
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= nChannels*nFibersPerChannel;
358

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

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

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

    
378
ANprobability=zeros(nChannels,segmentLength);
379
ANprobRateOutput=zeros(nChannels,signalLength);
380
% special variables for monitoring synaptic cleft (specialists only)
381
savePavailableSeg=zeros(nChannels,segmentLength);
382
savePavailable=zeros(nChannels,signalLength);
383

    
384
% spikes     % !  !  !    ! !        !   !  !
385
AN_refractory_period= AN_IHCsynapseParams.refractory_period;
386
lengthAbsRefractory= round(AN_refractory_period/ANdt);
387

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

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

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

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

    
409

    
410
%% CN (first brain stem nucleus - could be any subdivision of CN)
411
% Input to a CN neuorn is a random selection of AN fibers within a channel
412
%  The number of AN fibers used is ANfibersFanInToCN
413
ANfibersFanInToCN=MacGregorMultiParams.fibersPerNeuron;
414
nCNneuronsPerChannel=MacGregorMultiParams.nNeuronsPerBF;
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
CNtauGk=MacGregorMultiParams.tauGk;
418
ANavailableFibersPerChan=AN_IHCsynapseParams.numFibers;
419
nCNneurons=nCNneuronsPerChannel*nChannels;
420
% nCNneuronsPerFiberType= nCNneurons/nANfiberTypes;
421

    
422
CNmembranePotential=zeros(nCNneurons,reducedSegmentLength);
423

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

    
437
% input to CN units
438
AN_PSTH=zeros(nCNneurons,reducedSegmentLength);
439

    
440
% Generate CNalphaFunction function
441
%  by which spikes are converted to post-synaptic currents
442
CNdendriteLPfreq= MacGregorMultiParams.dendriteLPfreq;
443
CNcurrentPerSpike=MacGregorMultiParams.currentPerSpike;
444
CNspikeToCurrentTau=1/(2*pi*CNdendriteLPfreq);
445
t=ANdt:ANdt:5*CNspikeToCurrentTau;
446
CNalphaFunction= (1 / ...
447
    CNspikeToCurrentTau)*t.*exp(-t /CNspikeToCurrentTau);
448
CNalphaFunction=CNalphaFunction*CNcurrentPerSpike;
449

    
450
% figure(98), plot(t,CNalphaFunction)
451
% working memory for implementing convolution
452

    
453
CNcurrentTemp=...
454
    zeros(nCNneurons,reducedSegmentLength+length(CNalphaFunction)-1);
455
% trailing alphas are parts of humps carried forward to the next segment
456
CNtrailingAlphas=zeros(nCNneurons,length(CNalphaFunction));
457

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

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

    
480

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

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

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

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

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

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

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

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

    
527

    
528
%% Main program %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%
529

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

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

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

    
545

    
546
    % OME ----------------------
547

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

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

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

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

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

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

    
593

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

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

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

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

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

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

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

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

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

    
656

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

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

    
673
    % compute apical conductance
674
    G=IHCGmax./(1+exp(-(IHCciliaDisplacement-IHCu0)/IHCs0).*...
675
        (1+exp(-(IHCciliaDisplacement-IHCu1)/IHCs1)));
676
    Gu=G + IHCGa;
677

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

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

    
692
    % and save it
693
    IHCoutput(:, segmentStartPTR:segmentStartPTR+segmentLength-1)=IHC_RP;
694

    
695

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

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

    
710
    ICa=   (GmaxCa* mICa.^3) .* (Vsynapse- ECa);
711

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

    
718
    % NB vesicleReleaseRate is /s and is independent of dt
719
    vesicleReleaseRate = synapse_z * synapticCa.^synapse_power; % rate
720

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

    
728

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

    
740
                ANprobability(:,t)= min(Pejected,1);
741
                reuptakeandlost= PAN_rdt_plus_ldt .* Pcleft;
742
                reuptake= PAN_rdt.* Pcleft;
743

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

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

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

    
784

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

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

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

    
806
                % slow line
807
%                 probabilities= 1-(1-releaseProb).^AN_available;
808
                probabilities= 1-intpow((1-releaseProb), AN_available);
809
                ejected= probabilities> rand(length(AN_available),1);
810

    
811
                reuptakeandlost = AN_rdt_plus_ldt .* AN_cleft;
812
                reuptake = AN_rdt.* AN_cleft;
813

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

    
819
                % slow line
820
%                 probabilities= 1-(1-AN_ydt).^M_q;
821
                 probabilities= 1-intpow((1-AN_ydt), M_q);
822

    
823
                replenish= probabilities>rand(length(M_q),1);
824

    
825
                AN_available = AN_available + replenish - ejected ...
826
                    + reprocessed;
827
                AN_cleft = AN_cleft + ejected - reuptakeandlost;
828
                AN_reprocess = AN_reprocess + reuptake - reprocessed;
829

    
830
                % ANspikes is logical record of vesicle release events>0
831
                ANspikes(:, ANtimeCount)= ejected;
832
            end % t
833

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

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

    
860
            % segment debugging
861
            % plotInstructions.figureNo=98;
862
            % plotInstructions.displaydt=ANdt;
863
            %  plotInstructions.numPlots=1;
864
            %  plotInstructions.subPlotNo=1;
865
            % UTIL_plotMatrix(ANspikes, plotInstructions);
866

    
867
            % and save it. NB, AN is now on 'speedUp' time
868
            ANoutput(:, reducedSegmentPTR: shorterSegmentEndPTR)=ANspikes;
869

    
870

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

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

    
891
            % One alpha function per spike
892
            [alphaRows alphaCols]=size(CNtrailingAlphas);
893

    
894
            for unitNo=1:nCNneurons
895
                CNcurrentTemp(unitNo,:)= ...
896
                    conv(AN_PSTH(unitNo,:),CNalphaFunction);
897
            end
898
%             disp(['sum(AN_PSTH)= ' num2str(sum(AN_PSTH(1,:)))])
899
            % add post-synaptic current  left over from previous segment
900
            CNcurrentTemp(:,1:alphaCols)=...
901
                CNcurrentTemp(:,1:alphaCols)+ CNtrailingAlphas;
902

    
903
            % take post-synaptic current for this segment
904
            CNcurrentInput= CNcurrentTemp(:, 1:reducedSegmentLength);
905
%                 disp(['mean(CNcurrentInput)= ' num2str(mean(CNcurrentInput(1,:)))])
906

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

    
912
            if CN_c>0
913
                % variable threshold condition (slow)
914
                for t=1:reducedSegmentLength
915
                    CNtimeSinceLastSpike=CNtimeSinceLastSpike-ANdt;
916
                    s=CN_E>CN_Th & CNtimeSinceLastSpike<0 ;
917
                    CNtimeSinceLastSpike(s)=0.0005;         % 0.5 ms for sodium spike
918
                    dE =(-CN_E/CN_tauM + ...
919
                        CNcurrentInput(:,t)/CN_cap+(...
920
                        CN_Gk/CN_cap).*(CN_Ek-CN_E))*ANdt;
921
                    dGk=-CN_Gk*ANdt./tauGk + CN_b*s;
922
                    dTh=-(CN_Th-CN_Th0)*ANdt/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
                E=zeros(1,reducedSegmentLength);
931
                Gk=zeros(1,reducedSegmentLength);
932
                ss=zeros(1,reducedSegmentLength);
933
                for t=1:reducedSegmentLength
934
                    % time of previous spike moves back in time
935
                    CNtimeSinceLastSpike=CNtimeSinceLastSpike-ANdt;
936
                    % action potential if E>threshold
937
                    %  allow time for s to reset between events
938
                    s=CN_E>CN_Th0 & CNtimeSinceLastSpike<0 ;  
939
                    ss(t)=s(1);
940
                    CNtimeSinceLastSpike(s)=0.0005; % 0.5 ms for sodium spike
941
                    dE = (-CN_E/CN_tauM + ...
942
                        CNcurrentInput(:,t)/CN_cap +...
943
                        (CN_Gk/CN_cap).*(CN_Ek-CN_E))*ANdt;
944
                    dGk=-CN_Gk*ANdt./tauGk +CN_b*s;
945
                    CN_E=CN_E+dE;
946
                    CN_Gk=CN_Gk+dGk;
947
                    E(t)=CN_E(1);
948
                    Gk(t)=CN_Gk(1);
949
                    % add spike to CN_E and add resting potential (-60 mV)
950
                    CNmembranePotential(:,t)=CN_E +s.*(CN_Eb-CN_E)+CN_Er;
951
                end
952
            end
953
%             disp(['CN_E= ' num2str(sum(CN_E(1,:)))])
954
%             disp(['CN_Gk= ' num2str(sum(CN_Gk(1,:)))])
955
%             disp(['CNmembranePotential= ' num2str(sum(CNmembranePotential(1,:)))])
956
%             plot(CNmembranePotential(1,:))
957

    
958

    
959
            % extract spikes.  A spike is a substantial upswing in voltage
960
            CN_spikes=CNmembranePotential> -0.02;
961
%             disp(['CNspikesbefore= ' num2str(sum(sum(CN_spikes)))])
962

    
963
            % now remove any spike that is immediately followed by a spike
964
            % NB 'find' works on columns (whence the transposing)
965
            % for each spike put a zero in the next epoch
966
            CN_spikes=CN_spikes';
967
            idx=find(CN_spikes);
968
            idx=idx(1:end-1);
969
            CN_spikes(idx+1)=0;
970
            CN_spikes=CN_spikes';
971
%             disp(['CNspikes= ' num2str(sum(sum(CN_spikes)))])
972

    
973
            % segment debugging
974
            % plotInstructions.figureNo=98;
975
            % plotInstructions.displaydt=ANdt;
976
            %  plotInstructions.numPlots=1;
977
            %  plotInstructions.subPlotNo=1;
978
            % UTIL_plotMatrix(CN_spikes, plotInstructions);
979

    
980
            % and save it
981
            CNoutput(:, reducedSegmentPTR:shorterSegmentEndPTR)=...
982
                CN_spikes;
983

    
984

    
985
            %% IC ----------------------------------------------
986
                %  MacGregor or some other second order neurons
987

    
988
                % combine CN neurons in same channel, i.e. same BF & same tauCa
989
                %  to generate inputs to single IC unit
990
                channelNo=0;
991
                for idx=1:nCNneuronsPerChannel:nCNneurons-nCNneuronsPerChannel+1;
992
                    channelNo=channelNo+1;
993
                    CN_PSTH(channelNo,:)=...
994
                        sum(CN_spikes(idx:idx+nCNneuronsPerChannel-1,:));
995
                end
996

    
997
                [alphaRows alphaCols]=size(ICtrailingAlphas);
998
                for ICneuronNo=1:nICcells
999
                    ICcurrentTemp(ICneuronNo,:)= ...
1000
                        conv(CN_PSTH(ICneuronNo,:),  IC_CNalphaFunction);
1001
                end
1002

    
1003
                % add the unused current from the previous convolution
1004
                ICcurrentTemp(:,1:alphaCols)=ICcurrentTemp(:,1:alphaCols)...
1005
                    + ICtrailingAlphas;
1006
                % take what is required and keep the trailing part for next time
1007
                inputCurrent=ICcurrentTemp(:, 1:reducedSegmentLength);
1008
                ICtrailingAlphas=ICcurrentTemp(:, reducedSegmentLength+1:end);
1009

    
1010
                if IC_c==0
1011
                    % faster computation when threshold is stable (C==0)
1012
                    for t=1:reducedSegmentLength
1013
                        s=IC_E>IC_Th0;
1014
                        dE = (-IC_E/IC_tauM + inputCurrent(:,t)/IC_cap +...
1015
                            (IC_Gk/IC_cap).*(IC_Ek-IC_E))*ANdt;
1016
                        dGk=-IC_Gk*ANdt/IC_tauGk +IC_b*s;
1017
                        IC_E=IC_E+dE;
1018
                        IC_Gk=IC_Gk+dGk;
1019
                        ICmembranePotential(:,t)=IC_E+s.*(IC_Eb-IC_E)+IC_Er;
1020
                    end
1021
                else
1022
                    %  threshold is changing (IC_c>0; e.g. bushy cell)
1023
                    for t=1:reducedSegmentLength
1024
                        dE = (-IC_E/IC_tauM + ...
1025
                            inputCurrent(:,t)/IC_cap + (IC_Gk/IC_cap)...
1026
                            .*(IC_Ek-IC_E))*ANdt;
1027
                        IC_E=IC_E+dE;
1028
                        s=IC_E>IC_Th;
1029
                        ICmembranePotential(:,t)=IC_E+s.*(IC_Eb-IC_E)+IC_Er;
1030
                        dGk=-IC_Gk*ANdt/IC_tauGk +IC_b*s;
1031
                        IC_Gk=IC_Gk+dGk;
1032

    
1033
                        % After a spike, the threshold is raised
1034
                        % otherwise it settles to its baseline
1035
                        dTh=-(IC_Th-Th0)*ANdt/IC_tauTh +s*IC_c;
1036
                        IC_Th=IC_Th+dTh;
1037
                    end
1038
                end
1039

    
1040
                ICspikes=ICmembranePotential> -0.01;
1041
                % now remove any spike that is immediately followed by a spike
1042
                % NB 'find' works on columns (whence the transposing)
1043
                ICspikes=ICspikes';
1044
                idx=find(ICspikes);
1045
                idx=idx(1:end-1);
1046
                ICspikes(idx+1)=0;
1047
                ICspikes=ICspikes';
1048

    
1049
                nCellsPerTau= nICcells/nANfiberTypes;
1050
                firstCell=1;
1051
                lastCell=nCellsPerTau;
1052
                for tauCount=1:nANfiberTypes
1053
                    % separate rates according to fiber types
1054
                    % currently only the last segment is saved
1055
                    ICfiberTypeRates(tauCount, ...
1056
                        reducedSegmentPTR:shorterSegmentEndPTR)=...
1057
                        sum(ICspikes(firstCell:lastCell, :))...
1058
                        /(nCellsPerTau*ANdt);
1059
                    firstCell=firstCell+nCellsPerTau;
1060
                    lastCell=lastCell+nCellsPerTau;
1061
                end
1062
                
1063
                ICoutput(:,reducedSegmentPTR:shorterSegmentEndPTR)=ICspikes;
1064
                
1065
                % store membrane output on original dt scale
1066
                if nBFs==1  % single channel
1067
                    x= repmat(ICmembranePotential(1,:), ANspeedUpFactor,1);
1068
                    x= reshape(x,1,segmentLength);
1069
                    if nANfiberTypes>1  % save HSR and LSR
1070
                        y=repmat(ICmembranePotential(end,:),...
1071
                            ANspeedUpFactor,1);
1072
                        y= reshape(y,1,segmentLength);
1073
                        x=[x; y];
1074
                    end
1075
                    ICmembraneOutput(:, segmentStartPTR:segmentEndPTR)= x;
1076
                end
1077

    
1078
                % estimate efferent effects.
1079
                % ARis based on LSR units. LSR channels are 1:nBF
1080
                if nANfiberTypes>1  % AR is multi-channel only
1081
                    ARAttSeg=sum(ICspikes(1:nBFs,:),1)/ANdt;
1082
                    [ARAttSeg, ARboundary] = ...
1083
                        filter(ARfilt_b, ARfilt_a, ARAttSeg, ARboundary);
1084
                    ARAttSeg=ARAttSeg-ARrateThreshold;
1085
                    ARAttSeg(ARAttSeg<0)=0;   % prevent negative strengths
1086
                    % scale up to dt from ANdt
1087
                    x=    repmat(ARAttSeg, ANspeedUpFactor,1);
1088
                    x=reshape(x,1,segmentLength);
1089
                    ARattenuation(segmentStartPTR:segmentEndPTR)=...
1090
                        (1-ARrateToAttenuationFactor* x);
1091
                    ARattenuation(ARattenuation<0)=0.001;
1092
                else
1093
                    % single channel model; disable AR
1094
                    ARattenuation(segmentStartPTR:segmentEndPTR)=...
1095
                        ones(1,segmentLength);
1096
                end
1097

    
1098
                % MOC attenuation using HSR response only
1099
                % Separate MOC effect for each BF
1100
                HSRbegins=nBFs*(nANfiberTypes-1)+1;
1101
                rates=ICspikes(HSRbegins:end,:)/ANdt;
1102
                for idx=1:nBFs
1103
                    [smoothedRates, MOCboundary{idx}] = ...
1104
                        filter(MOCfilt_b, MOCfilt_a, rates(idx,:), ...
1105
                        MOCboundary{idx});
1106
                    MOCattSegment(idx,:)=smoothedRates;
1107
                    % expand timescale back to model dt from ANdt
1108
                    x= repmat(MOCattSegment(idx,:), ANspeedUpFactor,1);
1109
                    x= reshape(x,1,segmentLength);
1110
                    MOCattenuation(idx,segmentStartPTR:segmentEndPTR)= ...
1111
                        (1- MOCrateToAttenuationFactor*  x);
1112
                end
1113
                MOCattenuation(MOCattenuation<0)=0.04;
1114
                % segment debugging
1115
                % plotInstructions.figureNo=98;
1116
                % plotInstructions.displaydt=ANdt;
1117
                %  plotInstructions.numPlots=1;
1118
                %  plotInstructions.subPlotNo=1;
1119
                % UTIL_plotMatrix(ICspikes, plotInstructions);
1120

    
1121
    end     % AN_spikesOrProbability
1122
    segmentStartPTR=segmentStartPTR+segmentLength;
1123
    reducedSegmentPTR=reducedSegmentPTR+reducedSegmentLength;
1124

    
1125

    
1126
end  % segment
1127

    
1128
path(restorePath)