【问题标题】:Share data between multiple c mex s-functions在多个 c mex s-function 之间共享数据
【发布时间】:2019-04-08 20:38:12
【问题描述】:

我正在实现几个 c s-functions。它们必须依赖于相同的指针和变量,与当前的 s-function 无关。

基本上,我想在一个“设置”s 函数(在 mdlInitialize 内部)中实例化所有变量和指针,然后能够在它们的 mdlOutputs 函数中使用这些变量和不同 s 函数中的指针。每个 s-function 都将用 c 编写。

我在 mathworks 帮助中找不到任何有用的提示。你有什么主意吗?谢谢。

【问题讨论】:

    标签: c simulink mex s-function


    【解决方案1】:

    有几种方法可以做到这一点,尽管它们都不是明显最好的方法。

    一种方法是在 dll 中定义所有内容并由每个 S-Function 加载。问题How to share a C struct among C S-Functions? 中对此进行了概述。

    另一种(也是我首选的)方法是创建一个自定义数据类型,它是一个包含所有共享数据的 C 结构,并将其作为模型中 S-Function 之间的信号传递。这在文档Configure Custom Data TypesUsing Opaque Data Types in C S-Functions 部分进行了概述。

    该文档显示了需要在创建自定义结构的 S-Function 中完成的各种(相对简单的)事情。在这个 S-Functions MdlOutputs 方法中,自定义结构将按照通常的方式作为块的输出。例如,如果包含您的数据的自定义结构定义为,

    typedef struct{
        real_T sig0;
        real_T sig1;
    }myStruct;
    

    然后在mdlInitializeSizes 你需要类似的东西,

    myStruct tmp;
    
    /* Register the user-defined data types */
    id = ssRegisterDataType(S, "customDataType");
    if(id == INVALID_DTYPE_ID) return;
    
    /* Set the size of the user-defined data type */
    status = ssSetDataTypeSize(S, id, sizeof(tmp));
    if(status == 0) return;
    
    /* Set the zero representation */
    tmp.sig0 = 0;
    tmp.sig1 = 0;
    status = ssSetDataTypeZero(S, id, &tmp);
    

    并将其作为信号输出,在 mdlOutputs 方法中,您将拥有类似

    myStruct *pY0 = (myStruct *)ssGetOutputPortSignal(S, 0);
    
    pY0[0].sig0 = 'value of this param';
    pY0[0].sig1 = 'value of this param';
    

    然后在mdlInitializeSizes的任何需要使用这个信号的S-Function@你需要

    DTypeId  id;
    id = ssRegisterDataType(S, "customDataType");
    if(id == INVALID_DTYPE_ID) return;
    

    然后,您可以通过使用,在任何其他方法中访问自定义结构,

    myStruct **uPtrs = (myStruct **) ssGetInputPortSignalPtrs(S,0);
    

    然后以通常的方式访问结构的元素,

    firstVar = uPtrs[0]->sig0;
    secondVar = uPtrs[0]->sig1;
    

    这种方法的主要缺点是模型不能用于代码生成(使用 Simulink Coder)。

    【讨论】:

    • 谢谢!但我需要代码生成,因为它必须在外部硬件上运行。这就是我在 c 中做所有这些的原因。也许我应该在我最初的问题中提到它。 dll 方法(通常)是否适用于代码生成?
    • dll 方法应该可以工作,只要您可以为正在使用的平台编译 dll(并编写适当的 .tlc 文件)。
    • 有一件事我不明白:如果我在两个不同的 s 函数中(在任何 mdl 函数之外)声明相同的变量,我会收到关于已定义变量的错误。好的。但是,如果我只在一个 s-function 中声明它们,我会收到一个错误,即变量在一个 s-function 中未定义。这有什么意义?多个 s 函数是否共享相同的变量全局内存?除了 dll-approch 或您的解决方法之外,是否没有办法为 c-s-functions 全局定义变量?这看起来很奇怪。
    • AFAIK 无法在不同的 S-Function(即具有不同功能的 S-Function)之间共享它们。可以(并且相对容易)在同一个 S-Function 的多个实例之间共享它们(但我认为这不是您所要求的)。
    【解决方案2】:

    生成的代码中,在 S-Function 之间共享数据的最简单方法是通过全局变量传递数据,以防 S-Function 是非内联的。

    因为已经定义的变量出现错误,我想您是在目标平台上编译生成的代码。在这种情况下,它是由重复定义引起的——全局变量必须仅在“setup”S-Function 中定义,并在所有其他 S-Function 中使用 extern 关键字声明(这只是目标中的普通 C)。

    在 Simulink 环境中使用 mex 编译 S-Function 时,它不能静态链接到其他 S-Function。虽然可以将多个 S-Function 与同一个外部 C 源文件链接,但在 Simulink 中,可能会获得为每个 S-Funciton 独立创建的相同数据的多个实例。因为 S-Function 是在 Simulink 环境中独立编译和链接的,所以在每个 S-Function 中定义公共全局变量没有意义——您不能将它们外部化,因为它们不会为链接器定义(由 mex 调用)。

    在目标上链接全局变量的明显缺点是您不能使用 Simulink 环境来调试依赖于共享数据的功能。但如果它不是主要功能(例如一些补充日志记录),它可以有条件地包含在您的 S-Function 中的 RT 标志中,仅出现在生成的代码中,从而允许验证 Simulink 中的主要功能。

    【讨论】:

    • 很好的答案,谢谢。即使我问这个问题已经过去了一年,我认为这对很多人来说仍然有用。那时我确实只使用一个 s-function 解决了我的问题,但我可能会看看“extern”方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多