架构驱动方法

到目前为止,我们从扁平结构的建模方法为起点,逐渐在模型里使用Modelica的架构特性。我们会开始从上往下地用架构方法去建立系统。我们首先定义系统的结构,然后添加特定的子系统实现。

接口

我们希望首先建立顶层的架构模型,从而描述存在的子系统以及它们之间的连接。但是,我们需要把一些内容放入这个架构以表示我们的子系统。我们(暂时)不要直接为所有的子系统模型的建立实现。所以,我们从哪里开始?

答案是,我们会首先描述子系统的接口模型。还记得么?从本节前面里,重声明取决于约束类型,而且所有的实现必须和该约束类型具有一致性。其实接口模型基本上是约束类型的正式定义(即预期的公有接口)。不过接口模型并不包括实现细节。既然如此(即没有公式或子组件),因此接口模型是partial模型。但是,对于我们的目的这足够了。

让我们开始考虑sensor子系统的接口模型。我们已经详细讨论了公共接口。这是接口模型的Modelica定义以及图标:

within ModelicaByExample.Architectures.SensorComparison.Interfaces;
partial model Sensor "Interface for sensor"
  Modelica.Mechanics.Rotational.Interfaces.Flange_a shaft
    "Flange of shaft from which sensor information shall be measured"
    annotation (Placement(transformation(extent={{-110,-10},{-90,10}})));
  Modelica.Blocks.Interfaces.RealOutput w "Absolute angular velocity of flange"
    annotation (Placement(transformation(extent={{100,-10},{120,10}})));
  annotation (Icon(graphics={Rectangle(extent={{-100,100},{
              100,-100}}, lineColor={128,255,0})}));
end Sensor;
Sensor interface

这个model定义有几点需要注意。首先,正如我们刚才也提到,这种模型是partial 。这是因为这种模型仅具有连接器,但没有方程去帮助求解对这些连接器内的变量。另外值得注意的一点是,这些模型包含了批注。与连接器声明相关的标注说明这些连接器应该以如何形式表现。任何从这个extends的模型会继承这些标注。所以,连接器的位置必须在所有的实现里都有效。It also includes an Icon annotation.模型还包括一个Icon标注。这实际上定义了最终实现的图标的“背景”。换句话说,从此模型扩展的模型可以在Sensor模型图标的基础上中定义额外的图形。

而执行器模型的接口定义唯一不同之处在于,它包括了两个旋转连接器。其中一个用以施加指令转矩,另一个则用以处理反作用转矩。倘若例如我们的执行器模型为电动马达,前者就是在转子的连接器,而后者是定子的连接器。除此以外,此模型非常类似于我们Sensor定义:

within ModelicaByExample.Architectures.SensorComparison.Interfaces;
partial model Actuator "Interface for actuator"
  Modelica.Mechanics.Rotational.Interfaces.Flange_b shaft "Output shaft"
    annotation (Placement(transformation(extent={{90,-10},{110,10}})));
  Modelica.Mechanics.Rotational.Interfaces.Support housing
    "Connection to housing"
    annotation (Placement(transformation(extent={{90,-70},{110,-50}})));
  Modelica.Blocks.Interfaces.RealInput tau "Input torque command"
    annotation (Placement(transformation(extent={{-140,-20},{-100,20}})));
  annotation (Icon(graphics={Rectangle(extent={{-100,100},{
              100,-100}}, lineColor={255,85,85})}));
end Actuator;
Actuator interface

Plant接口有三个旋转连接器。一个在“输入”侧(与执行器相连接)。一个在“输出”侧(与传感器相连接)。而最后一个用于“支持”侧(用以“固定”在其他物体上):

within ModelicaByExample.Architectures.SensorComparison.Interfaces;
partial model Plant "Interface for plant model"
  Modelica.Mechanics.Rotational.Interfaces.Flange_b flange_b
    "Output shaft of plant"
    annotation (Placement(transformation(extent={{90,-10},{110,10}})));
  Modelica.Mechanics.Rotational.Interfaces.Flange_a flange_a
    "Input shaft for plant"
    annotation (Placement(transformation(extent={{-110,-10},{-90,10}})));
  Modelica.Mechanics.Rotational.Interfaces.Support housing
    "Connection to mounting"
    annotation (Placement(transformation(extent={{-110,-70},{-90,-50}})));
  annotation (Icon(graphics={Rectangle(extent={{-100,100},{
              100,-100}}, lineColor={128,0,255})}));
end Plant;
Plant interface

最后,我们有Controller接口定义:

within ModelicaByExample.Architectures.SensorComparison.Interfaces;
partial model Controller "Interface for controller subsystem"
  Modelica.Blocks.Interfaces.RealInput setpoint "Desired system response"
    annotation (Placement(transformation(
        extent={{-20,-20},{20,20}},
        rotation=270,
        origin={0,120})));
  Modelica.Blocks.Interfaces.RealInput measured "Actual system response"
    annotation (Placement(transformation(
        extent={{-20,-20},{20,20}},
        rotation=180,
        origin={100,0})));
  Modelica.Blocks.Interfaces.RealOutput command "Command to send to actuator"
    annotation (Placement(transformation(
        extent={{-10,-10},{10,10}},
        rotation=180,
        origin={-110,0})));
  annotation (Icon(graphics={Rectangle(extent={{-100,100},{
              100,-100}}, lineColor={0,128,255})}));
end Controller;
Controller interface

无论控制器是如何实现的(如比例控制, PID控制),Controller必须有目标值setpoint的输入连接器、另一个用于测速的输入连接器measured和用以发送指令转矩command到执行器的输出连接器。

架构

指定了接口后,我们的架构模型可以写成如下形式:

within ModelicaByExample.Architectures.SensorComparison.Examples;
partial model SystemArchitecture
  "A system architecture built from subsystem interfaces"

  replaceable Interfaces.Plant plant
    annotation (choicesAllMatching=true,
      Placement(transformation(extent={{-10,-50},{10,-30}})));
  replaceable Interfaces.Actuator actuator
    annotation (choicesAllMatching=true,
      Placement(transformation(extent={{-50,-50},{-30,-30}})));
  replaceable Interfaces.Sensor sensor
    annotation (choicesAllMatching=true,
      Placement(transformation(extent={{30,-50},{50,-30}})));
  replaceable Interfaces.Controller controller
    annotation (choicesAllMatching=true,
      Placement(transformation(extent={{-10,-10},{10,10}})));
  Modelica.Blocks.Sources.Trapezoid setpoint(period=1.0)
    annotation (choicesAllMatching=true,
      Placement(transformation(extent={{-60,30},{-40,50}})));
equation
  connect(actuator.shaft, plant.flange_a) annotation (Line(
      points={{-30,-40},{-10,-40}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(actuator.housing, plant.housing) annotation (Line(
      points={{-30,-46},{-10,-46}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(plant.flange_b, sensor.shaft) annotation (Line(
      points={{10,-40},{30,-40}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(controller.measured, sensor.w) annotation (Line(
      points={{10,0},{70,0},{70,-40},{51,-40}},
      color={0,0,127},
      smooth=Smooth.None));
  connect(controller.command, actuator.tau) annotation (Line(
      points={{-11,0},{-70,0},{-70,-40},{-52,-40}},
      color={0,0,127},
      smooth=Smooth.None));
  connect(setpoint.y, controller.setpoint) annotation (Line(
      points={{-39,40},{0,40},{0,12}},
      color={0,0,127},
      smooth=Smooth.None));
end SystemArchitecture;

我们可以从上述Modelica代码看出,架构由四个replaceable子系统组成: plantactuatorsensorsetpoint 。所有这些声明只包括一种类型。正如我们先前在本节了解到的,该类型将(如我们所望地)同时用作默认类型以及约束类型。此模型还包括子系统之间的所有连接。这样一来,模型完整描述了子系统以及其之间的联系。万事俱备,唯一缺少的就是去选择每个子系统的实现了

请注意,SystemArchitecture模型本身是partial 。这正是因为所有子系统的默认类型均为partial,而我们还没有指定模型的实现。换句话说,模型不包含实现,因此(还)不能进行模拟。为表明这一点,我们标记模型为partial

正如我们的接口模型,这个模型也包含图形标注。这是因为我们不但指定了子系统,还指定了子系统的位置和连接的路径。我们的系统架构显式的效果如下:

Top down architecture

实现

现在我们有了接口和架构,我们必须创建一些实现,用以“注入”到架构中。这些实现可以选择从现有的接口继承(从而避免冗余代码),或是仅确保在实现内的声明与接口插件兼容。显然在一般情况下从接口继承是一个更好的方法。但我们同时介绍这两种方法的例子,用以证明从接口继承并非必须。

这里有一些我们将在本节剩余部分使用的实现。请注意,尽管这些模型包括了多行的Modelica源代码,代码可以在图形化的Modelica环境内迅速生成(即通常不会手工键入这种模型代码)。

受控对象模型

within ModelicaByExample.Architectures.SensorComparison.Implementation;
model BasicPlant "Implementation of the basic plant model"
  parameter Modelica.SIunits.Inertia J_a=0.1 "Moment of inertia";
  parameter Modelica.SIunits.Inertia J_b=0.3 "Moment of inertia";
  parameter Modelica.SIunits.RotationalSpringConstant c=100 "Spring constant";
  parameter Modelica.SIunits.RotationalDampingConstant d_shaft=3
    "Shaft damping constant";
  parameter Modelica.SIunits.RotationalDampingConstant d_load=4
    "Load damping constant";

  Modelica.Mechanics.Rotational.Interfaces.Support housing
    "Connection to mounting"
    annotation (Placement(transformation(extent={{-110,-70},{-90,-50}})));
  Modelica.Mechanics.Rotational.Interfaces.Flange_a flange_a
    "Input shaft for plant"
    annotation (Placement(transformation(extent={{-110,-10},{-90,10}})));
  Modelica.Mechanics.Rotational.Interfaces.Flange_b flange_b
    "Output shaft of plant"
    annotation (Placement(transformation(extent={{90,-10},{110,10}})));
protected
  Modelica.Mechanics.Rotational.Components.Fixed fixed
    annotation (Placement(transformation(extent={{-10,-80},{10,-60}})));
  Modelica.Mechanics.Rotational.Components.Inertia inertia(J=J_a)
    annotation (Placement(transformation(extent={{-40,-10},{-20,10}})));
  Modelica.Mechanics.Rotational.Components.Inertia inertia1(J=J_b)
    annotation (Placement(transformation(extent={{20,-10},{40,10}})));
  Modelica.Mechanics.Rotational.Components.SpringDamper springDamper(c=c, d=
        d_shaft)
    annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
  Modelica.Mechanics.Rotational.Components.Damper damper(d=d_load)
    annotation (Placement(transformation(extent={{20,-40},{40,-20}})));
equation
  connect(springDamper.flange_a, inertia.flange_b) annotation (Line(
      points={{-10,0},{-20,0}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(springDamper.flange_b, inertia1.flange_a) annotation (Line(
      points={{10,0},{20,0}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(damper.flange_b, inertia1.flange_b) annotation (Line(
      points={{40,-30},{50,-30},{50,0},{40,0}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(damper.flange_a, fixed.flange) annotation (Line(
      points={{20,-30},{0,-30},{0,-70}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(inertia1.flange_b, flange_b) annotation (Line(
      points={{40,0},{100,0}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(inertia.flange_a, flange_a) annotation (Line(
      points={{-40,0},{-100,0}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(fixed.flange, housing) annotation (Line(
      points={{0,-70},{0,-60},{-100,-60}},
      color={0,0,0},
      smooth=Smooth.None));
  annotation (Icon(graphics={
        Rectangle(

执行器模型

within ModelicaByExample.Architectures.SensorComparison.Implementation;
model IdealActuator "An implementation of an ideal actuator"
  Modelica.Mechanics.Rotational.Interfaces.Flange_b shaft "Output shaft"
    annotation (Placement(transformation(extent={{90,-10},{110,10}})));
  Modelica.Mechanics.Rotational.Interfaces.Support housing
    "Connection to housing"
    annotation (Placement(transformation(extent={{90,-70},{110,-50}})));
protected
  Modelica.Mechanics.Rotational.Sources.Torque torque(useSupport=true)
    annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
  Modelica.Blocks.Interfaces.RealInput tau "Input torque command"
    annotation (Placement(transformation(extent={{-140,-20},{-100,20}})));
equation
  connect(torque.flange, shaft) annotation (Line(
      points={{10,0},{100,0}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(torque.support, housing) annotation (Line(
      points={{0,-10},{0,-60},{100,-60}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(torque.tau, tau) annotation (Line(
      points={{-12,0},{-120,0}},
      color={0,0,127},
      smooth=Smooth.None));
  annotation (Icon(graphics={
        Rectangle(
          extent={{-100,100},{100,-100}},
within ModelicaByExample.Architectures.SensorComparison.Implementation;
model LimitedActuator "An actuator with lag and saturation"
  extends Interfaces.Actuator;
  parameter Modelica.SIunits.Time delayTime
    "Delay time of output with respect to input signal";
  parameter Real uMax "Upper limits of input signals";
protected
  Modelica.Mechanics.Rotational.Sources.Torque torque(useSupport=true)
    annotation (Placement(transformation(extent={{30,-10},{50,10}})));
  Modelica.Blocks.Nonlinear.Limiter limiter(uMax=uMax)
    annotation (Placement(transformation(extent={{-18,-10},{2,10}})));
  Modelica.Blocks.Nonlinear.FixedDelay lag(delayTime=delayTime)
    annotation (Placement(transformation(extent={{-70,-10},{-50,10}})));
equation
  connect(torque.flange, shaft) annotation (Line(
      points={{50,0},{100,0}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(torque.support, housing) annotation (Line(
      points={{40,-10},{40,-60},{100,-60}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(limiter.y, torque.tau) annotation (Line(
      points={{3,0},{28,0}},
      color={0,0,127},
      smooth=Smooth.None));
  connect(lag.u, tau) annotation (Line(
      points={{-72,0},{-120,0}},
      color={0,0,127},
      smooth=Smooth.None));
  connect(lag.y, limiter.u) annotation (Line(
      points={{-49,0},{-20,0}},
      color={0,0,127},
      smooth=Smooth.None));
  annotation (Icon(graphics={
        Rectangle(
          extent={{-100,100},{100,-100}},
          lineColor={0,0,0},
          fillColor={255,85,85},

控制器模型

within ModelicaByExample.Architectures.SensorComparison.Implementation;
model ProportionalController "Implementation of a proportional controller"
  parameter Real k=20 "Controller gain";
  Modelica.Blocks.Interfaces.RealInput setpoint "Desired system response"
    annotation (Placement(transformation(
        extent={{-20,-20},{20,20}},
        rotation=270, origin={0,120})));
  Modelica.Blocks.Interfaces.RealInput measured "Actual system response"
    annotation (Placement(transformation(
        extent={{-20,-20},{20,20}},
        rotation=180, origin={100,0})));
  Modelica.Blocks.Interfaces.RealOutput command "Command to send to actuator"
    annotation (Placement(transformation(
        extent={{-10,-10},{10,10}},
        rotation=180, origin={-110,0})));
protected
  Modelica.Blocks.Math.Gain gain(k=k)
    annotation (Placement(transformation(
        extent={{-10,-10},{10,10}},
        rotation=180, origin={-50,0})));
  Modelica.Blocks.Math.Feedback feedback
    annotation (Placement(transformation(
        extent={{10,-10},{-10,10}})));
equation
  connect(feedback.y, gain.u) annotation (Line(
      points={{-9,0},{2,0},{2,0},{-38,0}},
      color={0,0,127}, smooth=Smooth.None));
  connect(feedback.u1, setpoint) annotation (Line(
      points={{8,0},{40,0},{40,60},{0,60},{0,120}},
      color={0,0,127},
      smooth=Smooth.None));
  connect(gain.y, command) annotation (Line(
      points={{-61,0},{-80.5,0},{-80.5,0},{-110,0}},
      color={0,0,127},
      smooth=Smooth.None));
  connect(measured, feedback.u2) annotation (Line(
      points={{100,0},{60,0},{60,-40},{0,-40},{0,-8}},
      color={0,0,127}, smooth=Smooth.None));
end ProportionalController;
within ModelicaByExample.Architectures.SensorComparison.Implementation;
model PID_Controller "Controller subsystem implemented using a PID controller"
  extends Interfaces.Controller;
  parameter Real k "Gain of controller";
  parameter Modelica.SIunits.Time Ti "Time constant of Integrator block";
  parameter Modelica.SIunits.Time Td "Time constant of Derivative block";
  parameter Real yMax "Upper limit of output";
protected
  Modelica.Blocks.Continuous.LimPID PID(k=k, Ti=Ti, Td=Td, yMax=yMax)
    annotation (Placement(transformation(
        extent={{10,-10},{-10,10}})));
equation
  connect(setpoint, PID.u_s) annotation (Line(
      points={{0,120},{0,60},{40,60},{40,0},{12,0}},
      color={0,0,127},
      smooth=Smooth.None));
  connect(measured, PID.u_m) annotation (Line(
      points={{100,0},{60,0},{60,-40},{0,-40},{0,-12}},
      color={0,0,127},
      smooth=Smooth.None));
  connect(PID.y, command) annotation (Line(
      points={{-11,0},{-110,0}},
      color={0,0,127},
      smooth=Smooth.None));
  annotation (Icon(graphics={
        Rectangle(
          extent={{-100,100},{100,-100}},

传感器模型

within ModelicaByExample.Architectures.SensorComparison.Implementation;
model IdealSensor "Implementation of an ideal sensor"
  Modelica.Mechanics.Rotational.Interfaces.Flange_a shaft
    "Flange of shaft from which sensor information shall be measured"
    annotation (Placement(transformation(extent={{-110,-10},{-90,10}})));
  Modelica.Blocks.Interfaces.RealOutput w "Absolute angular velocity of flange"
    annotation (Placement(transformation(extent={{100,-10},{120,10}})));
protected
  Modelica.Mechanics.Rotational.Sensors.SpeedSensor idealSpeedSensor
    "An ideal speed sensor" annotation (Placement(transformation(
        extent={{-10,-10},{10,10}})));
equation
  connect(idealSpeedSensor.flange, shaft) annotation (Line(
      points={{-10,0},{-100,0}},
      color={0,0,0},
      smooth=Smooth.None));
  connect(idealSpeedSensor.w, w) annotation (Line(
      points={{11,0},{110,0}},
      color={0,0,127},
      smooth=Smooth.None));
  annotation (Icon(graphics={
        Rectangle(
within ModelicaByExample.Architectures.SensorComparison.Implementation;
model SampleHoldSensor "Implementation of a sample hold sensor"
  parameter Modelica.SIunits.Time sample_rate(min=Modelica.Constants.eps);
  Modelica.Mechanics.Rotational.Interfaces.Flange_a shaft
    "Flange of shaft from which sensor information shall be measured"
    annotation (Placement(transformation(extent={{-110,-10},{-90,10}})));
  Modelica.Blocks.Interfaces.RealOutput w "Absolute angular velocity of flange"
    annotation (Placement(transformation(extent={{100,-10},{120,10}})));
protected
  Components.SpeedMeasurement.Components.SampleHold sampleHoldSensor(
      sample_rate=sample_rate)
    annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
equation
  connect(sampleHoldSensor.w, w) annotation (Line(
      points={{11,0},{110,0}},
      color={0,0,127},
      smooth=Smooth.None));
  connect(sampleHoldSensor.flange, shaft) annotation (Line(
      points={{-10,0},{-100,0}},
      color={0,0,0},
      smooth=Smooth.None));
  annotation ( Icon(graphics={
        Rectangle(

变体

基准配置

有了这些实现,我们可以创建完整的系统的一些不同实现。举个例子,为了实现我们最初的FlatSystem模型的行为,我们可以直接扩展SystemArchitecture模型,然后将每个子系统重新声明为与FlatSystem对应的子系统实现,即:

within ModelicaByExample.Architectures.SensorComparison.Examples;
model BaseSystem "System architecture with base implementations"
  extends SystemArchitecture(
    redeclare replaceable Implementation.ProportionalController controller,
    redeclare replaceable Implementation.IdealActuator actuator,
    redeclare replaceable Implementation.BasicPlant plant,
    redeclare replaceable Implementation.IdealSensor sensor);
end BaseSystem;

在这里,我们看到的Modelica指定配置的能力。注意了每个重声明都包括了replaceable限定词。这样做可以确保其他模型也可以继续重声明该部件。

如果我们希望SystemArchitecture模型使用上述部件作为默认实现,但同时仍使用接口作为约束类型,我们可以宣布SystemArchitecture子系统如下:

  replaceable Implementation.BasicPlant plant constrainedby Interfaces.Plant
    annotation (choicesAllMatching=true,
      Placement(transformation(extent={{-10,-50},{10,-30}})));
  replaceable Implementation.IdealActuator actuator constrainedby
    Interfaces.Actuator
    annotation (choicesAllMatching=true,
      Placement(transformation(extent={{-50,-50},{-30,-30}})));
  replaceable Implementation.IdealSensor sensor constrainedby Interfaces.Sensor
    annotation (choicesAllMatching=true,
      Placement(transformation(extent={{30,-50},{50,-30}})));
  replaceable Implementation.ProportionalController controller constrainedby
    Interfaces.Controller
    annotation (choicesAllMatching=true,
      Placement(transformation(extent={{-10,-10},{10,10}})));
  replaceable Modelica.Blocks.Sources.Trapezoid setpoint(period=1.0) constrainedby
    Modelica.Blocks.Interfaces.SO
    annotation (choicesAllMatching=true,
      Placement(transformation(extent={{-60,30},{-40,50}})));

Variation1

如果我们希望创建BaseSystem模型的变体,可以用继承和修饰词来创建它们,如:

within ModelicaByExample.Architectures.SensorComparison.Examples;
model Variant1 "Creating sample-hold variant using system architecture"
  extends BaseSystem(redeclare replaceable
      Implementation.SampleHoldSensor sensor(sample_rate=0.01));
end Variant1;

请注意如何模型是如何在扩展BaseSystem配置后,仅仅改变sensor模型的。若我们对这个系统进行仿真,性能相当于原来单层模型

但是,如果相反我们创建一个采样时间更长的配置,我们会发现系统变得不稳定(和在单层模型内的对应模型完全一样):

Variation2

请注意,即使装有性能足够的传感器,在Variant1配置里控制器似乎收敛到了错误的稳态速度。这是因为我们只使用了比例增益控制器。但是,如果我们扩展Variant1模型,并添加一个PID控制器和一个更真实的、最大提供转矩量有限的执行器,即:

within ModelicaByExample.Architectures.SensorComparison.Examples;
model Variant2 "Adds PID control and realistic actuator subsystems"
  extends Variant1(
      redeclare replaceable Implementation.PID_Controller controller(
        yMax=15, Td=0.1, k=20, Ti=0.1),
      redeclare replaceable Implementation.LimitedActuator actuator(
        delayTime=0.005, uMax=10));
end Variant2;

我们会得到下面的仿真结果:

此外,如果用一段时间来调整PID调节器的增益,即:

within ModelicaByExample.Architectures.SensorComparison.Examples;
model Variant2_tuned "A tuned up version of variant 2"
  extends Variant2(
    controller(yMax=50, Ti=0.07, Td=0.01, k=4),
    actuator(uMax=50),
    sensor(sample_rate=0.01));
end Variant2_tuned;

那么,我们将得到更好的仿真结果:

结论

我们就此完成了对上述架构的讨论。这个例子的重点是,我们可以非常容易地通过用架构探索系统的备选配置。但除了易用性外(意思是我们能很快完成这些事情),我们也能够确保一定程度的正确性,因为每个新配置都不需要增加连接。相反,用户只需要指定在各个子系统里使用的实现。而且在这时,Modelica编译器可以进行检查,以确保用户选择的实现插件兼容于指定架构的限制类型。