This documentation page applies to an outdated major AMT version. We show it for archival purposes only.
Click here for the documentation menu and here to download the latest AMT (1.6.0).
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;