用于代码生成的 matlab 中具有多个匹配项的 switch-case

switch-case with multiple matches in matlab for code generation

以下代码是有效的 matlab 语法,用于检查 b 是否匹配 a 中的任何元素。但是,如果代码用于代码生成(即 simulink),则会出现错误:

'code generation only supports cell operations for varargin and varargout  

您可以通过在脚本顶部添加 %#codegen 来检查这一点。)

a={2 3};
b=3;
switch b
    case a
        disp yay
    otherwise
        disp boo
end

我应该如何匹配代码生成兼容代码中 case 语句中的多个模式?

以下对我不起作用:

case a(1) || a(2) %//with a=[2, 3] above, since cells not allowed

case a(:)

Matlab 编码器不支持 'cell arrays',并且它可以处理的函数集有限。请记住,C 不如 Matlab 灵活,特别是关于它处理的数据 typeC 不做动态类型(一个结构应该被定义一次并且定义不能在代码中改变)。因此 Matlab 不能让您使用类型非常松散的 cell array,并且您要添加到 cell 数组的下一个元素的类型与其他元素的类型不同。

因此,如果您希望 Matlab 将其转换为可能的 C 语言,那么在某些情况下,您将不得不为 Matlab 明确说明。

对于您的情况,不同的选择:

直接在case语句中显式列表

如果您不必经常重复使用 a 进行比较,您可以将 case a 替换为一个显式列表,例如 case {2,3,4,5}:

function test_coder(b)
switch b
    case {2,3,4,5}
        disp yay
    otherwise
        disp boo
end

它看起来像元胞数组,但实际上不是。因为它足够明确(变量只包含 4 double 类型)Matlab 将在内部使用数组并将 b 与每个元素进行比较(它将 "expand" 和 case 语句) .事实上,这部分生成的代码看起来像 (pure C way):

  guard1 = FALSE;
  switch ((int32_T)emlrtIntegerCheckFastR2012b(b, &emlrtDCI, emlrtRootTLSGlobal))
  {
   case 2:
    guard1 = TRUE;
    break;

   case 3:
    guard1 = TRUE;
    break;

   case 4:
    guard1 = TRUE;
    break;

   case 5:
    guard1 = TRUE;
    break;
... // and so on

对数组使用 ismember

函数ismember is supported by the code generator。所以下面的代码也可以工作:

function test_coder(b)

a=[2 3 4 5] ; %// define array "a"
c=[8 9 10]  ; %// define array "c"

if ismember(b,a)
    disp yay
elseif ismember(b,c)
    disp youhou
else
    disp boo

end

但是请注意,编码器需要对发送到 ismember 的数组进行排序,否则会引发错误。

如果您需要进行大量比较,这会起作用,但是考虑到生成代码的复杂性,我建议您仅在真正需要时才使用 ismember
当您的案例足够简单时,我建议您对 cases 进行显式声明(如果需要,请使用 {...} "shortcut"。


还请始终注意查看生成的代码:
在你最初的例子中,当你在代码中指定 b=3 时,Matlab 检测到,检测到代码将 always 以这种方式流动,所以它甚至没有编写比较逻辑...生成的代码只是一个快速 disp yay ...

我不得不将 b 作为输入,让 Matlab 实际编写比较逻辑代码。要编译上面的代码,您必须指定输入变量 b 的类型。所以我编译上面使用:

codegen test_coder.m -args {0}