function h = adamsfir(m,up,lo,wp,ws,K,L) % h = adamsfir(m,up,lo,wp,ws,K,L) % An implementation of Adams' approach to constrained weighted % L2 Low Pass FIR filter design % 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 % % h : 2*m+1 filter coefficients % m : degree of cosine polynomial % up : [upper bound in passband, stopband] % lo : [lower bound in passband, stopband] % wp : passband edge % ws : stopband edge % K : stopband L2 weight / passband L2 weight % L : grid size % need % 0 < wp < ws < pi % example % up = [1.03, 0.02]; lo = [0.97, -0.02]; % wp = 0.27*pi; ws = 0.33*pi; % h = adamsfir(25,up,lo,wp,ws,2,2^11); r = sqrt(2); w = [0:L]'*pi/L; Z = zeros(2*L-1-2*m,1); kp = round(L*wp/pi+1); % index into grid for wp ks = round(L*ws/pi+1); % index into grid for ws q = round((wp+ws)*L/(2*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)]; c = 2*[wp/r; [sin(wp*[1:m])./[1:m]]']/pi; % ----- construct R matrix -------------------- 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); a = Ri*c; % best L2 cosine coefficients mu = []; % Lagrange multipliers SN = 1e-6; % Small Number while 1 % ----- calculate A ------------------------- A = fft([a(1)*r;a(2:m+1);Z;a(m+1:-1:2)]); A = real(A(1:L+1))/2; % ----- find extremals ---------------------- kmax = local_max(A); kmin = local_max(-A); % ---- append bandedges to constraint set --- kmin = [kmin; kp]; kmax = [kmax; ks]; kmax = kmax( A(kmax) > u(kmax)-10*SN ); kmin = kmin( A(kmin) < l(kmin)+10*SN ); 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; else kmax(zi) = []; n1 = n1 - 1; end else % (E0 >= Epi) % remove w = pi from constraint set if piext_type == -1 kmin(pii) = []; n2 = n2 - 1; else kmax(pii) = []; n1 = n1 - 1; 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; % update pii if nec. if (piext_type == -1) & (zi < pii) pii = pii-1; end else kmax(zi) = []; n1 = n1 - 1; % 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; else kmax(pii) = []; n1 = n1 - 1; end end figure(1) plot(w/pi,A) hold on plot(w(kmax)/pi,A(kmax),'o') plot(w(kmin)/pi,A(kmin),'o') hold off pause(.5) % ----- check stopping criterion ------------ Eup = A(kmax)-u(kmax); Elo = l(kmin)-A(kmin); E = max([Eup; Elo; 0]); if E < SN, break, end E % ----- calculate new multipliers ----------- O = [ones(n1,m+1); -ones(n2,m+1)]; G = O .* cos(w([kmax;kmin])*[0:m]); G(:,1) = G(:,1)/r; d = [u(kmax); -l(kmin)]; mu = (G*Ri*G')\(G*Ri*c-d); % ----- 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 coefficients ---------- a = Ri*(c-G'*mu); end h = [a(m+1:-1:2); a(1)*r; a(2:m+1)]/2; E figure(1) plot(w/pi,A) hold on plot(w(kmax)/pi,A(kmax),'o') plot(w(kmin)/pi,A(kmin),'o') hold off