Main Content

Verify Generated Code on NVIDIA Targets Using PIL in Simulink

Since R2020b

This example shows how to verify code generated from Simulink® using processor-in-the-loop (PIL) execution on NVIDIA® targets using 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 a generated PIL block and by simulating a top model using PIL execution.

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 execute commands while building and running the generated code on the 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 host name or IP address, user name, and password of the target board. On subsequent connections, you do not need to supply the address, user name, 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...
### Gathering hardware details is complete.
Board name              : NVIDIA Jetson Nano Developer Kit
CUDA Version            : 10.2
cuDNN Version           : 8.2
TensorRT Version        : 8.2
GStreamer Version       : 1.14.5
V4L2 Version            : 1.14.2-1
SDL Version             : 1.2
OpenCV Version          : 4.1.1
Available Webcams       :  
Available GPUs          : NVIDIA Tegra X1
Available Digital Pins  : 7  11  12  13  15  16  18  19  21  22  23  24  26  29  31  32  33  35  36  37  38  40

Verify the Generated Code by Using a PIL Block

You can generate a PIL block from a subsystem to verify that the results of the simulation match the generated code. This approach allows you to verify the code for an individual subsystem.

Note

To maintain your original subsystem, do not save your model after replacing the subsystem with the generated PIL block.

Open the UsingPilBlock model. The model contains a Sine Wave block that passes a sine wave to two MATLAB Function blocks that count the number of peaks from the incoming signal.

open_system("UsingPilBlock");

UsingPilBlock model

In the MATLAB Command Window, Use the set_param function to set the HardwareBoard parameter to NVIDIA Jetson.

set_param("UsingPilBlock","HardwareBoard","NVIDIA Jetson");

To compare the normal and PIL simulations, configure the logging options in the model to log output data.

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

To configure the build process to create the PIL block for verification, in the MATLAB Command Window, set the CreateSILPILBlock configuration parameter to PIL.

set_param("UsingPilBlock","CreateSILPILBlock","PIL");

Alternatively, you can configure the model to create a PIL block by opening the Configuration Parameters dialog box, and then, under the Code Generation > Verification section, set the Create Block parameter to PIL.

Configuration Parameters dialog showing the Create block parameter

Create a PIL block from the Count Peaks MATLAB Function block using the slbuild command. Alternatively, you can right-click on the Count Peaks MATLAB Function block and select C/C++ Code > Deploy this Subsystem to Hardware option.

After the build process completes, a new model opens containing only the generated PIL block.

slbuild("UsingPilBlock/Count Peaks")
### Searching for referenced models in model 'Count0'.
### Total of 1 models to build.
### Starting build procedure for: Count0
### Generating code and artifacts to 'Model specific' folder structure
### Generating code into build folder: /var/tmp/ExampleManager30cc10/user.Dec04/nvidia-ex89386547/Count0_ert_rtw
### Generated code for 'Count0' 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 /var/tmp/ExampleManager30cc10/user.Dec04/nvidia-ex89386547/Count0.elf is up to date.
### Successful completion of build procedure for: Count0
### Creating PIL block ...
### Connectivity configuration for "/var/tmp/ExampleManager30cc10/user.Dec04/nvidia-ex89386547/Count0_ert_rtw": NVIDIA Jetson ###
PIL execution is using Port 17725.
PIL execution is using 30 Sec(s) for receive time-out.

Build Summary

0 of 1 models built (1 models already up to date)
Build duration: 0h 0m 13.065s

Replace the existing Count Peaks(PIL) block in the model with the newly generated PIL block.

existingBlock = "UsingPilBlock/Count Peaks(PIL)";
blockPosition = get_param(existingBlock,"Position");
delete_block(existingBlock);
add_block("untitled/Count Peaks",existingBlock,...
          "Position", blockPosition);
close_system("untitled",0);
clear existingBlock blockPosition

Run the PIL simulation.

out = sim("UsingPilBlock",10);
### Connectivity configuration for "/var/tmp/ExampleManager30cc10/user.Dec04/nvidia-ex89386547/Count0_ert_rtw": NVIDIA Jetson ###
PIL execution is using Port 17725.
PIL execution is using 30 Sec(s) for receive time-out.
### Preparing to start PIL block simulation: UsingPilBlock/Count Peaks(PIL) ...
### Using toolchain: GNU GCC for NVIDIA Embedded Processors
### '/var/tmp/ExampleManager30cc10/user.Dec04/nvidia-ex89386547/Count0_ert_rtw/pil/Count0.mk' is up to date.
### Building 'Count0': make  -f Count0.mk -j4 all
### Starting application: 'Count0_ert_rtw/pil/Count0.elf'
### Launching application Count0.elf...
Runtime log on Target:
[sudo] password for ubuntu:
PIL execution terminated on target.

Double-click the Numerical Difference block to see the difference between the simulation output and the PIL block output that ran on the 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-simulationOutput), ...
    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.

To change the number of peaks, you can modify the frequency of the wave using the Sine Wave block and compare the output from the simulation and PIL blocks.

Close the model.

close_system("UsingPilBlock",0);

Verify the Generated Code by Using Top-Model PIL Simulation

Alternatively, you can verify the generated code for a Simulink 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: /var/tmp/ExampleManager30cc10/user.Dec04/nvidia-ex89386547/TopModelPil_ert_rtw
### Generated code for 'TopModelPil' is up to date because no structural, parameter or code replacement library changes were found.
### Skipping makefile generation and compilation because /var/tmp/ExampleManager30cc10/user.Dec04/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 2.8409s
### 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 ...
### Using toolchain: GNU GCC for NVIDIA Embedded Processors
### '/var/tmp/ExampleManager30cc10/user.Dec04/nvidia-ex89386547/TopModelPil_ert_rtw/pil/TopModelPil.mk' is up to date.
### Building 'TopModelPil': make  -f TopModelPil.mk -j4 all
### Starting application: 'TopModelPil_ert_rtw/pil/TopModelPil.elf'
### Launching application TopModelPil.elf...
Runtime log on Target:
[sudo] password for ubuntu:
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