from sympy import init_printing
init_printing()
from sympy import *
Bei der Eingangs-Zustandslinearisierung ist der Ausgang \(y\) des nichtlinearen Systems nicht relevant. Es gibt eine gut ausgebaute Theorie, welche die Überprüfung der Eingangs-Zustands-Linearisierbarkeit erlaubt.
Für die Überprüfung der Existenz eines Ausganges mit relativem Grad \(r=n\) erweist sich die Lie-Klammer als hilfreich. Das gilt sowohl für Ein- als auch Mehrgrößensysteme (SISO und MIMO Systeme).
Die Theorie der differential-geometrischen Regelungstechnik ist sehr gut ausgebaut, jedoch alles andere als trivial. Für das Erlernen dieser Techniken sollte viel Zeit eingeplant werden. An den Universitäten werden dafür meist mehrere Vorlesungen benötigt, um diese Theorie vollständig einzuführen.
Es soll hier nur gezeigt werden, dass Python / Sympy auf für nichtlineare Methoden gut geeignet ist.
Lie-Klammer
Die Lie-Klammer ist folgendermaßen definiert
\[ [f, g](x) = L_f g(x) = \frac{\partial g}{\partial x} f(x) - \frac{\partial f}{\partial x} g(x) \]
wobei hier sowohl \(f(x)\) als auch \(g(x)\) Vektorfelder sind.
Auch die Lie-Klammer (Lie-Ableitung der Vektorfelder) kann wie die Lie-Ableitung der skalaren Funktionen rekursive angewendet werden. Die k-fache Lie-Klammer lässt sich in der Form
\[ ad_f^kg(x) = \begin{bmatrix} f & ad_f^{k-1}g \end{bmatrix}(x) \qquad ad_f^0g(x) = g(x) \]
mit dem Operator \(ad\) definieren.
Existenz eines Ausganges mit relativem Grad r = n)
Für SISO Systeme ist es notwendig aber nicht hinreichend, dass die Matrix
\[ M = \begin{bmatrix}g & ad_f g & \cdots & ad_f^{n-1} g\end{bmatrix} \]
den Rang \(n\) besitzt.
Beispiel
Dieses Beispiel ist aus dem Vorlesungskript von Andreas Kugi, TU Wien entnommen.
Gegeben sei das AI-System
\[ \dot{x} = \underset{f(x)}{\underbrace{ \begin{bmatrix} x_3 \\ x_4 \\ - \frac{c}{I_1} x_1 + \frac{c}{I_1} x_2 - \frac{d_1}{I_1} x_3 \\ \frac{c}{I_2} x_1 - \frac{c}{I_2} x_2 - \frac{mgl}{I_2} cos(x_2) - \frac{d_2}{I_2} x_4 \end{bmatrix}}} + \underset{g(x)}{\underbrace{ \begin{bmatrix} 0 \\ 0 \\ \frac{1}{I_1} \\ 0 \end{bmatrix}}} u. \]
Das Durchführen der Rechnung führt auf das Ergebnis
\[ rang(\begin{bmatrix}ad_f^0g & ad_f^1g & ad_f^2g & ad_f^3g\end{bmatrix}) = rang \left(\begin{bmatrix} 0 & \frac{-1}{I_1} & \frac{-d_1}{I_1^2} & \frac{I_1c-d_1^2}{I_1^3} \\ 0 & 0 & 0 & -\frac{c}{I_2I_1} \\ \frac{1}{I_1} & \frac{d_1}{I_1^2} & \frac{d_1^2-cI_1}{I_1^3} & \frac{d_1^3-2cd_1I_1}{I_4^4} \\ 0 & 0 & \frac{c}{I_2I_1} & \frac{c}{I_2I_1}\left(\frac{d_1}{I_1} + \frac{d_2}{I_2} \right) \end{bmatrix}\right) = 4. \]
Wir wollen diese Berechnung nun in Python / Sympy durchführen.
def jac(f,x):
return f.jacobian(x)
def lie_deriv(f, h, x, n=1):
""" Lie-derivative of a scalar function h with respect to a vector-field f
"""
if n==0:
= h
Lfh else:
= h.jacobian(x)@f
Lfh for i in range(1,n):
= Lfh.jacobian(x)@f
Lfh return Lfh
def lie_braket(f, g, x, n=1):
""" Lie-bracket, Lie-derivative of a vector-field g with respect to another vector-field f
"""
if n==0:
= g
adfg else:
= g.jacobian(x)@f - f.jacobian(x)@g
adfg for i in range(1,n):
= adfg.jacobian(x)@f - f.jacobian(x)@adfg
adfg return adfg
= symbols('x1 x2 x3 x4', real=True)
x1, x2, x3, x4 = Matrix([[x1],[x2],[x3],[x4]]) x_vec
= symbols('c g l m', positive=True)
c, g, l, m = symbols('I1 d1', positive=True)
I1, d1 = symbols('I2 d2', positive=True) I2, d2
= Matrix([
f
[x3],
[x4],-c/I1*x1+c/I1*x2-d1/I1*x3],
[/I2*x1-c/I2*x2-m*g*l/I2*cos(x2)-d2/I2*x4]
[c
])
f
\(\displaystyle \left[\begin{matrix}x_{3}\\x_{4}\\- \frac{c x_{1}}{I_{1}} + \frac{c x_{2}}{I_{1}} - \frac{d_{1} x_{3}}{I_{1}}\\\frac{c x_{1}}{I_{2}} - \frac{c x_{2}}{I_{2}} - \frac{d_{2} x_{4}}{I_{2}} - \frac{g l m \cos{\left(x_{2} \right)}}{I_{2}}\end{matrix}\right]\)
= Matrix([
g 0],
[0],
[1/I1],
[0]
[
]) g
\(\displaystyle \left[\begin{matrix}0\\0\\\frac{1}{I_{1}}\\0\end{matrix}\right]\)
= lie_braket(f, g, x_vec,n=0)
adf0g = lie_braket(f, g, x_vec,n=1)
adf1g = lie_braket(f, g, x_vec,n=2)
adf2g = lie_braket(f, g, x_vec,n=3)
adf3g = adf0g
M = M.col_insert(1,adf1g)
M = M.col_insert(2,adf2g)
M = M.col_insert(3,adf3g)
M simplify(M)
\(\displaystyle \left[\begin{matrix}0 & - \frac{1}{I_{1}} & - \frac{d_{1}}{I_{1}^{2}} & \frac{I_{1} c - d_{1}^{2}}{I_{1}^{3}}\\0 & 0 & 0 & - \frac{c}{I_{1} I_{2}}\\\frac{1}{I_{1}} & \frac{d_{1}}{I_{1}^{2}} & \frac{- I_{1} c + d_{1}^{2}}{I_{1}^{3}} & \frac{d_{1} \left(- 2 I_{1} c + d_{1}^{2}\right)}{I_{1}^{4}}\\0 & 0 & \frac{c}{I_{1} I_{2}} & \frac{c \left(I_{1} d_{2} + I_{2} d_{1}\right)}{I_{1}^{2} I_{2}^{2}}\end{matrix}\right]\)
M.rank()
\(\displaystyle 4\)
Die Matrix
\[ M = \begin{bmatrix}ad_f^0g & ad_f^1g & ad_f^2g & ad_f^3g\end{bmatrix} \]
hat also den vollen Rang \(n=4\) und der relative Grad ist also \(r=4\).
Fazit
Python / Sympy bietet viele Möglichkeiten für die nichtlineare Regelungtechnik. Dieser Blogeintrag bezieht sich auf differentialgeometrischen Methoden, genauer auf die Exakte Eingangs-Zustandslinearisierung im Eingrößenfall.
Sind die nichtlinearen Regler einmal hergeleitet, so können diese mithilfe der Python-Control Submodule wie control.flatsys
oder control.NonlinearIOSystem
implementiert werden.
Referenzen
- Nichtlineare Systeme und Regelungen, 3. Auflage (Jürgen Adamy, 2018)
- The Geometry of Physics, Third Edition (Theodore Frankel, 2012)
- Regelsysteme 2 (Andreas Kugi, Vorlesung SS 2021)