Are.java
/*
* $Id: Are.java,v 1.39 2008/07/17 07:30:03 koga Exp $
*
* Copyright (C) 2004 Koga Laboratory. All rights reserved.
*/
package org.mklab.tool.control;
import java.util.List;
import org.mklab.nfc.eig.SchurDecomposition;
import org.mklab.nfc.matrix.ComplexNumericalMatrix;
import org.mklab.nfc.matrix.DoubleComplexMatrix;
import org.mklab.nfc.matrix.DoubleMatrix;
import org.mklab.nfc.matrix.IntMatrix;
import org.mklab.nfc.matrix.RealNumericalMatrix;
import org.mklab.nfc.scalar.ComplexNumericalScalar;
import org.mklab.nfc.scalar.DoubleNumber;
import org.mklab.nfc.scalar.RealNumericalScalar;
import org.mklab.tool.matrix.Schord;
/**
* 連続時間リカッティ方程式の解を求めるクラスです。
*
* <p>Solution of continuous-time Riccati equation
*
* @author koga
* @version $Revision: 1.39 $
* @see org.mklab.tool.control.Ric
* @see org.mklab.tool.control.Lqr
*/
public class Are {
/**
* 連続時間リカッティ方程式
*
* <pre><code> A#*P + P*A - P*R*P + Q = 0 </code></pre>
*
* の解をシュア分解を用いて求め、その解を返します。
*
* @param A システム行列 (system matrix)
* @param R 入力に関する重み(非負定対称)行列 (symmetric and nonnegative definite weighting matrix for inputs)
* @param Q 状態に関する重み(対称)行列 (symmetric weighting matrix for states)
* @return リカッティ方程式の解 (solution)
*/
public static DoubleMatrix are(DoubleMatrix A, DoubleMatrix R, DoubleMatrix Q) {
return are(A, R, Q, -1);
}
/**
* 虚軸に対する固有値の位置を判定するための許容誤差として<code>tolerance</code>を用いる。
*
* @param A システム行列 (system matrix)
* @param R 入力に関する重み(非負定対称)行列 (symmetric and nonnegative definite weighting matrix for inputs)
* @param Q 状態に関する重み(対称)行列 (symmetric weighting matrix for states)
* @param tolerance 許容誤差(tolerance)
* @return リカッティ方程式の解 (solution)
*/
public static DoubleMatrix are(DoubleMatrix A, DoubleMatrix R, DoubleMatrix Q, double tolerance) {
return are(A, R, Q, new DoubleNumber(tolerance));
}
/**
* 虚軸に対する固有値の位置を判定するための許容誤差として<code>tolerance</code>を用いる。
*
* @param A システム行列 (system matrix)
* @param R 入力に関する重み(非負定対称)行列 (symmetric and nonnegative definite weighting matrix for inputs)
* @param Q 状態に関する重み(対称)行列 (symmetric weighting matrix for states)
* @param tolerance 許容誤差(tolerance)
* @return リカッティ方程式の解 (solution)
*/
public static DoubleMatrix are(DoubleMatrix A, DoubleMatrix R, DoubleMatrix Q, DoubleNumber tolerance) {
String message;
if ((message = Abcdchk.abcdchk(A)).length() > 0) {
throw new IllegalArgumentException(message);
}
int n = A.getRowSize();
if (R.getRowSize() != n || R.getColumnSize() != n) {
message = Messages.getString("Are.0") + R.getRowSize() + "x" + R.getColumnSize() + Messages.getString("Are.2"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
throw new IllegalArgumentException(message);
}
if (Q.getRowSize() != n || Q.getColumnSize() != n) {
message = Messages.getString("Are.3") + Q.getRowSize() + "x" + Q.getColumnSize() + Messages.getString("Are.5"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
throw new IllegalArgumentException(message);
}
DoubleNumber unit = A.getElement(1, 1).createUnit();
DoubleMatrix tmp1 = A.appendRight(R.unaryMinus());
DoubleMatrix tmp2 = Q.unaryMinus().appendRight(A.conjugateTranspose().unaryMinus());
DoubleMatrix tmp3 = tmp1.appendDown(tmp2);
SchurDecomposition<DoubleNumber,DoubleMatrix> tmp4 = tmp3.schurDecompose();
DoubleMatrix U = tmp4.getU();
DoubleMatrix T = tmp4.getT();
DoubleNumber localTolerance = tolerance.clone();
if (localTolerance.isLessThan(0)) {
localTolerance = (T.diagonalToVector().absElementWise()).max().multiply(10).multiply(unit.getMachineEpsilon());
}
/*
* Location of eigenvalues: -1 : open left-half-plane 1 : open
* right-half-plane 0 : within tolerance of imaginary axis
*/
int np = 0;
IntMatrix idx = new IntMatrix(1, 2 * n);
for (int i = 1; i <= 2 * n; i++) {
if (T.getElement(i, i).isLessThan(localTolerance.unaryMinus())) {
idx.setElement(1, i, -1);
np++;
} else if (T.getElement(i, i).isGreaterThan(localTolerance)) {
idx.setElement(1, i, 1);
} else {
idx.setElement(1, i, 0);
}
}
if (np != n) {
throw new IllegalArgumentException(Messages.getString("Are.6")); //$NON-NLS-1$
}
List<DoubleComplexMatrix> tmp = Schord.schord(U, T, idx);
DoubleComplexMatrix Uc = tmp.get(0);
DoubleMatrix P = Uc.getSubMatrix(n + 1, n + n, 1, n).divide(Uc.getSubMatrix(1, n, 1, n)).getRealPart();
return P;
}
/**
* 虚軸に対する固有値の位置を判定するための許容誤差として<code>tolerance</code>を用いる。
*
* @param <RS> スカラーの型
* @param <RM> 行列の型
* @param <CS> 複素スカラーの型
* @param <CM> 複素行列の型
* @param A システム行列 (system matrix)
* @param R 入力に関する重み(非負定対称)行列 (symmetric and nonnegative definite weighting matrix for inputs)
* @param Q 状態に関する重み(対称)行列 (symmetric weighting matrix for states)
* @param tolerance 許容誤差(tolerance)
* @return リカッティ方程式の解 (solution)
*/
public static <RS extends RealNumericalScalar<RS, RM, CS, CM>, RM extends RealNumericalMatrix<RS, RM, CS, CM>, CS extends ComplexNumericalScalar<RS, RM, CS, CM>, CM extends ComplexNumericalMatrix<RS, RM, CS, CM>> RM are(RM A, RM R, RM Q, RS tolerance) {
String message;
if ((message = Abcdchk.abcdchk(A)).length() > 0) {
throw new IllegalArgumentException(message);
}
int n = A.getRowSize();
if (R.getRowSize() != n || R.getColumnSize() != n) {
message = Messages.getString("Are.0") + R.getRowSize() + "x" + R.getColumnSize() + Messages.getString("Are.2"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
throw new IllegalArgumentException(message);
}
if (Q.getRowSize() != n || Q.getColumnSize() != n) {
message = Messages.getString("Are.3") + Q.getRowSize() + "x" + Q.getColumnSize() + Messages.getString("Are.5"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
throw new IllegalArgumentException(message);
}
RS unit = A.getElement(1, 1).createUnit();
RM tmp1 = A.appendRight(R.unaryMinus());
RM tmp2 = Q.unaryMinus().appendRight(A.conjugateTranspose().unaryMinus());
RM tmp3 = tmp1.appendDown(tmp2);
SchurDecomposition<RS,RM> tmp4 = tmp3.schurDecompose();
RM U = tmp4.getU();
RM T = tmp4.getT();
RS localTolerance = tolerance.clone();
if (localTolerance.isLessThan(0)) {
localTolerance = (T.diagonalToVector().absElementWise()).max().multiply(10).multiply(unit.getMachineEpsilon());
}
/*
* Location of eigenvalues: -1 : open left-half-plane 1 : open
* right-half-plane 0 : within tolerance of imaginary axis
*/
int np = 0;
IntMatrix idx = new IntMatrix(1, 2 * n);
for (int i = 1; i <= 2 * n; i++) {
if (T.getElement(i, i).isLessThan(localTolerance.unaryMinus())) {
idx.setElement(1, i, -1);
np++;
} else if (T.getElement(i, i).isGreaterThan(localTolerance)) {
idx.setElement(1, i, 1);
} else {
idx.setElement(1, i, 0);
}
}
if (np != n) {
throw new IllegalArgumentException(Messages.getString("Are.6")); //$NON-NLS-1$
}
List<CM> tmp = Schord.schord(U, T, idx);
CM Uc = tmp.get(0);
RM P = Uc.getSubMatrix(n + 1, n + n, 1, n).divide(Uc.getSubMatrix(1, n, 1, n)).getRealPart();
return P;
}
}