Defining Component Equations

Equation Section Purpose

The equation section of a Simscape™ file follows the declaration, setup, and structure sections. It is executed throughout the simulation. The purpose of the equation section is to establish the mathematical relationships among a component's variables, parameters, inputs, outputs, time and the time derivatives of each of these entities.

A Simscape language equation consists of two expressions connected with the == operator. Unlike the regular assignment operator (=), the == operator specifies continuous mathematical equality between the two expressions (for more information, see Specifying Mathematical Equality). The equation expressions may be constructed from any of the identifiers defined in the model declaration. You can also access global simulation time from the equation section using the time function.

Equations in Simscape Language

Simple Algebraic System

This example shows implementation for a simple algebraic system:

y = x2

x = 2y + 1

The Simscape file looks as follows:

component MyAlgebraicSystem
  variables
    x = 0;
    y = 0;
  end
  equations
    y == x^2;        % y = x^2
    x == 2 * y + 1;  % x = 2 * y + 1
  end
end

Using Simulation Time in Equations

You can access global simulation time from the equation section using the time function. time returns the simulation time in seconds.

The following example illustrates y = sint), where t is simulation time:

component
  parameters
    w = { 1, ‘1/s' } % omega
  end
  outputs
    y = 0;
  end
  equations
    y == sin( w * time );
  end
end

Specifying Mathematical Equality

Simscape language stipulates semantically that all the equation expressions returned by the equation section of a Simscape file specify continuous mathematical equality between two expressions. Consider a simple example:

equations
   Expression1 == Expression2;
end

Here we have declared an equality between Expression1 and Expression2. The left- and right-hand side expressions are any valid MATLAB® expressions (see the next section for restrictions on using the relational operators: ==, <, >, <=, >=, ~=, &&, ||). The equation expressions may be constructed from any of the identifiers defined in the model declaration.

The equation is defined with the == operator. This means that the equation does not represent assignment but rather a symmetric mathematical relationship between the left- and right-hand operands. Because == is symmetric, the left-hand operand is not restricted to just a variable. For example:

component MyComponent
  [...]
  variables
    a = 1;
    b = 1;
    c = 1;
  end
  equations
    a + b == c;
  end
end

The following example is mathematically equivalent to the previous example:

component MyComponent
  [...]
  variables
    a = 1;
    b = 1;
    c = 1;
  end
  equations
    0 == c - a - b;
  end
end

    Note   Equation expressions must be terminated with a semicolon or a newline. Unlike MATLAB, the absence of a semicolon makes no difference. In any case, Simscape language does not display the result as it evaluates the equation.

Use of Relational Operators in Equations

In the previous section we discussed how == is used to declare mathematical equalities. In MATLAB, however, == yields an expression like any other operator. For example:

(a == b) * c;

where a, b, and c represent scalar double values, is a legal MATLAB expression. This would mean, take the logical value generated by testing a's equivalence to b, coerce this value to a double and multiply by c. If a is the same as b, then this expression will return c. Otherwise, it will return 0.

On the other hand, in MATLAB we can use == twice to build an expression:

a == b == c;

This expression is ambiguous, but MATLAB makes == and other relational operators left associative, so this expression is treated as:

(a == b) == c;

The subtle difference between (a == b) == c and a == (b == c) can be significant in MATLAB, but is even more significant in an equation. Because the use of == is significant in the Simscape language, and to avoid ambiguity, the following syntax:

component MyComponent
  [...]
  equations
    a == b == c;
  end
end

is illegal in the Simscape language. You must explicitly associate top-level occurrences of relational operators. Either

component MyComponent
  [...]
  equations
    (a == b) == c;
  end
end

or

component MyComponent
  [...]
  equations
    a == (b == c);
  end
end

are legal. In either case, the quantity in the parentheses is equated to the quantity on the other side of the equation.

With the exception of the top-level use of the == operator, == and other relational operators are left associative. For example:

component MyComponent
  [...]
  parameters
    a = 1;
    b = 1;
    c = false;
  end
  variables
    d = 1;
  end
  equations
    (a == b == c) == d;
  end
end

is legal and interpreted as:

component MyComponent
  [...]
  parameters
    a = 1;
    b = 1;
    c = false;
  end
  variables
    d = 1;
  end
  equations
    ((a == b) == c) == d;
  end
end

Equation Dimensionality

The expressions on either side of the == operator need not be scalar expressions. They must be either the same size or one must be scalar. For example:

equations
  [...]
  <3x3 Expression> == <3x3 Expression>;
  [...]
end

is legal and introduces 9 scalar equations. The equation expression:

equations
  [...]
  <1x1 Expression> == <3x3 Expression>;
  [...]
end

is also legal. Here, the left-hand side of the equation is expanded, via scalar expansion, into the same expression replicated into a 3x3 matrix. This equation expression also introduces 9 scalar equations.

However, the equation expression:

equations
  [...]
  <2x3 Expression> == <3x2 Expression>;
  [...]
end

is illegal because the sizes of the expressions on the left- and right-hand side are different.

Equation Continuity

The equation section is evaluated in continuous time. Some of the values that are accessible in the equation section are themselves piecewise continuous, that is, they change continuously in time. These values are:

  • variables

  • inputs

  • outputs

  • time

Piecewise continuous indicates that values are continuous over compact time intervals but may change value at certain instances. The following values are continuous, but not time-varying:

  • parameters

  • constants

Time-varying countable values, for example, integer or logical, are never continuous.

Continuity is propagated like a data type. It is propagated through continuous functions (see Supported Functions).

Using Conditional Expressions in Equations

You can specify conditional equations by using if statements.

equations
  [...]
  if Expression
    [...]
  elseif Expression
    [...]
  else
    [...]
  end
  [...]
end

Each [...] section may contain one or more equation expressions.

You can nest if statements, for example:

equations
  [...]
  if Expression
    [...]
    if Expression
       [...]
    else
    [...]
    end
  else
    [...]
  end
  [...]
end

Restrictions

  • Every if requires an else.

  • The total number of equation expressions, their dimensionality, and their order must be the same for every branch of the if-elseif-else statement. However, this rule does not apply to the assert expressions, because they are not included in the expression count for the branch.

  • Every branch of the if-elseif-else statement must define the same variable in terms of others. For example, you can design a hydraulic orifice with if-else branches for turbulent and laminar flow, where each branch defines flow rate in terms of pressure. However, a conditional expression similar to the following

    if x > 0
        i == 0;
    else
        v == 0;
    end

    is forbidden.

Example

For a component where x and y are declared as 1x1 variables, specify the following piecewise equation:

y={xfor 1<= x<=1x2otherwise 

This equation, written in the Simscape language, would look like:

equations
  if x >= -1 && x <= 1
    y == x;
  else
    y == x^2;
  end
end

Another way to write this equation in the Simscape language is:

equations
  y == if x>=-1 && x<=1, x else x^2 end
end

Using Intermediate Terms in Equations

Why Use Intermediate Terms?

Textbooks often define certain equation terms in separate equations, and then substitute these intermediate equations into the main one. For example, for fully developed flow in ducts, the Darcy friction factor can be used to compute pressure loss:

P=f·L·ρ·V22D

where P is pressure, f is the Darcy friction factor, L is length, ρ is density, V is flow velocity, and D is hydraulic area.

These terms are further defined by:

f=0.316Re1/4

Re=D·Vν

D=4Aπ

V=qA

where Re is the Reynolds number, A is the area, q is volumetric flow rate, and ν is the kinematic viscosity.

In Simscape language, you can define intermediate terms and use them in one or more equations by using the let expressions. The following example shows the same equations written out in Simscape language:

component MyComponent
  [...]
  parameters
    L   = { 1,    'm' };      % length
    rho = { 1e3,  'kg/m^3' }; % density
    nu  = { 1e-6, 'm^2/s' };  % kinematic viscosity
  end
  variables
    p    = { 0, 'Pa' };       % pressure
    q    = { 0, 'm^3/s' };    % volumetric flow rate
    A    = { 0, 'm^2' };      % area
  end
  equations
    let
      f    = 0.316 / Re_d^0.25;    % Darcy friction factor
      Re_d = D_h * V / nu;         % Reynolds number
      D_h  = sqrt( 4.0 * A / pi ); % hydraulic area
      V    = q / A;                % flow velocity
    in
      p == f * L * rho * V^2 / (2 * D_h); % final equation
    end
  end
end

After substitution of all intermediate terms, the final equation becomes:

p==0.316/(sqrt(4.0 * A / pi) * q / A / nu)^0.25 * L * rho * (q / A)^2 / (2 * sqrt(4.0 * A / pi));

Syntax Rules

A let expression consists of two clauses, the declaration clause and the expression clause.

equations
  [...]
  let 
    declaration clause
  in
    expression clause
  end
  [...]
end

The declaration clause assigns an identifier, or set of identifiers, on the left-hand side of the equal sign (=) to an equation expression on the right-hand side of the equal sign:

  LetValue = EquationExpression

The expression clause defines the scope of the substitution. It starts with the keyword in, and may contain one or more equation expressions. All the expressions assigned to the identifiers in the declaration clause are substituted into the equations in the expression clause during parsing.

    Note   The end keyword is required at the end of a let-in-end statement.

Here is a simple example:

component MyComponent
  [...]
  variables
    x = 0;
    y = 0;
  end
  equations
    let
      z = y + 1;
    in
      x == z;
    end
  end
end

In this example, the declaration clause of the let expression sets the value of the identifier z to be the expression y + 1. Thus, substituting y + 1 for z in the expression clause in the let statement, the code above is equivalent to:

component MyComponent
  [...]
  variables
    x = 0;
    y = 0;
  end
  equations
    x == y + 1;
  end
  end
end

There may be multiple declarations in the declaration clause. These declarations are order independent. The identifiers declared in one declaration may be referred to by the expressions for identifiers in other declarations in the same declaration clause. Thus, in the code example shown in the previous section, the identifier Re_d (Reynolds number) is used in the expression declaring the identifier f (Darcy friction factor). The only requirement is that the expression references are acyclic.

The expression clause of a let expression defines the scope of the substitution for the declaration clause. Other equations, that do not require these substitutions, may appear in the equation section outside of the expression clause. In the following example, the equation section contains the equation expression c == b + 2 outside the scope of the let expression before it.

component MyComponent
  [...]
  variables
    a = 0;
    b = 0;
    c = 0;
  end
  equations
    let
      x = a + 1;
    in
      b == x;
    end
    c == b + 2;
  end
end

These expressions are treated as peers. They are order independent, so this example is equivalent to

component MyComponent
  [...]
  variables
    a = 0;
    b = 0;
    c = 0;
  end
  equations
    c == b + 2;
    let
      x = a + 1;
    in
      b == x;
    end
  end
end

and, after the substitution, to

component MyComponent
  [...]
  variables
    a = 0;
    b = 0;
    c = 0;
  end
  equations
    b == a + 1;
    c == b + 2;
  end
end

Nested let Expressions

You can nest let expressions, for example:

component MyComponent
  [...]
  variables
    a = 0;
    b = 0;
    c = 0;
  end
  equations
    let
      w = a + 1;
    in
      let
        z = w + 1;
      in
        b == z;
        c == w;
      end
    end
  end
end

In case of nesting, substitutions are performed based on both of the declaration clauses. After the substitutions, the code above becomes:

component MyComponent
  [...]
  variables
    a = 0;
    b = 0;
    c = 0;
  end
  equations
    b == a + 1 + 1;
    c == a + 1;
  end
end

The innermost declarations take precedence. The following example illustrates a nested let expression where the inner declaration clause overrides the value declared in the outer one:

component MyComponent
  [...]
  variables
    a = 0;
    b = 0;
  end
  equations
    let
      w = a + 1;
    in
      let
        w = a + 2;
      in
        b == w;
      end
    end
  end
end

Performing substitution on this example yields:

  component MyComponent
  [...]
  variables
    a = 0;
    b = 0;
  end
  equations
    b == a + 2;
  end
end

Conditional let Expressions

You can use if statements within both declarative and expression clause of let expressions, for example:

component MyComponent
  [...]
  variables
    a = 0;
    b = 0;
    c = 0;
  end
  equations
    let
      x = if a < 0, a else b end;
    in
      c == x;
    end
  end
end

Here x is declared as the conditional expression based on a < 0. Performing substitution on this example yields:

component MyComponent
  [...]
  variables
    a = 0;
    b = 0;
    c = 0;
  end
  equations
    c == if a < 0, a else b end;
  end
end

The next example illustrates how you can use let expressions within conditional expressions. The two let expressions on either side of the conditional expression are independent:

component MyComponent
  [...]
  variables
    a = 0;
    b = 0;
    c = 0;
  end
  equations
    if a < 0
      let
        z = b + 1;
      in
        c == z;
      end
    else
      let
        z = b + 2;
      in
        c == z;
      end
    end
  end
end

This code is equivalent to:

  component MyComponent
  [...]
  variables
    a = 0;
    b = 0;
    c = 0;
  end
  equations
    if a < 0
      c == b + 1;
    else
      c == b + 2;
    end
  end
end

Identifier List in the Declarative Clause

This example shows using an identifier list, rather that a single identifier, in the declarative clause of a let expression:

component MyComponent
  [...]
  variables
    a = 0;
    b = 0;
    c = 0;
    d = 0;
  end
  equations
    let
      [x, y] = if a < 0, a; -a else -b; b end;
    in
      c == x;
      d == y;
    end
  end
end

Here x and y are declared as the conditional expression based on a < 0. Notice that each side of the if statement defines a list of two expressions. A first semantic translation of this example separates the if statement into

if a < 0, a; -a else -b; b end => 
   { if a < 0, a else -b end; if a < 0, -a else b end }

then the second semantic translation becomes

[x, y] = { if a < 0, a else -b end; if a < 0, -a else b end } => 
   x = if a < 0, a else -b end; y = if a < 0, -a else b end;

and the final substitution on this example yields:

component MyComponent
  [...]
  variables
    a = 0;
    b = 0;
    c = 0;
    d = 0;
  end
  equations
    c == if a < 0, a else -b end;
    d == if a < 0, -a else b end;
  end
end

Using Lookup Tables in Equations

You can use the tablelookup function in the equations section of the Simscape file to interpolate input values based on a set of data points in a one-dimensional or two-dimensional table. This functionality is similar to that of the Simulink® and Simscape Lookup Table blocks. It allows you to incorporate table-driven modeling directly in your custom block, without the need of connecting an external Lookup Table block to your model.

The following example implements mapping temperature to pressure using a one-dimensional lookup table.

component TtoP
 inputs
   u = {0, 'K'}; % temperature
 end
 outputs
   y = {0, 'Pa'}; % pressure
 end
 parameters (Size=variable)
   xd = {[100 200 300 400] 'K'};
   yd = {[1e5 2e5 3e5 4e5] 'Pa'};
 end
 equations
   y == tablelookup(xd, yd, u, interpolation=linear, extrapolation=nearest);
 end
end

xd and yd are declared as variable-size parameters with units. This enables the block users to provide their own data sets when the component is converted to a custom block, and also to select commensurate units from the drop-downs in the custom block dialog box. The next illustration shows the dialog box of the custom block generated from this component.

    Note   Currently, you can not use variable-size parameters in the equations section outside of the tablelookup function.

    To avoid repeating the same variable-size parameter declarations in each component that needs to use them in its tablelookup function, you can declare variable-size domain parameters and propagate them to components for interpolation purposes. For more information, see Propagation of Domain Parameters.

The following rules apply to the one-dimensional arrays xd and yd:

  • The two arrays must be of the same size.

  • For cubic or spline interpolation, each array must contain at least three values. For linear interpolation, two values are sufficient.

  • The xd values must be strictly monotonic, either increasing or decreasing.

If these rules are violated by...You get an error...
The block author, in the component Simscape fileAt build time, when running ssc_build to convert the component to a custom block
The block user, when entering values in the block dialog boxAt simulation time, when attempting to simulate the model containing the custom block

The TtoP component uses linear interpolation for values within the table range, but outputs the nearest value of yd for out-of-range input values. The following illustration shows a block diagram, where the custom TtoP block is used with a linear input signal changing from 0 to 1000, and the resulting output.

See the tablelookup reference page for syntax specifics and more examples.

Programming Run-Time Errors and Warnings

Use the assert construct to implement run-time error and warning messages for a custom block. In the component file, you specify the condition to be evaluated, as well as the error message to be output if this condition is violated. When the custom block based on this component file is used in a model, it will output this message if the condition is violated during simulation. The Warn attribute of the assert construct specifies whether simulation stops when the predicate condition is violated, or continues with a warning.

The following component file implements a variable resistor, where input physical signal R supplies the resistance value. The assert construct checks that this input signal is greater than or equal to zero:

component MyVariableResistor
% Variable Resistor
% Models a linear variable resistor. The relationship between voltage V
% and current I is V=I*R where R is the numerical value presented at the
% physical signal port R. If this signal becomes negative, simulation
% errors out.
%

  inputs
    R = { 0.0, 'Ohm' };
  end

  nodes
    p = foundation.electrical.electrical; % +:left
    n = foundation.electrical.electrical; % -:right
  end

  variables
    i = { 0, 'A' };
    v = { 0, 'V' };
  end

  branches
    i : p.i -> n.i;
  end

  equations
    assert( R >= 0, 'Negative resistance is not modeled' );
    v == p.v - n.v;
    v == i*R;
  end

end

If a model contains this Variable Resistor block, and signal R becomes negative during simulation, then simulation stops and the Simulation Diagnostics window opens with a message similar to the following:

At time 3.200000, an assertion is triggered. Negative resistance is not modeled.
The assertion comes from:
Block path: dc_motor1/Variable Resistor
Assert location: between line: 29, column: 14 and line: 29, column: 18 in file:
C:/Work/libraries/+MySimscapeLibrary/+ElectricalElements/MyVariableResistor.ssc

The error message contains the following information:

  • Simulation time when the assertion got triggered

  • The message string (in this example, Negative resistance is not modeled)

  • An active link to the block that triggered the assertion. Click the Block path link to highlight the block in the model diagram.

  • An active link to the assert location in the component source file. Click the Assert location link to open the Simscape source file of the component, with the cursor at the start of violated predicate condition. For Simscape protected files, the Assert location information is omitted from the error message.

See the assert reference page for syntax specifics and more examples.

Working with Physical Units in Equations

In Simscape language, you declare members (such as parameters, variables, inputs, and outputs) as value with unit, and the equations automatically handle all unit conversions.

However, empirical formulae often employ noninteger exponents where the base is either unitless or in known units. When working with these types of formulae, convert the base to a unitless value using the value function and then reapply units if needed.

For example, the following formula gives the pressure drop, in Pa, in terms of flow rate, in m^3/s:

p == k * q^1.023 

where p is pressure, q is flow rate and k is some unitless constant. To write this formula in Simscape language, use:

p == { k * value(q, 'm^3/s')^1.023, 'Pa' } 

This approach works regardless of the actual units of p or q, as long as they are commensurate with pressure and volumetric flow rate, respectively. For example, the actual flow rate can be in gallons per minute, the equation will still work and handle the unit conversion automatically.

Was this topic helpful?