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

History | View | Annotate | Download (43.4 KB)

1

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

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

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

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

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

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

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

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

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

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

    
55

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

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

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

    
70
% now accept last mintue parameter changes required by the calling program
71
if nargin>5 && ~isempty(paramChanges)
72
    nChanges=length(paramChanges);
73
    for idx=1:nChanges
74
        eval(paramChanges{idx})
75
    end
76
end
77

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

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

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

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

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

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

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

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

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

    
160
OMEhighPassBndry=[];
161

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

    
165
% Acoustic reflex
166
efferentDelayPts=round(OMEParams.ARdelay/dt);
167
% smoothing filter
168
% Nyquist=(1/ANdt)/2;
169
% [ARfilt_b,ARfilt_a] = butter(1, (1/(2*pi*OMEParams.ARtau))/Nyquist, 'low');
170
a1=dt/OMEParams.ARtau-1; a0=1;
171
b0=1+ a1;
172
ARfilt_b=b0; ARfilt_a=[a0 a1];
173

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

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

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

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

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

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

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

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

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

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

    
254
% nonlinear gammatone filter coefficients 
255
bw=DRNLParams.nlBWs';
256
phi = 2 * pi * bw * dt;
257
cf=DRNLParams.nonlinCFs';
258
theta = 2 * pi * cf * dt;
259
cos_theta = cos(theta);
260
sin_theta = sin(theta);
261
alpha = -exp(-phi).* cos_theta;
262
b0 = ones(nBFs,1);
263
b1 = 2 * alpha;
264
b2 = exp(-2 * phi);
265
z1 = (1 + alpha .* cos_theta) - (alpha .* sin_theta) * i;
266
z2 = (1 + b1 .* cos_theta) - (b1 .* sin_theta) * i;
267
z3 = (b2 .* cos(2 * theta)) - (b2 .* sin(2 * theta)) * i;
268
tf = (z2 + z3) ./ z1;
269
a0 = abs(tf);
270
a1 = alpha .* a0;
271
GTnonlin_a = [b0, b1, b2];
272
GTnonlin_b = [a0, a1];
273
GTnonlinOrder=DRNLnonlinearOrder;
274
firstGTnonlinBdry1=cell(nBFs);
275
firstGTnonlinBdry2=cell(nBFs);
276
firstGTnonlinBdry3=cell(nBFs);
277
firstGTnonlinBdry1out=cell(nBFs);
278
firstGTnonlinBdry2out=cell(nBFs);
279
firstGTnonlinBdry3out=cell(nBFs);
280

    
281
secondGTnonlinBdry1=cell(nBFs);
282
secondGTnonlinBdry2=cell(nBFs);
283
secondGTnonlinBdry3=cell(nBFs);
284
secondGTnonlinBdry1out=cell(nBFs);
285
secondGTnonlinBdry2out=cell(nBFs);
286
secondGTnonlinBdry3out=cell(nBFs);
287

    
288
% complete BM record (BM displacement)
289
DRNLoutput=zeros(nBFs, signalLength);
290

    
291

    
292
%% IHC ---
293
% IHC cilia activity and receptor potential
294
% viscous coupling between BM and stereocilia displacement
295
% Nyquist=sampleRate/2;
296
% IHCcutoff=1/(2*pi*IHC_cilia_RPParams.tc);
297
% [IHCciliaFilter_b,IHCciliaFilter_a]=...
298
%     butter(1, IHCcutoff/Nyquist, 'high');
299
a1=dt/IHC_cilia_RPParams.tc-1; a0=1;
300
b0=1+ a1;
301
% high pass (i.e. low pass reversed)
302
IHCciliaFilter_b=[a0 a1]; IHCciliaFilter_a=b0;
303
% figure(9), freqz(IHCciliaFilter_b, IHCciliaFilter_a)
304

    
305
IHCciliaBndry=cell(nBFs,1);
306

    
307
% IHC apical conductance (Boltzman function)
308
IHC_C= IHC_cilia_RPParams.C;
309
IHCu0= IHC_cilia_RPParams.u0;
310
IHCu1= IHC_cilia_RPParams.u1;
311
IHCs0= IHC_cilia_RPParams.s0;
312
IHCs1= IHC_cilia_RPParams.s1;
313
IHCGmax= IHC_cilia_RPParams.Gmax;
314
IHCGa= IHC_cilia_RPParams.Ga; % (leakage)
315

    
316
IHCGu0 = IHCGa+IHCGmax./(1+exp(IHCu0/IHCs0).*(1+exp(IHCu1/IHCs1)));
317

    
318
% Receptor potential
319
IHC_Cab= IHC_cilia_RPParams.Cab;
320
IHC_Gk= IHC_cilia_RPParams.Gk;
321
IHC_Et= IHC_cilia_RPParams.Et;
322
IHC_Ek= IHC_cilia_RPParams.Ek;
323
IHC_Ekp= IHC_Ek+IHC_Et*IHC_cilia_RPParams.Rpc;
324

    
325
IHCrestingV= (IHC_Gk*IHC_Ekp+IHCGu0*IHC_Et)/(IHCGu0+IHC_Gk);
326

    
327
IHC_Vnow= IHCrestingV*ones(nBFs,1); % initial voltage
328
IHC_RP= zeros(nBFs,segmentLength);
329

    
330
% complete record of IHC receptor potential (V)
331
IHCciliaDisplacement= zeros(nBFs,segmentLength);
332
IHCoutput= zeros(nBFs,signalLength);
333
IHC_cilia_output= zeros(nBFs,signalLength);
334

    
335

    
336
%% pre-synapse ---
337
% Each BF is replicated using a different fiber type to make a 'channel'
338
% The number of channels is nBFs x nANfiberTypes
339
% Fiber types are specified in terms of tauCa
340
nANfiberTypes= length(IHCpreSynapseParams.tauCa);
341
tauCas= IHCpreSynapseParams.tauCa;
342
nChannels= nANfiberTypes*nBFs;
343
synapticCa= zeros(nChannels,segmentLength);
344

    
345
% Calcium control (more calcium, greater release rate)
346
ECa=IHCpreSynapseParams.ECa;
347
gamma=IHCpreSynapseParams.gamma;
348
beta=IHCpreSynapseParams.beta;
349
tauM=IHCpreSynapseParams.tauM;
350
mICa=zeros(nChannels,segmentLength);
351
GmaxCa=IHCpreSynapseParams.GmaxCa;
352
synapse_z= IHCpreSynapseParams.z;
353
synapse_power=IHCpreSynapseParams.power;
354

    
355
% tauCa vector is established across channels to allow vectorization
356
%  (one tauCa per channel). Do not confuse with tauCas (one pre fiber type)
357
tauCa=repmat(tauCas, nBFs,1);
358
tauCa=reshape(tauCa, nChannels, 1);
359

    
360
% presynapse startup values (vectors, length:nChannels)
361
% proportion (0 - 1) of Ca channels open at IHCrestingV
362
mICaCurrent=((1+beta^-1 * exp(-gamma*IHCrestingV))^-1)...
363
    *ones(nBFs*nANfiberTypes,1);
364
% corresponding startup currents
365
ICaCurrent= (GmaxCa*mICaCurrent.^3) * (IHCrestingV-ECa);
366
CaCurrent= ICaCurrent.*tauCa;
367

    
368
% vesicle release rate at startup (one per channel)
369
% kt0 is used only at initialisation
370
kt0= -synapse_z * CaCurrent.^synapse_power;
371

    
372

    
373
%% AN ---
374
% each row of the AN matrices represents one AN fiber
375
% The results computed either for probabiities *or* for spikes (not both)
376
% Spikes are necessary if CN and IC are to be computed
377
nFibersPerChannel= AN_IHCsynapseParams.numFibers;
378
nANfibers= nChannels*nFibersPerChannel;
379

    
380
y=AN_IHCsynapseParams.y;
381
l=AN_IHCsynapseParams.l;
382
x=AN_IHCsynapseParams.x;
383
r=AN_IHCsynapseParams.r;
384
M=round(AN_IHCsynapseParams.M);
385

    
386
% probability            (NB initial 'P' on everything)
387
PAN_ydt = repmat(AN_IHCsynapseParams.y*dt, nChannels,1);
388
PAN_ldt = repmat(AN_IHCsynapseParams.l*dt, nChannels,1);
389
PAN_xdt = repmat(AN_IHCsynapseParams.x*dt, nChannels,1);
390
PAN_rdt = repmat(AN_IHCsynapseParams.r*dt, nChannels,1);
391
PAN_rdt_plus_ldt = PAN_rdt + PAN_ldt;
392
PAN_M=round(AN_IHCsynapseParams.M);
393

    
394
% compute starting values
395
Pcleft    = kt0* y* M ./ (y*(l+r)+ kt0* l);
396
Pavailable    = Pcleft*(l+r)./kt0;
397
Preprocess    = Pcleft*r/x; % canbe fractional
398

    
399
ANprobability=zeros(nChannels,segmentLength);
400
ANprobRateOutput=zeros(nChannels,signalLength);
401
% special variables for monitoring synaptic cleft (specialists only)
402
savePavailableSeg=zeros(nChannels,segmentLength);
403
savePavailable=zeros(nChannels,signalLength);
404

    
405
% spikes     % !  !  !    ! !        !   !  !
406
AN_refractory_period= AN_IHCsynapseParams.refractory_period;
407
lengthAbsRefractory= round(AN_refractory_period/ANdt);
408

    
409
AN_ydt= repmat(AN_IHCsynapseParams.y*ANdt, nANfibers,1);
410
AN_ldt= repmat(AN_IHCsynapseParams.l*ANdt, nANfibers,1);
411
AN_xdt= repmat(AN_IHCsynapseParams.x*ANdt, nANfibers,1);
412
AN_rdt= repmat(AN_IHCsynapseParams.r*ANdt, nANfibers,1);
413
AN_rdt_plus_ldt= AN_rdt + AN_ldt;
414
AN_M= round(AN_IHCsynapseParams.M);
415

    
416
% kt0  is initial release rate
417
% Establish as a vector (length=channel x number of fibers)
418
kt0= repmat(kt0', nFibersPerChannel, 1);
419
kt0=reshape(kt0, nANfibers,1);
420

    
421
% starting values for reservoirs
422
AN_cleft    = kt0* y* M ./ (y*(l+r)+ kt0* l);
423
AN_available    = round(AN_cleft*(l+r)./kt0); %must be integer
424
AN_reprocess    = AN_cleft*r/x;
425

    
426
% output is in a logical array spikes = 1/ 0.
427
ANspikes= false(nANfibers,reducedSegmentLength);
428
ANoutput= false(nANfibers,reducedSignalLength);
429

    
430

    
431
%% CN (first brain stem nucleus - could be any subdivision of CN)
432
% Input to a CN neuorn is a random selection of AN fibers within a channel
433
%  The number of AN fibers used is ANfibersFanInToCN
434
ANfibersFanInToCN=MacGregorMultiParams.fibersPerNeuron;
435
nCNneuronsPerChannel=MacGregorMultiParams.nNeuronsPerBF;
436
% CNtauGk (Potassium time constant) determines the rate of firing of
437
%  the unit when driven hard by a DC input (not normally >350 sp/s)
438
CNtauGk=MacGregorMultiParams.tauGk;
439
ANavailableFibersPerChan=AN_IHCsynapseParams.numFibers;
440
nCNneurons=nCNneuronsPerChannel*nChannels;
441
% nCNneuronsPerFiberType= nCNneurons/nANfiberTypes;
442

    
443
CNmembranePotential=zeros(nCNneurons,reducedSegmentLength);
444

    
445
% establish which ANfibers (by name) feed into which CN nuerons
446
CNinputfiberLists=zeros(nChannels*nCNneuronsPerChannel, ANfibersFanInToCN);
447
unitNo=1;
448
for ch=1:nChannels
449
    % Each channel contains a number of units =length(listOfFanInValues)
450
    for idx=1:nCNneuronsPerChannel
451
        fibersUsed=(ch-1)*ANavailableFibersPerChan + ...
452
            ceil(rand(1,ANfibersFanInToCN)* ANavailableFibersPerChan);
453
        CNinputfiberLists(unitNo,:)=fibersUsed;
454
        unitNo=unitNo+1;
455
    end
456
end
457

    
458
% input to CN units
459
AN_PSTH=zeros(nCNneurons,reducedSegmentLength);
460

    
461
% Generate CNalphaFunction function
462
%  by which spikes are converted to post-synaptic currents
463
CNdendriteLPfreq= MacGregorMultiParams.dendriteLPfreq;
464
CNcurrentPerSpike=MacGregorMultiParams.currentPerSpike;
465
CNspikeToCurrentTau=1/(2*pi*CNdendriteLPfreq);
466
t=ANdt:ANdt:5*CNspikeToCurrentTau;
467
CNalphaFunction=...
468
    (CNcurrentPerSpike/CNspikeToCurrentTau)*t.*exp(-t/CNspikeToCurrentTau);
469
% figure(98), plot(t,CNalphaFunction)
470
% working memory for implementing convolution
471
CNcurrentTemp=...
472
    zeros(nCNneurons,reducedSegmentLength+length(CNalphaFunction)-1);
473
% trailing alphas are parts of humps carried forward to the next segment
474
CNtrailingAlphas=zeros(nCNneurons,length(CNalphaFunction));
475

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

    
495
CN_PSTH=zeros(nChannels,reducedSegmentLength);
496
CNoutput=false(nCNneurons,reducedSignalLength);
497

    
498

    
499
%% MacGregor (IC - second nucleus) --------
500
nICcells=nChannels;  % one cell per channel
501

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

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

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

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

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

    
539
ICfiberTypeRates=zeros(nANfiberTypes,reducedSignalLength);
540
ICoutput=false(nChannels,reducedSignalLength);
541

    
542
ICmembranePotential=zeros(nICcells,reducedSegmentLength);
543
ICmembraneOutput=zeros(nICcells,signalLength);
544

    
545

    
546
%% Main program %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%
547

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

    
556
    iputPressureSegment=inputSignal...
557
        (:,segmentStartPTR:segmentStartPTR+segmentLength-1);
558

    
559
    % segment debugging plots
560
    % figure(98)
561
    % plot(segmentTime,iputPressureSegment), title('signalSegment')
562

    
563

    
564
    % OME ----------------------
565

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

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

    
593
    % OME stage 4:  apply stapes scalar
594
    stapesDisplacement=stapesDisplacement*stapesScalar;
595

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

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

    
608
    % and save
609
    OMEoutput(segmentStartPTR:segmentEndPTR)= stapesDisplacement;
610

    
611
    % needed for parallel processing
612
    if segmentStartPTR>efferentDelayPts
613
        MOCatt=MOCattenuation(:, segmentStartPTR-efferentDelayPts:...
614
            segmentEndPTR-efferentDelayPts);
615
    else    % no MOC available yet
616
        MOCatt=ones(nBFs, segmentLength);
617
    end
618
    %% BM ------------------------------
619
    % Each BM location is computed separately
620
    parfor BFno=1:nBFs
621

    
622
        %            *linear* path
623
        % repeats used to avoid parallel processin problems
624
        linOutput = stapesDisplacement * linGAIN;  % linear gain
625
        [linOutput GTlinBdry1out{BFno}] = ...
626
            filter(GTlin_b(BFno,:), GTlin_a(BFno,:), linOutput, GTlinBdry1{BFno});
627
        [linOutput GTlinBdry2out{BFno}] = ...
628
            filter(GTlin_b(BFno,:), GTlin_a(BFno,:), linOutput, GTlinBdry2{BFno});
629
        [linOutput GTlinBdry3out{BFno}] = ...
630
            filter(GTlin_b(BFno,:), GTlin_a(BFno,:), linOutput, GTlinBdry3{BFno});
631

    
632
        %           *nonLinear* path
633
        % efferent attenuation (0 <> 1)
634
        MOC=MOCatt(BFno);
635

    
636

    
637
        %       first gammatone filter
638
        [nonlinOutput firstGTnonlinBdry1out{BFno}] = ...
639
            filter(GTnonlin_b(BFno,:), GTnonlin_a(BFno,:), ...
640
            stapesDisplacement, firstGTnonlinBdry1{BFno});
641

    
642
        [nonlinOutput firstGTnonlinBdry2out{BFno}] = ...
643
            filter(GTnonlin_b(BFno,:), GTnonlin_a(BFno,:), ...
644
            stapesDisplacement, firstGTnonlinBdry2{BFno});
645

    
646
        [nonlinOutput firstGTnonlinBdry3out{BFno}] = ...
647
            filter(GTnonlin_b(BFno,:), GTnonlin_a(BFno,:), ...
648
            stapesDisplacement, firstGTnonlinBdry3{BFno});
649

    
650
        %       broken stick instantaneous compression
651
        % nonlinear gain is weakend by MOC before applied to BM response
652
        y= nonlinOutput.*(MOC* DRNLa);  % linear section.
653
        % compress those parts of the signal above the compression
654
        % threshold
655
        abs_x = abs(nonlinOutput);
656
        idx=find(abs_x>DRNLcompressionThreshold);
657
        if ~isempty(idx)>0
658
            y(idx)=sign(nonlinOutput(idx)).*...
659
                (DRNLb*abs_x(idx).^DRNLc);
660
        end
661
        nonlinOutput=y;
662

    
663
        %       second filter removes distortion products
664
        [nonlinOutput secondGTnonlinBdry1out{BFno}] = ...
665
            filter(GTnonlin_b(BFno,:), GTnonlin_a(BFno,:), ...
666
            nonlinOutput, secondGTnonlinBdry1{BFno});
667

    
668
        [nonlinOutput secondGTnonlinBdry2out{BFno}] = ...
669
            filter(GTnonlin_b(BFno,:), GTnonlin_a(BFno,:), ...
670
            nonlinOutput, secondGTnonlinBdry2{BFno});
671

    
672
        [nonlinOutput secondGTnonlinBdry3out{BFno}] = ...
673
            filter(GTnonlin_b(BFno,:), GTnonlin_a(BFno,:), ...
674
            nonlinOutput, secondGTnonlinBdry3{BFno});
675

    
676

    
677
        %  combine the two paths to give the DRNL displacement
678
        DRNLresponse(BFno,:)=linOutput+nonlinOutput;
679
    end % BF
680
    GTlinBdry1=GTlinBdry1out;
681
    GTlinBdry2=GTlinBdry2out;
682
    GTlinBdry3=GTlinBdry3out;
683
    firstGTnonlinBdry1=firstGTnonlinBdry1out;
684
    firstGTnonlinBdry2=firstGTnonlinBdry2out;
685
    firstGTnonlinBdry3=firstGTnonlinBdry3out;
686
    secondGTnonlinBdry1=secondGTnonlinBdry1out;
687
    secondGTnonlinBdry2=secondGTnonlinBdry2out;
688
    secondGTnonlinBdry3=secondGTnonlinBdry3out;
689
    % segment debugging plots
690
    % figure(98)
691
    %     if size(DRNLresponse,1)>3
692
    %         imagesc(DRNLresponse)  % matrix display
693
    %         title('DRNLresponse'); % single or double channel response
694
    %     else
695
    %         plot(segmentTime, DRNLresponse)
696
    %     end
697

    
698
    % and save it
699
    DRNLoutput(:, segmentStartPTR:segmentEndPTR)= DRNLresponse;
700

    
701

    
702
    %% IHC ------------------------------------
703
    %  BM displacement to IHCciliaDisplacement is  a high-pass filter
704
    %   because of viscous coupling
705
    for idx=1:nBFs
706
        [IHCciliaDisplacement(idx,:)  IHCciliaBndry{idx}] = ...
707
            filter(IHCciliaFilter_b,IHCciliaFilter_a, ...
708
            DRNLresponse(idx,:), IHCciliaBndry{idx});
709
    end
710
    
711
    % apply scalar
712
    IHCciliaDisplacement=IHCciliaDisplacement* IHC_C;
713

    
714
    % and save it
715
    IHC_cilia_output(:,segmentStartPTR:segmentStartPTR+segmentLength-1)=...
716
        IHCciliaDisplacement;
717

    
718
    % compute apical conductance
719
    G=IHCGmax./(1+exp(-(IHCciliaDisplacement-IHCu0)/IHCs0).*...
720
        (1+exp(-(IHCciliaDisplacement-IHCu1)/IHCs1)));
721
    Gu=G + IHCGa;
722

    
723
    % Compute receptor potential
724
    for idx=1:segmentLength
725
        IHC_Vnow=IHC_Vnow+ (-Gu(:, idx).*(IHC_Vnow-IHC_Et)-...
726
            IHC_Gk*(IHC_Vnow-IHC_Ekp))*  dt/IHC_Cab;
727
        IHC_RP(:,idx)=IHC_Vnow;
728
    end
729

    
730
    % segment debugging plots
731
    %     if size(IHC_RP,1)>3
732
    %         surf(IHC_RP), shading interp, title('IHC_RP')
733
    %     else
734
    %         plot(segmentTime, IHC_RP)
735
    %     end
736

    
737
    % and save it
738
    IHCoutput(:, segmentStartPTR:segmentStartPTR+segmentLength-1)=IHC_RP;
739

    
740

    
741
    %% synapse -----------------------------
742
    % Compute the vesicle release rate for each fiber type at each BF
743
    % replicate IHC_RP for each fiber type
744
    Vsynapse=repmat(IHC_RP, nANfiberTypes,1);
745

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

    
755
    ICa=   (GmaxCa* mICa.^3) .* (Vsynapse- ECa);
756

    
757
    for idx=1:segmentLength
758
        CaCurrent=CaCurrent +  ICa(:,idx)*dt - CaCurrent*dt./tauCa;
759
        synapticCa(:,idx)=CaCurrent;
760
    end
761
    synapticCa=-synapticCa; % treat IHCpreSynapseParams as positive substance
762

    
763
    % NB vesicleReleaseRate is /s and is independent of dt
764
    vesicleReleaseRate = synapse_z * synapticCa.^synapse_power; % rate
765

    
766
    % segment debugging plots
767
    %     if size(vesicleReleaseRate,1)>3
768
    %         surf(vesicleReleaseRate), shading interp, title('vesicleReleaseRate')
769
    %     else
770
    %         plot(segmentTime, vesicleReleaseRate)
771
    %     end
772

    
773

    
774
    %% AN
775
    switch AN_spikesOrProbability
776
        case 'probability'
777
            % No refractory effect is applied
778
            for t = 1:segmentLength;
779
                M_Pq=PAN_M-Pavailable;
780
                M_Pq(M_Pq<0)=0;
781
                Preplenish = M_Pq .* PAN_ydt;
782
                Pejected = Pavailable.* vesicleReleaseRate(:,t)*dt;
783
                Preprocessed = M_Pq.*Preprocess.* PAN_xdt;
784

    
785
                ANprobability(:,t)= min(Pejected,1);
786
                reuptakeandlost= PAN_rdt_plus_ldt .* Pcleft;
787
                reuptake= PAN_rdt.* Pcleft;
788

    
789
                Pavailable= Pavailable+ Preplenish- Pejected+ Preprocessed;
790
                Pcleft= Pcleft + Pejected - reuptakeandlost;
791
                Preprocess= Preprocess + reuptake - Preprocessed;
792
                Pavailable(Pavailable<0)=0;
793
                savePavailableSeg(:,t)=Pavailable;    % synapse tracking
794
            end
795
            % and save it as *rate*
796
            ANrate=ANprobability/dt;
797
            ANprobRateOutput(:, segmentStartPTR:...
798
                segmentStartPTR+segmentLength-1)=  ANrate;
799
            % monitor synapse contents (only sometimes used)
800
            savePavailable(:, segmentStartPTR:segmentStartPTR+segmentLength-1)=...
801
                savePavailableSeg;
802

    
803
            % Estimate efferent effects. ARattenuation (0 <> 1)
804
            %  acoustic reflex
805
            ARAttSeg=mean(ANrate(1:nBFs,:),1); %LSR channels are 1:nBF
806
            % smooth
807
            [ARAttSeg, ARboundaryProb] = ...
808
                filter(ARfilt_b, ARfilt_a, ARAttSeg, ARboundaryProb);
809
            ARAttSeg=ARAttSeg-ARrateThreshold;
810
            ARAttSeg(ARAttSeg<0)=0;   % prevent negative strengths
811
            ARattenuation(segmentStartPTR:segmentEndPTR)=...
812
                (1-ARrateToAttenuationFactorProb.* ARAttSeg);
813

    
814
            % MOC attenuation
815
            % within-channel HSR response only
816
            HSRbegins=nBFs*(nANfiberTypes-1)+1;
817
            rates=ANrate(HSRbegins:end,:);
818
            for idx=1:nBFs
819
                [smoothedRates, MOCprobBoundary{idx}] = ...
820
                    filter(MOCfilt_b, MOCfilt_a, rates(idx,:), ...
821
                    MOCprobBoundary{idx});
822
                smoothedRates=smoothedRates-MOCrateThresholdProb;
823
                smoothedRates(smoothedRates<0)=0;
824
                MOCattenuation(idx,segmentStartPTR:segmentEndPTR)= ...
825
                    (1- smoothedRates* rateToAttenuationFactorProb);
826
            end
827
            MOCattenuation(MOCattenuation<0)=0.001;
828

    
829

    
830
        case 'spikes'
831
            ANtimeCount=0;
832
            % implement speed upt
833
            for t = ANspeedUpFactor:ANspeedUpFactor:segmentLength;
834
                ANtimeCount=ANtimeCount+1;
835
                % convert release rate to probabilities
836
                releaseProb=vesicleReleaseRate(:,t)*ANdt;
837
                % releaseProb is the release probability per channel
838
                %  but each channel has many synapses
839
                releaseProb=repmat(releaseProb',nFibersPerChannel,1);
840
                releaseProb=reshape(releaseProb, nFibersPerChannel*nChannels,1);
841

    
842
                % AN_available=round(AN_available); % vesicles must be integer, (?needed)
843
                M_q=AN_M- AN_available;     % number of missing vesicles
844
                M_q(M_q<0)= 0;              % cannot be less than 0
845

    
846
                % AN_N1 converts probability to discrete events
847
                %   it considers each event that might occur
848
                %   (how many vesicles might be released)
849
                %   and returns a count of how many were released
850

    
851
                % slow line
852
%                 probabilities= 1-(1-releaseProb).^AN_available;
853
                probabilities= 1-intpow((1-releaseProb), AN_available);
854
                ejected= probabilities> rand(length(AN_available),1);
855

    
856
                reuptakeandlost = AN_rdt_plus_ldt .* AN_cleft;
857
                reuptake = AN_rdt.* AN_cleft;
858

    
859
                % slow line
860
%                 probabilities= 1-(1-AN_reprocess.*AN_xdt).^M_q;
861
                probabilities= 1-intpow((1-AN_reprocess.*AN_xdt), M_q);
862
                reprocessed= probabilities>rand(length(M_q),1);
863

    
864
                % slow line
865
%                 probabilities= 1-(1-AN_ydt).^M_q;
866
                 probabilities= 1-intpow((1-AN_ydt), M_q);
867

    
868
                replenish= probabilities>rand(length(M_q),1);
869

    
870
                AN_available = AN_available + replenish - ejected ...
871
                    + reprocessed;
872
                AN_cleft = AN_cleft + ejected - reuptakeandlost;
873
                AN_reprocess = AN_reprocess + reuptake - reprocessed;
874

    
875
                % ANspikes is logical record of vesicle release events>0
876
                ANspikes(:, ANtimeCount)= ejected;
877
            end % t
878

    
879
            % zero any events that are preceded by release events ...
880
            %  within the refractory period
881
            % The refractory period consist of two periods
882
            %  1) the absolute period where no spikes occur
883
            %  2) a relative period where a spike may occur. This relative
884
            %     period is realised as a variable length interval
885
            %     where the length is chosen at random
886
            %     (esentially a linear ramp up)
887

    
888
            % Andreas has a fix for this
889
            for t = 1:ANtimeCount-2*lengthAbsRefractory;
890
                % identify all spikes across fiber array at time (t)
891
                % idx is a list of channels where spikes occurred
892
                % ?? try sparse matrices?
893
                idx=find(ANspikes(:,t));
894
                for j=idx  % consider each spike
895
                    % specify variable refractory period
896
                    %  between abs and 2*abs refractory period
897
                    nPointsRefractory=lengthAbsRefractory+...
898
                        round(rand*lengthAbsRefractory);
899
                    % disable spike potential for refractory period
900
                    % set all values in this range to 0
901
                    ANspikes(j,t+1:t+nPointsRefractory)=0;
902
                end
903
            end  %t
904

    
905
            % segment debugging
906
            % plotInstructions.figureNo=98;
907
            % plotInstructions.displaydt=ANdt;
908
            %  plotInstructions.numPlots=1;
909
            %  plotInstructions.subPlotNo=1;
910
            % UTIL_plotMatrix(ANspikes, plotInstructions);
911

    
912
            % and save it. NB, AN is now on 'speedUp' time
913
            ANoutput(:, reducedSegmentPTR: shorterSegmentEndPTR)=ANspikes;
914

    
915

    
916
            %% CN Macgregor first neucleus -------------------------------
917
            % input is from AN so ANdt is used throughout
918
            % Each CNneuron has a unique set of input fibers selected
919
            %  at random from the available AN fibers (CNinputfiberLists)
920

    
921
            % Create the dendritic current for that neuron
922
            % First get input spikes to this neuron
923
            synapseNo=1;
924
            for ch=1:nChannels
925
                for idx=1:nCNneuronsPerChannel
926
                    % determine candidate fibers for this unit
927
                    fibersUsed=CNinputfiberLists(synapseNo,:);
928
                    % ANpsth has a bin width of dt
929
                    %  (just a simple sum across fibers)
930
                    AN_PSTH(synapseNo,:) = ...
931
                        sum(ANspikes(fibersUsed,:), 1);
932
                    synapseNo=synapseNo+1;
933
                end
934
            end
935

    
936
            % One alpha function per spike
937
            [alphaRows alphaCols]=size(CNtrailingAlphas);
938

    
939
            for unitNo=1:nCNneurons
940
                CNcurrentTemp(unitNo,:)= ...
941
                    conv(AN_PSTH(unitNo,:),CNalphaFunction);
942
            end
943
            % add post-synaptic current  left over from previous segment
944
            CNcurrentTemp(:,1:alphaCols)=...
945
                CNcurrentTemp(:,1:alphaCols)+ CNtrailingAlphas;
946

    
947
            % take post-synaptic current for this segment
948
            CNcurrentInput= CNcurrentTemp(:, 1:reducedSegmentLength);
949

    
950
            % trailingalphas are the ends of the alpha functions that
951
            % spill over into the next segment
952
            CNtrailingAlphas= ...
953
                CNcurrentTemp(:, reducedSegmentLength+1:end);
954

    
955
            if CN_c>0
956
                % variable threshold condition (slow)
957
                for t=1:reducedSegmentLength
958
                    CNtimeSinceLastSpike=CNtimeSinceLastSpike-dts;
959
                    s=CN_E>CN_Th & CNtimeSinceLastSpike<0 ;
960
                    CNtimeSinceLastSpike(s)=0.0005;         % 0.5 ms for sodium spike
961
                    dE =(-CN_E/CN_tauM + ...
962
                        CNcurrentInput(:,t)/CN_cap+(CN_Gk/CN_cap).*(CN_Ek-CN_E))*dt;
963
                    dGk=-CN_Gk*dt./tauGk + CN_b*s;
964
                    dTh=-(CN_Th-CN_Th0)*dt/CN_tauTh + CN_c*s;
965
                    CN_E=CN_E+dE;
966
                    CN_Gk=CN_Gk+dGk;
967
                    CN_Th=CN_Th+dTh;
968
                    CNmembranePotential(:,t)=CN_E+s.*(CN_Eb-CN_E)+CN_Er;
969
                end
970
            else
971
                % static threshold (faster)
972
                for t=1:reducedSegmentLength
973
                    CNtimeSinceLastSpike=CNtimeSinceLastSpike-dt;
974
                    s=CN_E>CN_Th0 & CNtimeSinceLastSpike<0 ;  % =1 if both conditions met
975
                    CNtimeSinceLastSpike(s)=0.0005;          % 0.5 ms for sodium spike
976
                    dE = (-CN_E/CN_tauM + ...
977
                        CNcurrentInput(:,t)/CN_cap+(CN_Gk/CN_cap).*(CN_Ek-CN_E))*dt;
978
                    dGk=-CN_Gk*dt./tauGk +CN_b*s;
979
                    CN_E=CN_E+dE;
980
                    CN_Gk=CN_Gk+dGk;
981
                    % add spike to CN_E and add resting potential (-60 mV)
982
                    CNmembranePotential(:,t)=CN_E+s.*(CN_Eb-CN_E)+CN_Er;
983
                end
984
            end
985

    
986
            % extract spikes.  A spike is a substantial upswing in voltage
987
            CN_spikes=CNmembranePotential> -0.01;
988

    
989
            % now remove any spike that is immediately followed by a spike
990
            % NB 'find' works on columns (whence the transposing)
991
            CN_spikes=CN_spikes';
992
            idx=find(CN_spikes);
993
            idx=idx(1:end-1);
994
            CN_spikes(idx+1)=0;
995
            CN_spikes=CN_spikes';
996

    
997
            % segment debugging
998
            % plotInstructions.figureNo=98;
999
            % plotInstructions.displaydt=ANdt;
1000
            %  plotInstructions.numPlots=1;
1001
            %  plotInstructions.subPlotNo=1;
1002
            % UTIL_plotMatrix(CN_spikes, plotInstructions);
1003

    
1004
            % and save it
1005
            CNoutput(:, reducedSegmentPTR:shorterSegmentEndPTR)=...
1006
                CN_spikes;
1007

    
1008

    
1009
            %% IC ----------------------------------------------
1010
                %  MacGregor or some other second order neurons
1011

    
1012
                % combine CN neurons in same channel, i.e. same BF & same tauCa
1013
                %  to generate inputs to single IC unit
1014
                channelNo=0;
1015
                for idx=1:nCNneuronsPerChannel:nCNneurons-nCNneuronsPerChannel+1;
1016
                    channelNo=channelNo+1;
1017
                    CN_PSTH(channelNo,:)=...
1018
                        sum(CN_spikes(idx:idx+nCNneuronsPerChannel-1,:));
1019
                end
1020

    
1021
                [alphaRows alphaCols]=size(ICtrailingAlphas);
1022
                for ICneuronNo=1:nICcells
1023
                    ICcurrentTemp(ICneuronNo,:)= ...
1024
                        conv(CN_PSTH(ICneuronNo,:),  IC_CNalphaFunction);
1025
                end
1026

    
1027
                % add the unused current from the previous convolution
1028
                ICcurrentTemp(:,1:alphaCols)=ICcurrentTemp(:,1:alphaCols)...
1029
                    + ICtrailingAlphas;
1030
                % take what is required and keep the trailing part for next time
1031
                inputCurrent=ICcurrentTemp(:, 1:reducedSegmentLength);
1032
                ICtrailingAlphas=ICcurrentTemp(:, reducedSegmentLength+1:end);
1033

    
1034
                if IC_c==0
1035
                    % faster computation when threshold is stable (C==0)
1036
                    for t=1:reducedSegmentLength
1037
                        s=IC_E>IC_Th0;
1038
                        dE = (-IC_E/IC_tauM + inputCurrent(:,t)/IC_cap +...
1039
                            (IC_Gk/IC_cap).*(IC_Ek-IC_E))*dt;
1040
                        dGk=-IC_Gk*dt/IC_tauGk +IC_b*s;
1041
                        IC_E=IC_E+dE;
1042
                        IC_Gk=IC_Gk+dGk;
1043
                        ICmembranePotential(:,t)=IC_E+s.*(IC_Eb-IC_E)+IC_Er;
1044
                    end
1045
                else
1046
                    %  threshold is changing (IC_c>0; e.g. bushy cell)
1047
                    for t=1:reducedSegmentLength
1048
                        dE = (-IC_E/IC_tauM + ...
1049
                            inputCurrent(:,t)/IC_cap + (IC_Gk/IC_cap)...
1050
                            .*(IC_Ek-IC_E))*dt;
1051
                        IC_E=IC_E+dE;
1052
                        s=IC_E>IC_Th;
1053
                        ICmembranePotential(:,t)=IC_E+s.*(IC_Eb-IC_E)+IC_Er;
1054
                        dGk=-IC_Gk*dt/IC_tauGk +IC_b*s;
1055
                        IC_Gk=IC_Gk+dGk;
1056

    
1057
                        % After a spike, the threshold is raised
1058
                        % otherwise it settles to its baseline
1059
                        dTh=-(IC_Th-Th0)*dt/IC_tauTh +s*IC_c;
1060
                        IC_Th=IC_Th+dTh;
1061
                    end
1062
                end
1063

    
1064
                ICspikes=ICmembranePotential> -0.01;
1065
                % now remove any spike that is immediately followed by a spike
1066
                % NB 'find' works on columns (whence the transposing)
1067
                ICspikes=ICspikes';
1068
                idx=find(ICspikes);
1069
                idx=idx(1:end-1);
1070
                ICspikes(idx+1)=0;
1071
                ICspikes=ICspikes';
1072

    
1073
                nCellsPerTau= nICcells/nANfiberTypes;
1074
                firstCell=1;
1075
                lastCell=nCellsPerTau;
1076
                for tauCount=1:nANfiberTypes
1077
                    % separate rates according to fiber types
1078
                    ICfiberTypeRates(tauCount, ...
1079
                        reducedSegmentPTR:shorterSegmentEndPTR)=...
1080
                        sum(ICspikes(firstCell:lastCell, :))...
1081
                        /(nCellsPerTau*ANdt);
1082
                    firstCell=firstCell+nCellsPerTau;
1083
                    lastCell=lastCell+nCellsPerTau;
1084
                end
1085
                ICoutput(:, reducedSegmentPTR:shorterSegmentEndPTR)=ICspikes;
1086

    
1087
                if nBFs==1  % single channel
1088
                    x= repmat(ICmembranePotential(1,:), ANspeedUpFactor,1);
1089
                    x= reshape(x,1,segmentLength);
1090
                    if nANfiberTypes>1  % save HSR and LSR
1091
                        y= repmat(ICmembranePotential(end,:), ANspeedUpFactor,1);
1092
                        y= reshape(y,1,segmentLength);
1093
                        x=[x; y];
1094
                    end
1095
                    ICmembraneOutput(:, segmentStartPTR:segmentEndPTR)= x;
1096
                end
1097

    
1098
                % estimate efferent effects.
1099
                % ARis based on LSR units. LSR channels are 1:nBF
1100
                if nANfiberTypes>1  % AR is multi-channel only
1101
                    ARAttSeg=sum(ICspikes(1:nBFs,:),1)/ANdt;
1102
                    [ARAttSeg, ARboundary] = ...
1103
                        filter(ARfilt_b, ARfilt_a, ARAttSeg, ARboundary);
1104
                    ARAttSeg=ARAttSeg-ARrateThreshold;
1105
                    ARAttSeg(ARAttSeg<0)=0;   % prevent negative strengths
1106
                    % scale up to dt from ANdt
1107
                    x=    repmat(ARAttSeg, ANspeedUpFactor,1);
1108
                    x=reshape(x,1,segmentLength);
1109
                    ARattenuation(segmentStartPTR:segmentEndPTR)=...
1110
                        (1-ARrateToAttenuationFactor* x);
1111
                    ARattenuation(ARattenuation<0)=0.001;
1112
                else
1113
                    % single channel model; disable AR
1114
                    ARattenuation(segmentStartPTR:segmentEndPTR)=...
1115
                        ones(1,segmentLength);
1116
                end
1117

    
1118
                % MOC attenuation using HSR response only
1119
                % Separate MOC effect for each BF
1120
                HSRbegins=nBFs*(nANfiberTypes-1)+1;
1121
                rates=ICspikes(HSRbegins:end,:)/ANdt;
1122
                for idx=1:nBFs
1123
                    [smoothedRates, MOCboundary{idx}] = ...
1124
                        filter(MOCfilt_b, MOCfilt_a, rates(idx,:), ...
1125
                        MOCboundary{idx});
1126
                    MOCattSegment(idx,:)=smoothedRates;
1127
                    % expand timescale back to model dt from ANdt
1128
                    x= repmat(MOCattSegment(idx,:), ANspeedUpFactor,1);
1129
                    x= reshape(x,1,segmentLength);
1130
                    MOCattenuation(idx,segmentStartPTR:segmentEndPTR)= ...
1131
                        (1- MOCrateToAttenuationFactor*  x);
1132
                end
1133
                MOCattenuation(MOCattenuation<0)=0.04;
1134
                % segment debugging
1135
                % plotInstructions.figureNo=98;
1136
                % plotInstructions.displaydt=ANdt;
1137
                %  plotInstructions.numPlots=1;
1138
                %  plotInstructions.subPlotNo=1;
1139
                % UTIL_plotMatrix(ICspikes, plotInstructions);
1140

    
1141
    end     % AN_spikesOrProbability
1142
    segmentStartPTR=segmentStartPTR+segmentLength;
1143
    reducedSegmentPTR=reducedSegmentPTR+reducedSegmentLength;
1144

    
1145

    
1146
end  % segment
1147

    
1148
path(restorePath)