Matlab Coder是一個將matlab代碼轉(zhuǎn)化為C/C++代碼或dll、lib的工具,得到的代碼或程序獨立于Matlab,可以在其他工程中隨意使用。這樣,如果碰到一些數(shù)學問題,比如矩陣運算、算法驗證等,可以先用Matlab實現(xiàn),然后方便地轉(zhuǎn)化為源代碼在各種應用中使用。
下面來介紹Coder的使用方法,內(nèi)容參考自Matlab幫助文檔。
Coder的使用主要基于3個組件:Matlab、Coder工具箱和C編譯器。一般安裝好Matlab后,前兩個是默認提供的(執(zhí)行ver命令可快速查看Coder工具箱是否安裝);C編譯器默認有提供,但可根據(jù)自己的情況更換其他C編譯器(Matlab推薦使用其他編譯器,自帶的性能不佳),具體可執(zhí)行mex
-setup進行編譯器配置,如
>> mex -setup
MEX configured to use 'Microsoft Visual C++ 2013 Professional (C)' for C language compilation.
Warning: The MATLAB C and Fortran API has changed to support MATLAB
variables with more than 2^32-1 elements. In the near future
you will be required to update your code to utilize the
new API. You can find more information about this at:
http://www./help/matlab/matlab_external/upgrading-mex-files-to-use-64-bit-api.html.
To choose a different language, select one from the following:
mex -setup C++
mex -setup FORTRAN
完成配置后,開始轉(zhuǎn)換Matlab函數(shù)代碼,例如下面函數(shù),它實現(xiàn)了搜索banana函數(shù)的最小值位置,并計算矩陣A的行列式:TestCoderFcn.m
% Test for Coder
function [x, Adet] = TestCoderFcn(x0, p0, A)%#codegen
% search minimum
global p
p = p0;
x = fminsearch(@myfun, x0);
% calculate det
Adet = det(A);
end
% banana function
function f = myfun(x)
global p
f = 100*(x(2)-x(1)^2)^2+(p-x(1))^2;
end
使用代碼main.m做效果測試:
% 測試
clc
clear
close all
x0 = [1,3];
p0 = 2;
A = [1 -2 4; -5 2 0; 1 0 3]; % det(A) = -32
[x, Adet] = TestCoderFcn(x0, p0, A);
fprintf('函數(shù)的極值出現(xiàn)在(%f, %f)\n', x)
fprintf('矩陣的行列式為%f\n', Adet)
測試結(jié)果為:
函數(shù)的極值出現(xiàn)在(2.000005, 4.000021)
矩陣的行列式為-32.000000
在轉(zhuǎn)化前,需要對代碼進行3種檢查:代碼語法檢查、代碼可轉(zhuǎn)換檢查和運行時檢查。
![]()
![]() ![]()
![]() ![]()
代碼通過語法檢查和可轉(zhuǎn)化檢查后,開始進行轉(zhuǎn)化。輸入coder打開MATLAB Coder,或通過工具欄打開:
![]() ![]()
選擇需要轉(zhuǎn)化的文件TestCoderFcn.m,Coder會在當前文件夾生成一個prj工程文件,便于工程設(shè)置保存:
![]()
點擊Next,選擇main.m文件,并點擊Autodefine Input Types運行該文件,Coder會跟蹤運行過程得到函數(shù)輸入輸出變量的類型和大?。?/div>
![]()
這里x0是1x2的向量,p0是常數(shù),A為3x3的矩陣,但實際上A的維數(shù)可以更高,所以進行如下調(diào)節(jié)
![]()
另外,由于使用了全局變量,所以Does this code use global variables?選擇Yes,并設(shè)置相應變量名和類型:
![]()
點擊Next,執(zhí)行Chech for issues進行運行時檢查
![]()
如果運行成功,會提示代碼沒問題,否則需要根據(jù)報錯進行修改
![]()
點擊Next,根據(jù)需要選擇相應選項產(chǎn)生所需代碼或庫文件,這里選擇產(chǎn)生源代碼,點擊Generate按鈕開始生成:
![]()
最后Coder會生成相應的源代碼:
![]() ![]()
這些源代碼保存在codegen\lib\TestCoderFcn文件夾下,可以看到Coder生成的文件很多,這也是一個不太方便的地方,如果需要代碼復用,就要把所有源文件拷過去,增加了工程目錄的復雜性:
![]()
另外,Coder提供源代碼打包功能,點擊結(jié)束界面右上角的PACKAGE可將必要源代碼壓縮打包,分享使用。
![]()
對于源代碼的使用,可以參考codegen\lib\TestCoderFcn\examples文件夾下main.h和.c文件。
下面利用這兩個文件測試生成源代碼的運行效果。首先把這兩個文件拷貝到其他文件夾,因為如果直接修改這兩個文件,再次運行Coder產(chǎn)生代碼時,會提示這兩個文件發(fā)生改變,影響代碼生成。
打開main.c文件,可以看到其中的main函數(shù)代碼如下:
int main(int argc, const char * const argv[])
{
(void)argc;
(void)argv;
/* Initialize the application.
You do not need to do this more than one time. */
TestCoderFcn_initialize();
/* Invoke the entry-point functions.
You can call entry-point functions multiple times. */
main_TestCoderFcn();
/* Terminate the application.
You do not need to do this more than one time. */
TestCoderFcn_terminate();
return 0;
}
前兩行代碼無用,先將其注釋掉:
//(void)argc;
//(void)argv;
剩下就是3個函數(shù),第一個函數(shù)用來初始化,第二個完成主要功能,第三個結(jié)束應用。第二個函數(shù)其實很簡單,就是初始化變量,傳入核心函數(shù)TestCoderFcn執(zhí)行得到結(jié)果:
static void main_TestCoderFcn(void)
{
double x0[2];
double p0;
emxArray_real_T *A;
double Adet;
double x[2];
/* Initialize function 'TestCoderFcn' input arguments. */
/* Initialize function input argument 'x0'. */
argInit_1x2_real_T(x0);
p0 = argInit_real_T();
/* Initialize function input argument 'A'. */
A = c_argInit_UnboundedxUnbounded_r();
/* Call the entry-point 'TestCoderFcn'. */
TestCoderFcn(x0, p0, A, x, &Adet);
emxDestroyArray_real_T(A);
}
所以關(guān)鍵需要修改的就是3個初始化:
argInit_1x2_real_T(x0);
p0 = argInit_real_T();
A = c_argInit_UnboundedxUnbounded_r();
其中p0的初始化可以直接修改:
//p0 = argInit_real_T();
p0 = 2;
其他兩個函數(shù)修改為
static void argInit_1x2_real_T(double result[2])
{
//int b_j1;
/* Loop over the array to initialize each element. */
//for (b_j1 = 0; b_j1 < 2; b_j1++) {
/* Set the value of the array element.
Change this value to the value that the application requires. */
//result[b_j1] = argInit_real_T();
//}
result[0] = 1;
result[1] = 3;
}
static emxArray_real_T *c_argInit_UnboundedxUnbounded_r(void)
{
emxArray_real_T *result;
//static int iv0[2] = { 2, 2 };
static int iv0[2] = { 3, 3 };
int b_j0;
int b_j1;
/* Set the size of the array.
Change this size to the value that the application requires. */
result = emxCreateND_real_T(2, iv0);
/* Loop over the array to initialize each element. */
double A[] = {1,-2,4,-5,2,0,1,0,3};
for (b_j0 = 0; b_j0 < result->size[0U]; b_j0++) {
for (b_j1 = 0; b_j1 < result->size[1U]; b_j1++) {
/* Set the value of the array element.
Change this value to the value that the application requires. */
result->data[b_j0 + result->size[0] * b_j1] = A[b_j0 + result->size[0] * b_j1];
}
}
return result;
}
為了展示擬合結(jié)果,在TestCoderFcn函數(shù)執(zhí)行后,加一句結(jié)果輸出:
TestCoderFcn(x0, p0, A, x, &Adet);
printf("Fitting Result: %f, %f\n", x[0], x[1]);
printf("Det pf A: %f\n", Adet);
如此修改后,在Coder中選擇生成exe文件,并在More Settings->Custom Code中設(shè)置Additional include directories為main.c所在目錄,Additional source files為main.c:
![]() ![]()
設(shè)置好后,點擊Generate生成可執(zhí)行文件TestCoderFcn.exe,并在Matlab中執(zhí)行如下語句查看結(jié)果:
!TestCoderFcn.exe
或
system('TestCoderFcn.exe');
結(jié)果為
>> !TestCoderFcn.exe
Fitting Result: 2.000005, 4.000021
Det pf A: -32.000000
>> system('TestCoderFcn.exe');
Fitting Result: 2.000005, 4.000021
Det pf A: -32.000000
![]()
可以看到運行結(jié)果與Matlab結(jié)果是一致的。
|
|