This example shows how to generate code for a MATLAB algorithm that runs a simulation of bouncing "atoms" and returns the result after a number of iterations. There are no upper bounds on the number of atoms that the algorithm accepts, so this example takes advantage of dynamic memory allocation.
There are no prerequisites for this example.
run_atoms
FunctionThe run_atoms.m
function runs a simulation of bouncing atoms (also applying gravity and energy loss).
help run_atoms
atoms = run_atoms(atoms,n) atoms = run_atoms(atoms,n,iter) Where 'atoms' the initial and final state of atoms (can be empty) 'n' is the number of atoms to simulate. 'iter' is the number of iterations for the simulation (if omitted it is defaulted to 3000 iterations.)
Create a code generation configuration object
cfg = coder.config; % Enable dynamic memory allocation for variable size matrices. cfg.DynamicMemoryAllocation = 'AllVariableSizeArrays';
Create a template structure 'Atom' to provide the compiler with the necessary information about input parameter types. An atom is a structure with four fields (x,y,vx,vy) specifying position and velocity in Cartesian coordinates.
atom = struct('x', 0, 'y', 0, 'vx', 0, 'vy', 0);
Use the command codegen
with the following arguments:
-args {coder.typeof(atom, [1 Inf]),0,0}
indicates that the first argument is a row vector of atoms where the number of columns is potentially infinite. The second and third arguments are scalar double values.
-config cfg
enables dynamic memory allocation, defined by workspace variable cfg
codegen run_atoms -args {coder.typeof(atom, [1 Inf]),0,0} -config cfg -o run_atoms_mex
The MEX function simulates 10000 atoms in approximately 1000 iteration steps given an empty list of atoms. The return value is the state of all the atoms after simulation is complete.
atoms = repmat(atom,1,0); atoms = run_atoms_mex(atoms,10000,1000)
Iteration: 50
Iteration: 100
Iteration: 150
Iteration: 200
Iteration: 250
Iteration: 300
Iteration: 350
Iteration: 400
Iteration: 450
Iteration: 500
Iteration: 550
Iteration: 600
Iteration: 650
Iteration: 700
Iteration: 750
Iteration: 800
Iteration: 850
Iteration: 900
Iteration: 950
Iteration: 1000 Completed iterations: 1000
atoms=1×10000 struct array with fields:
x
y
vx
vy
Continue the simulation with another 500 iteration steps
atoms = run_atoms_mex(atoms,10000,500)
Iteration: 50
Iteration: 100
Iteration: 150
Iteration: 200
Iteration: 250
Iteration: 300
Iteration: 350
Iteration: 400
Iteration: 450
Iteration: 500 Completed iterations: 500
atoms=1×10000 struct array with fields:
x
y
vx
vy
To generate a C library, create a standard configuration object for libraries:
cfg = coder.config('lib');
Enable dynamic memory allocation
cfg.DynamicMemoryAllocation = 'AllVariableSizeArrays';
In MATLAB the default data type is double. However, integers are usually used in C code, so pass int32
integer example values to represent the number of atoms and iterations.
codegen run_atoms -args {coder.typeof(atom, [1 Inf]),int32(0),int32(0)} -config cfg
When creating a library the code is generated in the folder codegen/lib/run_atoms/
. The code in this folder is self contained. To interface with the compiled C code you need only the generated header files and the library file.
dir codegen/lib/run_atoms
. rtGetNaN.o run_atoms_emxAPI.o .. rt_nonfinite.c run_atoms_emxutil.c .gitignore rt_nonfinite.h run_atoms_emxutil.h buildInfo.mat rt_nonfinite.o run_atoms_emxutil.o codeInfo.mat rtw_proj.tmw run_atoms_initialize.c codedescriptor.dmr rtwtypes.h run_atoms_initialize.h compileInfo.mat run_atoms.a run_atoms_initialize.o defines.txt run_atoms.c run_atoms_ref.rsp examples run_atoms.h run_atoms_rtw.mk interface run_atoms.o run_atoms_terminate.c rtGetInf.c run_atoms_data.c run_atoms_terminate.h rtGetInf.h run_atoms_data.h run_atoms_terminate.o rtGetInf.o run_atoms_data.o run_atoms_types.h rtGetNaN.c run_atoms_emxAPI.c rtGetNaN.h run_atoms_emxAPI.h
Typically, the main function is platform-dependent code that performs rendering or some other processing. In this example, a pure ANSI-C function produces a file run_atoms_state.m
which (when run) contains the final state of the atom simulation.
type run_atoms_main.c
/* Include standard C libraries */ #include <stdio.h> /* The interface to the main function we compiled. */ #include "codegen/exe/run_atoms/run_atoms.h" /* The interface to EMX data structures. */ #include "codegen/exe/run_atoms/run_atoms_emxAPI.h" int main(int argc, char **argv) { FILE *fid; int i; emxArray_Atom *atoms; /* Main arguments unused */ (void) argc; (void) argv; /* Initially create an empty row vector of atoms (1 row, 0 columns) */ atoms = emxCreate_Atom(1, 0); /* Call the function to simulate 10000 atoms in 1000 iteration steps */ run_atoms(atoms, 10000, 1000); /* Call the function again to do another 500 iteration steps */ run_atoms(atoms, 10000, 500); /* Print the result to a file */ fid = fopen("atoms_state.txt", "w"); for (i = 0; i < atoms->size[1]; i++) { fprintf(fid, "%f %f %f %f\n", atoms->data[i].x, atoms->data[i].y, atoms->data[i].vx, atoms->data[i].vy); } /* Close the file */ fclose(fid); /* Free memory */ emxDestroyArray_Atom(atoms); return(0); }
cfg = coder.config('exe'); cfg.DynamicMemoryAllocation = 'AllVariableSizeArrays';
You must pass the function (run_atoms.m
) as well as custom C code (run_atoms_main.c
) The codegen
command automatically generates C code from the MATLAB code, then calls the C compiler to bundle this generated code with the custom C code (run_atoms_main.c
).
codegen run_atoms run_atoms_main.c -args {coder.typeof(atom, [1 Inf]),int32(0),int32(0)} -config cfg
After simulation is complete, this produces the file atoms_state.txt
. The TXT file is a 10000x4 matrix, where each row is the position and velocity of an atom (x, y, vx, vy) representing the current state of the whole system.
system(['.' filesep 'run_atoms']);
Running the executable produced atoms_state.txt
. Now, recreate the structure array from the saved matrix:
load atoms_state.txt -ascii clear atoms for i = 1:size(atoms_state,1) atoms(1,i).x = atoms_state(i,1); atoms(1,i).y = atoms_state(i,2); atoms(1,i).vx = atoms_state(i,3); atoms(1,i).vy = atoms_state(i,4); end
Call run_atoms_mex
with zero iterations to render only.
run_atoms_mex(atoms, 10000, 0);