function [coeffs,poles,k] = residue(u,v,k)
%RESIDUE Partial-fraction expansion or residue computation.
%	[R,P,K] = RESIDUE(B,A) finds the residues, poles and direct term of
%	a partial fraction expansion of the ratio of two polynomials,
%	B(s) and A(s).  If there are no multiple roots,
%	   B(s)       R(1)       R(2)             R(n)
%	   ----  =  -------- + -------- + ... + -------- + K(s)
%	   A(s)     s - P(1)   s - P(2)         s - P(n)
%	Vectors B and A specify the coefficients of the polynomials in
%	descending powers of s.  The residues are returned in the column
%	vector R, the pole locations in column vector P, and the direct
%	terms in row vector K.  The number of poles is
%	   n = length(A)-1 = length(R) = length(P)
%	The direct term coefficient vector is empty if length(B) < length(A);
%	otherwise
%	   length(K) = length(B)-length(A)+1
%
%	If P(j) = ... = P(j+m-1) is a pole of multplicity m, then the
%	expansion includes terms of the form
%	             R(j)        R(j+1)                R(j+m-1)
%	           -------- + ------------   + ... + ------------
%	           s - P(j)   (s - P(j))^2           (s - P(j))^m
%	[B,A] = RESIDUE(R,P,K), with 3 input arguments and 2 output arguments,
%	converts the partial fraction expansion back to the polynomials with
%	coefficients in B and A.
%
%	Warning:
%	Numerically, the partial fraction expansion of a ratio of polynomials
%	represents an ill-posed problem.  If the denominator polynomial, A(s),
%	is near a polynomial with multiple roots, then small changes in the
%	data, including roundoff errors, can make arbitrarily large changes
%	in the resulting poles and residues.  Problem formulations making use
%	of state-space or zero-pole representations are preferable.

%	Reference:  A.V. Oppenheim and R.W. Schafer, Digital
%	Signal Processing, Prentice-Hall, 1975, p. 56-58.

%	C.R. Denham and J.N. Little, MathWorks, 1986, 1989.
%	Copyright (c) 1984-93 by The MathWorks, Inc.

tol = 0.001;   % Repeated-root tolerance; adjust as needed.

% This section rebuilds the U/V polynomials from residues,
%  poles, and remainder.  Multiple roots are those that
%  differ by less than tol.

if nargin > 2
   [p,i] = sort(-abs(v));   % Sort poles by magnitude.
   p = v(i); r = u(i);   % Rearrange residues similarly.
   n = length(p);
   q = [p(:).' ; ones(1,n)];   % Poles and multiplicities.
   for j = 2:n
      if abs(p(j) - p(j-1)) < tol
         q(2,j) = q(2,j-1) + 1;   % Multiplicity of pole.
      end
   end
   v = poly(p); u = zeros(1,n);
   for indx = 1:n
      ptemp = q(1,:);
      i = indx;
      for j = 1:q(2,indx), ptemp(i) = nan; i = i-1; end
      ptemp = ptemp(find(~isnan(ptemp))); temp = poly(ptemp);
      j = length(temp);
      if j < n, temp = [zeros(1,n-j) temp]; end
      u = u + (r(indx) .* temp);
   end
   if ~isempty(k)
      if any(k ~= 0)
         u = [zeros(1,length(k)) u];
         k = k(:).';
         temp = conv(k,v);
         u = u + temp;
      end
   end
   coeffs = u; poles = v;    % Rename.
   return
end

% This section does the partial-fraction expansion
%  for any order of pole.

u = u(:).'; v = v(:).'; k =[];
f = find(u ~= 0);
if length(f), u = u(f(1):length(u)); end
f = find(v ~= 0);
if length(f), v = v(f(1):length(v)); end
u = u ./ v(1); v = v ./ v(1);   % Normalize.
if length(u) >= length(v), [k,u] = deconv(u,v); end
r = roots(v); [p,i] = sort(-abs(r)); p = r(i);

q = zeros(2,length(p));   % For poles and multiplicity.
q(1,1) = p(1); q(2,1) = 1; j = 1;
repeated = 0;
for i = 2:length(p)
   av = q(1,j) ./ q(2,j);
   if abs(av - p(i)) <= tol    % Treat as repeated root.
      q(1,j) = q(1,j) + p(i);   % Sum for average value.
      q(2,j) = q(2,j) + 1;
      repeated = 1;
     else
      j = j + 1; q(1,j) = p(i); q(2,j) = 1;
   end
end
q(1,1:j) = q(1,1:j) ./ q(2,1:j);   % Multiple root average.

% Set desired = 1 if you want the output multiple poles
%  to be averaged.

desired = 1;
if repeated & desired
   indx = 0;
   for i = 1:j
      for ii = 1:q(2,i), indx = indx+1; p(indx) = q(1,i); end
   end
end

poles = p(:);  % Rename.

coeffs = zeros(length(p),1); 
if repeated   % Section for repeated root problem.
   v = poly(p);
   next = 0;
   for i = 1:j
      pole = q(1,i); n = q(2,i);
      for indx = 1:n
         next = next + 1;
         coeffs(next) = resi2(u,v,pole,n,indx);
      end
   end
  else   % No repeated roots.
   for i = 1:j
      temp = poly(p([1:i-1, i+1:j]));
      coeffs(i) = polyval(u,p(i)) ./ polyval(temp,p(i));
   end
end
