初始化

概述

正如我们先前在稳定状态初始化这节中提到过的,初始化是由一个模型中的两个方程和模型中初始条件给定的状态变量来描述的。在Modelica中,初始条件是通过结合普通方程(在 equation(方程)区域描述)和初始化方程(在initial equation(初始方程)区域中描述)来计算的。

对于初学者来说第一个混淆的来源是理解需要多少初始条件。这个问题的答案是简单的。为了有一个适定的初始化问题(就是没有过多或者过少的初始方程),需要如之前在系统中提到的在initial equation(初始方程)中具有相同数量的方程。注意,应当避免有太少的初始方程,因为工具可以增加我们给定的初始方程的数量直到问题适定,但是如果初始方程太多那问题就不能求解。

当然,提到初始方程的数量等于状态的数量只回答了一个问题,却很快产生了另一个问题。例如,要如何决定需要多少状态?对于本章中的模型,这个答案很简单。目前为止每个例子中的出现在der(...)操作中的状态都是变量。换句话说,例子中不同的变量表示一个状态。

常微分方程

需要注意的是,我们进行微分的每个变量并不总是状态。这章中,目前看到的所有模型都是常微分方程(ODEs)。当处理ODEs时,每个不同的变量都是状态。也就是说,每个初始变量需要一个初始方程。但是在接下来的章节中我们将会遇到所谓的微分代数方程(DAEs)。在这些方程中,仅仅只有一些微分变量可以认为是状态。

事实上理解初始化不需要详细讨论DAEs。实际上,所有的Modelica工具都要执行所谓的指标约简(index reduction)。但是指标约简算法本身是相当的复杂(因为现在不讨论),而效果却相当简单。指标约简将DAEs转化为ODEs。换句话说,Modelica编译器将包含Modelica代码的DAE问题转化为相对简单的ODE形式。

因此忽略DAEs和指标约简的讨论。我们假定问题已经转化为ODE,然后再讨论初始化。在这种情况下,只需要理解模型中的每个状态都需要初始化。模型将具有如下的ODE形式:

\[\begin{split}\dot{\vec{x}}(t) &= \vec{f}(\vec{x}(t), \vec{u}(t), t) \\ \vec{y}(t) &= \vec{g}(\vec{x}(t), \vec{u}(t), t)\end{split}\]

\(t\)是当前模拟的时间。\(\vec{x}(t)\)是系统时间为\(t\)时的状态值。\(\vec{u}(t)\)是系统时间为\(t\)时的外部输入。

注意,变量上部的箭头仅仅指的是这个变量是个矢量而不是标量。这个问题中出现的唯一的变量是\(\vec{x}\)\(\vec{x}\)代表了系统的状态。另外需要注意的是两个函数无论是\(\vec{f}\)还是\(\vec{g}\)都不依赖于变量\(\vec{y}\)

思考后,你会发现\(t\)\(\vec{u}(t)\)都是系统外部的量。所以,我们没有必要计算或者控制这些量。之所以认为\(\vec{x}\)是系统状态,原因在于它是计算\(\dot{\vec{x}}(t)\)\(\vec{y}(t)\)时所需要(从系统中获取)的唯一信息。

回到最初的初始化的主题,在一个正常的时间步内,将\(\dot{\vec{x}}(t)\)积分来求解 \(\vec{x}(t)\)。换句话说:

\[\vec{x}(T) = \int_{t_i}^{T} \dot{\vec{x}}(t) \ \mathrm{d}t + \vec{x}(t_i)\]

这只要前一个时间步就可以进行下去。当没有前面的时间步,那么插入方程的\(\vec{x}\)的值将成为模拟的第一个\(\vec{x}\)值。换句话说,这也就是初始条件。

可以想象,通过指定如下方程来指定初始条件:

\[\vec{x}(t_0) = \vec{x}_0\]

\(t_0\)是模拟的起始时间。\(\vec{x}_0\)是具体的初始值。为状态提供具体的值是指定初始条件最常见的情况。因此需要处理这种情况。但是这个方法在稳定状态初始化中是不起作用的。那种情况下我们不需要为状态提供具体的初始值。相反,我们要为 \(\dot{\vec{x}}(t_0)\) 提供初始值。那如何处理这两种情况呢?

初始方程

答案是假定在模拟开始时点我们需要求解以下问题:

\[\begin{split}\dot{\vec{x}}(t_0) &= \vec{f}(\vec{x}(t_0), \vec{u}(t_0), t_0) \\ \vec{y}(t_0) &= \vec{g}(\vec{x}(t_0), \vec{u}(t_0), t_0) \\ \vec{0} &= \vec{h}(\vec{x}(t_0), \dot{\vec{x}}(t_0), \vec{u}(t_0), t_0)\end{split}\]

注意到引进了新方程\(\vec{h}\)。这个新方程代表了initial equation中的任何方程。\(\vec{h}\)\(\vec{x}\)\(\dot{\vec{x}}\)作为参数,这允许表达很多可能的初始值。为了给状态定义一个明确的值,定义\(\vec{h}\)如下:

\[\vec{h}(\vec{x}(t_0), \dot{\vec{x}}(t_0), \vec{u}(t_0), t_0) = \vec{x}(t_0)-\vec{x}_0\]

如果希望从稳态解开始仿真,则应该定义\(\vec{h}\)如下:

\[\vec{h}(\vec{x}(t_0), \dot{\vec{x}}(t_0), \vec{u}(t_0), t_0) = \dot{\vec{x}}(t_0)\]

当然,对不同的状态,我们也可以对其各自使用上述不同的形式,乃至很多其他的形式,去描述初始条件。因此在写初始方程的时候,需要明白的是方程需要为上面所示的一般通用形式。而且你不能使用的方程数不能超过系统中的状态。

结论

正如在本章中所演示的一样,Modelica中initial equation结构允许应用多种方式去表达系统初始化。最终,所有形式都是可以计算系统的初始值。但是在描述这些值的计算时,我们有很大的自由度。

这是Modelica所擅长的领域。Modelica内初始化拥有第一等的地位。而这种灵活性也会为许多真实应用场景提供好处。