第五章 函数
5.1 概念
- 应用场合:当建模过程中,需要含有显性赋值的程序或算法的情况
- 函数的特点:
- 所有量必须显性标记为输入或输出
- 函数没有被连接到其他组件,而是在对表达式赋值时被调用
- 函数不允许持续保持内部状态(e.g. der算子不能出现在函数中)
- 函数定义中只能有且仅有一个算法段,用于函数计算
- 当函数被调用时,函数的输入对象相当于函数的自变量;而当函数用于表达式时,输出对象相当于函数值
5.2 简介
示例函数:从一个元素为名称的数组中搜寻一个特殊的名称,并获得数组中该名称的索引,找不到名称时输出一个错误信息(名称用字符串String
类型)
function FindName
input String names [:];
// ":"表明数组的长度为任意值
// 被定位为可以处理任意长度的 一维数组,以增强函数的鲁棒性
input String name_to_find;
output Integer index;
protected
// protected关键字:受保护的部分,包含了对所有局部变量的声明,且局部变量仅在函数中可见,用后即删
Integer i, len = size(names,1);
// size()函数可以返回正确的数组长度
algorithm
index :=-1;
i := 1;
while index == -1 and i <=len loop
if names[i] == name_to_find then
index := i;
end if;
i := i+1;
end while;
assert (index <> -1,"FindName:failed");
//assert()函数验证待定的条件,当结果为假,即index=-1时,输出函数中第二个自变量包含的信息
end FindName;
//函数调用
model TestFindName
parameter String names[:]={"H2O","CO2","N2"};
parameter Integer CO2 = FindName(names,"CO2");
end TestFindName;
- 调用函数时,自变量设置需依据函数声明的自变量顺序
5.3 插值函数
一维线性插值函数
function Piecewise "A piecewise linear interpolation"
input Real x "Independent variable";
input Real x_grid[:] "Independent variable data points";
input Real y_grid[:] "Dependent variable data points";
output Real y "Interpolated result";
protected
Integer n;
algorithm
n := size(x_grid,1);
assert(size(x_grid,1) == size(y_grid,1),"size mismatch");
// 确保输入数组x_grid和y_grid长度相同
assert(x>=x_grid[1] and x<= x_grid[n],"out of range");
//确保x在x_grid自变量给定的范围内
for i in 1:n-1 loop
//i是for循环的局部变量,循环开始时创建,end for后删除i,因此无需对i单独声明
if x>=x_grid[i] and x<= x_grid[i+1] then
y := y_grid[i] + (y_grid[i+1]-y_grid[i])*((x-x_grid[i])/(x_grid[i+1]-x_grid[i]));
end if;
end for;
end Piecewise;
model TestPiecewise
package SI = Modelica.SIunits;
parameter SI.Time x_vals(6)={0,2,4,6,8,10};
parameter Real y_vals(6)={0,0,4,16,36,64};
Real y;
equation
y=Piecewise(x=time,x_grid=x_vals,y_grid=y_vals);
end TestPiecewise;
调用函数的两种方法:
- 按函数定义中声明的自变量顺序进行数据传递
- 为每一个自变量提供一个显性等式
5.4 多重返回值
使用单一循环计算多项式的值和导数
model TestPolyEval
parameter Real coefs[3]= {2.0,1.0,2.0};
Real y,fdy,dy;
equation
(y,fdy)=PolyEval(time.coefs);
dy=der(y);
end TestPolyEval;
//可以通过比较fdy与dy,验证函数PolyEval
function PolyEval "Evaluate polynomial and derivative"
input Real x;
input Real coef[:] "low to high order";
output Real y;
output Real dydx "Derivative of polynomial";
protected
Integer n;
algorithm
n:=size(coef,1);
y:=coef[n];
dydx:=0.0;
for i in n-1 : -1 : 1 loop
y:=y*x+coef[i];
dydx:=dydx*x+i*coef[i+1];
end for;
end PolyEval;
5.5 自变量records
当需要传递大量的自变量给函数时,可以先定义一个record类型,该类型可以用于将几个逻辑上相关的自变量组合在一起,形成一个自变量集
正弦波求和函数:ΣAi sin(2pi x fi + ph_i)
function ComplexWave
record Data // 局部定义
constant Integer num "number of waves";
Real a[num] "Wave amplitudes";
Modelica.SIunits.Frequency f[num];
Modelica.SIunits.Angle phase[num];
end Data;
input Real x;
input Data d "Wave data";
output Real y;
protected
Integer n;
Real s;
algorithm
n:=d.num;
y:=0;
for i in 1:n loop
s:=sin(2*Modelica.Constants.pi*d.f[i]*x+d.phase[i]);
y:=y+d.a[i]*s;
end for;
end ComplexWave;
model TestComplexWave
parameter ComplexWave.Data wdata(num=3,
a={1.3,2.2,5.8},
f={2.0,3.0,7.0},
phase={0,Modelica.Constants.pi,0});
// 函数外,record定义必须使用限定名ComplexWave.Data
Real signal;
equation
signal=ComplexWave(time,wdata);
end TestComplexWave;
model TestComplexWave2
parameter ComplexWave.Data wdata(num=3);// 非参数设定
Real signal;
equation
signal=ComplexWave(time,wdata);
wdata.a={1.3,2.2,5.8*exp(-0.54*time};//声明一个含有随时间变化参数的record
wdata.f={2.0,3.0,7.0};
wdata.phase={0,Modelica.Constants.pi,0};
end TestComplexWave2;
使用record,可将函数ComplexWave的自变量数减少到2个
5.6 使用外部子程序
在调用外部子程序前,首先需要在Modelica模型中编写一个封装函数。
//调用C子程序compute_enthalpy
function Enthalpy
input Modelica.SIunits.Pressure P;
input Modelica.SIunits.Temp_K T;
output Modelica.SIunits.Enthalpy h;
external "C" compute_enthalpy(P,T,h);
end Enthalpy;
//调用FORTRAN77子程序的封装函数,有多个返回值
function SteamTable
input Modelica.SIunits.Pressure P;
input Modelica.SIunits.Temp_K T;
output Modelica.SIunits.SpecificEnthalpy h;
output Modelica.SIunits.SpecificEnergy u;
output Modelica.SIunits.SpecificHeatCapacity cp;
output Modelica.SIunits.Density rho;
external "FORTRAN77" calcprops(P,T,h,u,cp,rho);
end SteamTable;
5.7 Modelica语言基础
- 分支语句
if x>=0 then
y:=x;
elseif x<=-3 then
y:=-6;
else
y:=-2*x;
end if;
- 循环语句
//循环用于需要执行迭代的算法
While "Condition" loop
// do something
end While;
//for语句对矢量进行运算更方便
for someVar in someVector loop
//do something
end for;
//for语句尽可能基于矢量(一维数组)进行循环操作
-
调用函数
- 用方程给自变量赋值时,自变量顺序不分先后
- 只要有一个自变量用方程赋值,其余所有自变量都必须用方程赋值
- 若不用方程赋值,则函数定义中自变量的顺序决定了调用时所需自变量的顺序
- 函数只有一个返回值时,可以用在表达式中
y=x*Piecewise(t); - 函数有多个返回值时,函数调用只能在方程或赋值中使用,且函数必须完整地置于等式右边,而等式左边是括号中用逗号隔开的获取返回值的变量列表
(h,u,cp,rho)=SteamTable(P,T);
-
内置函数
- 类型分析:analysisType(),使模型可以根据不同的分析类型定制模型的行为,返回一个字符串说明模型当前进行的分析类型。
- 求绝对值:abs()
- 符号判别:sign()
- 求平方根:sqrt()
- 求最小及最大整数:ceil(),返回大于x的最小整数;floor(),返回小于x的最大整数
- 取整:integer(),返回一个不大于x的最大整数
- 整除:div(x,y),返回一个不带小数,即取整为零,的x/y代数商
- 余数:rem(x,y),返回div()函数丢弃的余数;rem(x,y)=x-div(x,y)*y
- 模运算:mod(x,y)=x-floor(x/y)*y