向量和参考帧#
在 sympy.physics.vector
向量和参考系是动态系统的“积木”。并用这个模块的数学描述这些代码。
矢量#
向量是一个具有大小(或长度)和方向的几何对象。三维空间中的向量通常在纸上表示为:
向量代数#
向量代数是第一个要讨论的话题。
当且仅当(iff)两个向量的大小和方向相同时,称两个向量相等。
向量运算#
多个代数运算可以用向量来完成:向量之间的加法、标量乘法和向量乘法。
基于平行四边形定律的矢量加法。
向量加法也是可交换的:
标量乘法是一个向量和一个标量的乘积;结果是一个方向相同但其大小由标量缩放的向量。注意,乘-1相当于在垂直于向量的平面上绕任意轴旋转矢量180度。
单位向量就是一个大小等于1的向量。给定任何向量 \(\mathbf{{v}}\) 我们可以将单位向量定义为:
注意,每个向量都可以写成标量和单位向量的乘积。
在中实现了三个向量积 sympy.physics.vector
:点积、叉积和外积。
点积运算将两个向量映射到一个标量。定义为:
在哪里? \(\theta\) 夹角是 \(\mathbf{{a}}\) 和 \(\mathbf{{b}}\) .
两个单位向量的点积表示共同方向的大小;对于其他向量,它是共同方向的大小与两个向量的大小的乘积。两条垂线的点积为零。下图显示了一些示例:
点积是可交换的:
两个向量的叉积向量乘法运算返回一个向量:
向量 \(\mathbf{{c}}\) 具有以下特性:它的方向与两者垂直 \(\mathbf{{a}}\) 和 \(\mathbf{{b}}\) ,其大小定义为 \(\Vert \mathbf{{c}} \Vert = \Vert \mathbf{{a}} \Vert \Vert \mathbf{{b}} \Vert \sin(\theta)\) (何处) \(\theta\) 夹角是 \(\mathbf{{a}}\) 和 \(\mathbf{{b}}\) ),并通过使用右手规则定义 \(\Vert \mathbf{{a}} \Vert \Vert \mathbf{{b}} \Vert\) . 如下图所示:
叉积具有以下特性:
它不是可交换的:
并且没有关联性:
两个平行向量将有一个零叉积。
这里不讨论两个向量之间的外积,而是在惯量部分(即使用它的地方)讨论。其他有用的向量属性和关系包括:
替代代表#
如果我们有三个非共面单位向量 \(\mathbf{{\hat{{n}}_x}},\mathbf{{\hat{{n}}_y}},\mathbf{{\hat{{n}}_z}}\) ,我们可以表示任何向量 \(\mathbf{{a}}\) 作为 \(\mathbf{{a}} = a_x \mathbf{{\hat{{n}}_x}} + a_y \mathbf{{\hat{{n}}_y}} + a_z \mathbf{{\hat{{n}}_z}}\) . 在这种情况下 \(\mathbf{{\hat{{n}}_x}},\mathbf{{\hat{{n}}_y}},\mathbf{{\hat{{n}}_z}}\) 被称为基础。 \(a_x, a_y, a_z\) 称为度量值。通常单位向量是相互垂直的,在这种情况下,我们可以把它们称为正交基,它们通常是右手的。
为了测试两个向量之间的相等性,现在我们可以执行以下操作。带向量:
如果: \(a_x = b_x, a_y = b_y, a_z = b_z\) .
然后,对于相同的两个向量,向量加法表示为:
乘法运算现在定义为:
要在给定的基础上写出向量,我们可以执行以下操作:
实例#
这些操作的一些数值示例如下:
向量演算#
对于运动物体的矢量计算,必须引入参考系的概念。一个典型的例子是一列火车沿着轨道行驶,车内有你和一个朋友。如果你和你的朋友都坐着,你俩之间的相对速度是零。从车外的观察者那里,你们俩都有速度。
我们现在将对这个定义应用更严格的定义。参考系是一个虚拟的“平台”,我们可以从中选择观察向量量。如果我们有一个参照系 \(\mathbf{{N}}\) ,矢量 \(\mathbf{{a}}\) 据说是固定在镜框里的 \(\mathbf{{N}}\) 如果从 \(\mathbf{{N}}\) . 我们通常会为每个参考帧指定一个固定的正交基向量集; \(\mathbf{{N}}\) 将有 \(\mathbf{{\hat{{n}}_x}}, \mathbf{{\hat{{n}}_y}},\mathbf{{\hat{{n}}_z}}\) 作为它的基本向量。
向量导数#
因此,在参考系中没有固定的向量,当从该参考系观察时,其性质会发生变化。微积分是对变化的研究,为了处理向量在不同参考系中固定和不固定的特性,我们需要在定义上更加明确。
在上图中,我们有向量 \(\mathbf{{c,d,e,f}}\) . 如果有人用 \(\mathbf{{e}}\) 关于 \(\theta\) :
目前还不清楚导数是什么。如果你从画面上观察 \(\mathbf{{A}}\) ,显然是非零。如果你从画面上观察 \(\mathbf{{B}}\) ,导数为零。因此,我们将引入框架作为导数符号的一部分:
以下是特定帧中向量导数的一些附加性质:
基向量的相关集合#
我们现在需要定义两个不同的参考坐标系之间的关系,或者如何将一个坐标系的基向量与另一个坐标系的基向量联系起来。我们可以用方向余弦矩阵(DCM)来实现。方向余弦矩阵以以下方式将一个帧的基向量与另一个帧的基向量相关联:
当两帧(比如, \(\mathbf{{A}}\) & \(\mathbf{{B}}\) )首先对齐,然后一个帧的所有基向量围绕一个与基向量对齐的轴旋转,我们称这些帧通过简单的旋转来关联。如下图所示:
上述旋转是绕Z轴旋转一个角度的简单旋转 \(\theta\) . 注意,在旋转之后,基向量 \(\mathbf{{\hat{{a}}_z}}\) 和 \(\mathbf{{\hat{{b}}_z}}\) 仍然保持一致。
这种旋转可以用以下方向的余弦矩阵表示:
围绕X和Y轴的简单旋转由以下定义:
此处正方向的旋转将使用右手规则定义。
方向余弦矩阵还涉及到基向量集之间点积的定义。如果我们有两个具有相关基向量的参考坐标系,它们的方向余弦矩阵可以定义为:
另外,方向余弦矩阵是正交的,其中:
如果我们有参考系 \(\mathbf{{A}}\) 和 \(\mathbf{{B}}\) ,在本例中,它经历了简单的z轴旋转 \(\theta\) ,我们将有两组基向量。然后我们可以定义两个向量: \(\mathbf{{a}} = \mathbf{{\hat{{a}}_x}} + \mathbf{{\hat{{a}}_y}} + \mathbf{{\hat{{a}}_z}}\) 和 \(\mathbf{{b}} = \mathbf{{\hat{{b}}_x}} + \mathbf{{\hat{{b}}_y}} + \mathbf{{\hat{{b}}_z}}\) . 如果我们想表达 \(\mathbf{{b}}\) 在 \(\mathbf{{A}}\) 框架,我们执行以下操作:
如果我们想表达 \(\mathbf{{a}}\) 在 \(\mathbf{{B}}\) ,我们可以:
多框架导数#
如果我们有参考系 \(\mathbf{{A}}\) 和 \(\mathbf{{B}}\) 我们将有两组基向量。然后我们可以定义两个向量: \(\mathbf{{a}} = a_x\mathbf{{\hat{{a}}_x}} + a_y\mathbf{{\hat{{a}}_y}} + a_z\mathbf{{\hat{{a}}_z}}\) 和 \(\mathbf{{b}} = b_x\mathbf{{\hat{{b}}_x}} + b_y\mathbf{{\hat{{b}}_y}} + b_z\mathbf{{\hat{{b}}_z}}\) . 如果我们要求 \(\mathbf{{b}}\) 在参考系中 \(\mathbf{{A}}\) ,我们必须先用 \(\mathbf{{A}}\) ,取度量值的导数:
实例#
向量演算的一个例子:
在这个例子中,我们有两个物体,每个物体都附有一个参照系。我们会这么说的 \(\theta\) 和 \(x\) 是时间的函数。我们想知道向量的时间导数 \(\mathbf{{c}}\) 在两者中 \(\mathbf{{A}}\) 和 \(\mathbf{{B}}\) 框架。
首先,我们需要定义 \(\mathbf{{c}}\) ; \(\mathbf{{c}}=x\mathbf{{\hat{{b}}_x}}+l\mathbf{{\hat{{b}}_y}}\) . 这提供了 \(\mathbf{{B}}\) 框架。我们现在可以执行以下操作:
在 \(\mathbf{{A}}\) 帧,我们必须首先关联两个帧:
现在我们可以执行以下操作:
注意,这是 \(\mathbf{{c}}\) 在里面 \(\mathbf{{A}}\) ,并用 \(\mathbf{{A}}\) 框架。我们可以用 \(\mathbf{{B}}\) 但是,表达式仍然有效:
注意这两种形式在表达复杂度上的差异。它们是等价的,但其中一个要简单得多。这是一个非常重要的概念,因为用更复杂的形式定义向量可以极大地减慢运动方程的表达速度,并增加其长度,有时甚至到了无法在屏幕上显示的程度。
使用向量和参考坐标系#
我们一直等到所有相关的数学关系都为向量和参考框架定义好之后才引入代码。这是由于向量是如何形成的。当开始出现任何问题时 sympy.physics.vector
,第一步是定义参考框架(记住导入sympy.物理.矢量第一个)::
>>> from sympy.physics.vector import *
>>> N = ReferenceFrame('N')
现在我们已经建立了一个参照系, \(\mathbf{{N}}\) . 要访问任何基向量,首先需要创建一个参考帧。现在我们已经做了 \(\mathbf{{N}}\) ,我们可以访问它的基向量:
>>> N.x
N.x
>>> N.y
N.y
>>> N.z
N.z
向量代数,in物理.矢量#
我们现在可以对这些向量进行基本的代数运算
>>> N.x == N.x
True
>>> N.x == N.y
False
>>> N.x + N.y
N.x + N.y
>>> 2 * N.x + N.y
2*N.x + N.y
记住,不要把标量加到向量上 (N.x + 5
);这将引发错误。在这一点上,我们将在向量中使用SymPy的符号。在处理符号时,请记住参考SymPy的陷阱和陷阱:
>>> from sympy import Symbol, symbols
>>> x = Symbol('x')
>>> x * N.x
x*N.x
>>> x*(N.x + N.y)
x*N.x + x*N.y
在 sympy.physics.vector
在运算符级、方法级和函数级,实现了向量乘法的多个接口。矢量点积的工作原理如下:::
>>> N.x.dot(N.x)
1
>>> N.x.dot(N.y)
0
>>> dot(N.x, N.x)
1
>>> dot(N.x, N.y)
0
“官方”接口是函数接口;这是所有示例中使用的接口。这是为了避免混淆属性和方法彼此相邻,并且在运算符操作优先级的情况下。中使用的运算符 sympy.physics.vector
因为向量乘法没有正确的运算顺序,这会导致错误。使用运算符表示向量乘法时,需要注意括号。
叉积是另一个向量乘法,我们将在这里讨论。它提供了与dot产品相似的接口,并带有相同的警告。:
>>> N.x.cross(N.x)
0
>>> N.x.cross(N.z)
- N.y
>>> cross(N.x, N.y)
N.z
>>> cross(N.x, (N.y + N.z))
- N.y + N.z
可以对向量执行两个附加操作:将向量规格化为长度1,并获取其大小。具体做法如下:
>>> (N.x + N.y).normalize()
sqrt(2)/2*N.x + sqrt(2)/2*N.y
>>> (N.x + N.y).magnitude()
sqrt(2)
向量通常以矩阵形式表示,特别是在数值计算中。由于矩阵形式不包含有关定义矢量的参考坐标系的任何信息,因此必须提供一个参考坐标系以从矢量中提取度量值。有一个方便的函数可以完成此操作:
>>> (x * N.x + 2 * x * N.y + 3 * x * N.z).to_matrix(N)
Matrix([
[ x],
[2*x],
[3*x]])
向量演算物理.矢量#
我们已经介绍了我们的第一个参考系。如果我们愿意的话,我们现在可以在这个框架中取导数:::
>>> (x * N.x + N.y).diff(x, N)
N.x
SymPy有一个 diff
函数,但它当前不适用于 sympy.physics.vector
向量,所以请使用 Vector
的 diff
方法。这是因为在区分 Vector
,除了要对SymPy的导数进行求导之外,还必须指定参照系 diff
函数不适合此模具。
更有趣的情况出现在多个参考系中。如果我们引入第二个参考系, \(\mathbf{{A}}\) ,我们现在有两个帧。注意,此时我们可以添加 \(\mathbf{{N}}\) 和 \(\mathbf{{A}}\) 但不能执行矢量乘法,因为这两个帧之间没有定义任何关系。:
>>> A = ReferenceFrame('A')
>>> A.x + N.x
N.x + A.x
If we want to do vector multiplication, first we have to define an
orientation. The orient
method of ReferenceFrame
provides that
functionality.
>>> A.orient(N, 'Axis', [x, N.y])
This orients the \(\mathbf{A}\) frame relative to the \(\mathbf{N}\)
frame by a simple rotation, around the Y axis, by an amount x.
The DCM between these two frames can be viewed at any time with the
dcm
method: A.dcm(N)
gives the dcm \(^{\mathbf{A}} \mathbf{C} ^{\mathbf{N}}\).
Other, more complicated rotation types include Body rotations, Space rotations, quaternions, and arbitrary axis rotations. Body and space rotations are equivalent to doing 3 simple rotations in a row, each about a basis vector in the new frame. An example follows:
>>> N = ReferenceFrame('N')
>>> Bp = ReferenceFrame('Bp')
>>> Bpp = ReferenceFrame('Bpp')
>>> B = ReferenceFrame('B')
>>> q1,q2,q3 = symbols('q1 q2 q3')
>>> Bpp.orient(N,'Axis', [q1, N.x])
>>> Bp.orient(Bpp,'Axis', [q2, Bpp.y])
>>> B.orient(Bp,'Axis', [q3, Bp.z])
>>> N.dcm(B)
Matrix([
[ cos(q2)*cos(q3), -sin(q3)*cos(q2), sin(q2)],
[sin(q1)*sin(q2)*cos(q3) + sin(q3)*cos(q1), -sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), -sin(q1)*cos(q2)],
[sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3), sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1), cos(q1)*cos(q2)]])
>>> B.orient(N,'Body',[q1,q2,q3],'XYZ')
>>> N.dcm(B)
Matrix([
[ cos(q2)*cos(q3), -sin(q3)*cos(q2), sin(q2)],
[sin(q1)*sin(q2)*cos(q3) + sin(q3)*cos(q1), -sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), -sin(q1)*cos(q2)],
[sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3), sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1), cos(q1)*cos(q2)]])
空间方向与实体方向类似,但从帧应用到实体。身体和空间旋转可以涉及两个或三个轴:“XYZ”工作,“YZX”、“ZXZ”、“YXY”等也可以。关键是每个简单的旋转都围绕着与前一个不同的轴;“ZZX”并不完全确定3个空间中一组基向量的方向。
有时,创建一个新的参考系并确定相对于现有参考系的方向会更加方便。这个 orientnew
方法允许此功能,并实质上包装 orient
方法。所有你能做的事情 orient
,你可以在 orientnew
. ::
>>> C = N.orientnew('C', 'Axis', [q1, N.x])
四元数(或Euler参数)使用4值来描述帧的方向。中描述了该旋转和任意轴旋转 orient
和 orientnew
方法帮助,或在引用中 [Kane1983].
最后,在开始多帧微积分操作之前,我们将介绍另一个 sympy.physics.vector
工具: dynamicsymbols
. dynamicsymbols
是在SymPy中创建未定义的时间函数的快捷函数。这种“动态符号”的导数如下所示。:
>>> from sympy import diff
>>> q1, q2, q3 = dynamicsymbols('q1 q2 q3')
>>> diff(q1, Symbol('t'))
Derivative(q1(t), t)
上面不太清楚“dynamicsymbol”打印;我们还将介绍一些其他工具。我们可以利用 vprint
而不是打印非交互式会话。:
>>> q1
q1(t)
>>> q1d = diff(q1, Symbol('t'))
>>> vprint(q1)
q1
>>> vprint(q1d)
q1'
对于交互式会话,请使用 init_vprinting
. 也有类似的东西 vprint
, vpprint
和 latex
, vlatex
. ::
>>> from sympy.physics.vector import init_vprinting
>>> init_vprinting(pretty_print=False)
>>> q1
q1
>>> q1d
q1'
“dynamicsymbol”应用于表示 sympy.physics.vector
,无论是坐标、变化位置还是力。“dynamicsymbol”的主要用途是用于速度和坐标(在文档的运动学部分会有更多的讨论)。
现在我们将用“动态符号”来定义新框架的方向,并且可以轻松地获取导数和时间导数。下面是一些例子。:
>>> N = ReferenceFrame('N')
>>> B = N.orientnew('B', 'Axis', [q1, N.x])
>>> (B.y*q2 + B.z).diff(q2, N)
B.y
>>> (B.y*q2 + B.z).dt(N)
(-q1' + q2')*B.y + q2*q1'*B.z
请注意,输出向量保持在与中提供的相同的帧中。对于包含来自多个帧的基向量组成的分量的向量,情况仍然如此:::
>>> (B.y*q2 + B.z + q2*N.x).diff(q2, N)
N.x + B.y
矢量如何编码#
下面是中的代码如何定义向量的简短说明 sympy.physics.vector
. 谁想知道更多这方面的信息 sympy.physics.vector
工作,并且不需要阅读才能使用此模块;除非您想了解此模块是如何实现的,否则不要阅读它。
每个 Vector
的主要信息存储在 args
属性,该属性存储帧中每个基向量的三个度量值,以及每个相关帧的度量值。向量在代码中不存在,直到 ReferenceFrame
已创建。在这一点上 x
, y
和 z
参考系的属性是不变的 Vector
的度量值为 [1,0,0] , [0,1,0] 和 [0,0,1] 与此相关 ReferenceFrame
. 一旦这些向量是可访问的,就可以通过对基向量进行代数运算来创建新的向量。一个向量可以有来自多个帧的分量。这就是为什么 args
是一个列表;列表中元素的数量与唯一元素的数量相同 ReferenceFrames
如果有 A
和 B
在我们的新向量中, args
长度为2;如果有 A
, B
和 C
帧基向量, args
长度是三。
中的每个元素 args
list是一个2元组;第一个元素是SymPy Matrix
(这是存储每组基向量的度量值的地方)第二个元素是 ReferenceFrame
将这些度量值与。
ReferenceFrame
存储一些东西。首先,它存储您在创建时提供的名称 (name
属性)。它还存储方向余弦矩阵,在创建时使用 orientnew
方法,或调用 orient
方法。方向余弦矩阵用SymPy矩阵表示 Matrix
,和是字典的一部分,其中的键是 ReferenceFrame
以及 Matrix
它们是双向设置的;当你定向时 A
到 N
你正在设置 A
的方向词典要包括 N
及其 Matrix
,但你也在设置 N
的方向词典要包括 A
及其 Matrix
(DCM是另一个的转置)。