Code covered by the BSD License  

Highlights from
QCAT

image thumbnail
from QCAT by Ola Harkegard
Quadratic Programming Control Allocation Toolbox

ip_alloc(B,v,umin,umax,ud,gam,tol,imax)
function [u,iter] = ip_alloc(B,v,umin,umax,ud,gam,tol,imax)
  
% IP_ALLOC - Control allocation using interior point method.
%
%  [u,iter] = ip_alloc(B,v,umin,umax,[ud,gamma,tol,imax])
%
% Solves the weighted, bounded least-squares problem
%
%   min ||u-ud||^2 + gamma ||Bu-v||^2   (unit weighting matrices)
%
%   subj. to  umin <= u <= umax
%
% using a primal dual interior point method.
%
%  Inputs:
%  -------
% B     control effectiveness matrix (k x m)
% v     commanded virtual control (k x 1)
% umin  lower position limits (m x 1)
% umax  upper position limits (m x 1)
% ud    desired control (m x 1) [0]
% gamma weight (scalar) [1e4]
% tol   tolerance used in stopping criterion [1e-4]
% imax  max no. of iterations [100]
% 
%  Outputs:
%  -------
% u     optimal control
% iter  no. of iterations
%
% See also: WLS_ALLOC, WLSC_ALLOC, FXP_ALLOC, QP_SIM.
%  
% Contributed by John Petersen.

% Set default values of optional arguments
  if nargin < 8
    imax = 100; % Heuristic value
    [k,m] = size(B);
    if nargin < 7, tol = 1e-4; end
    if nargin < 6, gam = 1e4; end
    if nargin < 5, ud = zeros(m,1); end
  end

  % Reformulate   min  ||u-ud||^2 + gamma ||Bu-v||^2  
  %               s.t. umin <= u <= umax
  %
  % as            min  ||Ax-b||^2 + h ||x-xd||^2
  %               s.t. 0 <= x <= xmax
  %
  % where x=u-umin, h=1/gamma, A=B, b=v-B*umin, xd=ud-umin, xmax=umax-umin 
  h = 1/gam; A = B; b = v - B*umin; xd = ud - umin; xmax = umax - umin;
  
  % ||Ax-b||^2 + h ||x-xd||^2 = 1/2x'Hx + c'x + f(xd)
  c = -2*(b'*A + h*xd');
  
  % Solve QP problem.
  [x,iter] = pdq(A,b,c',xmax,h,tol,imax);
  
  % Optimal control.
  u = x + umin;
  
function [x,iter] = pdq(A,b,c,u,wc,tol,imax);
  % Primal dual IP solver
  
  [k,m] = size(A);	% k = #constraints , m = #variables
  As2=A*sqrt(2);
  [s,w,x,z] = startpt(A,b,c,u,wc);
  rho = .9995; sig = 0.1; m2 = 2*m;
  xs = x.*s; wz = w.*z;
  mu = sig*(sum(xs + wz))/m2; % eq. (7)
  nxl=norm(x,1); iHd = 0; 
  ru = 0; rc = 0; rb = 0;
  
  for iter = 1:imax+1
    if (mu < tol) 
      % Close enough to optimum, bail out.
      break;
    end;   
    rxs = (xs - mu);
    iw = 1./w; rwz = (wz - mu);
    ix = 1./x; ixs = ix.*s;
    iwz = iw.*z;
    d = 2*wc + ixs + iwz; 						
    [ds,dw,dx,dz] = direct(d,As2,rb,rc,ru,rxs,rwz,ix,iw,ixs,iwz,z);
    alpha = stepsize(dx,ds,dw,dz,x,s,w,z);
    ralpha = rho*alpha;
    s = s + ralpha*ds;
    w = w + ralpha*dw;
    x = x + ralpha*dx;
    z = z + ralpha*dz;

    xs = x.*s; wz = w.*z;
    gap = sum(xs + wz)/m2;
    mu = min(.1,100*gap)*gap;
  
  end
  
  iter=iter-1;  %True number of iterations is one less

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Initial starting point  
function [s,w,x,z] = startpt(A,b,c,u,wc);
  
  m = size(A,2);
  en = ones(m,1);
  % Start at the center of the constraint box
  x = u/2; w = u - x; z = en; s = en; 
  if 0 
    AA = csm(A');  % csm efficiently computes cb'*cb
    for i=1:m
      AA(i,i) = AA(i,i) + wc;
    end % H = 2(A'A+wcI);
  else
    AA = A'*A + wc*eye(m);
  end
  ec = c + 2*AA*x;  %initial residual error used to initialize z,s;
  g = .1;  sg = 1+g;
  i = find(ec>0); s(i) =  sg*ec(i); z(i) =  g*ec(i); % Hx + c + z - s = 0;
  i = find(ec<0); z(i) = -sg*ec(i); s(i) = -g*ec(i);
  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Compute step direction
function [ds,dw,dx,dz] = direct(d,As2,rb,rc,ru,rxs,rwz,ix,iw,ixs,iwz,z);
  
  ixrxs = ix.*rxs; iwrwz = iw.*rwz;
  rr = iwrwz - ixrxs;

  if 0
    iHd = smwf(d,As2);  % smwf is a fast smw for the specific form used here
    dx = iHd*rr;
  else
    % iHd = inv(diag(d)+As2'*As2);
    dx = (diag(d)+As2'*As2)\rr;
  end
  ds = -ixs.*dx - ixrxs;	dw = -dx;
  dz = -iwz.*dw - iwrwz;
  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Compute stepsize
function alpha = stepsize(dx,ds,dw,dz,x,s,w,z);
  i = find(ds<0); as = min(-s(i)./ds(i));	
  i = find(dw<0); aw = min(-w(i)./dw(i));	
  i = find(dx<0); ax = min(-x(i)./dx(i));	
  i = find(dz<0); az = min(-z(i)./dz(i));	
  alpha = min([aw ax as az 1]);	

  
  
  
  
  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  csm.m  compute symmetric matrix from X = B*B'
function X = csm(B);
  
  [m,n] = size(B);
  for i=1:m-1
    for j=i+1:m
      X(i,j) = B(i,:)*B(j,:)';
      X(j,i) = X(i,j);
    end;	
  end;
  for i = 1:m;	X(i,i) = B(i,:)*B(i,:)'; end;
  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% smwf.m  computes the inverse of (A + B'B) using Sherman-Morrison-Woodbury formula
%    Fast version for specific matrices.
%   		where A is a diagonal matrix, but designated only by a vector
%													i.e. the input is the vector of the diagonal
%				B is non-square matrices 
%   H = inv(A) - inv(A)B'*inv(B*inv(A)B' + I)*B*inv(A);
%		
function		 H = smwf(A,B);
  
  [k,m] = size(B);
  iA = 1./A; iAB = zeros(m,k); BiA = zeros(k,m);  BAB = zeros(k);
  for i = 1:k    iAB(:,i) = iA.*B(i,:)'; end;
  for i = 1:k		BiA(i,:) = B(i,:).*iA';	end;
  for i=1:k-1
    for j=i+1:k
      BAB(i,j) = B(i,:)*iAB(:,j);
      BAB(j,i) = BAB(i,j);
    end;
  end;
  for i = 1:k;	BAB(i,i) = B(i,:)*iAB(:,i); end;
  Q = BAB;
  for i = 1:k;	Q(i,i) = Q(i,i) + 1; end
  QBA = Q\iAB';
  for i=1:m-1
    for j=i+1:m
      ABQBA(i,j) = iAB(i,:)*QBA(:,j);
      ABQBA(j,i) = ABQBA(i,j);
    end;
  end;
  for i = 1:m;  ABQBA(i,i) = iAB(i,:)*QBA(:,i); end
  H = -ABQBA;
  for i = 1:m
    H(i,i) = iA(i) + H(i,i);
  end
  

Contact us at files@mathworks.com