I have a set of data from a measurement [frequency, relative gain] stored in an excel-table. Now i want to use those values to build an EQ or otherwise somehow substract the values from mulitble audio-files.
Since the parametric EQ is limited to 10 bands and the graphic EQ has fixed frequency-bands, is there any chance doing this using the AudioToolbox?
Talking about a table of around 4000 frequencies with corresponding gain-values. Audio files are IRs of length under 1 second.
I'm thankful for any advice.

 Accepted Answer

hello
maybe you should share the data file (measurements) and code if you have already started one
once we have created the bank of filters we can use them to EQ the signal
for info, this code was for generating a bannk of 23 bandpass filters from 100 to 8,000 Hz center frequencies
%% INitializing Matlab Environment
close all;
clc;
clearvars;
b=log10(8000);%stop frequency and 100Hz is the pass frequency
yc1=logspace(2,b,23);
yd=stem(yc1);
grid on
xlabel('Borders','FontSize',12);
ylabel('F (Hz)','FontSize',12);
set(gca,'YScale', 'log')
%%
fs=44.1e3; %sampling frequency
figure(2)
hold on
for i= 1:1:23
BW = yc1(i)/5; % BW should be proportionnal to center frequencies (not fixed)
f_low = yc1(i) - BW/2;
f_high = yc1(i) + BW/2;
[B,A] = butter(1,[f_low, f_high]*2/fs,'bandpass');
freq = logspace(log10(f_low/4),log10(f_high*4),200);
[h]=freqz(B,A,freq,fs);
semilogx(freq,20*log10(abs(h)));
end
hold off
set(gca,'XLim',[0 fs/2.56],'XTick',10.^(0:4),'YLim',[-12 0],'YTick',-12:2:0,'XScale', 'log')

6 Comments

Thanks for your answer, your code helps quite a bit to understand how it could be done.
Based on that, i came up with the following code to create the bandpass-filters from the table (attached).
Meas = readtable('Example_Table.xlsx'); % header: frequency amplitude
L = height(Meas); % number of frequencies from measurement
fs=44100;
figure(1)
hold on
for i=1:1:L
if i<L
BW = Meas.Frequency(i+1)-Meas.Frequency(i); % bandwidth = distance to next frequency
else
BW = Meas.Frequency(i)-Meas.Frequency(i-1);
end
f_low = Meas.Frequency(i) - BW/2;
f_high = Meas.Frequency(i) + BW/2;
[B,A] = butter(1,[f_low, f_high]*2/fs, 'bandpass');
freq = logspace(log10(f_low/4),log10(f_high*4),200);
[h]=freqz(B,A,freq,fs);
semilogx(freq,20*log(abs(h)));
end
hold off
set(gca,'XLim',[0 1000],'XTick',10.^(0:4),'YLim',[-5 5],'YTick',-5:1:5,'XScale', 'lin');
Now i probably need to assign the measurement-values to the frequency-bands, right? Not sure how to do that.
I also came across the fir2, which seemed to also work, but the resulting values weren't right. That's what i tried, but there must be a logical misunterstanding according to the results.
close all;
clc;
clearvars;
fs = 44100;
fny = fs/2;
Meas = readtable('Example_Table.xlsx');
freq = [0;Meas.Frequency;fny];
amp = [0;Meas.Amplitude;0];
L = length(freq);
fn = freq/fny;
figure(1)
b = fir2(1,fn,amp);
[freq_response, fc] = freqz(b,1,L,fs);
dB = 20*log10(abs(freq_response));
semilogx(fc, dB);
hello again
had to shake my head a bit beacuse equalizing is not what I am doing regurlarly and some points had to be addressed again
one point we didn't really checked here is that a bank ok bandpass filters should be designed so that when all knobs are on the "0" position (no attenuation and no gain) the sum of all filters should be as close as possible to "no filter" gain (0 dB flat curve)
that's why the equalizers are build with specific center frequencies (log spaced to form the octave or 1/3 octave or even 1/24th octave scale) . that must be defined somewhere in a ISO standard
now your table of frequencies is not log scaledand donot follow the equalizer filters design rules , so when we o the sum of all filters (see thick black line) we don't get a flat 0 dB line , but an ascending trend as the "density" of filters goes up with frequency (when we look at the graph in log x )
so that should be corrected first before doing any further work
clc
clearvars
close all
Meas = readtable('Example_Table.xlsx'); % header: frequency amplitude
Center_freqs = Meas.Frequency;
L = numel(Center_freqs);
fs=44100;
figure(1)
freq = logspace(1.5,3.4,1000);
for ci=1:L
if ci<L
BW = Center_freqs(ci+1)-Center_freqs(ci); % bandwidth = distance to next frequency
else
BW = Center_freqs(ci)-Center_freqs(ci-1);
end
f_low = (-BW+sqrt(BW^2+4*Center_freqs(ci)^2))/2;
f_high = f_low + BW;
[B,A] = butter(1,[f_low f_high]*2/fs, 'bandpass');
[h]=freqz(B,A,freq,fs);
h_all(ci,:) = h; % same phase (positive) gain
% h_all(ci,:) = h*(-1)^ci; % alternate pos / neg gain for specific order filters
end
% sum of all filters responses should give flat or target amplitude curve
hh = sum(h_all);
semilogx(freq,20*log(abs(h_all)),freq,20*log(abs(hh)),'k','linewidth',5);
see this other example built on available equalizer (4th order filters)
the sum is quit close to flat 0 dB
clc
clearvars
close all
Center_freqs = [63 250 1000 4000];
f1 = [33.21 131.79 527.15 2108.6] % 0.5271 * Center_freqs
f2 = [119.51 474.25 1897.0 7588.0]; % 1.8970 * Center_freqs
L = numel(Center_freqs);
fs=44100;
figure(1)
freq = logspace(1.5,4.2,1000);
for ci=1:L
f_low = 0.5271*Center_freqs(ci);
f_high = 1.8970*Center_freqs(ci);
[B,A] = butter(4,[f_low f_high]*2/fs, 'bandpass');
[h]=freqz(B,A,freq,fs);
h_all(ci,:) = h; % same phase (pos) gain for even order filters
% h_all(ci,:) = h*(-1)^ci; % alternate pos / neg gain for odd order filters
end
% sum of all filters responses should give flat or target amplitude curve
hh = sum(h_all);
semilogx(freq,20*log(abs(h_all)),freq,20*log(abs(hh)),'k','linewidth',5);
hello again
In the mean time I looked at FIR realisation and that's the best result I could get (in my limited time) with a 300 taps long FIR filter. Maybe easier that the bank of bandpass filters solution in this case
I extended the frequency range below (down to 1 Hz) and above your data (up to 20 kHz) to make sure the filter would stay close to 0 dB gain outside your specified amplitude corrections.
Now you simply have to use this FIR filter with filter or filtfilt to apply to your audio files
clc
clearvars
Meas = readtable('Example_Table.xlsx'); % header: frequency amplitude
freqs = [1; 50; Meas.Frequency];
freqs2 = (max(freqs)+50:50:20000)';
freqs = [freqs;freqs2];
Correction_dB= [0;0;Meas.Amplitude;zeros(length(freqs2),1)];
H = 10.^(Correction_dB/20);
L = numel(freqs);
fs=44100;
ITER = 1e4;
% FIR filter design
NB = 300; % min around 128
NA = 0;
W = 2*pi*freqs/fs;
Wt = ones(size(W));
TOL = 1e-2;
[B,A] = invfreqz(H,W,NB,NA,Wt,ITER,TOL);
hverif = freqz(B,A,freqs,fs);
figure(1)
semilogx(freqs,Correction_dB,'b',freqs,20*log(abs(hverif)),'r');
legend('spec','FIR realisation');
xlabel('Frequency (Hz)');
ylabel('modulus (dB)');
Tanks a lot, that's what i was looking for! Already tried it with some measurement data & audiofiles and it works.
Good news ! glad it worked out !

Sign in to comment.

More Answers (0)

Products

Release

R2021b

Community Treasure Hunt

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

Start Hunting!