C++
A header-only core as a single struct — one object, one call per sample.
<name>_deployableCore.hpp<name>_testbench.cppCMakeLists.txt
DeployableCore core; core.execute_blocks();
g++ or clang
double
306 of 308
The whole core is a struct in one header, so adopting it is an include and a member. Params, signals, inputs and state are all members you can read and write directly; there is no wrapper class to learn and nothing to link.
The generated CMakeLists.txt builds the testbench as-is, which makes the
exported folder a working project rather than a pile of sources to wire up yourself.
What the export looks like
Every target page shows the same model, so the ten are directly comparable:
an input, an error junction, a gain of 1.8, a discrete plant
0.4z⁻¹ / (1 − 0.6z⁻¹), an output — and the plant's
output fed back into the junction. Five blocks, in a diagram the
export-verification suite calls DPT_Feedback_Discrete — which is where the names
in the file come from. Below is what Deploy writes for this target, with only the
file's header banner removed.
DPT_Feedback_Discrete_deployableCore.hpp
#pragma once #include <array> #include <cmath> #include <cstddef> #include <iostream> // Fixed-size matrix: R rows x C cols, stack/struct-allocated (no heap) template <std::size_t R, std::size_t C> using Mat = std::array<std::array<double, C>, R>; // Tunable parameters (editable from the testbench) struct Params { Mat<1, 1> blk2_gain = {{ {{1.8}} }}; }; // External inputs: set these before execute_blocks; each top-level input gate // copies its field into signal storage. struct Inputs { Mat<1, 1> sig0 {}; }; // Generated signal storage - one fixed-size matrix per output port struct Signals { // sig0: ICore Blocks/Home/DPT_Feedback_Discrete/In1/ICoreDouble-Out-0 Mat<1, 1> sig0 {}; // sig1: ICore Blocks/Home/DPT_Feedback_Discrete/Error/ICoreDouble-Out-0 Mat<1, 1> sig1 {}; // sig2: ICore Blocks/Home/DPT_Feedback_Discrete/Ctrl_Gain/ICoreDouble-Out-0 Mat<1, 1> sig2 {}; // sig3: ICore Blocks/Home/DPT_Feedback_Discrete/Plant/ICoreDouble-Out-0 Mat<1, 1> sig3 {}; // sig4: ICore Blocks/Home/DPT_Feedback_Discrete/ICoreDouble-Out-0 Mat<1, 1> sig4 {}; Inputs inputs {}; }; // blk0: ICore Blocks/Home/DPT_Feedback_Discrete/In1 struct Blk0 { void solve(Signals& signals, const Params& params) { (void)params; signals.sig0 = signals.inputs.sig0; } }; // blk1: ICore Blocks/Home/DPT_Feedback_Discrete/Error struct Blk1 { void solve(Signals& signals, const Params& params) { (void)params; Mat<1, 1> output {}; auto in0 = signals.sig0; for (std::size_t i = 0; i < output.size(); i++) { for (std::size_t j = 0; j < output[0].size(); j++) { output[i][j] += in0[i][j]; } } auto in1 = signals.sig3; for (std::size_t i = 0; i < output.size(); i++) { for (std::size_t j = 0; j < output[0].size(); j++) { output[i][j] -= in1[i][j]; } } signals.sig1 = output; } }; // blk2: ICore Blocks/Home/DPT_Feedback_Discrete/Ctrl_Gain struct Blk2 { void solve(Signals& signals, const Params& params) { auto gain = params.blk2_gain; auto input = signals.sig1; Mat<1, 1> output {}; for (std::size_t i = 0; i < output.size(); i++) { for (std::size_t j = 0; j < output[0].size(); j++) { output[i][j] = input[i][j] * gain[0][0]; } } signals.sig2 = output; } }; // blk3: ICore Blocks/Home/DPT_Feedback_Discrete/Plant struct Blk3 { double u_hist[1][1][2] {}; double y_hist[1][1][1] {}; void solve(Signals& signals, const Params& params) { static constexpr double num[2] = {0, 0.40000000000000002}; static constexpr double den[1] = {-0.59999999999999998}; auto input = signals.sig2; for (std::size_t r = 0; r < 1; r++) { for (std::size_t c = 0; c < 1; c++) { const double uk = input[r][c]; for (std::size_t k = 1; k > 0; k--) u_hist[r][c][k] = u_hist[r][c][k - 1]; u_hist[r][c][0] = uk; double yk = 0.0; for (std::size_t i = 0; i < 2; i++) yk += num[i] * u_hist[r][c][i]; for (std::size_t i = 0; i < 1; i++) yk -= den[i] * y_hist[r][c][i]; y_hist[r][c][0] = yk; signals.sig3[r][c] = yk; } } } }; // blk4: ICore Blocks/Home/DPT_Feedback_Discrete/Out1 struct Blk4 { void solve(Signals& signals, const Params& params) { (void)params; signals.sig4 = signals.sig3; } }; // Deployable core: owns params, signals and every stateful block instance struct DeployableCore { Params params {}; Signals signals {}; Blk0 blk0 {}; Blk1 blk1 {}; Blk2 blk2 {}; Blk3 blk3 {}; Blk4 blk4 {}; // Execution order generated automatically from block diagram void execute_blocks() { // blk0: ICore Blocks/Home/DPT_Feedback_Discrete/In1 blk0.solve(signals, params); // blk1: ICore Blocks/Home/DPT_Feedback_Discrete/Error blk1.solve(signals, params); // blk2: ICore Blocks/Home/DPT_Feedback_Discrete/Ctrl_Gain blk2.solve(signals, params); // blk3: ICore Blocks/Home/DPT_Feedback_Discrete/Plant blk3.solve(signals, params); // blk4: ICore Blocks/Home/DPT_Feedback_Discrete/Out1 blk4.solve(signals, params); } };
The same core as one struct per block, with std::array for every matrix.
Parameters carry their diagram values as member initialisers — blk2_gain is
1.8 the moment the object exists — so there is no init call to forget, and the
whole thing still fits in a header you can include from anywhere.
How it is checked
Every one of the ten targets is verifiable, and this one is no exception: the export is compiled with the toolchain above, run across the simulation window, and compared against the solver sample by sample. Software targets pass at around 1e-11 % against a 0.1 % tolerance; the HDL targets are bounded by their fixed-point quantum instead. See verification.
See also: Code export · Multi-target, multi-rate deploy
See it run on your own model.
Download the application from the customer portal, or read the documentation first — the manual, every block with its measured response, and the full command reference are public.