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 @ 26:b03ef38fe497

History | View | Annotate | Download (43.8 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
if nargin<1
56
    error(' MAP1_14 is not a script but a function that must be called')
57
end
58

    
59
if nargin<6
60
    paramChanges=[];
61
end
62
% Read parameters from MAPparams<***> file in 'parameterStore' folder
63
cmd=['method=MAPparams' MAPparamsName ...
64
    '(BFlist, sampleRate, 0, paramChanges);'];
65
eval(cmd);
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
% save as global for later plotting if required
71
savedBFlist=BFlist;
72
saveAN_spikesOrProbability=AN_spikesOrProbability;
73
saveMAPparamsName=MAPparamsName;
74

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

    
82
% all spiking activity is computed using longer epochs
83
ANspeedUpFactor=AN_IHCsynapseParams.ANspeedUpFactor;  % e.g.5 times
84

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

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

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

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

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

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

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

    
157
OMEhighPassBndry=[];
158

    
159
% OMEampStapes might be reducdant (use OMEParams.stapesScalar)
160
stapesScalar= OMEParams.stapesScalar;
161

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

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

    
176
% save complete OME record (stapes displacement)
177
OMEoutput=zeros(1,signalLength);
178
TMoutput=zeros(1,signalLength);
179

    
180
%% BM ---
181
% BM is represented as a list of locations identified by BF
182
DRNL_BFs=BFlist;
183
nBFs= length(DRNL_BFs);
184

    
185
% DRNLchannelParameters=DRNLParams.channelParameters;
186
DRNLresponse= zeros(nBFs, segmentLength);
187

    
188
MOCrateToAttenuationFactor=DRNLParams.rateToAttenuationFactor;
189
rateToAttenuationFactorProb=DRNLParams.rateToAttenuationFactorProb;
190
MOCrateThresholdProb=DRNLParams.MOCrateThresholdProb;
191

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

    
200
MOCattSegment=zeros(nBFs,reducedSegmentLength);
201
MOCattenuation=ones(nBFs,signalLength);
202

    
203
if DRNLParams.a>0
204
    DRNLcompressionThreshold=10^((1/(1-DRNLParams.c))* ...
205
    log10(DRNLParams.b/DRNLParams.a));
206
else
207
    DRNLcompressionThreshold=inf;
208
end
209

    
210
DRNLlinearOrder= DRNLParams.linOrder;
211
DRNLnonlinearOrder= DRNLParams.nonlinOrder;
212

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

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

    
263
% complete BM record (BM displacement)
264
DRNLoutput=zeros(nBFs, signalLength);
265

    
266

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

    
280
IHCciliaBndry=cell(nBFs,1);
281

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

    
291
IHCGu0 = IHCGa+IHCGmax./(1+exp(IHCu0/IHCs0).*(1+exp(IHCu1/IHCs1)));
292
IHCrestingCiliaCond=IHCGu0;
293

    
294
% Receptor potential
295
IHC_Cab= IHC_cilia_RPParams.Cab;
296
IHC_Gk= IHC_cilia_RPParams.Gk;
297
IHC_Et= IHC_cilia_RPParams.Et;
298
IHC_Ek= IHC_cilia_RPParams.Ek;
299
IHC_Ekp= IHC_Ek+IHC_Et*IHC_cilia_RPParams.Rpc;
300

    
301
IHCrestingV= (IHC_Gk*IHC_Ekp+IHCGu0*IHC_Et)/(IHCGu0+IHC_Gk);
302

    
303
IHC_Vnow= IHCrestingV*ones(nBFs,1); % initial voltage
304
IHC_RP= zeros(nBFs,segmentLength);
305

    
306
% complete record of IHC receptor potential (V)
307
IHCciliaDisplacement= zeros(nBFs,segmentLength);
308
IHCoutput= zeros(nBFs,signalLength);
309
IHC_cilia_output= zeros(nBFs,signalLength);
310

    
311

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

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

    
331
% tauCa vector is established across channels to allow vectorization
332
%  (one tauCa per channel). Do not confuse with tauCas (one pre fiber type)
333
tauCa=repmat(tauCas, nBFs,1);
334
tauCa=reshape(tauCa, nChannels, 1);
335

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

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

    
348

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

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

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

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

    
376
ANprobability=zeros(nChannels,segmentLength);
377
ANprobRateOutput=zeros(nChannels,signalLength);
378
lengthAbsRefractoryP= round(AN_refractory_period/dt);
379
% special variables for monitoring synaptic cleft (specialists only)
380
savePavailableSeg=zeros(nChannels,segmentLength);
381
savePavailable=zeros(nChannels,signalLength);
382

    
383
% spikes     % !  !  !    ! !        !   !  !
384
lengthAbsRefractory= round(AN_refractory_period/ANdt);
385

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

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

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

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

    
407

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

    
420
CNmembranePotential=zeros(nCNneurons,reducedSegmentLength);
421

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

    
435
% input to CN units
436
AN_PSTH=zeros(nCNneurons,reducedSegmentLength);
437

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

    
448
% figure(98), plot(t,CNalphaFunction)
449
% working memory for implementing convolution
450

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

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

    
475
CN_PSTH=zeros(nChannels,reducedSegmentLength);
476
CNoutput=false(nCNneurons,reducedSignalLength);
477

    
478

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

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

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

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

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

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

    
519
ICfiberTypeRates=zeros(nANfiberTypes,reducedSignalLength);
520
ICoutput=false(nChannels,reducedSignalLength);
521

    
522
ICmembranePotential=zeros(nICcells,reducedSegmentLength);
523
ICmembraneOutput=zeros(nICcells,signalLength);
524

    
525

    
526
%% Main program %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%
527

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

    
536
    inputPressureSegment=inputSignal...
537
        (:,segmentStartPTR:segmentStartPTR+segmentLength-1);
538

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

    
543

    
544
    % OME ----------------------
545

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

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

    
573
    % OME stage 4:  apply stapes scalar
574
    stapesDisplacement=stapesDisplacement*stapesScalar;
575

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

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

    
588
    % and save
589
    OMEoutput(segmentStartPTR:segmentEndPTR)= stapesDisplacement;
590

    
591

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

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

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

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

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

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

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

    
650
    % and save it
651
    DRNLoutput(:, segmentStartPTR:segmentEndPTR)= DRNLresponse;
652

    
653

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

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

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

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

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

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

    
692

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

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

    
707
    ICa=   (GmaxCa* mICa.^3) .* (Vsynapse- ECa);
708

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

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

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

    
725

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

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

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

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

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

    
785
            %             plot(MOCattenuation)
786

    
787

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
873

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

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

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

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

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

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

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

    
961

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

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

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

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

    
987

    
988
            %% IC ----------------------------------------------
989
                %  MacGregor or some other second order neurons
990

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

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

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

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

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

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

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

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

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

    
1125
    end     % AN_spikesOrProbability
1126
    segmentStartPTR=segmentStartPTR+segmentLength;
1127
    reducedSegmentPTR=reducedSegmentPTR+reducedSegmentLength;
1128

    
1129

    
1130
end  % segment
1131

    
1132
%% apply refractory correction to spike probabilities
1133

    
1134
% switch AN_spikesOrProbability
1135
%     case 'probability'
1136
%         ANprobOutput=ANprobRateOutput*dt;
1137
%         [r c]=size(ANprobOutput);
1138
%         % find probability of no spikes in refractory period
1139
%         pNoSpikesInRefrac=ones(size(ANprobOutput));
1140
%         pSpike=zeros(size(ANprobOutput));
1141
%         for epochNo=lengthAbsRefractoryP+2:c
1142
%             pNoSpikesInRefrac(:,epochNo)=...
1143
%                 pNoSpikesInRefrac(:,epochNo-2)...
1144
%                 .*(1-pSpike(:,epochNo-1))...
1145
%                 ./(1-pSpike(:,epochNo-lengthAbsRefractoryP-1));
1146
%             pSpike(:,epochNo)= ANprobOutput(:,epochNo)...
1147
%                 .*pNoSpikesInRefrac(:,epochNo);
1148
%         end
1149
%         ANprobRateOutput=pSpike/dt;
1150
% end
1151

    
1152
path(restorePath)