Skip to content
LIBRARY
Continuous.LimPIDExternalDerivative.md

Continuous.LimPIDExternalDerivative

PID controller with limited output, anti-windup, and an external derivative input.

A variant of LimPID where the internal filtered derivative block is removed entirely. Instead, the derivative contribution is supplied externally via the u_d input, which feeds directly into the PID summation with no internal filtering or differentiation. The derivative passed to the derivative input should be that of the control error u_s - u_m, potentially applying set-point weighting. To use a derivative of the measurement signal only, the gain should be -1, i.e., pass the derivative of -u_m.

Use this component when the derivative signal is already available from the plant (e.g., a velocity sensor, a model state, or an observer output) and internal numerical differentiation is unnecessary or undesirable.

The output is:

y=k[ep+1Tis(e+ysatyNiTi)+ud]+kffuff

where e_p = w_p \cdot u_s - u_m, e = u_s - u_m, and u_d is the externally supplied derivative signal passed through without modification.

This component extends from BlockComponents.Interfaces.SingleVariableController

Usage

BlockComponents.Continuous.LimPIDExternalDerivative(k=1, Ti=0.5, y_max=1e300, y_min=-y_max, wp=1, Ni=0.9, k_ff=1, xi0=0)

Parameters:

NameDescriptionUnitsDefault value
kGain of controller1
TiTime constant of the integrator blocks0.5
y_maxMaximum output1e+300
y_minMinimum output-y_max
wpSet-point weight for proportional block1
NiNi*Ti is time constant of anti-windup compensation0.9
k_ffGain of the feed-forward input1
xi0Initial guess value for integrator output0

Connectors

  • u_s - This connector represents a real signal as an input to a component (RealInput)

  • u_m - This connector represents a real signal as an input to a component (RealInput)

  • y - This connector represents a real signal as an output from a component (RealOutput)

  • u_ff - This connector represents a real signal as an input to a component (RealInput)

  • u_d - This connector represents a real signal as an input to a component (RealInput)

Variables

NameDescriptionUnits
control_error

Behavior

[connect(addp+y,proportional+u)connect(addi+y,integrator+u)connect(proportional+y,addpid+u1)connect(integrator+y,addpid+u3)connect(addpid+y,gainpid+u)connect(gainpid+y,addff+u1)connect(addff+y,limiter+u)connect(limiter+y,addsat+u1)connect(addsat+y,gaintrack+u)connect(gaintrack+y,addi+u3)connect(addff+y,addsat+u2)connect(limiter+y,y)connect(addff+u2,uff)connect(addpid+u2,ud)connect(addp+u1,us)connect(addi+u1,us)connect(addp+u2,um)connect(addi+u2,um)addp.y(t)=addp.k1addp.u1(t)+addp.k2addp.u2(t)addi.y(t)=addi.k1addi.u1(t)+addi.k2addi.u2(t)+addi.k3addi.u3(t)proportional.y(t)=proportional.kproportional.u(t)dintegrator.x(t)dt=integrator.kintegrator.u(t)integrator.y(t)=integrator.x(t)addpid.y(t)=addpid.k1addpid.u1(t)+addpid.k2addpid.u2(t)+addpid.k3addpid.u3(t)gainpid.y(t)=gainpid.kgainpid.u(t)addff.y(t)=addff.k1addff.u1(t)+addff.k2addff.u2(t)limiter.y(t)=clamp(limiter.u(t),limiter.ymin,limiter.ymax)addsat.y(t)=addsat.k1addsat.u1(t)+addsat.k2addsat.u2(t)gaintrack.y(t)=gaintrack.kgaintrack.u(t)]

Source

dyad
"""
PID controller with limited output, anti-windup, and an external derivative input.

A variant of `LimPID` where the internal filtered derivative block is removed entirely.
Instead, the derivative contribution is supplied externally via the `u_d` input, which
feeds directly into the PID summation with no internal filtering or differentiation.
The derivative passed to the derivative input should be that of the control error
`u_s - u_m`, potentially applying set-point weighting. To use a derivative of the
measurement signal only, the gain should be -1, i.e., pass the derivative of `-u_m`.

Use this component when the derivative signal is already available from the plant
(e.g., a velocity sensor, a model state, or an observer output) and internal
numerical differentiation is unnecessary or undesirable.

The output is:

math y = k \left[e_p + \dfrac{1}{T_is}\left(e + \dfrac{y_{sat} - y}{N_iT_i}\right) + u_d \right] + k_{ff}u_


where `e_p = w_p \cdot u_s - u_m`, `e = u_s - u_m`, and `u_d` is the externally
supplied derivative signal passed through without modification.
"""
component LimPIDExternalDerivative
  extends BlockComponents.Interfaces.SingleVariableController
  "Feed-forward input"
  u_ff = RealInput() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "input", "x1": 450, "y1": -100, "x2": 550, "y2": 0, "rot": 90}
      },
      "tags": []
    }
  }
  "External derivative input"
  u_d = RealInput() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "input", "x1": 450, "y1": 1000, "x2": 550, "y2": 1100, "rot": -90}
      },
      "tags": []
    }
  }
  add_p = BlockComponents.Math.Add(k1 = wp, k2 = -1) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 100, "y1": 100, "x2": 200, "y2": 200, "rot": 0},
        "diagram": {"iconName": "input", "x1": 80, "y1": 100, "x2": 180, "y2": 200, "rot": 0}
      },
      "tags": []
    }
  }
  add_i = BlockComponents.Math.Add3(k2 = -1) {
    "Dyad": {
      "placement": {"icon": {"iconName": "input", "x1": 100, "y1": 500, "x2": 200, "y2": 600}}
    }
  }
  proportional = BlockComponents.Math.Gain(k = 1) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 300, "y1": 100, "x2": 400, "y2": 200, "rot": 0},
        "diagram": {"iconName": "input", "x1": 260, "y1": 100, "x2": 360, "y2": 200, "rot": 0}
      },
      "tags": []
    }
  }
  integrator = Integrator(k = 1 / Ti, x0 = xi0) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 300, "y1": 500, "x2": 400, "y2": 600, "rot": 0},
        "diagram": {"iconName": "input", "x1": 260, "y1": 500, "x2": 360, "y2": 600, "rot": 0}
      },
      "tags": []
    }
  }
  add_pid = BlockComponents.Math.Add3() {
    "Dyad": {
      "placement": {"icon": {"iconName": "input", "x1": 500, "y1": 300, "x2": 600, "y2": 400}}
    }
  }
  gain_pid = BlockComponents.Math.Gain(k = k) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 700, "y1": 300, "x2": 800, "y2": 400, "rot": 0},
        "diagram": {"iconName": "input", "x1": 540, "y1": 100, "x2": 640, "y2": 200, "rot": 0}
      },
      "tags": []
    }
  }
  add_ff = BlockComponents.Math.Add(k2 = k_ff) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 900, "y1": 300, "x2": 1000, "y2": 400, "rot": 0},
        "diagram": {"iconName": "input", "x1": 700, "y1": 130, "x2": 800, "y2": 230, "rot": 0}
      },
      "tags": []
    }
  }
  limiter = BlockComponents.Nonlinear.Limiter(y_max = y_max, y_min = y_min) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 1100, "y1": 300, "x2": 1200, "y2": 400, "rot": 0},
        "diagram": {"iconName": "input", "x1": 840, "y1": 130, "x2": 940, "y2": 230, "rot": 0}
      },
      "tags": []
    }
  }
  add_sat = BlockComponents.Math.Add(k1 = 1, k2 = -1) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 1100, "y1": 500, "x2": 1200, "y2": 600, "rot": 90},
        "diagram": {"iconName": "input", "x1": 830, "y1": 290, "x2": 930, "y2": 390, "rot": 90}
      },
      "tags": []
    }
  }
  gain_track = BlockComponents.Math.Gain(k = 1 / (k * Ni)) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 500, "y1": 700, "x2": 600, "y2": 800, "rot": 180},
        "diagram": {"iconName": "input", "x1": 260, "y1": 690, "x2": 360, "y2": 790, "rot": 180}
      },
      "tags": []
    }
  }
  variable control_error::Real
  "Gain of controller"
  parameter k::Real = 1
  "Time constant of the integrator block"
  parameter Ti::Time = 0.5
  "Maximum output"
  parameter y_max::Real = 1e300
  "Minimum output"
  parameter y_min::Real = -y_max
  "Set-point weight for proportional block"
  parameter wp::Real = 1
  "`Ni*Ti` is time constant of anti-windup compensation"
  parameter Ni::Real = 0.9
  "Gain of the feed-forward input"
  parameter k_ff::Real = 1
  "Initial guess value for integrator output"
  parameter xi0::Real = 0
relations
  connect(add_p.y, proportional.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(add_i.y, integrator.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(proportional.y, add_pid.u1) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 450, "y": 150}, {"x": 450, "y": 320}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(integrator.y, add_pid.u3) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 450, "y": 550}, {"x": 450, "y": 380}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(add_pid.y, gain_pid.u) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [
            {"x": 630, "y": 350},
            {"x": 630, "y": 260},
            {"x": 500, "y": 260},
            {"x": 500, "y": 150}
          ],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(gain_pid.y, add_ff.u1) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(add_ff.y, limiter.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(limiter.y, add_sat.u1) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 970, "y": 180}, {"x": 970, "y": 250}, {"x": 910, "y": 250}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(add_sat.y, gain_track.u) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 880, "y": 740}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(gain_track.y, add_i.u3) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 75, "y": 740}, {"x": 75, "y": 580}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(add_sat.u2, add_ff.y) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 850, "y": 245}, {"x": 820, "y": 245}, {"x": 820, "y": 180}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(limiter.y, y) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 970, "y": 180}, {"x": 970, "y": 500}, {"x": 1050, "y": 500}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(add_ff.u2, u_ff) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 670, "y": 210}, {"x": 670, "y": 70}, {"x": 500, "y": 70}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(add_pid.u2, u_d) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 410, "y": 350}, {"x": 410, "y": 860}, {"x": 500, "y": 860}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(add_p.u1, u_s) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 20, "y": 120}, {"x": 20, "y": 270}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(add_i.u1, u_s) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 20, "y": 520}, {"x": 20, "y": 270}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(add_p.u2, u_m) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 50, "y": 180}, {"x": 50, "y": 730}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(add_i.u2, u_m) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 50, "y": 550}, {"x": 50, "y": 730}], "E": 2}],
      "renderStyle": "standard"
    }
  }
metadata {
  "Dyad": {
    "labels": [{"label": "$(instance)", "x": 500, "y": 1100, "rot": 0}],
    "icons": {"default": "dyad://BlockComponents/LimPID.svg"}
  }
}
end
Flattened Source
dyad
"""
PID controller with limited output, anti-windup, and an external derivative input.

A variant of `LimPID` where the internal filtered derivative block is removed entirely.
Instead, the derivative contribution is supplied externally via the `u_d` input, which
feeds directly into the PID summation with no internal filtering or differentiation.
The derivative passed to the derivative input should be that of the control error
`u_s - u_m`, potentially applying set-point weighting. To use a derivative of the
measurement signal only, the gain should be -1, i.e., pass the derivative of `-u_m`.

Use this component when the derivative signal is already available from the plant
(e.g., a velocity sensor, a model state, or an observer output) and internal
numerical differentiation is unnecessary or undesirable.

The output is:

math y = k \left[e_p + \dfrac{1}{T_is}\left(e + \dfrac{y_{sat} - y}{N_iT_i}\right) + u_d \right] + k_{ff}u_


where `e_p = w_p \cdot u_s - u_m`, `e = u_s - u_m`, and `u_d` is the externally
supplied derivative signal passed through without modification.
"""
component LimPIDExternalDerivative
  "Connector of setpoint input signal"
  u_s = RealInput() {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "default", "x1": -100, "y1": 220, "x2": 0, "y2": 320, "rot": 0},
        "diagram": {"iconName": "default", "x1": -100, "y1": 220, "x2": 0, "y2": 320, "rot": 0}
      }
    }
  }
  "Connector of measurement input signal"
  u_m = RealInput() {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "default", "x1": -100, "y1": 680, "x2": 0, "y2": 780, "rot": 0},
        "diagram": {"iconName": "default", "x1": -100, "y1": 680, "x2": 0, "y2": 780, "rot": 0}
      }
    }
  }
  "Connector of actuator output signal"
  y = RealOutput() {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "output", "x1": 1000, "y1": 460, "x2": 1100, "y2": 560, "rot": 0},
        "diagram": {"iconName": "output", "x1": 1000, "y1": 460, "x2": 1100, "y2": 560, "rot": 0}
      }
    }
  }
  "Feed-forward input"
  u_ff = RealInput() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "input", "x1": 450, "y1": -100, "x2": 550, "y2": 0, "rot": 90}
      },
      "tags": []
    }
  }
  "External derivative input"
  u_d = RealInput() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "input", "x1": 450, "y1": 1000, "x2": 550, "y2": 1100, "rot": -90}
      },
      "tags": []
    }
  }
  add_p = BlockComponents.Math.Add(k1 = wp, k2 = -1) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 100, "y1": 100, "x2": 200, "y2": 200, "rot": 0},
        "diagram": {"iconName": "input", "x1": 80, "y1": 100, "x2": 180, "y2": 200, "rot": 0}
      },
      "tags": []
    }
  }
  add_i = BlockComponents.Math.Add3(k2 = -1) {
    "Dyad": {
      "placement": {"icon": {"iconName": "input", "x1": 100, "y1": 500, "x2": 200, "y2": 600}}
    }
  }
  proportional = BlockComponents.Math.Gain(k = 1) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 300, "y1": 100, "x2": 400, "y2": 200, "rot": 0},
        "diagram": {"iconName": "input", "x1": 260, "y1": 100, "x2": 360, "y2": 200, "rot": 0}
      },
      "tags": []
    }
  }
  integrator = Integrator(k = 1 / Ti, x0 = xi0) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 300, "y1": 500, "x2": 400, "y2": 600, "rot": 0},
        "diagram": {"iconName": "input", "x1": 260, "y1": 500, "x2": 360, "y2": 600, "rot": 0}
      },
      "tags": []
    }
  }
  add_pid = BlockComponents.Math.Add3() {
    "Dyad": {
      "placement": {"icon": {"iconName": "input", "x1": 500, "y1": 300, "x2": 600, "y2": 400}}
    }
  }
  gain_pid = BlockComponents.Math.Gain(k = k) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 700, "y1": 300, "x2": 800, "y2": 400, "rot": 0},
        "diagram": {"iconName": "input", "x1": 540, "y1": 100, "x2": 640, "y2": 200, "rot": 0}
      },
      "tags": []
    }
  }
  add_ff = BlockComponents.Math.Add(k2 = k_ff) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 900, "y1": 300, "x2": 1000, "y2": 400, "rot": 0},
        "diagram": {"iconName": "input", "x1": 700, "y1": 130, "x2": 800, "y2": 230, "rot": 0}
      },
      "tags": []
    }
  }
  limiter = BlockComponents.Nonlinear.Limiter(y_max = y_max, y_min = y_min) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 1100, "y1": 300, "x2": 1200, "y2": 400, "rot": 0},
        "diagram": {"iconName": "input", "x1": 840, "y1": 130, "x2": 940, "y2": 230, "rot": 0}
      },
      "tags": []
    }
  }
  add_sat = BlockComponents.Math.Add(k1 = 1, k2 = -1) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 1100, "y1": 500, "x2": 1200, "y2": 600, "rot": 90},
        "diagram": {"iconName": "input", "x1": 830, "y1": 290, "x2": 930, "y2": 390, "rot": 90}
      },
      "tags": []
    }
  }
  gain_track = BlockComponents.Math.Gain(k = 1 / (k * Ni)) {
    "Dyad": {
      "placement": {
        "icon": {"iconName": "input", "x1": 500, "y1": 700, "x2": 600, "y2": 800, "rot": 180},
        "diagram": {"iconName": "input", "x1": 260, "y1": 690, "x2": 360, "y2": 790, "rot": 180}
      },
      "tags": []
    }
  }
  variable control_error::Real
  "Gain of controller"
  parameter k::Real = 1
  "Time constant of the integrator block"
  parameter Ti::Time = 0.5
  "Maximum output"
  parameter y_max::Real = 1e300
  "Minimum output"
  parameter y_min::Real = -y_max
  "Set-point weight for proportional block"
  parameter wp::Real = 1
  "`Ni*Ti` is time constant of anti-windup compensation"
  parameter Ni::Real = 0.9
  "Gain of the feed-forward input"
  parameter k_ff::Real = 1
  "Initial guess value for integrator output"
  parameter xi0::Real = 0
relations
  connect(add_p.y, proportional.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(add_i.y, integrator.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(proportional.y, add_pid.u1) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 450, "y": 150}, {"x": 450, "y": 320}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(integrator.y, add_pid.u3) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 450, "y": 550}, {"x": 450, "y": 380}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(add_pid.y, gain_pid.u) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [
            {"x": 630, "y": 350},
            {"x": 630, "y": 260},
            {"x": 500, "y": 260},
            {"x": 500, "y": 150}
          ],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(gain_pid.y, add_ff.u1) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(add_ff.y, limiter.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(limiter.y, add_sat.u1) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 970, "y": 180}, {"x": 970, "y": 250}, {"x": 910, "y": 250}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(add_sat.y, gain_track.u) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 880, "y": 740}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(gain_track.y, add_i.u3) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 75, "y": 740}, {"x": 75, "y": 580}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(add_sat.u2, add_ff.y) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 850, "y": 245}, {"x": 820, "y": 245}, {"x": 820, "y": 180}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(limiter.y, y) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 970, "y": 180}, {"x": 970, "y": 500}, {"x": 1050, "y": 500}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(add_ff.u2, u_ff) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 670, "y": 210}, {"x": 670, "y": 70}, {"x": 500, "y": 70}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(add_pid.u2, u_d) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 410, "y": 350}, {"x": 410, "y": 860}, {"x": 500, "y": 860}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(add_p.u1, u_s) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 20, "y": 120}, {"x": 20, "y": 270}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(add_i.u1, u_s) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 20, "y": 520}, {"x": 20, "y": 270}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(add_p.u2, u_m) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 50, "y": 180}, {"x": 50, "y": 730}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(add_i.u2, u_m) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 50, "y": 550}, {"x": 50, "y": 730}], "E": 2}],
      "renderStyle": "standard"
    }
  }
metadata {
  "Dyad": {
    "labels": [{"label": "$(instance)", "x": 500, "y": 1100, "rot": 0}],
    "icons": {"default": "dyad://BlockComponents/LimPID.svg"}
  }
}
end


Test Cases

No test cases defined.