4

I am trying to create an s-function in Simulink using s-function builder that will accept a 2d array as an input. In the input ports I specify the dimensions: 2d, rows: 4, columns: 4. When I try to access the input port using f[x][y], it gives an error: "error C2109: subscript requires array or pointer type", for the lines where the input port is adressed.

How can I create an s-function in Simulink with an input port that is a 2d array?

Relevant code:

static void mdlInitializeSizes(SimStruct *S)
{
  DECL_AND_INIT_DIMSINFO(inputDimsInfo);
  DECL_AND_INIT_DIMSINFO(outputDimsInfo);
  ssSetNumSFcnParams(S, NPARAMS);
  if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
  return; /* Parameter mismatch will be reported by Simulink */
  }

  ssSetNumContStates(S, NUM_CONT_STATES);
  ssSetNumDiscStates(S, NUM_DISC_STATES);

  if (!ssSetNumInputPorts(S, NUM_INPUTS)) return;
  /*Input Port 0 */
  inputDimsInfo.width = INPUT_0_WIDTH;
  ssSetInputPortDimensionInfo(S, 0, &inputDimsInfo);
  ssSetInputPortMatrixDimensions( S ,0, INPUT_0_WIDTH, INPUT_DIMS_0_COL);
  ssSetInputPortFrameData(S, 0, IN_0_FRAME_BASED);
  ssSetInputPortDataType(S, 0, SS_DOUBLE);
  ssSetInputPortComplexSignal(S, 0, INPUT_0_COMPLEX);
  ssSetInputPortDirectFeedThrough(S, 0, INPUT_0_FEEDTHROUGH);
  ssSetInputPortRequiredContiguous(S, 0, 1); /*direct input signal access*/

  if (!ssSetNumOutputPorts(S, NUM_OUTPUTS)) return;

  ssSetNumSampleTimes(S, 1);
  ssSetNumRWork(S, 0);
  ssSetNumIWork(S, 0);
  ssSetNumPWork(S, 0);
  ssSetNumModes(S, 0);
  ssSetNumNonsampledZCs(S, 0);

  /* Take care when specifying exception free code – see sfuntmpl_doc.c */
  ssSetOptions(S, (SS_OPTION_EXCEPTION_FREE_CODE |
  SS_OPTION_USE_TLC_WITH_ACCELERATOR |
  SS_OPTION_WORKS_WITH_CODE_REUSE));
}

In mdlOuputs I try to treat f(the port) as a normal array. Example:

x=f[0][0];

This throws the error.

Edit: Well, sort of figured it out.

You set the port dimensions according to the input parameters, then you can address the values using f[x*xw+y], where x and y are the x and y positions(starting with 0) and xw is the number of columns.

Haven't found a better way yet, but this works.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
Savage Reader
  • 387
  • 1
  • 4
  • 16
  • Can you copy paste the code generated by S-Function builder for `mdlInitializeSizes`, `mdlSetInputPortDimensionInfo` & `mdlOutputs` (the part where you're accessing the port)? – Praetorian Jul 17 '12 at 15:37
  • Stackoverflow won't let me post it here, so here is mdlInitializeSizes: http://textsave.de/?p=128363 . There is no mdlSetInputPortDimensionInfo. In mdlOuputs I try to treat f(the port) as a normal array. Example: x=f[0][0]. Which gives an error. – Savage Reader Jul 17 '12 at 16:09

2 Answers2

2

I'm guessing that the S-Function builder is generating code that looks like the following in mdlOutputs:

real_T *y0 = (real_T *)ssGetOutputPortSignal(S, 0);
// OR 
real_T *y0 = ssGetOutputPortRealSignal(S, 0);

With either line y0 is a pointer to a 1-D array, so when you try to access it using 2 subscripts as if it were a 2-D array, the compiler complains.

You can fix it by changing the 2-D indexing to linear indexing as you've posted in the edit. This works perfectly fine, in-fact it is what the compiler would have to do behind the scenes anyway when you index into a 2-D array using 2 subscripts.

The other option is to cast the return value of ssGetInputPortSignal (or ssGetInputPortRealSignal) to a pointer to pointer type.

real_T **y0 = (real_T **)ssGetOutputPortSignal(S, 0);

y0[1][1] = 0;
Praetorian
  • 106,671
  • 19
  • 240
  • 328
1

As you mention in your edit, using linear indexing is in fact the correct way to access matrices in C MEX s-functions. Take a look at mdlOutputs in the sfun_matadd.c s-function example: http://www.ligo.caltech.edu/~rana/mat/Jenne/sfun_matadd.c. The comment in the example code explains it very neatly:

 /* 
 * Note1: Matrix signals are stored in column major order.
 * Note2: Access each matrix element by one index not two indices.
 *        For example, if the output signal is a [2x2] matrix signal,
 *        -          - 
 *       | y[0]  y[2] |
 *       | y[1]  y[3] |
 *       -           -
 *       Output elements are stored as follows:
 *           y[0] --> row = 0, col = 0
 *           y[1] --> row = 1, col = 0
 *           y[2] --> row = 0, col = 1
 *           y[3] --> row = 1, col = 1
 */
gkanwar
  • 461
  • 1
  • 6
  • 12