%   [P, Y, X, S] = opde(G,epp,RF)
%
%   The ``Output-Pole-Direction-Eigenvalue'' opde-function 
%   computes the output pole directions through the use of 
%   egenvalue decomposition.
%   Outputs: P   - Vector containing the poles.
%            Y   - Matrix containing the output directions, 
%                  column i corresponds to pole P(i).
%            X   - Output state directions.
%            S   - Scaler used to normalize the output directions.
%   Inputs:  G   - System matrix.
%            epp - Tolerance, default value is 1e-12.
%                  It is used to check the norm of the output directions.
%                  If the norm of output direction is less than EPP,
%                  zero is stored in the corresponding output direction.
%            RF  - If FLG_RF==1 then the first element of 
%                  the output direction is made real.
%
%   Written by: Kjetil Havre, 12/9-1996, e-mail: kjetil@ife.no
%
%   See also:  IPDE, PDFST, IZDE, OZDE, ZDSVD and PDSVD.
%
%   Reference: Havre K. and S. Skogestad, 1996, ``Effect of RHP Zeros and
%              Poles on Performance in Multivariable Systems''.
%
   function [P,Y,X,S] = opde(G,epp,rf);

   P = []; Y = []; X = []; 
   [mt,ny,nu, nx] = minfo(G);
   S = ones(nx,1);
   
   if strcmp(mt, 'syst')==0
      disp( 'System matrix G is required, usage: [] = opde(G,epp)' );
      return
   end

   if nargin < 3
     rf = 0;
   end
   if nargin < 2
      epp = 1e-12;
   end
   [A, B, C, D] = unpck(G);
   
   if norm(D) > 1/epp
      disp('Warning: Directions may be inaccurate due to large effect from D.');
   end
   
   [V, D] = eig(A,'nobalance');   P = diag(D);
   [P,Is] = sorte(P); V = V(:,Is);
   Hm = A*V-V*diag(P);
   if norm(Hm) > 100*epp
      disp('Warning: inaccurate eigenvalue computation.')
      Hm = Hm
   end
   

   Npd = max(size(P));
   for i=1:Npd	 
      X(:,i) = V(:,i);
      if abs(P(i)-real(P(i))) < epp 
         P(i) = real(P(i));
	 if isreal(X(:,i)) == 0 % Rotate eigenvector.
	    inz = find(abs(X(:,i))>epp); 
	    if isempty(inz) == 0     % Rotate eigenvector.
	       vh = angle(X(inz(1),i));
               X(:,i)=X(:,i)*exp(-sqrt(-1)*vh);
	    end
            X(:,i) = zerm(X(:,i),epp/10);
         end
      end
      
      yph = C*X(:,i); nyph = norm(yph);
      
      if nyph > epp
         Y(:,i) = yph/nyph;
	 X(:,i) = X(:,i)/nyph;	 
	 S(i,1) = 1/nyph;
	 if (isreal(Y(:,i))==0) & (rf==1)   % Rotate output direction. 
            inz = find(abs(Y(:,i))>epp); 
	    if isempty(inz) == 0
	       vh = angle(Y(inz(1),i));
               Y(:,i) = Y(:,i)*exp(-sqrt(-1)*vh); 
               X(:,i)=X(:,i)*exp(-sqrt(-1)*vh);
	       S(i,1) = S(i,1)*exp(-sqrt(-1)*vh);
            end
         end
      else
         Y(:,i) = zeros(ny,1);    % Norm is small unobservable.
	 S(i,1) = 0;
      end
   end
   P = zerm(P,epp/10); X = zerm(X,epp/10); Y = zerm(Y,epp/10);
end

   

