slam面试题最小二成问题,wifi热点问题

1. 考虑线性方程组Ax=b,其中ARm×n且rank(A)=min{m,n}.

1)当m>n, 推导求解最小二乘解.xlsq=min||Ax-b||2需要写出细致的每一步的推导过程

推导步骤:

2. 假设有三个WIFI热点,位置分别在(x1,y1), (x2,y2), (x3,y3), 移动端测量到每一个热点的距离L1,L2和L3,要求解移动端的位置. 

需要写一个C/C++/JAVA的程序,(基于第一题的结论自己实现求解过程,可以调用基础的数学矩阵库,但是不允许调用Eigen等优化库),最终的程序需要可以运行,输入3个热点坐标和测量距离,可以得到正确的移动端位置。

下面是优化的问题解法。 其实还有更简单的解法,因为只有三个wifi热点,列三个方程,1,2,3,消掉其中的二次项,有点像高中的几何题,但这种方法只适合有三个wifi热点的情况。优化问题的解法能适合有更多wifi观测的情况。

#include <iostream>

#include <vector>

#include <opencv2/opencv.hpp>

using namespace std;

/**

 * @brief 计算误差向量

 * @param wifi_positions wifi的位置

 * @param term_loc 终端的位置

 * @param distances 观测的终端到wifi的位置

 * @param error_vector 存储误差向量(输出参数)

 * @param error_mean 存储平均误差用于迭代结束条件判断(输出参数)

 */

void CalErrorVector(const vector<cv::Point2f>& wifi_positions, const cv::Point2f& term_loc, const vector<float>& distances, cv::Mat& error_vector, float& error_mean)

{

    if (wifi_positions.size() != error_vector.rows||wifi_positions.size()!=distances.size()||error_vector.rows!=distances.size())

    {

        std::cout << "Please chack the dims of data" << std::endl;

        return;

    }

    cv::Point2f diff;

    error_mean = 0;

    for (int i = 0; i < wifi_positions.size(); i++)

    {

        diff = term_loc - wifi_positions[i];

        float e = diff.x * diff.x + diff.y * diff.y - distances[i] * distances[i];

        error_vector.at<float>(i, 0) = e;

        error_mean += std::fabs(e);

    }

    error_mean /= int(wifi_positions.size());

}

/**

 * @brief 计算雅可比矩阵

 * @param wifi_positions wifi的位置

 * @param term_loc 终端的位置

 * @param jac_matrix 存储雅可比矩阵(输出参数)

 */

void CalJacMatrix(const vector<cv::Point2f>& wifi_positions, const cv::Point2f& term_loc, cv::Mat& jac_matrix)

{

    if (wifi_positions.size() != jac_matrix.rows)

    {

        std::cout << "Please chack the dims of data" << std::endl;

        return;

    }

   

    cv::Point2f diff;

    for (int i = 0; i < wifi_positions.size(); i++)

    {

        diff = term_loc - wifi_positions[i];

        jac_matrix.at<float>(i, 0) = 2*diff.x;

        jac_matrix.at<float>(i, 1) = 2*diff.y;

    }

}


 

/**

 * @brief 优化函数

 * @param wifi_positions wifi的位置

 * @param distances 观测的终端到wifi的位置

 * @param term_loc 终端的位置(输出参数)

 */

void OptimizePosition(const vector<cv::Point2f>& wifi_potisions, const vector<float>& distances, cv::Point2f& term_loc)

{

    if (wifi_potisions.size() < 3)

    {

        std::cout << " The number of points should be greater than 3" << std::endl;

        return;

    }

    cv::Point2f init_loc(0.0, 0.0);

    for (int i = 0; i < wifi_potisions.size(); i++)

    {

        init_loc += wifi_potisions[i];

    }

    init_loc /= int(wifi_potisions.size());

    //定义误差向量

    cv::Mat error_vector;

    float error_mean;

    error_vector.create(wifi_potisions.size(), 1, CV_32F);

    CalErrorVector(wifi_potisions, init_loc, distances, error_vector, error_mean);

    //定义雅可比矩阵

    cv::Mat jac_mat;

    jac_mat.create(wifi_potisions.size(), 2, CV_32F);


 

    cv::Mat update;

    //当平均误差>0.0001执行while循环

    while (std::fabs(error_mean) > 0.0001)

    {

       

        //计算雅可比矩阵

        CalJacMatrix(wifi_potisions, init_loc, jac_mat);

        cv::Mat jac_mat_t;

        cv::transpose(jac_mat, jac_mat_t);

        cv::Mat H = jac_mat_t * jac_mat;

        cv::Mat H_inv;

        cv::invert(H, H_inv);

        //std::cout << H * H_inv << std::endl;

        cv::Mat g = - jac_mat_t * error_vector;

        update = H_inv * g;

        init_loc.x += update.at<float>(0, 0);

        init_loc.y += update.at<float>(1, 0);

        CalErrorVector(wifi_potisions, init_loc, distances, error_vector, error_mean);

        //std::cout << "loc: " << init_loc << std::endl;

    }

    term_loc = init_loc;

}



 

int main()

{

    //构造测试数据

    vector<cv::Point2f> wifi_positions = { cv::Point2f(1.0,0),cv::Point2f(0.0,1.0),cv::Point2f(1.0,1.0) };

    vector<float> distances = { 1.0,1.0,1.41421 };

    cv::Point2f term_loc_gt(0.0, 0.0), term_loc(0.0, 0.0);

    OptimizePosition(wifi_positions, distances, term_loc);

    //结果检验,如果diff的x和y成员接近0,则说明上面的代码是OK的

    auto diff = term_loc_gt - term_loc;

    std::cout << "diff: " << diff << std::endl;

    return 0;

}

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值