function Vihc=verhulst2018_ihctransduction(Vin,fs,version_year,keyvals)
%VERHULST2018_IHCTRANSDUCTION ihc transduction in Verhulst et al. 2018
%
% Inner hair cell transduction as used in Verhulst et al. models.
% Vihc represents the inner-hair-cell membrane potential in Volts.
%
% The following IHC transduction models are implemented here:
% version_year = 2018 ('verhulst2018b')
% version_year = 2015
%
% The 2018 model Vihc is obtained from the interplay between K+ ion channels
% and mechanoelectrical transduction (MET) currents. This model is described
% in verhulst2018a (Appendix A) and is based on the description/validation
% described in altoe2018. The influence of calcium channels is not accounted
% in this script but it is in verhulst2018_auditorynerve.m, where the effective
% exocystosis rate is controlled by Ca-related parameters. In this script
% an effect of the calcium channels could be added by setting a leak current
% but in the current validation such Ikeak is not active (because Gleak is 0).
%
% License:
% --------
%
% This model is licensed under the UGent Academic License. Further usage details are provided
% in the UGent Academic License which can be found in the AMT directory "licences" and at
% <https://raw.githubusercontent.com/HearingTechnology/Verhulstetal2018Model/master/license.txt>.
%
% References:
% S. Verhulst, A. Altoè, and V. Vasilkov. Functional modeling of the
% human auditory brainstem response to broadband stimulation.
% hearingresearch, 360:55--75, 2018.
%
% A. Altoè, V. Pulkki, and S. Verhulst. The effects of the activation of
% the inner-hair-cell basolateral k+ channels on auditory nerve
% responses. hearingresearch, 364:68--80, 2014.
%
%
% Url: http://amtoolbox.org/amt-1.1.0/doc/modelstages/verhulst2018_ihctransduction.php
% #License: ugent
% #StatusDoc: Good
% #StatusCode: Good
% #Verification: Unknown
% #Requirements: MATLAB M-Signal PYTHON C
% #Author: Alessandro Altoe (2018): original code of the model
% #Author: Alejandro Osses (2020): primary integration in the AMT
% #Author: Piotr Majdak (2021): adaptations for the AMT 1.0
if nargin < 4
keyvals = [];
keyvals.ihc_scal_constant = [];
end
if nargin < 3
version_year = 2018;
end
[N_samples,N_ch] = size(Vin); % 'size' in Python code
% Memory allocation:
Vihc = zeros([N_samples N_ch]);
if ~isempty(keyvals.ihc_scal_constant)
scal_constant = keyvals.ihc_scal_constant;
else
switch version_year
case 2018
scal_constant = 0.118; % [s] ratio to bring BM velocity to IHC cilia displacement range
case 2015
VBMmax = 41e-6; % m/s, former variable name: Mvel
YBmax = 200e-9; % m, or 200 nm
scal_constant = YBmax/VBMmax; % see Verhulst2015, Table I, parameter 'G' = 0.0049
end
end
Vin = scal_constant*Vin;
switch version_year
case 2018
flag = 'verhulst2018b'; % Calcium channels not implemented here yet. It is like in Verhulst2018b
%%% Loading parameters
pars = il_IHC_param(flag); % run(filename)
tau_kf = pars.tkf1; % time constant, K, fast
tau_ks = pars.tks1; % time constant, K, slow
tau_Met = pars.tauMet;
Gmet_max = pars.Gmet_max;
x0 = pars.x0;
s0 = pars.s0;
Gleak = pars.Gleak;
Gk_max = pars.Gk_max;
vk05 = pars.vk05;
sk = pars.sk;
EP = pars.EP;
Ekf = pars.Ekf;
Eks = pars.Eks;
Cm = pars.Cm;
Eca = pars.Eca;
s1 = pars.s1;
if Gleak ~= 0
warning('The Verhulst2018 model has not been validated with a leaky channel');
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
resting_potential = -0.05703; % 'Extra parameter'
% Memory allocation (check if it is needed):
Vm = zeros([1 N_ch])+resting_potential;
nMet = zeros([1 N_ch]);
%%% End of memory allocation
dt=1/fs;
alpha_Met = exp(-dt/tau_Met);
alpha_kf = exp(-dt/tau_kf);
alpha_ks = exp(-dt/tau_ks);
factor1 = exp(x0/s1);
factor0 = exp(x0/s0);
mt0 = 1/(1+factor1*(1+factor0)); % similar to Altoe2018, Eq. A2
nMet = nMet+mt0;
factor1 = exp((x0-Vin)/s1);
factor0 = exp((x0-Vin)/s0);
nMet_inf= 1./(1+factor1.*(1+factor0)); % Altoe2018, Eq. A2, note change of sign: -(mu-x0) as written is the same as (x0-mu)
% Also as Verhulst2018, Eq. A2
nk_f = 1./(1+exp(-(Vm-vk05)/sk));
nk_s = 1./(1+exp(-(Vm-vk05)/sk));
%%%
zero_sample = round(fs*50e-3);
for i = 1:zero_sample
Imet=(Gmet_max*nMet).*(Vm-EP);
Ileak=Gleak*(Vm-Eca);
nk_inf=1./(1+exp(-(Vm-vk05)/sk)); % Eq. A5
nk_f=(1-alpha_kf)*nk_inf+alpha_kf*nk_f;
nk_s=(1-alpha_ks)*nk_inf+alpha_ks*nk_s;
Ikf=(Gk_max*nk_f).*(Vm-Ekf); % fast activating basolateral K+ current
Iks=(Gk_max*nk_s).*(Vm-Eks); % slow activating basolateral K+ current
dV=-(Ileak+Imet+Ikf+Iks)/Cm;
Vm=Vm+dV*dt;
end
%%% Vm is now 'pre-charged'
for i = 1:N_samples
% Equations from Verhulst2018:
nMet=(1-alpha_Met)*nMet_inf(i,:)+alpha_Met*nMet;
Imet =(Gmet_max*nMet).*(Vm-EP); % Eq. A4
Ileak=Gleak*(Vm-Eca); % In the Verhulst2018 implementation Ileak should be 0
nk_inf=1./(1+exp(-(Vm-vk05)/sk)); % Eq. A5
nk_f=(1-alpha_kf)*nk_inf+alpha_kf*nk_f;
nk_s=(1-alpha_ks)*nk_inf+alpha_ks*nk_s;
Ikf=(Gk_max*nk_f).*(Vm-Ekf); % Eq. A7 - fast activating basolateral K+ current
Iks=(Gk_max*nk_s).*(Vm-Eks); % Eq. A7 - slow activating basolateral K+ current
dV=-(Ileak+Imet+Ikf+Iks)/Cm; % Eq. A1 - Imet is an inward current, Ikf and Iks are outward currents
Vm=Vm+dV*dt;
Vihc(i,:)=Vm;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
case 2015
VihcNF=zeros([N_samples N_ch]); % Memory allocation
% Some constants:
F_LPC=1000;
[b,a] = il_LowPass_coeff(F_LPC,fs);
%%% The following is the same as implemented in 'ol_NLogarithm':
A0=0.008; % %0.1 scalar in IHC nonlinear function
B=2000*6000; % #2000 par in IHC nonlinear function
C=0.33; % #1.74 par in IHC nonlinear function
D=200e-9;
idx_neg=find(Vin<0); % negative indexes
idx_pos=find(Vin>=0); % positive indexes, null samples are 'unprocessed'
VihcNF(idx_pos)= A0*log(1+B*abs(Vin(idx_pos))); % Eq. 5(A)
% The '3' in the denominator was taken from the original code, but in
% the paper it seems that that value should be 0.3 instead:
VihcNF(idx_neg)=-A0*(((abs(Vin(idx_neg)).^C)+D)./((3*abs(Vin(idx_neg)).^C)+D)).* ...
log(1+B*abs(Vin(idx_neg))); % Eq. 5(B)
%%% End of 'ol_NLogarithm'
past_Vin = zeros(1,N_ch);
past_output1 = zeros(1,N_ch);
past_output2 = zeros(1,N_ch);
for i=1:N_samples % check across which dimension I should go
%%% Cascade of IIR filters vectorised (all sections at once)
% two identical first order filters
y1 = (-a(2)*past_output1+b(1)*VihcNF(i,:)+ b(2)*past_Vin)/a(1); % intermediate output of the iir cascade
Vihc(i,:)= (-a(2)*past_output2+b(1)*y1 + b(2)*past_output1)/a(1);
% Update filters' past values
past_Vin = VihcNF(i,:);
past_output1=y1;
past_output2= Vihc(i,:);
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function par = il_IHC_param(flag)
% function par = IHC_param(flag)
%
% Parameters according to Altoe2018, Table 1. Parameters that differ from
% what it is defined in the table:
% here paper
% s1 = 48 nm 35 nm
% tks1 = 10 ms 8 ms
% Gkfs = var 19.8 nS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if nargin == 0
flag = 'verhulst2018';
end
par.Cm=12.5e-12; % F (pF), IHC capacitance
par.EP=90e-3; % V (mV), Endocochlear potencial
%%% MET channels:
par.Gmet_max=30e-9; % S (nS), maximum conductance
par.x0=20e-9; % m (nm), offset - Verhulst2018: set to obtain about 13% of the MET channels to be open at rest
par.s0=16e-9; % m (nm), sensitivity
par.s1=par.s0*3; % m (nm), sensitivity, AO: deviates from Alessandro's paper, same as in Verhulst2018b
par.tauMet=50e-6; % s (us), activation time constant
%%% Fast and slow K+ channels:
par.Gk_max= 230e-9; % S (nS), maximum conductance
par.vk05 =-31e-3; % V (mV), half action potential
par.sk = 10.5e-3;% V (mV), sensitivity
par.Ekf =-71e-3; % V (mV), reversal potential, fast
par.Eks =-78e-3; % V (mV), reversal potential, slow
par.tkf1 = 0.3e-3; % s (ms), activation time constant, fast
par.tks1 = 10e-3; % s (ms), activation time constant, slow, AO: deviates from Alessandro's paper, same as in Verhulst2018b
% Not indicated in the table:
par.Gleak=0e-9; % No leak
par.tkf2=0.1e-3;
par.tks2=2e-3;
%%% Ca2+ Channels:
par.GcaM=4.1e-9; % S (pS), maximum conductance
par.sca=7.5e-3; % V (mV), sensitivity
par.tau_Ca=0.2e-3; % s (ms), activation time constant
switch flag
case 'verhulst2018b'
par.xca=-30e-3; % V (mV), half action potential
case 'altoe'
par.xca=-25e-3; % V (mV), half action potential
end
par.Eca=45.0e-3; % V (mV), reversal potential
% Not indicated in the table:
switch flag
case 'verhulst2018b'
par.tauInS=0.5;
par.CaInMax=0.4;
par.xCaIn=-43e-3;
case 'altoe'
par.tauInS=1;
par.CaInMax=0.0;
par.xCaIn=-42e-3;
end
par.tauInF=50e-3;
par.sCaIn=6e-3;
par.Ileak=0.0e-9; % No leak
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [b,a] = il_LowPass_coeff(Fc,fs)
% double [b,a] = il_LowPass_coeff(Fc,fs)
%
% Returns the coefficients of a low-pass filter of first order with a cut-off
% frequency at Fc for a digital sampling frequency fs.
c = 2*fs;
C1LP = ( c - 2*pi*Fc ) / ( c + 2*pi*Fc );
C2LP = 2*pi*Fc / (2*pi*Fc + c);
b = [C2LP C2LP]; % filter coefficients (numerator)
a = [1 -C1LP]; % filter coefficients (denominator)