物理/力学中的线性化#
sympy.physics.mechanics
包括将生成的关于工作点的运动方程(EOM)线性化的方法(也称为配平条件)。注意,这个操作点不一定是一个平衡点,它只需要满足运动方程。
线性化是通过对运算点进行一阶泰勒展开来实现的。当没有相关的坐标或速度时,这只是右手边的雅可比 \(q\) 和 \(u\) . 然而,在存在限制的情况下,需要更加小心。这里提供的线性化方法可以正确地处理这些约束。
背景#
在 sympy.physics.mechanics
我们假设所有系统都可以用以下一般形式表示:
在哪里?
以这种形式,
\(f_{{c}}\) 表示配置约束方程
\(f_{{v}}\) 表示速度约束方程
\(f_{{a}}\) 表示加速度约束方程
\(f_{{0}}\) 和 \(f_{{1}}\) 形成运动微分方程
\(f_{{2}}\) , \(f_{{3}}\) 和 \(f_{{4}}\) 形成动力学微分方程
\(q\) 和 \(\dot{{q}}\) 是广义坐标及其导数
\(u\) 和 \(\dot{{u}}\) 是广义速度及其导数
\(r\) 是系统输入
\(\lambda\) 是拉格朗日乘数
这种广义形式被保存在 Linearizer
类,它执行实际的线性化。两者兼而有之 KanesMethod
和 LagrangesMethod
对象具有使用 to_linearizer
类方法。
一旦将系统强制为广义形式,就可以求解线性化的EOM。中提供的方法 sympy.physics.mechanics
考虑两种不同形式的线性EOM:
- \(M\), \(A\), and \(B\)
在这种形式下,强迫矩阵被线性化为两个独立的矩阵 \(A\) 和 \(B\) . 这是线性化EOM的默认形式。由此得出的方程为:
\[\begin{split}M\begin{bmatrix}\delta\dot{q}\\\ delta\dot{u}\\\ delta\lambda\end{bmatrix}=\end{split}\]在哪里?
\[\begin{split}M&\in\mathbb{R}^{(n+o+k)\times(n+o+k)}\\\end{split}\]注意 \(q_i\) 和 \(u_i\) 只是独立的坐标和速度,而 \(q\) 和 \(u\) 包含独立和从属坐标和速度。
- \(A\) and \(B\)
在这种形式下,线性化的EOM仅以独立的坐标和速度表示为一阶显式形式。这种形式通常用于稳定性分析或控制理论。由此得出的方程为:
\[\begin{split}\begin{bmatrix}\delta\dot{qu i}\\\ delta\dot{u}\end{bmatrix}=\end{split}\]在哪里?
\[\begin{split}A&\in\mathbb{R}^{(n-l+o-m)\times(n-l+o-m)}\\\end{split}\]使用此表单集
A_and_B=True
在linearize
类方法。
凯恩方程的线性化#
初始化后 KanesMethod
对象与形成 \(F_r\) 和 \(F_r^*\) 使用 kanes_equations
类方法,线性化可以用几种方法实现。用单摆系统演示不同的方法:
>>> from sympy import symbols, Matrix
>>> from sympy.physics.mechanics import *
>>> q1 = dynamicsymbols('q1') # Angle of pendulum
>>> u1 = dynamicsymbols('u1') # Angular velocity
>>> q1d = dynamicsymbols('q1', 1)
>>> L, m, t, g = symbols('L, m, t, g')
>>> # Compose world frame
>>> N = ReferenceFrame('N')
>>> pN = Point('N*')
>>> pN.set_vel(N, 0)
>>> # A.x is along the pendulum
>>> A = N.orientnew('A', 'axis', [q1, N.z])
>>> A.set_ang_vel(N, u1*N.z)
>>> # Locate point P relative to the origin N*
>>> P = pN.locatenew('P', L*A.x)
>>> vel_P = P.v2pt_theory(pN, N, A)
>>> pP = Particle('pP', P, m)
>>> # Create Kinematic Differential Equations
>>> kde = Matrix([q1d - u1])
>>> # Input the force resultant at P
>>> R = m*g*N.x
>>> # Solve for eom with kanes method
>>> KM = KanesMethod(N, q_ind=[q1], u_ind=[u1], kd_eqs=kde)
>>> fr, frstar = KM.kanes_equations([pP], [(P, R)])
1使用 Linearizer
直接上课:#
线性化器对象可以使用 to_linearizer
类方法。这将强制在 KanesMethod
对象转换为上述广义形式。由于独立和相关的坐标和速度是在创建KanesMethod对象时指定的,因此不需要在这里指定它们。:
>>> linearizer = KM.to_linearizer()
线性化的EOM可以用 linearize
方法 Linearizer
对象:::
>>> M, A, B = linearizer.linearize()
>>> M
Matrix([
[1, 0],
[0, -L**2*m]])
>>> A
Matrix([
[ 0, 1],
[L*g*m*cos(q1(t)), 0]])
>>> B
Matrix(0, 0, [])
或者, \(A\) 和 \(B\) 可以通过指定 A_and_B=True
::
>>> A, B = linearizer.linearize(A_and_B=True)
>>> A
Matrix([
[ 0, 1],
[-g*cos(q1(t))/L, 0]])
>>> B
Matrix(0, 0, [])
操作点也可以指定为字典或字典的iterable。这将在返回矩阵:::
>>> op_point = {q1: 0, u1: 0}
>>> A_op, B_op = linearizer.linearize(A_and_B=True, op_point=op_point)
>>> A_op
Matrix([
[ 0, 1],
[-g/L, 0]])
请注意,应用 msubs
生成的矩阵没有 op_point
夸格:::
>>> assert msubs(A, op_point) == A_op
有时返回的矩阵可能不是最简单的形式。简化可以在事后进行,或者 Linearizer
对象可以通过设置 simplify
克瓦格 True
.
2使用 linearize
类方法:#
这个 linearize
方法 KanesMethod
类是作为调用 to_linearizer
在内部,执行线性化,并返回结果。请注意,在 linearize
上面描述的方法在这里也可用:::
>>> A, B, inp_vec = KM.linearize(A_and_B=True, op_point=op_point, new_method=True)
>>> A
Matrix([
[ 0, 1],
[-g/L, 0]])
附加输出 inp_vec
是一个包含所有找到的 dynamicsymbols
不包括在广义坐标或速度矢量中。假设这些是系统的输入,形成 \(r\) 上述背景中描述的向量。在本例中没有输入,因此向量为空:::
>>> inp_vec
Matrix(0, 0, [])
拉格朗日方程的线性化#
拉格朗日方程的线性化过程与凯恩方程的线性化过程基本相同。如前所述,将用单摆系统演示该过程:
>>> # Redefine A and P in terms of q1d, not u1
>>> A = N.orientnew('A', 'axis', [q1, N.z])
>>> A.set_ang_vel(N, q1d*N.z)
>>> P = pN.locatenew('P', L*A.x)
>>> vel_P = P.v2pt_theory(pN, N, A)
>>> pP = Particle('pP', P, m)
>>> # Solve for eom with Lagrange's method
>>> Lag = Lagrangian(N, pP)
>>> LM = LagrangesMethod(Lag, [q1], forcelist=[(P, R)], frame=N)
>>> lag_eqs = LM.form_lagranges_equations()
1使用 Linearizer
直接上课:#
A Linearizer
可以从 LagrangesMethod
对象使用 to_linearizer
类方法。这个过程和 KanesMethod
班上那是 LagrangesMethod
对象尚未在内部指定其独立和相关的坐标和速度。这些必须在调用中指定 to_linearizer
. 在这个例子中没有相关的坐标和速度,但是如果有,它们将包含在 q_dep
和 qd_dep
夸格斯:::
>>> linearizer = LM.to_linearizer(q_ind=[q1], qd_ind=[q1d])
一旦以这种形式出现,一切都和以前一样 KanesMethod
示例:::
>>> A, B = linearizer.linearize(A_and_B=True, op_point=op_point)
>>> A
Matrix([
[ 0, 1],
[-g/L, 0]])
2使用 linearize
类方法:#
类似 KanesMethod
, the LagrangesMethod
类还提供了 linearize
方法作为调用 to_linearizer
在内部,执行线性化,并返回结果。和以前一样,唯一的区别是独立和相关的坐标和速度也必须在调用中指定:::
>>> A, B, inp_vec = LM.linearize(q_ind=[q1], qd_ind=[q1d], A_and_B=True, op_point=op_point)
>>> A
Matrix([
[ 0, 1],
[-g/L, 0]])
潜在问题#
而 Linearizer
类 应该 能够线性化所有系统,有一些潜在的问题可能发生。下面将讨论这些问题,以及解决这些问题的一些故障排除技巧。
1符号线性化 A_and_B=True
很慢#
这可能是由许多原因造成的,但最有可能的是,象征性地求解大型线性系统是一项昂贵的操作。指定操作点将减小表达式大小并加快速度。如果需要一个纯符号化的解决方案(例如,在以后的一段时间内应用许多操作点),一种解决这一问题的方法是使用 A_and_B=False
,然后应用操作点:::
>>> M, A, B = linearizer.linearize()
>>> M_op = msubs(M, op_point)
>>> A_op = msubs(A, op_point)
>>> perm_mat = linearizer.perm_mat
>>> A_lin = perm_mat.T * M_op.LUsolve(A_op)
>>> A_lin
Matrix([
[ 0, 1],
[-g/L, 0]])
中的符号越少 A
和 M
在求解之前,这个解会越快。因此,对于大型表达式,延迟转换到 \(A\) 和 \(B\) 直到大多数符号的数值都被细分。
2线性化形式有 nan
, zoo
或 oo
作为矩阵元素#
这有两个潜在的原因。第一个(你应该先检查一下)一些相关坐标的选择会在某些操作点产生奇点。以系统的方式协调分区以避免这种情况超出了本指南的范围;请参阅 [Blajer1994] 更多信息。
另一个可能的原因是,在替换操作点之前,矩阵可能不是最简化的形式。这种行为的一个简单示例是:::
>>> from sympy import sin, tan
>>> expr = sin(q1)/tan(q1)
>>> op_point = {q1: 0}
>>> expr.subs(op_point)
nan
请注意,如果在替换之前简化了此表达式,则会得到正确的值:::
>>> expr.simplify().subs(op_point)
1
避免这种情况的好办法还没有找到。对于大小合理的表达式,使用 msubs
具有 smart=True
将应用一个算法来避免这些情况。对于大型表达式,这是非常耗时的。:
>>> msubs(expr, op_point, smart=True)
1
其他示例#
上面使用的钟摆例子很简单,但没有包含任何相关的坐标或速度。为了更彻底的例子,使用凯恩和拉格朗日方法用相关坐标对同一摆进行线性化: