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

    function [h,a] = fircls1(n,wo,dp,ds,varargin)
%FIRCLS1 Low & high pass FIR filter design by constrained least-squares.
%   B = FIRCLS1(N,WO,DP,DS) is a length N+1 linear-phase lowpass FIR filter
%   with cut-off frequency W0 and maximum band deviations DP and DS. 
%   W0 is between 0 and 1 (1 corresponds to half the sampling frequency),
%   DP is the maximum passband deviation from 1, and DS is the maximum stopband
%   deviation from 0.
% 
%   B = FIRCLS1(N,WO,DP,DS,'high') is a highpass filter (order N must be even).
%
%   B = FIRCLS1(N,WO,DP,DS,WT) and B = FIRCLS1(N,WO,DP,DS,WT,'high') meets
%   a passband or stopband edge requirement. If WT is in the passband, then 
%   the use of this parameter ensures that |E(WT)| <= DP where E(w) is the 
%   error function. Similarly, if WT is in the stopband, then the use of WT
%   ensures that |E(WT)| <= DS. Note that in the design of very narrow band 
%   filters with small DP and DS, there may not exist a filter of the given 
%   length that meets these specifications. 
%
%   B = FIRCLS1(N,WO,DP,DS,WP,WS,K) weights the square error in the passband 
%   K times greater than that in the stopband. WP is the passband edge of the 
%   L2 weight function and WS is the stopband edge (WP < W0 < WS).  Use 
%   trailing WT and 'high' arguments to meet a requirement or design a highpass
%   filter as in the case with no weighting function, e.g. 
%      FIRCLS1(N,WO,DP,DS,WP,WS,K,WT,'high'). 
%   In the 'high' pass filter case, you must have WS < W0 < WP.
%
%   EXAMPLES
%      n = 55;
%      wo = 0.3;
%      dp = 0.02; ds = 0.008;
%      h = fircls1(n,wo,dp,ds);           % no L2 weights
%      wp = 0.28; ws = 0.32;
%      K = 10;
%      h1 = fircls1(n,wo,dp,ds,wp,ws,K);  % L2 weight
%
%   MONITORING THE DESIGN
%      For a textual progress report on the iteration, use a trailing 'trace' 
%      argument, e.g. FIRCLS1(N,W0,DP,DS,...,'trace').  To display plots of 
%      the design iteration, use a trailing 'plots' argument, 
%      FIRCLS1(N,W0,DP,DS,...,'plots').  For both text and plots, use 'both'.
%
%   See also FIRCLS, 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
%   Copyright (c) 1988-98 by The MathWorks, Inc.
%   $Revision: 1.2 $  $Date: 1998/07/13 18:46:35 $

%  subprograms : local_max.m, frefine.m

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

LOW = 0;
HIGH = 1;
pass_type = LOW;
EDGE = 0;
WEIGHTS = 0;
TEXT_PF = 0;
PLOT_PF = 0;

if nargin >= 7 & ~isstr(varargin{3})
	WEIGHTS = 1;
	wp = varargin{1};
	ws = varargin{2};
	K = varargin{3};
	varargin = varargin(4:end);
end

if nargin < 4
	error('You did not supply enough input parameters.')
elseif ( wo <= 0) | ( wo >= 1)
	error('W0 must lie between 0 and 1.')
elseif prod([size(n), size(wo), size(dp), size(ds)]) > 1
	error('Each of N, WO, DP, and DS must be a scalar.')
elseif (dp <= 0) | (ds <= 0)
	error('Both DP and DS must be positive.')
elseif length(varargin)==1
	if isstr(varargin{1})
		switch lower(varargin{1}(1))
		case 'h'
			pass_type = HIGH;
		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 string input.')
		end
	else
		wt = varargin{1};
		EDGE = 1;
	end
elseif length(varargin)==2
	if isstr(varargin{1})
               	switch lower(varargin{1}(1))
               	case 'h'
                       	pass_type = HIGH;
               	otherwise
                       	error('Unrecognized string input.')
               	end
               	switch lower(varargin{2}(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 string input.')
               	end
	else
		wt = varargin{1};
		EDGE = 1;
               	switch lower(varargin{2}(1))
               	case 'h'
                       	pass_type = HIGH;
		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 string input.')
               	end
	end
elseif length(varargin)==3
	wt = varargin{1};
	EDGE = 1;
	if isstr(varargin{2})
                switch lower(varargin{2}(1))
                case 'h'
                        pass_type = HIGH;
                otherwise
                        error('Unrecognized string input.')
                end
	end
	if isstr(varargin{3})
                switch lower(varargin{3}(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 string input.')
                end
	end
end
PASS = 1;
STOP = 2;
if EDGE
   if prod(size(wt)) > 1
	error('WT must be a scalar')
   elseif (wt <= 0) | (wt >= 1) 
	error('WT must lie between 0 and 1.')
   elseif wt == wo
	error('WT must not equal W0')
   elseif wt < wo
	if pass_type == LOW
		edge_type = PASS;
	else
		edge_type = STOP;
	end
   else
	if pass_type == LOW
		edge_type = STOP;
	else
		edge_type = PASS;
	end
   end
end

if WEIGHTS
    if pass_type == LOW
            if (wp > wo) | (ws < wo)
                    error('For lowpass filters, WP < W0 < WS is needed.')
            end
    else
            if (ws > wo) | (wp < wo)
                    error('For highpass filters, WS < W0 < WP is needed.')
            end
    end
end

if pass_type == LOW
   up = [1+dp  ds]; d1 = dp;
   lo = [1-dp -ds]; d2 = ds;
   mag = [1 0];
else
   up = [ ds 1+dp]; d1 = ds;
   lo = [-ds 1-dp]; d2 = dp;
   mag = [0 1];
end

n = n+1;  % convert order to length for this routine
if rem(n,2) == 1
	parity = 1;
else
	parity = 0;
	if pass_type == HIGH
		error('High pass filters must have EVEN orders.')
	end
end

% --------- start algorithm ---------

wo = wo*pi;
if WEIGHTS
    wp = wp*pi;
    ws = ws*pi;
end
if EDGE, wt = wt*pi; end
L = 2^ceil(log2(5*n));
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 parity  == 1
	m = (n-1)/2;
	if WEIGHTS
		c = 2*[wp/r; [sin(wp*[1:m])./[1:m]]']/pi;
	else
		c = 2*[wo/r; [sin(wo*[1:m])./[1:m]]']/pi;
	end
	if pass_type == HIGH
		c = -c;
		c(1) = c(1)+r;
	end
	Z = zeros(2*L-n,1);
	v = [0:m];
	tt = 1 - 1/r;
	NP = m+1;	% NP : number of parameters
else
	m = n/2;
        v = [1:m]-1/2;
	% c = [4*((sin(wo*[2*[1:m]-1]/2))./(2*[1:m]-1))/pi]';
	if WEIGHTS
		c = [2*sin(wp*v)./(v*pi)]';
	else
        	c = [2*sin(wo*v)./(v*pi)]';
	end
	Z = zeros(4*L,1);
	tt = 0;
	NP = m;		% NP : number of parameters
end


if WEIGHTS
	% ----- construct R matrix --------------------
	if rem(n,2) == 1
   	% odd length symmetric filter
   		v1 = 1:m;
   		v2 = m:2*m;
   		if pass_type == LOW
      			tp = [wp+K*(pi-ws), (sin(v1*wp)-K*sin(v1*ws))./v1]/pi;
      			hk = ((sin(v2*wp)-K*sin(v2*ws))./v2)/pi;
   		else % pass_type == HIGH
      			tp = [(pi-wp)+K*ws, (-sin(v1*wp)+K*sin(v1*ws))./v1]/pi;
      			hk = ((-sin(v2*wp)+K*sin(v2*ws))./v2)/pi;
   		end
   		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

	a = Ri*c;       % best L2 cosine coefficients
else
	a = c;          % best L2 cosine coefficients
end
mu = [];                % Lagrange multipliers
SN = 1e-8;              % Small Number
% -------- 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 filter length is even, then remove w=pi from constraint set
   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);

   % insert wt into constraint set if neccessary
   if EDGE
   if pass_type == LOW
      if edge_type == PASS
         w_key = max(cmax(cmax<wo));
         if wt > w_key
            kmin = [kmin; 1];
            cmin = [cmin; wt];
         end
      else % edge_type == STOP
         w_key = min(cmin(cmin>wo));
         if wt < w_key
            kmax = [kmax; L];
            cmax = [cmax; wt];
         end
      end
   else % pass_type == HIGH
      if edge_type == PASS
         w_key = min(cmax(cmax>wo));
         if wt < w_key
            kmin = [kmin; L];
            cmin = [cmin; wt];
         end
      else % edge_type == STOP
         w_key = max(cmin(cmin<wo));
         if wt > w_key
            kmax = [kmax; 1];
            cmax = [cmax; wt];
         end
      end
   end
   end

   % 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)-100*SN;
   v2   = Hmin < l(kmin)+100*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 PLOT_PF
   wv = [cmax; cmin];
   Hv = [Hmax; Hmin];
	subplot(311)
        plot(w/pi,H),
	axis([0 1 -.2 1.2])
	hold on,
	plot(wv/pi,Hv,'o'),
	hold off
	subplot(312)
	plot(w/pi,H-mag(1)),
	hold on,
	plot(wv/pi,Hv-mag(1),'o'),
	hold off
	axis([0 wo/pi -2*d1 2*d1])
	subplot(313)
	plot(w/pi,H-mag(2)),
	hold on,
	plot(wv/pi,Hv-mag(2),'o'),
	hold off
	axis([wo/pi 1 -2*d2 2*d2])
   pause(.5)
   end

   % remove a constraint set frequency if neccessary (if otherwise overdetermined)
   if (n1+n2) > NP
        if parity == 1
           H0 =  a(1)/sqrt(2) + sum(a(2:m+1));
           Hpi = a(1)/sqrt(2) + sum(a(3:2:m+1)) - sum(a(2:2:m+1));
           dH0dw = -sum(a(2:m+1)'.*([1:m].^2));
           dHpidw = sum(a(2:2:m+1)'.*([1:2:m].^2)) - sum(a(3:2:m+1)'.*([2:2:m].^2));
           if dH0dw > 0, E0 = lo(1) - H0;
           else, E0 = H0 - up(1); end
           if dHpidw > 0, Epi = lo(2) - Hpi;
           else, Epi = Hpi - up(2); end
        else % parity == 0
		% when length is even, we know that
		%  we must remove w = 0;
		E0 = 0; Epi = 1;
        end
        if E0 > Epi
                % remove w = pi from constraint set
                [temp1, k1] = max(kmin);
                [temp2, k2] = max(kmax);
                if temp1 < temp2
                        % pi is in kmax
                        kmax(k2) = [];
                        cmax(k2) = [];
                        Hmax(k2) = [];
                        n1 = n1 - 1;
                else
                        % pi is in kmin
                        kmin(k1) = [];
                        cmin(k1) = [];
                        Hmin(k1) = [];
                        n2 = n2 - 1;
                end
        else
		% remove w = 0 from constraint set
                [temp1, k1] = min(kmin);
                [temp2, k2] = min(kmax);
                if temp1 < temp2
                        % 0 is in kmin
                        kmin(k1) = []; 
			cmin(k1) = [];
                        Hmin(k1) = [];
                        n2 = n2 - 1;
                else
                        % 0 is in kmax
                        kmax(k2) = [];
                        cmax(k2) = [];
                        Hmax(k2) = [];
                        n1 = n1 - 1;
                end
        end
   end

   % check stopping criterion
   E  = max([Hmax-u(kmax); l(kmin)-Hmin; 0]);
   if TEXT_PF
      fprintf(1,'    Bound Violation = %15.13f  \n',E);
   end
   if E < SN
      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)];

   if WEIGHTS
       mu = (G*Ri*G')\(G*Ri*c-d);
   else
       mu = (G*G')\(G*c-d);            
   end

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

   % determine new cosine coefficients
   if WEIGHTS
      a = Ri*(c-G'*mu);
   else
      a = c-G'*mu;
   end

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

if nargout > 1
    a = 1;
end