ICore Blocks / Targets / Software

Rust.rs

A crate you can cargo run the moment it lands on disk.

Software Verified with rustc / cargo f64 800 of 806 blocks
DPT_Feedback_Discrete_deployableCore.rs
✓ verified · 0.1 %
// 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);
    }
}

What Deploy writes for the reference model below, with only the file's header banner removed. 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.

Export · Verify · Integrate

From the diagram to your Rust build.

Deploy writes the folder, ICore checks it against the simulation, and your code calls it once per sample.

01 · ExportICore

Deploy writes

  • <name>_deployableCore.rs
  • <name>_testbench.rs
  • Cargo.toml
→ code/<name>/
02 · VerifyICore

Built, run and compared

Built with rustc / cargo, run across the simulation window and compared with the solver sample by sample, against a 0.1 % tolerance.

observed ≈1e-11 %
03 · IntegrateYour build

One call, one sample

Numbers are f64, and 800 of 806 library blocks export to Rust.

core.execute_blocks()
With verification on, a failed comparison stops the export and says why, so a core that disagrees with the simulation never reaches your folder.
Software target

Where Rust fits.

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.

$ Code Engine → Code Export Verifier → Verify All
Target classToleranceObserved
Software · 7 languages0.1 %≈1e-11 %
HDL · Q16.161 %≈1e-3 %
Rust runs the same double-precision arithmetic as the solver, so anything above noise would be a real defect. Passing runs measure about 1e-11 %. See verification.
The reference model

One model, ten targets.

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 and an output, with the plant's output fed back into the junction. The export-verification suite calls it DPT_Feedback_Discrete - which is where the names in the file come from.

DPT_Feedback_Discrete · 5 blocks
In1 Σ + − Error × 1.8 Ctrl_Gain 0.4z⁻¹ 1 − 0.6z⁻¹ Plant Out1 the previous sample, fed back
Get started

See it run on your own model.

Download the application from the customer portal, or read the documentation first - the manual, a page for every block, and the full command reference are public.