正如我们在上一节中所看到的,模型定义通常包含变量声明。变量声明的基本语法就是变量的“类型”(将在内置类型一节中简要讨论)后跟变量的名称,例如:
Real x;
具有相同类型的变量可以使用以下语法组合在一起:
Real x, y;
一个声明之后也可以跟着一段描述,例如:
Real alpha "angular acceleration";
变异性
参数说明
默认情况下,在模型内部声明的变量被假定为连续变量(其解通常是平滑的,但也可能包含不连续性)。然而,正如我们在“实现物理性”一节中首先看到的那样,还可以在变量声明之前添加参数限定符,并表明该变量是事先已知的。你可以将参数视为模型的“输入数据”,这些数据对于时间而言是恒定不变的。
常量
与参数限定符密切相关的是常量限定符。当置于变量声明之前时,常量限定符还意味着该变量的值事先已知,并且在时间上是恒定的。这两者的区别在于,参数值可以在不同的模拟中进行更改,而常量的值一旦模型编译完成就不能更改。模型开发者使用常量这一做法确保最终用户无法对常量进行修改。常量通常用于表示诸如 或 地球重力加速度等物理量,这些量在大多数工程模拟中可以假定是恒定的。
离散变量
在变量声明之前还可以添加一个限定词——离散限定词。我们尚未展示过任何与该限定词相关的示例。不过,现在将其纳入其中是为了完整性考虑,因为它是最后剩下的一个可变性限定词。
内置类型
到目前为止,许多示例在声明变量时都使用了“Real”类型。正如其名称所示,“Real”用于表示实数值变量(通常会被 Modelica 编译器转换为浮点数表示形式)。然而,“Real”只是 Modelica 中的四种内置类型之一。
另一种内置类型是整数类型。这种类型用于表示整数值。整数变量有多种用途,包括表示数组的大小(这种用法将在后续关于向量和数组的章节中不久进行详细讨论)。
其余的内置类型包括布尔型(用于表示可以为“真”或“假”的值)和字符串型(用于表示字符字符串)。
每种内置类型都会限制变量所能具有的值的范围。显然,整型变量不能取值 2.5,布尔型或字符串型变量不能为 7,实型变量也不能取值“Hello”。
派生类型
正如我们在之前介绍的“物理类型”的示例中所看到的,可以对内置类型进行“特化”。此功能主要用于修改与诸如单位这样的属性相关的值。创建派生类型的通用语法为:
type NewTypeName = BaseTypeName(/* attributes to be modified */);
通常情况下,基类型名称会是内置类型之一(例如“Real”)。但它也可以是另一个派生类型。这意味着可以支持多层的特化,例如:
type Temperature = Real(unit="K"); // Could be a temperature difference type AbsoluteTemperature = Temperature(min=0); // Must be positive
枚举列表
枚举类型与整数类型非常相似。枚举通常用于定义一种只能取有限特定值的类型。实际上,在该语言中,枚举并非绝对必要。其值总是可以用整数来表示的。然而,枚举类型比整数类型更安全、更易读。
有两个内置的枚举类型。其中第一个是“断言级别”,其定义如下:
type AssertionLevel = enumeration(warning, error);
这些价值观的重要性将在接下来关于“assert”这一章节中进行探讨。
另一个内置枚举是“StateSelect”,其定义如下:
type StateSelect = enumeration(never, avoid, default, prefer, always);
属性
在本章中,我们已经提到了一些属性(例如单位),但尚未对其进行详细讨论。例如,给定的变量具有哪些属性呢?这取决于该变量的类型(以及它所基于的内置类型和派生类型)。以下表格列出了所有可能的属性及其类型(即该属性可以接受何种类型的值)、它们可以与哪些类型相关联,以及最后对该属性的简要描述:
Real类型的属性
quantity
对变量所代表含义的文本描述 默认值:"" 类型:String
对变量所代表含义的文本描述
默认值:""
类型:String
start
“start”属性有多种用途。该属性的主要作用(正如在“初始化”部分中详细论述的那样)是为状态变量提供“备用”初始条件(有关更多详情,请参阅“fixed”属性)。 “start”属性也可用作初始猜测值,前提是该变量已被选作迭代变量。 最后,如果某个参数未明确指定具体值,那么“开始”属性的值将被用作该参数的默认值。 默认值:0.0 类型:Real
“start”属性有多种用途。该属性的主要作用(正如在“初始化”部分中详细论述的那样)是为状态变量提供“备用”初始条件(有关更多详情,请参阅“fixed”属性)。
“start”属性也可用作初始猜测值,前提是该变量已被选作迭代变量。
最后,如果某个参数未明确指定具体值,那么“开始”属性的值将被用作该参数的默认值。
默认值:0.0
类型:Real
fixed
“fixed”属性会改变当“起始”属性被用作初始条件时其使用方式。通常情况下,起始属性被视为一种“备用”初始条件,并且只有在初始方程部分未明确指定足够的初始条件时才会使用它。然而,如果将“固定”属性设置为“真”,那么起始属性就会被视为已作为明确的初始方程使用(即它不再作为备用条件使用,而是被视为严格的初始条件)。 固定属性的另一种不太常见的用法是用于“计算参数”。在极少数情况下,如果某个参数无法通过显式方式进行初始化,那么可以在初始方程部分提供该参数的通用计算公式。但如果是以这种方式对参数进行初始化的话,那么该参数变量的“固定”属性必须设置为“false”。 默认值:false(但参数变量的情况除外,在这种情况下默认值为真) 类型:Boolean
“fixed”属性会改变当“起始”属性被用作初始条件时其使用方式。通常情况下,起始属性被视为一种“备用”初始条件,并且只有在初始方程部分未明确指定足够的初始条件时才会使用它。然而,如果将“固定”属性设置为“真”,那么起始属性就会被视为已作为明确的初始方程使用(即它不再作为备用条件使用,而是被视为严格的初始条件)。
固定属性的另一种不太常见的用法是用于“计算参数”。在极少数情况下,如果某个参数无法通过显式方式进行初始化,那么可以在初始方程部分提供该参数的通用计算公式。但如果是以这种方式对参数进行初始化的话,那么该参数变量的“固定”属性必须设置为“false”。
默认值:false(但参数变量的情况除外,在这种情况下默认值为真)
类型:Boolean
min
“min”属性用于指定变量的最小允许值。此属性可由编辑器和编译器以多种方式使用,以向用户或开发人员告知可能存在无效输入数据或解决方案的信息。 默认值:-DBL_MAX,其中 DBL_MAX 是在当前平台能够表示的最大浮点数值。 类型:Real
“min”属性用于指定变量的最小允许值。此属性可由编辑器和编译器以多种方式使用,以向用户或开发人员告知可能存在无效输入数据或解决方案的信息。
默认值:-DBL_MAX,其中 DBL_MAX 是在当前平台能够表示的最大浮点数值。
max
“max”属性用于指定变量所能接受的最大值。编辑人员和编译器可以通过多种方式使用此属性,向用户或开发人员告知可能存在无效的输入数据或解决方案。 默认值:DBL_MAX(其中 DBL_MAX 是在当前平台能够表示的最大浮点数值)。 类型:Real
“max”属性用于指定变量所能接受的最大值。编辑人员和编译器可以通过多种方式使用此属性,向用户或开发人员告知可能存在无效的输入数据或解决方案。
默认值:DBL_MAX(其中 DBL_MAX 是在当前平台能够表示的最大浮点数值)。
unit
正如本章中所详述的那样,变量可以与特定的物理单位相关联。关于这些单位的表示方式存在一些规则,但最终结果是,通过使用“单位”属性,可以检查模型以确保方程在物理上是一致的。值“1”表示该值没有物理单位。另一方面,值“”(如果未给出值则为默认值)表示物理单位并未明确指定。“1”和“”之间的区别在于,前者明确表示该量是无量纲的(没有单位),而后者则表示该量可能有物理单位,但这些单位未作明确说明。 默认值:空字符串(即未指定任何物理单位) 类型:String
正如本章中所详述的那样,变量可以与特定的物理单位相关联。关于这些单位的表示方式存在一些规则,但最终结果是,通过使用“单位”属性,可以检查模型以确保方程在物理上是一致的。值“1”表示该值没有物理单位。另一方面,值“”(如果未给出值则为默认值)表示物理单位并未明确指定。“1”和“”之间的区别在于,前者明确表示该量是无量纲的(没有单位),而后者则表示该量可能有物理单位,但这些单位未作明确说明。
默认值:空字符串(即未指定任何物理单位)
displayUnit
“unit”属性描述了应与变量值关联的物理单位是什么,而“displayUnit”则表达了在显示变量值时应采用何种单位的偏好。例如,压力的国际单位是帕斯卡。然而,标准大气压为 101,325 帕斯卡。在输入、显示或绘制压力时,使用巴作为单位可能会更方便。 “displayUnit”属性不会影响变量的值或用于模拟模型的方程式。它仅影响这些值的呈现方式,可能会将它们转换为更适合显示的单位。 默认值: "" 类型:String
“unit”属性描述了应与变量值关联的物理单位是什么,而“displayUnit”则表达了在显示变量值时应采用何种单位的偏好。例如,压力的国际单位是帕斯卡。然而,标准大气压为 101,325 帕斯卡。在输入、显示或绘制压力时,使用巴作为单位可能会更方便。
“displayUnit”属性不会影响变量的值或用于模拟模型的方程式。它仅影响这些值的呈现方式,可能会将它们转换为更适合显示的单位。
默认值: ""
nominal
“nominal”名义属性用于为变量指定一个名义值。这个名义值通常在数值计算中使用,以执行各种类型的缩放操作,从而避免舍入或截断误差。 默认设置: 类型:Real
“nominal”名义属性用于为变量指定一个名义值。这个名义值通常在数值计算中使用,以执行各种类型的缩放操作,从而避免舍入或截断误差。
默认设置:
stateSelect
stateSelect 属性用于向 Modelica 编译器提供提示,告知其某个变量是否应被选作状态变量(在需要进行选择的情况下)。正如在关于枚举的章节中之前所讨论的,此属性的可能取值为“从不”、“避免”、“默认”、“优先”和“总是”。 默认值:default 类型:StateSelect(枚举类型,详见枚举)
stateSelect 属性用于向 Modelica 编译器提供提示,告知其某个变量是否应被选作状态变量(在需要进行选择的情况下)。正如在关于枚举的章节中之前所讨论的,此属性的可能取值为“从不”、“避免”、“默认”、“优先”和“总是”。
默认值:default
类型:StateSelect(枚举类型,详见枚举)
Integer类型的属性
对变量所代表含义的文本描述 默认值:"" 类型: String
类型: String
值得注意的是,整型变量既可以作为状态变量使用,也可以作为迭代变量使用。在这种情况下,编译器可以像对待实型变量那样使用“起始”属性(请参阅之前关于实型变量属性的讨论) 对于参数而言,其“起始”属性(通常情况下)将被用作该参数的默认值。 默认值:0.0 类型:Integer
值得注意的是,整型变量既可以作为状态变量使用,也可以作为迭代变量使用。在这种情况下,编译器可以像对待实型变量那样使用“起始”属性(请参阅之前关于实型变量属性的讨论)
对于参数而言,其“起始”属性(通常情况下)将被用作该参数的默认值。
类型:Integer
参见关于“Real类型的属性”的之前讨论内容 默认值:false(但参数变量的情况除外,在这种情况下默认值为真) 类型:Boolean
参见关于“Real类型的属性”的之前讨论内容
“min”属性用于指定变量的最小允许值。此属性可由编辑器和编译器以多种方式使用,以向用户或开发人员告知可能存在无效输入数据或解决方案的信息。 默认值:- 类型:Integer
默认值:-
“max”属性用于指定变量所能接受的最大值。编辑人员和编译器可以通过多种方式使用此属性,向用户或开发人员告知可能存在无效的输入数据或解决方案。 默认设置: 类型:Integer
Boolean类型的属性
值得注意的是,布尔型变量既可以作为状态变量使用,也可以作为迭代变量使用。在这种情况下,编译器在使用“开始”属性时的方式与使用实型变量时的方式相同(请参阅之前关于实型变量属性的讨论) 对于参数而言,其“起始”属性(通常情况下)将被用作该参数的默认值。 默认值:0.0 类型:Boolean
值得注意的是,布尔型变量既可以作为状态变量使用,也可以作为迭代变量使用。在这种情况下,编译器在使用“开始”属性时的方式与使用实型变量时的方式相同(请参阅之前关于实型变量属性的讨论)
参见关于“ Real类型的属性”的之前讨论内容 默认值:false(但参数变量的情况除外,在这种情况下默认值为真) 类型:Boolean
参见关于“ Real类型的属性”的之前讨论内容
String类型的属性
从技术上讲,字符串可以被用作状态变量(甚至可以作为迭代变量),但在实际应用中这种情况从不会出现。因此,对于字符串变量而言,start 属性的唯一实际用途是定义参数的值(如果未给定参数的明确值,则该参数的值将为字符串类型)。 默认值:"" 类型:String
从技术上讲,字符串可以被用作状态变量(甚至可以作为迭代变量),但在实际应用中这种情况从不会出现。因此,对于字符串变量而言,start 属性的唯一实际用途是定义参数的值(如果未给定参数的明确值,则该参数的值将为字符串类型)。
值得注意的是,派生类型会保留其最终派生自的内置类型的属性。此外,例如,实型变量上的“最小值”属性的类型虽然被列为实型,但必须明确指出的是,属性本身不能具有属性。换句话说,“起始”属性本身并没有“起始”属性这一属性。
修正
到目前为止,我们已经看到了两种类型的修改方式。第一种是当我们更改某个属性的值时,例如:
Real x(start=10);
在这种情况下,我们创建了一个名为“x”的实数类型变量。但我们并非直接保持其原样,而是对“x”进行了修改。具体来说,我们“深入”到“x”内部,并更改了其“起始”属性值。在这个例子中,我们仅深入到“x”一层来进行修改。但正如我们在下一个例子中将会看到的,也可以在任意深度进行修改。
我们还见过一次修改的情况,是在“避免重复”这一部分。在那里,我们看到了修改与“扩展子句”相结合的使用方式,例如:
extends QuiescentModelWithInheritance(gamma=0.3, delta=0.01);
在这里,这种修改是针对从“静止模型(具有继承性)”模型继承而来的元素进行的。与对属性的修改一样,被修改的元素(在此情况下为一个模型)后面跟着一对括号,而在括号内我们则指明了我们想要进行的修改。
值得注意的是,修改操作可以任意深度嵌套。例如,假设我们想要修改从“QuiescentModelWithInheritance”模型继承而来的变量“x”的“start”属性。在 Modelica 中,这样的修改应如下进行:
extends QuiescentModelWithInheritance(x(start=5));
首先,我们“深入”到“静止模型带继承”这一模型中,对从它那里“继承”而来的内容(在此例中为“x”)进行修改,然后我们再“深入”到“x”内部,对“start”属性的值进行修改。
Modelica 的核心主题之一是支持代码的复用,并避免“复制粘贴”代码的需求。在 Modelica 中,修改功能是支持复用的重要特性之一。我们将在后续章节中了解其他相关特性。