Communicating with an External Application for Co-Simulation
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.
In case you did not know, MathWorks' website lists a lot of third-party modeling and simulation tools from MathWorks Connection Partners.
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.
The Project
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.
ZeroMQ
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.
Installing ZeroMQ
In my opinion, the easiest way to get the library is through GitHub. You will need two GitHub entries: cppzmq and libzmq.
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.
The Client
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.
At the beginning of the simulation, we use mdlSetupRuntimeResources to open the connection with the server. We store in a pointer work vector the information related to this connection.
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.
- Category:
- S-functions,
- Simulation
Comments
To leave a comment, please click here to sign in to your MathWorks Account or create a new one.