gusucode.com > 信号处理工具箱 - signal源码程序 > signal\signal\signal\fircls.m

    function [h,a] = fircls(n,be,mag,up,lo,PF)
%FIRCLS  Linear-phase FIR filter design by constrained least-squares.
%   B = FIRCLS(N,F,A,UP,LO) is a length N+1 linear phase FIR filter which 
%   approximates the desired piecewise constant frequency response in F and A
%   subject to the constraints given in UP and LO.  
%
%   A is a vector describing the piecewise constant desired amplitude of 
%   the frequency response. The length of A is the number of different bands.
%   UP and LO are vectors of the same length of A. They give the upper and 
%   lower bounds for the frequency response in each band.  
%   F is a vector of transition frequencies. These frequencies must
%   be in increasing order, must start with 0.0, and must end with 1.0.
%   The length of F should exceed the length of A by exactly 1. 
%
%   EXAMPLE 
%      n   = 51;
%      f   = [0 0.4 0.8 1];
%      a = [0 1 0];
%      up  = [ 0.02 1.02  0.01]; 
%      lo  = [-0.02 0.98 -0.01];
%      b   = fircls(n,f,a,up,lo);
%
%   NOTE
%      By setting LO equal to 0 in the stopbands, a nonnegative frequency 
%      response amplitude can be obtained. Such filters can be spectrally
%      factored to obtain minimum phase filters.
%
%   MONITORING THE DESIGN
%      For a textual progress report on the iteration, use a trailing 'trace' 
%      argument, e.g. FIRCLS(N,F,A,UP,LO,'trace').  To display plots of 
%      the design iteration, use a trailing 'plots' argument, 
%      FIRCLS(N,F,A,UP,LO,'plots').  For both text and plots, use 'both'.
%
%   See also FIRCLS1, FIRLS, REMEZ.

%   Reference:
%   I. W. Selesnick, M. Lang and C. S. Burrus,
%   Constrained Least Square Design of FIR Filters 
%   Without Specified Transition Bands,
%   IEEE Trans. on Signal Processing,
%   Aug 1996, Vol 44, Number 8, pp. 1879-1892.

%   Author: Ivan Selesnick, Rice University, 1995
%   Copyright (c) 1988-98 by The MathWorks, Inc.
%   $Revision: 1.1 $  $Date: 1998/06/03 14:42:39 $

%   subprograms : local_max.m, frefine.m

% -------- check input parameters -------------

if nargin < 5
	error('You did not supply enough input parameters.')
else
	lm = length(mag);
	lu = length(up);
	ll = length(lo);
	if (lm ~= lu) | (lm ~= ll) | (lu ~= ll)
		error('Each of A, UP, and LO must have the same length.')
	elseif length(be) ~= (lm+1)
		error('F must have one more element than A')
	elseif be(1) ~= 0
		error('F must begin with 0')
	elseif be(lm+1) ~= 1
		error('F must end with 1')
	elseif any(diff(be)<=0)
		error('The frequencies in F must be in ascending order.')
	elseif any(up <= lo)
		error('Each element of UP must be greater than the corresponding element of LO.')
	elseif any(lo > mag)
		error('Each entry of LO should no greater than the corresponding element of A.')
	elseif any(up < mag)
		error('Each entry of UP should no less than the corresponding element of A.')
	end
end

n = n+1;  % convert order to length

TEXT_PF = 0;
PLOT_PF = 0;
if nargin == 6
    PF = lower(PF);
    switch PF(1)
    case 't'    % as in 'text'
        TEXT_PF = 1;
    case 'p'    % as in 'plots'
        PLOT_PF = 1;
    case 'b'    % as in 'both'
        TEXT_PF = 1; PLOT_PF = 1;
    otherwise, 
      error('Unrecognized trace option. Try ''trace'', ''plots'', or ''both''.')
    end
end

if prod(size(n)) > 1
	error('n should be a scalar')
end

L = 2^ceil(log2(3*n));
num_bands = length(mag);

if rem(n,2) == 0
        parity = 0;
	m = n/2;
	if (lo(num_bands) > 0) | (up(num_bands) < 0)
		error('Even length filters must equal 0 at F=1.');
	end
else
        parity = 1;
	m = (n-1)/2;
end

r = sqrt(2);
be = be * pi;
% ----- calculate Fourier coefficients and upper ---
% ----- and lower bound functions ------------------
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
mu = [];     % Lagrange multipliers
SN = 1e-8;   % Small Number
it = 0;
kmax = zeros(0,1); kmin = zeros(0,1); 
cmax = zeros(0,1); cmin = zeros(0,1);
okmax = []; okmin = []; uvo = 0;
ocmax = []; ocmin = []; lvo = 0;

while 1

  if (uvo < -SN/10) | (lvo < -SN/10) 
     % ----- 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 PLOT_PF
        cc = [cmax; cmin];
        occ = [ocmax; ocmin];
        if ~isempty(cc)
            Acc = cos(cc*v)*a - tt*a(1);
        else
            Acc = [];
        end
        if ~isempty(occ)
            Aocc = cos(occ*v)*a - tt*a(1);
        else
            Aocc = [];
        end

        subplot(length(be),1,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
         subplot(length(be),1,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))])
         ylabel(sprintf('Band #%g',k))
        end
        xlabel('Frequency')
    drawnow
    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;
     v2 = Amin < l(kmin)+SN;
     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]);
     if TEXT_PF
        fprintf(1,'  Bound Violation = %15.13f  \n',E);
     end
     if E < SN, break, end
  end

  % ----- calculate new multipliers -----------
  n1 = length(kmax);         n2 = length(kmin);
  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]*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) = [];
       %if length(Amin)>=K-n1
       %   Amin(K-n1) = [];
       %end
       n2 = n2 - 1;
    else
       kmax(K) = [];
       cmax(K) = [];
       %Amax(K) = [];
       n1 = n1 - 1;
    end
    [min_mu,K] = min(mu);
  end

  % ----- determine new coefficients ----------
  a = c-G'*mu;

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

  it = it + 1;
end

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

h = h(:)';

if nargout > 1
    a = 1;
end