概述
ctypes + matlab coder
- MATLAB coder
- ctypes
之前为便捷工作,想做个简单的工具用于无MATLAB环境的算法验证,还不错。最近闲暇,总结一下。
MATLAB coder
从 MATLAB 代码生成 C 和 C++ 代码
MATLAB coder : 根据编写的MATLAB .m 文件,可以生成c/c++代码、.exe执行文件、dll/lib库及MEX文件;并且提供主流的硬件平台,生成可支持嵌入式的代码。
上篇文章讲了如何简单配置MATLAB并生成 dll/lib 库,但是封装好的库是没有给调用函数接口示例的,而MATLAB计算多为矩阵操作,对嵌入式(c /c++)而言这种矩阵操作大多需要结构体等类型支持,所以用mcc类的方法对于简单的函数封装没有问题,但稍微有一定复杂度就不好用了。
这个时候MATLAB coder还是比较强大的,或许它在 .m 转 c/c++ 的时候部分处理代码不够简洁、有优化的空间,这主要是因为它以“逐行翻译”为主,但是在生成 dll/lib 库的时候不仅给出所有相关 .c .h等文件,还给出 main.c文件展示调用接口示例,这对于直接使用接口函数来说很方便。
大概说一下MATLAB coder的简单用法,其实MATLAB的所有工具及内置app都很“人性化”,在使用 coder的时候,它完全给出了类似于引导的步骤,只要按步骤操作就可以了。有些步骤中的设置这里简单说明一下(使用的MATLAB 2015版本):
首先给出示例的conv_fun.m 函数,代码如下:
function [d] = conv_fun(a,b,c)
% ************************************************************************
% Function : conv_fun
% Description : d = conv(a,c) + conv(b,c)
% Input : complex: a b c
% Output : complex d
% ************************************************************************
d = conv(a,c) + conv(b,c);
调用的test.m内容如下:
a = [1+1i,2+2*1i,3+3i,4+4i,5+5i];
b = [1+2i,2+1i,3+1i,1+3i,4+1i];
c = [1+4i,1+5i,5+1i,2+3i,3+2i];
d = conv_fun(a,b,c);
以上函数非常简单,conv函数是MATLAB自带的函数,在命令窗口输入:open conv即可打开其定义的m文件,所以只要有m文件的定义,基本上都可以。
STEP 1
在MATLAB的APPS里面找到MATLAB coder,打开即为如下界面。首先选择是否支持浮点运算,因为大部分嵌入式编程都设为定点运算,这个根据需要自定义,本例为python下使用ctypes,所以不需要定点。
从后面的 … (默认为当前MATLAB的工作路径)中选择要转换的m文件,自动转为如下界面:
next后,需要根据调用函数来确定转换函数的输入数据和输出数据的格式。
STEP 2
选择调用该函数的m文件
该步骤可以自定义数据格式,也可以autodefine 自动生成,自动生成的也可再自己修改,通常自动生成方便些,如果入参较多,自定义选格式也要敲一会……
从上图可以看出,自动生成完全是按照调用时所给的格式,修改时给了三种方案:精确到5,最多到5及不限制,本例选择无限制。后面还要确定要转换的函数是否使用了全局变量,如果是,需要给出变量名字及格式,本例没有。
STEP 3
接下来就是 CHECK 环节了,按照前面的配置,这里不用选择什么,直接点检查问题让其自动运行就行了。但是前面在Define环节自定义函数入参格式的(没有提供调用函数的m文件),这里需要填一下。
继续next
STEP 4
这时候就可以生成所需要的结果了,这里选择 .dll类型。由于是主机上python调用,所以这里不用选择适配的硬件类型,默认为该MATLAB 主机就行了。
生成后可以看到为了这个dll中间产生的多有 c文件,其中比较重要的就是调用函数的输入输出定义格式,例如结构体emxArray_creal_T的定义,可以在conv_fun_types.h里面看到,main.c里面给了使用封装函数的举例。所有生成的文件都在conv_fun.m的路径下,MATLAB会自动建立一个叫codegen的文件夹,有个dll文件夹,生成的.dll就在里面。
ctypes
ctypes : 是python的一个外部函数库,由于上面的库是基于c语言生成的,所以单纯的python 是无法提供c的数据类型的,而ctypes库可兼容c,并允许调用dll或共享库中的函数。本例以基本使用和实用为主,ctypes的详细使用可以参考官方指导(https://docs.python.org/zh-cn/3.7/library/ctypes.html)。
首先定义需要的结构体类型,参照conv_fun_types.h:
struct emxArray_creal_T
{
creal_T *data;
int *size;
int allocatedSize;
int numDimensions;
boolean_T canFreeData;
};
creal_T及boolean_T类型在rtwtypes.h中定义如下:
typedef struct {
real_T re;
real_T im;
} creal_T;
typedef unsigned char boolean_T;
对应的ctypes中定义方法如下:
from ctypes import *
class creal_T(Structure):
_fields_=[('re',c_double),
('im',c_double),
]
class emxArray_creal_T(Structure):
_fields_=[('data',POINTER(creal_T)),
('size',POINTER(c_int)),
('allocatedSize',c_int),
('numDimensions',c_int),
('canFreeData',c_ubyte),
]
导入dll中的库函数并声明输入输出的类型:
dll = CDLL("E:/test/conv_fun/conv_fun.dll")
# load function
conv_fun = dll.conv_fun
# declare function
conv_fun.restype = POINTER(emxArray_creal_T)
conv_fun.argtypes = [POINTER(emxArray_creal_T),POINTER(emxArray_creal_T),POINTER(emxArray_creal_T)]
对变量的定义:
size = (c_int*2)(1,5)
a_data = (creal_T*5)((1,1),(2,2),(3,3),(4,4),(5,5))
a = emxArray_creal_T()
a.size = size
a.data = a_data
a.allocatedSize = 0
a.numDimensions = 2
a.canFreeData = 0
size1 = (c_int*2)(1,9)
# d_data = (creal_T*9)()
d = emxArray_creal_T()
d.size = size1
# d.data = pointer(d_data[0])
d.allocatedSize = 0
d.numDimensions = 2
d.canFreeData = 0
对于test.m中的a、b、c三个参数定义基本一致,d作为输出参数,结构体中的data可以预先给空间,也可以不给。函数调用:
conv_fun(byref(a),byref(b),byref(c),byref(d))
上述整体过程是为写这篇文章的一个小示范,运行结果同MATLAB一致。其中ctypes的指针类型函数,个人理解如下:
POINTER:定义数据类型的指针,eg. POINTER(emxArray_creal_T),类似c中的(emxArray_creal_T *);
pointer:指向数据的指针,eg. d.data = pointer(d_data[0]),类似c中的 int *pointer_a = a,指针变量是可以改变指向的;
byref:ctypes标准库中说明 byref()用于 函数传递参数引用。程序中 byref可以使用pointer代替,但是pointer会额外创建一个指针对象,byref不会,类似c中 &取地址符;
总结
个人感觉MATLAB转dll/lib还比较好用,虽然.c文件看着很绕,转化代码不是很精简,但是很方便。至于python + ctypes 如果有c基础,参照着ctypes的标准库指导来使用其中的库函数还是比较容易使用的。
最后
以上就是精明秀发为你收集整理的ctypes + matlab coderMATLAB coderctypes的全部内容,希望文章能够帮你解决ctypes + matlab coderMATLAB coderctypes所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复