Generate FMU from C/C++ Code Using S-Function Builder
This topic shows how to generate an Functional Mockup Unit (FMU) that is compatible with FMI 3.0 standards from your C/C++ code using the S-Function Builder. Use S-Function Builder to integrate your existing C/C++ code into Simulink®. You can then generate an FMU from the S-Function Builder block.
This workflow requires the FMU Builder for Simulink support package.
Generate FMU for First-Order Low Pass Filter
Open Model That Integrates C/C++ Code into Simulink
In this model, we integrate a C++ class that defines a first-order low pass filter into Simulink using an S-Function Builder.
The filter is defined by the following equation,
,
where:
is the cutoff frequency
The filter can be represented in time domain using Tustin Bilinear transform as,
,
,
where:
and are the filter outputs at the current and previous time steps
and are the filter inputs at the current and previous time steps
is the sample time
OutputBusDefinition;
open_system("FirstOrderLowPassFilterSFunctionBuilder.slx");
Integrate C/C++ Code and Build S-Function
Define the first-order low pass filter using C++ code.
class FirstOrderLowPassFilter { private: double cutoffFrequency; double sampleTime; double previousOutput; double previousInput; public: FirstOrderLowPassFilter(double cutoffFrequency, double sampleTime); double computeFilterOutput(double input); };
Define the methods.
#include "FirstOrderLowPassFilter.hpp" FirstOrderLowPassFilter::FirstOrderLowPassFilter(double cutoffFreq, double SampleTime) { cutoffFrequency = cutoffFreq; sampleTime = SampleTime; previousInput = 0.0; previousOutput = 0.0; } double FirstOrderLowPassFilter::computeFilterOutput(double input) { double alpha = (3.14*cutoffFrequency*sampleTime); double output = ((1-alpha)/(1+alpha))*previousOutput + ((alpha)/(1+alpha))*(input + previousInput); previousOutput = output; previousInput = input; return output; }
The model uses the S-Function Builder block to integrate this code into Simulink and implement the low pass filter. Specify the source and header files names and paths in the Libraries table of the S-Function Builder editor.
handle = getSimulinkBlockHandle("FirstOrderLowPassFilterSFunctionBuilder/S-Function Builder"); Simulink.SFunctionBuilder.add(handle,"LibraryItem","LibraryItemTag","INC_PATH",'LibraryItemValue',fullfile(pwd)); Simulink.SFunctionBuilder.add(handle,"LibraryItem","LibraryItemTag","SRC_PATH",'LibraryItemValue',fullfile(pwd)); Simulink.SFunctionBuilder.add(handle,"LibraryItem","LibraryItemTag","ENTRY","LibraryItemValue",'FirstOrderLowPassFilter.cpp'); Simulink.SFunctionBuilder.add(handle,"LibraryItem","LibraryItemTag","ENTRY","LibraryItemValue",'FirstOrderLowPassFilter.hpp');
The S-Function Builder code uses one PWork to store a pointer to the instantiated filter object. The S-Function Builder is configured to have one input and one output port. The input port receives the noisy signal. The output port is configured with a bus data type. The bus output signal gives the filtered and unfiltered signal. The sample time and cutoff frequency are set as parameters with units for the S-Function Builder.
Build the S-Function by clicking Build on the S-Function Builder editor toolstrip or run this code.
Simulink.SFunctionBuilder.build(handle);
Generating 'LowPassFilterSFcn.cpp' ....Please wait Compiling 'LowPassFilterSFcn.cpp' ....Please wait ### 'LowPassFilterSFcn.cpp' created successfully ### 'LowPassFilterSFcn_wrapper.cpp' created successfully ### 'LowPassFilterSFcn.tlc' created successfully ### 'LowPassFilterSFcn_bus.h' created successfully Compile of 'LowPassFilterSFcn.cpp' failed.
Generate FMU from S-Function Builder
Use the exportToFMU
function to generate FMU for the S-Function Builder block. For example, the following command generates a co-simulation FMU compatible with FMI 3.0 standards and adds a description for it.
Simulink.SFunctionBuilder.generateFMU(handle,'FMUType','CS','Description','FirstOrderLowPassFilter');
Generating 'LowPassFilterSFcn.fmu'. .... Please wait. FMU 'LowPassFilterSFcn.fmu' created successfully.
Import and Simulate FMU in Simulink
Use the FMU Import block to import the generated FMU into a Simulink Model.
open_system("FirstOrderLowPassFilterFMU.slx");
The generated FMU has the same port, parameter, and unit configuration as specified in the S-Function Builder editor.
View and specify the parameters SampleTime
and CutoffFrequency
in the Parameters tab of the FMU Import block dialog box.
Simulate the model and observe the FMU output.
output = sim("FirstOrderLowPassFilterFMU.slx"); plotData = figure(1); plot(output.yout{1}.Values,'-r','LineWidth',1.5); hold on; plot(output.yout{2}.Values,'--g','LineWidth',1.5); legend('Filtered Signal','Noisy Signal'); xlabel('Time (s)'); ylabel('Signal Value'); grid minor;
See Also
Simulink.SFunctionBuilder.generateFMU
| Build S-Functions Automatically Using S-Function Builder