ICore Blocks / Targets / Industrial

PLC Structured Text

IEC 61131-3 Structured Text: the model as a function block, one call per PLC scan.

Deploy writes
  • <name>_deployableCore.st
  • <name>_testbench.st
One call, one sample

FUNCTION_BLOCK FB_<name> — one call = one scan

Verified with

matiec (iec2c)

Numbers

LREAL

Library blocks

306 of 308

The core is a FUNCTION_BLOCK. Call it once per scan from your program and the model has advanced one sample — the same contract as every other target, expressed the way a PLC expects it. Numbers are LREAL, the ST equivalent of the double the software targets use, so this is a full-precision target and not a fixed-point one.

Structured Text and VHDL are the strictest of the ten about identifiers, and between them they set the naming rules the export applies to all targets — anything outside [A-Za-z0-9] collapses to an underscore, and a leading digit gets a prefix.

Verification compiles the generated ST with matiec (iec2c). If that transpiler is missing, every block fails this column at once — which is the signature to look for before suspecting the generator.

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.st

FUNCTION_BLOCK FB_DPT_Feedback_Discrete
VAR_INPUT
    (* ---- Tunable parameters (set from the testbench: core.<name> := ...) ---- *)
    gain_blk2 : ARRAY[0..0, 0..0] OF LREAL := [LREAL#1.8000000000000000];   (* tunable gain *)
    in_sig0 : ARRAY[0..0, 0..0] OF LREAL;   (* external input: ICore Blocks/Home/DPT_Feedback_Discrete/In1/ICoreDouble-Out-0 *)
END_VAR
VAR_OUTPUT
    (* ---- Signals (observable from the testbench: core.<name>) ---- *)
    sig0 : ARRAY[0..0, 0..0] OF LREAL;   (* ICore Blocks/Home/DPT_Feedback_Discrete/In1/ICoreDouble-Out-0 *)
    sig1 : ARRAY[0..0, 0..0] OF LREAL;   (* ICore Blocks/Home/DPT_Feedback_Discrete/Error/ICoreDouble-Out-0 *)
    sig2 : ARRAY[0..0, 0..0] OF LREAL;   (* ICore Blocks/Home/DPT_Feedback_Discrete/Ctrl_Gain/ICoreDouble-Out-0 *)
    sig3 : ARRAY[0..0, 0..0] OF LREAL;   (* ICore Blocks/Home/DPT_Feedback_Discrete/Plant/ICoreDouble-Out-0 *)
    sig4 : ARRAY[0..0, 0..0] OF LREAL;   (* ICore Blocks/Home/DPT_Feedback_Discrete/ICoreDouble-Out-0 *)
END_VAR
VAR
    (* ---- Persistent block state ---- *)
    (* blk3: ICore Blocks/Home/DPT_Feedback_Discrete/Plant *)
    uh_blk3 : ARRAY[0..0, 0..0, 0..1] OF LREAL := [LREAL#0.0, LREAL#0.0];
    yh_blk3 : ARRAY[0..0, 0..0, 0..0] OF LREAL := [LREAL#0.0];
    y_blk3 : LREAL;
END_VAR

    (* ===== Ordered execution pass (one scan == executeBlocks) ===== *)
    (* blk0: ICore Blocks/Home/DPT_Feedback_Discrete/In1 *)
    sig0[0, 0] := in_sig0[0, 0];

    (* blk1: ICore Blocks/Home/DPT_Feedback_Discrete/Error *)
    sig1[0, 0] := sig0[0, 0] - sig3[0, 0];

    (* blk2: ICore Blocks/Home/DPT_Feedback_Discrete/Ctrl_Gain *)
    sig2[0, 0] := sig1[0, 0] * gain_blk2[0, 0];

    (* blk3: ICore Blocks/Home/DPT_Feedback_Discrete/Plant *)
    (* Discrete transfer function (direct-form IIR) applied per [p,m] entry: rotate u, y = sum num*u - sum den*y *)
    uh_blk3[0, 0, 1] := uh_blk3[0, 0, 0];
    uh_blk3[0, 0, 0] := sig2[0, 0];
    y_blk3 := 0.0;
    y_blk3 := y_blk3 + LREAL#0.0 * uh_blk3[0, 0, 0];
    y_blk3 := y_blk3 + LREAL#0.40000000000000002 * uh_blk3[0, 0, 1];
    y_blk3 := y_blk3 - LREAL#-0.59999999999999998 * yh_blk3[0, 0, 0];
    yh_blk3[0, 0, 0] := y_blk3;
    sig3[0, 0] := y_blk3;

    (* blk4: ICore Blocks/Home/DPT_Feedback_Discrete/Out1 *)
    sig4[0, 0] := sig3[0, 0];
END_FUNCTION_BLOCK

Tunable parameters and the external input are VAR_INPUT, the signals are VAR_OUTPUT, and block state is VAR — so calling the function block once from your program is one scan and one sample, with the state surviving between scans by definition. Note what the emitter does with a 1×1 model: the loops are gone entirely and the pass is a handful of scalar assignments, including the plant's history rotation.

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

Get started

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.