Main Content

Verify Generated Code on NVIDIA Targets Using PIL in Simulink

This example shows how to verify code generated from Simulink® using processor-in-the-loop (PIL) execution on NVIDIA® targets with the MATLAB® Coder™ Support Package for NVIDIA® Jetson™ and NVIDIA DRIVE™ Platforms.

The PIL verification process tests that the behavior of the deployment code matches the design. In a PIL simulation, Simulink runs the generated code on the NVIDIA Jetson board and captures the results to verify the numerical equivalence of the simulation on the host computer and the code generation results.

This example shows how to verify the results of the generated code by using PIL execution for a referenced model and a top model.

Prerequisites

Target Board Requirements

  • NVIDIA Jetson embedded platform.

  • Ethernet crossover cable to connect the target board and host PC. If you can connect the board to a local network, a cable is not required.

  • NVIDIA CUDA® toolkit installed on the board.

  • Environment variables on the target for the compilers and libraries. For more information, see Prerequisites for Generating Code for NVIDIA Boards.

Development Host Requirements

  • Simulink Coder™ for C/C++ code generation.

Connect to NVIDIA Jetson

The MATLAB Coder Support Package for NVIDIA Jetson and NVIDIA DRIVE Platforms uses an SSH connection over TCP/IP to build and run the generated code on Jetson or DRIVE platforms. Connect the target platform to the same network as the host computer or use an Ethernet crossover cable to connect the board directly to the host computer. For information on how to set up and configure your board, see the NVIDIA documentation.

To communicate with the NVIDIA Jetson hardware, create a live hardware connection object by using the jetson function.

hwobj = jetson("jetson-deviceaddress","username","password");

When connecting to the target board for the first time, you must provide the hostname or IP address, username, and password of the target board. On subsequent connections, you do not need to supply the address, username, and password. The Jetson hardware connection object reuses these settings from the most recent successful connection to an NVIDIA board.

hwobj = jetson;
### Checking for CUDA availability on the target...
### Checking for 'nvcc' in the target system path...
### Checking for cuDNN library availability on the target...
### Checking for TensorRT library availability on the target...
### Checking for prerequisite libraries is complete.
### Gathering hardware details...
### Checking for third-party library availability on the target...
### Checking for available I2C buses...
### Gathering hardware details is complete.
Board name              : NVIDIA Jetson AGX Thor Developer Kit
CUDA Version            : 13.0
cuDNN Version           : 9.1
TensorRT Version        : 10.
GStreamer Version       : 1.24.2
V4L2 Version            : 1.26.1-4build3
SDL Version             : 1.2
OpenCV Version          : 4.8.0
Available Webcams       :  
Available GPUs          : NVIDIA Thor
Available Digital Pins  : 

Verify the Generated Code by Using a Model Reference PIL Simulation

To verify generated code for a referenced model, run a PIL simulation by using a Model block. You can use this approach to verify the code for a model without modifying the top model.

In this example, you verify the code for the model CountPeaks. The CountPeaks model contains a MATLAB Function block that counts the number of peaks in an input signal and outputs the result.

open_system("CountPeaks");

CountPeaks model

To configure the model to run on NVIDIA Jetson, open the Configuration Parameters dialog box and, in the Hardware Implementation section, set the Hardware board parameter to NVIDIA Jetson. Alternatively, enter this code in the MATLAB Command Window:

set_param("CountPeaks",HardwareBoard="NVIDIA Jetson");

Open the UsingPilBlock model. The UsingPilBlock model contains a Sine Wave block that passes a sine wave to two Model blocks that both reference the CountPeaks model. To compare the results of normal mode simulation against PIL simulation, you use the Count Peaks block to simulate the model in normal mode and the Count Peaks(PIL) block to simulate the model in PIL mode.

open_system("UsingPilBlock");

UsingPilBlock model. The model has two references to the CountPeaks model that receive input data from the Sine Wave block.

To capture the results from the normal simulation mode and PIL simulation mode, configure the model to log output data.

set_param("UsingPilBlock",SignalLogging="on");
set_param("UsingPilBlock",SignalLoggingName="logsout");

Set the simulation mode of the Count Peaks(PIL) Model block. Right-click the Count Peaks(PIL) block, select Block Parameters, and set the Simulation mode parameter to Processor-in-the-loop (PIL). Alternatively, enter this code in the MATLAB Command Window:

set_param("UsingPilBlock/Count Peaks(PIL)",SimulationMode="Processor-in-the-loop (PIL)");

Run the simulation. Simulink generates code for the CountPeaks model, deploys the code to the NVIDIA Jetson board, and runs both the normal and PIL simulations simultaneously.

out = sim("UsingPilBlock",10);
### Searching for referenced models in model 'UsingPilBlock'.
### Total of 1 models to build.
### Starting serial code generation build.
### Model reference code generation target 'CountPeaks.c' for model 'CountPeaks' might have been out of date. Model or library 'CountPeaks' changed.
### Starting build procedure for: CountPeaks
### Generating code and artifacts to 'Model specific' folder structure
### Code for the model reference code generation target for model CountPeaks is up to date because no functional changes were found in referenced model.
### Saving binary information cache.
### Skipping code compilation for model "CountPeaks".
### Model reference code generation target for CountPeaks is up to date.

Build Summary

0 of 1 models built (1 models already up to date)
Build duration: 0h 0m 2.8054s
### Connectivity configuration for component "CountPeaks": NVIDIA Jetson ###
PIL execution is using Port 17725.
PIL execution is using 30 Sec(s) for receive time-out.
### Preparing to start PIL simulation ...
### Skipping makefile generation and compilation because C:\ExampleManager30cc10\user.Bdoc26a.May13\nvidia-ex89386547\slprj\ert\CountPeaks\coderassumptions\lib\CountPeaks_ca.a is up to date.
### Skipping makefile generation and compilation because C:\ExampleManager30cc10\user.Bdoc26a.May13\nvidia-ex89386547\slprj\ert\CountPeaks\pil\CountPeaks.elf is up to date.
### Starting application: 'slprj\ert\CountPeaks\pil\CountPeaks.elf'
### Launching application CountPeaks.elf...
PIL execution terminated on target.

Plot and compare the results of the normal and PIL simulations. The results match.

simulationOutput = out.logsout{1}.Values.Data;
pilOutput = out.logsout{2}.Values.Data;

fig1 = figure;
subplot(3,1,1), plot(simulationOutput), title("Normal Simulation")
subplot(3,1,2), plot(pilOutput), title("PIL Simulation")
subplot(3,1,3), plot(simulationOutput-pilOutput), ...
title("Difference Between Normal and PIL Simulations")

Figure contains 3 axes objects. Axes object 1 with title Normal Simulation contains an object of type line. Axes object 2 with title PIL Simulation contains an object of type line. Axes object 3 with title Difference Between Normal and PIL Simulations contains an object of type line.

Close the models.

close_system("UsingPilBlock",0);
close_system("CountPeaks",0);

Verify the Generated Code by Using Top-Model PIL Simulation

Alternatively, verify the generated code for the top model by running a PIL simulation. Use this approach to test code generated for the top model or when you want to switch the model between normal and PIL simulation modes.

Open the TopModelPil model. This model contains one Inport block that loads the input signal from MATLAB workspace. The model passes the input signal to a MATLAB function block that counts the number of peaks in the incoming signal. The model logs the number of peaks in the input signal to the MATLAB workspace using the Outport block.

open_system("TopModelPil");

TopModelPil model

Use the set_param function to set the HardwareBoard parameter to NVIDIA Jetson.

set_param("TopModelPil",HardwareBoard="NVIDIA Jetson");

Generate the input stimulus data by using the model stop time and the step size.

StopTime = 10;
StepSize = 0.2;
Input.time = (0:StepSize:StopTime)';
Input.signals.values = sin(Input.time);
Input.signals.dimensions = 1;

Configure the logging options for the model.

set_param("TopModelPil",LoadExternalInput="on");
set_param("TopModelPil",ExternalInput="Input");
set_param("TopModelPil",SignalLogging="on");
set_param("TopModelPil",SignalLoggingName="logsout");
set_param("TopModelPil",SaveOutput="on");
set_param("TopModelPil",OutputSaveName="yout");

Run a normal mode simulation and store the output.

set_param("TopModelPil",SimulationMode="normal");
simOutput = sim("TopModelPil",StopTime);
simulationOutput = simOutput.yout.signals.values;

Run a PIL simulation programmatically by using the sim command.

set_param("TopModelPil",SimulationMode="processor-in-the-loop (pil)");
simOutput = sim("TopModelPil",StopTime);
### Skipped unpacking from Simulink cache file "TopModelPil.slxc" because the relevant build artifacts on disk are up to date.
### Searching for referenced models in model 'TopModelPil'.
### Total of 1 models to build.
### Starting build procedure for: TopModelPil
### Generating code and artifacts to 'Model specific' folder structure
### Generating code into build folder: C:\ExampleManager30cc10\user.Bdoc26a.May13\nvidia-ex89386547\TopModelPil_ert_rtw
### Generated code for 'TopModelPil' is up to date because no structural, parameter or code replacement library changes were found.
### Saving binary information cache.
### Skipping makefile generation and compilation because C:\ExampleManager30cc10\user.Bdoc26a.May13\nvidia-ex89386547\TopModelPil.elf is up to date.
### Successful completion of build procedure for: TopModelPil

Build Summary

0 of 1 models built (1 models already up to date)
Build duration: 0h 0m 4.4711s
### Connectivity configuration for component "TopModelPil": NVIDIA Jetson ###
PIL execution is using Port 17725.
PIL execution is using 30 Sec(s) for receive time-out.
### Preparing to start PIL simulation ...
### Skipping makefile generation and compilation because C:\ExampleManager30cc10\user.Bdoc26a.May13\nvidia-ex89386547\TopModelPil_ert_rtw\coderassumptions\lib\TopModelPil_ca.a is up to date.
### Skipping makefile generation and compilation because C:\ExampleManager30cc10\user.Bdoc26a.May13\nvidia-ex89386547\TopModelPil_ert_rtw\pil\TopModelPil.elf is up to date.
### Starting application: 'TopModelPil_ert_rtw\pil\TopModelPil.elf'
### Launching application TopModelPil.elf...
PIL execution terminated on target.
pilOutput = simOutput.yout.signals.values;

Alternatively, you can run a PIL simulation by using the SIL/PIL Manager. In the Apps tab, under Code Verification, Validation, and Test, select SIL/PIL Manager. In the SIL/PIL tab, set SIL/PIL mode to Processor-in-the-loop (PIL) and click Run Verification to start the PIL simulation.

SIL/PIL tab showing the SIL/PIL mode drop-down and the Run Verification button

The code generator generates, compiles, and runs the code for the model.

Plot and compare the results of the normal and PIL simulations. The results match.

fig = figure;
subplot(3,1,1), plot(simulationOutput), title("Normal Simulation")
subplot(3,1,2), plot(pilOutput), title("PIL Simulation")
subplot(3,1,3), plot(simulationOutput-pilOutput), ...
title("Difference Between Normal and PIL");

Figure contains 3 axes objects. Axes object 1 with title Normal Simulation contains an object of type line. Axes object 2 with title PIL Simulation contains an object of type line. Axes object 3 with title Difference Between Normal and PIL contains an object of type line.

Close the model.

close_system("TopModelPil",0);

See Also

Functions

Objects

Topics