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 @ 23:6cce421531e2

History | View | Annotate | Download (43 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
    inputPressureSegment=inputSignal...
539
        (:,segmentStartPTR:segmentStartPTR+segmentLength-1);
540

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

    
545

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

    
548
    % OME Stage 1: external resonances. Add to inputSignal pressure wave
549
    y=inputPressureSegment;
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
            inputPressureSegment, OMEExtFilterBndry{n});
555
        x= x* OMEgainScalars(n);
556
        % This is a parallel resonance so add it
557
        y=y+x;
558
    end
559
    inputPressureSegment=y;
560
    OMEextEarPressure(segmentStartPTR:segmentEndPTR)= inputPressureSegment;
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,inputPressureSegment, ...
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
        % apply MOC to nonlinear input function       
614
        nonlinOutput=stapesDisplacement.* MOC;
615

    
616
        %       first gammatone filter (nonlin path)
617
        for order = 1 : GTnonlinOrder
618
            [nonlinOutput GTnonlinBdry1{BFno,order}] = ...
619
                filter(GTnonlin_b(BFno,:), GTnonlin_a(BFno,:), ...
620
                nonlinOutput, GTnonlinBdry1{BFno,order});
621
        end
622
        %       broken stick instantaneous compression
623
        y= nonlinOutput.* DRNLa;  % linear section.
624
        % compress parts of the signal above the compression threshold
625
        abs_x = abs(nonlinOutput);
626
        idx=find(abs_x>DRNLcompressionThreshold);
627
        if ~isempty(idx)>0
628
            y(idx)=sign(y(idx)).* (DRNLb*abs_x(idx).^DRNLc);
629
        end
630
        nonlinOutput=y;
631

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

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

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

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

    
655

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

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

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

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

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

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

    
694

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

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

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

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

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

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

    
727

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

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

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

    
757
            % Estimate efferent effects. ARattenuation (0 <> 1)
758
            %  acoustic reflex
759
            [r c]=size(ANrate);
760
            if r>nBFs % Only if LSR fibers are computed
761
                ARAttSeg=mean(ANrate(1:nBFs,:),1); %LSR channels are 1:nBF
762
                % smooth
763
                [ARAttSeg, ARboundaryProb] = ...
764
                    filter(ARfilt_b, ARfilt_a, ARAttSeg, ARboundaryProb);
765
                ARAttSeg=ARAttSeg-ARrateThreshold;
766
                ARAttSeg(ARAttSeg<0)=0;   % prevent negative strengths
767
                ARattenuation(segmentStartPTR:segmentEndPTR)=...
768
                    (1-ARrateToAttenuationFactorProb.* ARAttSeg);
769
            end
770
            %             plot(ARattenuation)
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
            %             plot(MOCattenuation)
788

    
789

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

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

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

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

    
816
                reuptakeandlost = AN_rdt_plus_ldt .* AN_cleft;
817
                reuptake = AN_rdt.* AN_cleft;
818

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

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

    
828
                replenish= probabilities>rand(length(M_q),1);
829

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

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

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

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

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

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

    
875

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

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

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

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

    
908
            % take post-synaptic current for this segment
909
            CNcurrentInput= CNcurrentTemp(:, 1:reducedSegmentLength);
910
%                 disp(['mean(CNcurrentInput)= ' num2str(mean(CNcurrentInput(1,:)))])
911

    
912
            % trailingalphas are the ends of the alpha functions that
913
            % spill over into the next segment
914
            CNtrailingAlphas= ...
915
                CNcurrentTemp(:, reducedSegmentLength+1:end);
916

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

    
963

    
964
            % extract spikes.  A spike is a substantial upswing in voltage
965
            CN_spikes=CNmembranePotential> -0.02;
966
%             disp(['CNspikesbefore= ' num2str(sum(sum(CN_spikes)))])
967

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

    
978
            % segment debugging
979
            % plotInstructions.figureNo=98;
980
            % plotInstructions.displaydt=ANdt;
981
            %  plotInstructions.numPlots=1;
982
            %  plotInstructions.subPlotNo=1;
983
            % UTIL_plotMatrix(CN_spikes, plotInstructions);
984

    
985
            % and save it
986
            CNoutput(:, reducedSegmentPTR:shorterSegmentEndPTR)=...
987
                CN_spikes;
988

    
989

    
990
            %% IC ----------------------------------------------
991
                %  MacGregor or some other second order neurons
992

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

    
1002
                [alphaRows alphaCols]=size(ICtrailingAlphas);
1003
                for ICneuronNo=1:nICcells
1004
                    ICcurrentTemp(ICneuronNo,:)= ...
1005
                        conv(CN_PSTH(ICneuronNo,:),  IC_CNalphaFunction);
1006
                end
1007

    
1008
                % add the unused current from the previous convolution
1009
                ICcurrentTemp(:,1:alphaCols)=ICcurrentTemp(:,1:alphaCols)...
1010
                    + ICtrailingAlphas;
1011
                % take what is required and keep the trailing part for next time
1012
                inputCurrent=ICcurrentTemp(:, 1:reducedSegmentLength);
1013
                ICtrailingAlphas=ICcurrentTemp(:, reducedSegmentLength+1:end);
1014

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

    
1038
                        % After a spike, the threshold is raised
1039
                        % otherwise it settles to its baseline
1040
                        dTh=-(IC_Th-Th0)*ANdt/IC_tauTh +s*IC_c;
1041
                        IC_Th=IC_Th+dTh;
1042
                    end
1043
                end
1044

    
1045
                ICspikes=ICmembranePotential> -0.01;
1046
                % now remove any spike that is immediately followed by a spike
1047
                % NB 'find' works on columns (whence the transposing)
1048
                ICspikes=ICspikes';
1049
                idx=find(ICspikes);
1050
                idx=idx(1:end-1);
1051
                ICspikes(idx+1)=0;
1052
                ICspikes=ICspikes';
1053

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

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

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

    
1127
    end     % AN_spikesOrProbability
1128
    segmentStartPTR=segmentStartPTR+segmentLength;
1129
    reducedSegmentPTR=reducedSegmentPTR+reducedSegmentLength;
1130

    
1131

    
1132
end  % segment
1133

    
1134
path(restorePath)