是否可以在C MEX S-Function中使用可变大小的信号?

时间:2016-01-18 17:57:33

标签: c matlab simulink

我知道可以使用可变大小的信号编写 Level-2 MATLAB S-Functions。 在 C MEX S-Functions?

中是否也可以这样做?

我的数据在每个时间步都有不同的大小。该要求源自压缩块,其获得固定大小的信号(2D)作为其输入。但是,输出信号(1D / Vector)会在每个mdlOutput()时改变其大小。

1 个答案:

答案 0 :(得分:1)

该问题的评论已经回答: 是的,这是可能的!

这是我的例子:

// Required S-Function header
#define S_FUNCTION_LEVEL 2
#define S_FUNCTION_NAME  sfunc_varsignal

#include "simstruc.h"

enum {INPUT_PORT = 0, NUM_INPUT_PORTS};
enum {OUTPUT_PORT = 0, NUM_OUPUT_PORTS};      

/**
 * "Specify the number of inputs, outputs, states, parameters, and other
 * characteristics of the C MEX S-function"
 */
static void mdlInitializeSizes(SimStruct* S)
{
    boolean_T boolret;
    int_T intret;

    // Parameter
    ssSetNumSFcnParams(S, 0);
    if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S))
    {
        return; // Parameter mismatch will be reported by Simulink
    }

    // Input port
    boolret = ssSetNumInputPorts(S, NUM_INPUT_PORTS);
    if (boolret == 0)
    {
        return;
    }    
    ssSetInputPortDirectFeedThrough(S, INPUT_PORT, 1);    
    intret = ssSetInputPortDimensionInfo(S, INPUT_PORT, DYNAMIC_DIMENSION);
    if (intret == 0)
    {
        ssWarning(S, "Input dimensions could not be set.");
    }
    _ssSetInputPortNumDimensions(S, INPUT_PORT, 1);    

    // Output port
    boolret = ssSetNumOutputPorts(S, NUM_OUPUT_PORTS);
    if (boolret == 0)
    {
        return;
    }

    intret = ssSetOutputPortDimensionInfo(S, OUTPUT_PORT, DYNAMIC_DIMENSION);

    if (intret == 0)
    {
        ssWarning(S, "Output dimensions could not be set.");
    }
    _ssSetOutputPortNumDimensions(S, OUTPUT_PORT, 1);


    // Sample Times
    ssSetNumSampleTimes(S, 1);

    // Dimension Modes of the Ports
    ssSetInputPortDimensionsMode(S, INPUT_PORT, INHERIT_DIMS_MODE);
    ssSetOutputPortDimensionsMode(S, OUTPUT_PORT, INHERIT_DIMS_MODE);
    // This is required for any kind of variable size signal:
    ssSetInputPortRequiredContiguous(S, INPUT_PORT, true);

    ssSetOptions(S, 0);

    // Note: In the doc of ssSetOutputPortWidth it is wriiten:
    // "If the width is dynamically sized, the S-function must provide
    // mdlSetOutputPortDimensionInfo and mdlSetDefaultPortDimensionInfo
    // methods to enable the signal dimensions to be set correctly
    // during signal propagation."
    // However in the example sfun_varsize_concat1D this methods are
    // not present. The function _ssSetOutputPortNumDimensions() may be sufficient
    // This usgae of this function is copied from the example sfcndemo_varsize    
}

#if defined(MATLAB_MEX_FILE)    
/**
 * "Set the width of an input port that accepts 1-D (vector) signals"
 */
#define MDL_SET_INPUT_PORT_WIDTH
static void mdlSetInputPortWidth(SimStruct* S, int_T port, int_T width)
{
    // Set to the sugessted width (e.g. the output width
    // from the connected block)
    ssSetInputPortWidth(S, port, width);

    // Check if the setting was sucessful
    if (ssGetInputPortWidth(S, INPUT_PORT) != DYNAMICALLY_SIZED)
    {
        ssSetOutputPortWidth(S, OUTPUT_PORT, width);
    }
    return;
}    

/**
 * "Set the width of an output port that outputs 1-D (vector) signals"
 */
#define MDL_SET_OUTPUT_PORT_WIDTH
static void mdlSetOutputPortWidth(SimStruct* S, int_T port, int_T width)
{
    // Nothing here, but its required since the output port is set as
    // dynamically sized. But its size is set in mdlSetInputPortWidth()
    UNUSED_ARG(S);
    UNUSED_ARG(port);
    UNUSED_ARG(width);
    return;
}    
#endif //defined(MATLAB_MEX_FILE)

/**
 * "Specify the sample rates at which this C MEX S-function operates"
 */
static void mdlInitializeSampleTimes(SimStruct* S)
{
    ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);
    ssSetOffsetTime(S, 0, 0.0);
    ssSetModelReferenceSampleTimeDefaultInheritance(S);
}

/**
 * "Compute the signals that this block emits."
 */
static void mdlOutputs(SimStruct* S, int_T tid)
{
    UNUSED_ARG(tid);

    const real_T* insignal = ssGetInputPortRealSignal(S, INPUT_PORT);
    auto width = static_cast<const int>(insignal[0]);
    // This function does the trick:
    ssSetCurrentOutputPortDimensions(S, OUTPUT_PORT, 0, width);
    // newWidth should be width
    int_T newWidth = ssGetCurrentOutputPortDimensions(S, OUTPUT_PORT, 0 /* dimension ID */);

    real_T* outsignal = ssGetOutputPortRealSignal(S, OUTPUT_PORT);

    for (int i = 0; i < newWidth; i++)
    {
         *outsignal++ = i+1;
    }
}

/**
 * "Perform any actions required at termination of the simulation"
 */
static void mdlTerminate(SimStruct* S)
{
    UNUSED_ARG(S);
}

// Required S-function trailer    
#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */
#include "simulink.c"      /* MEX-file interface mechanism */
#else
#include "cg_sfun.h"       /* Code generation registration function */
#endif