scipy.spatial.transform.Rotation.

align_vectors#

static Rotation.align_vectors(a, b, weights=None, return_sensitivity=False)[源代码]#

估计一个旋转,以最优地对齐两组向量。

在 A 帧和 B 帧之间找到一个旋转,该旋转能最佳地对齐在这两帧中观测到的一组向量 ab。以下损失函数被最小化以求解旋转矩阵 \(C\)

\[L(C) = \frac{1}{2} \sum_{i = 1}^{n} w_i \lVert \mathbf{a}_i - C \mathbf{b}_i \rVert^2 ,\]

其中 \(w_i\)’s 是与每个向量对应的 weights

旋转通过 Kabsch 算法 [1] 进行估计,解决了所谓的“指向问题”或“Wahba 问题” [2]

请注意,此公式中每个向量的长度都充当隐式权重。因此,在所有向量需要被同等加权的情况下,您应该在调用此方法之前先将它们归一化为单位向量。

有两种特殊情况。第一种是当 ab 各只给出一个向量时,此时将返回将 b 对齐到 a 的最短距离旋转。

第二种情况是一个权重为无穷大。在这种情况下,首先计算具有无限权重的基本向量之间的最短距离旋转。然后,围绕已对齐的基本向量计算旋转,使得次要向量根据上述损失函数被最优地对齐。结果是这两个旋转的组合。通过此过程得到的结果与 Kabsch 算法在相应权重趋于无穷大的极限情况下的结果相同。对于单个次要向量,这被称为“align-constrain”算法 [3]

对于这两种特殊情况(单个向量或无限权重),灵敏度矩阵没有物理意义,如果请求它将引发错误。对于无限权重,基本向量充当具有完美对齐的约束,因此它们的 rssd 贡献将被强制为 0,即使它们的长度不同。 rssd 是加权平方距离之和的平方根。默认权重为 1,因此在这种情况下, rssd 计算如下:

参数:
aarray_like, shape (3,) 或 (N, 3)

在初始帧 A 中观测到的向量分量。 a 的每一行代表一个向量。

barray_like, shape (3,) 或 (N, 3)

在另一个帧 B 中观测到的向量分量。 b 的每一行代表一个向量。

weightsarray_like shape (N,), optional

描述向量观测相对重要性的权重。如果为 None(默认值),则假设 weights 中的所有值都为 1。可以有一个且仅一个权重为无穷大,并且权重必须为正。

return_sensitivitybool, optional

是否返回灵敏度矩阵。请参阅“Notes”了解详情。默认值为 False。

返回:
rotationRotation 实例

b 转换为 a 的最佳估计旋转。

rssdfloat

代表“均方根距离”。对齐后给定向量集合之间的加权平方距离之和的平方根。它等于 sqrt(2 * minimum_loss),其中 minimum_loss 是在找到的最优旋转下评估的损失函数。请注意,结果还将根据向量的幅度进行加权,因此完美对齐的向量对将具有非零 rssd,除非它们的长度相同。通过在调用此方法之前将它们归一化为单位长度可以避免这种情况,但请注意,这样做会改变生成的旋转。

sensitivity_matrixndarray, shape (3, 3)

如“Notes”中所述,估计旋转的灵敏度矩阵。仅在 return_sensitivity 为 True 时返回。当对齐单个向量对或存在无限权重时无效,在这种情况下将引发错误。

附注

灵敏度矩阵给出了估计旋转对向量测量的小扰动的敏感性。具体来说,我们将旋转估计误差视为 A 帧的一个小旋转向量。假设 a 中的向量测量误差远小于其长度,则灵敏度矩阵与此旋转向量的协方差成正比。要获得真实的协方差矩阵,返回的灵敏度矩阵必须乘以每次观测方差的调和平均值 [4]。请注意,为了获得一致的结果, weights 应与观测方差成反比。例如,如果所有向量都以相同的精度 0.01 (weights 必须都相等) 测量,则应将灵敏度矩阵乘以 0.01**2 以获得协方差。

有关协方差估计的更严谨的讨论,请参阅 [5]。有关指向问题和最小正向指向的更多讨论,请参阅 [6]

此函数不支持广播或 N > 2 的 ND 数组。

数组 API 标准支持

align_vectors 除了 NumPy 之外,还实验性地支持兼容 Python Array API Standard 的后端。请通过设置环境变量 SCIPY_ARRAY_API=1 并提供 CuPy、PyTorch、JAX 或 Dask 数组作为数组参数来测试这些功能。支持以下后端和设备(或其他功能)的组合。

CPU

GPU

NumPy

不适用

CuPy

不适用

PyTorch

JAX

Dask

不适用

有关更多信息,请参阅 对数组 API 标准的支持

参考文献

[3]

Magner, Robert, “Extending target tracking capabilities through trajectory and momentum setpoint optimization.” Small Satellite Conference, 2018.

[5]

F. Landis Markley, “Attitude determination using vector observations: a fast optimal matrix algorithm”, Journal of Astronautical Sciences, Vol. 41, No.2, 1993, pp. 261-280.

[6]

Bar-Itzhack, Itzhack Y., Daniel Hershkowitz, and Leiba Rodman, “Pointing in Real Euclidean Space”, Journal of Guidance, Control, and Dynamics, Vol. 20, No. 5, 1997, pp. 916-922.

示例

>>> import numpy as np
>>> from scipy.spatial.transform import Rotation as R

这里我们运行基线 Kabsch 算法来最佳对齐两组向量,其中 b 集合的最后两个向量测量值存在噪声

>>> a = [[0, 1, 0], [0, 1, 1], [0, 1, 1]]
>>> b = [[1, 0, 0], [1, 1.1, 0], [1, 0.9, 0]]
>>> rot, rssd, sens = R.align_vectors(a, b, return_sensitivity=True)
>>> rot.as_matrix()
array([[0., 0., 1.],
       [1., 0., 0.],
       [0., 1., 0.]])

当我们对 b 应用旋转时,我们会得到接近 a 的向量

>>> rot.apply(b)
array([[0. , 1. , 0. ],
       [0. , 1. , 1.1],
       [0. , 1. , 0.9]])

第一个向量的误差为 0,最后两个向量的误差幅度为 0.1。 rssd 是加权平方误差之和的平方根,默认权重均为 1,因此在这种情况下, rssd 的计算方式为 sqrt(1 * 0**2 + 1 * 0.1**2 + 1 * (-0.1)**2) = 0.141421356237308

>>> a - rot.apply(b)
array([[ 0., 0.,  0. ],
       [ 0., 0., -0.1],
       [ 0., 0.,  0.1]])
>>> np.sqrt(np.sum(np.ones(3) @ (a - rot.apply(b))**2))
0.141421356237308
>>> rssd
0.141421356237308

此示例的灵敏度矩阵如下所示

>>> sens
array([[0.2, 0. , 0.],
       [0. , 1.5, 1.],
       [0. , 1. , 1.]])

特殊情况 1:查找单个向量之间的最小旋转

>>> a = [1, 0, 0]
>>> b = [0, 1, 0]
>>> rot, _ = R.align_vectors(a, b)
>>> rot.as_matrix()
array([[0., 1., 0.],
       [-1., 0., 0.],
       [0., 0., 1.]])
>>> rot.apply(b)
array([1., 0., 0.])

特殊情况 2:一个无限权重。这里我们找到主向量和次向量之间的旋转,可以精确对齐

>>> a = [[0, 1, 0], [0, 1, 1]]
>>> b = [[1, 0, 0], [1, 1, 0]]
>>> rot, _ = R.align_vectors(a, b, weights=[np.inf, 1])
>>> rot.as_matrix()
array([[0., 0., 1.],
       [1., 0., 0.],
       [0., 1., 0.]])
>>> rot.apply(b)
array([[0., 1., 0.],
       [0., 1., 1.]])

这里次要向量必须是最佳拟合

>>> a = [[0, 1, 0], [0, 1, 1]]
>>> b = [[1, 0, 0], [1, 2, 0]]
>>> rot, _ = R.align_vectors(a, b, weights=[np.inf, 1])
>>> rot.as_matrix()
array([[0., 0., 1.],
       [1., 0., 0.],
       [0., 1., 0.]])
>>> rot.apply(b)
array([[0., 1., 0.],
       [0., 1., 2.]])