function [h,L2E,mL2,it,cs] = adamslpr(n,up,lo,wp,ws,K,L) % [h,L2E,mL2,it,cs] = adamslpr(n,up,lo,wp,ws,K,L) % An implementation of Adams' approach to constrained weighted % L2 Low Pass FIR filter design % (constraint frequncies are refined with Newton's Method) % see John Adams' paper: FIR Digital Filters with % Least-Squares Stopbands Subject to Peak-Gain Constraints, % in IEEE Trans on Circuits and Systems, % vol 39, no 4, April 1991 % % input: % n : filter length % up : [upper bound in pass band, upper bound in stop band] % lo : [lower bound in pass band, lower bound in stop band] % wp : passband edge of L2 weight function % ws : stopband edge of L2 weight function % K : stopband L2 weight / passband L2 weight % L : grid size (optional) % output: % h : filter of length n % L2E : _unweighted_ L2 error % mL2 : minimum _unweighted_ L2 error achievable % (L2 error of best unweighted L2 filter) % it : number of iterations % cs : constraint set at convergence % % subprograms called: % frefine : refines the extremal frequencies of an FIR filter % local_max : finds local maxima % % EXAMPLE % wp = 0.27*pi; ws = 0.333*pi; n = 55; K = 3; % dp = 0.03; ds = 0.01; up = [1+dp, ds]; lo = [1-dp, -ds]; % [h,L2E,mL2,it,cs] = adamslpr(n,up,lo,wp,ws,K); % % % example from Adams' paper % wp = 0.0625*2*pi; ws = 0.0804*2*pi; n = 95; % ds = 10^(-45/20); % up = [1 ds]; % lo = [10^(-1/20) -ds]; % K = 1000; % [h,L2E,mL2,it,cs] = adamslpr(n,up,lo,wp,ws,K); % this program was coded by: Ivan Selesnick, October 95, Rice University PF = 1; % flag : Plot Figures (1:plot figs, 0:don't) if nargin < 8 L = 2^ceil(log2(3*n)); end r = sqrt(2); w = [0:L]*pi/L; % w includes both 0 and pi kp = round(L*wp/pi+1); ks = round(L*ws/pi+1); wo = (wp+ws)/2; q = round(wo*L/pi); u = [up(1)*ones(q,1); up(2)*ones(L+1-q,1)]; l = [lo(1)*ones(q,1); lo(2)*ones(L+1-q,1)]; if rem(n,2) == 1 parity = 1; m = (n-1)/2; % c = 2*[wo/r; [sin(wo*[1:m])./[1:m]]']/pi; c = 2*[wp/r; [sin(wp*[1:m])./[1:m]]']/pi; Z = zeros(2*L-n,1); v = [0:m]; tt = 1 - 1/r; else parity = 0; m = n/2; Z = zeros(4*L,1); v = [1:m]-1/2; c = [2*sin(wp*v)./(v*pi)]'; tt = 0; end % ----- construct R matrix -------------------- if rem(n,2) == 1 % odd length symmetric filter v1 = 1:m; v2 = m:2*m; tp = [wp+K*(pi-ws), (sin(v1*wp)-K*sin(v1*ws))./v1]/pi; hk = ((sin(v2*wp)-K*sin(v2*ws))./v2)/pi; R = toeplitz(tp,tp) + hankel(tp,hk); R(1,:) = R(1,:)/r; R(:,1) = R(:,1)/r; Ri = inv(R); else % even length symmetric filter v1 = 1:(m-1); v2 = (m-1):2*(m-1); tp = [(wp+K*(pi-ws)), (sin(v1*wp)-K*sin(v1*ws))./v1]/pi; v1 = 1:m; v2 = m:2*m-1; tp2 = ((sin(v1*wp)-K*sin(v1*ws))./v1)/pi; hk2 = ((sin(v2*wp)-K*sin(v2*ws))./v2)/pi; R = toeplitz(tp,tp) + hankel(tp2,hk2); Ri = inv(R); end mL2 = wo/pi - c'*c/2; L2E = mL2; a = Ri*c; % best L2 cosine coefficients mu = []; % Lagrange multipliers SN = 1e-7; % Small Number it = 0; % BEGIN LOOPING while 1 % calculate A (filter response amplitude) if parity == 1 A = fft([a(1)*r; a(2:m+1); Z; a(m+1:-1:2)]); A = real(A(1:L+1)/2); else Z(2:2:2*m) = a; Z(4*L-2*m+2:2:4*L) = a(m:-1:1); A = fft(Z); A = real(A(1:L+1)/2); end % find local maxima and minima kmax = local_max(A); kmin = local_max(-A); if parity == 0 n1 = length(kmax); if kmax(n1) == L+1 kmax(n1) = []; n1 = n1 - 1; end n2 = length(kmin); if kmin(n2) == L+1 kmin(n2) = []; n2 = n2 - 1; end end % refine frequencies cmax = (kmax-1)*pi/L; cmin = (kmin-1)*pi/L; cmax = frefine(a,v,cmax); cmin = frefine(a,v,cmin); % append band edges to constraint set kmax = [kmax; ks]; kmin = [kmin; kp]; cmax = [cmax; ws]; cmin = [cmin; wp]; % evaluate A at refined frequencies Amax = cos(cmax*v)*a - tt*a(1); Amin = cos(cmin*v)*a - tt*a(1); % determine new constraint set v1 = Amax > u(kmax)-10*SN; v2 = Amin < l(kmin)+10*SN; kmax = kmax(v1); kmin = kmin(v2); cmax = cmax(v1); cmin = cmin(v2); Amax = Amax(v1); Amin = Amin(v2); n1 = length(kmax); n2 = length(kmin); % if constraint set is too big, then trim it down % to its maximum size (m+1). % identify w=0 and w=pi as local max or min if (n1+n2) > m+1 [tmp1,i1] = min(kmin); [tmp2,i2] = min(kmax); if tmp1 == 1 zext_type = -1; zi = i1; % (w=0 is a local minimum) else zext_type = 1; zi = i2; % (w=0 is a local maximum) end [tmp1,i1] = max(kmin); [tmp2,i2] = max(kmax); if tmp1 == L+1 piext_type = -1; pii = i1; % (w=pi is a local minimum) else piext_type = 1; pii = i2; % (w=pi is a local maximum) end end if (n1+n2) == m+2 % remove either w=0 or w=pi from % constraint set, not both. % decide which one to remove: if zext_type == 1 E0 = A(1) - up(1); else E0 = lo(1) - A(1); end if piext_type == 1 Epi = A(L+1) - up(2); else Epi = lo(2) - A(L+1); end if E0 > Epi % remove w = 0 from constraint set if zext_type == -1 kmin(zi) = []; n2 = n2 - 1; cmin(zi) = []; Amin(zi) = []; else kmax(zi) = []; n1 = n1 - 1; cmax(zi) = []; Amax(zi) = []; end else % (E0 >= Epi) % remove w = pi from constraint set if piext_type == -1 kmin(pii) = []; n2 = n2 - 1; cmin(pii) = []; Amin(pii) = []; else kmax(pii) = []; n1 = n1 - 1; cmax(pii) = []; Amax(pii) = []; end end elseif (n1+n2) == m+3 % remove both w=0 and w=pi from constraint set if zext_type == -1 kmin(zi) = []; n2 = n2 - 1; cmin(zi) = []; Amin(zi) = []; % update pii if nec. if (piext_type == -1) & (zi < pii) pii = pii-1; end else kmax(zi) = []; n1 = n1 - 1; cmax(zi) = []; Amax(zi) = []; % update pii if nec. if (piext_type == 1) & (zi < pii) pii = pii-1; end end % remove w = pi from constraint set if piext_type == -1 kmin(pii) = []; n2 = n2 - 1; cmin(pii) = []; Amin(pii) = []; else kmax(pii) = []; n1 = n1 - 1; cmax(pii) = []; Amax(pii) = []; end end % plot figures if PF wv = [cmax; cmin]; Av = [Amax; Amin]; figure(1), plot(w/pi,A), axis([0 1 -.2 1.2]) hold on, plot(wv/pi,Av,'o'), hold off figure(2) subplot(211) plot(w/pi,A-1), hold on, plot(wv/pi,Av-1,'o'), hold off axis([0 wo/pi 2*(lo(1)-1) 2*(up(1)-1)]) subplot(212) plot(w/pi,A), hold on, plot(wv/pi,Av,'o'), hold off axis([wo/pi 1 2*lo(2) 2*up(2)]) pause(.5) end % check stopping criterion E = max([Amax-u(kmax); l(kmin)-Amin; 0]); fprintf(1,' Bound Violation = %15.13f L2E = %18.15f\n',E,L2E); if E < SN fprintf(1,' I converged in %d iterations\n',it) break end if E > 20 fprintf(1,'\nI think your specifications are unrealizable.\n\n') end % calculate new Lagrange multipliers if parity == 1 G = [ones(n1,m+1); -ones(n2,m+1)].*cos([cmax; cmin]*[0:m]); G(:,1) = G(:,1)/r; else G = [ones(n1,m); -ones(n2,m)].*cos([cmax; cmin]*([1:m]-1/2)); end d = [u(kmax); -l(kmin)]; mu = (G*Ri*G')\(G*Ri*c-d); % iteratively remove negative multiplier [min_mu,K] = min(mu); while min_mu < 0 G(K,:) = []; d(K) = []; mu = (G*Ri*G')\(G*Ri*c-d); [min_mu,K] = min(mu); end % determine new cosine coefficients vv = G'*mu; L2E = vv'*vv/2 + mL2; a = Ri*(c-vv); it = it + 1; end if parity == 1 h = [a(m+1:-1:2)/2; a(1)/r; a(2:m+1)/2]; else h = [a(m:-1:1); a]/2; end cs = [cmax; cmin];