gusucode.com > 信号处理工具箱 - signal源码程序 > signal\signal\signal\maxflat.m
function [b,a,b1,b2] = maxflat(Z,P,wo,PF) %MAXFLAT Maximally flat (a.k.a. generalized Butterworth) digital filter design. % [B,A] = MAXFLAT(NB,NA,Wn) is a lowpass Butterworth filter with numerator % and denominator coefficients B and A of orders NB and NA respectively. % Wn is the cut-off frequency at which the filter's magnitude response % is equal to 1/sqrt(2) (approx. -3 dB). Wn must be between 0 and 1, with % 1 corresponding to half the sample rate of the filter. When NA=0, the % range of Wn is further restricted due to the smoothness of the filter's % response. % % B = MAXFLAT(NB,'sym',Wn) is a symmetric FIR Butterworth filter. NB must be % even, and Wn is restricted to a subinterval of [0,1]. The function will % raise an error if you specify Wn outside of this subinterval. % % [B,A,B1,B2] = MAXFLAT(NB,NA,Wn) and [B,A,B1,B2] = MAXFLAT(NB,'sym',Wn) % return two polynomials B1 and B2 whose product is equal to the numerator % polynomial B (i.e., B = CONV(B1,B2)). B1 contains all the zeros at z=-1, % and B2 contains all the other zeros. % % EXAMPLES % NB = 10; NA = 2; Wn = 0.6; % [b,a,b1,b2] = maxflat(NB,NA,Wn); % h = maxflat(NB,'sym',Wn); % % MONITORING THE DESIGN % For a textual display of the design table used in the design, use a % trailing 'trace' argument, e.g. MAXFLAT(NB,NA,Wn,'trace'). To display % plots of the filter's magnitude, group delay and zeros and poles, use % a trailing 'plots' argument, MAXFLAT(NB,NA,Wn,'plots'). For both text % and plots, use 'both'. % % See also BUTTER, FREQZ, FILTER. % by I. W. Selesnick and C. S. Burrus % see: Generalized Digital Butterworth Filter Design % by I. W. Selesnick and C. S. Burrus, % IEEE International Conference on Acoustics, % Speech and Signal Processing, % May 1996, Volume 3, p. 1367. % Author: Ivan Selesnick, Rice University, September 1995. % Copyright (c) 1988-98 by The MathWorks, Inc. % $Revision: 1.1 $ $Date: 1998/06/03 14:43:16 $ % required subprograms : spec_table.m, choose.m TEXT_PF = 0; PLOT_PF = 0; SYMM = 0; if isstr(P) SYMM = 1; P = 0; if rem(Z,2)==1 error('For symmetric FIR filters, only even orders are allowed.') else % (Z is even) Z = Z/2; end end if nargin > 3 if ~isstr(PF) error('Plot flag must be ''trace'', ''plots'', or ''both''.') end switch lower(PF(1)) case 't' TEXT_PF = 1; case 'p' PLOT_PF = 1; case 'b' TEXT_PF = 1; PLOT_PF = 1; otherwise error('Plot flag must be ''trace'', ''plots'', or ''both''.') end end SN = 1e-7; table = spec_table(Z,P,SYMM); wo = wo*pi; k = max(find((table(:,4) < wo/pi+SN) & (table(:,5) > wo/pi-SN))); %%%%%%%%%%%%%%%%%%%% DISPLAY TABLE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if TEXT_PF disp(' Table:') disp(' ') disp(' L M N wo_min/pi wo_max/pi') disp(' ') disp(table) if SYMM disp(' L and M are doubled for symmetric FIR filters.') disp(' ') end % L+M : total number of zeros % N : total number of poles % % L : number of zeros at z=-1 % M : number of zeros contributing to passband flatness % N : number of poles end if PLOT_PF clf set(gcf,'nextplot','add'); a1 = axes('units','normalized','position',[.1 .6 .8 .3]); a2 = axes('units','normalized','position',[.1 .1 .35 .4]); a3 = axes('units','normalized','position',[.55 .1 .35 .4]); end %%%%%%%%%%%%%%%%%%%% error %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if length(k) == 0 error(sprintf('For NB=%g and NA=%g, Wn must be between %g and %g.',... (1+SYMM)*Z,P,table(1,4),table(end,5))) end %%%%%%%%%%%%%%%%%%%% CALCULATE x-Domain function %%%%%%%%%%%%%%%%%% L = table(k,1); M = table(k,2); N = table(k,3); xo = (1-cos(wo))/2; %Fo = (1/2)^2; Fo = 1/2; if SYMM Fo = sqrt(Fo); end if N == 0 %%%%%%%%%%%% FIR %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% k = M-1:-1:0; R = [0, choose(M-k-1,0).*choose(L+k-1,k)]; T = [choose(M-k-2,-1).*choose(L+k,k), 0]; c1 = (Fo/(1-xo)^L - polyval(R,xo)); c2 = polyval(T,xo); S = c2*R + c1*T; Q = 1; elseif M == 0 %%%%%%%%%%%% ALL ZEROS at z = -1 %%%%%%%%%%%%%%%%%%%%%%%%%% k = min([L,N]):-1:0; Q = choose(L,k).*(-1).^k; if L < N Q = [zeros(1,N-L), Q]; end c1 = ((1/Fo)*(1-xo)^L - polyval(Q,xo))/(xo^N); Q(1) = Q(1) + c1; S = 1; else % M > 0 %%%%%%%%%%%% Some Zeros contribute to passband %%%%%%%%%%%% k = M-1:-1:0; R = [0, choose(M+N-k-1,N).*choose(L-N+k-1,k)]; T = [choose(M+N-k-2,N-1).*choose(L-N+k,k), 0]; k = N:-1:0; AGR = choose(M+N-k-1,M-1).*choose(M+L-1,k).*(-1).^k; AGT = choose(M+N-k-1,M-1).*choose(M+L-1,k-1).*(-1).^(k-1); c1 = (((1-xo)^L)*polyval(R,xo) - Fo*polyval(AGR,xo)); c2 = (Fo*polyval(AGT,xo) - ((1-xo)^L)*polyval(T,xo)); S = c2*R + c1*T; Q = c2*AGR + c1*AGT; end %%%%%%%%%%%%%%%%%%%% convert to z-domain %%%%%%%%%%%%%%%%%%%%%%%%%% tmp = 1 - 2*roots(S); br1 = tmp+sqrt(tmp.^2-1); br2 = tmp-sqrt(tmp.^2-1); br = sort([br1; br2]+eps*sqrt(-1)); % sort by absolute value if ~SYMM if c1 ~= 0 br = br(1:M); % take roots INSIDE unit circle else br = [br(1:M-1); 0]; % take roots INSIDE unit circle end end b2 = real(poly(br)); Qrts = roots(Q); ar1 = 1-2*Qrts+sqrt((1-2*Qrts).^2-1); ar2 = 1-2*Qrts-sqrt((1-2*Qrts).^2-1); ar = sort([ar1; ar2]+eps*sqrt(-1)); % sort by absolute value if ~SYMM ar = ar(1:N); % take roots INSIDE unit circle end a = real(poly(ar)); %%%%%%%%%%%%%%%%%%%% construct b1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if SYMM L = 2*L; end b1 = 1; b = b2; for t = 1:L b1 = conv(b1,[1 1]); b = conv(b,[1 1]); end %%%%%%%%%%%%%%%%%%%% normalize %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if abs(sum(b2)) < 100*eps % terminate program error('A pole-zero pair cancels at z=1. Use a lower order.') else b2 = b2*sum(a)/(sum(b1)*sum(b2)); b = conv(b1,b2); end %%%%%%%%%%%%%%%%%%%% DISPLAY RESULTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if length(a) & PLOT_PF % ---- PLOT MAGNITUDE ---- [Mb1,w] = h2mag(b1); [Mb2,w] = h2mag(b2); [Ma,w] = h2mag(a); Mag = Mb1.*Mb2./Ma; axes(a1) plot(w/pi,Mag) xlabel('\omega/\pi') ylabel('Magnitude') title('Frequency response') axis([0 1 -.1 1.1]) % ---- PLOT POLE-ZERO DIAGRAM ---- I = sqrt(-1); SN = 1e-7; axes(a2) circ = exp([0:100]/100 * 2 * pi * I); plot(circ,'--') hold on if length(ar) plot(ar+SN*I,'x') end if length(br) plot(br+SN*I,'o') end plot([-1+SN*I],'o') hold off axis([-1 1 -1 1]*1.2) xlabel('Real') ylabel('Imaginary') if SYMM title('Zero plot (zeros outside circle not shown)') else title('Pole-zero plot') end s1 = ['<- deg ',num2str(L)]; t1 = text(-0.9,0,s1); axis('square') % ---- PLOT GROUP DELAY ---- gd = grpdelay(b2,a,w)+L/2; axes(a3) plot(w/pi,gd) mingd = min(gd); maxgd = max(gd); if (maxgd-mingd)<(1e-10)*(abs(maxgd)+abs(mingd)) set(a3,'ylim',[0 2*maxgd]) end xlabel('\omega/\pi') ylabel('Samples') title('Group delay') set(gcf,'nextplot','replace'); end function table = spec_table(Z,P,SYMM) % % table = spec_table(Z,P,SYMM); % % General Butterworth Filter Design % This program decides how many zeros should lie at % z = -1 and how many should contribute to the passband % % Z : total number of zeros % P : total number of poles % % % Example: % % Z = 10; P = 2; % table = spec_table(Z,P); % % Ivan Selesnick, Rice University, % September 1995. % see: Generalized Digital Butterworth Filter Design % required subprograms : choose.m if Z <= P table = [Z 0 P 0 1]; return else table = []; end %Fo = (1/2)^2; % value of mag squared at half-mag freq. Fo = 1/2; % value of mag squared at half-mag freq. if SYMM Fo = sqrt(Fo); end %%%%%%% begin with all zeros at z = -1 %%%%%%% L = Z; M = 0; N = P; if N > 0 if rem(N,2) == 0 c = 0; % N even else c = choose(L-1,N); % N odd end %%%%%%% construct polynomial for checking boundary %%%%%% Y = zeros(1,L+1); for i = 0:N Y(i+1) = choose(L,i)*(1-Fo)*(-1)^i; end for i = N+1:L Y(i+1) = choose(L,i)*(-1)^i; end Y(N+1) = Y(N+1) - c*Fo; Y = Y(L+1:-1:1); %%% extract appropriate root %%% r = specroot(Y); wo_max = acos(1-2*r); table = [Z, 0, P, 0, wo_max/pi]; end %%%%%%%%% go through each and check %%%%%%%%% for M = 1:Z-P-1 L = Z-M; k = M-1:-1:0; R = [0, choose(M+N-k-1,N).*choose(L-N+k-1,k)]; T = [choose(M+N-k-2,N-1).*choose(L-N+k,k), 0]; k = M+L:-1:0; GR = choose(M+N-k-1,M-1).*choose(M+L-1,k).*(-1).^k; GT = choose(M+N-k-1,M-1).*choose(M+L-1,k-1).*(-1).^(k-1); AGR = GR(M+L+1-N:M+L+1); AGT = GT(M+L+1-N:M+L+1); %%% ------- wo_max ---------------------------------- %%% if rem(N,2) == 0 c = (L-N)/(M+N); % N even else c = (L-N)/N; % N odd end Y = [zeros(1,M+L-N), Fo*AGR+c*Fo*AGT]-GR-c*GT; %%%%%%% extract appropriate root %%% r = specroot(Y); wo_max = acos(1-2*r); %%% ------- wo_min ---------------------------------- %%% if rem(N,2) == 0 c = -1; % N even Y = [zeros(1,M+L-N), Fo*AGR+c*Fo*AGT]-GR-c*GT; else c = inf; % N odd Y = [zeros(1,M+L-N), Fo*AGT]-GT; end %%%%%%% extract appropriate root %%% r = specroot(Y); wo_min = acos(1-2*r); table = [table; [L,M,N, wo_min/pi, wo_max/pi]]; end if N > 0 M = Z-P; L = Z-M; table = [table; [L,M,N, table(Z-P,5), 1]]; end function a = choose(n,k) % % a = choose(n,k) % BINOMIAL COEFFICIENTS % % allowable inputs: % n : integer, k : integer % n : integer vector, k : integer % n : integer, k : integer vector % n : integer vector, k : integer vector (of equal dimension) % nv = n; kv = k; if (length(nv) == 1) & (length(kv) > 1) nv = nv * ones(size(kv)); elseif (length(nv) > 1) & (length(kv) == 1) kv = kv * ones(size(nv)); end a = nv; for i = 1:length(nv) n = nv(i); k = kv(i); if n >= 0 if k >= 0 if n >= k c = prod(1:n)/(prod(1:k)*prod(1:n-k)); else c = 0; end else c = 0; end else if k >= 0 c = (-1)^k * prod(1:k-n-1)/(prod(1:k)*prod(1:-n-1)); else if n >= k c = (-1)^(n-k)*prod(1:-k-1)/(prod(1:n-k)*prod(1:-n-1)); else c = 0; end end end a(i) = c; end function r = specroot(Y) r = roots(Y); r = r(imag(r)==0); [temp,i] = min(abs(r-0.5)); r = r(i); % other alternatives: %SN = 1e-5; %r = newton(Y,[SN 1-SN]); %f = inline('polyval(p,x)','x','p'); %r = fzero(f,.5,eps,0,Y); function [M,w] = h2mag(h) % [M,w] = h2mag(h) L = 2^9; f = fft(h,2*L); M = abs(f); M = M(1:L+1); w = [0:L]'*pi/L;