2
votes

I have to design 1/3-Octave-Band filters in MatLAB (or alternatively in Octave). I've read this doc article and I've tried using the fdesign.octave-design duo, but this method allows creation of band filters for mid-band frequencies starting at around 25Hz. I need to create filters for frequency range from 0.5Hz to 100Hz.

I know how to calculate midband frequencies (fm) for those filters and corresponding upper and lower frequency bounds, so I've tried creating them myself using butter or cheby1 functions or using the fdatool. While filters created/displayed in fdatool look good, when I use them to filter chirp signal using the filer function, I can see something like in the image below: filtered chirp

Top plot is chirp filtered with my custom filter, bottom plot shows the same chirp filtered with the filter of the same order, type and mid-band frequency, but created using fdesign.octave-design duo. I don't know how to get rid of that signal gain at the beginning and this one is actually one of the lowest signal gain, which shows for 100hZ mid-band frequency. The lower the mid-band frequency is, the worse my filter is (actually, below 2 or 3 Hz my filters filter out everything).

Hers is the code, that I am using to build my filter:

Wn = [Fl(i) Fh(i)] / (Fs/2);
[ z, p, k ] = butter( N, Wn, 'bandpass' );
% [z,p,k] = cheby1( N, Rp, Wn, 'bandpass' );
[ sos, g ]=zp2sos( z, p, k );
f = dfilt.df2sos( sos, g );

Can anyone help me with designing proper 1/3-Octave-Band filters for that frequency range (0.5÷100)Hz?


EDIT: I've found another way to do what I want using the standardized fdesign.octave method. Read my answer below.

2

2 Answers

4
votes

Just do it manually by working out the centre frequencies you want and then calculating upper and lower bounds. The following demo uses simple butterworth filters, but you can swap that out with any prototype you like.

fs = 250;
bw = 1/3;

fMin = 0.5;
fMax = 100;

octs = log2(fMax/fMin);
bmax = ceil(octs/bw);

fc = fMin*2.^( (0:bmax) * bw ); % centre frequencies
fl = fc*2^(-bw/2); % lower cutoffs
fu = fc*2^(+bw/2); % upper cutoffs

numBands = length(fc);

b = cell(numBands,1);
a = cell(numBands,1);

figure
for nn = 1:length(fc)

    [b{nn},a{nn}] = butter(2, [fl(nn) fu(nn)]/(fs/2), 'bandpass');
    [h,f]=freqz(b{nn},a{nn},1024,fs);

    hold on;
    plot(f, 20*log10(abs(h)) );

end
set(gca, 'XScale', 'log')
ylim([-50 0])

Which gives . . .

enter image description here

You can then use tf2sos if you want stability from higher order filters as a cascade of 2nd order sections.

You can use the following code to test a chirp to see that nothing weird is going on . .

dt=1/fs;
t = 0:dt:2000;      % 2 seconds
fo = 0.5; f1 = 120; 
x = chirp(t,fo,numel(t)*dt,f1,'logarithmic')';
y = zeros(numel(x), length(fc));
for nn = 1:length(fc)
    y(:,nn) = filter(b{nn},a{nn},x);
end

figure; plot(y)

enter image description here

0
votes

Although I've accepted learnvst's answer (as it helped me a bit at the beginning), I've later found other way to create correct filters, that would comply with ANSI S1.11 / IEC 61260 and it's actually quite easy. My idea is based on a specific property of digital filters, i.e. they can be used for signals of different sampling rate than they were designed for, which will result in changing the actual passband range of a filter.

I've used the standardized fdesign.octave method but with different parameter values. For mid-band frequencies of (25÷100)Hz range I did everything the normal way, but for the range starting around 2.5Hz (up to 24Hz) I have specified 10 times bigger sampling rate and 10 times bigger mid-band frequency. For frequencies of 0.5Hz and up (<2.5Hz) I've multiplied those values by 100. As a result, I've obtained valid filters for (0.5÷100)Hz range for actual sampling rate of my source signals.