Main Content

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=\frac{f\xb7L\xb7\rho \xb7{V}^{2}}{2D}$$

where * P* is pressure,

`f`

`L`

`V`

`D`

These terms are further defined by:

$$f=\frac{0.316}{{\mathrm{Re}}^{1/4}}$$

$$\mathrm{Re}=\frac{D\xb7V}{\nu}$$

$$D=\sqrt{\frac{4A}{\pi}}$$

$$V=\frac{q}{A}$$

where * Re* is the Reynolds number,

`A`

`q`

In Simscape™ language, there are two ways that you can define intermediate terms for use in equations:

`intermediates`

section — Declare reusable named intermediate terms in the`intermediates`

section in a component or domain file. You can reuse these intermediate terms in any equations section within the same component file, in an enclosing composite component file, or in any component that has nodes of that domain type.`let`

expressions in the`equations`

section — Declare intermediate terms in the declaration clause and use them in the expression clause of the same`let`

expression. Use this method if you need to define intermediate terms of limited scope, for use in a single group of equations. This way, the declarations and equations are close together, which improves code readability.

Another advantage of using named intermediate terms instead of
`let`

expressions is that you can include named
intermediate terms in simulation data logs.

The following example shows the same Darcy-Weisbach equation with intermediate terms 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 intermediates 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 diameter V = q / A; % Flow velocity end equations 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));

When you use this component in a model and log simulation data, the logs will include
data for the four intermediate terms, with their descriptive names (such as ```
Darcy
friction factor
```

) shown in the Simscape Results Explorer.

The `intermediates`

section in a component file lets
you define named intermediate terms for use in equations. Think of named intermediate terms
as of defining an alias for an expression. You can reuse it in any equations section within
the same file or an enclosing composite component. When an intermediate term is used in an
equation, it is ultimately substituted with the expression that it refers to.

You can also include an `intermediates`

section in a
domain file and reuse these intermediate terms in any component that has nodes of that
domain type.

You declare an intermediate term by assigning a unique identifier on the left-hand
side of the equal sign (`=`

) to an expression on the right-hand side of
the equal sign.

The expression on the right-hand side of the equal sign:

Can refer to other intermediate terms. For example, in the Darcy-Weisbach equation, the identifier

`Re_d`

(Reynolds number) is used in the expression declaring the identifier`f`

(Darcy friction factor). The only requirement is that these references are acyclic.Can refer to parameters, variables, inputs, outputs, member components and their parameters, variables, inputs, and outputs, as well as Across variables of domains used by the component nodes.

Cannot refer to Through variables of domains used by the component nodes.

You can use intermediate terms in equations, as described in Use in Equations. However, you
cannot access intermediate terms in the `setup`

function.

Intermediate terms can appear in simulation data logs and Simscape Results Explorer, as described in Data Logging. However, intermediate terms do not appear in:

Variable Viewer

Statistics Viewer

Operating Point data

Block dialog boxes and Property Inspector

After declaring an intermediate term, you can refer to it by its identifier anywhere in the equations section of the same component. For example:

component A [...] parameters p1 = { 1, 'm' }; end variables v1 = { 0, 'm' }; v2 = { 0, 'm^2' }; end intermediates int_expr = v1^2 * pi / p1; end equations v2 == v1^2 + int_expr; end end

You can refer to a public intermediate term declared in a member component in the equations of an enclosing composite component. For example:

component B [...] components comp1 = MyPackage.A; end variables v1 = { 0, 'm^2' }; end [...] equations v1 == comp1.int_expr; end end

Similarly, you can refer to an intermediate term declared in a domain in the equations section of any component that has nodes of this domain type. For example:

domain D [...] intermediates int_expr = v1 / sqrt(2); end [...] end

component C [...] nodes n = D; end variables v1 = { 0, 'V' }; end [...] equations v1 == n.int_expr; end end

Accessibility of intermediate terms outside of the file where they are declared is
governed by their `Access`

attribute value. For mode information, see
Attribute Lists.

Intermediate terms with `ExternalAccess`

attribute values of
`modify`

or `observe`

are included in simulation data
logs. For mode information, see Attribute Lists.

If you specify a descriptive name for an intermediate term, this name appears in the status panel of the Simscape Results Explorer.

For example, you declare the intermediate term `D_h`

(hydraulic
diameter) as a function of the orifice area:

component E [...] intermediates D_h = sqrt( 4.0 * A / pi ); % Hydraulic diameter end [...] end

When you use a block based on this component in a model and log simulation data,
selecting `D_h`

in the Simscape Results Explorer tree on the left displays a plot of the values of the
hydraulic diameter over time in the right pane and the name ```
Hydraulic
diameter
```

in the status panel at the bottom. For more information, see About the Simscape Results Explorer.

`let`

Expressions`let`

expressions provide another way to define intermediate terms for
use in one or more equations. Use this method if you need to define intermediate terms of
limited scope, for use in a single group of equations. This way, the declarations and
equations are close together, which improves file readability.

The following example shows the same Darcy-Weisbach equation as in the beginning of this
topic but with intermediate terms written out using the `let`

expression:

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 diameter 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));

However, in this case the four intermediate terms do not appear in logged simulation data.

`let`

ExpressionsA `let`

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

equations [...] letdeclaration clauseinexpression clauseend [...] 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`

`y`

`z`

`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 example with the Darcy-Weisbach equation, 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

`let`

ExpressionsYou 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

`let`

ExpressionsYou 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

This example shows using an identifier list, rather than 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`

`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