更多关于坐标系的内容

我们现在将探讨如何在 sympy.vector 中初始化新的坐标系,这些坐标系相对于已存在的系统以用户定义的方式进行变换。

定位新系统

我们已经知道,CoordSys3Dorigin 属性对应于表示其原点参考点的 Point 实例。

考虑一个坐标系 \(N\)。假设我们想要定义一个新的系统 \(M\),其原点位于 \(N\) 的原点 \(\mathbf{3\hat{i} + 4\hat{j} + 5\hat{k}}\) 处。换句话说,从 \(N\) 的角度来看,\(M\) 的原点坐标恰好是 \((3, 4, 5)\)。此外,这也意味着相对于 \(M\)\(N\) 的原点坐标将是 \((-3, -4, -5)\)

这可以通过以下程序化方式实现 -

>>> from sympy.vector import CoordSys3D
>>> N = CoordSys3D('N')
>>> M = N.locate_new('M', 3*N.i + 4*N.j + 5*N.k)
>>> M.position_wrt(N)
3*N.i + 4*N.j + 5*N.k
>>> N.origin.express_coordinates(M)
(-3, -4, -5)

值得注意的是,\(M\) 的方向与 \(N\) 的方向相同。这意味着 \(N\) 相对于 \(M\) 的旋转矩阵,反之亦然,等于 3x3 的单位矩阵。locate_new 方法初始化了一个 CoordSys3D,该系统仅在空间中相对于’父’系统进行了平移,而没有重新定向。

定向新系统

类似于’定位’新系统,sympy.vector 也允许初始化新的 CoordSys3D 实例,这些实例以用户定义的方式相对于现有系统进行定向。

假设你有一个坐标系 \(A\)

>>> from sympy.vector import CoordSys3D
>>> A = CoordSys3D('A')

你想要初始化一个新的坐标系 \(B\) ,它是相对于 \(A\) 的 Z 轴旋转了角度 \(\theta\)

>>> from sympy import Symbol
>>> theta = Symbol('theta')

方向显示在下面的图中:

image/svg+xml A B θ θ azbz ax bx ay by

有两种方法可以实现这一点。

直接使用 CoordSys3D 的方法

这是最简单、最干净的方式,因此也是推荐的做法。

>>> B = A.orient_new_axis('B', theta, A.k)

这将用相对于 \(A\) 的所需方向信息初始化 \(B\)

CoordSys3D 在其 API 中提供了以下直接定向方法:

  1. orient_new_axis

  2. orient_new_body

  3. orient_new_space

  4. orient_new_quaternion

请查看本模块文档中提供的 CoordSys3D 类 API,以详细了解其功能和所需参数。

使用 Orienter(s) 和 orient_new 方法

首先,你需要初始化一个 AxisOrienter 实例来存储旋转信息。

>>> from sympy.vector import AxisOrienter
>>> axis_orienter = AxisOrienter(theta, A.k)

然后使用 orient_new 方法应用它,以获得 \(B\)

>>> B = A.orient_new('B', axis_orienter)

orient_new 还允许你使用多个 Orienter 实例来定向新系统,这些实例以可迭代对象的形式提供。旋转/定向将按照 Orienter 实例在可迭代对象中出现的顺序应用于新系统。

>>> from sympy.vector import BodyOrienter
>>> from sympy.abc import a, b, c
>>> body_orienter = BodyOrienter(a, b, c, 'XYZ')
>>> C = A.orient_new('C', (axis_orienter, body_orienter))

The sympy.vector API 提供了以下四个 Orienter 类用于方向目的:

  1. AxisOrienter

  2. BodyOrienter

  3. SpaceOrienter

  4. QuaternionOrienter

请参考本模块文档中各个类的API以了解更多。

在上述每个例子中,新坐标系的原点与’父’坐标系的原点重合。

>>> B.position_wrt(A)
0

要计算任意坐标系相对于另一个坐标系的旋转矩阵,请使用 rotation_matrix 方法。

>>> B = A.orient_new_axis('B', a, A.k)
>>> B.rotation_matrix(A)
Matrix([
[ cos(a), sin(a), 0],
[-sin(a), cos(a), 0],
[      0,      0, 1]])
>>> B.rotation_matrix(B)
Matrix([
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]])

定位和定位新系统

如果你想初始化一个不仅以预定义方式定向,而且相对于父对象进行转换的新系统,该怎么办?

每个 orient_new_<方向方法> 方法,以及 orient_new 方法,都支持一个 location 关键字参数。

如果为此 kwarg 提供了 Vector 作为值,新系统的原点将自动定义为相对于父坐标系统位于该位置矢量的位置。

因此,定位方法也作为支持新系统定位的方法。

>>> C = A.orient_new_axis('C', a, A.k, location=2*A.j)
>>> C.position_wrt(A)
2*A.j
>>> from sympy.vector import express
>>> express(A.position_wrt(C), C)
(-2*sin(a))*C.i + (-2*cos(a))*C.j

稍后会详细介绍 express 函数。

转换新系统

创建用户定义系统的最通用方法是使用 CoordSys3D 中的 transformation 参数。在这里我们可以定义任何变换方程。如果我们对一些典型的非笛卡尔曲线坐标系感兴趣,我们也可以使用一些预定义的坐标系。通过设置适当的变换方程,也可以实现系统的平移或旋转。

>>> from sympy.vector import CoordSys3D
>>> from sympy import sin, cos
>>> A = CoordSys3D('A', transformation='spherical')
>>> B = CoordSys3D('A', transformation=lambda x,y,z: (x*sin(y), x*cos(y), z))

CoordSys3D 中也有一个专门的方法,create_new,它的工作方式类似于 locate_neworient_new_axis 等方法。

>>> from sympy.vector import CoordSys3D
>>> A = CoordSys3D('A')
>>> B = A.create_new('B', transformation='spherical')

不同坐标系中的量表达

向量和张量

如前所述,相同的向量在不同的坐标系中会表现出不同的表达式。一般来说,标量表达式和并矢张量也是如此。

sympy.vector 支持使用 express 函数在不同的坐标系中表达向量/标量量。

在本节中,假设有以下初始化:

>>> from sympy.vector import CoordSys3D, express
>>> from sympy.abc import a, b, c
>>> N = CoordSys3D('N')
>>> M = N.orient_new_axis('M', a, N.k)

Vector 实例可以使用 express 在用户定义的系统中表示。

>>> v1 = N.i + N.j + N.k
>>> express(v1, M)
(sin(a) + cos(a))*M.i + (-sin(a) + cos(a))*M.j + M.k
>>> v2 = N.i + M.j
>>> express(v2, N)
(1 - sin(a))*N.i + (cos(a))*N.j

除了 Vector 实例,express 还支持标量(一般 SymPy Expr)和 Dyadic 对象的重表达。

express 也接受第二个坐标系来重新表达 Dyadic 实例。

>>> d = 2*(M.i | N.j) + 3* (M.j | N.k)
>>> express(d, M)
(2*sin(a))*(M.i|M.i) + (2*cos(a))*(M.i|M.j) + 3*(M.j|M.k)
>>> express(d, M, N)
2*(M.i|N.j) + 3*(M.j|N.k)

坐标变量

坐标系原点的位置不影响 BaseVector 实例的重新表达。然而,它确实影响 BaseScalar 实例在不同系统中的表达方式。

BaseScalar 实例是坐标 ‘符号’,用于表示在 sympy.vector 中定义向量/标量场时使用的变量。

例如,考虑在系统 \(N\) 中定义的标量场 \(\mathbf{{T}_{N}(x, y, z) = x + y + z}\)。因此,在坐标为 \((a, b, c)\) 的点上,场值为 \(a + b + c\)。现在考虑系统 \(R\),其原点相对于 \(N\) 位于 \((1, 2, 3)\) 处(方向不变)。在 \(R\) 中坐标为 \((a, b, c)\) 的点在 \(N\) 中的坐标为 \((a + 1, b + 2, c + 3)\)。因此,\(\mathbf{{T}_{N}}\)\(R\) 中的表达式变为 \(\mathbf{{T}_{R}}(x, y, z) = x + y + z + 6\)

坐标变量,如果存在于向量/标量/并矢表达式中,也可以通过将 expressvariables 关键字参数设置为 True,在给定的坐标系中重新表达。

上述提到的示例,以编程方式完成,将如下所示 -

>>> R = N.locate_new('R', N.i + 2*N.j + 3*N.k)
>>> T_N = N.x + N.y + N.z
>>> express(T_N, R, variables=True)
R.x + R.y + R.z + 6

其他依赖表达式的方法

Vectorto_matrix 方法和 Pointexpress_coordinates 方法也会根据提供的坐标系返回不同的结果。

>>> P = R.origin.locate_new('P', a*R.i + b*R.j + c*R.k)
>>> P.express_coordinates(N)
(a + 1, b + 2, c + 3)
>>> P.express_coordinates(R)
(a, b, c)
>>> v = N.i + N.j + N.k
>>> v.to_matrix(M)
Matrix([
[ sin(a) + cos(a)],
[-sin(a) + cos(a)],
[               1]])
>>> v.to_matrix(N)
Matrix([
[1],
[1],
[1]])