function [h,wp,ws,L2E,mL2,it,cs] = cl2lpr(n,wo,up,lo,L)
% [h,wp,ws,L2E,mL2,it,cs] = cl2lpr(n,wo,up,lo,L)
% Constrained L2 Low Pass FIR filter design with Refinement
% (constraint frequncies are refined with Newton's Method)
% Author : Ivan Selesnick, October 94, Rice University
% input:  
%  n  : filter length
%  wo : cut-off frequency in (0,pi)
%  up : [upper bound in pass band, upper bound in stop band]
%  lo : [lower bound in pass band, lower bound in stop band]
%  L  : grid size (optional)
% output:
%  h   : filter of length n
%  wp  : passband edge
%  ws  : stopband edge
%  L2E : L2 error
%  mL2 : minimum L2 error achievable (L2 error of best L2 filter)
%  it  : number of iterations
%  cs  : constraint set at convergence
% subprograms called:
%  frefine   : refines the extremal frequencies of an FIR filter
%  ffbe      : finds the band edges of an FIR filter
%  local_max : finds local maxima
% EXAMPLE
%  wo = 0.3*pi; n = 50; 
%  dp = 0.02; ds = 0.004; up = [1+dp, ds]; lo = [1-dp, -ds];
%  [h,wp,ws,L2E,mL2,it,cs] = cl2lpr(n,wo,up,lo);

PF = 1;                          % flag : Plot Figures (1:plot figs, 0:don't)

if nargin < 5
   L = 2^ceil(log2(3*n));
end
r = sqrt(2);
w = [0:L]*pi/L;                  % w includes both 0 and pi
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;
	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(wo*v)./(v*pi)]';
	tt = 0;
end

mL2 = wo/pi - c'*c/2;
L2E = mL2;
a = c;                          % best L2 cosine coefficients
mu = [];                        % Lagrange multipliers
SN = 1e-8;                      % Small Number
it = 0;
% BEGIN LOOPING
while 1

   % calculate H 
   if parity == 1
      H = fft([a(1)*r; a(2:m+1); Z; a(m+1:-1:2)]); 
      H = real(H(1:L+1)/2);
   else
      Z(2:2:2*m) = a;
      Z(4*L-2*m+2:2:4*L) = a(m:-1:1);
      H = fft(Z);
      H = real(H(1:L+1)/2);
   end

   % find local maxima and minima
   kmax = local_max(H);
   kmin = local_max(-H);
   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);

   % evaluate H at refined frequencies
   Hmax = cos(cmax*v)*a - tt*a(1);
   Hmin = cos(cmin*v)*a - tt*a(1);

   % determine new constraint set
   v1   = Hmax > u(kmax)-10*SN;
   v2   = Hmin < l(kmin)+10*SN;
   kmax = kmax(v1);
   kmin = kmin(v2);
   cmax = cmax(v1);
   cmin = cmin(v2);
   Hmax = Hmax(v1);
   Hmin = Hmin(v2);
   n1   = length(kmax);
   n2   = length(kmin);

   % plot figures
   if PF 
   wv = [cmax; cmin];
   Hv = [Hmax; Hmin];
   figure(1),
	plot(w/pi,H),
	axis([0 1 -.2 1.2])
	hold on,
	plot(wv/pi,Hv,'o'),
	hold off
   figure(2)
	subplot(211)
	plot(w/pi,H-1),
	hold on,
	plot(wv/pi,Hv-1,'o'),
	hold off
	axis([0 wo/pi 2*(lo(1)-1) 2*(up(1)-1)])
	subplot(212)
	plot(w/pi,H),
	hold on,
	plot(wv/pi,Hv,'o'),
	hold off
	axis([wo/pi 1 2*lo(2) 2*up(2)])
   pause(.5)
   end

   % check stopping criterion
   E  = max([Hmax-u(kmax); l(kmin)-Hmin; 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

   % 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*G')\(G*c-d);            

   % iteratively remove negative multiplier
   [min_mu,K] = min(mu);
   while min_mu < 0
      G(K,:) = [];
      d(K) = [];
      mu = (G*G')\(G*c-d);            
      [min_mu,K] = min(mu);
   end

   % determine new cosine coefficients
   vv  = G'*mu;
   L2E = vv'*vv/2 + mL2;
   a   = 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

be = ffbe(a,v,[wo,wo],[lo(1),up(2)]+tt*a(1));
wp = be(1);
ws = be(2);
cs = [cmax; cmin];


