-
Sylvain CALINON authoredSylvain CALINON authored
mpc_utils.cpp 6.12 KiB
// Interactive MPC helper functions
#include "mpc_utils.h"
//#include <LinAlg/LapackWrapperExtra.h>
//#include <SymEigsSolver.h>
#define PI 3.14159265359
// We are going to calculate the eigenvalues of M
using namespace arma;
/*
void symEigs( arma::vec* Dv, arma::mat* V, arma::mat A, int numEigs, int convFactor)
{
// Construct matrix operation object using the wrapper class DenseGenMatProd
DenseGenMatProd<double> op(A);
// Construct eigen solver object, requesting the largest three eigenvalues
SymEigsSolver< double, LARGEST_ALGE, DenseGenMatProd<double> > eigs(&op, numEigs, convFactor);
eigs.init();
int nconv = eigs.compute();
if(nconv > 0)
{
*Dv = eigs.eigenvalues();
*V = eigs.eigenvectors(nconv);
}
else
{
*Dv = arma::zeros(2);
*V = arma::eye(2,2);
}
}
*/
double factorials[15] =
{
1,
1,
2,
6,
24,
120,
720,
5040,
40320,
362880,
3628800,
39916800,
479001600,
6227020800,
87178291200
};
static mat transformSigma( const mat& m, const mat& Sigma)
{
mat V;
vec d;
eig_sym(d, V, Sigma);
mat D = diagmat(d);
V = m*V;
return V*D*inv(V);
}
arma::mat rot2d( double theta, bool affine )
{
int d = affine?3:2;
arma::mat m = arma::eye(d,d);
double ct = cos(theta);
double st = sin(theta);
m(0,0) = ct; m(0,1) = -st;
m(1,0) = st; m(1,1) = ct;
return m;
}
static mat makeSigma( float rot, vec scale )
{
mat Q = rot2d(rot, false);
mat Lambda = diagmat(scale%scale);
return Q * Lambda * inv(Q);
}
/// Inits the system matrices with a chain of integrators
void makeIntegratorChain(arma::mat* A, arma::mat* B, int order)
{
*A = zeros(order, order);
A->submat(0, 1, order-2, order-1)
= eye(order-1, order-1);
*B = join_vert(zeros(order-1,1),
ones(1,1));
}
void discretizeSystem(arma::mat* _A, arma::mat* _B, arma::mat A, arma::mat B, double dt, bool zoh )
{
if(zoh)
{
// matrix eponential trick
// From Linear Systems: A State Variable Approach with Numerical Implementation pg 215
// adapted from scipy impl
mat EM = join_horiz(A, B);
mat zero = join_horiz(zeros(B.n_cols, B.n_rows),
zeros(B.n_cols, B.n_cols));
EM = join_vert(EM, zero);
mat M = expmat(EM * dt);
*_A = M.submat(span(0, A.n_rows-1), span(0, A.n_cols-1));
*_B = M.submat(span(0, B.n_rows-1), span(A.n_cols, M.n_cols-1));
}
else // euler
{
*_A = eye(A.n_rows, A.n_cols) + A*dt;
*_B = B * dt;
}
}
/// Creates random gaussians as targets for LQR constraints
void randomCovariances(arma::cube* Sigma, const arma::mat& Mu, const arma::vec& covscale, bool semiTied, double theta, double minRnd )
{
int m = Mu.n_cols;
*Sigma = zeros(2,2,m);
vec s;
for( int i = 0; i < m; i++ )
{
vec s = (minRnd+(randu(2)*(1.-minRnd))) % covscale;
if(!semiTied)
theta = -PI + arma::randu()*2.*PI;
mat sigm = makeSigma(theta, s);
Sigma->slice(i) = makeSigma(theta, s);
}
}
double SHM_r(double d, double period, int order)
{
double omega = (2. * PI) / period;
return 1. / pow(d * pow(omega,order), 2);
}
arma::ivec stepwiseIndices(int m, int n)
{
return arma::conv_to<arma::ivec>::from(
arma::linspace(0, (float)m-0.1, n) );
}
arma::ivec viaPointIndices(int m, int n)
{
float a = 0.;
float b = n-1;
ivec inds = zeros<ivec>(m);
for( int i = 0; i < m; i++ )
inds(i) = (int)(a + i*(b-a)/(m-1));
return inds;
}
void stepwiseReference( arma::mat* MuQ, arma::mat* Q, const mat& Mu, const cube& Sigma, int n, int order, int dim, double endWeight )
{
int m = Mu.n_cols;
int cDim = order*dim;
int muDim = Mu.n_rows;
// equally distributed optimal states
// Could try something along the lines of Fitts here based on covariance.
arma::ivec qList = stepwiseIndices(m, n);
// precision matrices
mat Lambda = zeros(muDim, m*muDim);
for( int i = 0; i < m; i++ )
Lambda.cols(i*muDim, muDim*(i+1)-1) = inv(Sigma.slice(i));
*Q = zeros(cDim*n, cDim*n); // Precision matrix
*MuQ = zeros(cDim, n); // Mean vector
for( int i = 0; i < qList.n_rows; i++ )
{
// Precision matrix based on state sequence
Q->submat(i*cDim,
i*cDim,
i*cDim+muDim-1,
i*cDim+muDim-1) =
Lambda.cols(qList[i]*muDim, (qList[i]+1)*muDim-1);
// Mean vector
MuQ->submat(span(0,muDim-1), span(i,i)) = Mu.col(qList[i]);
}
if(endWeight > 0.0)
{
// Set last value for Q to enforce 0 end condition
int ind = qList.n_rows-1;
for( int i = 2; i < cDim; i++ )
Q->operator()(ind*cDim+i, ind*cDim+i) = endWeight;
}
}
void viaPointReference( arma::mat* MuQ, arma::mat* Q, const mat& Mu, const cube& Sigma, int n, int order, int dim, double endWeight )
{
int m = Mu.n_cols;
int cDim = order*dim;
int muDim = Mu.n_rows;
// equally distributed optimal states
// Could try something along the lines of Fitts here based on covariance.
arma::ivec qList = stepwiseIndices(m, n);
// precision matrices
mat Lambda = zeros(muDim, m*muDim);
for( int i = 0; i < m; i++ )
Lambda.cols(i*muDim, muDim*(i+1)-1) = inv(Sigma.slice(i));
*Q = zeros(cDim*n, cDim*n); // Precision matrix
*MuQ = zeros(cDim, n); // Mean vector
ivec vI = viaPointIndices(m, n);
for( int i = 0; i < vI.n_rows; i++ )
{
int t = vI[i];
Q->submat(t*cDim,
t*cDim,
t*cDim+muDim-1,
t*cDim+muDim-1)
=
Lambda.cols(i*muDim, (i+1)*muDim-1);
MuQ->submat(span(0,muDim-1), span(t,t)) = Mu.col(i);
}
if(endWeight > 0.0)
{
// Set last value for Q to enforce 0 end condition
int ind = n-1;
for( int i = 2; i < cDim; i++ )
Q->operator()(ind*cDim+i, ind*cDim+i) = endWeight;
}
}