Struct array with differently sized fields as parameter data for Simulink simulation

4 vues (au cours des 30 derniers jours)
I have CAD files of 3D shapes in obj format. In this format, the shapes are made up of a number of triangles. Using a MATLAB function, I can import data of these shapes into MATLAB. The data are made up of the coordinates of the triangles' vertices, the vector of the triangles' surface normals and the triangles' area. Using the function on one of the files looks like this:
[vertices, surfaceNormals, areas] = objImport('some3dShape.obj');
Now, vertices is a double array of size 3x3xN. N is the number of triangles of this shape and there are three vertices per triangle and each vertex is described by three coordinates. Consequently, surfaceNormals is of size 3xN and areas is of size 1xN.
I want to use these data of multiple shapes in a Simulink simulation. So, I thought, that I could store the data of all shapes nicely in a struct array in the MATLAB workspace before starting the simulation.
shapes = struct();
[shapes(1).vertices, shapes(1).surfaceNormals, shapes(1).areas] = objImport('shape1.obj');
[shapes(2).vertices, shapes(2).surfaceNormals, shapes(2).areas] = objImport('shape2.obj');
[shapes(3).vertices, shapes(3).surfaceNormals, shapes(3).areas] = objImport('shape3.obj');
A MATLAB function block within the Simulink simulation could then access the shapes struct array from the MATLAB workspace as parameter data.
At least, that was the idea. MATLAB can deal with this kind of struct array. However, Simulink throws the error message "Mixed field types in structure arrays are not supported". This only works if all fields with the same name in the struct array have the same size. So, if shapes(1).vertices had size 3x3x100, then shapes(2).vertices would also have to have this size, meaning all shapes must be made up of the same number of triangles.
I am assuming that this error is the same one as described here. So, I am assuming this has to do with the compilation of the simulation into C code.
Possible Solutions I came up with
  1. Create a new struct for every shape (shape1, shape2, ...).
  2. Pad the smaller arrays with zeros and add another field that keeps track of the actual amount of triangles per shape.
Solution 1 has the drawback that I would have to adapt my simulation every time I use a different number of shapes. I wanted to use the struct array so that the MATLAB function block can simply iterate over all struct array items in order to keep the simulation as generic as possible.
Solution 2 seems inefficient. If one of the shapes has a lot of triangles, then the struct array items of the other shapes would also have use up the same amount of memory even if they actually had a lot less triangles.
Are there any other solutions? Is there maybe some pointer-based alternative to struct arrays that does not store the actual data but just a pointer to it? That way the fields would all have the same size (that of a pointer).
  1 commentaire
Friedrich Tuttas
Friedrich Tuttas le 12 Juil 2024
I found a solution that seems to be working for me. Instead of creating a struct array with an item for every shape, I create a single struct and append the arrays of the individual shapes into a big array. So, if I had 4 shapes, my struct shapes would have a field vertices which has a size of 3x3x(N1+N2+N3+N4). The size of the other fields surfaceNormals and areas follow the same principle. Now, I only need to additionally save the initial index for each shape so that I know that e.g. the vertices of shape 3 are located at something like:
current_body_vertices = vertices(:,:,417:529);
In my MATLAB function block within Simulink, I now need to read these indices before accessing the shape data instead of simply iterating over a struct array like I intended before. This results in a few more lines of code, which is fine. However, I am surprised that the Simulink coder is not able to do something like this under the hood itself.

Connectez-vous pour commenter.

Réponse acceptée

Paul
Paul le 12 Juil 2024
Hi Friedrich,
Using 2022a (so there might be some updates in this area if using a later version), the Matlab Fucntion block can use a cell array as the parameter as long as the parameter is not tunable. If that's acceptable, then you can try storing shapes as a cell array of structs
[shapes{1}.vertices, shapes{1}.surfaceNormals, shapes{1}.areas] = objImport('shape1.obj');
[shapes{2}.vertices, shapes{2}.surfaceNormals, shapes{2}.areas] = objImport('shape2.obj');
In the Matlab Function block define shapes as parameter data in the usual way and uncehck the Tunable property under Advanced in the Property Inspector. And then you'll have to update the code in the function to access fields in a shape using brace indexing, e.g.,
v = shapes{ii}.vertices
AFAIK, you can change shapes in the base workspace and those changes will get pulled in on the next run.
There's probably a downside by making that parameter non-tunable in regards to how/when Simulink determines it needs to regenerate the code, but I think it might no be too bad. Check the doc pages, I'm sure there's a page that talks about the diferences between tunable and non-tunable parameters (I hardly ever use non-tunable, so have never really had to worry about it).
  1 commentaire
Friedrich Tuttas
Friedrich Tuttas le 12 Juil 2024
Hello Paul,
That works! While searching for a solution, I did come across cell arrays and Simulink's error message that they cannot be used in tunable parameters. However, I could not find out what "tunable" exactly means or that I can simply switch it off.
Thank you!

Connectez-vous pour commenter.

Plus de réponses (0)

Catégories

En savoir plus sur Simulink Functions dans Help Center et File Exchange

Produits


Version

R2023a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by