The Parks-McClellan algorithm is an approach based on the
alternation theorem
for the design of optimal FIR filters.
Here we test the algorithm as implemented in matlab to construct a low-pass filter with passband [0,7/40] and stopband [9/40,1/2].
We consider in the
matlab code the cases
delta=0.09,
delta=0.017 and
delta=0.004
that with the notation in my signal processing course corresponds to
N=7,
N=16 and
N=24.
First of all let us see the graph of the approximated filter in comparison with the ideal low-pass filter with a linear behavior in the transition band.
|
delta=0.09, N=7
|
|
delta=0.017, N=16
|
|
delta=0.004, N=24
|
According to the numerical data, the maximal errors in the passband and the stopband are
0.11076,
0.016955 and
0.0045000 which are close to the specified values of delta. The plots of the errors in these zones is
|
delta=0.09, N=7
|
|
delta=0.017, N=16
|
|
delta=0.004, N=24
|
This is in clear agreement with the expected equioscillation property.
If you are curious about the aspect of the graphs of the error including the transition band, here they are:
|
delta=0.09, N=7
|
|
delta=0.017, N=16
|
|
delta=0.004, N=24
|
The code
This is the matlab code that generates the data. Uncomment the lines with % to see some figures.
df = 0.025;
nuc = 0.2;
delta = 0.09;
passb = nuc-df;
stopb = nuc+df;
dpass = delta;
dstop = delta;
nusamp = 1;
[n,fo,ao,w] = firpmord([passb stopb],[1 0],[dpass dstop],nusamp);
b = firpm(n,fo,ao,w);
[h,w] = freqz(b,1,512);
%figure(1)
%plot(fo/2,ao,w/pi/2,abs(h));
kv = [0:511]';
newh = h.*exp(n*pi*i/1024*kv);
%figure(2)
%plot(fo/2,ao,w/pi/2,real(newh));
%figure(3)
%plot(w/pi/2,real(newh));
format shortE
%size(real(newh))
disp('------------------------------------------')
disp((n-1)/2)
delta
%real(newh)
The data generated putting in the matlab program the different values of delta
was stored in files
dpm1.txt,
dpm2.txt,
dpm3.txt
and the figures above were generated with the following SAGE program:
for k in srange(1,4):
with open('dpm'+str(k)+'.txt','r') as f:
text = f.read()
temp = text.split('\n')[:512]
for m in srange(512):
temp[m] = sage_eval( temp[m] )
P = line( [(0,1),(7/40,1),(9/40,0), (1/2,0)], thickness=2, linestyle='--', color='red', zorder= 60)
P += list_plot([(m/1024,temp[m]) for m in srange(512)], plotjoined=True, thickness=4)
P.fontsize(25)
P.save('./pa_mc_'+str(k)+'.png')
error = [(m/1024,1-temp[m]) for m in srange(180)]
error += [( m/1024, 20*(9/40-m/1024)-temp[m] ) for m in srange(180, 231)]
error += [( m/1024,0-temp[m] ) for m in srange(231, 512)]
P = list_plot( error, plotjoined=True, thickness=4)
P.fontsize(25)
P.save('./pa_mc_er'+str(k)+'.png')
error = [(m/1024,1-temp[m]) for m in srange(180)]
P = list_plot( error, plotjoined=True, thickness=4)
ma = 1-min(temp[:180])
mi = 1-max(temp[:180])
error = [( m/1024,0-temp[m] ) for m in srange(231, 512)]
ma = max( ma, 0-min(temp[231:512]) )
mi = min( mi, 0-max(temp[231:512]) )
print k,'->',max(-mi,ma)
P += list_plot( error, plotjoined=True, thickness=4)
P += plot( ma+0*x,7/40,9/40, fill=mi+0*x, color='gray', fillcolor='gray', fillalpha=1)
# P += polygon([(7/40,ma), (9/40,ma), (9/40,mi), (7/40,mi)], color='gray')
P.fontsize(25)
P.save('./pa_mc_e'+str(k)+'.png')