Eigen
庫
矩陣運算是一種非常重要的運算方式,在Matlab
中,矩陣運算可以輕松的實現,但在C++
這種偏底層的語言中,若不借助第三方庫,矩陣運算需要我們進行較為復雜的代碼設計。Eigen
庫是一個用于線性運算的C++
模板庫,它支持矩陣運算、矢量運算、數值分析以及相關的算法,安裝Eigen
庫可以大大提高我們的開發效率。
安裝與配置Eigen
庫
安裝
在ubuntu系統中,安裝Eigen
庫較為簡單,只需在命令行中運行
sudo apt-get install libeigen3-dev
之后,我們可以在系統中找到/usr/include/eigen3
,這證明我們安裝成功
在Vscode
配置
使用Vscode
可以很方便地配置Eigen
庫的編譯,在c_cpp_properties.json
的includepath
中添加"/usr/include/**"
即可,如果已經有了那就無需再添加。
{"configurations": [{"browse": {"databaseFilename": "${default}","limitSymbolsToIncludedHeaders": false},"includePath": ["/opt/ros/noetic/include/**","/usr/include/**","/home/aliang/vehicle_sim/devel/include/**"],"name": "ROS","intelliSenseMode": "gcc-x64","compilerPath": "/usr/bin/gcc","cStandard": "gnu11","cppStandard": "c++17"}],"version": 4
}
與ROS
中配置
在ROS
中,我們還需在功能包的CMakeList
中添加:
include_directories("/usr/include/eigen3")
這樣我們就可以在程序中用這種方法引入包:
#include <Eigen/Eigen>#include <Eigen/Dense>#include <Eigen/Geometry>#include <Eigen/Eigenvalues>
否則,需要使用這種方法引入包:
#include <eigen3/Eigen/Eigen>#include <eigen3/Eigen/Dense>#include <eigen3/Eigen/Geometry>#include <eigen3/Eigen/Eigenvalues>
驗證是否可以正常使用
在ROS
的功能包下新建一個cpp
文件
#include <Eigen/Eigen>
#include <Eigen/Dense>
#include <Eigen/Geometry>
#include <Eigen/Eigenvalues>int main(int argc, char *argv[]){// here is an arbitrary normal vector
// initialized to (1,2,3) upon instantiationEigen::Vector3d normal_vec(1,2,3); return 0;
}
在CMakeList
中加入
add_executable(vec_compute src/compute.cpp)
target_link_libraries(vec_compute ${catkin_LIBRARIES})
編譯通過,證明可以正常使用
基于Eigen
庫的RBF徑向基核函數的二維曲線擬合
RBF徑向基核函數的二維曲線擬合
RBF徑向基核函數
的二維曲線擬合的核心在于,根據 N N N個擬合點求解出 N N N個徑向基核函數( N N N個徑向基核函數分別對應 N N N個擬合點)的加權數。對于目標二維曲線 F ( x , y ) = 1 F(x,y)=1 F(x,y)=1即優化下列方程:
∑ k = 1 N w k ? f ( r ) = 1 \sum_{k=1}^N w_k*f(r) = 1 k=1∑N?wk??f(r)=1
展開為向量形式:
( f ( ∣ ∣ q ? q 1 ∣ ∣ ) f ( ∣ ∣ q ? q 2 ∣ ∣ ) ? f ( ∣ ∣ q ? q N ∣ ∣ ) ) ? ( w 1 w 2 ? w N ) = 1 \begin{pmatrix} f(||q-q_1||) & f(||q-q_2||) & \cdots & f(||q-q_N||) \end{pmatrix}* \begin{pmatrix} w_1\\ w_2\\ \vdots\\ w_N \end{pmatrix}=1 (f(∣∣q?q1?∣∣)?f(∣∣q?q2?∣∣)???f(∣∣q?qN?∣∣)?)? ?w1?w2??wN?? ?=1
其中 q N q_N qN?表示被擬合的 N N N個點,由于每個被擬合點都滿足該公式,替換掉 q q q,可以再次展開為:
( f ( ∣ ∣ q 1 ? q 1 ∣ ∣ ) f ( ∣ ∣ q 1 ? q 2 ∣ ∣ ) ? f ( ∣ ∣ q 1 ? q N ∣ ∣ ) f ( ∣ ∣ q 2 ? q 1 ∣ ∣ ) f ( ∣ ∣ q 2 ? q 2 ∣ ∣ ) ? f ( ∣ ∣ q 2 ? q N ∣ ∣ ) ? ? ? ? f ( ∣ ∣ q N ? q 1 ∣ ∣ ) f ( ∣ ∣ q N ? q 2 ∣ ∣ ) ? f ( ∣ ∣ q N ? q N ∣ ∣ ) ) ? ( w 1 w 2 ? w N ) = 1 \begin{pmatrix} f(||q_1-q_1||) & f(||q_1-q_2||) & \cdots & f(||q_1-q_N||)\\ f(||q_2-q_1||) & f(||q_2-q_2||) & \cdots & f(||q_2-q_N||)\\ \vdots & \vdots & \ddots & \vdots\\ f(||q_N-q_1||) & f(||q_N-q_2||) & \cdots & f(||q_N-q_N||)\\ \end{pmatrix}* \begin{pmatrix} w_1\\ w_2\\ \vdots\\ w_N \end{pmatrix}=1 ?f(∣∣q1??q1?∣∣)f(∣∣q2??q1?∣∣)?f(∣∣qN??q1?∣∣)?f(∣∣q1??q2?∣∣)f(∣∣q2??q2?∣∣)?f(∣∣qN??q2?∣∣)??????f(∣∣q1??qN?∣∣)f(∣∣q2??qN?∣∣)?f(∣∣qN??qN?∣∣)? ?? ?w1?w2??wN?? ?=1
左邊的矩陣可以看為一個Gram相關矩陣形式,則可以求出我們想要的 w ? \vec{w} w:
w ? = G r a m M a t r i x N × N ? 1 ? 1 N × 1 \vec{w} = GramMatrix^{-1}_{N \times N}*1_{N \times 1} w=GramMatrixN×N?1??1N×1?
選取徑向基核函數為 f ( r ) = r 2 l n ( r + 1 ) f(r)=r^2ln(r+1) f(r)=r2ln(r+1)
基于Eigen
庫的實現
#include <Eigen/Eigen>
#include <Eigen/Dense>
#include <Eigen/Geometry>
#include <Eigen/Eigenvalues>
#include <iostream>
#include <cmath>int main(int argc, char *argv[]){int num = 6;Eigen::MatrixXd p_x(1, num);Eigen::MatrixXd dis_x(num, num);Eigen::MatrixXd p_y(1, num);Eigen::MatrixXd dis_y(num, num);Eigen::MatrixXd dis_sqr(num, num);Eigen::MatrixXd dis_r(num, num);Eigen::MatrixXd w(num, 1);p_x << 1.5, 1.5, -0.75, -3, -0.75, 1.5;p_y << 0, 2.6, 1.3, 0, -1.3, -2.6;Eigen::MatrixXd mat_x = p_x.replicate(num, 1); // 該函數將p_x作為一個矩陣元素,填充出n*m的矩陣Eigen::MatrixXd mat_y = p_y.replicate(num, 1);mat_x = mat_x - p_x.transpose().replicate(1, num);mat_y = mat_y - p_y.transpose().replicate(1, num);dis_x = mat_x.cwiseProduct(mat_x); //對應位置相乘dis_y = mat_y.cwiseProduct(mat_y);dis_sqr = dis_x + dis_y;dis_r = dis_sqr.unaryExpr([](double x){return std::sqrt(x);});std::cout << "矩陣:\n" << dis_r << std::endl;dis_r = dis_r.unaryExpr([](double x){return x*x*log(x+1);});dis_r = dis_r.inverse();w = dis_r.rowwise().sum();std::cout << "矩陣:\n" << w << std::endl;return 0;
}
與Matlab
計算結果相同
w=-0.04752690.0351389-0.04752050.0351453-0.04752050.0351389