框图组件

到目前为止,本章的重点一直放在非因果建模里。但Modelica同时还支持因果形式的建模。我们强调非因果建模的主要原因在于,非因果方法非常适用于物理系统的建模。这使得组装物理系统可以使用示意图进行组合,开发者无须进行数学推导。组合后的系统会自动生成守恒方程,以确保模型运行正确。

框图则是另一种建模方法。框图需要重点创建代表大量数学运算的组件模型。然后,上述数学运算作用在(通常随时间变化)的信号,然后返回而其他信号。事实上,我们将在本节介绍一种特殊的model。这种模型名为blockblock仅有inputoutput的信号。

本节中,我们会先看看如何构建代表基本数学运算的因果模块。然后,我们会看到如何用两种不同的方式使用这些模块。第一种使用方式是对一个简单的物理系统进行建模。我们将讨论并对比因果方法以及非因果方法。第二种使用方式是将模块用于建模控制系统。如我们所见,使用模块来构建控制系统更符合框图模型的形式。

好在Modelica同时允许因果和非因果的方法。而我们会马上看到,两种建模方法也可以混合在一起。这样一来,Modelica可以让模型开发者选择在特定情况下效果最好的方法。

模块

Modelica标准库

本节中,我们会充分利用Modelica标准库里的定义。首先是连接器的几个定义:

connector RealInput = input Real "'input Real' as connector";
connector RealOutput = output Real "'output Real' as connector";

如其名称所示,RealInputRealOutput分别代表实值的输入和输出信号连接器。在简图视图里,RealInput连接器显示为蓝色的实心三角:

RealOutput连接器是一个蓝色的三角形边框:

我们将充分利用Modelica标准库内的几个不同partial模块定义。第一个使用的partial定义是SO,或者说“单输出”(single output)的定义:

partial block SO "Single Output continuous control block"
  extends Modelica.Blocks.Icons.Block;

  RealOutput y "Connector of Real output signal" annotation (Placement(
        transformation(extent={{100,-10},{120,10}}, rotation=0)));
end SO;

显然,这个定义用于拥有单个输出的模块。按照惯例,该输出信号命名为y。我们使用的另一个定义是SISO,或者说“单输入、单输出”(single input, single output)的模块:

partial block SISO "Single Input Single Output continuous control block"
  extends Modelica.Blocks.Icons.Block;

  RealInput u "Connector of Real input signal" annotation (Placement(
        transformation(extent={{-140,-20},{-100,20}}, rotation=0)));
  RealOutput y "Connector of Real output signal" annotation (Placement(
        transformation(extent={{100,-10},{120,10}}, rotation=0)));
end SISO;

此模型除了输出信号y,还多了一个输入信号u。最后,对于具有多个输入的模块,MISO模块可以将输入信号u定义为向量:

partial block MISO "Multiple Input Single Output continuous control block"
  extends Modelica.Blocks.Icons.Block;
  parameter Integer nin=1 "Number of inputs";
  RealInput u[nin] "Connector of Real input signals" annotation (Placement(
        transformation(extent={{-140,-20},{-100,20}}, rotation=0)));
  RealOutput y "Connector of Real output signal" annotation (Placement(
        transformation(extent={{100,-10},{120,10}}, rotation=0)));
end MISO;

nin参数用于指定模块输入的数目。

值得指出的是,我们即将定义的所有模块都可以在Modelica标准库中找到。但我们会在这里创建自己的版本。这样做的目的是去展示可以如何定义这样的模型。

Constant

我们能想象的最简单的模块应该是简单的恒定值输出了。因为这种模型只有一个输出,模型扩展自SO模块

within ModelicaByExample.Components.BlockDiagrams.Components;
block Constant "A constant source"
  parameter Real k "Constant output value";
  extends Icons.Axes;
  extends Interfaces.SO;
equation
  y = k;
end Constant;

模块显示如下:

Gain Block

Gain

另一个简单的block是“增益模块”。其输出信号为输入信号乘以一个常数的结果。这样的模块将有一个输入信号和一个输出信号。因此,它可从SISO模型扩展如下:

within ModelicaByExample.Components.BlockDiagrams.Components;
block Gain "A gain block model"
  extends Interfaces.SISO;
  parameter Real k "Gain coefficient";
equation
  y = k*u;
end Gain;

模块显示如下:

Gain Block

Sum

Sum模块可以使用任意数量的输入信号。此次,它扩展自MISO模块:

within ModelicaByExample.Components.BlockDiagrams.Components;
block Sum "Block that sums its inputs"
  extends Interfaces.MISO;
equation
  y = sum(u);
end Sum;

Sum模块使用sum函数来计算输入信号数组u的总和,以此得到输出信号y

模块显示如下:

Gain Block

Product

Product模块与Sum模块几乎相同。不同点在于它采用了product函数:

within ModelicaByExample.Components.BlockDiagrams.Components;
block Product "Block that outputs the product of its inputs"
  extends Interfaces.MISO;
equation
  y = product(u);
end Product;

模块显示如下:

Gain Block

Feedback

与先前模块不同,Feedback模块并没有扩展自Modelica标准库中的任何定义。相反,该模块明确声明了它使用的所有连接器:

within ModelicaByExample.Components.BlockDiagrams.Components;
block Feedback "A block to compute feedback terms"
  Interfaces.RealInput u1
    annotation (Placement(transformation(extent={{-120,-10},{-100,10}})));
  Interfaces.RealInput u2 annotation (Placement(transformation(
        extent={{-10,-10},{10,10}},
        rotation=90,
        origin={0,-110})));
  Interfaces.RealOutput y
    annotation (Placement(transformation(extent={{90,-10},{110,10}})));
equation
  y = u1-u2;
end Feedback;

Feedback模块的输出是两个input信号u1u2之间的差。

模块显示如下:

Gain Block

Integrator

Integrator模块是又一个SISO模块。模块对输入信号u进行积分,以此计算输出信号y。由于此block执行积分,它需要一个初始条件。参数y0用以指定初始条件:

within ModelicaByExample.Components.BlockDiagrams.Components;
block Integrator
  "This block integrates the input signal to compute the output signal"
  parameter Real y0 "Initial condition";
  extends Interfaces.SISO;
initial equation
  y = y0;
equation
  der(y) = u;
end Integrator;

模块显示如下:

Gain Block

系统

我们已经创建了一系列模块。现在我们将在一些例子里探讨,如何用上述模块来对系统进行建模。我们将看到,因果性的block组件的适用性因应用而异。

冷却示例

我们用block定义建模的首个系统是本章前面部分提到的传热示例。不过,这次我们不会使用非因果组件来构建模型。相反,我们将使用与block定义相关的数学运算方面来进行建模。

由于这些模块均代表了数学运算,那让我们先重温这个例子相关的方程:

\[m c_p \dot{T} = h A (T_{\infty}-T)\]

以下框图可以解出温度曲线\(T\)

Gain Block

这个例子的Modelica的源代码为:

within ModelicaByExample.Components.BlockDiagrams.Examples;
model NewtonCooling "Newton cooling system modeled with blocks"
  import Modelica.SIunits.Conversions.from_degC;
  parameter Real h = 0.7 "Convection coefficient";
  parameter Real A = 1.0 "Area";
  parameter Real m = 0.1 "Thermal mass";
  parameter Real c_p = 1.2 "Specific heat";
  parameter Real T_inf = from_degC(25) "Ambient temperature";
  Components.Integrator T(y0=from_degC(90))
    annotation (Placement(transformation(extent={{-30,-10},{-10,10}})));
  Components.Gain gain(k=-1)
    annotation (Placement(transformation(extent={{10,-10},{30,10}})));
  Components.Constant ambient(k=T_inf)
    annotation (Placement(transformation(extent={{10,-40},{30,-20}})));
  Components.Sum sum(nin=2)
    annotation (Placement(transformation(extent={{52,-20},{72,0}})));
  Components.Gain gain1(k=h*A/(m*c_p))
    annotation (Placement(transformation(extent={{-70,-10},{-50,10}})));
equation
  connect(T.y, gain.u) annotation (Line(
      points={{-9,0},{9,0}}, color={0,0,255},
      smooth=Smooth.None));
  connect(sum.y, gain1.u) annotation (Line(
      points={{73,-10},{80,-10},{80,60},{-80,60},{-80,0},{-71,0}},
      color={0,0,255}, smooth=Smooth.None));
  connect(gain.y, sum.u[2]) annotation (Line(
      points={{31,0},{40,0},{40,-9.5},{51,-9.5}},
      color={0,0,255}, smooth=Smooth.None));
  connect(ambient.y, sum.u[1]) annotation (Line(
      points={{31,-30},{40,-30},{40,-10.5},{51,-10.5}},
      color={0,0,255}, smooth=Smooth.None));
  connect(gain1.y, T.u) annotation (Line(
      points={{-49,0},{-31,0}},
      color={0,0,255}, smooth=Smooth.None));
end NewtonCooling;

温度\(T\)是在该模型中由变量T.y表示。对上述系统进行仿真,我们会得到温度的以下解:

../../../_images/BNC.png

我们可以看到,该解与该例此前所有形式内所得的解完全一样。

到目前为止,我们用三种方式表述了上述问题。第一种描述是使用了单个公式的数学结构。第二种方式是使用非因果的单个物理效应元件模型来表示相同的动力学。最后,我们有了上述最新的框图表述。但真正的问题是,哪种方法最适合于这个特定问题?

实际上,需要考虑两种极端的情况。如果,我们仅仅想解决问题的这一个特定的配置。也就是说,我们仅仅考虑单热容与一些环境无限热容进行对流。这样的话,基于等式的版本很可能是最好的选择。因为整个问题的行为,可以通过单一的公式来表示:

m*c_p*der(T) = h*A*(T_inf-T) "Newton's law of cooling";

这样的公式可以非常迅速地键入。相比之下,基于组件的版本会要求用户拖拽、放入然后连接组件模型。这样总是会需要更长时间。

但是,如果你要创建问题的变种,例如结合不同模式的热传递、不同的边界条件等,那么非因果版本就更好了。这是因为虽然创建组件模型需要一些投入,但要重新配置部件模型就几乎毫不费力了。

有些人可能说框图版本的模型也是一样的(即可以毫不费力对其重新配置),但事实并非如此。框图版模型是问题的一个数学表述,而不是基于原理的表述。如果你要设定不同的边界条件、添加热容、加入不同模式的热传递等,那么更改原理图甚为简单。然而,对于框图表述,你将需要彻底重新制定框图。这是因为,所得的状态空间形式数学方程可能非常不同。非因果、以原理为基础的方法其中一大优势在于,Modelica编译器会自动将教科书里的方程翻译为状态空间形式。这节省了模型开发要做的大量繁琐、耗时且容易出错的工作。这也正是何以非因果方法是首选方法。

热控制

在接下来的例子中,我们将两者在本节中开发的因果组件与本章前面开发的传热组件这些非因果成分组合在一起。我们会看到这是一个强大的组合。因为这使我们能够用原理表示物理组件。但这同时可以让我们用数学表述控制策略。

以下是显示这两种方法可以如何组合的示意图:

Gain Block

在与控制系统一起建模的物理系统中,物理组件和效果将使用非因果表述。代表控制策略的组件则通常会使用因果表述。将两种方法连接在一起的是传感器和执行器。该传感器测量系统的某些方面(本例为温度)与执行器对系统施加一定的“影响”(这里为热通量)。

执行器的模型通常具有信号输入以及到物理系统的非因果连接(“影响”,如力或电流,将通过其应用在物理系统上)。传感器模型与之正正相反。这时,因果连接器为输出,而非因果连接器将被用于“感应”物理系统的某些方面(如电压、温度等)。

我们的示例模型可以用Modelica的表述为:

within ModelicaByExample.Components.BlockDiagrams.Examples;
model MultiDomainControl
  "Mixing thermal components with blocks for sensing, actuation and control"

  import Modelica.SIunits.Conversions.from_degC;

  parameter Real h = 0.7 "Convection coefficient";
  parameter Real A = 1.0 "Area";
  parameter Real m = 0.1 "Thermal maass";
  parameter Real c_p = 1.2 "Specific heat";
  parameter Real T_inf = from_degC(25) "Ambient temperature";
  parameter Real T_bar = from_degC(30.0) "Desired temperature";
  parameter Real k = 2.0 "Controller gain";

  Components.Constant setpoint(k=T_bar)
    annotation (Placement(transformation(extent={{-40,30},{-20,50}})));
  Components.Feedback feedback
    annotation (Placement(transformation(extent={{-10,30},{10,50}})));
  Components.Gain controller_gain(k=k) "Gain for the proportional control"
    annotation (Placement(transformation(extent={{20,30},{40,50}})));
  HeatTransfer.ThermalCapacitance cap(C=m*c_p, T0 = from_degC(90))
    "Thermal capacitance component"
    annotation (Placement(transformation(extent={{-30,-30},{-10,-10}})));
  HeatTransfer.Convection convection2(h=h*A)
    annotation (Placement(transformation(extent={{10,-30},{30,-10}})));
  HeatTransfer.AmbientCondition
                   amb(T_amb(displayUnit="K") = T_inf)
    annotation (Placement(transformation(extent={{50,-30},{70,-10}})));
  Components.IdealTemperatureSensor sensor annotation (Placement(transformation(
        extent={{-10,-10},{10,10}},
        rotation=90,
        origin={0,10})));
  Components.HeatSource heatSource
    annotation (Placement(transformation(extent={{-60,-30},{-40,-10}})));
equation
  connect(setpoint.y, feedback.u1) annotation (Line(
      points={{-19,40},{-11,40}}, color={0,0,255},
      smooth=Smooth.None));
  connect(feedback.y, controller_gain.u) annotation (Line(
      points={{10,40},{19,40}}, color={0,0,255},
      smooth=Smooth.None));
  connect(convection2.port_a, cap.node) annotation (Line(
      points={{10,-20},{-20,-20}}, color={191,0,0},
      smooth=Smooth.None));
  connect(amb.node, convection2.port_b) annotation (Line(
      points={{60,-20},{30,-20}}, color={191,0,0},
      smooth=Smooth.None));
  connect(sensor.y, feedback.u2) annotation (Line(
      points={{0,21},{0,24.5},{0,24.5},{0,29}},
      color={0,0,255},
      smooth=Smooth.None));
  connect(heatSource.node, cap.node) annotation (Line(
      points={{-40,-20},{-20,-20}}, color={191,0,0},
      smooth=Smooth.None));
  connect(controller_gain.y, heatSource.u) annotation (Line(
      points={{41,40},{50,40},{50,60},{-70,60},{-70,-20},{-61,-20}},
      color={0,0,255},
      smooth=Smooth.None));
  connect(sensor.node, cap.node) annotation (Line(
      points={{0,0},{0,0},{0,-20},{-20,-20}},
      color={191,0,0},
      smooth=Smooth.None));
end MultiDomainControl;

观察模型,我们可以看到,初始温度为\(90\,^{\circ}\mathrm{C}\)。而环境温度则为\(25\,^{\circ}\mathrm{C}\)。此外,该设定点温度(所需温度)为\(30\,^{\circ}\mathrm{C}\)。我们先前的例子里,系统温度最终变为环境温度。与之不同,此系统由于控制系统的影响,其温度应接近设定点温度。对上述系统进行仿真,我们可以得到以下温度响应:

../../../_images/MDC.png

我们可以增加控制器的“增益”k。这时,我们看到了不同的响应:

../../../_images/MDC_hg.png

不过,我们可以从以下图中看到,我们的执行机构需要更大的热量输出。这是为了在第二种情况能得到更快的响应:

../../../_images/MDC_heat.png

这仅仅是一个很简单的例子。但这演示了包含控制以及物理响应的系统可以如何让模型开发者允许探索两者对系统整体性能的影响。

结论

本节中,我们已经看到了如何定义因果性的block组件。而且,我们将其用在模拟物理系统以及与控制相关的行为。我们甚至看到了这些因果部件可以与非因果部件相结合,以产生一个“两全其美”的组合。这样一来,控制功能使用了因果部件来实现。而物理部件则使用非因果的部件。