Eigen3 教程基础篇(二)

参考

Eigen3 主页,Eigen3 官网教程

矩阵的本质,通过多种矩阵的应用去感受矩阵本质

3Blue1Brown 的线性代数,用可视化方法来表现线性代数的特性,强推

如何理解复数和虚数,有动画方便理解复数的意义

相关文章

Eigen3 教程基础篇(一)

Eigen3 教程基础篇(三)

Eigen3 基础数据类型和操作

矩阵的核心是向量和线性代数,而线性代数的核心是向量加法和标量乘法。

Vector 向量类

向量类是列或行只有 1 的特殊矩阵,Vector 类是列向量,RowVector 类是行向量。

预定义好的向量模板

和矩阵类似,向量也有预定义好的模板:

VectorNt 格式:N 大小的列向量,例如 Vector2fMatrix<float, 2, 1>

RowVectorNt 格式:N 大小的行向量,例如 RowVector3dMatrix<double, 1, 3>

维数大小 N ∈ {2,3,4,X}。

数据类型 t ∈ {i,f,d,cf,cd}。分别是 int ,float,double,complex<float>(复数),complex<double>(复数)。

向量初始化和系数读写

void TestVector()
{
  setlocale(LC_ALL, "zh_CN.UTF-8"); // 支持 ros 打印中文

  Eigen::Vector3i v(3, 6, 9);
  ROS_INFO_STREAM("列向量3i v 构造初始化指定了系数和行数:" << std::endl << v);

  //! 固定向量类不支持 << 赋值,会导致段错误,但是动态向量类支持。
  Eigen::RowVectorXf u(5);
  u << 1.2, 2.3, 3.4, 4.5, 5.6;
  ROS_INFO_STREAM("动态行向量 u 默认初始化:" << std::endl << u);

  Eigen::VectorXd w(5);
  w.Random(5);
  ROS_INFO_STREAM("列向量 w 随机赋值:" << std::endl << w);
  ROS_INFO_STREAM("列向量[]访问 w[2]:" << std::endl << w[2]);
  w[2] = 12.34;
  ROS_INFO_STREAM("列向量[]修改 w[2]:" << std::endl << w[2]);

}

向量类的默认初始化并不会默认把系数设置为 0,支持 [ ] 访问修改系数。固定的向量类不支持 << 赋值,但是动态向量类支持。

向量运算

  • 向量加减运算和标量乘法运算

向量加法:

u= \left[\begin{matrix} u_x \\ u_y \\ \end{matrix}\right], v= \left[\begin{matrix} v_x \\ v_y \\ \end{matrix}\right], u+v= \left[\begin{matrix} u_x+v_x \\ u_y+v_y \\ \end{matrix}\right]

几何上看向量加法:u+v 表示把向量 v 起点移动到向量 u 终点,再从 u 起点指向 v 终点的向量 w。

e.g. 向量 u [2, 1],v [1, 3],u + v = w [3, 4]。

向量减法:

u= \left[\begin{matrix} u_x \\ u_y \\ \end{matrix}\right], v= \left[\begin{matrix} v_x \\ v_y \\ \end{matrix}\right], u-v= \left[\begin{matrix} u_x-v_x \\ u_y-v_y \\ \end{matrix}\right]

几何上看向量的标量乘法:u*k 表示把向量 u 的模缩放 k 倍,k < 0 表示向量方向取反。

e.g. 向量 u [2, 2],v = 1.8 * u,w = -0.8 * u。

void TestVectorOperate()
{
  Eigen::Vector3i u(3, 6, 9);
  Eigen::Vector3i v(2, 3, 3);
  ROS_INFO_STREAM("列向量3i u:" << std::endl << u);
  ROS_INFO_STREAM("列向量3i v:" << std::endl << v);
  ROS_INFO_STREAM("u+v=" << std::endl << u+v);

  Eigen::Vector3f fu(2.5, 0, -1.5);
  Eigen::Vector3f fv(5.1, 3.3, 1.3);
  ROS_INFO_STREAM("列向量3f fu:" << std::endl << u);
  ROS_INFO_STREAM("列向量3f fv:" << std::endl << v);
  ROS_INFO_STREAM("fu-fv=" << std::endl << fu-fv);

  Eigen::Vector3d du(0.7, -1.2, -3.5);
  ROS_INFO_STREAM("列向量3d du:" << std::endl << du);
  ROS_INFO_STREAM("列向量3d -3.3 * du=" << std::endl << -3.3*du);
}

  • 向量点乘(内积)运算

u= \left[\begin{matrix} u_x \\ u_y \\ \end{matrix}\right], v= \left[\begin{matrix} v_x \\ v_y \\ \end{matrix}\right], u·v=|u|*|v|*cos(\alpha)= u_x*v_x+u_y*v_y

向量点乘的几何意义:v 在 u 方向上投影与 u 的模的乘积,反映了两个向量的相似度,结果越大越相似。

u ⋅ v > 0,两向量方向基本同向,夹角在 0°~90° 之间;

u ⋅ v = 0,向量正交,互相垂直;

u ⋅ v < 0,两向量方向相反,夹角在 90°~180° 之间;

向量点乘(内积)有下面应用:

  1. 寻找一个向量投影到另一个向量的样子;

  2. 测量两个方向的接近程度;

  3. 确定另一个方向是向前还是向后;

void TestVectorDot()
{
  Eigen::Vector3f u0(0.0, 0.3, 0.5);
  Eigen::Vector3f v0(0.5, 0.0, 0.3);
  ROS_INFO_STREAM("u0:" << std::endl << u0);
  ROS_INFO_STREAM("v0:" << std::endl << v0);
  ROS_INFO_STREAM("u0 · v0 = " << u0.dot(v0));
  ROS_INFO_STREAM("v0 · u0 = " << v0.dot(u0));

  Eigen::Vector3f u1(1.2, 2.3, 3.4);
  Eigen::Vector3f v1(5.4, 6.5, 7.6);
  ROS_INFO_STREAM("u1:" << std::endl << u1);
  ROS_INFO_STREAM("v1:" << std::endl << v1);
  ROS_INFO_STREAM("u1 · v1 = " << u1.dot(v1));
}

  • 向量叉乘(外积)运算

u= \left[\begin{matrix} u_x \\ u_y \\ \end{matrix}\right], v= \left[\begin{matrix} v_x \\ v_y \\ \end{matrix}\right], u×v=|u|*|v|*sin(\alpha)*n_{uv}

几何意义:外积得到的向量由“右手法则”确定,模长为向量 u 和 v 构成的四边形面积。

向量叉乘(外积)有下面应用:

  1. 判断左右;

  2. 判断内外;

void TestVectorCross()
{
  Eigen::Vector3f u0(0.0, 0.3, 0.5);
  Eigen::Vector3f v0(0.5, 0.0, 0.3);
  ROS_INFO_STREAM("u0:" << std::endl << u0);
  ROS_INFO_STREAM("v0:" << std::endl << v0);
  ROS_INFO_STREAM("u0 x v0 = " << u0.cross(v0));
  ROS_INFO_STREAM("v0 x u1 = " << v0.cross(u0));

  Eigen::Vector3f u1(1.2, 2.3, 3.4);
  Eigen::Vector3f v1(5.4, 6.5, 7.6);
  ROS_INFO_STREAM("u1:" << std::endl << u1);
  ROS_INFO_STREAM("v1:" << std::endl << v1);
  ROS_INFO_STREAM("u1 x v1 = " << u1.cross(v1));
}

Array 数组类

数组类模板 Array,与 Matrix 类有一样的模板参数。

预定义好的模板

ArrayNt:N 大小的数组,例如 ArrayXfArray<float, Dynamic, 1>

ArrayNNd:N*N大小的数组,例如 Array33dArray<double, 3, 3>

数组初始化和系数读写

数组类的 () 运算符被重载作读写,[ ] 只能读写一维数组,运算符<< 运算符也可以给数组赋值。

void TestArray()
{
  Eigen::ArrayXf a0(3);
  a0.Random(3);
  ROS_INFO_STREAM("a0:" << a0);

  Eigen::Array33d a1;
  a1(2, 2) = 23.33;
  ROS_INFO_STREAM("a1(2, 2):" << a1(2, 2));

  a1 << 1.2, 2.3, 3.4,
        4.5, 5.6, 6.7,
        7.8, 8.9, 9.1;
  ROS_INFO_STREAM("a1:" << std::endl << a1);

  Eigen::Array4i a2;
  a2[2] = 123;
  ROS_INFO_STREAM("a2[2]=" << a2[2]);
}

数组运算

  • 加减法

如果两个数组大小相同,那么加减法运算是对应数组系数一一加减。

同时还支持数组加减一个标量,这样会让整个数组系数全部加减标量值。

  • 乘法

如果两个数组大小相同,数组的乘法运算是对应数组系数一一相乘。

数组类乘以标量是将数组的系数全部乘以标量值。

除法类似。

  • 其他系数运算

abs() 运算可以得到系数绝对值的数组,sqrt() 运算可以得到系数平方根,min() 能够得到两个大小相同数组中,相同位置最小系数组成的数组。

void TestArrayOperate()
{
  Eigen::Array22f a0;
  a0 << 1.2, -2.3,
        -3.4, 4.5;
  Eigen::Array22f a1;
  a1 << -6.5, 7.6,
        8.7, -9.8;
  ROS_INFO_STREAM("a0= " << std::endl << a0);
  ROS_INFO_STREAM("a1= " << std::endl << a1);
  ROS_INFO_STREAM("a0 + a1 = " << std::endl << a0+a1);
  ROS_INFO_STREAM("a1 + 5.5 = " << std::endl << a1+5.5);
  ROS_INFO_STREAM("a0 * a1 = " << std::endl << a0*a1);
  ROS_INFO_STREAM("a0 * 2.33 = " << std::endl << a0*2.33);
  ROS_INFO_STREAM("a0 / a1 = " << std::endl << a0/a1);
  ROS_INFO_STREAM("a0.abs() = " << std::endl << a0.abs());
  ROS_INFO_STREAM("a1.sqrt() = " << std::endl << a1.sqrt());
  ROS_INFO_STREAM("a0.min(a1) = " << std::endl << a0.min(a1));
}

数组类和矩阵类的转换

Matrix.array() 可以转换为数组类,Array.matrix() 可以转换为矩阵类。这两个方法都能做左值和右值!

大小相同的 Matrix 和 Array 可以相互赋值。

void TestArrayTransform()
{
  Eigen::Array22f a;
  a << 1.2, -2.3,
       -3.4, 4.5;
  
  Eigen::Matrix2f t;
  t << 0, -1,
       1, 0;

  Eigen::Matrix2f m;
  m = t*a.matrix();
  ROS_INFO_STREAM("数组 a = " << std::endl << a);
  ROS_INFO_STREAM("旋转矩阵 t = " << std::endl << t);
  ROS_INFO_STREAM("旋转后的矩阵 m = t * a.matrix() = " << std::endl << m);
  ROS_INFO_STREAM("m.array() 和 a 中最小系数组成的数组 = " << std::endl << m.array().min(a));
}

数组 a 对应的向量组是 u 和 w,旋转后的矩阵 m 对应的向量组是 v 和 s。可以结合上面矩阵乘法运算的几何意义想象下旋转过程。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值