gusucode.com > 信号处理工具箱 - signal源码程序 > signal\signal\signal\zp2sos.m
function [sos,g] = zp2sos(varargin) %ZP2SOS Zero-pole-gain to second-order sections model conversion. % [SOS,G] = ZP2SOS(Z,P,K) finds a matrix SOS in second-order sections % form and a gain G which represent the same system H(z) as the one % with zeros in vector Z, poles in vector P and gain in scalar K. % The poles and zeros must be in complex conjugate pairs. Because of % the scaling done, all poles must be inside the unit circle, i.e, % the system must be stable. % % SOS is an L by 6 matrix with the following structure: % SOS = [ b01 b11 b21 1 a11 a21 % b02 b12 b22 1 a12 a22 % ... % b0L b1L b2L 1 a1L a2L ] % % Each row of the SOS matrix describes a 2nd order transfer function: % b0k + b1k z^-1 + b2k z^-2 % Hk(z) = ---------------------------- % 1 + a1k z^-1 + a2k z^-2 % where k is the row index. % % G is a scalar which accounts for the overall gain of the system. If % G is not specified, the gain is embedded in the first section. % The second order structure thus describes the system H(z) as: % H(z) = G*H1(z)*H2(z)*...*HL(z) % % ZP2SOS(Z,P,K,DIR_FLAG) specifies the ordering of the 2nd order % sections. If DIR_FLAG is equal to 'UP', the first row will contain % the poles closest to the origin, and the last row will contain the % poles closest to the unit circle. If DIR_FLAG is equal to 'DOWN', the % sections are ordered in the opposite direction. The zeros are always % paired with the poles closest to them. DIR_FLAG defaults to 'UP'. % % ZP2SOS(Z,P,K,DIR_FLAG,SCALE) specifies the desired scaling of the gain % and the numerator coefficients of all 2nd order sections. SCALE can be % either 'NONE', 'INF' or 'TWO' which correspond to no scaling, infinity % norm scaling and 2-norm scaling respectively. SCALE defaults to 'NONE'. % Using infinity-norm scaling in conjunction with 'UP' ordering will % minimize the probability of overflow in the realization. On the other % hand, using 2-norm scaling in conjunction with 'DOWN' ordering will % minimize the peak roundoff noise. % % See also TF2SOS, SOS2ZP, SOS2TF, SOS2SS, SS2SOS, CPLXPAIR. % NOTE: restricted to real coefficient systems (poles and zeros % must be in conjugate pairs) % References: % [1] L. B. Jackson, DIGITAL FILTERS AND SIGNAL PROCESSING, 3rd Ed. % Kluwer Academic Publishers, 1996, Chapter 11. % [2] S.K. Mitra, DIGITAL SIGNAL PROCESSING. A Computer Based Approach. % McGraw-Hill, 1998, Chapter 9. % [3] P.P. Vaidyanathan. ROBUST DIGITAL FILTER STRUCTURES. Ch 7 in % HANDBOOK FOR DIGITAL SIGNAL PROCESSING. S.K. Mitra and J.F. % Kaiser Eds. Wiley-Interscience, N.Y. % Author(s): R. Losada % Copyright (c) 1988-98 by The MathWorks, Inc. % $Revision: 1.3 $ $Date: 1998/07/30 19:05:40 $ error(nargchk(2,5,nargin)) z = varargin{1}; p = varargin{2}; % Setup default values k = 1; direction_flag = 'up'; scale = 'none'; % Replace with given values if nargin > 2, if ~isempty(varargin{3}), k = varargin{3}; end if nargin > 3, if ~isempty(varargin{4}), direction_flag = varargin{4}; end if nargin > 4, if ~isempty(varargin{5}), scale = varargin{5}; end end end end % Input check diropts = {'up','down'}; scaleopts = {'none','inf','two'}; indx1 = strmatch(lower(direction_flag),diropts); if isempty(indx1), error('DIR_FLAG must be either ''UP'' or ''DOWN''.'); end direction_flag = diropts{indx1}; indx2 = strmatch(lower(scale),scaleopts); if isempty(indx2), error('SCALE must be either ''NONE'', ''INF'' or ''TWO''.'); end scale = scaleopts{indx2}; % Check for stability if 1 - max(abs(p)) < eps^(3/4), error('The system must be stable.'); end % Order the poles and zeros in complex conj. pairs z = cplxpair(z); p = cplxpair(p); % Get the number of poles and zeros lz = length(z); lp = length(p); if lz > lp, error('The number of zeros cannot be greater than the number of poles.'); end L = ceil(lp/2); % break up conjugate pairs and real poles ind = find(abs(imag(p))>0); p_conj = p(ind); % the poles that have conjugate pairs ind_complement = 1:length(p); if length(ind)>0 ind_complement(ind) = []; end p_real = p(ind_complement); % the poles that are real % order the conjugate pole pairs according to proximity to unit circle [temp,ind] = sort(abs(p_conj - exp(j*angle(p_conj)))); p_conj = p_conj(ind); % order the real poles according to proximity to unit circle too [temp,ind] = sort(abs(p_real - sign(p_real))); p_real = p_real(ind); % Save the ordered poles new_p = [p_conj;p_real]; % break up conjugate pairs and real zeros ind = find(abs(imag(z))>0); z_conj = z(ind); % the zeros that have conjugate pairs ind_complement = 1:length(z); if length(ind)>0 ind_complement(ind) = []; end z_real = z(ind_complement); % the zeros that are real % order the conjugate zero pairs according to proximity to pole pairs new_z = []; for i = 1:length(z_conj)/2, if ~isempty(p_conj), [temp,ind1] = min(abs(z_conj-p_conj(1))); [temp,ind2] = min(abs(z_conj-p_conj(2))); new_z = [new_z; z_conj(ind1); z_conj(ind2)]; p_conj([1 2]) = []; z_conj([ind1 ind2]) = []; elseif ~isempty(p_real), [temp,ind] = min(abs(z_conj-p_real(1))); new_z = [new_z; z_conj(ind); z_conj(ind+1)]; z_conj([ind ind+1]) = []; p_real(1) = []; if ~isempty(p_real), p_real(1) = []; end else new_z = [new_z; z_conj]; break end end % order the real zeros according to proximity to pole pairs too for i = 1:length(z_real), if ~isempty(p_conj), [temp,ind] = min(abs(z_real-p_conj(1))); new_z = [new_z; z_real(ind)]; z_real(ind) = []; p_conj(1) = []; elseif ~isempty(p_real), [temp,ind] = min(abs(z_real-p_real(1))); new_z = [new_z; z_real(ind)]; z_real(ind) = []; p_real(1) = []; else new_z = [new_z; z_real]; break end end sos = []; if lz == 0, if lp == 0, sos = [1 0 0 1 0 0]; elseif ~rem(lp,2), sos = sosfun(1,2*L-1,new_p,sos); %even number of poles else sos = sosfun(1,2*(L-1)-1,new_p,sos); %odd number of poles sos = last_pole([],new_p(end),sos);%handle the last pole separately end else if ~rem(lz,2), sos = sosfun2(1,lz-1,new_z,new_p,sos); %even number of zeros % Now continue for the excess poles if any if ~rem(lp,2), sos = sosfun(lz+1,lp,new_p,sos); %even number of poles else sos = sosfun(lz+1,lp-1,new_p,sos); %odd number of poles sos = last_pole([],new_p(end),sos);%handle the last pole separately end else sos = sosfun2(1,lz-1,new_z,new_p,sos); %odd number of zeros %handle the last zero separately if lz == lp, %if number of poles = number of zeros sos = last_pole(new_z(lz),new_p(lz),sos);%handle the last pole separately else % more poles than zeros [num,den] = zp2tf(new_z(lz),new_p(lz:lz+1),1); sos = [num den;sos]; % Now continue for the excess poles if any if ~rem(lp,2), sos = sosfun(lz+2,lp,new_p,sos); %even number of poles else sos = sosfun(lz+2,lp-1,new_p,sos); %odd number of poles sos = last_pole([],new_p(end),sos);%handle the last pole separately end end end end % Change direction if requested if strcmp(direction_flag,'down'), sos = flipud(sos); end % At this point no scaling has been peformed % The leading coefficients of both num and den are one. % Perform appropriate scaling if any(strcmp(scale,{'two','inf'})), [sos,k] = scaling(sos,k,L,scale); end % Embed the gain if only one output argument was specified if nargout == 1, sos(1,1:3) = k*sos(1,1:3); else g = k; end function [sos,g] = scaling(sos,k,L,scale) % SCALING, scale the cascaded sos filters using the infinity norm % or the 2 norm as specified. % Find the L scaling factors s(m) and perform the scaling Fnum = 1; Fden = 1; den = sos(1,4:6); if strcmp(scale,'inf'), F = freqz(1,den,256); s(1) = max(abs(F)); elseif strcmp(scale,'two'), % Find the efective time constant of the transfer function by using % the abs of the largest pole (see Orfanidis, Intro. to Sig. Proc. 1996, pp 238) rho = max(abs(roots(den))); tol = 0.01; % This value can be modified for greater or less accuracy in the two norm approximation logtol = log(tol); % We don't want to be recomputing this all the time neff = logtol/log(rho); H = impz(1,den,neff); s(1) = norm(H); end for m = 2:L den = sos(m,4:6); Fnum = conv(Fnum,sos(m-1,1:3)); Fden = conv(Fden,sos(m-1,4:6)); Fden2 = conv(Fden,den); if strmatch(lower(scale),'inf'), F = freqz(Fnum,Fden2,256); s(m) = max(abs(F)); elseif strmatch(lower(scale),'two'), rho = max(abs(roots(Fden2))); neff = logtol/log(rho); % Again, this is an approximation of the effective time it takes the impulse response to decay H = impz(Fnum,Fden2,neff); s(m) = norm(H); end % Now perform the scaling for the first L-1 sos sections sos(m-1,1:3) = s(m-1)./s(m).*sos(m-1,1:3); end % And now scale the last section sos(end,1:3) = k*s(end)*sos(end,1:3); g = 1/s(1); function sos = last_pole(z,p,sos) % Handle the last pole separately [num,den] = zp2tf(z,p,1); num = [num 0]; den = [den 0]; sos = [num den;sos]; function sos = sosfun(start,stop,p,sos) % This function was made to not repeat code in several places for m = start:2:stop, [num,den] = zp2tf([],p(m:m+1),1); sos = [num den;sos]; end function sos = sosfun2(start,stop,z,p,sos) % This function was made to not repeat code in several places for m = start:2:stop, [num,den] = zp2tf(z(m:m+1),p(m:m+1),1); sos = [num den;sos]; end