3. 李群与李代数:李群基础、指数映射与对数映射、扰动模型、Sophus库使用

各位同学,欢迎来到第三章。这一章我们聊点硬核的——李群与李代数。

说实话,我刚入行那会儿,看到「李群」这两个字,第一反应是「这玩意儿跟我有啥关系?」。后来在做一个VIO项目时,优化位姿总是跑飞,我才意识到:没有李代数,你连个像样的姿态优化都做不了。嗯,今天我们就把它彻底讲明白。

3.1 为什么需要李群与李代数?

先问个问题:在SLAM里,我们怎么表示相机的位姿?

答案通常是旋转矩阵 R 和平移向量 t。旋转矩阵属于特殊正交群 SO(3),变换矩阵属于特殊欧氏群 SE(3)。

但问题来了——

  • 旋转矩阵是正交的,有9个参数,但自由度只有3。你直接优化9个参数,约束条件很难满足。
  • 更麻烦的是,你没法直接对旋转矩阵做加法。R + ΔR 大概率不再是旋转矩阵。

说白了,SO(3) 和 SE(3) 是流形,不是向量空间。你不能用常规的微积分去处理它们。

李代数就是来解决这个问题的。它把流形上的优化问题,转化成了向量空间里的优化问题。你想想看,这多方便。

核心思想:李群是流形,李代数是它的切空间。我们在切空间里做优化,再映射回流形上。

3.2 李群基础

先给个定义。李群是一种连续群,它既是群又是光滑流形。常见的李群有:

李群 含义 维度
SO(3) 三维旋转群 3
SE(3) 三维刚体变换群 6
SO(2) 二维旋转群 1
SE(2) 二维刚体变换群 3

SO(3) 的定义很简单:

SO(3) = { R ∈ ℝ³ˣ³ | RRᵀ = I, det(R) = 1 }

SE(3) 则是:

SE(3) = { T = [R t; 0 1] | R ∈ SO(3), t ∈ ℝ³ }

我个人习惯把 SE(3) 想象成一个「带旋转的平移」。你想想看,一个刚体在空间中的运动,不就是先转再移吗?

3.3 指数映射与对数映射

这是李群和李代数之间的桥梁。说白了,指数映射把李代数(切空间)映射到李群(流形),对数映射反过来。

3.3.1 SO(3) 的指数映射

对于 SO(3),它的李代数是 so(3),由三维向量 φ 的反对称矩阵组成:

so(3) = { Φ = φ^ = [0 -φ₃ φ₂; φ₃ 0 -φ₁; -φ₂ φ₁ 0] | φ ∈ ℝ³ }

指数映射公式:

R = exp(φ^) = I + sin(θ)/θ · φ^ + (1-cos(θ))/θ² · (φ^)²

其中 θ = ||φ||。

这个公式是不是很眼熟?对,就是罗德里格斯公式。所以李代数 so(3) 的物理意义就是旋转向量。

我的经验:我在做IMU预积分时,经常用这个公式把角速度增量转换成旋转矩阵。注意 θ 很小的时候要用泰勒展开,避免数值问题。

3.3.2 SE(3) 的指数映射

SE(3) 的李代数是 se(3),由六维向量 ξ = [ρ; φ] 组成。指数映射为:

T = exp(ξ^) = [R t; 0 1]

其中 R 由 φ 通过 SO(3) 的指数映射得到,t 由 ρ 和 φ 共同决定。

对数映射就是反过来,从 T 求 ξ。这个在代码里很常用,比如从变换矩阵里提取旋转向量。

3.4 扰动模型

终于到了最实用的部分。在SLAM后端优化中,我们需要对位姿求导。但直接对 R 求导不行,怎么办?

两种方式:

  1. 李代数求导:对 R 对应的李代数 φ 求导。
  2. 扰动模型:给 R 左乘或右乘一个小扰动,对扰动求导。

我个人更推荐扰动模型。为什么?因为它更简洁,而且不涉及复杂的指数映射求导。

3.4.1 SO(3) 的左扰动模型

假设我们有一个旋转矩阵 R,给它左乘一个小扰动 ΔR = exp(δφ^),然后对 δφ 求导:

∂(Rp) / ∂δφ = -R·p^

这个结果非常漂亮。你想想看,一个复杂的旋转求导,最后就变成了一个简单的反对称矩阵乘法。

注意:左扰动和右扰动结果不一样。左扰动对应世界坐标系下的扰动,右扰动对应相机坐标系下的扰动。我在项目中吃过这个亏,大家一定要分清。

3.4.2 SE(3) 的扰动模型

对于 SE(3),左扰动模型给出:

∂(Tp) / ∂δξ = [I₃, -p^; 0, 0]

这个雅可比矩阵在BA优化和VIO中频繁出现。我建议你把它背下来,或者至少知道怎么推导。

3.5 Sophus库使用

理论讲完了,我们看看怎么用代码实现。Sophus 是 Strasdat 写的李代数库,现在已经是 Eigen 的官方模块了。

3.5.1 安装与包含

#include <sophus/se3.hpp>
#include <sophus/so3.hpp>

如果你用 CMake,记得链接:

find_package(Sophus REQUIRED)
target_link_libraries(your_target Sophus::Sophus)

3.5.2 基本操作

// 创建 SO3 从旋转矩阵
Eigen::Matrix3d R = Eigen::AngleAxisd(M_PI/4, Eigen::Vector3d::UnitZ()).toRotationMatrix();
Sophus::SO3d SO3_R(R);

// 创建 SO3 从旋转向量
Sophus::SO3d SO3_v(0, 0, M_PI/4);

// 指数映射:李代数 -> 李群
Eigen::Vector3d phi(0.1, 0.2, 0.3);
Sophus::SO3d SO3_exp = Sophus::SO3d::exp(phi);

// 对数映射:李群 -> 李代数
Eigen::Vector3d phi_log = SO3_exp.log();

// 创建 SE3
Sophus::SE3d SE3_Rt(R, Eigen::Vector3d(1, 2, 3));

// 扰动模型示例
Eigen::Vector3d p(1, 0, 0);
Eigen::Vector3d delta_phi(0.01, 0, 0);
Sophus::SO3d R_new = SO3_R * Sophus::SO3d::exp(delta_phi);
Eigen::Vector3d p_new = R_new * p;

避坑指南:我曾经在优化时忘记对扰动取对数,直接用了增量加法。结果迭代了几步就发散。记住:李代数上的增量必须通过指数映射回到李群。

3.6 知识体系总览

下面这张图总结了本章的核心逻辑。我建议你多看几遍,把整个脉络理清楚。

李群与李代数知识体系 李群 SO(3) / SE(3) 流形,不可直接求导 旋转矩阵 / 变换矩阵 李代数 so(3) / se(3) 向量空间,可求导 旋转向量 / 六维向量 指数映射 对数映射 扰动模型 左扰动 / 右扰动 在切空间求导,映射回流形 Sophus 库 C++ 实现,Eigen 集成 SLAM优化 BA / 位姿图 VIO融合 IMU预积分

3.7 本章小结

这一章我们讲了:

  • 李群 SO(3) 和 SE(3) 是什么,为什么需要它们
  • 指数映射和对数映射怎么用
  • 扰动模型如何优雅地解决求导问题
  • Sophus 库的基本用法

说实话,李群李代数这东西,光看理论容易晕。我建议你打开编辑器,把上面的代码跑一遍。亲手试试指数映射、对数映射、扰动求导,比看十遍书都管用。

嗯,下一章我们会把这些知识用到实际的位姿图优化中。到时候你就知道,今天学的这些,全是真功夫。


专注资料整理