Create S-Function Using S-Function Builder API
This example shows how to programmatically configure an S-Function Builder block to integrate an external C Code and generate an S-function from the configuration specifications. In this example, the C code computes position and velocity for a mass attached to a spring and damper. The mass-spring-damper system is represented using a set of discrete-state differential equations.
Set up the Model
This section shows how you can create and configure the model sfcnbuilderapi
. When you run this example for the first time, create the model using new_system
function.
However, if the model already exists in your working folder, use clear mex
followed by delete sfcnbuilderapi.slx mySFcn.mexw64
in your command line before creating the new model. Also, close the model if it is open from a previous MATLAB® session.
mdl = "sfcnbuilderapi";
new_system(mdl);
Add an S-Function Builder block.
add_block('simulink/User-Defined Functions/S-Function Builder',[gcs,'/S-Function Builder']);
Obtain the block handle blk
. This block handle is used to configure the S-Function Builder block.
blk = getSimulinkBlockHandle('sfcnbuilderapi/S-Function Builder');
Configure S-Function Builder Block
The configuration of the S-Function Builder block involves setting up the S-function, adding states and parameters, and setting the build options for the S-Function Builder block.
Set up S-function
Set the name of the S-function to mySFcn
.
Simulink.SFunctionBuilder.setSFunctionName(blk,'mySFcn');
Specify the settings for the block. The array layout for the code is column major, the sample mode is discrete, and the sample time is 0.1 s.
Simulink.SFunctionBuilder.setSettings(blk, ArrayLayout= "Column", SampleMode="Discrete", SampleTime= 0.1, DirectFeedthrough=true, CodeReuseSupport = false); Simulink.SFunctionBuilder.setTargetLanguage(blk,'c');
Add S-Function Builder Block States and Parameters
Add two discrete states, state and velocity.
Simulink.SFunctionBuilder.add(blk,'DiscreteState', InitialCondition="1"); %% Position Simulink.SFunctionBuilder.add(blk,'DiscreteState', InitialCondition="0"); %% Velocity
The state-space representation of the mass-spring damper system in discrete-time is:
where the vectors , and are the state, input and output vectors at time.
For this example, mass is 3.6 kg, spring constant is 400 N/m, and damping coefficient is 10 N-s/m. In this workflow, the system matrix () and input array () values are obtained using c2d
(System Identification Toolbox) function.
Add the parameter values.
Simulink.SFunctionBuilder.add(blk,'Parameter', Name = "A", DataType= "double", Value ="[0.5369 0.07204; -8.004 0.3368]"); Simulink.SFunctionBuilder.add(blk,'Parameter', Name = "B", DataType= "double", Value ="[0.001158; 0.02001]"); Simulink.SFunctionBuilder.add(blk,'Parameter', Name = "C", DataType= "double", Value ="[1 0]"); Simulink.SFunctionBuilder.add(blk,'Parameter', Name = "D", DataType= "double", Value ="0");
Specify Code for S-function Methods
Add output code. This section of code determines output value of the S-function.
OL = "y0[0]= C[0]*xD[0]+C[1]*xD[1]+D[0]*u0[0];"; Simulink.SFunctionBuilder.setUserCode(blk,"output",OL);
Add update code. This code computes the state value at every time step of simulation.
U1 = "real_T tempX[2] = {0.0,0.0};" + newline + "tempX[0] = A[0]*xD[0]+ A[2]*xD[1]+ B[0]*u0[0];"+ newline + "tempX[1]= A[1]*xD[0]+ A[3]*xD[1]+ B[1]*u0[0];" + newline + "xD[0] = tempX[0];" + newline + "xD[1] = tempX[1];"; U1 = U1 + newline + "tempX[1]= A[1]*xD[0]+ A[3]*xD[1]+ B[1]*u0[0];" + newline + "xD[0] = tempX[0];" + newline + "xD[1] = tempX[1];"; Simulink.SFunctionBuilder.setUserCode(blk,"update", U1);
Specify Build Options for S-Function Builder Block
In this example, the build steps are not logged and the debugging information are not included in the generated MEX file. However, you can log build steps by changing the value of ShowCompileSteps
to true
and include the debugging information in the generated MEX file by changing the value of CreateDebuggableMEX
to true
.
Simulink.SFunctionBuilder.setBuildOptions (blk, "ShowCompileSteps",false,"CreateDebuggableMEX",false,"GenerateWrapperTLC",true); Simulink.SFunctionBuilder.build(blk);
Generating 'mySFcn.c' ....Please wait ### Output folder is '/tmp/Bdoc25a_2864802_2681706/tp6aebe4b0/simulink_general-ex62441600' ### 'mySFcn.c' created successfully ### 'mySFcn_wrapper.c' created successfully ### 'mySFcn.tlc' created successfully Compiling 'mySFcn.c' ....Please wait ### S-function 'mySFcn.mexa64' created successfully
Configure Simulation Environment
Add source and sink blocks.
add_block('simulink/Sources/Step',[gcs,'/Input']); % Step block add_block('simulink/Sinks/Scope',[gcs,'/Output']); % Scope block that displays the system response myScopeConfiguration = get_param('sfcnbuilderapi/Output','ScopeConfiguration'); myScopeConfiguration.OpenAtSimulationStart = true;
Position the input and output blocks relative to the S-Function Builder block.
h = getSimulinkBlockHandle('sfcnbuilderapi/S-Function Builder'); pos = get_param(h,'Position'); pos = [pos(1)*2 pos(2)*2 pos(3)*2 pos(4)*2]; set_param('sfcnbuilderapi/S-Function Builder','Position',pos); posStep = [pos(1)-200 pos(2) pos(3)-200 pos(4)]; %% Position of the Step block relative to the S-Function Builder block set_param('sfcnbuilderapi/Input','Position',posStep); posScope = [pos(1)+200 pos(2) pos(3)+200 pos(4)]; %% Position of the Scope block relative to the S-Function Builder block set_param('sfcnbuilderapi/Output','Position',posScope);
Connect the S-Function Builder block to a Step block.
srcIn = 'sfcnbuilderapi/Input'; dstIn = 'sfcnbuilderapi/S-Function Builder'; Simulink.connectBlocks(srcIn,dstIn);
Connect the S-Function Builder block to a Scope block.
srcOut = 'sfcnbuilderapi/S-Function Builder'; dstOut = 'sfcnbuilderapi/Output'; Simulink.connectBlocks(srcOut,dstOut);
Simulate Open-Loop Model
To create the test environment, connect a Step block to the input port (u0
) and a Scope block to display the output (y0
). Simulate the model and visualize the open-loop step response to the system.
save_system ("sfcnbuilderapi") outOL = sim("sfcnbuilderapi");
Update Open-Loop Model to Closed-Loop Model
A controller is designed using place
(Control System Toolbox) function to place poles that reduce the setting time of the system. Update the S-Function Builder block parameters.
Simulink.SFunctionBuilder.update(blk,"Parameter",Name="A",FieldToUpdate="Value",NewValue ="[0.8632 0.07103; -2.415 0.437]"); Simulink.SFunctionBuilder.update(blk,"Parameter",Name="B",FieldToUpdate="Value",NewValue ="[0.001117; 0.01973]"); Simulink.SFunctionBuilder.update(blk,"Parameter",Name="C",FieldToUpdate="Value",NewValue ="[1 0]"); Simulink.SFunctionBuilder.update(blk,"Parameter",Name="D",FieldToUpdate="Value",NewValue ="[0]");
Simulate Closed-Loop Model
Simulate the model using sim
command and visualize the step response using the Scope block.
outCL = sim("sfcnbuilderapi"); save_system("sfcnbuilderapi");
close_system("sfcnbuilderapi",1);