Hi, How can I create an FIR from difference of two impulse responses?

43 views (last 30 days)
Hello, I am trying to create an FIR and assocaited waveform for a trasnfer fucntion that is the magnitude difference between the two impulses responses. I have recorded both IR's but am struggling with getting the correction factor to be correct. Here is my code and results of the IRs and difference which is clearly wrong because it is reducing magntiude incorrectly. I can see kind of where it is going wrong which seems to be in taking the difference between them which results in the following magnitude graph and DBFS graph. I have inlcuded wav files as csv if trying to run.
when i mak apply 20*log(x) to each vector to find DBFS
% Define the sampling frequency
close all
%[x1,fs] = audioread('711_Tap1024.wav');
%[x2,fs] = audioread('5128_Tap1024.wav');
x1 = readmatrix('711_Tap1024.csv');
x2 = readmatrix('5128_Tap1024.csv');
fs = 48000;
Nfft = length(x1);
% Frequency vector (assume frequencies are normalized, or you need to normalize by fs/2)
f = linspace(0, fs, Nfft);
f = f';
% Define or import the frequency responses H1 and H2
H1 = fft(x1,Nfft);
H2 = fft(x2,Nfft);
% Compute the difference in frequency responses
H_diff = H1-H2;
% Inverse FFT to obtain the impulse response
y = real(ifft(H_diff,Nfft));
% Normalize the impulse response
y_new = 0.99*y/max(abs(y));
% Save the impulse response as a WAV file
audiowrite('impulse_response_diff.wav', y, fs);
% Plot the impulse response (optional)
figure;
plot(y)
y1=abs(fft(x1,Nfft));
y2=abs(fft(x2,Nfft));
y3=abs(fft(y,Nfft));
y1= 20*log10(y1);
y2= 20*log10(y2);
y3= 20*log10(y3);
figure
plot(f(1:Nfft/2), y1(1:Nfft/2));
hold on
plot(f(1:Nfft/2), y2(1:Nfft/2));
hold on
plot(f(1:Nfft/2), y3(1:Nfft/2));
xlim([20 20000])
xticks([100 1000 10000])
grid on
set(gca, 'XScale', 'log')
xlabel ('Frequency (Hz)');
ylabel ('Amplitude ');
  3 Comments
Star Strider
Star Strider on 22 Nov 2024 at 18:39
You need to subttract the complex results, not the abs results. Then, you should be able to invert the difference. (This is essentiially frequency-domain filtering, and while not recommended, is possible.)
That aside, it is difficult to understand what you want to do.
Paul
Paul on 22 Nov 2024 at 22:42
Can you show mathematically why the difference between H1 and H2 is needed?
From a comment below, it sounds like you have:
Y1 = H1*U
but you want to compute
Y2 = H2*U
based on knowing Y1, H2, and H1. If so, how would H2-H1 come into the analysis?

Sign in to comment.

Answers (1)

Star Strider
Star Strider on 22 Nov 2024 at 18:25
I slightly changed your original code here, in order to define my questions about it.
It is possible to use the firls function to approximatee the ‘y3’ plot. If you want to use it on your existing data, be miindful of the filter length (in this instance the filter order), since it should be less than one-third of the signal length.
This result is far from perfect, however it should provide a startiing point —
x1 = readmatrix('711_Tap1024.csv');
x2 = readmatrix('5128_Tap1024.csv');
fs = 48000;
Nfft = length(x1);
% Frequency vector (assume frequencies are normalized, or you need to normalize by fs/2)
f = linspace(0, fs, Nfft);
f = f';
% Define or import the frequency responses H1 and H2
H1 = fft(x1,Nfft);
H2 = fft(x2,Nfft);
% Compute the difference in frequency responses
H_diff = H1-H2;
% Inverse FFT to obtain the impulse response
y = H_diff;
% % y = real(ifft(H_diff,Nfft));
% Normalize the impulse response
y_new = 0.99*y/max(abs(y));
% Save the impulse response as a WAV file
% % audiowrite('impulse_response_diff.wav', y, fs);
% Plot the impulse response (optional)
% % figure;
% % plot(y)
y1=abs(fft(x1,Nfft));
y2=abs(fft(x2,Nfft));
y3=abs(fft(y,Nfft));
y1= 20*log10(y1);
y2= 20*log10(y2);
y3= 20*log10(y3);
figure
plot(f(1:Nfft/2), y1(1:Nfft/2), DisplayName='y_1');
hold on
plot(f(1:Nfft/2), y2(1:Nfft/2), DisplayName='y_2');
hold on
plot(f(1:Nfft/2), y3(1:Nfft/2), DisplayName='y_3');
xlim([20 20000])
xticks([100 1000 10000])
grid on
set(gca, 'XScale', 'log')
xlabel ('Frequency (Hz)');
ylabel ('Amplitude ');
legend('Location','best')
% ylim([-50 50])
format shortG
fn = fs/2
fn =
24000
Lv = f < fn;
fstop = (y3(Lv) < -275);
stopbands = f(fstop)
stopbands = 3×1
1.0e+00 * 4926.7 15343 20551
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
firn = 150;
fv = f < fn;
firf = f(fv);
a = y3(fv);
ftype = 'hilbert';
b = firls(firn, firf, a, ftype);
figure
freqz(b, 1, 2^16, fs)
.
  4 Comments
Star Strider
Star Strider on 22 Nov 2024 at 22:09
My pleasure!
I am having problems understanding what you are doing. The filter based on ‘H_diff’ has a lowpass characteristic with a cutoff frequency of abour 18.5 kHz. It might be easier to just design a filter to do that, using the fir1 function. I did that as well here.
As I understand it, you want to do something liike this —
x1 = readmatrix('711_Tap1024.csv');
x2 = readmatrix('5128_Tap1024.csv');
fs = 48000;
Nfft = length(x1);
% Frequency vector (assume frequencies are normalized, or you need to normalize by fs/2)
f = linspace(0, fs, Nfft);
f = f';
% Define or import the frequency responses H1 and H2
H1 = fft(x1,Nfft);
H2 = fft(x2,Nfft);
% Compute the difference in frequency responses
H_diff = H1-H2;
fn = fs/2;
fp = f <= fn; % Logical Vector<
figure
plot(f(fp), mag2db(abs(H1(fp))*2), DisplayName='H_1');
hold on
plot(f(fp), mag2db(abs(H2(fp))*2), DisplayName='H_2');
hold on
plot(f(fp), mag2db(abs(H_diff(fp))*2), DisplayName='H_{diff}');
xlim([20 20000])
xticks([100 1000 10000])
grid on
set(gca, 'XScale', 'log')
xlabel ('Frequency (Hz)');
ylabel ('Amplitude ');
legend('Location','best')
format shortG
a = mag2db(abs(H_diff(fp))*2);
an = a - max(a);
idx = find(diff(sign(an + 6)));
hpf = f(idx)
hpf = 6×1
1.0e+00 * 5818.2 12434 14311 17736 17783 18534
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
figure
plot(f(fp), mag2db(abs(H_diff(fp))*2))
hold on
plot(f(fp), an)
hold off
grid
yline(-6, '--k', '-6 dB')
xlabel('Frequency (Hz)')
ylabel('Magnitude (dB)')
title('H_{diff}')
fn = fs/2;
firn = fix(numel(x1)/4);
firf = f(fp)/fn;
% a = mag2db(abs(H_diff(fp)));
% a = a - max(a);
ftype = 'hilbert';
b1 = firls(firn, firf, an, ftype);
figure
freqz(b1, 1, 2^16, fs)
b1 = firls(firn, firf, an);
figure
freqz(b1, 1, 2^16, fs)
b2 = fir1(firn, max(hpf)/fn);
figure
freqz(b2, 1, 2^16, fs)
% set(subplot(2,1,1), 'XScale','log', 'XLim',[20 20000])
% set(subplot(2,1,2), 'XScale','log', 'XLim',[20 20000])
.
Pierce
Pierce about 6 hours ago
Hi Star,
Thank you again for answering. this is not quite what I am looking for and have updates since. Essentially I have 2 impulses responses that give me a SPL frequency response in dB after abs fft and converting to decibel scale. I am trying to find the deltas between them as an FIR so that when i apply the FIR to IR 1 it shows me the FR of IR2. so lets say at 100Hz IR2 is 5dB quiter than IR1. that means my resulting FIR should have a -5dB value at 100Hz so thaqt in the future when I apply the FIR to IR1 I will get the result as if I meaured form the IR2 system. hopefully that makes sense.
I have since found I need to divide H2./H1 to get the right data. I am now getting the right results, HOWEVER my time domain plot of the correciton curve does not look correct to me even though when I take the FFT of it I get the result i want.
Here is updated code.
% Define the sampling frequency
close all
%[x1,fs] = audioread('711_Tap1024.wav');
%x2,fs] = audioread('5128_Tap1024.wav');
x1 = readmatrix('711_Tap1024.csv');
x2 = readmatrix('5128_Tap1024.csv');
fs = 48000;
Nfft = length(x1);
% Frequency vector (assume frequencies are normalized, or you need to normalize by fs/2)
f = linspace(0, fs, Nfft);
f = f';
%define Target Curve
x1FR = 20*log10(abs(fft(x1,Nfft)));
x2FR = 20*log10(abs(fft(x2,Nfft)));
targetCurve = x1FR-x2FR;
targetCurve = targetCurve*-1;
% Define or import the frequency responses H1 and H2
% H1 = abs(fft(x1,Nfft));
% H2 = abs(fft(x2,Nfft));
H1 = fft(x1,Nfft);
H2 = fft(x2,Nfft);
% Compute the difference in frequency responses divide
%H_diff = H1-H2;
H_diff = H2./H1;
% Inverse FFT to obtain the impulse response
y = real(ifft(H_diff,Nfft));
% Normalize the impulse response
y = 0.99*y/max(abs(y));
% Save the impulse response as a WAV file
audiowrite('impulse_response_diff.wav', y, fs);
% Plot the impulse response (optional)
figure;
plot(y)
% plot result of y
y_new=abs(fft(y,Nfft));
y_new= 20*log10(y_new);
figure
plot(f(1:Nfft/2), x1FR(1:Nfft/2));
hold on
plot(f(1:Nfft/2), x2FR(1:Nfft/2));
hold on
plot(f(1:Nfft/2), targetCurve(1:Nfft/2));
hold on
plot(f(1:Nfft/2), y_new(1:Nfft/2));
xlim([20 20000])
xticks([100 1000 10000])
grid on
set(gca, 'XScale', 'log')
xlabel ('Frequency (Hz)');
ylabel ('Magnitude');
legend('H1', 'H2', 'Target Curve','Correction Curve')

Sign in to comment.

Products


Release

R2024a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!