SLAM从入门到精通(基础数学)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        不可否认,slam中的有一部分内容来自于数学。但是,我们在学习使用的过程中,也不用纠结于整个数学的推导过程,能正确使用数学结论也是可以的。有能力的同学,按照书本提示的方法,自己推导一下,也无可厚非。实在觉得麻烦,可以暂时先放下,或者用的比较熟练了,再来查看相关的推导原理也可以。和那些复杂的高维矩阵运算、优化算法相比,有一些基本的数学和规则,可能大家在日常处理中遇到的机会更大,这里不妨总结一下。

1、浮点数

        过去我们自己编写web前后端、或者写os、db的时候,遇到浮点数的机会并不多。即使遇到,也是简单的加减法。但是slam学习中,大量的操作都是浮点数。既然是浮点数,那么就离不开比较、除法、滤波、平方根这些计算。

1.1 数值比较

        既然做浮点运算,那么数值比较肯定是少不了的。这个时候,大家一定要理解,浮点数之间是没有绝对相等的。要比较他们是否相等,只要判断是不是在一个范围内即可,

if(fabs(f1 - f2) < 1e-6)
{
    std::cout << "equal" << std::endl;
}
else
{
    std::cout << "not equal" << std::endl;
}

1.2 除法运算

        用浮点做除法运算,本身是一件很危险的事情。因为f1/f2的时候,如果f2很小,那么f1/f2就会是非常大的一个数值。这样的话,这个结果本身其实是没有任何意义的。所以,即使要做除法运算,一定、一定要约束一下f2的数值范围。

1.3 数值滤波

        SLAM中用到的数据大部分都是从传感器采集过来的。既然是采集的物理数据,就会不可避免地引入噪声。所以这个时候,就要对浮点数进行降噪处理,常用的方法一般有,

1)取平均值;

2)去掉最大值、最小值,取平均值;

3)v_new = v_old * 0.95 + v_capture * (1 - 0.95);

4)连续满足某个条件之后,才开始采样等等。

1.4 平方根

        SLAM中的欧氏距离真的很好用。有的时候,最简单的方法往往就是最鲁棒的方法。所以distance = sqrt (pow(x, 2) + pow(y, 2))这样的计算方法一定要多看多用。

2、角度的计算

        在一个平面上面,假设有一个x轴和一个y轴,那么任何的坐标p都会被拆解为(x0,y0)。其中它和x轴的角度称之为theta,那么就会有了下面一些列的计算,

2.1 点p到原点的距离

r = sqrt (pow(x, 2) + pow(y, 2))

2.2 对应的角度theta该如何计算

theta = atan(y0 / x0)

2.3 角度和弧度的对应关系

rad = (angle * 2 * pi) / 360

2.4 sin、cos、tan

        由于时间的关系,大家对于sin、cos、tan的周期性可能没有那么熟悉了,这里为了方便大家回忆。我们分别贴上sin&cos的周期图、tan的周期图。首先是sin&cos的周期图,

SLAM从入门到精通(基础数学)_第1张图片

        其次是tan的周期图,

SLAM从入门到精通(基础数学)_第2张图片

        仔细观察下,sin的周期是2*pi,其中(-pi,0)为负,(0,pi)为正。cos的周期也是2*pi,其中(-pi/2,pi/2)为正,(-pi,-pi/2)&(pi/2,pi)为负。tan的周期是pi,其中(-pi/2,0)为负,(0,pi/2)为正。

2.5 一个有意思的旋转

        之前我们谈到,假设有一个点,他处在(x0,y0),这个时候,如果逆时针旋转alpha角度,新的坐标是多少。要注意,这里面其实是有一个不变的量,那就是距离distance,也可以记着为r。按照道理,新的坐标应该是,

x1 = r * cos(theta + alpha)
y1 = r * sin(theta + alpha)

        如果仅仅是这样,那么数值并不太容易求出来,所以这里需要进一步分解一下,

x1 = r * cos(alpha + theta)
   = r * (cos(alpha) * cos(theta) - sin(alpha) * sin(theta))
   = x * cos(alpha) - y * sin(alpha)

y1 = r * sin(alpha + theta)
   = r * (sin(alpha) * cos(theta) + cos(alpha) * sin(theta))
   = x * sin(alpha) + y * cos(alpha)

        如果换成矩阵,其实写起来就很容易了,

[x1, y1] = [cos(alpha), -sin(alpha); sin(alpha), cos(alpha)] * [x, y]

3、矩阵的计算

        大学数学里面除了高等代数,也就是微分和积分之外,最重要的两门数学课就是线性代数和概率。而线性代数中最重要的计算就是矩阵。例2中提到的旋转,大家就可以转变成矩阵乘法的形式来进行处理,就是这样的,

pos_new = matrix * pos_old;

        有些同学也许忘记了矩阵的相关内容,没关系。其实大家只要会使用eigen这个库就好了。这个库是一个模板库,本身没有.a或者.so文件,直接使用即可。

sudo apt-get install libeigen3-dev

4、概率的计算

        概率这部分,大部分都是浮点的相关计算。中间以统计、加减法为主,本身困难不大。需要注意的地方就两个,一个是随机数的生成;一个就是高斯分布的生成。两个都很重要。

        如果是随机数的生成,一般是先给一个种子,然后生成随机数,

#include 
#include 
#include 
int main(int argc, char *argv[])
{
    int i;
    srand((int) time(0));
    for(i=0;i< 10;i++)
    {
        printf(" %d ", rand());
    }
    printf("n");
    return 0;
}

        另外一个就是高斯分布的生成,两个参数,一个是平均值,一个是方差,

#include 
#include 
#include 
 
int main(int argc, char* argv[]) 
{
    unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
  
    std::default_random_engine generator(seed);
    std::normal_distribution distribution(0.0, 1.0);
 
    for (int i = 0; i < 10; ++i)
    {
        std::cout << distribution(generator) << std::endl;
    }
    
    return 0;
}

你可能感兴趣的:(SLAM从入门到精通,算法)