Main Content

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,

H(s)=(ωcutoffs+ωcutoff),

where:

ωcutoff is the cutoff frequency

The filter can be represented in time domain using Tustin Bilinear transform as,

yk=(1-α1+α)yk-1+(α1+α)[uk+uk-1],

α=(ωcutoffTs2),

where:

yk and yk-1 are the filter outputs at the current and previous time steps

uk and uk-1 are the filter inputs at the current and previous time steps

Ts 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.

SFB_editor_lowPassFilter.png

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.

SFB_FMU_Import_Output.png

View and specify the parameters SampleTime and CutoffFrequency in the Parameters tab of the FMU Import block dialog box.

SFB_FMU_Import_Parameters.png

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; 

Figure contains an axes object. The axes object with title Time Series Plot:<FilteredSignal>, xlabel Time (s), ylabel Signal Value contains 2 objects of type stair. These objects represent Filtered Signal, Noisy Signal.

See Also

|