Main Content

Work with MATLAB Structure Arrays

In MATLAB®, you can create struct arrays by dynamically assigning field names and values. In contrast, C++ is a statically typed language that requires all fields of a struct and their types to be declared upfront. This discussion uses the example Deploy MATLAB Function That Accepts Struct Array as Input Argument to explain how to handle MATLAB structs in C++ code.

Struct Input

In MATLAB, struct arrays can be created by dynamically assigning field names and values. C++ being a statically typed language requires all fields of a struct and their types to be declared upfront.

When C++ code calls a MATLAB function that requires a MATLAB struct as input, the struct must be explicitly created in C++ using appropriate data types through the MATLAB Data API. For example:

% MATLAB
data = struct();
data.temperatures = [72, 75, 69, 68, 70];
data.pressures = [30, 29.5, 30.2, 29.9, 30.1];
// C++
matlab::data::ArrayFactory factory;
matlab::data::TypedArray<double> temperatures = factory.createArray<double>({ 5 }, { 72, 75, 69, 68, 70 });
matlab::data::TypedArray<double> pressures = factory.createArray<double>({ 5 }, { 30, 29.5, 30.2, 29.9, 30.1 });
matlab::data::StructArray inputStruct = factory.createStructArray({ 1 }, { "temperatures", "pressures" });
inputStruct[0]["temperatures"] = temperatures;
inputStruct[0]["pressures"] = pressures;
  • An ArrayFactory object named factory is created. This object is used to create MATLAB data arrays in C++. It's a factory class that provides methods to create various types of MATLAB data arrays.

  • The matlab::data::TypedArray<T> class in the MATLAB Data API is a template class designed to represent arrays of a specific type <T> in C++ code that interact with MATLAB. This class allows C++ programs to create arrays that are compatible with MATLAB data types, facilitating the exchange of data between C++ and MATLAB environments.

    Two TypedArray<double> objects, temperatures and pressures, are created using the factory object. Each call to factory.createArray<double>() specifies the array dimensions and initializes the array with given values. Here, both arrays are 1-dimensional with 5 elements each, representing temperature and pressure data, respectively.

  • A StructArray named inputStruct is created, again using the factory object. The createStructArray method is called with two arguments:

    • The first specifies the dimensions of the struct array. In this case, a 1x1 struct array.

    • The second is an initializer list of strings that define the field names of the struct: "temperatures" and "pressures".

  • Finally, the fields of the first (and only) struct in inputStruct are populated with the temperatures and pressures arrays. The syntax inputStruct[0]["temperatures"] accesses the "temperatures" field of the first struct and assigns the temperatures array to it. Similarly, the "pressures" field is populated with the pressures array.

Struct Output

When a MATLAB function called from C++ returns a MATLAB struct, it is returned as a matlab::data::Array in the C++ code. To retrieve the field names and field values, some processing is necessary. For example:

// Function to print the MATLAB computation results
void printMatlabResults(matlab::data::Array outputArray) {
    matlab::data::StructArray structArray = outputArray;
    auto topLevelStructFieldNamesIterable = structArray.getFieldNames();
    std::vector<matlab::data::MATLABFieldIdentifier> 
        topLevelStructFieldNames(topLevelStructFieldNamesIterable.begin(), topLevelStructFieldNamesIterable.end());

    for (const matlab::data::MATLABFieldIdentifier& fieldName : topLevelStructFieldNames) {
        std::string outerFieldName(fieldName);
        std::cout << "Field: " << outerFieldName << std::endl;

        matlab::data::TypedArrayRef<matlab::data::Struct> nestedStruct = outputArray[0][fieldName];
        
        auto nestedStructFieldNamesIterable = nestedStruct.getFieldNames();
        std::vector<matlab::data::MATLABFieldIdentifier> 
			nestedStructFieldNames(nestedStructFieldNamesIterable.begin(), nestedStructFieldNamesIterable.end());
        for (const matlab::data::MATLABFieldIdentifier& fieldName : nestedStructFieldNames) {
            std::string innerFieldName(fieldName);
            matlab::data::TypedArrayRef<double> fieldValue = nestedStruct[0][fieldName];

            double value = fieldValue[0];
            std::cout << "  " << innerFieldName << ": " << std::fixed << std::setprecision(4) << value << std::endl;
        }
    }
}

  • The MATLAB struct returned from the MATLAB function as a matlab::data::Array needs to be converted to a matlab::data::StructArray. Direct access to the struct fields is not available.

    matlab::data::StructArray structArray = outputArray;
    
  • Retrieve the iterable of field names from the struct array.

    auto topLevelStructFieldNamesIterable = structArray.getFieldNames();
    std::vector<matlab::data::MATLABFieldIdentifier> 
         topLevelStructFieldNames(topLevelStructFieldNamesIterable.begin(), topLevelStructFieldNamesIterable.end());
    
  • Use a loop to process each field in the struct. This involves accessing each field by name and processing its contents.

    for (const matlab::data::MATLABFieldIdentifier& fieldName : topLevelStructFieldNames) {
        std::string outerFieldName(fieldName);
        std::cout << "Field: " << outerFieldName << std::endl;
        ...
    }
    
  • If the fields themselves contain structs, repeat the process of getting field names and iterating over them.

    matlab::data::TypedArrayRef<matlab::data::Struct> nestedStruct = outputArray[0][fieldName];
    auto nestedStructFieldNamesIterable = nestedStruct.getFieldNames();
    std::vector<matlab::data::MATLABFieldIdentifier> 
         nestedStructFieldNames(nestedStructFieldNamesIterable.begin(), nestedStructFieldNamesIterable.end());
    

Related Topics