THE AUDITORY MODELING TOOLBOX

Applies to version: 1.2.0

View the help

Go to function

LYON2011_IHCSTEP - update of inner-hair-cell (IHC) model

Program code:

function [ihc_out, state] = lyon2011_ihcstep(filters_out, coeffs, state)
%LYON2011_IHCSTEP update of inner-hair-cell (IHC) model
%
%   Usage: [CF, decim_naps, naps, BM, ohc, agc] = lyon2011(CF, input_waves, AGC_plot_fig_num, open_loop);
%
%   Input parameters:
%     detects             : The CF struct holds the filterbank design and 
%                           state; if you want to break the input up into
%                           segments, you need to use the updated CF
%                           to keep the state between segments.
%     coeffs              : input_waves is a column vector if there's just one
%                           audio channel; more generally, it has a row per 
%                           time sample, a column per audio channel. The 
%                           input_waves are assumed to be sampled at the 
%                           same rate as the CARFAC is designed for. 
%                           A resampling may be needed before calling this.
%     state               : Plot automatic gain control figure. Default is 0.
%
%   Output parameters:
%     state               : The CF struct holds the filterbank design and 
%                           state; if you want to break the input up into
%                           segments, you need to use the updated CF
%                           to keep the state between segments.
%     update              : decim_naps is like naps but time-decimated by 
%                           the int CF.decimation.
%
%   LYON2011_IHCSTEP updates the inner-hair-cell (IHC) model, including the
%   detection nonlinearity and one or two capacitor state variables.
%
%
%   See also:   lyon2011_agcstep lyon2011_carstep
%               lyon2011_closeagcloop lyon2011_design
%               lyon2011_ihcstep lyon2011_init
%               lyon2011_spatialsmooth
%               demo_lyon2011
%
%   References:
%     R. F. Lyon. Cascades of two-pole–two-zero asymmetric resonators are
%     good models of peripheral auditory function. J. Acoust. Soc. Am.,
%     130(6), 2011.
%     
%
%   Url: http://amtoolbox.org/amt-1.2.0/doc/modelstages/lyon2011_ihcstep.php

% Copyright (C) 2009-2022 Piotr Majdak, Clara Hollomey, and the AMT team.
% This file is part of Auditory Modeling Toolbox (AMT) version 1.2.0
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.

%   #Author: Amin Saremi (2016) adaptations for the AMT (based on <https://github.com/google/carfac>, Richard F. Lyon)
%   #Author: Clara Hollomey (2021) adaptation for the AMT 1.0
%   #License: gpl3



% AC couple the filters_out, with 20 Hz corner
ac_diff = filters_out - state.ac_coupler;
state.ac_coupler = state.ac_coupler + coeffs.ac_coeff * ac_diff;

if coeffs.just_hwr
  ihc_out = min(2, max(0, ac_diff));  % limit it for stability
else
  %conductance = lyon2011_detect(ac_diff);
  % An IHC-like sigmoidal detection nonlinearity for the CARFAC.
  % Resulting conductance is in about [0...1.3405]
  a = 0.175;   % offset of low-end tail into neg x territory
  % this parameter is adjusted for the book, to make the 20% DC
  % response threshold at 0.1

  set = ac_diff > -a;
  z = ac_diff(set) + a;

  % zero is the final answer for many points:
  conductance = zeros(size(ac_diff));
  conductance(set) = z.^3 ./ (z.^3 + z.^2 + 0.1);
    
  if coeffs.one_cap
    ihc_out = conductance .* state.cap_voltage;
    state.cap_voltage = state.cap_voltage - ihc_out .* coeffs.out_rate + ...
      (1 - state.cap_voltage) .* coeffs.in_rate;
  else
    % change to 2-cap version more like Meddis's:
    ihc_out = conductance .* state.cap2_voltage;
    state.cap1_voltage = state.cap1_voltage - ...
      (state.cap1_voltage - state.cap2_voltage) .* coeffs.out1_rate + ...
      (1 - state.cap1_voltage) .* coeffs.in1_rate;

    state.cap2_voltage = state.cap2_voltage - ihc_out .* coeffs.out2_rate + ...
      (state.cap1_voltage - state.cap2_voltage) .* coeffs.in2_rate;
  end

  % smooth it twice with LPF:

  ihc_out = ihc_out * coeffs.output_gain;
  state.lpf1_state = state.lpf1_state + coeffs.lpf_coeff * ...
    (ihc_out - state.lpf1_state);
  state.lpf2_state = state.lpf2_state + coeffs.lpf_coeff * ...
    (state.lpf1_state - state.lpf2_state);
  ihc_out = state.lpf2_state - coeffs.rest_output;
end

state.ihc_accum = state.ihc_accum + ihc_out;  % for where decimated output is useful