物理/力学中的线性化#

sympy.physics.mechanics 包括将生成的关于工作点的运动方程(EOM)线性化的方法(也称为配平条件)。注意,这个操作点不一定是一个平衡点,它只需要满足运动方程。

线性化是通过对运算点进行一阶泰勒展开来实现的。当没有相关的坐标或速度时,这只是右手边的雅可比 \(q\)\(u\) . 然而,在存在限制的情况下,需要更加小心。这里提供的线性化方法可以正确地处理这些约束。

背景#

sympy.physics.mechanics 我们假设所有系统都可以用以下一般形式表示:

\[\begin{split}f{c}(q,t)&=0{l\乘以1}\\\end{split}\]

在哪里?

\[\begin{split}q、 \dot{q}&\in\mathbb{R}^n\\\end{split}\]

以这种形式,

  • \(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 类,它执行实际的线性化。两者兼而有之 KanesMethodLagrangesMethod 对象具有使用 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=Truelinearize 类方法。

凯恩方程的线性化#

初始化后 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_depqd_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]])

中的符号越少 AM 在求解之前,这个解会越快。因此,对于大型表达式,延迟转换到 \(A\)\(B\) 直到大多数符号的数值都被细分。

2线性化形式有 nanzoooo 作为矩阵元素#

这有两个潜在的原因。第一个(你应该先检查一下)一些相关坐标的选择会在某些操作点产生奇点。以系统的方式协调分区以避免这种情况超出了本指南的范围;请参阅 [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

其他示例#

上面使用的钟摆例子很简单,但没有包含任何相关的坐标或速度。为了更彻底的例子,使用凯恩和拉格朗日方法用相关坐标对同一摆进行线性化: