<name>_deployableCore.rs<name>_testbench.rsCargo.toml
core.execute_blocks(&mut self)
rustc / cargo
f64
306 of 308
The export writes a Cargo.toml beside the core and the testbench, so the
folder is a crate: build it, run it, or drop the core module into an existing workspace.
The core is a pub struct whose step function takes &mut self
— the borrow checker sees exactly what it needs to see, because the model's state really is
owned by one object and mutated once per sample.
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.rs
// Tunable parameters (editable from the testbench) pub struct Params { pub blk2_gain: [[f64; 1]; 1], } impl Params { pub fn new() -> Params { Params { blk2_gain: [[1.8_f64]], } } } // External inputs: set these (e.g. from a testbench) before execute_blocks; // each top-level input gate copies its field into signal storage. pub struct Inputs { pub sig0: [[f64; 1]; 1], } impl Inputs { fn new() -> Inputs { Inputs { sig0: [[0.0_f64; 1]; 1], } } } // Generated signal storage - one fixed-size matrix per output port pub struct Signals { // sig0: ICore Blocks/Home/DPT_Feedback_Discrete/In1/ICoreDouble-Out-0 pub sig0: [[f64; 1]; 1], // sig1: ICore Blocks/Home/DPT_Feedback_Discrete/Error/ICoreDouble-Out-0 pub sig1: [[f64; 1]; 1], // sig2: ICore Blocks/Home/DPT_Feedback_Discrete/Ctrl_Gain/ICoreDouble-Out-0 pub sig2: [[f64; 1]; 1], // sig3: ICore Blocks/Home/DPT_Feedback_Discrete/Plant/ICoreDouble-Out-0 pub sig3: [[f64; 1]; 1], // sig4: ICore Blocks/Home/DPT_Feedback_Discrete/ICoreDouble-Out-0 pub sig4: [[f64; 1]; 1], pub inputs: Inputs, } impl Signals { fn new() -> Signals { Signals { sig0: [[0.0_f64; 1]; 1], sig1: [[0.0_f64; 1]; 1], sig2: [[0.0_f64; 1]; 1], sig3: [[0.0_f64; 1]; 1], sig4: [[0.0_f64; 1]; 1], inputs: Inputs::new(), } } } // blk0: ICore Blocks/Home/DPT_Feedback_Discrete/In1 struct Blk0; impl Blk0 { fn new() -> Blk0 { Blk0 } fn solve(&mut self, signals: &mut Signals, _params: &Params) { signals.sig0 = signals.inputs.sig0; } } // blk1: ICore Blocks/Home/DPT_Feedback_Discrete/Error struct Blk1; impl Blk1 { fn new() -> Blk1 { Blk1 } fn solve(&mut self, signals: &mut Signals, _params: &Params) { // Accumulate all inputs element-wise into the fixed-size output let mut output = [[0.0_f64; 1]; 1]; let in0 = signals.sig0; for i in 0..output.len() { for j in 0..output[0].len() { output[i][j] += in0[i][j]; } } let in1 = signals.sig3; for i in 0..output.len() { for j in 0..output[0].len() { output[i][j] -= in1[i][j]; } } signals.sig1 = output; } } // blk2: ICore Blocks/Home/DPT_Feedback_Discrete/Ctrl_Gain struct Blk2 {} impl Blk2 { fn new() -> Blk2 { Blk2 {} } fn solve(&mut self, signals: &mut Signals, params: &Params) { let gain = params.blk2_gain; let input = signals.sig1; let mut output = [[0.0_f64; 1]; 1]; for i in 0..output.len() { for j in 0..output[0].len() { output[i][j] = input[i][j] * gain[0][0]; } } signals.sig2 = output; } } // blk3: ICore Blocks/Home/DPT_Feedback_Discrete/Plant struct Blk3 { u_hist: [[[f64; 2]; 1]; 1], y_hist: [[[f64; 1]; 1]; 1], } impl Blk3 { fn new() -> Blk3 { Blk3 { u_hist: [[[0.0; 2]; 1]; 1], y_hist: [[[0.0; 1]; 1]; 1] } } fn solve(&mut self, signals: &mut Signals, _params: &Params) { let num: [f64; 2] = [0_f64, 0.40000000000000002_f64]; let den: [f64; 1] = [-0.59999999999999998_f64]; let _ = &den; let input = signals.sig2; for r in 0..1 { for c in 0..1 { let uk = input[r][c]; for k in (1..2).rev() { self.u_hist[r][c][k] = self.u_hist[r][c][k - 1]; } self.u_hist[r][c][0] = uk; let mut yk = 0.0_f64; for i in 0..2 { yk += num[i] * self.u_hist[r][c][i]; } for i in 0..1 { yk -= den[i] * self.y_hist[r][c][i]; } self.y_hist[r][c][0] = yk; signals.sig3[r][c] = yk; } } } } // blk4: ICore Blocks/Home/DPT_Feedback_Discrete/Out1 struct Blk4; impl Blk4 { fn new() -> Blk4 { Blk4 } fn solve(&mut self, signals: &mut Signals, _params: &Params) { signals.sig4 = signals.sig3; } } // Deployable core: owns params, signals and every stateful block instance pub struct DeployableCore { pub params: Params, pub signals: Signals, blk0: Blk0, blk1: Blk1, blk2: Blk2, blk3: Blk3, blk4: Blk4, } impl DeployableCore { pub fn new() -> DeployableCore { DeployableCore { params: Params::new(), signals: Signals::new(), blk0: Blk0::new(), blk1: Blk1::new(), blk2: Blk2::new(), blk3: Blk3::new(), blk4: Blk4::new(), } } // Execution order generated automatically from block diagram pub fn execute_blocks(&mut self) { // blk0: ICore Blocks/Home/DPT_Feedback_Discrete/In1 self.blk0.solve(&mut self.signals, &self.params); // blk1: ICore Blocks/Home/DPT_Feedback_Discrete/Error self.blk1.solve(&mut self.signals, &self.params); // blk2: ICore Blocks/Home/DPT_Feedback_Discrete/Ctrl_Gain self.blk2.solve(&mut self.signals, &self.params); // blk3: ICore Blocks/Home/DPT_Feedback_Discrete/Plant self.blk3.solve(&mut self.signals, &self.params); // blk4: ICore Blocks/Home/DPT_Feedback_Discrete/Out1 self.blk4.solve(&mut self.signals, &self.params); } }
Each block is a struct holding its own state, with a
solve(&mut Signals, &Params); the core owns all five and takes
&mut self once per sample. Look at Blk3: the plant's
u_hist and y_hist live inside the block rather than in a global, so
ownership matches the model and the borrow checker never has to be worked around.
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.