Hi Juan,

See attached file. Please note that although I feel the algorithms used for the 
transform are sound, the implementation in Octave isn't the most efficient. The 
intention was to write a reference implementation that proves the concept and 
can serve as a basis for improvements.


Regards,
Rudy.



________________________________
From: Juan Manuel Parrilla Gutiérrez <joanma...@gmail.com>
To: reschauz...@yahoo.com
Cc: octave-dev@lists.sourceforge.net
Sent: Wednesday, September 28, 2011 3:19 PM
Subject: Impulse invariance transform implementation


Hi Rudy,

I see here: http://comments.gmane.org/gmane.comp.gnu.octave.sources/116 that 
you implemented "impulse invariance transform" for octave.
I'd like to use your implementation with octave. Also the octave community 
would be interested in adding your code.
Please, reply as "reply all" in this e-mail so that your answer also arrives to 
the list of octave.

Thank you very much.

-- 
Juan Manuel Parrilla Gutiérrez
1;

%    Copyright 2007 R.G.H. Eschauzier

%    This program is free software; you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation; either version 2 of the License, or
%    (at your option) any later version.

%    This program is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.

%    You should have received a copy of the GNU General Public License
%    along with this program; if not, write to the Free Software
%    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA


function [b_out a_out]=c2d_imp(b_in,a_in,ts)
% Impulse invariant conversion from s to z domain

  tol=0.0001;

  [r_in p_in k_in]=residue(b_in,a_in); % partial fraction expansion

  n=length(r_in); % Number of poles/residues

  if (length(k_in)>0) % Greater than zero means we cannot do impulse invariance
    error("Order numerator >= order denominator");
  endif

  r_out=zeros(1,n); % Residues of H(z)
  p_out=zeros(1,n); % Poles of H(z)
  k_out=0; % Contstant term of H(z)

  i=1;
  while (i<=n)
    m=1;
    first_pole=p_in(i); % Pole in the s-domain
    while (i<n && abs(first_pole-p_in(i+1))<tol) % Multiple poles at p(i)
       i++; %Next residue
       m++; % Next multiplicity
    endwhile
    [r p k]=z_res(r_in(i-m+1:i),first_pole,ts); % Find z-domain residues
    k_out+=k; % Add direct term to output
    p_out(i-m+1:i)=p; % Copy z-domain pole(s) to output
    r_out(i-m+1:i)=r; % Copy z-domain residue(s) to output

    i++; % Next s-domain residue/pole
  endwhile
  [b_out a_out]=inv_residue(r_out,p_out,k_out);
  a_out=to_real(a_out); % Get rid of spurious imaginary part
  b_out=to_real(b_out);
  b_out=polyreduce(b_out);
endfunction


function [b_out a_out]=d2c_imp(b_in,a_in,ts)
% Impulse invariant conversion from s to z domain

  tol=0.0001;

  [r_in p_in k_in]=residue(b_in,a_in); % partial fraction expansion

  n=length(r_in); % Number of poles/residues

  if (length(k_in)>1) % Greater than one means we cannot do impulse invariance
    error("Order numerator > order denominator");
  endif

  r_out=zeros(1,n); % Residues of H(s)
  sm_out=zeros(1,n); % Poles of H(s)

  i=1;
  while (i<=n)
    m=1;
    first_pole=p_in(i); % Pole in the z-domain
    while (i<n && abs(first_pole-p_in(i+1))<tol) % Multiple poles at p(i)
       i++; %Next residue
       m++; % Next multiplicity
    endwhile
    [r sm k]=inv_z_res(r_in(i-m+1:i),first_pole,ts); % Find s-domain residues
    k_in-=k; % Just to check, should end up zero for physical system
    sm_out(i-m+1:i)=sm; % Copy s-domain pole(s) to output
    r_out(i-m+1:i)=r; % Copy s-domain residue(s) to output

    i++; % Next z-domain residue/pole
  endwhile
  [b_out a_out]=inv_residue(r_out,sm_out,0);
  a_out=to_real(a_out); % Get rid of spurious imaginary part
  b_out=to_real(b_out);
  b_out=polyreduce(b_out);
endfunction


function b=h1_deriv(n,ts)
% Find (z^n)*(d/dz)^n*H1(z), where H1(z)=ts*z/(z-p), ts=sampling period,
% p=exp(sm*ts) and sm is the s-domain pole with multiplicity n+1.
% The result is (ts^(n+1))*(b(1)*p/(z-p)^1 + b(2)*p^2/(z-p)^2 + b(n+1)*p^(n+1)/(z-p)^(n+1)),
% where b(i) is the binomial coefficient bincoeff(n,i) times n!. Works for n>0.

  b=factorial(n)*bincoeff(n,0:n); % Binomial coefficients: [1], [1 1], [1 2 1], [1 3 3 1], etc.
  b*=(-1)^n;
endfunction


function b=h1_z_deriv(n,p,ts)
% Find {-zd/dz}^n*H1(z). I.e., first multiply by -z, then diffentiate, then multiply by -z, etc.
% The result is (ts^(n+1))*(b(1)*p/(z-p)^1 + b(2)*p^2/(z-p)^2 + b(n+1)*p^(n+1)/(z-p)^(n+1)).
% Works for n>0.

  % Build the vector d that holds coefficients for all the derivatives of H1(z)
  % The results reads d(n)*z^(1)*(d/dz)^(1)*H1(z) + d(n-1)*z^(2)*(d/dz)^(2)*H1(z) +...+ d(1)*z^(n)*(d/dz)^(n)*H1(z)
  d=(-1)^n; % Vector with the derivatives of H1(z)
  for i=(1:n-1)
    d=conv(d,[1 0]); % Shift result right (multiply by -z)
    d+=pad_poly(polyderiv(d),i+1); % Add the derivative
  endfor

  % Build output vector
  b=zeros(1,n+1);
  for i=(1:n)
    b+=d(i)*pad_poly(h1_deriv(n-i+1,ts),n+1);
  endfor

  b*=ts^(n+1)/factorial(n);
  for i=(1:n+1)
    b(n-i+2)*=p^i; % Multiply coefficients with p^i, where i is the index of the coeff.
  endfor

endfunction


function p_out=polyrev(p_in)
% Reverse the coefficients of a polynomial

  n=length(p_in);

  for i=(1:n)
    p_out(i)=p_in(n-i+1);
  endfor
endfunction


function [r_out p_out k_out]=z_res(r_in,sm,ts);
% Convert residue vector for single and multiple poles in s-domain (located at sm) to
% residue vector in z-domain. The variable k is the direct term of the result.

  p_out=exp(ts*sm); % z-domain pole
  n=length(r_in); % Multiplicity of the pole
  r_out=zeros(1,n); % Residue vector

  % First pole (no multiplicity)
  k_out=r_in(1)*ts; % PFE of z/(z-p) = p/(z-p)+1; direct part
  r_out(1)=r_in(1)*ts*p_out; % pole part of PFE

  for i=(2:n) % Go through s-domain residues for multiple pole
    r_out(1:i)+=r_in(i)*polyrev(h1_z_deriv(i-1,p_out,ts)); % Add z-domain residues
  endfor
endfunction


function [r_out sm_out k_out]=inv_z_res(r_in,p_in,ts)
% Inverse function of z_res

  n=length(r_in); % multiplicity of the pole
  r_in=r_in'; % From column vector to row vector
  
  i=n;
  while (i>1) % Go through residues starting from highest order down
    r_out(i)=r_in(i)/((ts*p_in)^i); % Back to binomial coefficient for highest order (always 1)
    r_in(1:i)-=r_out(i)*polyrev(h1_z_deriv(i-1,p_in,ts)); % Subtract highest order result, leaving r_in(i) zero
    i--;
  endwhile

  % Single pole (no multiplicity)
  r_out(1)=r_in(1)/((ts*p_in));
  k_out=r_in(1)/p_in;

  sm_out=log(p_in)/ts;
endfunction


function p_out=pad_poly(p_in,n)
% Pad polynomial to length n

  l=length(p_in); % Length of input polynomial
  p_out(n-l+1:n)=p_in(1:l); % Right shift for proper length
  p_out(1:n-l)=0; % Set first elements to zero
endfunction


function [b_out a_out]=inv_residue(r_in,p_in,k_in)
% Inverse of Octave residue function

  tol=0.0001;

  n=length(r_in); % Number of poles/residues

  k=0; % Capture contstant term
  if (length(k_in)==1) % A single direct term (order N = order D)
    k=k_in(1); % Capture constant term
  elseif (length(k_in)>1) % Greater than one means non-physical system
    error("Order numerator > order denominator");
  endif

  a_out=1; % Calculate denominator
  for i=(1:n)
    a_out=conv(a_out,[1 -p_in(i)]);
  endfor

  b_out=zeros(1,n+1);
  b_out+=k*a_out; % Constant term: add k times denominator to numerator
  i=1;
  while (i<=n)
    term=[1 -p_in(i)]; % Term to be factored out
    p=r_in(i)*deconv(a_out,term); % Residue times resulting polynomial
    p=pad_poly(p,n+1); % Pad for proper length
    b_out+=p;

    m=1;
    mterm=term;
    first_pole=p_in(i);
    while (i<n && abs(first_pole-p_in(i+1))<tol) % Multiple poles at p(i)
       i++; %Next residue
       m++;
       mterm=conv(mterm,term); % Next multiplicity to be factored out
       p=r_in(i)*deconv(a_out,mterm); % Resulting polynomial
       p=pad_poly(p,n+1); % Pad for proper length
       b_out+=p;
    endwhile
  i++;
  endwhile
b_out=polyreduce(b_out);
endfunction


function p_out=to_real(p_in)
% Round complex number to nearest real number

  p_out=abs(p_in).*sign(real(p_in));
endfunction
------------------------------------------------------------------------------
All the data continuously generated in your IT infrastructure contains a
definitive record of customers, application performance, security
threats, fraudulent activity and more. Splunk takes this data and makes
sense of it. Business sense. IT sense. Common sense.
http://p.sf.net/sfu/splunk-d2dcopy1
_______________________________________________
Octave-dev mailing list
Octave-dev@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/octave-dev

Reply via email to