本页对应的英文页面已更新,但尚未翻译。 若要查看最新内容,请点击此处访问英文页面。

外部函数

在 MATLAB® 代码中处理对函数 foo 的调用时,代码生成器会找到 foo 的定义并为其函数体生成代码。在某些情况下,您可能希望绕过代码生成,而是使用 MATLAB 引擎来执行调用。使用 coder.extrinsic('foo') 声明对 foo 的调用不生成代码,而是使用 MATLAB 引擎执行。在此上下文中,foo 称为外部函数。仅当 MATLAB 引擎在 MEX 函数中可用或在编译时在 coder.const 调用期间可用时,此功能才可用。

如果为调用 foo 并包含 coder.extrinsic('foo') 的函数生成独立代码,代码生成器将尝试确定 foo 是否影响输出。如果 foo 不影响输出,则代码生成器继续生成代码,但会从生成的代码中排除 foo。否则,代码生成器会产生编译错误。

代码生成器自动将许多常见的 MATLAB 可视化函数(例如 plotdispfigure)视为外部函数。您不必使用 coder.extrinsic 将它们显式声明为外部函数。例如,您可能希望通过调用 plot 来可视化 MATLAB 环境中的结果。如果您从调用 plot 的函数中生成一个 MEX 函数并运行该 MEX 函数,代码生成器会将对 plot 函数的调用调度给 MATLAB 引擎。如果您生成一个库或可执行文件,生成的代码中将不包含对 plot 函数的调用。代码生成报告会突出显示从您的 MATLAB 代码中对外部函数的调用,因此可以轻松确定哪些函数仅在 MATLAB 环境中支持。

除了常见的可视化函数外,对于其他不支持的函数,您必须将它们声明为外部函数(请参阅Resolution of Function Calls for Code Generation)。外部函数未编译,但会在 MATLAB 仿真过程中执行(请参阅在仿真过程中解析外部函数)。

将函数声明为外部函数有两种方式:

MATLAB 函数声明为外部函数

要将 MATLAB 函数声明为外部函数,请在主函数或局部函数的顶部添加一个 coder.extrinsic 构造:

coder.extrinsic('function_name_1', ... , 'function_name_n');

声明外部函数

以下代码在局部函数 create_plot 中将 MATLAB patch 函数声明为外部函数。不需要将 axis 声明为外部函数,因为 axis 是代码生成器自动视为外部函数的常见可视化函数之一。

function c = pythagoras(a,b,color) %#codegen
% Calculates the hypotenuse of a right triangle
%  and displays the triangle. 

c = sqrt(a^2 + b^2);
create_plot(a, b, color);


function create_plot(a, b, color)
%Declare patch as extrinsic

coder.extrinsic('patch'); 

x = [0;a;a];
y = [0;0;b];
patch(x, y, color);
axis('equal');

代码生成器不会为 patchaxis 生成代码,而是将它们调度给 MATLAB 来执行。

要测试该函数,请执行以下操作:

  1. 在 MATLAB 提示符下,通过执行以下命令将 pythagoras 转换为 MEX 函数:

    codegen -report pythagoras -args {1, 1, [.3 .3 .3]}

  2. 点击代码生成报告的链接,然后在该报告中查看 create_plot 的 MATLAB 代码。

    该报告突出显示了 patchaxis 函数,表明仅在 MATLAB 环境中支持它们。

  3. 通过执行以下命令运行 MEX 函数:

    pythagoras_mex(3, 4, [1.0 0.0 0.0]);

    MATLAB 将直角三角形的绘图显示为红色补片对象:

何时使用 coder.extrinsic 构造

使用 coder.extrinsic 构造可以:

  • 调用在仿真过程中不会生成输出,从而不会生成不必要代码的 MATLAB 函数(请参阅在仿真过程中解析外部函数)。

  • 使您的代码具有自说明,从而更容易调试。您可以扫描 coder.extrinsic 语句的源代码以隔离对 MATLAB 函数的调用,它们可能会创建并传播 mxArrays(请参阅使用 mxArray)。

  • 节省打字。使用一个 coder.extrinsic 语句,就能让每个后续函数调用都是外部调用,只要调用和语句在相同的作用域内(请参阅外部函数声明的作用域)。

  • 在整个调用函数作用域内将 MATLAB 函数声明为外部函数(请参阅外部函数声明的作用域)。要缩小作用域,请使用 feval(请参阅使用 feval 调用 MATLAB 函数)。

外部函数声明规则

为代码生成声明外部函数时,请遵循以下规则:

  • 在调用函数之前将其声明为外部函数。

  • 不要在条件语句中使用外部声明。

外部函数声明的作用域

coder.extrinsic 构造具有函数作用域。以如下代码为例:

function y = foo %#codegen
coder.extrinsic('rat','min');
[N D] = rat(pi);
y = 0;
y = min(N, D);

在此示例中,ratmin 每次在主函数 foo 中调用时都被视为外部函数。有两种方式可以缩小外部函数声明在主函数内的作用域:

  • 在局部函数中将 MATLAB 函数声明为外部函数,如以下示例中所示:

    function y = foo %#codegen
    coder.extrinsic('rat');
    [N D] = rat(pi);
    y = 0;
    y = mymin(N, D);
     
    function y = mymin(a,b)
    coder.extrinsic('min');
    y = min(a,b);
    

    这里,函数 rat 每次在主函数 foo 内调用时都是外部函数,但函数 min 只有在局部函数 mymin 内调用时才是外部函数。

  • 使用 feval 调用 MATLAB 函数,如使用 feval 调用 MATLAB 函数中所述。

使用 feval 调用 MATLAB 函数

在代码生成过程中,函数 feval 自动被解释为外部函数。因此,您可以使用 feval 很方便地调用要在 MATLAB 环境中执行的函数,而不用编译为生成的代码。

请参考以下示例:

function y = foo 
coder.extrinsic('rat');
[N D] = rat(pi);
y = 0;
y = feval('min', N, D);

因为 feval 是外部函数,所以语句 feval('min', N, D) 由 MATLAB 计算(而不进行编译),这样产生的结果与专门为此调用将 min 声明为外部函数相同。相比之下,函数 rat 在整个函数 foo 中都是外部函数。

代码生成器不支持使用 feval 来调用局部函数或位于私有文件夹中的函数。

对非静态方法进行外部声明

假设您定义一个具有非静态方法 foo 的类 myClass,然后创建此类的实例 obj。如果要在用于代码生成的 MATLAB 代码中将方法 obj.foo 声明为外部方法,请遵循以下规则:

  • 将对 foo 的调用编写为函数调用。不要使用圆点表示法来编写调用。

  • 使用语法 coder.extrinsic('foo')foo 声明为外部函数。

例如,将 myClass 定义为:

classdef myClass
    properties
        prop = 1
    end
    methods
        function y = foo(obj,x)
            y = obj.prop + x;
        end
    end
end

下面是将 foo 声明为外部函数的 MATLAB 函数示例。

function y = myFunction(x) %#codegen
coder.extrinsic('foo');
obj = myClass;
y = foo(obj,x);
end

非静态方法也称为普通方法。请参阅方法和函数

在仿真过程中解析外部函数

代码生成器按如下方式解析对外部函数(不支持代码生成的函数)的调用:

在仿真过程中,代码生成器会为外部函数的调用生成代码,但不会为函数生成内部代码。因此,您只能在安装了 MATLAB 软件的平台上运行仿真。

在代码生成过程中,代码生成器会尝试确定外部函数是否影响调用时所在函数的输出 - 例如,通过将 mxArrays 返回给输出变量(请参阅使用 mxArray)。如果输出不变,将继续进行代码生成,但会从生成的代码中排除外部函数。否则,代码生成器将生成编译器错误。

使用 mxArray

外部函数的输出是一个 mxArray - 也称为 MATLAB 数组。对 mxArrays 有效的操作只有下列几个:

  • mxArrays 存储在变量中

  • mxArrays 传递给函数,并从函数中返回它们

  • 在运行时将 mxArrays 转换为已知类型

要在其他操作中使用外部函数返回的 mxArrays,必须先将它们转换为已知类型,如将 mxArray 转换为已知类型中所述。

将 mxArray 转换为已知类型

要将 mxArray 转换为已知类型,请将 mxArray 指定给已定义类型的变量。在运行时,mxArray 将被转换为其指定给的变量的类型。但是,如果 mxArray 中的数据与该变量的类型不一致,将会发生运行时错误。

以如下代码为例:

function y = foo %#codegen
coder.extrinsic('rat');
[N D] = rat(pi);
y = min(N, D);

这里,顶层函数 foo 调用外部 MATLAB 函数 rat,后者返回两个 mxArrays,分别代表 pi 的有理分式逼近式的分子 N 和分母 D。虽然可以将这两个 mxArrays 传递给另一个 MATLAB 函数(本例中为 min),但不能将 min 返回的 mxArray 指定给输出 y

如果在 Simulink® 模型中的 MATLAB Function 模块中运行此函数 foo,仿真过程中代码将生成以下错误:

Function output 'y' cannot be of MATLAB type.

要解决此问题,请按如下方式将 y 定义为您希望 min 返回的值的类型和大小,本例中为双精度标量值:

function y = foo %#codegen
coder.extrinsic('rat');
[N D] = rat(pi);
y = 0; % Define y as a scalar of type double
y = min(N,D);

代码生成中对于外部函数的限制

代码生成过程中不支持完整的 MATLAB 运行时环境。因此,从外部调用 MATLAB 函数时存在以下限制:

  • 检查调用方或者读取或写入调用方工作区的 MATLAB 函数在代码生成过程中不起作用。此类函数包括:

  • MATLAB 调试器无法检查在外部函数中定义的变量。

  • 如果您的外部函数在运行时执行以下操作,则生成的代码中的函数可能会产生不可预知的结果:

    • 更改文件夹

    • 更改 MATLAB 路径

    • 删除或添加 MATLAB 文件

    • 更改警告状态

    • 更改 MATLAB 预设

    • 更改 Simulink 参数

  • 代码生成器不支持使用 coder.extrinsic 来调用位于私有文件夹中的函数。

  • 代码生成器不支持使用 coder.extrinsic 来调用局部函数。

有关函数参数的限制

您可以调用最多具有 64 个输入和 64 个输出的函数。