THE AUDITORY MODELING TOOLBOX

Applies to version: 0.9.2

View the help

Go to function

DIETZ2011 - Dietz 2011 binaural model

Program code:

function [fine, env, fc, ild] = dietz2011(insig,fs,varargin)
%DIETZ2011  Dietz 2011 binaural model
%   Usage: [...] = dietz(insig,fs);
%
%   Input parameters:
%       insig       : binaural signal for which values should be calculated
%       fs          : sampling rate (Hz)
%
%   Output parameters:
%       fine        : Information about the fine structure (see below)
%       env         : Information about the envelope (see below)
%
%   `dietz2011(insig,fs)` calculates interaural phase, time and level
%   differences of fine- structure and envelope of the signal, as well as
%   the interaural coherence, which can be used as a weighting function.
%
%   The output structures *fine* and *env* have the following fields:
%
%     s1        : left signal as put in the binaural processor
%     s2        : right signal as put in the binaural processor
%     fc        : center frequencies of the channels (f_carrier or f_mod)
%     itf       : transfer function
%     itf_equal : transfer function without amplitude
%     ipd : phase difference in rad
%     ipd_lp    : based on lowpass-filtered itf, phase difference in rad
%     ild : level difference in dB
%     itd, itd_C, itd_lp, itd_C_lp - time difference based on instantaneous
%                  and central frequencies, with and without low-passed itf
%     f_inst_1 : instantaneous frequencies in the channels of the filtered s1
%     f_inst_2 : instantaneous frequencies in the channels of the filtered s2
%     f_inst   : instantaneous frequencies (average of f_inst1 and 2)
%  
%   The steps of the binaural model to calculate the result are the
%   following (see also Dietz et al., 2011):
%
%   1) Middle ear filtering (500-2000 Hz 1st order bandpass)
%
%   2) Auditory bandpass filtering on the basilar membrane using a
%      4th-order all-pole gammatone filterbank, employing 23 filter
%      bands between 200 and 5000 Hz, with a 1 ERB spacing. The filter
%      width was set to correspond to 1 ERB.
%
%   3) Cochlear compression was simulated by power-law compression with
%      an exponent of 0.4.
%
%   4) The transduction process in the inner hair cells was modelled
%      using half-wave rectification followed by filtering with a 770-Hz
%      5th order lowpass.
%
%   The interaural temporal disparities are then extracted using a
%   second-order complex gammatone bandpass (see paper for details).
%
%   `dietz2011` accepts the following optional parameters:
%
%     'flow',flow    Set the lowest frequency in the filterbank to
%                    flow. Default value is 200 Hz.
%
%     'fhigh',fhigh  Set the highest frequency in the filterbank to
%                    fhigh. Default value is 5000 Hz.
%
%     'basef',basef  Ensure that the frequency basef is a center frequency
%                    in the filterbank. The default value  is 1000.
%
%     'filters_per_ERB', filters_per_erb
%                    Filters per erb. The default value is 1.
%
%     'middle_ear_thr',r
%                    Bandpass freqencies for middle ear transfer. The
%                    default value is `[500 2000]`.
%
%     'middle_ear_order',n 
%                    Order of middle ear filter. Only even numbers are
%                    possible. The default value is 2.
%
%     'haircell_lp_freq',hlpfreq
%                    Cutoff frequency for haircell lowpass filter.
%                    The default value is 770.
%
%     'haircell_lp_order',hlporder
%                    Order of haircell lowpass filter. The default value is 5.
%
%     'compression_power',cpwr
%                    XXX. The default value is 0.4.
%
%     'alpha',alpha  Internal noise strength. Convention FIXME 65dB =
%                    0.0354. The default value is 0.
%
%     'int_randn'    Internal noise XXX. This is the default.
%
%     'int_mini'     Internal noise XXX.
%
%     'filter_order',fo
%                    Filter order for output XXX. Used for both 'mod' and 'fine'.
%                    The default value is 2.
%
%     'filter_attenuation_db',fadb
%                    XXX. Used for both 'mod' and 'fine'. The default value is 10.
% 
%     'fine_filter_finesse',fff
%                    Only for finestructure plugin. The default value is 3.
%
%     'mod_center_frequency_hz',mcf_hz
%                    XXX. Only for envelope plugin. The default value is 135.
%
%     'mod_filter_finesse',mff
%                    XXX. Only for envelope plugin. The default value is 8.
% 
%     'level_filter_cutoff_hz',lfc_hz
%                    XXX. For ild- or level-plugin. The default value is 30.
%
%     'level_filter_order',lforder
%                    XXX. For ild- or level-plugin. The default value is 2.
%
%     'coh_param',coh_param
%                    This is a structure used for the localization
%                    plugin. It has the following fields:
%  
%                      `max_abs_itd`
%                         XXX. The default value is 1e-3.
%
%                      `tau_cycles`
%                         XXX. The default value is 5. 
%
%                      `tau_s`
%                         XXX. The default value is 10e-3.
%
%     'signal_level_dB_SPL',signal_level
%                    Sound pressure level of left channel. Used for data
%                    display and analysis. Default value is 70.
%
%   See also: dietz2011interauralfunctions
%
%   References: dietz2011auditory

% AUTHOR: Mathias Dietz, Martin Klein-Hennig (implementation for AMT)

%   Copyright (C) 2002-2012   AG Medizinische Physik,
%                             Universitaet Oldenburg, Germany
%                             http://www.physik.uni-oldenburg.de/docs/medi
%
%   Authors: Tobias Peters (tobias@medi.physik.uni-oldenburg.de) 2002
%            Mathias Dietz (mathias.dietz@uni-oldenburg.de)      2006-2009
%            Martin Klein-Hennig (martin.klein.hennig@uni-oldenburg.de) 2011
 
  
if nargin<2
  error('%s: Too few input parameters.',upper(mfilename));
end;

if ~isnumeric(insig) || min(size(insig))~=2
    error('%s: insig has to be a numeric two channel signal!',upper(mfilename));
end

if ~isnumeric(fs) || ~isscalar(fs) || fs<=0
    error('%s: fs has to be a positive scalar!',upper(mfilename));
end

  
% Gammatone filterbank parameters
definput.keyvals.flow = 200;
definput.keyvals.fhigh = 5000;
definput.keyvals.basef = 1000;
definput.keyvals.filters_per_ERB = 1;

% Preprocessing parameters
definput.keyvals.middle_ear_thr = [500 2000]; % Bandpass freqencies for middle ear transfer
definput.keyvals.middle_ear_order = 2;        % Only even numbers possible
definput.keyvals.haircell_lp_freq = 770;      % Cutoff frequency for haircell lowpass
definput.keyvals.haircell_lp_order = 5;       % Order of haircell lowpass
definput.keyvals.compression_power = 0.4;
definput.keyvals.alpha = 0;                   % Internal noise strength
                                              % 65dB = 0.0354
% randn: add random noise with rms = alpha
% mini: set all values < alpha to alpha
definput.flags.int_noise_case = {'int_randn','int_mini'};

% Parameters for filtering the haircell output
definput.keyvals.filter_order = 2;            % Used for both mod and fine
definput.keyvals.filter_attenuation_db = 10;  % Used for both mod and fine

% Only for finestructure plugin
definput.keyvals.fine_filter_finesse = 3;

% Only for envelope plugin
definput.keyvals.mod_center_frequency_hz = 135;
definput.keyvals.mod_filter_finesse = 8;

% For ild- or level-plugin
definput.keyvals.level_filter_cutoff_hz = 30;
definput.keyvals.level_filter_order = 2;

% Parameters for localization plugin
definput.keyvals.coh_param.max_abs_itd = 1e-3;
definput.keyvals.coh_param.tau_cycles  = 5;   % in cycles
definput.keyvals.coh_param.tau_s       = 10e-3; % in s for faller

% parameters for data display and analysis
definput.keyvals.signal_level_dB_SPL = 70; % sound pressure level of left channel

% display current process
displ                = 0;   % display current process (0 = do not)


[flags,kv]  = ltfatarghelper({},definput,varargin);

%% Model processing starts here

siglen=length(insig);

t = (0:siglen-1)/fs.';

%% ---- middle ear band pass filtering ------
if displ 
  disp(['band pass filtering of input according to middle ear transfer ' ...
        'charact. -> signal_me']); 
end

[b,a] = butter(kv.middle_ear_order,kv.middle_ear_thr(2)/(fs/2),'low');
low_filtered= filter(b,a,insig);

[b,a] = butter(kv.middle_ear_order,kv.middle_ear_thr(1)/(fs/2),'high');
signal_me = filter(b,a,low_filtered);


%% Filterbank analysis
if displ 
  disp('splitting signal into frequency channels -> signal_filtered');
end

% create filterbank
analyzer = gfb_analyzer_new(fs, kv.flow, kv.basef, kv.fhigh,...
                            kv.filters_per_ERB);
channels = length(analyzer.center_frequencies_hz);
fc=analyzer.center_frequencies_hz;
analyzer_sh = analyzer;

% apply filterbank
[signal_filtered, analyzer] = gfb_analyzer_process(analyzer, signal_me(:,1));
[signal_sh_filtered, analyzer_sh] = gfb_analyzer_process(analyzer_sh,...
                                                  signal_me(:,2));

% get number of channels
channels = length(fc);

% determine lowpass parameter
tau = kv.coh_param.tau_cycles./fc;

% rectification, comression, and lowpass filtering of filtered signals
% (haircell processing)
if displ 
  disp('haircell processing of frequency bands -> hairc');
end

% haircell processing
hairc = haircell(signal_filtered', kv.haircell_lp_freq,...
                 kv.haircell_lp_order,kv.compression_power, fs);

hairc_sh = haircell(signal_sh_filtered',kv.haircell_lp_freq,...
                    kv.haircell_lp_order,kv.compression_power,fs);

% also haircell processing, but no 770 Hz filter for fine-structure channel
hairc_nolp = haircell(signal_filtered', [],[],...
                      kv.compression_power, fs);

hairc_nolp_sh = haircell(signal_sh_filtered', [],[],...
                         kv.compression_power, fs);

% adding internal noise
if flags.do_int_randn
  if displ 
    disp('adding internal random noise -> hairc');
  end
  hairc = hairc + (randn(length(hairc),channels)*kv.alpha);
  hairc_sh = hairc_sh + (randn(length(hairc_sh),length(fc))*kv.alpha);
  hairc_nolp = hairc_nolp + (randn(length(hairc),channels)*kv.alpha);
  hairc_nolp_sh = hairc_nolp_sh + (randn(length(hairc_sh), ...
                                         length(fc))*kv.alpha);
end;

if flags.do_int_mini
  if displ 
    disp('adding internal noise via minimum -> hairc');
  end
  hairc = max(hairc,kv.alpha);
  hairc_sh = max(hairc_sh,kv.alpha);
  hairc_nolp = max(hairc,kv.alpha);
  hairc_nolp_sh = max(hairc_sh,kv.alpha);
end

% processing the hairc output with a modulation frequency filter
%cmin = min(find(fc>2*mod_center_frequency_hz)); % lowest freq. band for envelope detection
if displ 
  disp('enveloping haircell output -> hairc_mod'); 
end

mod_filter_bandwidth_hz = kv.mod_center_frequency_hz/kv.mod_filter_finesse;
[hairc_mod, hairc_sh_mod] =... %gfb_envelope_filter(hairc(:,cmin:end), hairc_sh(:,cmin:end), fs,...
    gfb_envelope_filter(hairc, hairc_sh, fs,...
    kv.mod_center_frequency_hz, mod_filter_bandwidth_hz, ...
    kv.filter_attenuation_db, kv.filter_order);

% calculation of interaural functions from haircell modulation
if displ disp('calculating interaural functions from haircell modulation'); end
env = dietz2011interauralfunctions(...
    hairc_mod, hairc_sh_mod, tau,kv.mod_center_frequency_hz+0*fc,...
    kv.signal_level_dB_SPL, kv.compression_power, kv.coh_param.tau_cycles, fs);

% processing the hairc output with a fine structure filter
if displ disp('deriving fine structure of haircell output -> hairc_fine'); end
[hairc_fine, hairc_sh_fine] =...
    gfb_envelope_filter(hairc_nolp, hairc_nolp_sh, fs, fc,...
    fc/kv.fine_filter_finesse, kv.filter_attenuation_db, kv.filter_order);

% calculation of interaural functions from haircell fine structure
if displ 
  disp('calculating interaural functions from haircell fine structure');
end
fine = dietz2011interauralfunctions(...
    hairc_fine, hairc_sh_fine, tau, fc,...
    kv.signal_level_dB_SPL, kv.compression_power, kv.coh_param.tau_cycles, fs);

% determine ILD of the hairc output
if displ disp('determining ild of the haircell output -> ild'); end
ild = ild_filter(hairc,hairc_sh,kv.level_filter_cutoff_hz,...
                       kv.level_filter_order,kv.compression_power,fs);

% remove finestructure information > 1400 Hz
fine.f_inst(:,fc>1400)=[];
fine.ic(:,fc>1400)=[];
fine.ipd_lp(:,fc>1400)=[];
fine.itd_lp(:,fc>1400)=[];


if displ 
  disp('finished');
end

end



%% gfb_envelope_filter %%%%%%%%%%%%%%%%%
function [envelopes_filtered, envelopes_sh_filtered] = gfb_envelope_filter(s1, s2, sampling_rate_hz, center_frequency_hz,...
    bandwidth_hz, attenuation_db, gamma_filter_order)
% [envelopes_filtered, envelopes_sh_filtered] =...
%   gfb_envelope_filter(s1, s2, sampling_rate_hz, center_frequency_hz, bandwidth_hz, attenuation_db, gamma_filter_order);
%
% Filters each row of s1 and s2 with the gammatone filter defined by the input parameters.
% Takes both vectors and matrices.
%
% Input
%   s1, s2 - signals to be filtered
%   sampling_rate_hz - sampling frequency / Hz
%   center_frequency_hz - centre frequency of the gammatone filter / Hz
%   bandwidth_hz - bandwidth of the gammatone filter at the level attenuation_db / Hz
%   attenuation_db - attenuation in dB at which the filter has bandwidth_hz
%   gamma_filter_order - order of the filter

s1 = s1';
s2 = s2';

[M, N] = size(s1);
if length(center_frequency_hz) == 1
    center_frequency_hz = center_frequency_hz * ones(1,M);
end
if isempty(bandwidth_hz) % default: width = 1 ERB
    recip_width1erb = diff(gfb_hz2erbscale(1:N/2));
    bandwidth_hz = round(1./recip_width1erb(round(center_frequency_hz)));
elseif length(bandwidth_hz) == 1
    bandwidth_hz = bandwidth_hz * ones(1,M);
end

for i = 1:M
    filter = gfb_filter_new(sampling_rate_hz, center_frequency_hz(i),...
        bandwidth_hz(i), attenuation_db, gamma_filter_order);
    [envelopes_filtered(:,i),    filter_obj] = ...
        gfb_filter_process(filter, s1(i,:));

    [envelopes_sh_filtered(:,i), filter_obj] = ...
        gfb_filter_process(filter, s2(i,:));
end
end



%% haircell
function output = haircell(input,cutoff,order,compress_power,fs)

% half-wave rectification
rect = max(real(input),0);

% compression
output = rect.^compress_power;

% lowpass filtering, only if desired
if (~isempty(cutoff) || ~isempty(order))
    fNorm = cutoff*(1/sqrt((2^(1/order)-1))) / (fs/2);
    [b,a] = butter(1,fNorm,'low');
    for k = 1:order
        output= filter(b,a,output);
    end
end

end


%% ild_filter
function output = ild_filter(hairc,hairc_sh,lp_threshold_freq,lp_order,compression,fs)

% lowpass filtering
[b,a] = butter(lp_order,lp_threshold_freq/(fs/2),'low');
hclp    = filter(b,a,hairc);
hclp_sh = filter(b,a,hairc_sh);

output = 20*log10(max(hclp_sh,1e-4)./max(hclp,1e-4))/compression;
end