导入物理类型

在前面的小节里,我们学会了如何引用其他包中定义的类型。这令开发者不必不断地在自己的局部模型进行重复定义。相反,他们可以将定义放在包内,然后去引用这些软件包。

不过,一遍又一遍地键入冗长的全限定名进行引用不一定十分有趣。因此,Modelica语言包括import语句,令我们可以方便地使用这些定义,仿佛这些定义是在本模型进行的一样。

再次回忆前面讨论物理类型时的这个例子:

within ModelicaByExample.BasicEquations.CoolingExample;
model NewtonCoolingWithTypes "Cooling example with physical types"
  // Types
  type Temperature=Real(unit="K", min=0);
  type ConvectionCoefficient=Real(unit="W/(m2.K)", min=0);
  type Area=Real(unit="m2", min=0);
  type Mass=Real(unit="kg", min=0);
  type SpecificHeat=Real(unit="J/(K.kg)", min=0);

  // Parameters
  parameter Temperature T_inf=298.15 "Ambient temperature";
  parameter Temperature T0=363.15 "Initial temperature";
  parameter ConvectionCoefficient h=0.7 "Convective cooling coefficient";
  parameter Area A=1.0 "Surface area";
  parameter Mass m=0.1 "Mass of thermal capacitance";
  parameter SpecificHeat c_p=1.2 "Specific heat";

  // Variables
  Temperature T "Temperature";
initial equation
  T = T0 "Specify initial value for T";
equation
  m*c_p*der(T) = h*A*(T_inf-T) "Newton's law of cooling";
end NewtonCoolingWithTypes;

前面已经介绍了,我们要如何通过使用Modelica标准库内的类型以避免进行本地定义。但是,我们也可以使用import命令一次性地从Modelica语言标准库中导入这些类型,然后不需输入指定其全限定名而去使用它们。这样代码变为如下:

within ModelicaByExample.PackageExamples;
model NewtonCooling
  "Cooling example importing physical types from the Modelica Standard Library"
  import Modelica.SIunits.Temperature;
  import Modelica.SIunits.Mass;
  import Modelica.SIunits.Area;
  import ConvectionCoefficient = Modelica.SIunits.CoefficientOfHeatTransfer;
  import SpecificHeat = Modelica.SIunits.SpecificHeatCapacity;

  // Parameters
  parameter Temperature T_inf=300.0 "Ambient temperature";
  parameter Temperature T0=280.0 "Initial temperature";
  parameter ConvectionCoefficient h=0.7 "Convective cooling coefficient";
  parameter Area A=1.0 "Surface area";
  parameter Mass m=0.1 "Mass of thermal capacitance";
  parameter SpecificHeat c_p=1.2 "Specific heat";

  // Variables
  Temperature T "Temperature";
initial equation
  T = T0 "Specify initial value for T";
equation
  m*c_p*der(T) = h*A*(T_inf-T) "Newton's law of cooling";
end NewtonCooling;

在这里,我们将类型定义换成import语句。注意被高亮行如何等价于以前的代码。让我们仔细观察其中的两个导入语句以了解其对模型的影响。首先观察下面的导入语句:

  import Modelica.SIunits.Temperature;

这将类型Modelica.SIunits.Temperature导入到当前的模型。默认情况下,导入类型的名称会是全限定名最后一项的名称,即Temperature。这意味着,只要有上述import语句,我们可以简单地使用类型名Temperature,而引用将自动转到Modelica.SIunits.Temperature处。

现在,让我们来看看另一种import语句:

  import ConvectionCoefficient = Modelica.SIunits.CoefficientOfHeatTransfer;

这里的语法有点不同。在这种情况下,我们正在导入的类型是Modelica.SIunits.CoefficientOfHeatTransfer。但是,相对于直接用全限定名最后一项的名称,即CoefficientOfHeatTransfer,我们将此类型的本地名称指定为ConvectionCoefficient。在这里,改变名称允许我们使用在最初几个例子中定义的名称。通过这种方式,我们能够避免重构任何使用了旧名称的代码。另一个指定替代名称(而非Modelica编译器通常指派的默认名称)的原因是为了避免命名冲突。试想,我们希望从两个不同的包导入两种类型,如:

import Modelica.SIunits.Temperature; // Celsius
import ImperialUnits.Temperature;    // Fahrenheit

这将使两种名为Temperature的类型。通过为本地别名定义替代名称,我们进行以下行为:

import DegK = Modelica.SIunits.Temperature; // Kelvin
import DegR = ImperialUnits.Temperature;    // Rankine

国际单位

请注意,此示例导入英制单位只是为了演示潜在的命名冲突可能如何发生。但这样做在实践中是非常不好的做法。使用Modelica语言时,用户应该完全使用国际单位,切勿使用任何其他单位系统。如果你想用其他单位来输入数据或显示效果,请使用在 属性小节里讨论的displayUnit属性。

import语句最后一个值得讨论的形式是通配符导入语句。一个一个地导入单位可能有些乏味。通配符导入允许我们从给定的包里一次性导入所有类型。回想一下早前的如下例子:

within ModelicaByExample.BasicEquations.RotationalSMD;
model SecondOrderSystem "A second order rotational system"
  type Angle=Real(unit="rad");
  type AngularVelocity=Real(unit="rad/s");
  type Inertia=Real(unit="kg.m2");
  type Stiffness=Real(unit="N.m/rad");
  type Damping=Real(unit="N.m.s/rad");
  parameter Inertia J1=0.4 "Moment of inertia for inertia 1";
  parameter Inertia J2=1.0 "Moment of inertia for inertia 2";
  parameter Stiffness k1=11 "Spring constant for spring 1";
  parameter Stiffness k2=5 "Spring constant for spring 2";
  parameter Damping d1=0.2 "Damping for damper 1";
  parameter Damping d2=1.0 "Damping for damper 2";
  Angle phi1 "Angle for inertia 1";
  Angle phi2 "Angle for inertia 2";
  AngularVelocity omega1 "Velocity of inertia 1";
  AngularVelocity omega2 "Velocity of inertia 2";
initial equation
  phi1 = 0;
  phi2 = 1;
  omega1 = 0;
  omega2 = 0;
equation
  // Equations for inertia 1
  omega1 = der(phi1);
  J1*der(omega1) = k1*(phi2-phi1)+d1*der(phi2-phi1);
  // Equations for inertia 2
  omega2 = der(phi2);
  J2*der(omega2) = k1*(phi1-phi2)+d1*der(phi1-phi2)-k2*phi2-d2*der(phi2);
end SecondOrderSystem;

我们可以用导入语句替换这些类型定义,如:

import Modelica.SIunits.Angle;
import Modelica.SIunits.AngularVelocity;
import Modelica.SIunits.Inertia;
import Stiffness = Modelica.SIunits.RotationalSpringConstant;
import Damping = Modelica.SIunits.RotationalDampingConstant;

不过,导入的类型越多,我们需要添加的导入语句就越多。相对地,我们可以将模型写成如下形式:

within ModelicaByExample.PackageExamples;
model SecondOrderSystem
  "A second order rotational system importing types from Modelica Standard Library"
  import Modelica.SIunits.*;
  parameter Angle phi1_init = 0;
  parameter Angle phi2_init = 1;
  parameter AngularVelocity omega1_init = 0;
  parameter AngularVelocity omega2_init = 0;
  parameter Inertia J1=0.4;
  parameter Inertia J2=1.0;
  parameter RotationalSpringConstant k1=11;
  parameter RotationalSpringConstant k2=5;
  parameter RotationalDampingConstant d1=0.2;
  parameter RotationalDampingConstant d2=1.0;
  Angle phi1;
  Angle phi2;
  AngularVelocity omega1;
  AngularVelocity omega2;
initial equation
  phi1 = phi1_init;
  phi2 = phi2_init;
  omega1 = omega1_init;
  omega2 = omega2_init;
equation
  omega1 = der(phi1);
  omega2 = der(phi2);
  J1*der(omega1) = k1*(phi2-phi1)+d1*der(phi2-phi1);
  J2*der(omega2) = k1*(phi1-phi2)+d1*der(phi1-phi2)-k2*phi2-d2*der(phi2);
end SecondOrderSystem;

注意高亮的import语句。这条(通配符)导入语句从Modelica.SIunits导入其中的所有定义到当前的模型里。通配符导入语句不能“重命名”类型。导入类型的本地名称将和其在包内的名称一样。

在使用通配符进口之前,请务必阅读这条警告

在本章里,我们已经看到import语句如何用于从其他包内导入类型。事实证明,import语句并非总是那么有用的。当使用图形化建模环境开发模型时,工具一般采用歧义最少、最明确的方法去引用类型:使用全限定名。毕竟,使用图形工具时,名称的长度不会是问题了,用户不再需要输入类型的名称。这也避免了名称查找,命名冲突等问题。