Code covered by the BSD License  

Highlights from
DPLQR

from DPLQR by Ivo Houtzager
Nonsteady LQ state-feedback gain design with final state penalty

dplqr(a,b,q,r,f,n)
function [K,S,E] = dplqr(a,b,q,r,f,n)
%DPLQR Dynamic programming of LQR design for a discrete state-space system.
%   [K,S,E] = DPLQR(SYS,Q,R,F,N) calculates the optimal gain matrices K[n]
%   such that:
%
%   For a discrete-time state-space model SYS, u[n] = -K[n]x[n] minimizes
%
%             J = 0.5*Sum {x[n]'Qx[n] + u[n]'Ru[n]} + 0.5*x[N]'Fx[N]
%
%   subject to  x[n+1] = Ax[n] + Bu[n] with n = 0...N-1.
%
%   Also returned are the the solution S of the associated algebraic
%   Riccati equation and the closed-loop eigenvalues E = EIG(A-B*K).
%
%   [K,S,E] = DPLQR(A,B,Q,R,F,N) is an equivalent syntax for LTV 
%   state-space models with dynamics  x[n+1] = A[n]x[n] + B[n]u[n].

%   written by, I. Houtzager [2006]
%   Delft Center of Systems and Control

% number of inputs
ni = nargin;

% Determine which syntax is being used
switch ni
    case 5
        if ndims(a) > 2
            error('LTI models not supported for arrays of state-space models.')
        elseif isct(a)
                error('System is not discrete. Use C2D.')
        elseif hasdelay(a),
            if isdt(a),
                % Map delay times to poles at z=0 in discrete-time case
                a = delay2z(a);
            else
                error('Not supported for continuous-time systems with delays.')
            end
        end
        [A,B,C,D,Ts] = ssdata(a);
        Q = b;
        F = r;
        R = f;
        N = r;
        array = 1;
    case 6
        A = a;
        B = b;
        Q = q;
        F = f;
        R = r;
        N = n;
        if ndims(a) > 2;
            array = 2;
        else
            array = 1;
        end
    otherwise
        error('DPLQR requires at least five or six input arguments')
end

% check dimensions and symmetry
[nax ns nna] = size(A);
[nbx nb nnb] = size(B);
[nqx nq nnq] = size(Q);
[nfx nf nnf] = size(F);
[nrx nr nnr] = size(R);
if ~isequal(nna,nnb,nnq,nnr,N);
    if array == 2
        error('The number of arrays have to be equal to N.');
    end
end
if ~isequal(nbx,nax);
    error('The A and B matrices must have the same number of rows.')
end
if ~isequal(nqx,nax,nfx,ns,nq,nf);
    error('The A, Q and F matrices must be the same size.')
end
if ~isequal(nrx,nr,nb);
    error('The R matrix must be square with as many columns as B.')
end
if ~isreal(Q) || ~isreal(R)
   error('The weight matrices Q, R must be real valued.')
end

% backwards iteration
K = zeros(nb,ns,N);
E = zeros(ns,N);
S = zeros(ns,ns,N);
S(:,:,N+1) = F;
switch array
    case 1
        for t = N:-1:1
            K(:,:,t) = (R + B'*S(:,:,t+1)*B)\B'*S(:,:,t+1)*A;
            S(:,:,t) = (A - B*K(:,:,t))'*S(:,:,t+1)*(A - B*K(:,:,t)) + K(:,:,t)'*R*K(:,:,t) + Q;
            if nargout >= 2
                E(:,t) = eig(A - B*K(:,:,t));
            end
        end
    case 2
        for t = N:-1:1
            K(:,:,t) = (R(:,:,t) + B(:,:,t)'*S(:,:,t+1)*B(:,:,t))\B(:,:,t)'*S(:,:,t+1)*A(:,:,t);
            S(:,:,t) = (A(:,:,t) - B(:,:,t)*K(:,:,t))'*S(:,:,t+1)*(A(:,:,t) - B(:,:,t)*K(:,:,t)) + K(:,:,t)'*R(:,:,t)*K(:,:,t) + Q(:,:,t);
            if nargout >= 2
                E(:,t) = eig(A(:,:,t) - B(:,:,t)*K(:,:,t));
            end
        end
end

Contact us at files@mathworks.com