By Jakob Engblom
There are many ways to use simulation in model-based design (MBD) of control systems. In a typical MBD workflow, it is common to model a controller (essentially the electronic “brain” of the system) along with the plant it is designed to control (“plant” is the common term for a model of the physical system and its environment). The starting point is the creation of the model of the controller and the plant in a modeling tool. It is then common to run simulations inside the modeling tool with simulated inputs and outputs to test the design as it evolves. As the project progresses, the controller model will need to migrate to the real electronic system of software and hardware, while the plant model will be replaced by real physical systems and tested in the real environment. Both the computer and the physical parts of the end product have to be built, and while they are being developed there is a need to ensure that their realization stays in-line with the design created in the model. During this process, more concrete simulation is needed for the control computer part, to allow the ideal controller to be realized as real code running on top of a real computer.
Simics is often used to run target-processor code for the controller, while the modeling tool is used to simulate the plant. Through these simulation setups the team developing the product can validate that their software and target hardware system is behaving in same way as the design model. These simulator integrations or co-simulations have typically been custom solutions based on user-created integrations using Simics’ extendable architecture. However, we have recently created a ready-to-use package for the specific case of processor-in-the-loop (PIL) simulation with Mathworks Simulink and Embedded Coder, providing a solution that is not dependent on custom integration work, and which can be used earlier in the design flow compared to a full co-simulation setup.
The purpose of PIL testing is to make sure that the code generated from a controller model will run correctly on the actual processor that will be used in the final target system. Prior to PIL testing, control algorithms will have been developed and validated on the host, using high-precision floating point and with no concern for the implementation system. PIL is used to test the code that is generated from the controller model (using Embedded Coder in this case), as it is compiled for a particular target processor. The Simics-Simulink PIL integration makes the process of running on a real processor painless, and obviates the need for any physical hardware beyond the host machine.
As shown above, in PIL testing the plant model is running in the Simulink modeling environment, while the controller is turned into target code and compiled to run on the real target system. This allows the user to verify that the code generation, compilation to the target system using the target system compiler, and execution with the actual integer and floating-point semantics of the target system do not introduce errors in the control system. The results of the hardware runs are compared against the results obtained on the host, allowing the modeler to validate that the generated code will provide correct results. However, running on a physical hardware system can be difficult. Configuring a system to the point where a PIL run can be performed requires a bit of work, typically setting up a network connection and installing an operating system and a target-side agent to handle code download on the target hardware. It is necessary to have a system available in the first place, and this is often a limited resource. Development boards might not be a perfect match for the final target system, and communications with a final target system could be complicated and unreliable.
With the Simics-based PIL solution, every developer can have their own target system with no limitations or need to queue up to use one of a few shared systems. Starting a PIL run with Simics is completely automatic, and there is no need to configure or even be aware of the precise nature of the target system. Once the solution is installed, all a user needs to do is to configure the model to generate code for the real target, and then select “PIL” as the simulation mode in the Simulink toolbar, as shown in the picture above.
Pressing “Run” will build the target software and start Simics for a quick run like this, where the Simics windows show up briefly as tests are run on the Simics target.
In detail, when the Run button is pressed for a Simulink model configured for PIL is that the controller part of the model is used to generate target code using the Embedded Coder product. The generated code is then compiled using the configured target compiler, combined with a test framework that manages inputs and outputs library and linked with a Simics target support library. Once the binary is built, a Simics process is started by Simulink, and the binary loaded into Simics for execution. The flow looks like this:
The Simulink test bench drives the simulation by sending input values to the controller code running on Simics, and retrieving the output values sent back by the controller code as they are computed. It is worth noting that the code on the Simics target does not need an operating system to run and communicate with Simulink. Instead, the Simics setup uses a module in Simics to communicate with Simulink. This module then communicates with the target software over a special device. The target system we use is a Simics quick-start platform (QSP), which provides a simple and stable system for running code on the processor.
After the run, Simulink lets you inspect the simulation results and check that the values computed in the ideal simulation and when run on the Simics-simulated real processor agree. The Simulink data inspector provides several ways to compare signals. In the example shown below, we have run the same model with Simics (first run) and then using a “Normal” simulation setting. As you can see, the waveforms for the counter overlap perfectly, and the difference is zero across the entire run. This is the best possible case, where the code generation and compilation for the real target did not affect the results at all.
Another nice feature made possible by Simics is profiling of the target code running on Simics. The special device present in the Simics virtual platform to facilitate the communication also provides a register that reads out the count of instructions executed, and this makes it easy to measure the execution time of the code. The below example shows how the execution of the step function in the standard Simulink rtwdemo_sil_counter demo setup takes more time for certain steps. Even with the simplified timing model used by Simics processor models, it is possible to find bottlenecks and timing jitter in the generated code.
The PIL integration is somewhat different from the typical integration or co-simulation of Simics and physics simulators that I have described before (see “Cyberphysical Simics”). In a co-simulation setup, the goal is to validate the integrated system and not just the controller. A co-simulation setup uses models of the real inputs and outputs of the physical control computer, rather than the shortcut employed in PIL, and it runs a complete software stack with operating system and device drivers. It is a complementary approach to PIL, and typically both would be used in a project, but in different phases of the project execution. As a final note, it is worth pointing out that the approach to PIL simulation we have taken here with Simics is yet another example of using a virtual platform to simplify tasks that would by necessity be more complicated on physical hardware. It demonstrates how easy it is to automate running Simics from another program, and how to work faster with a virtual platform thanks to shortcuts and application-specific back doors.