diff m-toolbox/classes/+utils/@math/pfallpsymz.m @ 0:f0afece42f48

Import.
author Daniele Nicolodi <nicolodi@science.unitn.it>
date Wed, 23 Nov 2011 19:22:13 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m-toolbox/classes/+utils/@math/pfallpsymz.m	Wed Nov 23 19:22:13 2011 +0100
@@ -0,0 +1,216 @@
+% PFALLPSYMZ all pass filtering in order to stabilize TF poles and zeros.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DESCRIPTION:
+% 
+%     All pass filtering in order to stabilize transfer functions poles. 
+%     It inputs a partial fraction expanded discrete model and outpu
+%     residues, poles direct terms and frequency response of the stabilized
+%     model. Function can handle multiple models with common poles.
+% 
+% CALL:
+% 
+%     [nr,np,nd,resp] = pfallpsymz(r,p,d,f,fs)
+% 
+% INPUTS:
+% 
+%     r: are residues. (Npx1) or (NpxM) vector
+%     p: are poles. (Npx1) vector
+%     d: is direct term (1x1) or (1xM) vector
+%     mresp: input model response. (Nx1) or (NxM) vector
+%     f: is the frequancies vector in (Hz). (Nx1) vector
+%     fs: is the sampling frequency in (Hz). (1x1)
+%     
+% OUTPUTS:
+% 
+%     nr: new residues. (Npx1) or (NpxM) vector
+%     np: new stable poles. (Npx1) vector
+%     nd: new direct term. (1x1) or (1xM) vector
+%     nmresp: new model response. (Nx1) or (NxM) vector
+% 
+% NOTE:
+% 
+%     This function make use of symbolic math toolbox functions
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VERSION: $Id: pfallpsymz.m,v 1.5 2008/11/10 15:40:11 luigi Exp $
+%
+% HISTORY:     12-09-2008 L Ferraioli
+%                 Creation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [nr,np,nd,nmresp] = pfallpsymz(r,p,d,mresp,f,fs)
+
+  % Reshaping
+  [a,b] = size(r);
+  if a<b
+    r = r.'; % reshape as a column vector
+  end
+
+  [a,b] = size(p);
+  if a<b
+    p = p.'; % reshape as a column vector
+  end
+
+  [a,b] = size(f);
+  if a<b
+    f = f.'; % reshape as a column vector
+  end
+
+  [a,b] = size(f);
+  if a<b
+    f = f.'; % reshape as a column vector
+  end
+
+  [a,b] = size(d);
+  if a > b
+    d = d.'; % reshape as a row
+    d = d(1,:); % taking the first row (the function can handle only simple constant direct terms)
+  end
+
+  if isempty(fs)
+    fs = 1;
+  end
+  [a,b] = size(fs);
+  if a ~= b
+    disp(' Fs has to be a number. Only first term will be considered! ')
+    fs = fs(1);
+  end
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  f = sym(f,'f');
+  fs = sym(fs,'f');
+  syms z
+  p = sym(p,'f');
+
+  % stabilize poles
+  sp = p;
+  unst = abs(double(sp)) > 1;
+  sp(unst) = 1./conj(sp(unst));
+  skp = prod(1./conj(p(unst)));
+
+  [Na,Nb] = size(r);
+
+  for nn = 1:Nb
+    
+%     pp = p(unst);
+%     psp = sp(unst);
+%     tterm = 1;
+%     for ii = 1:length(pp)
+%       tterm = tterm.*(z-pp(ii))./(z-psp(ii));
+%     end
+%     
+%     s = cos((2*pi/fs).*f) + 1i.*sin((2*pi/fs).*f);
+%     allresp = subs(tterm,z,s);
+%     phs = angle(allresp);
+%     nmresp(:,nn) = mresp(:,nn).*(cos(phs)+1i.*sin(phs));
+%     np = double(sp);
+
+    % digits(100)
+    % Defining inputs as symbolic variable
+    rt = sym(r(:,nn),'f');
+  %   p = sym(p,'f');
+    dt = sym(d(1,nn),'f');
+  %   f = sym(f,'f');
+  %   fs = sym(fs,'f');
+  %   syms z
+
+    % Function gain coefficient
+    k = sum(rt)+dt;
+
+    Np = length(p);
+
+    % Defining the symbolic transfer function
+    vter = rt.*z./(z-p);
+    vter = [vter; dt];
+    Mter = diag(vter);
+    H = trace(Mter);
+
+    % Factorizing the transfer function
+    HH = factor(H);
+
+    % Extracting numerator and denominator
+    [N,D] = numden(HH);
+
+    % Symbolci calculation of function zeros
+    cN = coeffs(expand(N),z);
+    n = length(cN);
+    cN2 = -1.*cN(2:end)./cN(1);
+    A = sym(diag(ones(1,n-2),-1));
+    A(1,:) = cN2;
+    zrs = eig(A);
+    if double(d) == 0
+      zrs = [zrs; sym(0,'f')];
+    end
+
+    % % stabilize zeros
+    % szrs = zrs;
+    % unst = abs(double(szrs)) > 1;
+    % szrs(unst) = 1./conj(szrs(unst));
+    % skz = prod(conj(zrs(unst)));
+
+  %   % stabilize poles
+  %   sp = p;
+  %   unst = abs(double(sp)) > 1;
+  %   sp(unst) = 1./conj(sp(unst));
+  %   skp = prod(1./conj(p(unst)));
+
+    % Correcting for some special cases
+    % if isempty(skz)
+    %   skz = sym(1,'f');
+    % end
+    if isempty(skp)
+      skp = sym(1,'f');
+    end
+    if isempty(k)
+      k = sym(1,'f');
+    end
+
+    % Calculating new gain
+    % sk = real(k*skz*skp);
+    sk = real(k*skp);
+
+    HHHn = sym(1,'f');
+
+    for jj = 1:Np
+      HHHn = HHHn.*(z-zrs(jj));
+      tsp = sp;
+      tsp(jj) = [];
+      tHHHd = sym(1,'f');
+      for kk = 1:Np-1
+        tHHHd = tHHHd.*(z-tsp(kk));
+      end
+      HHHd(jj,1) = tHHHd;
+
+    end
+
+    for jj = 1:Np
+      sr(jj,1) = subs(sk*HHHn/(z*HHHd(jj,1)),z,sp(jj));
+    end
+
+    np = double(sp);
+    for kk = 1:Np
+      if imag(np(kk)) == 0
+        sr(kk) = real(sr(kk));
+      end
+    end
+
+    nr(:,nn) = double(sr);
+    nd(:,nn) = double(dt);
+
+    % Model evaluation
+    pfparams.type = 'disc';
+    pfparams.freq = f;
+    pfparams.fs = fs;
+    pfparams.res = nr(:,nn);
+    pfparams.pol = np;
+    pfparams.dterm = nd(:,nn);
+    pfr = utils.math.pfresp(pfparams);
+    resp = pfr.resp;
+
+    ratio = mean(abs(mresp(:,nn))./abs(resp));
+    resp = resp.*ratio;
+    nr(:,nn) = nr(:,nn).*ratio;
+    nd(:,nn) = nd(:,nn).*ratio;
+    nmresp(:,nn) = resp;
+
+  end