Skip to content

Commit 67d2034

Browse files
Vera Erbeshagenw
Vera Erbes
authored andcommitted
Method for interpolation of HRTFs in the time domain (#189)
1 parent 45cc6f8 commit 67d2034

File tree

3 files changed

+72
-11
lines changed

3 files changed

+72
-11
lines changed

SFS_config.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,8 @@
421421
% see test_interpolation_methods.m in the validation folder. For
422422
% typical HRIRs with leading and trailing zeros, the error is
423423
% negligible.
424+
% 'timedomain' - Interpolation in the time domain with cross-correlation for
425+
% estimation of time of arrival (TOA) differences.
424426
conf.ir.interpolationmethod = 'simple';
425427
%
426428
% If you have HRIRs in the form of the SimpleFreeFieldHRIR SOFA convention, zeros

SFS_ir/interpolate_ir.m

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
% M ... Number of measurements
99
% C ... Number of channels
1010
% N ... Number of samples
11-
% weights - M weights for impulse reponses
11+
% weights - M weights for impulse reponses [M 1]
1212
% conf - configuration struct (see SFS_config)
1313
%
1414
% Output parameters:
@@ -25,6 +25,8 @@
2525
% responses.
2626
% 'freqdomain' - Interpolation in the frequency domain performed separately
2727
% for magnitude and phase.
28+
% 'timedomain' - Interpolation in the time domain with cross-correlation for
29+
% estimation of time of arrival (TOA) differences
2830
% Note that the given parameters are not checked if they all have the correct
2931
% dimensions in order to save computational time, because this function could
3032
% be called quite often.
@@ -122,6 +124,44 @@
122124
ir = ifft(magnitude.*exp(1i*phase),[],3);
123125
% Avoid round-off errors
124126
ir = real(ir);
127+
case 'timedomain'
128+
% See Hartung et al. (1999)
129+
%
130+
% Loop over channels
131+
ir_results = zeros(1,size(ir,2),size(ir,3));
132+
for n = 1:size(ir,2)
133+
% Determine TOA differences
134+
ir_upsampled = resample(squeeze(ir(:,n,:))',10,1);
135+
for nn = 1:size(ir,1)
136+
[~,idx_max(nn)] = ...
137+
max(xcorr(ir_upsampled(:,1),ir_upsampled(:,nn)));
138+
end
139+
N = size(ir_upsampled,1);
140+
k = -(N-1):(N-1);
141+
shifts = k(idx_max);
142+
143+
% Shift all irs back to align with last ir
144+
max_shift = max(shifts)-min(shifts);
145+
TOA_diff_to_last = shifts-min(shifts);
146+
ir_shifted = zeros(N+max_shift,size(ir,1));
147+
for nn = 1:size(ir,1)
148+
ir_shifted(:,nn) = [zeros(TOA_diff_to_last(nn),1); ...
149+
ir_upsampled(:,nn); ...
150+
zeros(max_shift-TOA_diff_to_last(nn),1)];
151+
end
152+
153+
% Interpolate aligned irs
154+
ir_interp = sum(bsxfun(@times,ir_shifted,weights'),2);
155+
156+
% Interpolate TOA differences and shift interpolated ir accordingly
157+
TOA_diff_interp = round(TOA_diff_to_last*weights);
158+
ir_interp = ...
159+
ir_interp(TOA_diff_interp+1:end-(max_shift-TOA_diff_interp));
160+
161+
% Downsample and collect results per channel
162+
ir_results(1,n,:) = resample(ir_interp,1,10);
163+
end
164+
ir = ir_results;
125165
otherwise
126166
error('%s: %s is an unknown interpolation method.', ...
127167
upper(mfilename),interpolationmethod);

validation/test_interpolation_methods.m

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
% interpolation points
8181
x0 = [1 3; 0 0; 0 0]/180*pi;
8282
% weights (for target point: xs = [2; 0; 0]/180*pi )
83-
weights = [.5 .5];
83+
weights = [.5; .5];
8484
N = 50; %length impulse responses
8585

8686
% 1. Interpolate between Dirac impulses with one sample in between
@@ -97,6 +97,8 @@
9797
h_int1_simple = interpolate_ir(irs1,weights,conf);
9898
conf.ir.interpolationmethod = 'freqdomain';
9999
h_int1_fd = interpolate_ir(irs1,weights,conf);
100+
conf.ir.interpolationmethod = 'timedomain';
101+
h_int1_td = interpolate_ir(irs1,weights,conf);
100102

101103
% 2. Interpolate between neighbouring Dirac impulses at impulse reponse start
102104
h1 = zeros(1,N);
@@ -112,6 +114,8 @@
112114
h_int2_simple = interpolate_ir(irs2,weights,conf);
113115
conf.ir.interpolationmethod = 'freqdomain';
114116
h_int2_fd = interpolate_ir(irs2,weights,conf);
117+
conf.ir.interpolationmethod = 'timedomain';
118+
h_int2_td = interpolate_ir(irs2,weights,conf);
115119

116120
% 3. Interpolate between neighbouring Dirac impulses in middle of impulse response
117121
h4 = zeros(1,N);
@@ -127,6 +131,8 @@
127131
h_int3_simple = interpolate_ir(irs3,weights,conf);
128132
conf.ir.interpolationmethod = 'freqdomain';
129133
h_int3_fd = interpolate_ir(irs3,weights,conf);
134+
conf.ir.interpolationmethod = 'timedomain';
135+
h_int3_td = interpolate_ir(irs3,weights,conf);
130136

131137
% Plots
132138
% impulse responses
@@ -135,29 +141,32 @@
135141
plot(0:N-1,squeeze(irs1(2,1,:)),'b')
136142
plot(0:N-1,squeeze(h_int1_simple(1,1,:)),'r')
137143
plot(0:N-1,squeeze(h_int1_fd(1,1,:)),'m')
144+
plot(0:N-1,squeeze(h_int1_td(1,1,:)),'c')
138145
grid
139146
xlabel('samples'), ylabel('amplitude')
140-
legend('h_1','h_2','simple interp','freqdomain interp')
147+
legend('h_1','h_2','simple interp','freqdomain interp','timedomain interp')
141148
title('Interpolation between Dirac impulses with one sample in between')
142149

143150
figure
144151
plot(0:N-1,squeeze(irs2(1,1,:)),'k'), hold on
145152
plot(0:N-1,squeeze(irs2(2,1,:)),'b')
146153
plot(0:N-1,squeeze(h_int2_simple(1,1,:)),'r')
147154
plot(0:N-1,squeeze(h_int2_fd(1,1,:)),'m')
155+
plot(0:N-1,squeeze(h_int2_td(1,1,:)),'c')
148156
grid
149157
xlabel('samples'), ylabel('amplitude')
150-
legend('h_1','h_2','simple interp','freqdomain interp')
158+
legend('h_1','h_2','simple interp','freqdomain interp','timedomain interp')
151159
title('Interpolation of neighbouring Dirac impulses at impulse response start')
152160

153161
figure
154162
plot(0:N-1,squeeze(irs3(1,1,:)),'k'), hold on
155163
plot(0:N-1,squeeze(irs3(2,1,:)),'b')
156164
plot(0:N-1,squeeze(h_int3_simple(1,1,:)),'r')
157165
plot(0:N-1,squeeze(h_int3_fd(1,1,:)),'m')
166+
plot(0:N-1,squeeze(h_int3_td(1,1,:)),'c')
158167
grid
159168
xlabel('samples'), ylabel('amplitude')
160-
legend('h_1','h_2','simple interp','freqdomain interp')
169+
legend('h_1','h_2','simple interp','freqdomain interp','timedomain interp')
161170
title('Interpolation of neighbouring Dirac impulses in middle of impulse response')
162171

163172

@@ -168,29 +177,33 @@
168177
idx2 = 183; %index for 2° azimuth
169178
x0_close = [hrtf.SourcePosition(idx0,:).' hrtf.SourcePosition(idx2,:).']/180*pi;
170179
% weights (for target point: xs_close = hrtf.SourcePosition(idx1,:).'/180*pi )
171-
weights_close = [.5 .5];
180+
weights_close = [.5; .5];
172181
hrir_close = [hrtf.Data.IR(idx0,:,:); hrtf.Data.IR(idx2,:,:)];
173182
hrir_close_ref = hrtf.Data.IR(idx1,:,:);
174183

175184
conf.ir.interpolationmethod = 'simple';
176185
hrir_close_simple = interpolate_ir(hrir_close,weights_close,conf);
177186
conf.ir.interpolationmethod = 'freqdomain';
178187
hrir_close_fd = interpolate_ir(hrir_close,weights_close,conf);
188+
conf.ir.interpolationmethod = 'timedomain';
189+
hrir_close_td = interpolate_ir(hrir_close,weights_close,conf);
179190

180191
% 2. Interpolate between distant HRIRs
181192
idx0 = 181; %index for 0° azimuth
182193
idx30 = 211; %index for 30° azimuth
183194
idx60 = 241; %index for 60° azimuth
184195
x0_dist = [hrtf.SourcePosition(idx0,:).' hrtf.SourcePosition(idx60,:).']/180*pi;
185196
% weights (for target point: xs_dist = hrtf.SourcePosition(idx30,:).'/180*pi )
186-
weights_dist = [.5 .5];
197+
weights_dist = [.5; .5];
187198
hrir_dist = [hrtf.Data.IR(idx0,:,:); hrtf.Data.IR(idx60,:,:)];
188199
hrir_dist_ref = hrtf.Data.IR(idx30,:,:);
189200

190201
conf.ir.interpolationmethod = 'simple';
191202
hrir_dist_simple = interpolate_ir(hrir_dist,weights_dist,conf);
192203
conf.ir.interpolationmethod = 'freqdomain';
193204
hrir_dist_fd = interpolate_ir(hrir_dist,weights_dist,conf);
205+
conf.ir.interpolationmethod = 'timedomain';
206+
hrir_dist_td = interpolate_ir(hrir_dist,weights_dist,conf);
194207

195208
% Plots
196209
% impulse responses
@@ -200,10 +213,12 @@
200213
plot(0:hrtf.API.N-1,squeeze(hrir_close_ref(1,1,:)),'g')
201214
plot(0:hrtf.API.N-1,squeeze(hrir_close_simple(1,1,:)),'r')
202215
plot(0:hrtf.API.N-1,squeeze(hrir_close_fd(1,1,:)),'m')
216+
plot(0:hrtf.API.N-1,squeeze(hrir_close_td(1,1,:)),'c')
203217
grid
204218
xlabel('samples'), ylabel('amplitude')
205219
axis([0 160 -0.6 0.6])
206-
legend('hrir_1','hrir_2','hrir_{ref}','simple interp','freqdomain interp')
220+
legend('hrir_1','hrir_2','hrir_{ref}','simple interp','freqdomain interp',...
221+
'timedomain interp')
207222
title('Interpolation of close HRIRs')
208223

209224
figure
@@ -212,10 +227,12 @@
212227
plot(0:hrtf.API.N-1,squeeze(hrir_dist_ref(1,1,:)),'g')
213228
plot(0:hrtf.API.N-1,squeeze(hrir_dist_simple(1,1,:)),'r')
214229
plot(0:hrtf.API.N-1,squeeze(hrir_dist_fd(1,1,:)),'m')
230+
plot(0:hrtf.API.N-1,squeeze(hrir_dist_td(1,1,:)),'c')
215231
grid
216232
xlabel('samples'), ylabel('amplitude')
217233
axis([0 160 -0.6 0.6])
218-
legend('hrir_1','hrir_2','hrir_{ref}','simple interp','freqdomain interp')
234+
legend('hrir_1','hrir_2','hrir_{ref}','simple interp','freqdomain interp',...
235+
'timedomain interp')
219236
title('Interpolation of distant HRIRs')
220237

221238
% magnitude responses
@@ -226,11 +243,12 @@
226243
semilogx(f,db(abs(fft(squeeze(hrir_close_ref(1,1,:))))),'g')
227244
semilogx(f,db(abs(fft(squeeze(hrir_close_simple(1,1,:))))),'r')
228245
semilogx(f,db(abs(fft(squeeze(hrir_close_fd(1,1,:))))),'m')
246+
semilogx(f,db(abs(fft(squeeze(hrir_close_td(1,1,:))))),'c')
229247
grid
230248
xlabel('frequency in Hz'), ylabel('amplitude in dB')
231249
axis([0 hrtf.Data.SamplingRate/2 -60 20])
232250
legend('hrir_1','hrir_2','hrir_{ref}','simple interp','freqdomain interp',...
233-
'Location','SW')
251+
'timedomain interp','Location','SW')
234252
title('Interpolation of close HRIRs')
235253

236254
figure
@@ -239,11 +257,12 @@
239257
semilogx(f,db(abs(fft(squeeze(hrir_dist_ref(1,1,:))))),'g')
240258
semilogx(f,db(abs(fft(squeeze(hrir_dist_simple(1,1,:))))),'r')
241259
semilogx(f,db(abs(fft(squeeze(hrir_dist_fd(1,1,:))))),'m')
260+
semilogx(f,db(abs(fft(squeeze(hrir_dist_td(1,1,:))))),'c')
242261
grid
243262
xlabel('frequency in Hz'), ylabel('amplitude in dB')
244263
axis([0 hrtf.Data.SamplingRate/2 -60 20])
245264
legend('hrir_1','hrir_2','hrir_{ref}','simple interp','freqdomain interp',...
246-
'Location','SW')
265+
'timedomain interp','Location','SW')
247266
title('Interpolation of distant HRIRs')
248267

249268
status = true;

0 commit comments

Comments
 (0)