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:
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:
where Re
is the Reynolds number, A
is
the area, q
is volumetric flow rate, and
ν is the kinematic viscosity.
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 theintermediates
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 theequations
section — Declare intermediate terms in the declaration clause and use them in the expression clause of the samelet
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.
Declaring and Using Named Intermediate Terms
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.
Syntax Rules and Restrictions
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 identifierf
(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
Use in Equations
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 = MyNamespace.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.
Data Logging
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 Simscape Results
Explorer.
Using the 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.
Syntax Rules of let
Expressions
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 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
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
. Performing substitution on
this example yields: a
< 0
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 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
are declared as the
conditional expression based on
.
Notice that each side of the a
< 0if
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