主要内容

Synchronize MATLAB Structure with Structure Type in Generated Code

When you generate C or C++ code from a MATLAB® entry-point function that uses a structure, you often need to create an instance of the MATLAB structure in the generated code that you can pass to custom external functions. You must keep the generated structure definition synchronized with changes in the MATLAB structure.

This example shows how to address these requirements by:

  • Defining a constructor entry-point function that returns the structure.

  • Using coder.OutputType to pass the output of the constructor function to other entry-point functions.

This approach allows you to:

  • Use a single source for the structure layout.

  • Propagate changes in structure layout to other entry points.

  • Create a valid instance of the structure in the generated code with one C or C++ call.

  • Maintain consistency between the MATLAB structure and the generated structure type by updating the constructor and regenerating code.

Examine MATLAB Structure

This nested structure contains data from multiple sensors, of multiple types, across multiple experiments.

experimentStruct:
   .experimentID: [1x1 double]
   .modality: [1x1 struct]
      .type: SensorType.EEG
      .sensorData: [1x1 struct]
         .sensorID: [1x1 double]
         .dataGroup: [1x1 struct]
            .groupID: [1x1 double]
            .data: [:100x:100 double]

For this example, assume that many of your MATLAB functions use this structure, and that you use this structure in your external C++ code. You want all of these applications to use the same type definition, and you want to propagate changes to this structure definition to other entry-point functions and the generated code.

Define Constructor Function

Examine the constructor function, which generates the experimentStruct structure. The function takes an input argument named dataMatrix and uses coder.varsize to specify that the dataMatrix field of the experimentStruct is a variable-size array with an upper bound of 100-by-100. The function uses coder.cstructname to name the structure types in the generated code.

type experimentStructTypeConstructor.m
function experimentStructType = experimentStructTypeConstructor(dataMatrix)
coder.varsize("experimentStruct.modality.sensorData.dataGroup.data",[100 100],[true true]);
dataStruct = struct("groupID",0,"data",dataMatrix);
sensorStruct = struct("sensorID",0,"dataGroup",dataStruct);
modalityStruct = struct("type",SensorType.EEG,"sensorData",sensorStruct);
experimentStruct = struct("experimentID",0,"modality",modalityStruct);
coder.cstructname(experimentStruct,"expStructType");
coder.cstructname(experimentStruct.modality,"modalityStructType");
coder.cstructname(experimentStruct.modality.sensorData,"sensorDataStructType");
coder.cstructname(experimentStruct.modality.sensorData.dataGroup,"dataGroupStructType");
experimentStructType = experimentStruct;
end

Examine Additional Entry-Point Functions

For this example, assume that your MATLAB code includes two different functions that take the experimentStruct as an input argument.

Examine the function addData. This function populates the structure with information about the experiment number, sensor type, sensor ID, and experimental data.

type addData.m
function out = addData(expStruct,expID,senType,senID,grpID,sampleData)
expStruct.experimentID = expID;
expStruct.modality.type = senType;
expStruct.modality.sensorData.sensorID = senID;
expStruct.modality.sensorData.dataGroup.groupID = grpID;
expStruct.modality.sensorData.dataGroup.data = sampleData;
out = expStruct;
end

Examine the function averageData. This function calculates the average of each column of the data matrix in the structure.

type averageData.m
function out = averageData(expStruct)
out = mean(expStruct.modality.sensorData.dataGroup.data);
end

Generate and Examine C++ Code

Generate code for the entry-point functions experimentStructTypeConstructor, addData, and averageData by using the codegen command. Use the -config:lib option to generate standalone code and the -lang:c++ option to generate C++. Use coder.OutputType to specify the output of the constructor function as an input to the addData and averageData functions and use coder.typeof to specify that the input to the constructor function is a variable-size matrix with a maximum size of 100-by-100.

structType = coder.OutputType("experimentStructTypeConstructor");
dataType = coder.typeof(0,[100 100],[true true]);
sensorType = coder.typeof(SensorType.EEG);

codegen -config:lib -lang:c++ experimentStructTypeConstructor -args {dataType} ...
    addData -args {structType,0,sensorType,0,0,dataType} ...
    averageData -args {structType}
Code generation successful.

Examine the generated type definitions. The generated code defines the nested structure only once. The name of the generated structure type for the top-level structure is ExpStructType and the name of the generated structure type for the nested sensor data structure is sensorDataStructType.

file = fullfile("codegen","lib","experimentStructTypeConstructor", ...
    "experimentStructTypeConstructor_types.h");
coder.example.extractLines(file,"struct ","#endif",1,0)
struct dataGroupStructType {
  double groupID;
  coder::array<double, 2U> data;
};

struct sensorDataStructType {
  double sensorID;
  dataGroupStructType dataGroup;
};

struct modalityStructType {
  SensorType type;
  sensorDataStructType sensorData;
};

struct expStructType {
  double experimentID;
  modalityStructType modality;
};

See Also

| | |

Topics