热力控制¶
在这一章中,我们将考虑另一个系统。这个系统包括了受控对象、控制器、传感器和执行器。这个应用场景是分为三区的房子的热控制。受控对象将是房子本身。传感器为温度传感器。执行器则为房内的火炉。利用这些模型,我们将探索不同的控制策略。
我们也将如同上节一般,遵循架构驱动的方法来构建该系统。然而,在开始时我们会使用一组接口。然后,在讨论其局限性后,我们重新使用不同的方法,以获得更大的灵活性。
初步方法¶
架构¶
让我们从下列架构开始:
Here we see the same basic pieces we saw in the previous section, a plant model, a sensor, a controller and an actuator. In fact, this is a pretty typical architecture. In some cases, people may break down the plant model into a few subsystems and/or include multiple controllers and control loops. But many closed loop system control problems have a similar structure.
各种应用里的不同点一般在于,上述部件之间交换的特定信号有不同。在本例里,我们可以从上述结构原理图上看出,接口定义如下:
执行器接收到目标温度,然后通过与受控对象的热连接注入热
传感器模型也带有热连接器(和受控对象相连)。而且它还包含了测量温度的输出信号。
受控对象有两个热连接。一个热连接代表炉子热量和受控对象的连接。另一个是传感器的位置。
控制器以(从传感器)测得的温度作为输入,并输出一个指定热输出(到执行器)
此基本系统的Modelica代码如下:
within ModelicaByExample.Architectures.ThermalControl.Architectures;
partial model BaseArchitecture "A basic thermal architecture"
replaceable Interfaces.PlantModel plant
annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
replaceable Interfaces.ControlSystem controller
annotation (Placement(transformation(extent={{-10,30},{10,50}})));
replaceable Interfaces.Sensor sensor
annotation (Placement(transformation(extent={{32,-10},{52,10}})));
replaceable Interfaces.Actuator actuator
annotation (Placement(transformation(extent={{-50,-10},{-30,10}})));
equation
connect(plant.room, sensor.room) annotation (Line(
points={{10,0},{32,0}},
color={191,0,0}, smooth=Smooth.None));
connect(sensor.temperature, controller.temperature) annotation (Line(
points={{53,0},{70,0},{70,40},{12,40}},
color={0,0,127}, smooth=Smooth.None));
connect(actuator.furnace, plant.furnace) annotation (Line(
points={{-30,0},{-10,0}},
color={191,0,0}, smooth=Smooth.None));
connect(controller.heat, actuator.heat) annotation (Line(
points={{-11,40},{-70,40},{-70,0},{-52,0}},
color={0,0,127}, smooth=Smooth.None));
end BaseArchitecture;
初始实现¶
受控对象¶
受控对象的模型如下:
我们在这里可以看到,其中暖炉加热的区域与测温的第三区是分隔开的。暖炉模型是一个简单的热源:
执行器以指令热量水平作为输入,然后注入相应的热量到系统里。
类似地,传感器也很简单:
这种传感器不引入任何误差。相反,这个传感器提供精确温度这一连续信号。
我们将使用以下PI控制器来控制温度:
初步结果¶
将上述实现填充入架构,模型看起来如下:
请注意各个子系统的图标已经改变了。这是因为当我们进行了redeclare
后,子系统便会使用相关联的新类型的图标。这个系统的Modelica语言代码是:
within ModelicaByExample.Architectures.ThermalControl.Examples;
model BaseModel "Base model using a conventional architecture"
extends Architectures.BaseArchitecture(
redeclare Implementations.ThreeZonePlantModel plant(
C=2, G=1, h=2, T_ambient=278.15),
redeclare
ModelicaByExample.Architectures.ThermalControl.Implementations.ConventionalPIControl
controller(setpoint=300, T=1, k=20),
redeclare Implementations.ConventionalActuator actuator,
redeclare Implementations.ConventionalSensor sensor);
end BaseModel;
如果我们对系统进行仿真,会得到以下的结果:

我们可以看到,这种方法效果非常好。实现这种程度控制所需的暖炉热量如下:

开关控制¶
到目前为止,这种做法好像已经相当成功。我们有一个很好的架构,我们可以用其来考虑不同的执行器、传感器、控制器甚至受控对象模型。我们开发的控制系统在这种情况性能似乎不错。
但有一点值得注意的是,在这种情况下暖炉热量必须为连续。不过,家庭取暖系统通常不采用这种类型的控制策略。相反,这类系统倾向于使用所谓的开关控制。在这种控制策略里,暖炉是非“开”即“关”。
我们有这个灵活的架构。为了解决这个问题,我们也许应该创建控制器和执行器模型的实现。其中控制器命令是一个布尔值,去指示是否暖炉的开启或关闭。但是,如果我们开始这么做的话,很快就会遇到以下问题:
需要注意的是,从我们的控制器输出Boolean
值,但我们的ControlSystem
接口里的命令信号heat
却为Real
值。我们在执行器处也有同样的问题:
该接口提供Real
值的执行机构。但我们再一次看到,如果暖炉要求“开启”或“关闭”命令时,我们就有不匹配。
所以,问题就变成:如何处理不同子系统要求不同接口这种情况?
可扩展方法¶
expandable
连接器定义解决了这个问题。通过这种方法,不论控制策略输出Boolean
或Real
,我们的子系统接口都不会改变。在这种情况下,改变的是连接器实例中的内容。
要了解这些expandable
连接器是如何工作的,我们将重新设计架构模型。新架构包括expandable
连接器,然后我们会考虑架构模型如何可用于连续以及“开关”的控制策略。
可扩展连接器¶
让我们可以构造更灵活架构模型的关键功能是expandable connector
。举个例子,先前我们定义了如下的Actuator
接口:
within ModelicaByExample.Architectures.ThermalControl.Interfaces;
partial model Actuator "Actuator subsystem interface"
Modelica.Blocks.Interfaces.RealInput heat "Heating command" annotation (
Placement(transformation(
extent={{-20,-20},{20,20}},
origin={-120,0})));
Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_b furnace
"Connection point for the furnace"
annotation (Placement(transformation(extent={{90,-10},{110,10}})));
end Actuator;
此接口包含两个连接器,heat
连接器和furnace
连接器。furnace
连接器为热连接器,它使暖炉与受控对象产生热相互作用。heat
连接器为来自控制器的Real
值输入信号。该信号指定所需的热量输出大小。事实上,在我们切换到需要Boolean
信号的控制方法时,接口模型的上述信号为Real
值这点正是问题所在。为了解决这个问题,我们将使用下面的接口定义执行器:
within ModelicaByExample.Architectures.ThermalControl.Interfaces;
partial model Actuator_WithExpandableBus
"Actuator subsystem interface with an expandable bus"
ExpandableBus bus
annotation (Placement(transformation(extent={{-110,-10},{-90,10}})));
Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_b furnace
"Connection point for the furnace"
annotation (Placement(transformation(extent={{90,-10},{110,10}})));
end Actuator_WithExpandableBus;
这里我们看到furnace
连接器仍然存在。但是heat
连接器已经不见了。相反,它已被替换为新的连接器实例:类型为ExpandableBus
的bus
。ExpandableBus
连接器的定义是:
within ModelicaByExample.Architectures.ThermalControl.Interfaces;
expandable connector ExpandableBus "An example of an expandable bus connector"
end ExpandableBus;
换句话说,连接器是空的。但重要的是expandable
限定词的存在。如果总线总是需要某些特定信号,这些信号就应该列在其连接器的定义之内。而事实上,ExpandableBus
类没有任何变量或子连接器。这意味着总线内的信息量没有最低要求。不过总线可以通过扩展来包含更多的信息。
当然,我们可以使用继承来添加新信号。但是,继承会引入了一个新类型。而接口定义中使用的类型规定了连接器的类型。所以,通过继承并不能真正有效创造更复杂的接口。
注意,Modelica内并有一个没有正式的“总线”定义。这个术语经常用于上述情况去表示携带多条信息的连接器。
可扩展连接器的功能比较特殊。可扩展总线的信号由其上的连接决定。通过向可扩展总线添加连接,信号便会隐含地添加在连接器上。这时的Modelica编译会观察与上述连接器相连的所有连接器,并将这些连接器全部扩展。这样一来,所有的连接器才可以互相匹配。稍后,我们将进一步介绍上述过程。但在这之前,我们需要首先有讨论的实际模型。
受控对象模型的接口没有受使用expandable
连接器的影响。但传感器和控制器的接口如下:
within ModelicaByExample.Architectures.ThermalControl.Interfaces;
partial model Sensor_WithExpandableBus
"Sensor subsystem interface using an expandable bus"
Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a room
"Thermal connection to room"
annotation (Placement(transformation(extent={{-110,-10},{-90,10}})));
ModelicaByExample.Architectures.ThermalControl.Interfaces.ExpandableBus bus
annotation (Placement(transformation(extent={{90,-10},{110,10}})));
end Sensor_WithExpandableBus;
within ModelicaByExample.Architectures.ThermalControl.Interfaces;
partial model ControlSystem_WithExpandableBus
"Control system interface using an expandable bus connector"
ExpandableBus bus annotation (Placement(transformation(extent={{-10,-110},{10,
-90}}), iconTransformation(extent={{-10,-110},{10,-90}})));
end ControlSystem_WithExpandableBus;
请注意控制器接口变得多么简单。这是因为通过使用expandable
连接器,我们可以把从传感器接收到的温度测量以及发送到执行器的热量命令放在在同一总线上。因此,我们只需要一个接口。开发人员仍可以直接使用多个总线去组织信号,使信号更好地反映物理存在或避免混乱。在此,我们使用单一连接器的目的纯粹是为了告诉读者这样做是可能的。
使用可扩展的连接器,我们可以创建以下改进版的架构:
可扩展实现¶
有了这个更灵活的架构,让我们先重建原有的连续控制系统配置:
若我们绘制这个系统的仿真结果,会得到如下的响应:

请注意,所测温度对应于信号controller.bus.temp
。其中bus
是可扩展的连接器的一个实例。进一步回忆的ExpandableBus
定义不含有一个叫temperature
的信号。所以现在的问题是,该信号是怎么去到连接器上的?问题就出在传感器模型的实现。传感器模型的框图如下:
对应的Modelica代码是:
within ModelicaByExample.Architectures.ThermalControl.Implementations;
model TemperatureSensor "Temperature sensor using an expandable bus"
extends Interfaces.Sensor_WithExpandableBus;
protected
Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor sensor
annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
equation
connect(sensor.T, bus.temperature) annotation (Line(
points={{10,0},{100,0}},
color={0,0,127},
smooth=Smooth.None));
connect(room, sensor.port) annotation (Line(
points={{-100,0},{-10,0}},
color={191,0,0},
smooth=Smooth.None));
end TemperatureSensor;
重要的是高亮显示的那行。
在该图中,我们可以看到,温度传感器组件的输出信号连接在总线上。但是,我们观察connect
声明可以看出,信号不仅仅是连接到总线上。此信号连接在总线上一个名为temperature
的量上。temperature
连接器并不存在于ExpandableBus
的定义里。相反,它是由connect
语句本身创建的!这也恰恰是expandable
限定词所允许的。
一般情况下,我们不希望所有连接器均为expandable
。若我们先验地知道所有信号的的名称和类型,那么就应该明确的列出。这样做会允许Modelica语言的编译器进行一些重要的检查,以确保模型的正确性。值得注意的是,添加所述expandable
限定词到连接器会使不小心创建无用信号成为可能(例如由于打错字)。这种错误在没有添加限定词的时候,本来可以由编译器找出。
重配置¶
现在,我们已经演示了如何使用可扩展的方法对系统的连续控制版本进行建模。现在,让我们重新关注到“开关”版本。
我们已经看到如何配置可扩展连接器版的温度传感器子系统。剩下的就是控制器和执行器的模型。执行器模型框图如下所示:
同样,看Modelica的代码时要注意对bus
连接器信号的引用:
within ModelicaByExample.Architectures.ThermalControl.Implementations;
model OnOffActuator "On-off actuator implemented with an expandable bus"
extends Interfaces.Actuator_WithExpandableBus;
parameter Real heating_capacity "Heating capacity of actuator";
protected
Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow heater
annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
Modelica.Blocks.Math.BooleanToReal command(realTrue=heating_capacity,
realFalse=0)
annotation (Placement(transformation(extent={{-60,-10},{-40,10}})));
equation
connect(heater.port, furnace) annotation (Line(
points={{10,0},{100,0}}, color={191,0,0},
smooth=Smooth.None));
connect(command.y, heater.Q_flow) annotation (Line(
points={{-39,0},{-10,0}}, color={0,0,127},
smooth=Smooth.None));
connect(command.u, bus.heat_command) annotation (Line(
points={{-62,0},{-100,0}}, color={255,0,255},
smooth=Smooth.None));
end OnOffActuator;
再次,注意强调的那行。该行引用bus
连接器的名为heat_command
的元素。和上面一样,该信号不存在于ExpandableBus
的定义内。该信号是隐式创建的。因为它在上述高亮显示connect
语句中被引用了。
由传感器模型我们可以看到,测得的温度输出到bus
连接器的一个名为temperature
的Real
信号里。由执行器模型我们则看到,执行器需要的控制器命令来自一个名为heat_command
的Boolean
信号。因此,我们应该会看到控制器模型使用这两个信号。控制器的框图如下:
但图内不包含足够的细节去让我们得知所引用bus
连接器信号的准确名称。为此,我们需要看实际的源代码:
within ModelicaByExample.Architectures.ThermalControl.Implementations;
model ExpandablePIControl "PI controller implemented with an expandable bus"
extends Interfaces.ControlSystem_WithExpandableBus;
parameter Real setpoint "Desired temperature";
parameter Real k=1 "Gain";
parameter Modelica.SIunits.Time T "Time Constant (T>0 required)";
protected
Modelica.Blocks.Sources.Trapezoid setpoint_signal(
amplitude=5, final offset=setpoint, rising=1,
width=10, falling=1, period=20)
annotation (Placement(transformation(extent={{-20,-40},{0,-20}})));
Modelica.Blocks.Math.Feedback feedback
annotation (Placement(transformation(extent={{30,-10},{10,10}})));
Modelica.Blocks.Continuous.PI PI(final T=T, final k=-k)
annotation (Placement(transformation(extent={{-10,-10},{-30,10}})));
equation
connect(setpoint_signal.y, feedback.u2)
annotation (Line(
points={{1,-30},{20,-30},{20,-8}},
color={0,0,127}, smooth=Smooth.None));
connect(PI.u,feedback. y) annotation (Line(
points={{-8,0},{11,0}},
color={0,0,127}, smooth=Smooth.None));
connect(bus.temperature, feedback.u1) annotation (Line(
points={{0,-100},{60,-100},{60,0},{28,0}},
color={0,0,0}, smooth=Smooth.None));
connect(PI.y, bus.heat) annotation (Line(
points={{-31,0},{-60,0},{-60,-100},{0,-100}},
color={0,0,127}, smooth=Smooth.None));
end ExpandablePIControl;
再次,注意高亮行。这些connect
语句不仅隐式将temperature
和heat_command
信号加入bus
连接器,而且这两个名称传感器和执行器模型所需的信号相匹配。
将所有子系统组合起来,我们得到系统的框图如下:
系统模型的源代码甚为简单:
within ModelicaByExample.Architectures.ThermalControl.Examples;
model OnOffVariant "Variation with on-off control"
extends ExpandableModel(
redeclare replaceable
Implementations.OnOffActuator actuator(heating_capacity=500),
redeclare replaceable
Implementations.OnOffControl controller(setpoint=300));
end OnOffVariant;

然而,这些模型仍有一个问题。若我们观察暖炉的负载循环,就可以更清楚地看出这个问题:

这正是我们在前面小节滞回中展示的相同问题。正因为控制策略缺乏任何迟滞,我们才所看到的暖炉不断打开和关闭。如果再加上迟滞,控制器模型就变为:
其余部分均保持不变。我们将使用相同的传感器和执行器模型。我们仍然使用相同的总线信号,因为这仍然是一个开关控制器。所以,系统级模型的唯一变化(相对于OnOffVariant
模型)就是所使用的不同控制器模型。我们可以看到,Modelica的这些配置管理功能可以很好地在系统模型内表述这点:
within ModelicaByExample.Architectures.ThermalControl.Examples;
model HysteresisVariant "Using on-off controller with hysteresis"
extends OnOffVariant(redeclare Implementations.OnOffControl_WithHysteresis
controller(setpoint=300, bandwidth=1));
end HysteresisVariant;
使用迟滞控制,我们的模拟结果如下:

但最重要的区别是,滞后不会导致之前在开关控制器中看到的抖振:

结论¶
这是我们能够使用Modelica配置管理功能,采取基于架构的方法来建立系统模型的第二个例子。当存在基于相同架构有很多变体需要分析时,架构方法非常有用。使用redeclare
特性,能够容易地替换子系统的不同设计,或者对应不同的工程分析使用具有所需细节度的子系统。
在本例中,我们看到了对比标准连接器而言expandable
连接器如何提供了更大的灵活性。不过,这也带有一定的风险。Modelica语言编译器通常会进行类型检查。但在使用了可扩展连接器后,类型检测就不那么严格了。