home *** CD-ROM | disk | FTP | other *** search
- function K = place(A,B,P)
- %PLACE K = place(A,B,P) computes the state feedback matrix K such that
- % the eigenvalues of A-B*K are those specified in vector P.
- % The complex eigenvalues in the vector P must appear in consecu-
- % tive complex conjugate pairs. No eigenvalue may be placed with
- % multiplicity greater than the number of inputs.
- %
- % The displayed "ndigits" is an estimate of how well the
- % eigenvalues were placed. The value seems to give an estimate
- % of how many decimal digits in the eigenvalues of A-B*K match
- % the specified numbers given in the array P.
- %
- % A warning message is printed if the nonzero closed loop poles
- % are greater than 10% from the desired locations specified in P.
- %
- % See also: LQR and RLOCUS.
-
- % M. Wette 10-1-86
- % UCSB ECE, Santa Barbara, CA 93106, (805) 961-4691
- % E-mail: riccati@hub.ucsb.edu
- % Revised 9-25-87 JNL
- % Revised 8-4-92 Wes Wang
- %
- % Ref:: Kautsky, Nichols, Van Dooren, "Robust Pole Assignment in Linear
- % State Feedback," Intl. J. Control, 41(1985)5, pp 1129-1155
- %
-
- % Copyright (c) 1986-93 by the MathWorks, Inc.
-
- NTRY=5; % - number of iterations for "optimization" -
- %
- [nx,na] = size(A);
-
- P = P(:);
- if length(P)~=nx, error('P must have the same number of states as A.'); end
-
- [n,m] = size(B);
- if (nx == 0 | n == 0),
- error('A and B matrices cannot be empty.')
- end
- nx=0; i=1; while (i<=n),
- if imag(P(i))~=0.0,
- pr = [pr real(P(i))]; pi = [pi imag(P(i))];
- cmplx = [cmplx 1]; i = i+2;
- else,
- pr = [pr real(P(i))]; pi = [pi 0.0];
- cmplx = [cmplx 0]; i = i+1;
- end;
- nx = nx+1;
- end;
- %
- m = rank(B);
- % Make sure there are more inputs than repeated poles:
- ps = sort(P);
- for i=1:n-m
- imax = min(n,i+m);
- if all(ps(i:imax) == ps(i))
- error('Can''t place poles with multiplicity greater than the number of inputs.');
- end
- end
- nmmp1 = n-m+1; mp1 = m+1; jj = sqrt(-1);
- [Qb,Rb] = qr(B); q0 = Qb(:,1:m); q1 = Qb(:,mp1:n); Rb = Rb(1:m,:);
- %
- % - special case: (#inputs)==(#states) - efficient, but not clean
- if (m==n),
- A = A - diag(real(P));
- i=0; for j=1:nx,
- i = i+1;
- if cmplx(j),
- A(i,i+1) = A(i,i+1) + pi(j);
- A(i+1,i) = A(i+1,i) - pi(j);
- i = i+1;
- end;
- end;
- disp(sprintf('place: ndigits= %g', fix(log10(1.0/eps))))
- K = Rb\q0'*A;
- return; % escape here!
- end
- %
- % - compute bases for eigenvectors -
- I = eye(n);
- for i=1:nx,
- [Q,R] = qr(((pr(i)+jj*pi(i))*I-A)'*q1);
- Bx = [ Bx Q(:,nmmp1:n) ];
- end;
- %
- % - choose basis set -
- % at each iteration of i pick the eigenvector Xj, j~=i,
- % which is "most orthogonal" to the current eigenvector Xi
- %Wes changed the following
- nn=1;
- for i=1:nx,
- X(:,i) = Bx(:,(i-1)*m+1);
- if m>1 %check if X is a full rank matrix. If it is not, make it up
- for ii = 2:m
- nnx = nn + cmplx(i);
- Y(:,nnx) = imag(X(:,i)); %if cmplx(i)==1 take imag part, else empty action
- Y(:,nn) = real(X(:,i));
- if rank(Y) < nnx,
- X(:,i) = Bx(:,(i-1)*m+ii);
- else
- ii = m;
- end; % if rank(Y) < nnx,
- end; %for ii = 2:m
- nn = nn + 1 + cmplx(i);
- end; %if m>1
- end; %for i=1:nx,
- % Wes changed the above
- if (m>1),
- for k = 1:NTRY,
- for i = 1:nx,
- S = [ X(:,1:i-1) X(:,i+1:nx) ]; S = [ S conj(S) ];
- [Us,Ss,Vs] = svd(S);
- Pr = Bx(:,(i-1)*m+1:i*m); Pr = Pr*Pr';
- X(:,i) = Pr*Us(:,n); X(:,i) = X(:,i)/norm(X(:,i));
- end
- end
- end
- for i = 1:nx,
- if cmplx(i),
- Xf = [ Xf X(:,i) conj(X(:,i)) ];
- else,
- Xf = [ Xf X(:,i) ];
- end;
- end;
- cnd = cond(Xf);
- if (cnd*eps >= 1.0),
- disp('place: can''t place eigenvalues there');
- return;
- end
- disp(sprintf('place: ndigits= %g', fix(log10(cnd/eps))))
- %
- % - compute feedback -
- K = Rb\q0'*(A-real(Xf*diag(P,0)/Xf));
-
- % Check results. Start by removing 0.0 pole locations
- P = sort(P);
- i = find(P ~= 0);
- P = P(i);
- Pc = sort(eig(A-B*K));
- Pc = Pc(i);
- if max(abs(P-Pc)./abs(P)) > .1
- disp('Warning: Pole locations are more than 10% in error.')
- end
- % --- last line of place ---
-