Skip to content

CODEGEN Blocks Library

CODEGEN provides a library of reusable modeling blocks for constructing user-defined dynamic models. Each block is specified by a keyword (prefixed with &), followed by input/output state names and parameters. Parameters can be literal values, named data enclosed in braces {T}, or arithmetic expressions.


BlockDescription
absAbsolute value of input
algeqAlgebraic equation
max1v1cMaximum of a state and a constant
max2vMaximum of two states
min1v1cMinimum of a state and a constant
min2vMinimum of two states
nintNearest integer
pwlinPiecewise linear function
BlockDescription
tf1pFirst-order: G/(1+sT)G/(1 + sT)
tf1plimFirst-order with non-windup output limits
tf1pvlimFirst-order with variable non-windup limits
tf1p2limFirst-order with rate limits and output limits
tf1p1zOne zero, one pole: G(1+sTz)/(1+sTp)G(1 + sT_z)/(1 + sT_p)
tf2p2zTwo zeros, two poles
tfder1pDerivative (washout): sT/(1+sT)sT/(1 + sT)
BlockDescription
intIntegrator with time constant
inlimIntegrator with non-windup limits
invlimIntegrator with variable non-windup limits
BlockDescription
pictlProportional-Integral controller
pictllimPI with non-windup limit on integral
pictl2limPI with limits on integral and total output
pictlieeePI with non-windup limit (IEEE formulation)
BlockDescription
limLimiter with constant bounds
limvbLimiter with variable bounds
dbDeadband
hystHysteresis
switchSelect one of nn inputs
swsignSwitch based on sign of input
BlockDescription
f_injFrequency at bus of injector
f_twop_bus1Frequency at first bus of two-port
f_twop_bus2Frequency at second bus of two-port
BlockDescription
fsaFinite State Automaton
tsaTwo-state automaton
timerTimer with piecewise-linear delay
timerscTimer with staircase delay


Absolute value of input.

Syntax

& abs
x_i
x_j

x_i is the input state; x_j is the output state (the absolute value of x_i).

Internal states: none

Discrete variable: z{1,1}z \in \{-1, 1\}

Equations

0={xjxiif z=1xj+xiif z=10 = \begin{cases} x_j - x_i & \text{if } z = 1 \\ x_j + x_i & \text{if } z = -1 \end{cases}

Discrete transitions

if z = 1:
if x_i < 0:
z ← -1
else: # z = -1
if x_i > 0:
z ← 1

Initialization

if x_i > 0:
z ← 1
else:
z ← 0

Notes

The model has a discontinuous derivative at xi=0x_i = 0. It is implemented internally with a small hysteresis; see the hyst block with xI=ϵx_I = \epsilon, yIB=ϵy_{IB} = -\epsilon, yIA=ϵy_{IA} = \epsilon, xD=ϵx_D = -\epsilon, yDB=ϵy_{DB} = -\epsilon, yDA=ϵy_{DA} = \epsilon, where ϵ\epsilon is the absolute accuracy used to solve the algebraic equations in RAMSES.


Algebraic equation.

Syntax

& algeq
math expression

Internal states: none

Discrete variables: none

Description

This block forces an algebraic constraint (or equation) involving one or several states:

f(x1,x2,,xn)=0f(x_1, x_2, \ldots, x_n) = 0

where nn is the number of states (n1n \ge 1).

Notes

This block does not have distinct “inputs” and “outputs”. Those roles emerge from the rest of the model that incorporates the algebraic constraint.


Maximum between a state and a constant.

Syntax

& max1v1c
x_i
x_j
{C}

x_i is the input state, x_j is the output (max(xi,C)\max(x_i, C)), and C is a constant (data name, parameter name, or math expression).

Internal states: none

Discrete variable: z{1,2}z \in \{1, 2\}

Equations

0={xjCif z=1xjxiif z=20 = \begin{cases} x_j - C & \text{if } z = 1 \\ x_j - x_i & \text{if } z = 2 \end{cases}

When z=1z = 1 the output is clamped to CC; when z=2z = 2 the output tracks xix_i.

Discrete transitions

if z = 1:
if x_i > C:
z ← 2
else: # z = 2
if x_i <= C:
z ← 1

Initialization

if x_i < C:
z ← 1
else:
z ← 2

Maximum between two states.

Syntax

& max2v
x_i
x_j
x_k

x_i and x_j are the two input states; x_k is the output (max(xi,xj)\max(x_i, x_j)).

Internal states: none

Discrete variable: z{1,2}z \in \{1, 2\}

Equations

0={xixkif z=1xjxkif z=20 = \begin{cases} x_i - x_k & \text{if } z = 1 \\ x_j - x_k & \text{if } z = 2 \end{cases}

When z=1z = 1 the output follows xix_i; when z=2z = 2 the output follows xjx_j.

Discrete transitions

if z = 1:
if x_i < x_j:
z ← 2
else: # z = 2
if x_j <= x_i:
z ← 1

Initialization

if x_i > x_j:
z ← 1
else:
z ← 2

Minimum between a state and a constant.

Syntax

& min1v1c
x_i
x_j
{C}

x_i is the input state, x_j is the output (min(xi,C)\min(x_i, C)), and C is a constant (data name, parameter name, or math expression).

Internal states: none

Discrete variable: z{1,2}z \in \{1, 2\}

Equations

0={xjxiif z=1xjCif z=20 = \begin{cases} x_j - x_i & \text{if } z = 1 \\ x_j - C & \text{if } z = 2 \end{cases}

When z=1z = 1 the output tracks xix_i; when z=2z = 2 the output is clamped to CC.

Discrete transitions

if z = 1:
if x_i > C:
z ← 2
else: # z = 2
if x_i <= C:
z ← 1

Initialization

if x_i < C:
z ← 1
else:
z ← 2

Minimum between two states.

Syntax

& min2v
x_i
x_j
x_k

x_i and x_j are the two input states; x_k is the output (min(xi,xj)\min(x_i, x_j)).

Internal states: none

Discrete variable: z{1,2}z \in \{1, 2\}

Equations

0={xixkif z=1xjxkif z=20 = \begin{cases} x_i - x_k & \text{if } z = 1 \\ x_j - x_k & \text{if } z = 2 \end{cases}

When z=1z = 1 the output follows xix_i; when z=2z = 2 the output follows xjx_j.

Discrete transitions

if z = 1:
if x_i > x_j:
z ← 2
else: # z = 2
if x_j >= x_i:
z ← 1

Initialization

if x_i < x_j:
z ← 1
else:
z ← 2

Integer nearest to the input shifted by a constant cc.

Syntax

& nint
x_i
x_j
{c}

x_i is the input state, x_j is the output (nearest integer), and c is a shift constant (data name, parameter name, or math expression).

Internal states: none

Discrete variable: zIz \in \mathcal{I} (the integers)

Equations

0=xjz0 = x_j - z

Discrete transitions

if nint(x_i + c) ≠ z:
z ← nint(x_i + c)

where nint()\text{nint}(\cdot) returns the nearest integer.

Initialization

znint(xi+c)z \leftarrow \text{nint}(x_i + c)

Notes — particular cases

  • With c=0c = 0: the output is the integer nearest to xix_i.
  • With c=0.5c = -0.5: the output is the floor of xix_i (largest integer xi\le x_i).
  • With c=0.5c = 0.5: the output is the ceiling of xix_i (smallest integer xi\ge x_i).


Limiter with constant bounds.

Syntax

& lim
x_i
x_j
{x_min}
{x_max}

x_i is the input, x_j is the (limited) output. x_min and x_max are constant bounds (data names, parameter names, or math expressions).

Internal states: none

Discrete variable: z{1,0,1}z \in \{-1, 0, 1\}

Equations

0={xjxiif z=0xjxmaxif z=1xjxminif z=10 = \begin{cases} x_j - x_i & \text{if } z = 0 \\ x_j - x_{max} & \text{if } z = 1 \\ x_j - x_{min} & \text{if } z = -1 \end{cases}

Discrete transitions

if z = 0:
if x_i > x_max:
z ← 1
else if x_i < x_min:
z ← -1
else if z = 1:
if x_i < x_max:
z ← 0
else: # z = -1
if x_i > x_min:
z ← 0

Initialization

if x_j > x_max:
z ← 1
else if x_j < x_min:
z ← -1
else:
z ← 0

Limiter with variable bounds.

Syntax

& limvb
x_i
x_min
x_max
x_j

x_i is the input; x_min and x_max are variable (state) lower and upper bounds; x_j is the (limited) output.

Internal states: none

Discrete variable: z{1,0,1}z \in \{-1, 0, 1\}

Equations

0={xjxiif z=0xjxmaxif z=1xjxminif z=10 = \begin{cases} x_j - x_i & \text{if } z = 0 \\ x_j - x_{max} & \text{if } z = 1 \\ x_j - x_{min} & \text{if } z = -1 \end{cases}

Discrete transitions

if z = 0:
if x_i > x_max:
z ← 1
else if x_i < x_min:
z ← -1
else if z = 1:
if x_i < x_max:
z ← 0
else: # z = -1
if x_i > x_min:
z ← 0

Initialization

if x_i > x_max:
z ← 1
else if x_i < x_min:
z ← -1
else:
z ← 0

Notes

Unlike lim, the bounds xminx_{min} and xmaxx_{max} are model states (variables) rather than fixed parameters, allowing dynamic limit variation during simulation.


Deadband.

Syntax

& db
x_i
x_j
{delta_1}
{s_1}
{a_1}
{delta_2}
{s_2}
{a_2}

x_i is the input, x_j is the output. Parameters δ1\delta_1, s1s_1, a1a_1, δ2\delta_2, s2s_2, a2a_2 are data names, parameter names, or math expressions.

Internal states: none

Discrete variable: z{0,1,1}z \in \{0, 1, -1\}

Equations

0={xjif z=0xjs2a2(xiδ2)if z=1xjs1a1(xiδ1)if z=10 = \begin{cases} x_j & \text{if } z = 0 \\ x_j - s_2 - a_2(x_i - \delta_2) & \text{if } z = 1 \\ x_j - s_1 - a_1(x_i - \delta_1) & \text{if } z = -1 \end{cases}

Discrete transitions

if z ∈ {0, 1}:
if x_i < delta_1:
z ← -1
else if z ∈ {-1, 0}:
if x_i > delta_2:
z ← 1
else if z ∈ {-1, 1}:
if delta_1 < x_i < delta_2:
z ← 0

Initialization

if x_i > delta_2:
z ← 1
else if x_i < delta_1:
z ← -1
else:
z ← 0

Notes

  • The data must satisfy δ1<δ2\delta_1 < \delta_2, a10a_1 \ge 0, and a20a_2 \ge 0.
  • A common special case is s1=s2=0s_1 = s_2 = 0 and a1=a2=1a_1 = a_2 = 1, although all values are permitted.
  • The pwlin4, pwlin5, or pwlin6 blocks can be used as alternatives.

Hysteresis.

Syntax

& hyst
x_i
x_j
{x_I}
{y_IB}
{y_IA}
{x_D}
{y_DB}
{y_DA}
{z0}

x_i is the input, x_j is the output. The parameters xIx_I, yIBy_{IB}, yIAy_{IA}, xDx_D, yDBy_{DB}, yDAy_{DA} define the hysteresis shape. z0 specifies the initial discrete state when the input starts in the indeterminate region.

Internal states: none

Discrete variable: z{1,1}z \in \{-1, 1\}

Equations

0={xjyIAyIAyDBxIxD(xixI)if z=1xjyDAyIByDAxIxD(xixD)if z=10 = \begin{cases} \displaystyle x_j - y_{IA} - \frac{y_{IA} - y_{DB}}{x_I - x_D}(x_i - x_I) & \text{if } z = 1 \\[8pt] \displaystyle x_j - y_{DA} - \frac{y_{IB} - y_{DA}}{x_I - x_D}(x_i - x_D) & \text{if } z = -1 \end{cases}

Discrete transitions

if z = -1:
if x_i > x_I:
z ← 1
else: # z = 1
if x_i < x_D:
z ← -1

Initialization

if x_i > x_I:
z ← 1
else if x_i < x_D:
z ← -1
else:
if z0 >= 0:
z ← 1
else:
z ← 0

Notes

At t=0t = 0, if xD<xi(0)<xIx_D < x_i(0) < x_I the initial operating branch is indeterminate — the system could operate on either the (yIA,yDB)(y_{IA}, y_{DB}) line (z=1z = 1) or the (yDA,yIB)(y_{DA}, y_{IB}) line (z=1z = -1). The user must therefore supply z0 to resolve the ambiguity.

If xi(0)<xDx_i(0) < x_D then zz is initialised to 1-1; if xi(0)>xIx_i(0) > x_I then zz is initialised to 11, and z0 is ignored in both cases.

The data must satisfy xD<xIx_D < x_I. The degenerate case xD=xIx_D = x_I is not allowed by this block but can be handled with the pwlin4 block.



Computes ff, an estimate of the frequency (in per unit) at a given bus, from the evolution of the rectangular components vxv_x and vyv_y of the bus voltage. A measurement time constant TT is involved. Can be used in the model of an injector only.

Syntax

& f_inj
f
{T}

f is the name of the estimated frequency variable; T is the measurement time constant (data name, parameter name, or math expression). The voltage components vxv_x and vyv_y are automatically inherited and must not be declared.

Internal states: vxmv_{xm} and vymv_{ym} (measured/filtered voltage components)

Discrete variables: none

Equations

v˙xm=vxvxmTv˙ym=vyvymT0=ωref,pu+(vyvym)vxm(vxvxm)vym2πfNT(vxm2+vym2)f\begin{aligned} \dot{v}_{xm} &= \frac{v_x - v_{xm}}{T} \\[6pt] \dot{v}_{ym} &= \frac{v_y - v_{ym}}{T} \\[6pt] 0 &= \omega_{ref,pu} + \frac{(v_y - v_{ym})\,v_{xm} - (v_x - v_{xm})\,v_{ym}}{2\pi f_N T \left(v_{xm}^2 + v_{ym}^2\right)} - f \end{aligned}

Initialization

vxm=vxvym=vyv_{xm} = v_x \qquad v_{ym} = v_y

Explanation

The voltage components vxv_x and vyv_y are the projections of the bus voltage phasor onto the reference axes rotating at angular speed ωref\omega_{ref} (rad/s). The instantaneous angular frequency is:

ω=ωref+dϕdt,ϕ=arctanvyvx\omega = \omega_{ref} + \frac{d\phi}{dt}, \qquad \phi = \arctan\frac{v_y}{v_x}

The per-unit frequency is therefore:

f=ω2πfN=ωref,pu+12πfNddt ⁣(arctanvyvx)=ωref,pu+12πfNv˙yvxv˙xvyvx2+vy2f = \frac{\omega}{2\pi f_N} = \omega_{ref,pu} + \frac{1}{2\pi f_N}\frac{d}{dt}\!\left(\arctan\frac{v_y}{v_x}\right) = \omega_{ref,pu} + \frac{1}{2\pi f_N}\frac{\dot{v}_y v_x - \dot{v}_x v_y}{v_x^2 + v_y^2}

where fNf_N is the nominal frequency (known from the system data). To filter transients, vxv_x and vyv_y are passed through first-order filters with time constant TT, yielding the measured values vxmv_{xm} and vymv_{ym}. Substituting the filter derivatives into the frequency expression yields the third equation above.

Notes

  • A recommended value for TT is in the range 0.050.050.100.10 s.
  • T=0T = 0 is not allowed. If TT is too small, the solver may encounter a singularity and the simulation may fail.

Similar to f_inj. Computes ff, an estimate of the frequency (in per unit) at the first bus of a given two-port. Can be used in the model of a two-port only.

Syntax

& f_twop_bus1
f
{T}

f is the name of the estimated frequency variable; T is the measurement time constant (data name, parameter name, or math expression).

Internal states: vxmv_{xm} and vymv_{ym} (filtered voltage components at bus 1)

Discrete variables: none

Equations, initialization, and notes: identical to f_inj — refer to that block for the full mathematical description. The only difference is that this block uses the voltage at the first bus of a two-port rather than an injector bus.


Similar to f_inj. Computes ff, an estimate of the frequency (in per unit) at the second bus of a given two-port. Can be used in the model of a two-port only.

Syntax

& f_twop_bus2
f
{T}

f is the name of the estimated frequency variable; T is the measurement time constant (data name, parameter name, or math expression).

Internal states: vxmv_{xm} and vymv_{ym} (filtered voltage components at bus 2)

Discrete variables: none

Equations, initialization, and notes: identical to f_inj — refer to that block for the full mathematical description. The only difference is that this block uses the voltage at the second bus of a two-port rather than an injector bus.



Finite State Automaton.

This block forces a set of nn algebraic equations. There are ss possible sets, each corresponding to a value of the discrete state zz. Transitions between sets occur when Boolean expressions evaluate to true.

Syntax

The block is specified via an inline example. For s=3s = 3 states and n=2n = 2 algebraic constraints per state:

& fsa
initial_state
# 1
algebraic constraint No. 1
algebraic constraint No. 2
-> 2
boolean expression C1
# 2
algebraic constraint No. 3
algebraic constraint No. 4
-> 1
boolean expression C2
-> 3
boolean expression C3
-> 3
boolean expression C4
# 3
algebraic constraint No. 5
algebraic constraint No. 6
-> 1
boolean expression C5
##

Internal states: none

Discrete variable: zz — the index of the currently active state

Syntax rules

TokenMeaning
# NBegins the section for state NN. States must be numbered consecutively from 1 to ss in increasing order.
##Marks the end of the state list.
-> NDeclares a transition to state NN. The following line is the Boolean expression that triggers the transition.
Second lineInteger specifying the initial state of the automaton.

Notes

  • The number nn of algebraic constraints must be identical across all states.
  • Multiple transitions from the same state to the same target state are permitted (e.g., two separate conditions C3 and C4 both targeting state 3 in the example). Alternatively a single transition with the combined condition C3 or C4 may be used.
  • Transitions and algebraic constraints may involve any model states and parameters.


Integrator with (positive) time constant TT.

Syntax

& int
x_i
x_j
{T}

x_i is the input, x_j is the integrated output, and T is the (positive) time constant (data name, parameter name, or math expression).

Internal states: none

Discrete variables: none

Equation

Tx˙j=xiT\,\dot{x}_j = x_i

Notes

T=0T = 0 is not allowed. If TT is too small, the solver may encounter a singularity and the simulation may fail.


Integrator with (positive) time constant TT and non-windup limits on output.

Syntax

& inlim
x_i
x_j
{T}
{x_min}
{x_max}

x_i is the input, x_j is the limited integrated output. T is the time constant; x_min and x_max are constant output limits (data names, parameter names, or math expressions).

Internal states: none

Discrete variable: z{0,1,1}z \in \{0, 1, -1\}

Equations

Tx˙j=xiif z=00=xjxminif z=10=xjxmaxif z=1\begin{aligned} T\,\dot{x}_j &= x_i && \text{if } z = 0 \\ 0 &= x_j - x_{min} && \text{if } z = -1 \\ 0 &= x_j - x_{max} && \text{if } z = 1 \end{aligned}

Discrete transitions

if z = 0:
if x_j > x_max:
z ← 1
else if x_j < x_min:
z ← -1
else if z = 1:
if x_i < 0:
z ← 0
else: # z = -1
if x_i > 0:
z ← 0

Initialization

if x_j > x_max:
z ← 1
else if x_j < x_min:
z ← -1
else:
z ← 0

Notes

The limits are non-windup: when the output reaches a limit, integration stops and the limit is enforced as an algebraic constraint. Integration resumes (in the direction away from the limit) once the input drives the output back into the feasible range.

T=0T = 0 is not allowed. If TT is too small, the solver may encounter a singularity and the simulation may fail.


Integrator with (positive) time constant TT and non-windup limits on output. The lower and upper limits are variables.

Syntax

& invlim
x_i
x_min
x_max
x_j
{T}

x_i is the input; x_min and x_max are variable (state) lower and upper limits; x_j is the limited integrated output; T is the time constant (data name, parameter name, or math expression).

Internal states: none

Discrete variable: z{0,1,1}z \in \{0, 1, -1\}

Equations

Tx˙j=xiif z=00=xjxminif z=10=xjxmaxif z=1\begin{aligned} T\,\dot{x}_j &= x_i && \text{if } z = 0 \\ 0 &= x_j - x_{min} && \text{if } z = -1 \\ 0 &= x_j - x_{max} && \text{if } z = 1 \end{aligned}

Discrete transitions

if z = 0:
if x_j > x_max:
z ← 1
else if x_j < x_min:
z ← -1
else if z = 1:
if x_i < 0:
z ← 0
else: # z = -1
if x_i > 0:
z ← 0

Initialization

if x_j > x_max:
z ← 1
else if x_j < x_min:
z ← -1
else:
z ← 0

Notes

Unlike inlim, the bounds xminx_{min} and xmaxx_{max} are model states (variables) that can change during simulation, enabling dynamic limit adjustment.

The non-windup behaviour is identical to inlim: integration halts when a limit is reached and resumes once the input drives the output away from that limit.

T=0T = 0 is not allowed. If TT is too small, the solver may encounter a singularity and the simulation may fail.


Proportional-Integral (PI) controller.

& pictl
name of variable x_k
name of variable x_j
data name, parameter name or math expression for K_i
data name, parameter name or math expression for K_p

xix_i

None.

x˙i=Kixk0=Kpxk+xixj\begin{aligned} \dot{x}_i &= K_i \, x_k \\ 0 &= K_p \, x_k + x_i - x_j \end{aligned}

xi=xjx_i = x_j


Proportional-Integral (PI) controller with non-windup limit on the integral term.

& pictllim
name of variable x_k
name of variable x_j
data name, parameter name or math expression for K_i
data name, parameter name or math expression for K_p
data name, parameter name or math expression for x_i^min
data name, parameter name or math expression for x_i^max

xix_i

z{1,0,1}z \in \{-1, 0, 1\}

0={x˙i=Kixkif z=0xiximinif z=1xiximaxif z=10 = \begin{cases} \dot{x}_i = K_i x_k & \text{if } z = 0 \\ x_i - x_i^{min} & \text{if } z = -1 \\ x_i - x_i^{max} & \text{if } z = 1 \end{cases}

0=Kpxk+xixj0 = K_p x_k + x_i - x_j

if z = 0:
if x_i > x_i^max: z ← 1
else if x_i < x_i^min: z ← -1
else if z = 1:
if K_i * x_k < 0: z ← 0
else if z = -1:
if K_i * x_k > 0: z ← 0
if K_i * x_k > 0:
z ← 1; x_i ← x_i^max
else if K_i * x_k < 0:
z ← -1; x_i ← x_i^min
else:
z ← 0; x_i ← x_j

Proportional-Integral (PI) controller with non-windup limit on the integral term and limit on the proportional term.

& pictl2lim
name of variable x_k
name of variable x_j
data name, parameter name or math expression for K_i
data name, parameter name or math expression for K_p
data name, parameter name or math expression for x_i^min
data name, parameter name or math expression for x_i^max
data name, parameter name or math expression for x_p^min
data name, parameter name or math expression for x_p^max

xix_i and xpx_p

z1{1,0,1}z_1 \in \{-1, 0, 1\} and z2{1,0,1}z_2 \in \{-1, 0, 1\}

{0=Kpxkxpif z1=00=xpxpminif z1=10=xpxpmaxif z1=1\begin{cases} 0 = K_p x_k - x_p & \text{if } z_1 = 0 \\ 0 = x_p - x_p^{min} & \text{if } z_1 = -1 \\ 0 = x_p - x_p^{max} & \text{if } z_1 = 1 \end{cases} {x˙i=Kixkif z2=00=xiximinif z2=10=xiximaxif z2=1\begin{cases} \dot{x}_i = K_i x_k & \text{if } z_2 = 0 \\ 0 = x_i - x_i^{min} & \text{if } z_2 = -1 \\ 0 = x_i - x_i^{max} & \text{if } z_2 = 1 \end{cases}

0=xp+xixj0 = x_p + x_i - x_j

# Proportional limiter (z_1):
if z_1 = 0:
if x_p > x_p^max: z_1 ← 1
else if x_p < x_p^min: z_1 ← -1
else if z_1 = 1:
if K_p * x_k < x_p^max: z_1 ← 0
else if z_1 = -1:
if K_p * x_k > x_p^min: z_1 ← 0
# Integral limiter (z_2):
if z_2 = 0:
if x_i > x_i^max: z_2 ← 1
else if x_i < x_i^min: z_2 ← -1
else if z_2 = 1:
if K_i * x_k < 0: z_2 ← 0
else if z_2 = -1:
if K_i * x_k > 0: z_2 ← 0

Initialization of xpx_p:

xp=min ⁣(xpmax,max(xpmin,Kpxk))x_p = \min\!\left(x_p^{max},\, \max(x_p^{min},\, K_p x_k)\right)

Initialization of xix_i and discrete variables:

if K_p * x_k > x_p^max: z_1 ← 1
else if K_p * x_k < x_p^min: z_1 ← -1
else: z_1 ← 0
if K_i * x_k > 0:
z_2 ← 1; x_i ← x_i^max
else if K_i * x_k < 0:
z_2 ← -1; x_i ← x_i^min
else:
z_2 ← 0; x_i ← x_j - x_p

Proportional-Integral (PI) controller with non-windup limit on the integral term, compliant with IEEE standards.

This PI controller implements the non-windup integrator specified in:

  • IEEE Std 421.5-1992, IEEE Std 421.5-2005, and IEEE Std 421.5-2016 (excitation system models for power system stability studies).

The IEEE standard specifies that the integrator state x1x_1 is frozen as soon as xjx_j reaches its lower or upper limit. To avoid limit cycles when the integrator is released, a second “open-loop” integrator tracks what x1x_1 would be if unconstrained. The lower integrator is re-activated only when Kpxk+x2K_p x_k + x_2 re-enters [xjmin,xjmax][x_j^{min},\, x_j^{max}].

& pictlieee
name of variable x_k
name of variable x_j
data name, parameter name or math expression for K_i
data name, parameter name or math expression for K_p
data name, parameter name or math expression for x_j^min
data name, parameter name or math expression for x_j^max

x1x_1 and x2x_2

z{2,1,0,1,2}z \in \{-2, -1, 0, 1, 2\}

if z=0:{0=Kpxk+x1xjx˙1=Kixk0=x2x1\text{if } z = 0: \quad \begin{cases} 0 = K_p x_k + x_1 - x_j \\ \dot{x}_1 = K_i \, x_k \\ 0 = x_2 - x_1 \end{cases} if z=2:{0=xjmaxxjx˙1=00=x2x1if z=1:{0=xjmaxxjx˙1=0x˙2=Kixk\text{if } z = 2: \quad \begin{cases} 0 = x_j^{max} - x_j \\ \dot{x}_1 = 0 \\ 0 = x_2 - x_1 \end{cases} \qquad \text{if } z = 1: \quad \begin{cases} 0 = x_j^{max} - x_j \\ \dot{x}_1 = 0 \\ \dot{x}_2 = K_i \, x_k \end{cases} if z=2:{0=xjminxjx˙1=00=x2x1if z=1:{0=xjminxjx˙1=0x˙2=Kixk\text{if } z = -2: \quad \begin{cases} 0 = x_j^{min} - x_j \\ \dot{x}_1 = 0 \\ 0 = x_2 - x_1 \end{cases} \qquad \text{if } z = -1: \quad \begin{cases} 0 = x_j^{min} - x_j \\ \dot{x}_1 = 0 \\ \dot{x}_2 = K_i \, x_k \end{cases}

The tests marked (*) use x2x_2 (the open-loop integrator) to decide when the active integrator x1x_1 can be released.

if z = 0:
if x_j > x_j^max: z ← 2
else if x_j < x_j^min: z ← -2
else if z = 2:
if K_p*x_k + x_1 < x_j^max: z ← 1
else if z = 1:
if K_p*x_k + x_1 > x_j^max: z ← 2
else if K_p*x_k + x_2 < x_j^max: z ← 0 (*)
else if z = -2:
if K_p*x_k + x_1 > x_j^min: z ← -1
else if z = -1:
if K_p*x_k + x_1 < x_j^min: z ← -2
else if K_p*x_k + x_2 > x_j^min: z ← 0 (*)
if x_j >= x_j^max:
z ← 2; x_1 ← x_j^max - K_p*x_k; x_2 ← x_1
else if x_j <= x_j^min:
z ← -2; x_1 ← x_j^min - K_p*x_k; x_2 ← x_1
else:
z ← 0; x_1 ← x_j; x_2 ← x_1

Transfer function between input and output: one time constant.

& tf1p
name of variable x_i
name of variable x_j
data name, parameter name or math expression for G
data name, parameter name or math expression for T

None.

None.

Tx˙j=xj+GxiT \, \dot{x}_j = -x_j + G \, x_i

The time constant TT can be zero, in which case the block behaves as a simple gain xj=Gxix_j = G \, x_i.


Transfer function between input and output: one time constant with non-windup limits on output.

& tf1plim
name of variable x_i
name of variable x_j
data name, parameter name or math expression for G
data name, parameter name or math expression for T
data name, parameter name or math expression for x_min
data name, parameter name or math expression for x_max

None.

z{1,0,1}z \in \{-1, 0, 1\}

{Tx˙j=Gxixjif z=00=xjxmaxif z=10=xjxminif z=1\begin{cases} T \, \dot{x}_j = G \, x_i - x_j & \text{if } z = 0 \\ 0 = x_j - x_{max} & \text{if } z = 1 \\ 0 = x_j - x_{min} & \text{if } z = -1 \end{cases}
if z = 0:
if x_j > x_max: z ← 1
else if x_j < x_min: z ← -1
else if z = 1:
if G*x_i - x_j < 0: z ← 0
else if z = -1:
if G*x_i - x_j > 0: z ← 0
if x_j >= x_max: z ← 1
else if x_j <= x_min: z ← -1
else: z ← 0

The time constant TT can be zero. In this case the block behaves as a gain (xj=Gxix_j = G x_i) but the limits xminx_{min} and xmaxx_{max} remain in effect.


Transfer function between input and output: one time constant with non-windup limits on output. The limits are variables.

This block is identical in behaviour to tf1plim except that xminx_{min} and xmaxx_{max} are variable states rather than fixed data parameters.

& tf1pvlim
name of variable x_i
name of variable x_j
name of variable x_min
name of variable x_max
data name, parameter name or math expression for G
data name, parameter name or math expression for T

None.

z{1,0,1}z \in \{-1, 0, 1\}

{Tx˙j=Gxixjif z=00=xjxmaxif z=10=xjxminif z=1\begin{cases} T \, \dot{x}_j = G \, x_i - x_j & \text{if } z = 0 \\ 0 = x_j - x_{max} & \text{if } z = 1 \\ 0 = x_j - x_{min} & \text{if } z = -1 \end{cases}
if z = 0:
if x_j > x_max: z ← 1
else if x_j < x_min: z ← -1
else if z = 1:
if G*x_i - x_j < 0: z ← 0
else if z = -1:
if G*x_i - x_j > 0: z ← 0
if x_j >= x_max: z ← 1
else if x_j <= x_min: z ← -1
else: z ← 0

The time constant TT can be zero. In this case the block behaves as a gain (xj=Gxix_j = G x_i) but the variable limits remain in effect.


Transfer function between input and output: one time constant, with limits on rate of change of output and non-windup limits on output.

& tf1p2lim
name of variable x_i
name of variable x_j
data name, parameter name or math expression for G
data name, parameter name or math expression for T
data name, parameter name or math expression for x_min
data name, parameter name or math expression for x_max
data name, parameter name or math expression for dx_min/dt
data name, parameter name or math expression for dx_max/dt

x1x_1, initialized at min ⁣[max ⁣(0,Tx˙min),Tx˙max]\min\!\left[\max\!\left(0,\, T \, \dot{x}_{min}\right),\, T \, \dot{x}_{max}\right]

z1{1,0,1}z_1 \in \{-1, 0, 1\} (rate limiter) and z2{1,0,1}z_2 \in \{-1, 0, 1\} (output limiter)

{0=x1Gxi+xjif z1=00=x1Tx˙maxif z1=10=x1Tx˙minif z1=1\begin{cases} 0 = x_1 - G \, x_i + x_j & \text{if } z_1 = 0 \\ 0 = x_1 - T \, \dot{x}_{max} & \text{if } z_1 = 1 \\ 0 = x_1 - T \, \dot{x}_{min} & \text{if } z_1 = -1 \end{cases} {Tx˙j=x1if z2=00=xjxmaxif z2=10=xjxminif z2=1\begin{cases} T \, \dot{x}_j = x_1 & \text{if } z_2 = 0 \\ 0 = x_j - x_{max} & \text{if } z_2 = 1 \\ 0 = x_j - x_{min} & \text{if } z_2 = -1 \end{cases}

x˙max\dot{x}_{max} (resp. x˙min\dot{x}_{min}) is the maximum (resp. minimum) rate of change of xjx_j with time.

# Rate limiter (z_1):
if z_1 = 0:
if x_1 > T*dx_max: z_1 ← 1
else if x_1 < T*dx_min: z_1 ← -1
else if z_1 = 1:
if G*x_i - x_j < T*dx_max: z_1 ← 0
else if z_1 = -1:
if G*x_i - x_j > T*dx_min: z_1 ← 0
# Output limiter (z_2):
if z_2 = 0:
if x_j > x_max: z_2 ← 1
else if x_j < x_min: z_2 ← -1
else if z_2 = 1:
if x_1 < 0: z_2 ← 0
else if z_2 = -1:
if x_1 > 0: z_2 ← 0
if G*x_i - x_j > T*dx_max: z_1 ← 1
else if G*x_i - x_j < T*dx_min: z_1 ← -1
else: z_1 ← 0
if x_j > x_max: z_2 ← 1
else if x_j < x_min: z_2 ← -1
else: z_2 ← 0

The time constant TT can be zero. In this case x1=0x_1 = 0 throughout the simulation, the block behaves as a gain xj=Gxix_j = G x_i, and both limiters are ignored (xmaxx_{max} \to \infty, xminx_{min} \to -\infty, Tx˙maxT\dot{x}_{max} \to \infty, Tx˙minT\dot{x}_{min} \to -\infty).


Transfer function: derivative with one time constant.

The transfer function is xj=Gs1+sTxi\displaystyle x_j = \frac{G s}{1 + sT} x_i.

& tfder1p
name of variable x_i
name of variable x_j
data name, parameter name or math expression for G
data name, parameter name or math expression for T

x1x_1

None.

Tx˙1=xj0=Gxix1xj\begin{aligned} T \, \dot{x}_1 &= x_j \\ 0 &= G \, x_i - x_1 - x_j \end{aligned}

x1=Gxix_1 = G \, x_i

The model allows T=0T = 0. In this case xj=0x_j = 0 as expected; the second equation is formally retained but becomes redundant.


Transfer function between input and output: one zero and one pole.

The transfer function is xj=G1+sTz1+sTpxi\displaystyle x_j = G \frac{1 + s T_z}{1 + s T_p} x_i.

& tf1p1z
name of variable x_i
name of variable x_j
data name, parameter name or math expression for G
data name, parameter name or math expression for T_z
data name, parameter name or math expression for T_p

x1x_1

None.

x˙1=Gxixj0=TpxjGTzxix1\begin{aligned} \dot{x}_1 &= G \, x_i - x_j \\ 0 &= T_p \, x_j - G \, T_z \, x_i - x_1 \end{aligned}

x1=G(TpTz)xix_1 = G \, (T_p - T_z) \, x_i

  • Tz=0T_z = 0 is allowed: the block reduces to Tpx˙j=xj+GxiT_p \dot{x}_j = -x_j + G x_i (i.e., tf1p).
  • Tp=0T_p = 0 is formally allowed but produces a pure differentiator G(1+sTz)G(1 + sT_z); undesired transients may occur at discontinuities of xix_i or x˙i\dot{x}_i.
  • Tp=Tz=TT_p = T_z = T: x1x_1 is initialized to zero and remains zero, giving xj=Gxix_j = G x_i.

Transfer function between input and output: two real zeros and two real poles.

The transfer function is xj=G(1+n1s)(1+n2s)(1+d1s)(1+d2s)xi\displaystyle x_j = G \frac{(1 + n_1 s)(1 + n_2 s)}{(1 + d_1 s)(1 + d_2 s)} x_i.

& tf2p2z
name of variable x_i
name of variable x_j
data name, parameter name or math expression for G
data name, parameter name or math expression for n_1
data name, parameter name or math expression for n_2
data name, parameter name or math expression for d_1
data name, parameter name or math expression for d_2

x1x_1 and x2x_2

None.

State-space controllable canonical form:

x˙1=x2d2x˙2=x1d1x2+d2xi0=G(d2n2)x1+G(n1d2d1n2)x2+Gn2d2xid22xj\begin{aligned} \dot{x}_1 &= x_2 \\ d_2 \, \dot{x}_2 &= -x_1 - d_1 x_2 + d_2 x_i \\ 0 &= G(d_2 - n_2) x_1 + G(n_1 d_2 - d_1 n_2) x_2 + G n_2 d_2 x_i - d_2^2 x_j \end{aligned}

x2=0,x1=d2xix_2 = 0, \qquad x_1 = d_2 \, x_i

Exception. If d2<0.005d_2 < 0.005, both d2d_2 and n2n_2 are set to zero and the transfer function reduces to:

G1+n1s1+d1sG \frac{1 + n_1 s}{1 + d_1 s}

as in the tf1p1z block. If additionally d1<0.005d_1 < 0.005, both d1d_1 and n1n_1 are set to zero and the block becomes a simple gain xj=Gxix_j = G x_i.


Piece-wise linear function of input, defined by nn points. Separate blocks exist for n=3,4,5n = 3, 4, 5 and 66.

& pwlin3
name of variable x_i
name of variable x_j
data/parameter/expression for v_x(1)
data/parameter/expression for v_y(1)
data/parameter/expression for v_x(2)
data/parameter/expression for v_y(2)
data/parameter/expression for v_x(3)
data/parameter/expression for v_y(3)

For pwlin4, pwlin5, and pwlin6, append additional (vx(k),vy(k))(v_x(k), v_y(k)) pairs up to k=4k = 4, 55, or 66 respectively.

None.

z{1,,n1}z \in \{1, \ldots, n-1\}

0=vy(z)+vy(z+1)vy(z)vx(z+1)vx(z)(xivx(z))xj0 = v_y(z) + \frac{v_y(z+1) - v_y(z)}{v_x(z+1) - v_x(z)} \left( x_i - v_x(z) \right) - x_j

if x_i < v_x(1):
z ← 1
else if x_i >= v_x(n):
z ← n-1
else:
for k = 1 to n-1:
if v_x(k) <= x_i < v_x(k+1):
z ← k

Same logic as discrete transitions.

  • The vxv_x values must be strictly increasing at the endpoints: vx(1)<vx(2)v_x(1) < v_x(2) and vx(n1)<vx(n)v_x(n-1) < v_x(n); intermediate values may be equal: vx(1)<vx(2)vx(n1)<vx(n)v_x(1) < v_x(2) \le \cdots \le v_x(n-1) < v_x(n).
  • For xi<vx(1)x_i < v_x(1) or xi>vx(n)x_i > v_x(n), xjx_j is obtained by linear extrapolation from the first or last two points respectively.

Set the output state to one among nn input states, based on the value of a controlling state. Separate blocks exist for n=2,3,4n = 2, 3, 4 and 55.

& switch2
name of variable x_i(1)
name of variable x_i(2)
name of variable x_k (selector)
name of variable x_j (output)

For switch3switch5, prepend additional input variables xi(3)x_i(3) through xi(n)x_i(n) before xkx_k.

None.

z{1,2,,n}z \in \{1, 2, \ldots, n\}

0=xjxi(z)0 = x_j - x_i(z)

zmax ⁣(1,min ⁣(n,nint(xk)))z \leftarrow \max\!\left(1,\, \min\!\left(n,\, \text{nint}(x_k)\right)\right)

where nint\text{nint} returns the nearest integer.

Same as discrete transitions.


Switch between two input states, based on the sign of a third input state.

& swsign
name of variable x_i (selected when x_k >= 0)
name of variable x_j (selected when x_k < 0)
name of variable x_k (sign selector)
name of variable x_l (output)

None.

z{1,2}z \in \{1, 2\}

0={xlxiif z=1xlxjif z=20 = \begin{cases} x_l - x_i & \text{if } z = 1 \\ x_l - x_j & \text{if } z = 2 \end{cases}
if z = 1:
if x_k < 0: z ← 2
else if z = 2:
if x_k >= 0: z ← 1
if x_k < 0: z ← 2
else: z ← 1

Timer with varying delay. The delay is a piecewise linear function of the monitored variable. Separate blocks exist for n=1,2,3,4n = 1, 2, 3, 4 and 55 characteristic points.

If xix_i is smaller than a threshold v1v_1, the output xjx_j is zero. Otherwise, xjx_j changes from zero to one at time t+τ(xi)t^\star + \tau(x_i), where tt^\star is the time at which xix_i first exceeded v1v_1 and τ(xi)\tau(x_i) is a piecewise linear function of xix_i defined by the (vk,Tk)(v_k, T_k) pairs.

& timer1
name of variable x_i
name of variable x_j
data/parameter/expression for v_1
data/parameter/expression for T_1

For timer2timer5, append additional (vk,Tk)(v_k, T_k) pairs up to the required nn.

x1x_1 (elapsed time counter)

z{1,0,1}z \in \{-1, 0, 1\}

0={xjif z{1,0}xj1if z=10 = \begin{cases} x_j & \text{if } z \in \{-1, 0\} \\ x_j - 1 & \text{if } z = 1 \end{cases} {0=x1if z=1x˙1=1if z=0x˙1=0if z=1\begin{cases} 0 = x_1 & \text{if } z = -1 \\ \dot{x}_1 = 1 & \text{if } z = 0 \\ \dot{x}_1 = 0 & \text{if } z = 1 \end{cases}
if z = -1:
if x_i >= v_1: z ← 0
else (z = 0 or 1):
if x_i < v_1: z ← -1
if z = 0:
if x_1 >= τ(x_i): z ← 1

x10,z1x_1 \leftarrow 0, \qquad z \leftarrow -1

  • The viv_i values must be non-decreasing: v1v2vnv_1 \le v_2 \le \cdots \le v_n.
  • Typical use: approximating an inverse-time characteristic with T1T2TnT_1 \ge T_2 \ge \cdots \ge T_n.
  • If xi>v1x_i > v_1 at t=0t = 0, xjx_j will trip to one after τ(xi)\tau(x_i) unless xix_i drops below v1v_1 first.

Timer with varying delay. The delay is a staircase function of the monitored variable. Separate blocks exist for n=1,2,3,4,5n = 1, 2, 3, 4, 5 and 66 characteristic points.

Identical behaviour to timer except that the delay function τ(xi)\tau(x_i) is a staircase (step) function instead of a piecewise linear interpolation.

& timersc1
name of variable x_i
name of variable x_j
data/parameter/expression for v_1
data/parameter/expression for T_1

For timersc2timersc6, append additional (vk,Tk)(v_k, T_k) pairs up to the required nn.

x1x_1 (elapsed time counter)

z{1,0,1}z \in \{-1, 0, 1\}

0={xjif z{1,0}xj1if z=10 = \begin{cases} x_j & \text{if } z \in \{-1, 0\} \\ x_j - 1 & \text{if } z = 1 \end{cases} {0=x1if z=1x˙1=1if z=0x˙1=0if z=1\begin{cases} 0 = x_1 & \text{if } z = -1 \\ \dot{x}_1 = 1 & \text{if } z = 0 \\ \dot{x}_1 = 0 & \text{if } z = 1 \end{cases}
if z = -1:
if x_i >= v_1: z ← 0
else (z = 0 or 1):
if x_i < v_1: z ← -1
if z = 0:
if x_1 >= τ(x_i): z ← 1

x10,z1x_1 \leftarrow 0, \qquad z \leftarrow -1

  • The viv_i values must be non-decreasing: v1v2vnv_1 \le v_2 \le \cdots \le v_n.
  • The staircase characteristic is typically used to approximate an inverse-time protection curve.
  • If xi>v1x_i > v_1 at t=0t = 0, xjx_j trips to one after τ(xi)\tau(x_i) unless xix_i drops below v1v_1 first.

Two-state automaton with transitions based on signs of two inputs.

The output state xkx_k can take two values: v1v_1 or v2v_2. When xk=v1x_k = v_1, a positive x1x_1 triggers the transition to v2v_2; when xk=v2x_k = v_2, a positive x2x_2 triggers the return to v1v_1.

& 2sa
name of variable x_1 (trigger for transition to v_2)
name of variable x_2 (trigger for transition to v_1)
name of variable x_k (output)
data/parameter/expression for v_1
data/parameter/expression for v_2

None.

z{1,2}z \in \{1, 2\} represents the automaton state.

0={xkv1if z=1xkv2if z=20 = \begin{cases} x_k - v_1 & \text{if } z = 1 \\ x_k - v_2 & \text{if } z = 2 \end{cases}
if z = 1 and x_1 > 0: z ← 2
else if z = 2 and x_2 > 0: z ← 1

z1(xk=v1 is assumed initially)z \leftarrow 1 \quad (x_k = v_1 \text{ is assumed initially})


The following functions can be used in any mathematical expression within CODEGEN model definitions.

Signature: double precision function equal(var1, var2)

Arguments: double precision :: var1, var2

Description: Returns 1.0 if var1 differs from var2 by less than 10610^{-6}, and 0.0 otherwise.

Notes: General-purpose; available in all model types.


Signature: double precision function equalstr(var1, var2)

Arguments: character :: var1, var2

Description: Returns 1.0 if the non-blank portions of var1 and var2 are identical strings, and 0.0 otherwise.

Notes: General-purpose; available in all model types.


Signature: double precision ppower([vx], [vy], [ix], [iy])

Description: Returns the active power injected into the network.

Model type: inj only.

Computation:

P=vxix+vyiyP = v_x \, i_x + v_y \, i_y


Signature: double precision qpower([vx], [vy], [ix], [iy])

Description: Returns the reactive power injected into the network.

Model type: inj only.

Computation:

Q=vyixvxiyQ = v_y \, i_x - v_x \, i_y


Signature: double precision function vrectif([if], [vin], {kc})

Arguments: double precision :: kc

Description: Models the voltage drop in a rectifier. Returns the output voltage vrectifvrectif as a function of output current ifif and input voltage vinvin. Used in IEEE standard excitation models with vrectif=fexEFDvrectif = f_{ex} \, E_{FD}.

Model type: exc only.

Computation:

in = kc * if / max(vin, 1e-3)
if in <= 0:
vrectif = vin
else if in <= 0.433:
vrectif = vin - 0.577 * kc * if
else if in <= 0.75:
vrectif = sqrt(0.75 * vin^2 - (kc * if)^2)
else if in <= 1.00:
vrectif = 1.732 * (vin - kc * if)
else:
vrectif = 0

Signature: double precision function vinrectif([if], [vrectif], {kc})

Arguments: double precision :: kc

Description: Inverse of vrectif. Given the field current ifif and rectifier output voltage vrectifvrectif, returns the rectifier input voltage vinrectifvinrectif. Intended for use at initialization. The computation is iterative because the operating segment of the piecewise characteristic is not known a priori. Does not work when vrectif=0vrectif = 0 (indeterminate input).

Model type: exc only.

Computation:

nbtries = 1
vinest = vrectif + 0.577 * kc * if
loop:
in = kc * if / max(vinest, 1e-3)
if in <= 0:
vinrectif = vrectif
else if in <= 0.433:
vinrectif = vrectif + 0.577 * kc * if
else if in <= 0.75:
vinrectif = sqrt(vrectif^2 + (kc * if)^2) / 0.75
else:
vinrectif = (vrectif / 1.732) + kc * if
if vinrectif == vinest or nbtries > 5:
exit loop
nbtries = nbtries + 1
vinest = vinrectif

Signature: double precision function vcomp([v], [p], [q], {Kv}, {Rc}, {Xc})

Arguments: double precision :: Kv, Rc, Xc

Description: Returns the magnitude of a combination of terminal voltage and current of a synchronous machine. Appears in IEEE standard excitation models.

Model type: exc only.

Computation:

Vcomp=KvVˉ+(Rc+jXc)Iˉ=KvV+(Rc+jXc) ⁣(PVjQV)=1V(KvV2+RcP+XcQ)2+(XcPRcQ)2\begin{aligned} V_{comp} &= \left| K_v \bar{V} + (R_c + j X_c) \bar{I} \right| \\ &= \left| K_v V + (R_c + j X_c)\!\left(\frac{P}{V} - j\frac{Q}{V}\right) \right| \\ &= \frac{1}{V} \sqrt{\left(K_v V^2 + R_c P + X_c Q\right)^2 + \left(X_c P - R_c Q\right)^2} \end{aligned}

Signature: double precision function satur([ve], {ve1}, {se1}, {ve2}, {se2})

Arguments: double precision :: ve1, se1, ve2, se2

Description: Returns the increment of field current needed to obtain a given output voltage, accounting for magnetic saturation. Appears in IEEE excitation system models.

Model type: exc only.

Computation:

satur=mvensatur = m \, ve^n

where:

n=log10(se1/se2)log10(ve1/ve2)m=se1ve1n\begin{aligned} n &= \frac{\log_{10}(se1/se2)}{\log_{10}(ve1/ve2)} \\[4pt] m &= \frac{se1}{ve1^n} \end{aligned}

Exception. Returns satur=0satur = 0 if any of the following conditions holds:

ve0orve10orve20orve1=ve2orse1=0orse2=0ve \le 0 \quad \text{or} \quad ve1 \le 0 \quad \text{or} \quad ve2 \le 0 \quad \text{or} \quad ve1 = ve2 \quad \text{or} \quad se1 = 0 \quad \text{or} \quad se2 = 0