Revision MAP/old MAP files

View differences:

MAP/old MAP files/MAP1_14AP.m
1

  
2
function  MAP1_14AP(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 vector of BFs but can be '-1' to allow MAPparams to choose
9
%  MAPparamsName='Normal';          % source of model parameters
10
%  AN_spikesOrProbability='spikes'; % or 'probability'
11
%  paramChanges is a cell array of strings that can be used to make last
12
%   minute parameter changes, e.g., to simulate OHC loss
13
%  e.g.  paramChanges{1}= 'DRNLParams.a=0;'; % disable OHCs
14
%  e.g.  paramchanges={};                    % no changes
15
% The model parameters are established in the MAPparams<***> file
16
%  and stored as global
17

  
18
restorePath=path;
19
addpath (['..' filesep 'parameterStore'])
20

  
21

  
22
CONVOLUTION_CHANGE_TEST = 0; %for debug
23

  
24

  
25
global OMEParams DRNLParams IHC_cilia_RPParams IHCpreSynapseParams
26
global AN_IHCsynapseParams MacGregorParams MacGregorMultiParams
27

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

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

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

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

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

  
57
if nargin<1
58
    error(' MAP1_14 is not a script but a function that must be called')
59
end
60

  
61
if nargin<6
62
    paramChanges=[];
63
end
64
% Read parameters from MAPparams<***> file in 'parameterStore' folder
65
% Beware, 'BFlist=-1' is a legitimate argument for MAPparams<>
66
%  It means that the calling program allows MAPparams to specify the list
67
cmd=['method=MAPparams' MAPparamsName ...
68
    '(BFlist, sampleRate, 0, paramChanges);'];
69
eval(cmd);
70
BFlist=DRNLParams.nonlinCFs;
71

  
72
% save as global for later plotting if required
73
savedBFlist=BFlist;
74
saveAN_spikesOrProbability=AN_spikesOrProbability;
75
saveMAPparamsName=MAPparamsName;
76

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

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

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

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

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

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

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

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

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

  
159
OMEhighPassBndry=[];
160

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

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

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

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

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

  
187
% DRNLchannelParameters=DRNLParams.channelParameters;
188
DRNLresponse= zeros(nBFs, segmentLength);
189

  
190
MOCrateToAttenuationFactor=DRNLParams.rateToAttenuationFactor;
191
rateToAttenuationFactorProb=DRNLParams.rateToAttenuationFactorProb;
192
MOCrateThresholdProb=DRNLParams.MOCrateThresholdProb;
193

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

  
202
MOCattSegment=zeros(nBFs,reducedSegmentLength);
203
MOCattenuation=ones(nBFs,signalLength);
204

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

  
212
DRNLlinearOrder= DRNLParams.linOrder;
213
DRNLnonlinearOrder= DRNLParams.nonlinOrder;
214

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

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

  
265
% complete BM record (BM displacement)
266
DRNLoutput=zeros(nBFs, signalLength);
267

  
268

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

  
282
IHCciliaBndry=cell(nBFs,1);
283

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

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

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

  
303
IHCrestingV= (IHC_Gk*IHC_Ekp+IHCGu0*IHC_Et)/(IHCGu0+IHC_Gk);
304

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

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

  
313

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

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

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

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

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

  
350

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

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

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

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

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

  
385
% spikes     % !  !  !    ! !        !   !  !
386
lengthAbsRefractory= round(AN_refractory_period/ANdt);
387

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

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

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

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

  
409

  
410
%% CN (first brain stem nucleus - could be any subdivision of CN)
411
% Input to a CN neuorn is a random selection of AN fibers within a channel
412
%  The number of AN fibers used is ANfibersFanInToCN
413
% 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
% If there is more than one value, everything is replicated accordingly
416

  
417
ANavailableFibersPerChan=AN_IHCsynapseParams.numFibers;
418
ANfibersFanInToCN=MacGregorMultiParams.fibersPerNeuron;
419

  
420
CNtauGk=MacGregorMultiParams.tauGk; % row vector of CN types (by tauGk)
421
nCNtauGk=length(CNtauGk);
422

  
423
% the total number of 'channels' is now greater
424
nCNchannels=nANchannels*nCNtauGk;
425

  
426
nCNneuronsPerChannel=MacGregorMultiParams.nNeuronsPerBF;
427
tauGk=repmat(CNtauGk, nCNneuronsPerChannel,1);
428
tauGk=reshape(tauGk,nCNneuronsPerChannel*nCNtauGk,1);
429

  
430
% Now the number of neurons has been increased
431
nCNneurons=nCNneuronsPerChannel*nCNchannels;
432
CNmembranePotential=zeros(nCNneurons,reducedSegmentLength);
433

  
434
% establish which ANfibers (by name) feed into which CN nuerons
435
CNinputfiberLists=zeros(nANchannels*nCNneuronsPerChannel, ANfibersFanInToCN);
436
unitNo=1;
437
for ch=1:nANchannels
438
    % Each channel contains a number of units =length(listOfFanInValues)
439
    for idx=1:nCNneuronsPerChannel
440
        for idx2=1:nCNtauGk
441
            fibersUsed=(ch-1)*ANavailableFibersPerChan + ...
442
                ceil(rand(1,ANfibersFanInToCN)* ANavailableFibersPerChan);
443
            CNinputfiberLists(unitNo,:)=fibersUsed;
444
            unitNo=unitNo+1;
445
        end
446
    end
447
end
448

  
449
% input to CN units
450
AN_PSTH=zeros(nCNneurons,reducedSegmentLength);
451

  
452
% Generate CNalphaFunction function
453
%  by which spikes are converted to post-synaptic currents
454
CNdendriteLPfreq= MacGregorMultiParams.dendriteLPfreq;
455
CNcurrentPerSpike=MacGregorMultiParams.currentPerSpike;
456
CNspikeToCurrentTau=1/(2*pi*CNdendriteLPfreq);
457
t=ANdt:ANdt:5*CNspikeToCurrentTau;
458
CNalphaFunction= (1 / ...
459
    CNspikeToCurrentTau)*t.*exp(-t /CNspikeToCurrentTau);
460
CNalphaFunction=CNalphaFunction*CNcurrentPerSpike;
461

  
462
% figure(98), plot(t,CNalphaFunction)
463
% working memory for implementing convolution
464

  
465
CNcurrentTemp=...
466
    zeros(nCNneurons,reducedSegmentLength+length(CNalphaFunction)-1);
467
% trailing alphas are parts of humps carried forward to the next segment
468
CNtrailingAlphas=zeros(nCNneurons,length(CNalphaFunction));
469

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

  
489
CNoutput=false(nCNneurons,reducedSignalLength);
490

  
491

  
492
%% MacGregor (IC - second nucleus) --------
493
nICcells=nANchannels*nCNtauGk;  % one cell per channel
494
CN_PSTH=zeros(nICcells ,reducedSegmentLength);
495

  
496
ICspikeWidth=0.00015;   % this may need revisiting
497
epochsPerSpike=round(ICspikeWidth/ANdt);
498
if epochsPerSpike<1
499
    error(['MacGregorMulti: sample rate too low to support ' ...
500
        num2str(ICspikeWidth*1e6) '  microsec spikes']);
501
end
502

  
503
% short names
504
IC_tauM=MacGregorParams.tauM;
505
IC_tauGk=MacGregorParams.tauGk;
506
IC_tauTh=MacGregorParams.tauTh;
507
IC_cap=MacGregorParams.Cap;
508
IC_c=MacGregorParams.c;
509
IC_b=MacGregorParams.dGkSpike;
510
IC_Th0=MacGregorParams.Th0;
511
IC_Ek=MacGregorParams.Ek;
512
IC_Eb= MacGregorParams.Eb;
513
IC_Er=MacGregorParams.Er;
514

  
515
IC_E=zeros(nICcells,1);
516
IC_Gk=zeros(nICcells,1);
517
IC_Th=IC_Th0*ones(nICcells,1);
518

  
519
% Dendritic filtering, all spikes are replaced by CNalphaFunction functions
520
ICdendriteLPfreq= MacGregorParams.dendriteLPfreq;
521
ICcurrentPerSpike=MacGregorParams.currentPerSpike;
522
ICspikeToCurrentTau=1/(2*pi*ICdendriteLPfreq);
523
t=ANdt:ANdt:3*ICspikeToCurrentTau;
524
IC_CNalphaFunction= (ICcurrentPerSpike / ...
525
    ICspikeToCurrentTau)*t.*exp(-t / ICspikeToCurrentTau);
526
% figure(98), plot(t,IC_CNalphaFunction)
527

  
528
% working space for implementing alpha function
529
ICcurrentTemp=...
530
    zeros(nICcells,reducedSegmentLength+length(IC_CNalphaFunction)-1);
531
ICtrailingAlphas=zeros(nICcells, length(IC_CNalphaFunction));
532

  
533
ICfiberTypeRates=zeros(nANfiberTypes,reducedSignalLength);
534
ICoutput=false(nICcells,reducedSignalLength);
535

  
536
ICmembranePotential=zeros(nICcells,reducedSegmentLength);
537
ICmembraneOutput=zeros(nICcells,signalLength);
538

  
539

  
540
%% Main program %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%  %%
541

  
542
%  Compute the entire model for each segment
543
segmentStartPTR=1;
544
reducedSegmentPTR=1; % when sampling rate is reduced
545
while segmentStartPTR<signalLength
546
    segmentEndPTR=segmentStartPTR+segmentLength-1;
547
    % shorter segments after speed up.
548
    shorterSegmentEndPTR=reducedSegmentPTR+reducedSegmentLength-1;
549

  
550
    inputPressureSegment=inputSignal...
551
        (:,segmentStartPTR:segmentStartPTR+segmentLength-1);
552

  
553
    % segment debugging plots
554
    % figure(98)
555
    % plot(segmentTime,inputPressureSegment), title('signalSegment')
556

  
557

  
558
    % OME ----------------------
559

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

  
582
    % OME stage 3: middle ear high pass effect to simulate stapes inertia
583
    [stapesDisplacement  OMEhighPassBndry] = ...
584
        filter(stapesDisp_b,stapesDisp_a,TMdisplacementSegment, ...
585
        OMEhighPassBndry);
586

  
587
    % OME stage 4:  apply stapes scalar
588
    stapesDisplacement=stapesDisplacement*stapesScalar;
589

  
590
    % OME stage 5:    acoustic reflex stapes attenuation
591
    %  Attenuate the TM response using feedback from LSR fiber activity
592
    if segmentStartPTR>efferentDelayPts
593
        stapesDisplacement= stapesDisplacement.*...
594
            ARattenuation(segmentStartPTR-efferentDelayPts:...
595
            segmentEndPTR-efferentDelayPts);
596
    end
597

  
598
    % segment debugging plots
599
    % figure(98)
600
    % plot(segmentTime, stapesDisplacement), title ('stapesDisplacement')
601

  
602
    % and save
603
    OMEoutput(segmentStartPTR:segmentEndPTR)= stapesDisplacement;
604

  
605

  
606
    %% BM ------------------------------
607
    % Each location is computed separately
608
    for BFno=1:nBFs
609

  
610
        %            *linear* path
611
        linOutput = stapesDisplacement * linGAIN;  % linear gain
612
        for order = 1 : GTlinOrder
613
            [linOutput GTlinBdry{BFno,order}] = ...
614
                filter(GTlin_b(BFno,:), GTlin_a(BFno,:), linOutput, GTlinBdry{BFno,order});
615
        end
616

  
617
        %           *nonLinear* path
618
        % efferent attenuation (0 <> 1)
619
        if segmentStartPTR>efferentDelayPts
620
            MOC=MOCattenuation(BFno, segmentStartPTR-efferentDelayPts:...
621
                segmentEndPTR-efferentDelayPts);
622
        else    % no MOC available yet
623
            MOC=ones(1, segmentLength);
624
        end
625
        % apply MOC to nonlinear input function       
626
        nonlinOutput=stapesDisplacement.* MOC;
627

  
628
        %       first gammatone filter (nonlin path)
629
        for order = 1 : GTnonlinOrder
630
            [nonlinOutput GTnonlinBdry1{BFno,order}] = ...
631
                filter(GTnonlin_b(BFno,:), GTnonlin_a(BFno,:), ...
632
                nonlinOutput, GTnonlinBdry1{BFno,order});
633
        end
634
        %       broken stick instantaneous compression
635
        y= nonlinOutput.* DRNLa;  % linear section.
636
        % compress parts of the signal above the compression threshold
637
        abs_x = abs(nonlinOutput);
638
        idx=find(abs_x>DRNLcompressionThreshold);
639
        if ~isempty(idx)>0
640
            y(idx)=sign(y(idx)).* (DRNLb*abs_x(idx).^DRNLc);
641
        end
642
        nonlinOutput=y;
643

  
644
        %       second filter removes distortion products
645
        for order = 1 : GTnonlinOrder
646
            [ nonlinOutput GTnonlinBdry2{BFno,order}] = ...
647
                filter(GTnonlin_b(BFno,:), GTnonlin_a(BFno,:), ...
648
                nonlinOutput, GTnonlinBdry2{BFno,order});
649
        end
650

  
651
        %  combine the two paths to give the DRNL displacement
652
        DRNLresponse(BFno,:)=linOutput+nonlinOutput;
653
    end % BF
654

  
655
    % segment debugging plots
656
    % figure(98)
657
    %     if size(DRNLresponse,1)>3
658
    %         imagesc(DRNLresponse)  % matrix display
659
    %         title('DRNLresponse'); % single or double channel response
660
    %     else
661
    %         plot(segmentTime, DRNLresponse)
662
    %     end
663

  
664
    % and save it
665
    DRNLoutput(:, segmentStartPTR:segmentEndPTR)= DRNLresponse;
666

  
667

  
668
    %% IHC ------------------------------------
669
    %  BM displacement to IHCciliaDisplacement is  a high-pass filter
670
    %   because of viscous coupling
671
    for idx=1:nBFs
672
        [IHCciliaDisplacement(idx,:)  IHCciliaBndry{idx}] = ...
673
            filter(IHCciliaFilter_b,IHCciliaFilter_a, ...
674
            DRNLresponse(idx,:), IHCciliaBndry{idx});
675
    end
676
    
677
    % apply scalar
678
    IHCciliaDisplacement=IHCciliaDisplacement* IHC_C;
679

  
680
    % and save it
681
    IHC_cilia_output(:,segmentStartPTR:segmentStartPTR+segmentLength-1)=...
682
        IHCciliaDisplacement;
683

  
684
    % compute apical conductance
685
    G=IHCGmax./(1+exp(-(IHCciliaDisplacement-IHCu0)/IHCs0).*...
686
        (1+exp(-(IHCciliaDisplacement-IHCu1)/IHCs1)));
687
    Gu=G + IHCGa;
688

  
689
    % Compute receptor potential
690
    for idx=1:segmentLength
691
        IHC_Vnow=IHC_Vnow+ (-Gu(:, idx).*(IHC_Vnow-IHC_Et)-...
692
            IHC_Gk*(IHC_Vnow-IHC_Ekp))*  dt/IHC_Cab;
693
        IHC_RP(:,idx)=IHC_Vnow;
694
    end
695

  
696
    % segment debugging plots
697
    %     if size(IHC_RP,1)>3
698
    %         surf(IHC_RP), shading interp, title('IHC_RP')
699
    %     else
700
    %         plot(segmentTime, IHC_RP)
701
    %     end
702

  
703
    % and save it
704
    IHCoutput(:, segmentStartPTR:segmentStartPTR+segmentLength-1)=IHC_RP;
705

  
706

  
707
    %% synapse -----------------------------
708
    % Compute the vesicle release rate for each fiber type at each BF
709
    % replicate IHC_RP for each fiber type
710
    Vsynapse=repmat(IHC_RP, nANfiberTypes,1);
711

  
712
    % look-up table of target fraction channels open for a given IHC_RP
713
    mICaINF=    1./( 1 + exp(-gamma  * Vsynapse)  /beta);
714
    % fraction of channel open - apply time constant
715
    for idx=1:segmentLength
716
        % mICaINF is the current 'target' value of mICa
717
        mICaCurrent=mICaCurrent+(mICaINF(:,idx)-mICaCurrent)*dt./tauM;
718
        mICa(:,idx)=mICaCurrent;
719
    end
720

  
721
    ICa=   (GmaxCa* mICa.^3) .* (Vsynapse- ECa);
722

  
723
    for idx=1:segmentLength
724
        CaCurrent=CaCurrent +  ICa(:,idx)*dt - CaCurrent*dt./tauCa;
725
        synapticCa(:,idx)=CaCurrent;
726
    end
727
    synapticCa=-synapticCa; % treat IHCpreSynapseParams as positive substance
728

  
729
    % NB vesicleReleaseRate is /s and is independent of dt
730
    vesicleReleaseRate = synapse_z * synapticCa.^synapse_power; % rate
731

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

  
739

  
740
    %% AN
741
    switch AN_spikesOrProbability
742
        case 'probability'
743
            % No refractory effect is applied
744
            for t = 1:segmentLength;
745
                M_Pq=PAN_M-Pavailable;
746
                M_Pq(M_Pq<0)=0;
747
                Preplenish = M_Pq .* PAN_ydt;
748
                Pejected = Pavailable.* vesicleReleaseRate(:,t)*dt;
749
                Preprocessed = M_Pq.*Preprocess.* PAN_xdt;
750

  
751
                ANprobability(:,t)= min(Pejected,1);
752
                reuptakeandlost= PAN_rdt_plus_ldt .* Pcleft;
753
                reuptake= PAN_rdt.* Pcleft;
754

  
755
                Pavailable= Pavailable+ Preplenish- Pejected+ Preprocessed;
756
                Pcleft= Pcleft + Pejected - reuptakeandlost;
757
                Preprocess= Preprocess + reuptake - Preprocessed;
758
                Pavailable(Pavailable<0)=0;
759
                savePavailableSeg(:,t)=Pavailable;    % synapse tracking
760
            end
761
            % and save it as *rate*
762
            ANrate=ANprobability/dt;
763
            ANprobRateOutput(:, segmentStartPTR:...
764
                segmentStartPTR+segmentLength-1)=  ANrate;
765
            % monitor synapse contents (only sometimes used)
766
            savePavailable(:, segmentStartPTR:segmentStartPTR+segmentLength-1)=...
767
                savePavailableSeg;
768

  
769
            % Estimate efferent effects. ARattenuation (0 <> 1)
770
            %  acoustic reflex
771
            [r c]=size(ANrate);
772
            if r>nBFs % Only if LSR fibers are computed
773
                ARAttSeg=mean(ANrate(1:nBFs,:),1); %LSR channels are 1:nBF
774
                % smooth
775
                [ARAttSeg, ARboundaryProb] = ...
776
                    filter(ARfilt_b, ARfilt_a, ARAttSeg, ARboundaryProb);
777
                ARAttSeg=ARAttSeg-ARrateThreshold;
778
                ARAttSeg(ARAttSeg<0)=0;   % prevent negative strengths
779
                ARattenuation(segmentStartPTR:segmentEndPTR)=...
780
                    (1-ARrateToAttenuationFactorProb.* ARAttSeg);
781
            end
782
            %             plot(ARattenuation)
783

  
784
            % MOC attenuation
785
            % within-channel HSR response only
786
            HSRbegins=nBFs*(nANfiberTypes-1)+1;
787
            rates=ANrate(HSRbegins:end,:);
788
            if rateToAttenuationFactorProb<0
789
                % negative factor implies a fixed attenuation
790
                MOCattenuation(:,segmentStartPTR:segmentEndPTR)= ...
791
                    ones(size(rates))* -rateToAttenuationFactorProb;
792
            else
793
                for idx=1:nBFs
794
                    [smoothedRates, MOCprobBoundary{idx}] = ...
795
                        filter(MOCfilt_b, MOCfilt_a, rates(idx,:), ...
796
                        MOCprobBoundary{idx});
797
                    smoothedRates=smoothedRates-MOCrateThresholdProb;
798
                    smoothedRates(smoothedRates<0)=0;
799
                    MOCattenuation(idx,segmentStartPTR:segmentEndPTR)= ...
800
                        (1- smoothedRates* rateToAttenuationFactorProb);
801
                end
802
            end
803
            MOCattenuation(MOCattenuation<0)=0.001;
804

  
805
            %             plot(MOCattenuation)
806

  
807

  
808
        case 'spikes'
809
            ANtimeCount=0;
810
            % implement speed upt
811
            for t = ANspeedUpFactor:ANspeedUpFactor:segmentLength;
812
                ANtimeCount=ANtimeCount+1;
813
                % convert release rate to probabilities
814
                releaseProb=vesicleReleaseRate(:,t)*ANdt;
815
                % releaseProb is the release probability per channel
816
                %  but each channel has many synapses
817
                releaseProb=repmat(releaseProb',nFibersPerChannel,1);
818
                releaseProb=reshape(releaseProb, nFibersPerChannel*nANchannels,1);
819

  
820
                % AN_available=round(AN_available); % vesicles must be integer, (?needed)
821
                M_q=AN_M- AN_available;     % number of missing vesicles
822
                M_q(M_q<0)= 0;              % cannot be less than 0
823

  
824
                % AN_N1 converts probability to discrete events
825
                %   it considers each event that might occur
826
                %   (how many vesicles might be released)
827
                %   and returns a count of how many were released
828

  
829
                % slow line
830
%                 probabilities= 1-(1-releaseProb).^AN_available;
831
                probabilities= 1-intpow((1-releaseProb), AN_available);
832
                ejected= probabilities> rand(length(AN_available),1);
833

  
834
                reuptakeandlost = AN_rdt_plus_ldt .* AN_cleft;
835
                reuptake = AN_rdt.* AN_cleft;
836

  
837
                % slow line
838
%                 probabilities= 1-(1-AN_reprocess.*AN_xdt).^M_q;
839
                probabilities= 1-intpow((1-AN_reprocess.*AN_xdt), M_q);
840
                reprocessed= probabilities>rand(length(M_q),1);
841

  
842
                % slow line
843
%                 probabilities= 1-(1-AN_ydt).^M_q;
844
                 probabilities= 1-intpow((1-AN_ydt), M_q);
845

  
846
                replenish= probabilities>rand(length(M_q),1);
847

  
848
                AN_available = AN_available + replenish - ejected ...
849
                    + reprocessed;
850
                AN_cleft = AN_cleft + ejected - reuptakeandlost;
851
                AN_reprocess = AN_reprocess + reuptake - reprocessed;
852

  
853
                % ANspikes is logical record of vesicle release events>0
854
                ANspikes(:, ANtimeCount)= ejected;
855
            end % t
856

  
857
            % zero any events that are preceded by release events ...
858
            %  within the refractory period
859
            % The refractory period consist of two periods
860
            %  1) the absolute period where no spikes occur
861
            %  2) a relative period where a spike may occur. This relative
862
            %     period is realised as a variable length interval
863
            %     where the length is chosen at random
864
            %     (esentially a linear ramp up)
865

  
866
            % Andreas has a fix for this
867
            for t = 1:ANtimeCount-2*lengthAbsRefractory;
868
                % identify all spikes across fiber array at time (t)
869
                % idx is a list of channels where spikes occurred
870
                % ?? try sparse matrices?
871
                idx=find(ANspikes(:,t));
872
                for j=idx  % consider each spike
873
                    % specify variable refractory period
874
                    %  between abs and 2*abs refractory period
875
                    nPointsRefractory=lengthAbsRefractory+...
876
                        round(rand*lengthAbsRefractory);
877
                    % disable spike potential for refractory period
878
                    % set all values in this range to 0
879
                    ANspikes(j,t+1:t+nPointsRefractory)=0;
880
                end
881
            end  %t
882

  
883
            % segment debugging
884
            % plotInstructions.figureNo=98;
885
            % plotInstructions.displaydt=ANdt;
886
            %  plotInstructions.numPlots=1;
887
            %  plotInstructions.subPlotNo=1;
888
            % UTIL_plotMatrix(ANspikes, plotInstructions);
889

  
890
            % and save it. NB, AN is now on 'speedUp' time
891
            ANoutput(:, reducedSegmentPTR: shorterSegmentEndPTR)=ANspikes;
892

  
893

  
894
            %% CN Macgregor first neucleus -------------------------------
895
            % input is from AN so ANdt is used throughout
896
            % Each CNneuron has a unique set of input fibers selected
897
            %  at random from the available AN fibers (CNinputfiberLists)
898

  
899
            % Create the dendritic current for that neuron
900
            % First get input spikes to this neuron
901
            synapseNo=1;
902
            for ch=1:nCNchannels
903
                for idx=1:nCNneuronsPerChannel
904
                    % determine candidate fibers for this unit
905
                    fibersUsed=CNinputfiberLists(synapseNo,:);
906
                    % ANpsth has a bin width of ANdt
907
                    %  (just a simple sum across fibers)
908
                    AN_PSTH(synapseNo,:) = ...
909
                        sum(ANspikes(fibersUsed,:), 1);
910
                    synapseNo=synapseNo+1;
911
                end
912
            end
913
            
914

  
915

  
916
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
917
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
918

  
919
                        
920
            
921
            % One alpha function per spike
922
            [alphaRows alphaCols]=size(CNtrailingAlphas);
923

  
924
           for unitNo=1:nCNneurons 
925

  
926
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
927

  
928
                 CNcurrentTemp0(unitNo,:)= ...
929
                      conv(AN_PSTH(unitNo,:),CNalphaFunction);
930
              
931

  
932
                 
933
                 CNcurrentTemp(unitNo,:)= ...
934
                      conv2(AN_PSTH(unitNo,:),CNalphaFunction);
935
            % Changed conv to conv2 because it runs faster. (Andreas)   
936

  
937

  
938
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
939

  
940
% 
941
%              
942
%                 f = CNalphaFunction;
943
%                 g = AN_PSTH(unitNo,:);
944
% 
945
% 
946
%                 g = [g zeros(1,length(f)-1)];
947
% 
948
%                 spikePos = find(g)';
949
% 
950
%                 result = zeros(1,length(g));
951
% 
952
%                 for index = 1:length(spikePos)
953
%                     k = spikePos(index);
954
%                     result(k:(k+length(f)-1)) = result(k:(k+length(f)-1)) + g(k)*f;
955
%                 end
956
%              
957
%                 CNcurrentTemp2(unitNo,:) = result;    
958

  
959

  
960
            end
961
            
962

  
963
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%            
964

  
965

  
966
         
967
            
968
            f = CNalphaFunction;
969
            g = AN_PSTH;
970

  
971
            g = [g zeros(size(g,1),length(f)-1)];
972

  
973
            [r c] = find(g);
974

  
975
            CNcurrentTemp2 = zeros(size(g));
976

  
977
            for index = 1:length(r)
978

  
979
                row = r(index);
980
                col = c(index);
981

  
982
               CNcurrentTemp2(row,col:col+length(f)-1) =  CNcurrentTemp2(row,col:col+length(f)-1) + f*g(row,col);
983

  
984
            end
985

  
986

  
987

  
988
CONVOLUTION_CHANGE_TEST =  CONVOLUTION_CHANGE_TEST + sum(abs(CNcurrentTemp2 - CNcurrentTemp))+ sum(abs(CNcurrentTemp0 - CNcurrentTemp));
989

  
990

  
991
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
992
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
993

  
994

  
995

  
996

  
997
%             disp(['sum(AN_PSTH)= ' num2str(sum(AN_PSTH(1,:)))])
998
            % add post-synaptic current  left over from previous segment
999
            CNcurrentTemp(:,1:alphaCols)=...
1000
                CNcurrentTemp(:,1:alphaCols)+ CNtrailingAlphas;
1001

  
1002
            % take post-synaptic current for this segment
1003
            CNcurrentInput= CNcurrentTemp(:, 1:reducedSegmentLength);
1004
%                 disp(['mean(CNcurrentInput)= ' num2str(mean(CNcurrentInput(1,:)))])
1005

  
1006
            % trailingalphas are the ends of the alpha functions that
1007
            % spill over into the next segment
1008
            CNtrailingAlphas= ...
1009
                CNcurrentTemp(:, reducedSegmentLength+1:end);
1010

  
1011
            if CN_c>0
1012
                % variable threshold condition (slow)
1013
                for t=1:reducedSegmentLength
1014
                    CNtimeSinceLastSpike=CNtimeSinceLastSpike-ANdt;
1015
                    s=CN_E>CN_Th & CNtimeSinceLastSpike<0 ;
1016
                    CNtimeSinceLastSpike(s)=0.0005;         % 0.5 ms for sodium spike
1017
                    dE =(-CN_E/CN_tauM + ...
1018
                        CNcurrentInput(:,t)/CN_cap+(...
1019
                        CN_Gk/CN_cap).*(CN_Ek-CN_E))*ANdt;
1020
                    dGk=-CN_Gk*ANdt./tauGk + CN_b*s;
1021
                    dTh=-(CN_Th-CN_Th0)*ANdt/CN_tauTh + CN_c*s;
1022
                    CN_E=CN_E+dE;
1023
                    CN_Gk=CN_Gk+dGk;
1024
                    CN_Th=CN_Th+dTh;
1025
                    CNmembranePotential(:,t)=CN_E+s.*(CN_Eb-CN_E)+CN_Er;
1026
                end
1027
            else
1028
                % static threshold (faster)
1029
                E=zeros(1,reducedSegmentLength);
1030
                Gk=zeros(1,reducedSegmentLength);
1031
                ss=zeros(1,reducedSegmentLength);
1032
                for t=1:reducedSegmentLength
1033
                    % time of previous spike moves back in time
1034
                    CNtimeSinceLastSpike=CNtimeSinceLastSpike-ANdt;
1035
                    % action potential if E>threshold
1036
                    %  allow time for s to reset between events
1037
                    s=CN_E>CN_Th0 & CNtimeSinceLastSpike<0 ;  
1038
                    ss(t)=s(1);
1039
                    CNtimeSinceLastSpike(s)=0.0005; % 0.5 ms for sodium spike
1040
                    dE = (-CN_E/CN_tauM + ...
1041
                        CNcurrentInput(:,t)/CN_cap +...
1042
                        (CN_Gk/CN_cap).*(CN_Ek-CN_E))*ANdt;
1043
                    dGk=-CN_Gk*ANdt./tauGk +CN_b*s;
1044
                    CN_E=CN_E+dE;
1045
                    CN_Gk=CN_Gk+dGk;
1046
                    E(t)=CN_E(1);
1047
                    Gk(t)=CN_Gk(1);
1048
                    % add spike to CN_E and add resting potential (-60 mV)
1049
                    CNmembranePotential(:,t)=CN_E +s.*(CN_Eb-CN_E)+CN_Er;
1050
                end
1051
            end
1052
%             disp(['CN_E= ' num2str(sum(CN_E(1,:)))])
1053
%             disp(['CN_Gk= ' num2str(sum(CN_Gk(1,:)))])
1054
%             disp(['CNmembranePotential= ' num2str(sum(CNmembranePotential(1,:)))])
1055
%             plot(CNmembranePotential(1,:))
1056

  
1057

  
1058
            % extract spikes.  A spike is a substantial upswing in voltage
1059
            CN_spikes=CNmembranePotential> -0.02;
1060
%             disp(['CNspikesbefore= ' num2str(sum(sum(CN_spikes)))])
1061

  
1062
            % now remove any spike that is immediately followed by a spike
1063
            % NB 'find' works on columns (whence the transposing)
1064
            % for each spike put a zero in the next epoch
1065
            CN_spikes=CN_spikes';
1066
            idx=find(CN_spikes);
1067
            idx=idx(1:end-1);
1068
            CN_spikes(idx+1)=0;
1069
            CN_spikes=CN_spikes';
1070
%             disp(['CNspikes= ' num2str(sum(sum(CN_spikes)))])
1071

  
1072
            % segment debugging
1073
            % plotInstructions.figureNo=98;
1074
            % plotInstructions.displaydt=ANdt;
1075
            %  plotInstructions.numPlots=1;
1076
            %  plotInstructions.subPlotNo=1;
1077
            % UTIL_plotMatrix(CN_spikes, plotInstructions);
1078

  
1079
            % and save it
1080
            CNoutput(:, reducedSegmentPTR:shorterSegmentEndPTR)=...
1081
                CN_spikes;
1082

  
1083

  
1084
            %% IC ----------------------------------------------
1085
                %  MacGregor or some other second order neurons
1086

  
1087
                % combine CN neurons in same channel, 
1088
                %  i.e. same BF & same tauCa
1089
                %  to generate inputs to single IC unit
1090
                channelNo=0;
1091
                for idx=1:nCNneuronsPerChannel:nCNneurons-nCNneuronsPerChannel+1;
1092
                    channelNo=channelNo+1;
1093
                    CN_PSTH(channelNo,:)=...
1094
                        sum(CN_spikes(idx:idx+nCNneuronsPerChannel-1,:));
1095
                end
1096

  
1097
                [alphaRows alphaCols]=size(ICtrailingAlphas);
1098
                for ICneuronNo=1:nICcells
1099
                    ICcurrentTemp(ICneuronNo,:)= ...
1100
                        conv2(CN_PSTH(ICneuronNo,:),  IC_CNalphaFunction);
1101
                % Changed conv to conv2 because it runs faster. (Andreas)
1102
                end
1103

  
1104
                % add the unused current from the previous convolution
1105
                ICcurrentTemp(:,1:alphaCols)=ICcurrentTemp(:,1:alphaCols)...
1106
                    + ICtrailingAlphas;
1107
                % take what is required and keep the trailing part for next time
1108
                inputCurrent=ICcurrentTemp(:, 1:reducedSegmentLength);
1109
                ICtrailingAlphas=ICcurrentTemp(:, reducedSegmentLength+1:end);
1110

  
1111
                if IC_c==0
1112
                    % faster computation when threshold is stable (C==0)
1113
                    for t=1:reducedSegmentLength
1114
                        s=IC_E>IC_Th0;
1115
                        dE = (-IC_E/IC_tauM + inputCurrent(:,t)/IC_cap +...
1116
                            (IC_Gk/IC_cap).*(IC_Ek-IC_E))*ANdt;
1117
                        dGk=-IC_Gk*ANdt/IC_tauGk +IC_b*s;
1118
                        IC_E=IC_E+dE;
1119
                        IC_Gk=IC_Gk+dGk;
1120
                        ICmembranePotential(:,t)=IC_E+s.*(IC_Eb-IC_E)+IC_Er;
1121
                    end
1122
                else
1123
                    %  threshold is changing (IC_c>0; e.g. bushy cell)
1124
                    for t=1:reducedSegmentLength
1125
                        dE = (-IC_E/IC_tauM + ...
1126
                            inputCurrent(:,t)/IC_cap + (IC_Gk/IC_cap)...
1127
                            .*(IC_Ek-IC_E))*ANdt;
1128
                        IC_E=IC_E+dE;
1129
                        s=IC_E>IC_Th;
1130
                        ICmembranePotential(:,t)=IC_E+s.*(IC_Eb-IC_E)+IC_Er;
1131
                        dGk=-IC_Gk*ANdt/IC_tauGk +IC_b*s;
1132
                        IC_Gk=IC_Gk+dGk;
1133

  
1134
                        % After a spike, the threshold is raised
1135
                        % otherwise it settles to its baseline
1136
                        dTh=-(IC_Th-Th0)*ANdt/IC_tauTh +s*IC_c;
1137
                        IC_Th=IC_Th+dTh;
1138
                    end
1139
                end
1140

  
1141
                ICspikes=ICmembranePotential> -0.01;
1142
                % now remove any spike that is immediately followed by a spike
1143
                % NB 'find' works on columns (whence the transposing)
1144
                ICspikes=ICspikes';
1145
                idx=find(ICspikes);
1146
                idx=idx(1:end-1);
1147
                ICspikes(idx+1)=0;
1148
                ICspikes=ICspikes';
1149

  
1150
                nCellsPerTau= nICcells/nANfiberTypes;
1151
                firstCell=1;
1152
                lastCell=nCellsPerTau;
1153
                for tauCount=1:nANfiberTypes
1154
                    % separate rates according to fiber types
1155
                    % currently only the last segment is saved
1156
                    ICfiberTypeRates(tauCount, ...
1157
                        reducedSegmentPTR:shorterSegmentEndPTR)=...
1158
                        sum(ICspikes(firstCell:lastCell, :))...
1159
                        /(nCellsPerTau*ANdt);
1160
                    firstCell=firstCell+nCellsPerTau;
1161
                    lastCell=lastCell+nCellsPerTau;
1162
                end
1163
                
1164
                ICoutput(:,reducedSegmentPTR:shorterSegmentEndPTR)=ICspikes;
1165
                
1166
                % store membrane output on original dt scale
1167
                if nBFs==1  % single channel
1168
                    x= repmat(ICmembranePotential(1,:), ANspeedUpFactor,1);
1169
                    x= reshape(x,1,segmentLength);
1170
                    if nANfiberTypes>1  % save HSR and LSR
1171
                        y=repmat(ICmembranePotential(end,:),...
1172
                            ANspeedUpFactor,1);
1173
                        y= reshape(y,1,segmentLength);
1174
                        x=[x; y];
1175
                    end
1176
                    ICmembraneOutput(:, segmentStartPTR:segmentEndPTR)= x;
1177
                end
1178

  
1179
                % estimate efferent effects.
1180
                % ARis based on LSR units. LSR channels are 1:nBF
1181
                if nANfiberTypes>1  % AR is multi-channel only
1182
                    ARAttSeg=sum(ICspikes(1:nBFs,:),1)/ANdt;
1183
                    [ARAttSeg, ARboundary] = ...
1184
                        filter(ARfilt_b, ARfilt_a, ARAttSeg, ARboundary);
1185
                    ARAttSeg=ARAttSeg-ARrateThreshold;
1186
                    ARAttSeg(ARAttSeg<0)=0;   % prevent negative strengths
1187
                    % scale up to dt from ANdt
1188
                    x=    repmat(ARAttSeg, ANspeedUpFactor,1);
1189
                    x=reshape(x,1,segmentLength);
1190
                    ARattenuation(segmentStartPTR:segmentEndPTR)=...
1191
                        (1-ARrateToAttenuationFactor* x);
1192
                    ARattenuation(ARattenuation<0)=0.001;
1193
                else
1194
                    % single channel model; disable AR
1195
                    ARattenuation(segmentStartPTR:segmentEndPTR)=...
1196
                        ones(1,segmentLength);
1197
                end
1198

  
1199
                % MOC attenuation using HSR response only
1200
                % Separate MOC effect for each BF
1201
                HSRbegins=nBFs*(nANfiberTypes-1)+1;
1202
                rates=ICspikes(HSRbegins:end,:)/ANdt;
1203
                for idx=1:nBFs
1204
                    [smoothedRates, MOCboundary{idx}] = ...
1205
                        filter(MOCfilt_b, MOCfilt_a, rates(idx,:), ...
1206
                        MOCboundary{idx});
1207
                    % spont 'rates' is zero for IC
1208
                    MOCattSegment(idx,:)=smoothedRates;
1209
                    % expand timescale back to model dt from ANdt
1210
                    x= repmat(MOCattSegment(idx,:), ANspeedUpFactor,1);
1211
                    x= reshape(x,1,segmentLength);
1212
                    MOCattenuation(idx,segmentStartPTR:segmentEndPTR)= ...
1213
                        (1- MOCrateToAttenuationFactor*  x);
1214
                end
1215
                MOCattenuation(MOCattenuation<0)=0.04;
1216
                % segment debugging
1217
                % plotInstructions.figureNo=98;
1218
                % plotInstructions.displaydt=ANdt;
1219
                %  plotInstructions.numPlots=1;
1220
                %  plotInstructions.subPlotNo=1;
1221
                % UTIL_plotMatrix(ICspikes, plotInstructions);
1222

  
1223
    end     % AN_spikesOrProbability
1224
    segmentStartPTR=segmentStartPTR+segmentLength;
1225
    reducedSegmentPTR=reducedSegmentPTR+reducedSegmentLength;
1226

  
1227

  
1228
end  % segment
1229

  
1230
disp('CONVOLUTION_CHANGE_TEST (if followed by zero all is good)')
1231
disp(max(CONVOLUTION_CHANGE_TEST)) %% for debugging
1232

  
1233

  
1234
%% apply refractory correction to spike probabilities
1235

  
1236
% switch AN_spikesOrProbability
1237
%     case 'probability'
1238
%         ANprobOutput=ANprobRateOutput*dt;
1239
%         [r nEpochs]=size(ANprobOutput);
1240
%         % find probability of no spikes in refractory period
1241
%         pNoSpikesInRefrac=ones(size(ANprobOutput));
1242
%         pSpike=zeros(size(ANprobOutput));
1243
%         for epochNo=lengthAbsRefractoryP+2:nEpochs
1244
%             pNoSpikesInRefrac(:,epochNo)=...
1245
%                 pNoSpikesInRefrac(:,epochNo-2)...
1246
%                 .*(1-pSpike(:,epochNo-1))...
1247
%                 ./(1-pSpike(:,epochNo-lengthAbsRefractoryP-1));
1248
%             pSpike(:,epochNo)= ANprobOutput(:,epochNo)...
1249
%                 .*pNoSpikesInRefrac(:,epochNo);
1250
%         end
1251
%         ANprobRateOutput=pSpike/dt;
1252
% end
1253

  
1254
path(restorePath)
MAP/old MAP files/MAP1_14parallel.m
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;
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff