function [Bm,Am,FIR]=tf2delparf_ls(B,A,NLS); %TF2DELPARF_LS converts the transfer function form to delayed parallel SOS form. % [Bm,Am,FIR]=TF2DELPARF_LS(B,A,NLS) converts the transfer function B(z)/A(z) % defined by vectors B and A to delayed parallel second-order sections % described by Bm and Am, plus a parallel FIR part, if the order of % B(z) is larger than the order of A(z). % % The difference from TF2DELPARF is that now the parameters are computed % by a least-squares fit to match the impulse response of the original % filter, instead of partial fraction expansion. This procedure is % suggested for large (>100) filter orders due to its better numerical % preformance. The NLS parameter sets the length of the impulse response fit. % % The Bm and Am matrices are containing the [b0 b1]' and [1 a0 a1]' % coefficients for the different sections in their columns. For example, % Bm(:,3) gives the [b0 b1]' parameters of the third second-order % section. These can be used by the filter command separatelly (e.g., by % y=filter(Bm(:,3),Am(:,3),x), or by the DELPARFILT command. % % Note that if there is an FIR part, then the IIR part must be delayed by % the length (order+1) of the FIR filter when this form is implemented. % This leads to much better numerical properties compared to the standard % parallel filter computed by TF2PARF. % % Also, remember that converting a transfer function to parallel second-order % is not possible if there is pole mulitplicity. % % For the details, see: % % Balázs Bank, "Converting IIR filters to parallel form," IEEE Signal Processing % Magazine, Tips and tricks, 2018. % % http://www.mit.bme.hu/~bank/parconv % % C. Balazs Bank, 2017-2018. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % computing the impulse response of the direct-form filter if nargin < 3, % if NLS is not specified NLS=2*length(B); end; imp=zeros(1,NLS); imp(1)=1; impresp=filter(B,A,imp); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % computing the poles of the filter p=roots(A); % computing the poles of the filter % if there was an error in root finding giving unstable poles: % we make the filter stable by flipping the poles into the unit cirle for k=1:length(p), if abs(p(k))>1 p(k)=1/conj(p(k)); end; end; p=cplxpair(p); %order it to complex pole pairs + real ones afterwards %in order to have second-order sections only (i.e., no first order) pnum=length(p); %number of poles ppnum=2*floor(pnum/2); %the even part of pnum ODD=0; if pnum>ppnum, %if the number of poles is odd ODD=1; end; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % preparing the target for the LS fit NFIR=max(length(B)-length(A)+1,0); % FIR part order parfresp=impresp(NFIR+1:end); % the part modeled by the parallel filter L=length(parfresp); imp=zeros(L,1); imp(1)=1; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %constructing the modeling signal matrix for k=1:2:ppnum-1, %second-order sections resp=filter(1,poly(p(k:k+1)),imp); %impluse response of the two-pole filter M(:,k)=resp; M(:,k+1)=[0 ;resp(1:L-1)]; %the response delayed by one sample end; if ODD, %if the number of poles is odd, we have a first-order section resp=filter(1,poly(p(pnum)),imp); M(:,pnum)=resp; end; y=parfresp(:); %making the target a column vector %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %Looking for min(||y-M*par||) as a function of par by the LS fit par=M\y; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % constructing the Bm and Am matrices from par for k=1:ppnum/2, % second-order sections Am(:,k)=poly(p(2*k-1:2*k)).'; Bm(:,k)=par(2*k-1:2*k); end; if ODD, %we extend the first-order section to a second-order one by adding zero coefficients Am(:,k+1)=[poly(p(pnum)).'; 0]; Bm(:,k+1)=[par(pnum); 0]; end; FIR=0; % the FIR part is simply the first NFIR samples of the impulse response if NFIR>0, FIR=impresp(1:NFIR); end;