scipy.spatial.transform.Rotation.

align_vectors#

classmethod Rotation.align_vectors(cls, 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\) 是与每个向量对应的 weights

使用 Kabsch 算法 [1] 估计旋转,并解决所谓的“指向问题”或“Wahba 问题”[2]

有两种特殊情况。第一种是如果为 ab 给定单个向量,则返回将 b 对齐到 a 的最短距离旋转。

第二种情况是当其中一个权重为无穷大时。在这种情况下,将计算主要无穷大权重向量之间的最短距离旋转,如上所述。然后,计算关于对齐的主要向量的旋转,使得次要向量根据上述损失函数最优对齐。结果是这两个旋转的组合。通过此过程获得的结果与 Kabsch 算法相同,因为当相应的权重在极限中接近无穷大时。对于单个次要向量,这被称为“对齐约束”算法 [3]

对于两种特殊情况(单个向量或无穷大权重),灵敏度矩阵没有物理意义,如果请求,将引发错误。对于无穷大权重,主向量充当完美对齐的约束,因此即使它们的长度不同,它们对 rssd 的贡献也将被强制为 0。

参数:
aarray_like,形状为 (3,) 或 (N, 3)

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

barray_like,形状为 (3,) 或 (N, 3)

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

weightsarray_like,形状为 (N,),可选

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

return_sensitivitybool,可选

是否返回灵敏度矩阵。有关详细信息,请参阅“注释”。默认值为 False。

返回:
rotationRotation 实例

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

rssdfloat

代表“均方根距离”。对齐后给定向量集之间平方距离的加权和的平方根。它等于 sqrt(2 * minimum_loss),其中 minimum_loss 是为找到的最佳旋转评估的损失函数。请注意,结果也将由向量的大小加权,因此如果完美对齐的向量对的长度不同,则它们将具有非零 rssd。因此,根据用例,可能需要在调用此方法之前将输入向量归一化为单位长度。

sensitivity_matrixndarray,形状为 (3, 3)

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

注释

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

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

参考文献

[3]

Magner, Robert, “通过轨迹和动量设定点优化扩展目标跟踪能力。” 小型卫星会议,2018 年。

[5]

F. Landis Markley,“使用向量观测确定姿态:快速最优矩阵算法”,《天文学期刊》,第 41 卷,第 2 期,1993 年,第 261-280 页。

[6]

Bar-Itzhack, Itzhack Y.,Daniel Hershkowitz 和 Leiba Rodman,“在实欧几里得空间中指向”,《制导、控制和动力学期刊》,第 20 卷,第 5 期,1997 年,第 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.]])