Today I am describing an example that I recently submitted to MATLAB Central and GitHub with the help of my colleague Haihua Feng: Example implementation of Co-simulation using Simulink.
Many of them offer the option to do Co-simulation with Simulink. With such solutions, those third-party tools allow their users to design part of their algorithms in the third-party tool (usually a specialized domain for which MathWorks does not have a dedicated toolbox), and part of it in Simulink (for example designing a controller for which you want to generate embedded code).
If you are the author of such a tool or would like to integrate your tool in Simulink for co-simulation, I recommend going through this post in details.
Once you have downloaded the submission from MATLAB Central or cloned it from GitHub, open the Simulink Project SimulinkCoSimulationExample.prj. In the Shortcuts tab, you will notice that I added shortcuts to help you go through the steps you will need to follow to run the examples.
Those steps include:
- Download and build the ZeroMQ library
- Build a co-simulation server executable
- Build a S-function to communicate with the server executable
Let's look at those steps in more details.
To implement the communication between Simulink and the other software, we decided to use a library named ZeroMQ. I could try myself to describe what ZeroMQ is, but I thought the best would be to quote the ZeroMQ manual description of how it began:
We took a normal TCP socket, injected it with a mix of radioactive isotopes stolen from a secret Soviet atomic research project, bombarded it with 1950-era cosmic rays, and put it into the hands of a drug-addled comic book author with a badly-disguised fetish for bulging muscles clad in spandex. Yes, ZeroMQ sockets are the world-saving superheroes of the networking world.
See the full manual for more details.
In MATLAB, if you already have set up Git source control, you can clone the repositories from the Current Folder browser. If you prefer, you can also simply clone the repositories by calling the Git command-line client directly from the MATLAB prompt.
Once this is done, you need to build the library. For that, you will need a compiler. In my case, I used Microsoft Visual Studio 2015, so I launched the command prompt from Visual Studio:
I navigated to the build folder of libzmq and executed the provided build batch script:
As you can imagine, there are many ways of building the library for various OS and compilers, see the ZMQ documentation for the options available for your particular setup.
Once the library has been built, it needs to be added to the system path. If you are in my Simulink Project, the shortcut SetEnvVariable will do it using the setenv function.
The Server Application
The next step is creating a server app. In this example, the server app implements a simple algorithm: an exponentially weighted moving average. At every time step, Simulink will send data to the server, the server will do some math and send the results back to Simulink.
The main file of the server app is statcalserver.cpp. If you go through the code, what you will find is a simple example that first binds to a socket (a specific IP address and port). Then it goes in a loop where it waits for a request from the client. When a request comes in, it decodes the data associated with it, processes it and sends the reply to the client. Here is a snippet of the server code:
In the Simulink Project, look at shortcut buildCoSimExample to see how the mex command can be used to build the server app.
On the Simulink side, the client is implemented using a C-Mex S-function (In fact it is a C++ S-function). Let's look at the most important parts.
One important thing to note is that for maximum performance, we made the input of the S-function non-directfeedthrough. That way the S-Function does not use its input at the current time step to compute its output. As you can imagine, this introduces a delay, but this allows Simulink to not wait for the server to respond before moving forward and execute other blocks in the simulation.
To make that work, we send the request to the server after all block outputs have been computed, in mdlUpdate.
and at the next time step, in mdlOutput we retrieve the response from the server and output it.
Finally, when the simulation is over we close the connection in mdlCleanupRuntimeResources
In the Simulink Project, look at shortcut buildCoSimExample to see how the mex command can be used to build the S-Function.
To learn more about the available callback methods in an S-Function and when they are called, I recommend looking at Simulink Engine Interaction with C S-Functions.
The Final Result
As mentioned above, in the Simulink Project I created shortcuts to MATLAB scripts to help with all the steps leading to here.
Once you have the libzmq DLL built and on the OS path, the server executable built, and the S-function mexed and on the MATLAB path, you should be able to launch the server. In the Simulink Project, you can use shortcut startCoSimServer, which will execute the following code:
With the server running, we can finally simulate the example model clientModel.slx and observe the results:
Now it's your turn
If you are considering implementing a co-simulation with an external application, give a try to this technique and let us know how that goes in the comments below.
4 CommentsOldest to Newest
For anyone interested i was able to build the .dll s using Visual Studio 2017 and VisualGDB CMake import functionality. As a compiler only MinGW 64 based TDM-GCC-64 was able to compile (Gcc 5.01 based)
@Timofte: Thank you for sharing. I heard from others that the CMake is a good way to build the zeroMQ library.
Once again thanks for your interesting post.
On a slightly related topic:
Have you used the new FMU import capability of Matlab since 2017b?
I find its a hidden gem of a feature.
Unfortunately there is no code generation support (embedded coder) – any thoughts or tips on how to go about this?
Thanks a lot!
@Rajesh Kallur: You are correct that the FMU Import feature does not support code generation. We are working on that for a future release. I would be curious to hear which type of target you are interested in. If the FMU only contains a dynamic library (DLL), would you expect the generated code to load and call this DLL?