导数、对数和变换

日期:2023年2月7日 标签:Programming

给定一个变换 \(T\) 和一个点 x,我们可以使用 \(T * x\) 找到变换后的点。但是,如果我们想平滑地插值 \(T\),使其将 \(x\) 沿着从其初始位置到被 \(T\) 变换后的位置的路径移动,该怎么办?

我们想要找到的是时间 \(t\) 时的点 \(x\): \(x(t) = T(t) * x(0)\)

其中 \(x(0)\) 是点的初始位置,\(T(t)\) 是时间 \(t\) 时的变换。因为我们只有一个变换 \(T\),所以我们需要找到一种方法来随着时间的推移对其进行插值。

一种实现方法是将 \(T\) 提升到 \(t\) 的幂,这可以通过使用变换的指数和对数来完成。有趣的是,变换的对数也可以用来轻松找到空间中点 \(x\) 的速度:速度向量(也称为切线向量)只是 \(log(T) * x\)。这篇博文展示了对数和速度之间的关系。

示例

查看这个交互式示例,了解当您操纵 gizmo 来平移和旋转变换时,向量场如何变化。向量场表示变换过程中空间中每个点的速度向量。

当您移动 gizmo 时,您会注意到一条白色曲线,它描绘了从原点到 gizmo 变换的路径。沿着这条曲线,您会看到插值的变换,因为它从原点移动到 gizmo。正如您所看到的,插值沿着速度向量场的流向进行。该小程序的代码使用变换的指数和对数来计算曲线、插值变换和向量场。

该小程序的源代码可以在这里找到,其中包括刚体变换的闭式 log() 和 exp() 的实现。

接下来,我将描述如何计算您在此示例中看到的插值变换和速度向量场。

什么是 \(T(t)\)?

我们有 \(T\),但没有随时间变化的 \(T(t)\)。假设将两个变换相乘表示这些变换的组合,我们可以通过以下方式找到 \(T(t)\):

\(T(0) = I\) (单位变换) \(T(1) = T\) \(T(2) = T * T\) \(T(3) = T * T * T\)

更一般地,我们可以通过以下方式找到任何时间的 \(T\):

\(T(t) = T^t\)。

上面的技巧来自 Fabian Giesen 的一篇博文 这里,但适用于任何使用乘法进行组合的变换。

现在我们知道了 \(T(t) = T^t\),原始方程可以重新排列为

\(x(t) = T^t * x(0)\)。

什么是 \(T^t\)?

要计算 \(T^t\),我们需要使用矩阵指数和矩阵对数。

让我们从关于矩阵 X 的两个事实开始:

\(e^{log(X)} = X\) 和 \(log(X^y) = log(X) * y\)。

放在一起,我们可以说

\(T^t = e^{log(T^t)} = e^{log(T)*t}\)

我们可以将其插入到先前的等式中,得出

\(x(t) = e^{log(T) * t} * x(0)\)。

这说明,要找到时间 t 时的点 x,使用 \(e^{log(T) * t}\) 找到时间 t 时的变换,并使用它来变换其初始位置(时间 0)的点。

什么是导数?

在微积分中,我们了解到

\(\dfrac{d}{dt}e^{a t} = a e^{a t}\)

这对于矩阵也成立:

\(\dfrac{d}{dt}e^{A t} = A e^{A t}\)

这种关系在矩阵指数的导数部分有更详细的解释。

我们可以使用此属性来找到我们之前方程 \(x(t) = e^{log(T)t} x(0)\) 关于 t 的导数:

\(\dfrac{d}{dt}x(t) = log(T) e^{log(T) t} x(0)\)。

该方程指出,要找到时间 t 时点的导数(速度向量,也称为切线向量),首先使用插值变换 \(e^{log(T)t}\) 变换点的初始位置 \(x(0)\),然后将其乘以变换的对数 \(log(T)\)。此表达式遵循列向量的从右到左约定,因此您将从初始位置 \(x(0)\) 开始,然后应用插值变换 \(e^{log(T)t}\),最后乘以对数 \(log(T)\)。

\(e^{log(T) t}\) 充当一个算子,将点从其初始位置映射到时间 t 的新位置。矩阵指数可以被认为类似于积分。在时间 0,\(e^{log(T) t}\) 是单位矩阵 (\(e^0=I\) 对于矩阵指数),在时间 1.0,\(e^{log(T) t}\) 等于原始变换矩阵 T (\(e^{log(T)}=T\))。

这都意味着什么?

如果我们采用“什么是 \(T^t\)?”末尾的等式

\(x(t) = e^{log(T) t} x(0)\)

并将其代入“什么是导数?”末尾的等式

\(\dfrac{d}{dt}x(t) = log(T) e^{log(T) t} x(0)\),

那么我们有:

\(\dfrac{d}{dt}x(t) = log(T) x(t)\)。

这与移动点的导数相关联,该移动点由变换的对数移动。

一种思考 \(log(T)\) 的方式是将其视为变换的切线向量的向量场。换句话说,它是第一个导数的场。该向量场独立于时间,并显示空间中每个点的速度。

该等式说明,如果您通过变换的对数来变换空间中的任何点,您将获得该点的导数。导数是速度,因此 \(log(T)\) 定义了速度场(空间中每个点的切线向量的场)。

当一个点通过变换在空间中移动时,它会形成一条曲线。时间 t 的切线向量与时间 t 时点在曲线上的位置相切。

您可以将矩阵的对数视为由该矩阵执行的动作的速度场。上面交互式示例中可视化的速度场就是这个场。

更不正式地看待这一点的方式是说

\(velocity = log(transform) * position\)

意思是,要了解一个点将如何随时间移动,请将变换的对数的向量场视为速度场。当该点沿该速度场流动时,它会及时移动。

什么是微分方程?

我们也可以将所有这些重新表述为微分方程。早些时候,我们有

\(\dfrac{d}{dt} x(t) = log(T) x(t)\)

这是一个微分方程。因为 \(log(T)\) 是一个矩阵,所以它更具体地说是矩阵微分方程。

以下形式的标量常微分方程

\(y'(t)=ay(t)\)

具有一般解

\(y(t)=e^{at}y(0)\)。

类似地,以下形式的矩阵微分方程

\(x'(t)=Ax(t)\)

具有一般解

\(x(t)=e^{At}x(0)\)。

因此,给定我们之前的方程

\(\dfrac{d}{dt} x(t) = log(T) x(t)\)

我们有解决方案

\(x(t) = e^{log(T) t} x(0)\)。

这与我们原来的等式相同,但是我们从一个微分方程开始并找到了一个解。为了证明这个解是正确的,只需取它的导数,这正是我们之前在什么是导数?部分所做的。

指数映射和对数映射

指数映射定义为无穷级数

$$e^{A t} = I + A t + \frac{1}{2}(A t)^2 + \frac{1}{3!}(A t)^3 + ... = \sum_{i=0}^{\infty} \frac{(At)^i}{i!}$$

可用于查找实数、复数、四元数、矩阵等的指数。例如,当将方阵插入到该级数中时,结果称为矩阵指数

类似地,对数定义为无穷级数

$$log(A) = \sum_{i=1}^{\infty} (-1)^{i+1} \frac{(A - I)^i}{i}$$

如果您想了解更多信息,请搜索指数映射和对数映射。您会发现这些是李群理论中的重要概念。指数映射和对数映射是彼此的逆运算。在李理论中,指数映射将点 p 处的切向量映射到流形上的一个点。对数映射则相反,将流形上的一个点映射回 p 处的切向量。

在阅读李群时,您会遇到许多不同类型的群。但是,只有少数群与变换相关。 SO(3) 是一个 3D 旋转矩阵,SU(2) 是一个四元数,SE(3) 是一个 3D 刚体变换(旋转和平移),SIM(3) 是旋转、平移和(正)均匀缩放,而 GL(n) 是一个 nxn 矩阵。

对于如何实际计算矩阵或其他对象的指数映射和对数映射,有几种选择:

  1. 使用像 Eigen 或 Armadillo 这样的数学库。这些库具有计算矩阵指数和矩阵对数的函数。
  2. 库 Sophus 具有用于群 SO(3)、SE(3) 和 SIM(3) 的闭式 exp/log 代码。但要注意,它将其四元数限制为 -\(\pi\) … +\(\pi\) 中的 3D 旋转角度。
  3. 在 Ethan Eade 的网站上有一个优秀的 PDF 这里,其中包含群 SO(3)、SE(3) 和 SIM(3) 的闭式方程。
  4. 通过使用上面的无穷级数定义计算矩阵指数和对数,并在一些项之后截断。根据我的经验,当使用浮点数时,这并不稳定,因为您会很快开始处理非常小和非常大的数字,具体取决于您的输入矩阵。
  5. 通过数值积分计算指数。给定一个起点 \(x\),将其积分一段时间 t 与指数相同。从 Euler 到 Runge-Kutta 再到自适应方法,有很多方法可以计算数值积分。

陷阱

您应该注意以下几个问题。

陷阱 #1

旋转矩阵的对数将返回 -\(\pi\) … +\(\pi\) 中的 3D 旋转角度。更技术地说,矩阵有无限多个对数,每个对数对应于比前一个对数大 2\(\pi\) 的旋转角度。通常,矩阵对数代码将返回主对数,即 -\(\pi\) … +\(\pi\) 中的对数。这可能会导致插值包含旋转的变换时出现不连续性,例如来自人体关节的旋转(您可以将头从左肩上方看向右肩上方,并且旋转稍微超过 180 度)。

另一方面,四元数的对数返回 -2\(\pi\) … +2\(\pi\) 的较大范围内的 3D 旋转角度,这使得四元数更易于使用。

陷阱 #2

在使用对数时,请注意以下属性

\(log(AB) = log(A) + log(B)\)

当 A 和 B 可交换时才成立,对于大多数变换来说情况并非如此。但是,实数总是可交换的,因此该属性适用于它们。将该属性应用于变换很诱人,但重要的是要记住它仅在 A 和 B 可交换时才适用。

陷阱 #3

与陷阱 #2 相关,您可能想要使用以下方式插值两个变换 A 和 B

\(interpolate(A, B, t) = e^{(1-t)log(A) + tlog(B)}\)

但要小心:这仅在 A 和 B 可交换时才有效,对于变换来说通常不是这样。否则,此插值既不是最短路径也不是恒定速度。

相反,插值从 A 到 B 的相对(也称为增量)变换,如下所示:

\(interpolate(A, B, t) = e^{log(B A^{-1}) t} A\)

但是,此方法仅适用于在两个变换之间进行插值,而不适用于混合两个以上的变换。

将矩阵可视化为向量场

如果您想知道如何将矩阵可视化为向量场,3Blue1Brown 关于矩阵指数的视频中有一个雄辩的解释。关于作为向量场的矩阵的部分很好地解释了这一点:

矩阵指数的导数

早些时候我们使用了属性 \(\dfrac{d}{dt}e^{A t} = A e^{A t}\)。为什么此属性为真并不明显,但它是解锁所有这些的重要组成部分。

对此推导的一个很好的参考是在教科书《现代机器人学》中。可以在此处找到该书的免费副本。请参阅该书中的等式 (3.43)。

矩阵指数定义为

\(e^{A t} = I + A t + \frac{1}{2}(A t)^2 + \frac{1}{3!}(A t)^3 + ...\)

那么 \(\dfrac{d}{dt}e^{A t}\) 是什么?如果我们取矩阵指数的展开定义的每一项的导数,我们有

\(\dfrac{d}{dt}e^{A t} = 0 + A + A^2 t + \frac{1}{2} A^3 t^2 + ...\)

拉出 A,然后我们有

\(\dfrac{d}{dt}e^{A t} = A*(I + A t + \frac{1}{2} (A t)^2 + ...) = A e^{A t}\)。

值得注意的是,矩阵 \(A\) 可以放在左边或右边,并且对于任何方阵,以下情况始终成立

\(Ae^{A t} = e^{A t}A\)

如《现代机器人学》中的等式 (3.44) 中所述。

评论

在 Github Issues 上留下对此帖子的评论 这里