Model-level debugging: a bridge between control engineering and software engineering

Model-level debugging: a bridge between control engineering and software engineering
Feature articles |
A "model-level" debugger is a debugger that can provide a side-by-side view of a simulation model of a control system (for example defined using Simulink) with the source code produced by an automatic code generator, and allow the developer to use the model instead of the generated source code for setting breakpoints, viewing and updating signal values, and stepping through execution. 
By eeNews Europe


This is similar to how a “source-level” debugger supports debugging using the source code, freeing the user from worrying about the details of the assembly-level code.

Screen capture of the QGen model-level debugger.

A model-level debugger that is based on an underlying source-level debugger can also be used for testing systems that combine auto-generated and hand-written code, potentially on both the host and on some final target.  Furthermore, presuming a separate simulator for the model, the developer can use such a debugger to perform back-to-back comparisons against signal values logged during simulation, for an individual block, or for a model as a whole, while delving into the details of a particular subsystem as needed.  By displaying the model together with the generated source code, a model-level debugger provides a uniquely productive bridge between control engineering and software engineering.


Interacting with a model-level debugger

A model-level debugger lets you monitor and control the execution of code generated from simulation models, either on the host (“Software in the Loop”, or SIL) or on an embedded target machine (“Processor in the Loop”, or PIL). Such a debugger gives you full control through model-level breakpoints and signal-value displays, helping to connect the software elements to the corresponding modeling elements.

You can combine auto-generated and hand-written code. Both can be debugged together, and a model-level debugger can display the model and its signal values whenever it reaches sections of code that were auto-generated.  If the debugger stops in hand-written code, then only the source code would be displayed.  But if a breakpoint is reached in auto-generated code, then the source code line, and the associated block within the model, can both be displayed.  In effect, model-level debugging keeps the simulation model execution in sync with code execution, by using traceability information built by the automatic code generator.  You can thus analyze the model’s behavior while stepping through the generated source code, or even the final assembly code.

A model-level debugger can also let you alter the values of signals and redirect program execution to force the model to reach a certain state at any point. This effect can be difficult to achieve by merely altering the inputs to the model. If you suspect a problem in one part of the model, you can probe it further without needing to leave the debugger to change the model or craft new input streams.

An important capability of a model-level debugger is to log signal values during a debugger run, and then trace them back to the original block(s) within the model in the simulator. This can help resolve unexpected behavior and let you make any desired changes in the simulator at the identified point in the model.


Cross development using a model-level debugger

Many source-level debuggers support “cross” debugging, where a program can be debugged on a separate target machine, using a network or other connection between the host (where the debugger is running) and the target (where some kind of small-footprint “agent” is running).  This same capability is present in a model-level debugger that incorporates such a cross-debugger. By using the normal cross-compiler toolchain and target interfacing capabilities, together with an appropriate auto code-generator, you can directly cross-compile and run the auto-generated code on a supported platform while debugging at the model level from the host and observing the execution behavior of the target.

Examples of use of a model-level debugger

The simulation model can be displayed and browsed within an IDE, as a read-only view showing all simulation blocks, subsystems, and sub-model references.

Displaying the model in an Integrated Development
Environment (IDE)

You can define the model’s inputs via using the standard simulator capabilities, or even using completely separate models. A model-level debugger can record all inputs provided

Creating input for the target using the simulator.

to the model and create a debugging session where the same inputs are sent, under control of the debugger, to the generated code. The behavior of the model and the generated code with these inputs can then be observed and debugged in sync.

Just as you can insert a breakpoint in the source code, a model-level debugger lets you insert a breakpoint directly from the model view. Execution will subsequently pause when reaching the code corresponding to the block containing the breakpoint.

Inserting a breakpoint on a given block or model



Displaying values for signals dynamically.

By maintaining exact traceability between code variables and their corresponding signals in the simulation model, a model-level debugger can display signal values as they are updated. It can grey out blocks that have been executed, to show which signals have been updated and which still have values from the previous computation cycle.


Changing signal values during the execution.

A model-level debugger provides a powerful way to analyze the specific behavior of a given simulation model. By changing signal values for one or more iterations you can direct the model into a desired state of interest to the debugging session.

A model-level debugger can store in a file all or some signal values obtained during a debug session. When opening this file in the simulator, you then have links to the corresponding simulation block of each signal. This helps trace problems identified at the code level to corresponding model-level blocks, where you can investigate them further in the simulator.

Logging signals and highlighting corresponding
blocks in the simulator.

A model-level debugger shows you how a model-based system performs on the final target, even when combined with hand-written code. You can observe and understand the behavior of the system at multiple levels – the model, the source code, or the assembly code – by stopping at critical points, examining signal values and seeing how they change over time, and stopping within hand-written code as desired. You can thus monitor, test, and debug an entire program, and bridge the gap from the control engineering view of the world of blocks and signals, to the software engineering view of the world of functions and variables. A model-level debugger can help you isolate and identify problems where they are most easily captured, by combining the full power of a low-level debugger with the model-level view of the whole system.

AdaCore has developed a model-level debugger based on the principles outlined above, as part of its QGen Model-Based Development Suite. This is helpful for users who prefer a model-based view of the world, to nevertheless debug problems that only show up on the final target.  Something that was unexpected, is that such a debugger turns out to be helpful for users who are new to model-based development, by showing them the correlation between models and auto-generated code, and connecting modeling concepts with programming concepts, which modeling neophytes may find more accessible.  And finally, the ability to see the same system from multiple viewpoints allows system engineers and software engineers to work together to ensure the overall quality of the delivered model-based system.

About the author:

S. Tucker Taft is Director of Language Research at AdaCore – – He can be reached at

Linked Articles
eeNews Embedded