function [h,bev,L2E,mL2,it,cs] = cl2mbr(n,mag,be,up,lo)
% [h,bev,L2E,mL2,it,cs] = cl2mbr(n,mag,be,up,lo)
% Constrained L2 MultiBand FIR filter design
% Author: Ivan Selesnick, Rice University, 1995
%  n   : filter length
%  mag : vector of magnitudes
%  be  : vector of band edges
%  up  : vector of upper bounds
%  lo  : vector of lower bounds
% output:
%   h   : filter of length n
%   bev : vector of bandeges
%   L2E : L2 error
%   mL2 : minimum L2 error achievable (L2 error of best L2 filter)
%   it  : number of iterations
%   cs  : constraint set at convergence
%
% example
%   n   = 30;
%   mag = [0 1 0];
%   be  = [0.3, 0.6]*pi;
%   up  = [0.02, 1.02, 0.02]; lo = [-0.02, 0.98, -0.02];
%   h   = cl2mbr(n,mag,be,up,lo);

PF = 0;		% PF : print flag

L = 2^ceil(log2(3*n));
r = sqrt(2);
be = [0; be(:); pi];
if rem(n,2) == 0
        parity = 0;
	m = n/2;
else
        parity = 1;
	m = (n-1)/2;
end

% ----- calculate Fourier coefficients and upper ---
% ----- and lower bound functions ------------------

num_bands = length(mag);
if parity == 1
   c = zeros(m+1,1);
   Z = zeros(2*L-1-2*m,1);
   v = [0:m];
   tt = 1-1/r;
else
   c = zeros(m,1);
   Z = zeros(4*L,1);
   v = [1:m]-1/2;
   tt = 0;
end
u = [];
l = [];
for k = 1:num_bands
   if parity == 1
   	c = c + mag(k) * ...
        	(2*[be(k+1)/r; [sin(be(k+1)*[1:m])./[1:m]]']/pi - ...
         	 2*[be(k)/r;   [sin(be(k)*[1:m])./[1:m]]']/pi);
   else
   	c = c + mag(k) * ...
        	( [4*((sin(be(k+1)*[2*[1:m]-1]/2))./(2*[1:m]-1))/pi]' - ...
          	  [4*((sin(be(k) * [2*[1:m]-1]/2))./(2*[1:m]-1))/pi]' ) ;

   end
   q = round(L*(be(k+1)-be(k))/pi);
   u = [u; up(k)*ones(q,1)];
   l = [l; lo(k)*ones(q,1)];
end
flen = length(u);
if flen < L+1
   ov = ones(L+1-flen,1);
   u(flen+1:L+1) = up(num_bands)*ov;
   l(flen+1:L+1) = lo(num_bands)*ov;
elseif flen > L+1
   u = u(1:L+1);
   l = l(1:L+1);
end

w = [0:L]'*pi/L;
a = c;       % best L2 cosine coefficients
mL2 = sum([diff(be(:)) .* (mag(:).^2)])/pi - c'*c/2;
L2E = mL2;
mu = [];     % Lagrange multipliers
SN = 1e-9;   % Small Number
it = 0;
okmax = []; okmin = []; uvo = 0;
ocmax = []; ocmin = []; lvo = 0;
kmax = []; kmin = [];
cmax = []; cmin = [];

while 1

  if (uvo > SN/2) | (lvo > SN/2) 
     % ----- include old extremal ----------------
     if uvo > lvo
        kmax = [kmax; okmax(k1)]; okmax(k1) = [];
        cmax = [cmax; ocmax(k1)]; ocmax(k1) = [];
     else
        kmin = [kmin; okmin(k2)]; okmin(k2) = [];
        cmin = [cmin; ocmin(k2)]; ocmin(k2) = [];
     end
  else
     % ----- calculate A -------------------------
     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

     if PF
	cc = [cmax; cmin];
	occ = [ocmax; ocmin];
	if length(cc)>0
	   Acc = cos(cc*v)*a - tt*a(1);
        else
           Acc = [];
        end
	if length(occ)>0
	   Aocc = cos(occ*v)*a - tt*a(1);
        else
	   Aocc = [];
        end

        figure(1);
        plot(w/pi,A), hold on
        plot(cc/pi,Acc,'o')
        plot(occ/pi,Aocc,'x')
        hold off

        for k = 1:length(be)-1
         figure(k+1);
         plot(w/pi,A), hold on
         plot(cc/pi,Acc,'o')
         plot(occ/pi,Aocc,'x')
         hold off
         axis([be(k)/pi be(k+1)/pi ...
                mag(k)-1.5*(mag(k)-lo(k)) mag(k)+1.5*(up(k)-mag(k))])
        end
    end

     % ----- find extremals ----------------------
     okmax = kmax;              okmin = kmin;
     ocmax = cmax;              ocmin = cmin;
     kmax = local_max(A);       kmin = local_max(-A);
     if parity == 0
        n1 = length(kmax);
        if kmax(n1) == L+1, kmax(n1) = []; end
        n2 = length(kmin);
        if kmin(n2) == L+1, kmin(n2) = []; end
     end
     cmax = (kmax-1)*pi/L;      cmin = (kmin-1)*pi/L;
     cmax = frefine(a,v,cmax);  cmin = frefine(a,v,cmin);

     Amax = cos(cmax*v)*a - tt*a(1);
     Amin = cos(cmin*v)*a - tt*a(1);
     v1 = Amax > u(kmax)-SN/10;
     v2 = Amin < l(kmin)+SN/10;
     kmax = kmax(v1); kmin = kmin(v2);
     cmax = cmax(v1); cmin = cmin(v2);
     Amax = Amax(v1); Amin = Amin(v2);

     % ----- check stopping criterion ------------
     Eup = Amax-u(kmax); Elo = l(kmin)-Amin;
     E = max([Eup; Elo]);
     fprintf(1,'  Bound Violation = %15.13f  L2E = %18.15f\n',E,L2E);
     if E < SN, break, end
  end

  % ----- calculate new multipliers -----------
  n1 = length(kmax);         n2 = length(kmin);
  if parity == 1
     O  = [ones(n1,m+1); -ones(n2,m+1)];
     G  = O .* cos([cmax;cmin]*[0:m]);
     G(:,1) = G(:,1)/r;
  else
     O  = [ones(n1,m); -ones(n2,m)];
     G  = O .* cos([cmax;cmin]*v);
  end
  d  = [u(kmax); -l(kmin)];
  mu = (G*G')\(G*c-d);

  % ----- remove negative multiplier ----------
  [min_mu,K] = min(mu);
  while min_mu < 0
    G(K,:) = []; d(K) = [];
    mu = (G*G')\(G*c-d);
    if K > n1
       kmin(K-n1) = [];
       cmin(K-n1) = [];
       n2 = n2 - 1;
    else
       kmax(K) = [];
       cmax(K) = [];
       n1 = n1 - 1;
    end
    [min_mu,K] = min(mu);
  end

  % ----- determine new coefficients ----------
  vv  = G'*mu;
  L2E = vv'*vv/2 + mL2;
  a   = c-vv;

  if length(ocmax)>0
     oAmax = cos(ocmax*v)*a - tt*a(1);
     [uvo,k1] = max([oAmax-u(okmax); 0]);
  else
     uvo = 0;
  end
  if length(ocmin)>0
     oAmin = cos(ocmin*v)*a - tt*a(1);
     [lvo,k2] = max([l(okmin)-oAmin; 0]);
  else
     lvo = 0;
  end

  it = it + 1;
end

fprintf(1,'    I converged in %d iterations\n',it)

if parity == 1
   h = [a(m+1:-1:2); a(1)*r; a(2:m+1)]/2;
else
   h = [a(m:-1:1); a]/2;
end
be = be(2:length(be)-1);
Q = [be(:)'; be(:)'];
Q = Q(:);
S = [mag(:)'; mag(:)'];
S = S(:);
S = S(2:length(S)-1);
bev = ffbe(a,v,Q,S+tt*a(1));
cs  = [cmax; cmin];

	Acs = cos(cs*v)*a - tt*a(1);
        figure(1);
        plot(w/pi,A), hold on
        plot(cs/pi,Acs,'o')
        hold off



