THE AUDITORY MODELING TOOLBOX

Applies to version: 0.9.6

View the help

Go to function

ENZNER2008 - Calculate HRIR set

Program code:

function [hrir_data, hrir_angles, fs] = enzner2008(mu, delta_phi,varargin)
%ENZNER2008  Calculate HRIR set
%   Usage: [hrir_data,hrir_angles,fs] = enzner2008(mu,delta_phi,...)
%
%   Input parameters:
%     mu          : NLMS stepzize, e.g., 0.75 or 1
%     delta_phi   : azimuthal resolution (delta_phi) in degree to store
%                   hrir,e.g., 0.1 or 1 
%     varargin (not necessary, function will also run without): 
%                   'fig2': plot figure like [Enzner2008, Fig.2] 
%                   'fig4_enzner2009': plot figure like [Enzner2009, Fig.4]
%  
%   Output parameters:
%     hrir_data   : sampled HRIR data at arbitrary azimuth-resolution delta_phi
%     hrir_angles : vector with azimuthal angles corresponding to the azimuthal
%                   index of hrir_data
%     fs          : sampling rate of the used binaural ear signal recording
%
%   ENZNER2008 calculates a set of HRIRs using the normalized LMS-algorithm.
%   A test signal in mono, e.g., white noise, perfect sweeps, or a reference
%   recording at the position in the middle of the listeners head is used as
%   the input of the algorithm, whereas the other input of the algorithm is
%   given by the corresponding spatially-continuous (i.e., dynamical) binaural
%   recording.
%  
%   This recording contains the measured ear signals along the trajectory of
%   interest, e.g., the horizontal plane, plus some symmetric overhead.  The
%   overhead is used to ensure capturing of all data of interest, to give the
%   algorithm a scope to adapt and to be able to shift the signals against
%   each other to ensure causality (see sys_latency). The binaural recording
%   of the ear signals has to begin/end at the rear of the subject.  Thus the
%   first recorded sample number subsequent to the required overhead (see
%   adapt) corresponds to an azimuth of phi = 180° (rear).
%  
%   From a given set of example files, the HRIR data will be calculated. Per
%   default the measured ear signals (stimulus: white noise) and the
%   corresponding reference recording will be used for the computation. If
%   you want to use the loudspeaker driving signals or a perfect sweep data
%   set, please uncomment only the case of interest in the section
%   "changeable parameters" in lines 74-104. In this section you can also
%   adjust the used filter length.
%  
%   The computation is performed continuously for each sample, in compliance with
%   a continuous-azimuth HRIR representation. The storage of the HRIR data is 
%   sampled with an arbitrary azimuth-spacing delta_phi. The HRIR data will be 
%   written into the array hrir_data.
%  
%   Structure of hrir_data:
%     hrir_data(filter coefficients, left/right, no. of channels, azimuthal index)
%         filter coefficients: see h_length
%         left/right: 1 = left, 2 = right
%         no. of channels: allways 1 (single channel NLMS-algorithm)
%         azimuthal index: corresponding to an azimuth phi
%                          Note: The rotational direction during the
%                          recording of the ear signals is counterclockwise!
%                          (1 = -180 °, 2 = -180 ° + delta_phi, end = 180 ° - delta_phi )
%  
%  
%  
%   Changeable parameters (See the section "Changeable parameters" in the
%   code:
%
%     h_length = filter length in samples, e.g., 256 (or 308 for single channel perfect sweeps)
%  
%     Adjust only if using own mwasurements:
%     rec_filename = recorded ear signals as WAV-file (stereo)
%     ref_filename = reference WAV-file (mono), e.g., reference recording or 
%                    playback (white noise, perfect sweeps,...)
%     adapt = No. of symmetrically overlapping samples of the recorded ear signals
%             arround phi = 180 °, used as adaptation buffer before HRIR data will
%             be stored, also used to shift the algorithm's input signals to enshure
%             causality, e.g, adapt = 20000 for the given examples
%     sys_latency = system latency, No. of samples to shift input signals against
%                   each other (ensure causality), e.g. 30, if using a reference
%                   recording or -290, if using loudspeaker driving signals
%                   whereupon the loudspeaker distance is approx. 2 m (fs = 44100)
%
%   Url: http://amtoolbox.sourceforge.net/amt-0.9.6/doc/binaural/enzner2008.php

% Copyright (C) 2009-2014 Peter L. Søndergaard.
% This file is part of AMToolbox version 1.0.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/>.

%  Authors: Michael Weinert (Michael.Weinert@rub.de), Gerald Enzner (Gerald.Enzner@rub.de)
%  Date: 21-01-2013


%%%%%%%%%%%%%%%%%%%%%%%%%% changeable parameters %%%%%%%%%%%%%%%%%%%%%%%%%%
% Please choose a specific case (1.1, 1.2, 1.3 or 1.4) by commenting the others 
 
% option 1.1 using reference signals, measurement stimulus: white noise 
h_length = 256;
rec_filename = fullfile(amtbasepath,'hrtf','enzner2008','measurement','example_1ch_white_noise_earsignals.wav');
ref_filename = fullfile(amtbasepath,'hrtf','enzner2008','signals','reference','example_1ch_white_noise_reference.wav');
adapt = 20000; % depends on the recording (overhead at the end and the beginnig)
sys_latency = 30;

%   % option 1.2 using loudspeaker driving signals, measurement stimulus: white noise 
% h_length = 256;
% rec_filename = fullfile(amtbasepath,'hrtf','continuous-azimuth HRIR','measurement','example_1ch_white_noise_earsignals.wav');
% ref_filename = fullfile(amtbasepath,'hrtf','continuous-azimuth HRIR','signals','playback','example_1ch_white_noise_playback.wav');
% adapt = 20000; % depends on the recording (overhead at the end and the beginnig)
% sys_latency = -290;

% %   % option 1.3 using reference signals, measurement stimulus: perfect sweeps 
% h_length = 308;
% rec_filename = fullfile(amtbasepath,'hrtf','continuous-azimuth HRIR','measurement','example_1ch_PSWEEP308_earsignals.wav');
% ref_filename = fullfile(amtbasepath,'hrtf','continuous-azimuth HRIR','signals','reference','example_1ch_PSWEEP308_reference.wav');
% adapt = 20000; % depends on the recording (overhead at the end and the beginnig)
% sys_latency = 30;

%   % option 1.4 using loudspeaker driving signals, measurement stimulus: perfect sweeps 
% h_length = 308;
% rec_filename = fullfile(amtbasepath,'hrtf','continuous-azimuth HRIR','measurement','example_1ch_PSWEEP308_earsignals.wav');
% ref_filename = fullfile(amtbasepath,'hrtf','continuous-azimuth HRIR','signals','playback','example_1ch_PSWEEP308_playback.wav');
% adapt = 20000; % depends on the recording (overhead at the end and the beginnig)
% sys_latency = -290;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% main code %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%% read signals %%%
x = wavread(ref_filename);
[y, fs] = wavread(rec_filename);

%%% sample numbers at which HRIR will be saved %%%
%%% Note: Computation is continuous corresponding to every sample %%%
circle = 360;                                               % range of measured trajectory in degree
delta_phi_samples = (length(y)-2*adapt)/circle * delta_phi; % length of ear signals contains full circle plus some overhead (2 * adapt)
if delta_phi_samples < 1
    display(['delta_phi can not be smaller than ', num2str(circle/(length(y)-2*adapt)),' ° = 1 Sample']);
    display(['delta_phi is set to ', num2str(circle/(length(y)-2*adapt)),' ° = 1 Sample']);
    delta_phi_samples = 1;
end;
save_data_samples = zeros(round((length(y)-2*adapt)/delta_phi_samples),1);
for k = 1:length(save_data_samples)
    save_data_samples(k) = round((k-1)*delta_phi_samples)+1;
end;

%%% run NLMS-algorithm %%%
hrir_data = zeros(h_length,2,1,length(save_data_samples));  
hrir_angles = zeros(length(save_data_samples),1);
h0 = zeros(h_length,2);                            
error = zeros(length(x),2);                       
n = 1;                                                  % counter
k = adapt/2;                                            % counter, calculation begins at sample #adapt/2
                                                        % samples before adapt/2 are reserved for sys_latency
                                                        % samples from adapt/2 to adapt are used as adaptation time
k_phi90 = round((length(y)-2*adapt)/360*270)+1;         % equivalent sample to azimuth phi = 90 ° (used to plot like [Enzner2008, Fig.2])                                                       
tic;  
%wb = waitbar(0,'calculating, please wait...');
while k <= length(x)-sys_latency-adapt/2                % note that adapt is also an overhead at the end of measurement                        
    x_buffer = x(k+sys_latency:-1:k+sys_latency-h_length+1,:);    % input vector backwards, considering sys_latency
    y_estimate(1) = h0(:,1).' * x_buffer(:);            % estimated ear signal left
    y_estimate(2) = h0(:,2).' * x_buffer(:);            % estimated ear signal right
    error(k,1) = y(k,1) - y_estimate(1);                % error signal left
    error(k,2) = y(k,2) - y_estimate(2);                % error signal right
    x_norm = x_buffer' * x_buffer;        
    h0(:,1) = h0(:,1) + mu/(x_norm) .* error(k,1) .* x_buffer(:); % estimated left ear hrir at sample #k
    h0(:,2) = h0(:,2) + mu/(x_norm) .* error(k,2) .* x_buffer(:); % estimated right ear hrir at sample #k             
       
    if n <= length(save_data_samples)                     
        if (k-adapt == save_data_samples(n))            % store hrir at specified azimuth

            %if ishandle(wb)                                                                              
            %waitbar(((k-1-adapt)/delta_phi_samples)/(circle/ delta_phi),wb, ...
            %['calculating, please wait... ', num2str((k-1- adapt)/ ...
            %       delta_phi_samples*delta_phi),'/',num2str(circle)])
            %end;
            hrir_data(:,1,n) = h0(:,1);                 % left                
            hrir_data(:,2,n) = h0(:,2);                 % right     
            hrir_angles(n) = ((k-1-adapt)/delta_phi_samples*delta_phi)-180; % corresponding azimuth to stored hrir_data
            n = n+1;
        end;
    end; 
    
    if (k == k_phi90+adapt) && (sum(cell2mat(cellfun(@(x) strcmp(x,'fig2'),varargin,'UniformOutput',false))) >= 1)  % plot like [Enzner2008, Fig.2] 
        figure
        subplot(2,1,1)
        plot(20*log10(abs(h0(:,1)./max(max(abs(h0))))))
        xlim([1 length(h0(:,1))])
        ylim([-80 3])
        ylabel('|h_1(\kappa,\theta_k)| [dB]')
        title(['azimuth \theta_k = ',num2str(round(360/(length(y)-2*adapt)*(k-adapt+1))),' °, left ear'])
        grid on
        subplot(2,1,2)
        plot(20*log10(abs(h0(:,2)./max(max(abs(h0))))))
        xlim([1 length(h0(:,2))])
        ylim([-80 3])
        ylabel('|h_2(\kappa,\theta_k)| [dB]') 
        xlabel('impulse response lag \kappa')
        title(['azimuth \theta_k = ',num2str(round(360/(length(y)-2*adapt)*(k-adapt+1))),' °, right ear'])
        grid on
    end;    
    
k = k+1; 
end;
toc;                

%if ishandle(wb)
%     close(wb);
%end; 

hrir_data = hrir_data./(max(max(max(max(abs(hrir_data))))));
% save hrir_data.mat hrir_data

%%% plot recorded earsignals vs. error signals like [Enzner2009, Fig.4] %%%
if sum(cell2mat(cellfun(@(x) strcmp(x,'fig4_enzner2009'),varargin,'UniformOutput',false))) >= 1
    SNR_l = 10*log10(var(error(adapt+1:(length(y)-adapt),1))/var(y(adapt+1:(length(y)-adapt),1))/h_length);
    SNR_r = 10*log10(var(error(adapt+1:(length(y)-adapt),2))/var(y(adapt+1:(length(y)-adapt),2))/h_length);
    t = linspace(0, length(y)/fs, length(y));
    figure
    subplot(2,1,1)
    txt1 = ['(\sigma_{e^l}^2/\sigma_{y^l}^2)/N = ',num2str(SNR_l),' dB'];
    title({txt1});
    hold on
    p1 = plot(t, y(:,1),'b');
    p2 = plot(t, error(:,1),'m');
    xlim([(adapt+1)/fs (length(y)-adapt)/fs]);
    xlabel('time [s]');
    ylim([-0.5 0.5]);
    ylabel('amplitude');    
    legend([p1 p2],{'left ear recording y^l(k)' 'error signal e^l(k)'}, 'location', 'northwest') 
    grid on;
    subplot(2,1,2)
    txt2 = ['(\sigma_{e^r}^2/\sigma_{y^r}^2)/N = ',num2str(SNR_r),' dB'];
    title({txt2});
    hold on
    p1 = plot(t,y(:,2),'b');
    p2 = plot(t,error(:,2),'m');
    xlim([(adapt+1)/fs (length(y)-adapt)/fs]);
    xlabel('time [s]');
    ylim([-0.5 0.5]);
    ylabel('amplitude');
    legend([p1 p2],{'right ear recording y^r(k)' 'error signal e^r(k)'}, 'location', 'northeast') 
    grid on;
end;