导言
本章续接我的前一篇总结Matlab转C之混合编程真香,在上一篇文章中,提到了matlab在矩阵运算和自己的数学函数在运算速度上无与伦比的优势,这个看法原本对我写代码的作用域范围可能仅仅在如果我需要一个数学函数,那我毫不动摇的选择封装一个函数去调用matlab的数学函数,而矩阵运算说实话在我上一个翻译的功能上体现的还不是很明显,因而我仅仅调用了matlab的插值滤波。
但现在,同志们,乡亲们,矩阵运算是真的快啊,本次我翻译的功能中,一个matlab里O(1)的循环,内部存在着较多的插值和矩阵运算,在matlab中的一句话,无论是赋值还是运算在C中往往代表着一个循环,又因为可观的数据量,即便我充分考虑了数据循环长度,尽量减少循环操作来优化代码,在这样的情况下matlab最终的处理速度依旧是C的70倍左右,我分析了一波,如果还想继续优化下去和matlab的速度硬刚,可能就需要从设计更合适的数据类型或者干脆来个类来进行矩阵运算的仿写来靠近matlab,依靠C的执行速度来取得胜利。
反正爷彻底被折服了,跪拜了,今后但凡遇见matlab转C,我直接循环体外是C循环体内是调matlab,直接粗暴对待。
至于如何调用matlab来实现混合编程,可以看我这里的例子做一下参考,有些数据类型啥的根据自己的类型修改一下:
调用Matlab的filter()实现复数滤波
这里我对工作中matlab的程序需要实现的功能进行讲解:
/*
很需要注意的是,当我们把数据给matlab的引擎时,无论是指向数据的指针还是数据本身,都最好优先改为double类型,
否则数据会出现错误(试出来的),这可能和matlab默认是double类型有关,但更可能是因为将数据转为代码将matlab
数据格式时将我们的其他类型的数据放到了基础类型为double的特殊类型数据中
*/
#include <math.h>
#include <vector>
#include <iostream>
using namespace std;
添加matlab引擎库的头文件-----需要自己在项目属性里配置一些东西哦
//#include "resample_qy.h"
#include "engine.h"
导入相关lib库
#pragma comment(lib, "libeng.lib")
#pragma comment(lib, "libmx.lib")
#pragma comment(lib, "libmat.lib")
//#pragma comment(lib, "resample_qy.lib")
const struct comInt
{
vector<INT16> real;
vector<INT16> imag;
double time;
};
const struct comDouble
{
vector<double> real;
vector<double> imag;
double time;
};
/*
调用的思路很简单:
1.确定调用matlab的程序语句中会出现哪些变量
2.以指针的方式创建动态数组存储我们的数据
3.将数据转存到matlab数据格式的变量中(详见代码)
4.在引擎里创建变量并赋值
5.将要运行的语句放进引擎
6.从引擎中拿到指向matlab运行结果的指针
7.赋值给C++的变量即拿到了结果
*/
comDouble Matlabfilter(vector<double> lbf, double a, comDouble x_d, Engine *ep)
{
/*
注意:需要在项目属性里配置一些东西哦,详细自己查博客
参数介绍:
lbf: 滤波器系数
a: 分母系数(这里默认是1,因为我工作需要的就是标量1)
x_d: 复数
x_d.real: 复数实部
x_d.imag: 复数虚部
temp1_iq: 复数滤波结果
temp1_iq.real: 复数实部滤波结果
temp1_iq.imag: 复数虚部滤波结果
*/
comDouble temp1_iq;
mxArray *Lbf = NULL,
*Real = NULL,
*Imag = NULL,
*temp1_i = NULL,
*temp1_q = NULL;
double *newLbf = new double[lbf.size()];
double *newReal = new double[x_d.real.size()];
double *newImag = new double[x_d.imag.size()];
for (int j = 0; j < lbf.size(); j++) {
newLbf[j] = lbf[j];
}
for (int j = 0; j < x_d.real.size(); j++) {
newReal[j] = x_d.real[j];
newImag[j] = x_d.imag[j];
}
Lbf = mxCreateDoubleMatrix(1, lbf.size(), mxREAL);
Real = mxCreateDoubleMatrix(1, x_d.real.size(), mxREAL);
Imag = mxCreateDoubleMatrix(1, x_d.real.size(), mxREAL);
memcpy((void *)mxGetPr(Lbf), (void *)newLbf, lbf.size() * sizeof(lbf[0]));
memcpy((void *)mxGetPr(Real), (void *)newReal, x_d.real.size() * sizeof(newReal[0]));
memcpy((void *)mxGetPr(Imag), (void *)newImag, x_d.real.size() * sizeof(newImag[0]));
engPutVariable(ep, "Lbf", Lbf); // put data to engine
engPutVariable(ep, "Real", Real);
engPutVariable(ep, "Imag", Imag);
// execute matlab operations
engEvalString(ep, "temp1_i=filter(Lbf,1,Real);");
engEvalString(ep, "temp1_q=filter(Lbf,1,Imag);");
temp1_i = engGetVariable(ep, "temp1_i");
temp1_q = engGetVariable(ep, "temp1_q");
auto firstAddress = mxGetPr(temp1_i);
auto secondAddress = mxGetPr(temp1_q);
for (int j = 0; j < x_d.real.size(); j++) {
temp1_iq.real.push_back(*firstAddress);
temp1_iq.imag.push_back(*secondAddress);
firstAddress++;
secondAddress++;
}
mxDestroyArray(Lbf);
mxDestroyArray(Real);
mxDestroyArray(Imag);
mxDestroyArray(temp1_i);
mxDestroyArray(temp1_q);
delete newLbf;
delete newReal;
delete newImag;
return temp1_iq;
}
Engine *ep;
if (!(ep = engOpen("\0")))
{
fprintf(stderr, "\nCan't start MATLAB engine\n");
return;
}
//这句可以让matlab的框隐藏
engSetVisible(ep, false);
comDouble temp1_iq;
//滤波计算 lbf是滤波器系数,1是分子系数,x_d是待处理数据,ep是matlab引擎
temp1_iq = Matlabfilter(lbf, 1, x_d, ep);
C调用matlab的interp1()实现复数插值
comDouble Matlabinterp1(double Ti[], int len_Ti, double To[], int len_To, INT16 I_Id[], INT16 Q_Id[], Engine *ep)
{
/*
这里我是分别进行了复数数据实部虚部的插值
*/
comDouble OUTD;
mxArray *ti = NULL,
*to = NULL,
*I_id = NULL,
*Q_id = NULL,
*outDi = NULL,
*outDq = NULL;
double *id = new double[len_Ti];
double *qd = new double[len_Ti];
for (int i = 0; i < len_Ti; i++)
{
id[i] = I_Id[i];
qd[i] = Q_Id[i];
}
ti = mxCreateDoubleMatrix(1, len_Ti, mxREAL);
to = mxCreateDoubleMatrix(1, len_To, mxREAL);
I_id = mxCreateDoubleMatrix(1, len_Ti, mxREAL);
Q_id = mxCreateDoubleMatrix(1, len_Ti, mxREAL);
memcpy((void *)mxGetPr(ti), (void *)Ti, len_Ti * sizeof(double));
memcpy((void *)mxGetPr(to), (void *)To, len_To * sizeof(double));
memcpy((void *)mxGetPr(I_id), (void *)id, len_Ti * sizeof(id[0]));
memcpy((void *)mxGetPr(Q_id), (void *)qd, len_Ti * sizeof(qd[0]));
engPutVariable(ep, "ti", ti); // put data to engine
engPutVariable(ep, "to", to);
engPutVariable(ep, "I_id", I_id);
engPutVariable(ep, "Q_id", Q_id);
// execute matlab operations
engEvalString(ep, "outDi=interp1(ti,I_id,to,'linear','extrap');");
engEvalString(ep, "outDq=interp1(ti,Q_id,to,'linear','extrap');");
outDi = engGetVariable(ep, "outDi");
outDq = engGetVariable(ep, "outDq");
auto firstAddress = mxGetPr(outDi);
auto secondAddress = mxGetPr(outDq);
for (int j = 0; j < len_To; j++) {
OUTD.real.push_back(*firstAddress);
OUTD.imag.push_back(*secondAddress);
firstAddress++;
secondAddress++;
}
mxDestroyArray(ti);
mxDestroyArray(to);
mxDestroyArray(I_id);
mxDestroyArray(Q_id);
mxDestroyArray(outDi);
mxDestroyArray(outDq);
return OUTD;
}
C调用matlab的interp1()实现实数插值
vector<double> Vsqt::MatlabInterp1ZS(vector<double> sat1, vector<double> sat2, vector<double> TI, Engine *ep) {
/*
实数插值
*/
/*
很需要注意的是,当我们把数据给matlab的引擎时,无论是指向数据的指针还是数据本身,都最好优先改为double类型,
否则数据会出现错误(试出来的),这可能和matlab默认是double类型有关,但更可能是因为将数据转为代码将matlab
数据格式时将我们的其他类型的数据放到了基础类型为double的特殊类型数据中
*/
vector<double> OUTD;
mxArray *satm1 = NULL,
*satm2 = NULL,
*ti_m = NULL,
*Y = NULL;
double *sat_1 = new double[sat1.size()];
double *sat_2 = new double[sat2.size()];
for (int i = 0; i < sat1.size(); i++)
{
sat_1[i] = sat1[i];
sat_2[i] = sat2[i];
}
double *TI_m = new double[TI.size()];
for (int i = 0; i < TI.size(); i++)
{
TI_m[i] = TI[i];
}
satm1 = mxCreateDoubleMatrix(1, sat1.size(), mxREAL);
satm2 = mxCreateDoubleMatrix(1, sat2.size(), mxREAL);
ti_m = mxCreateDoubleMatrix(1, TI.size(), mxREAL);
memcpy((void *)mxGetPr(satm1), (void *)sat_1, sat1.size() * sizeof(double));
memcpy((void *)mxGetPr(satm2), (void *)sat_2, sat2.size() * sizeof(double));
memcpy((void *)mxGetPr(ti_m), (void *)TI_m, TI.size() * sizeof(double));
engPutVariable(ep, "satm1", satm1); // put data satm2 engine
engPutVariable(ep, "satm2", satm2);
engPutVariable(ep, "ti_m", ti_m);
// execute matlab operations
engEvalString(ep, "outDi=interp1(satm1,satm2,ti_m,'linear','extrap');");
Y = engGetVariable(ep, "outDi");
auto firstAddress = mxGetPr(Y);
for (int j = 0; j < TI.size(); j++) {
OUTD.push_back(*firstAddress);
firstAddress++;
}
mxDestroyArray(satm1);
mxDestroyArray(satm2);
mxDestroyArray(ti_m);
mxDestroyArray(Y);
return OUTD;
}
注意
该文章仅个人学习使用,欢迎大家一起交流学习