百科问答小站 logo
百科问答小站 font logo



怎么在matlab中执行c语言代码,或者把c代码转换成matlab代码? 第1页

  

user avatar   wangzheng-80 网友的相关建议: 
      

在嵌入式领域,MATLAB非常适合进行算法原型开发和验证,C代码适合部署到最终目标产品平台。符合一定要求的MATLAB代码也可以通过MATLAB Coder生成C代码。

在实际研发过程中,一般同时存在MATLAB代码和C代码。为了提升整体研发效率,往往会使用MATLAB和C代码混合编程。本文介绍使用MATLAB自带的calllib等接口调用C代码的方式。

应用场景

一般来说,首先使用MATLAB进行原型开发。

相对成熟,且对性能有一定要求的模块,使用C代码实现。其来源可能是手写代码,也可能是MATLAB Coder或Simulink Coder或Embedded Coder生成的C代码。

这些代码按照实际运行平台的特点,封装为相应的库。例如,Windows平台的DLL库,Linux平台的so库等。

MATLAB仿真时,可以调用这些C代码的库。

被调C代码

被调C代码为计算一个数组的均值和标准差,如下所示:

       /* 头文件 */ typedef struct S_DEMO_IN {  double n;  double *arr; } DemoIn;  typedef struct S_DEMO_RESULT {  double mean;  double std; } DemoRes;  void demo_mean_std(DemoRes *pRes, double *arr, DemoIn *pIn);     

实现文件

       /* 实现文件 */ extern "C" _declspec(dllexport) void demo_mean_std(DemoRes *pRes, double *arr, DemoIn *pIn) {  int N_std;  pRes->mean = 0.0;  pRes->std = 0.0;  N_std = 0;  for (int i = 0; i < pIn->n; i++)  {   N_std = N_std + 1;   pRes->std = pRes->std + (N_std - 1) * (pIn->arr[i] - pRes->mean) * (pIn->arr[i] - pRes->mean) / N_std;   pRes->mean = pRes->mean + (pIn->arr[i] - pRes->mean) / N_std;  }  if (N_std > 1)  {   pRes->std = sqrt(pRes->std / (N_std - 1));  }  else  {   pRes->std = 0.0;  }  for (int i = 0; i < pIn->n; i++)  {   if (pIn->arr[i] > pRes->mean + 3.0 * pRes->std)   {    arr[i] = pRes->mean + 3.0 * pRes->std;   }   else if (pIn->arr[i] < pRes->mean - 3.0 * pRes->std)   {    arr[i] = pRes->mean - 3.0 * pRes->std;   }   else   {    arr[i] = pIn->arr[i];   }  }  return; }     

将上述代码编译为动态链接库,设库文件名为“Dll_demo.dll”,头文件名为“Dll_demo.h”。

载入C库

打开MATLAB(本文使用的是MATLAB 2021a),将Dll_demo.dll和Dll_demo.h所在路径,或将这两个文件拷贝到工作路径。

编写MATLAB指令,首先,定义所需的库名、头文件名、函数名及涉及的类型名:

       slib_name = 'Dll_demo'; shead_name = 'Dll_demo.h'; stype_in_name = 'S_DEMO_IN'; stype_res_name = 'S_DEMO_RESULT'; sfunc_name = 'demo_mean_std';     

使用loadlibrary接口,载入库函数。为了避免重复载入,需要先检查是否已被载入。

       if not(libisloaded(slib_name))     [m1, m2] = loadlibrary(slib_name, shead_name);     disp(m1);     disp(m2); end     

可以使用下列命令查看载入的库的函数接口:

                libfunctions         (         slib_name         ,         '-full'         );            

对于本文的例子,MATLAB的输出如下:

C函数demo_mean_std的三个参数均为指针型,MATLAB语言本身无法直接支持指针类型,因此,它将其视为特殊的xxxPtr类型。

C使用指针类型可以实现输入参数同时作为输出参数,而MATLAB不支持输入参数同时作为输出参数。因此,在MATLAB视角下,该函数有三个返回值。

构造参数

接下里,需要使用MATLAB指令构造输入参数。

  • 构造参数DemoRes *pRes:
       para_out.mean = 0; para_out.std = 0; s_para_res = libstruct(stype_res_name, para_out);     
  • 构造参数DemoIn *pIn:
       arr = [17, 124, 1, 8, 15, 23, 5, 7, 14, 16, 4, 6, 13, 20, 22, 10, 12, 19, 21, 3, 11, 18, 25, 2, 9]; ptr_arr = libpointer('doublePtr', arr); para_in.n = length(arr); para_in.arr = ptr_arr; s_para_in = libstruct(stype_in_name, para_in);     
  • 构造参数double *arr:
       arr2 = zeros(length(arr), 1); ptr_arr2 = libpointer('doublePtr', arr2);     

调用C函数并解析结果

使用calllib接口调用C函数:

       [out_ret, out_arr, ~] = calllib(slib_name, sfunc_name, s_para_res, ptr_arr2, s_para_in); out_mean = out_ret.mean; out_std = out_ret.std;     

C代码中结构体指针型的输出参数pRes直接被解析为MATLAB结构体,double指针型输出参数则被解析为MATLAB数组。

注意,在C语言层面,out_arr和ptr_arr2其实是同一个参数,因此,out_arr的维数和ptr_arr2完全一致。

清理空间并释放C库

使用clear指令清零空间,使用unloadlibrary指令释放库:

       clear s_para_in; clear s_para_res; clear ptr_arr; clear ptr_arr2; unloadlibrary(slib_name);     

注意,所有使用libpointer、libstruct指令定义的MATLAB变量都应当使用clear释放。

封装为MATLAB函数

为了方便使用,可以将上述脚本封装为MATLAB函数

       function [out_mean, out_std, out_arr, m1, m2] = call_c_demo(arr) slib_name = 'Dll_demo'; shead_name = 'Dll_demo.h'; stype_in_name = 'S_DEMO_IN'; stype_res_name = 'S_DEMO_RESULT'; sfunc_name = 'demo_mean_std';  % 载入库文件 if not(libisloaded(slib_name))     [m1, m2] = loadlibrary(slib_name, shead_name); else     m1 = cell(0,0);     m2 = 'already loaded ...'; end  % 构造参数 ptr_arr = libpointer('doublePtr', arr); para_in.n = length(arr); para_in.arr = ptr_arr; s_para_in = libstruct(stype_in_name, para_in); arr2 = zeros(length(arr), 1); ptr_arr2 = libpointer('doublePtr', arr2); para_out.mean = 0; para_out.std = 0; s_para_res = libstruct(stype_res_name, para_out);   % 调用库中的函数 [out_ret, out_arr, ~] = calllib(slib_name, sfunc_name, s_para_res, ptr_arr2, s_para_in); out_mean = out_ret.mean; out_std = out_ret.std; % 释放空间 clear s_para_in; clear s_para_res; clear ptr_arr; clear ptr_arr2; end     

注意,封装为函数之后,没有调用unloadlibrary接口。这是为了提升运行效率,多次调用时,避免反复加载/释放带来的开销。MATLAB开发者可以在确认不会再使用该库时,再使用unloadlibrary接口释放C库。

调用示例如下:

       arr = [17, 124, 1, 8, 15, 23, 5, 7, 14, 16, 4, 6]; [out_mean, out_std, out_arr, m1, m2] = call_c_demo(arr); disp(out_mean);  disp(out_std);  disp(out_arr);  disp(m1);  disp(m2);     

由图中标红和标蓝的信息可知,调用结果正确。

针对封装后的MATLAB函数的测试

MATLAB提供了单元测试框架matlab.unittest.TestCase,使用该框架,可以更规范、更方便地对封装的MATLAB函数进行测试。

       classdef TestDemoC < matlab.unittest.TestCase     properties         slib_name = 'Dll_demo';         shead_name = 'Dll_demo.h';     end          methods(TestMethodSetup)         function loadDemoLib(test)             if not(libisloaded(test.slib_name))                 [m1, m2] = loadlibrary(test.slib_name, test.shead_name);                 disp(m1);                 disp(m2);             end         end     end          methods(TestMethodTeardown)         function releaseDemoLib(test)             if libisloaded(test.slib_name)                 disp('release library');                 unloadlibrary(test.slib_name);             end         end     end         % 测试用例     methods (Test)                  % 用例1: 边界情况, 仅一个元素         function tes01(test)             arr = 17;             [out_mean, out_std, out_arr, ~, ~] = call_c_demo(arr);             test.verifyEqual(out_mean, arr);             test.verifyEqual(out_std, 0.0);             test.verifyEqual(out_arr, arr);         end                  % 用例2: 一般情况         function tes02(test)             arr = [17, 24, 1, 8, 15, 23, 5, 7, 14, 16, 4, 6];             [out_mean, out_std, out_arr, ~, ~] = call_c_demo(arr);             test.verifyEqual(out_mean, mean(arr));             test.verifyEqual(out_std, std(arr));             test.verifyEqual(out_arr, arr);         end                  % 用例3: 一般情况 - 存在异常值, 被限幅         function tes03(test)             arr = [17, 124, 1, 8, 15, 23, 5, 7, 14, 16, 4, 6];             arr2 = [17, 120.1626, 1, 8, 15, 23, 5, 7, 14, 16, 4, 6];             [out_mean, out_std, out_arr, ~, ~] = call_c_demo(arr);             test.verifyEqual(out_mean, mean(arr));             test.verifyEqual(out_std, std(arr));             test.verifyEqual(out_arr, arr2, 'AbsTol', 1.0e-5);         end     end end     




  

相关话题

  为什么我写的c语言三个数求最大值,最后出来的结果总是第一个? 
  C 语言的「void main」是怎么一代代传下来的? 
  为什么现在大厂很少招C语言开发了? 
  C语言中float的取值范围的问题,为啥? 
  这个代码int函数无返回值且开-O2,for循环会无限循环,是什么原因? 
  各位老铁,谁有能免费使用的学习c语言的编程软件推荐一下,本人万分感谢? 
  如何评价 mimalloc? 
  p-p plot图不在直线上,但是有规律,怎么调整原始数据? 
  对于一个大一计科新生,有什么代码行数在 500~1000 的程序(C 语言)可以试着写来练手? 
  为什么8bit限制是-128到127而不是-127到128? 

前一个讨论
路由表里的子网掩码有什么作用?
下一个讨论
为什么中国精神科大夫喜欢开奥氮平?





© 2024-12-22 - tinynew.org. All Rights Reserved.
© 2024-12-22 - tinynew.org. 保留所有权利