zoukankan      html  css  js  c++  java
  • 高博SLAM基础课第四讲——非线性优化

    一、 矩阵微分问题

    0

    1-2:

    更多性质见https://blog.csdn.net/crazy_scott/article/details/80557814 和书

    二、

    //
    // Created by 高翔 on 2017/12/15.
    //
    #include <iostream>
    #include <opencv2/opencv.hpp>
    #include <Eigen/Core>
    #include <Eigen/Dense>
    #include <math.h>
    using namespace std;
    using namespace Eigen;
    
    int main(int argc, char **argv) {
        double ar = 1.0, br = 2.0, cr = 1.0;         // 真实参数值
        double ae = 2.0, be = -1.0, ce = 5.0;        // 估计参数值
        int N = 100;                                 // 数据点
        double w_sigma = 1;                   // 噪声Sigma值
        cv::RNG rng;                                 // OpenCV随机数产生器
    
        vector<double> x_data, y_data;      // 数据
        for (int i = 0; i < N; i++) {
            double x = i / 100.0;
            x_data.push_back(x);
            y_data.push_back(exp(ar * x * x + br * x + cr) + rng.gaussian(w_sigma));
        }
    
        // 开始Gauss-Newton迭代
        int iterations = 100;    // 迭代次数
        double cost = 0, lastCost = 0;  // 本次迭代的cost和上一次迭代的cost
    
        for (int iter = 0; iter < iterations; iter++) {
    
            Matrix3d H = Matrix3d::Zero();             // Hessian = J^T J in Gauss-Newton
            Vector3d b = Vector3d::Zero();             // bias
            cost = 0;
    
            for (int i = 0; i < N; i++) {
                double xi = x_data[i], yi = y_data[i];  // 第i个数据点
                // start your code here
                double ex=exp(ae*xi*xi+be*xi+ce);
                double error = 0;   // 第i个数据点的计算误差
                error = yi-ex; // 填写计算error的表达式
                Vector3d J; // 雅可比矩阵
                J[0] = -xi*xi*ex;  // de/da
                J[1] = -xi*ex;  // de/db
                J[2] = -ex;  // de/dc
    
                H += J * J.transpose(); // GN近似的H
                b += -error * J;
                // end your code here
    
                cost += error * error;
            }
    
            // 求解线性方程 Hx=b,建议用ldlt
            // start your code here
            Vector3d dx;
            dx=H.ldlt().solve(b);
    
            // end your code here
    
            if (isnan(dx[0])) {
                cout << "result is nan!" << endl;
                break;
            }
    
            if (iter > 0 && cost > lastCost) {
                // 误差增长了,说明近似的不够好
                cout << "cost: " << cost << ", last cost: " << lastCost << endl;
                break;
            }
    
            // 更新abc估计值
            ae += dx[0];
            be += dx[1];
            ce += dx[2];
    
            lastCost = cost;
    
            cout<<"iterate: "<<iter<<endl;
            cout<<"ae="<<ae<<" be="<<be<<" ce="<<ce<<endl;
            cout<<"cost= "<<cost<<endl;
        // end your code here
    
            cout << "total cost: " << cost << endl;
        }
    
        cout << "estimated abc = " << ae << ", " << be << ", " << ce << endl;
        return 0;
    }

    代码如上。

    自写部分:

     double ex=exp(ae*xi*xi+be*xi+ce);
     double error = 0;   // 第i个数据点的计算误差
     error = yi-ex; // 填写计算error的表达式
     Vector3d J; // 雅可比矩阵
     J[0] = -xi*xi*ex;  // de/da
     J[1] = -xi*ex;  // de/db
     J[2] = -ex;  // de/dc
    
     H += J * J.transpose(); // GN近似的H
     b += -error * J;
    然后解个方程

    自己开始推了一大堆后来发现按照提示写很简单就完了。

    需要注意的地方:

      每一个点引入一个error,在内层循环中只计算了单个error的J矩阵,并且不考虑外面的平方。内层就是f(x),所以形式都很简单,然后在外层把算出来的H和b加起来最后统一求解,这里的加法原理是讲得通的。

      一开始我解得欲仙欲死就是因为想到这个函数是一百个点误差平方加起来,之后对这个大函数求一次J和H然后解方程直接得到迭代值,最后出了问题。

      其实这么做理论上也是对的,一会再试试。(PS:没有试出来)

    运行结果如下:

  • 相关阅读:
    josn类库引用
    WPF圆角按钮
    C#实现某一属性值变化时触发事件 Form1_changeEvent是对应的事件
    C#winform生成安装包
    特性
    反射可以动态调用对象(一般是类)的名称,属性,方法等。具体见下。重要
    原子操作 和Inerlocked 常用于多线程同步
    spingboot 配置多个数据源报错
    Address already in use: JVM_Bind 端口被占用的几个解决办法
    数据库问题(一)
  • 原文地址:https://www.cnblogs.com/CaptainLL/p/10831072.html
Copyright © 2011-2022 走看看