使用自定义约束和目标函数计算工作点
通常,在使用基于优化的搜索计算Simulink®模型的稳态工作点时,您可以指定已知的固定值或边界来约束模型状态、输入或输出。金宝app然而,一些系统或应用程序在定义优化搜索参数时需要额外的灵活性。
对于这样的系统,您可以指定自定义约束、附加优化目标函数或两者兼有。当软件计算一个稳态工作点时,除了标准状态、输入和输出规范外,它还应用这些自定义约束和目标函数。
您可以将自定义的等式和不等式约束指定为模型状态、输入和输出的代数组合。这些约束允许您通过指定输入、输出和状态之间的已知关系来限制作业点搜索空间。例如,您可以指定一个模型状态是其他两个状态的和。
您还可以将自定义标量目标函数指定为模型状态、输入和输出的代数组合。使用目标函数,您可以根据应用程序需求优化稳态工作点。例如,假设你的模型有多个潜在的平衡点。你可以指定一个目标函数来找到输入能量最小的稳态点。
对于复杂的模型,您可以指定一个自定义映射函数,该函数选择模型输入、输出和状态的子集,以传递给自定义成本和约束函数。
你可以在修剪模型时指定自定义优化函数:
在命令行:使用
operspec
属性指定自定义函数CustomConstrFcn
,CustomCostFcn
,CustomMappingFcn
规范的属性。使用稳态管理器:在规范选项卡上,单击削减选项.在“修剪选项”对话框中自定义优化函数节中,指定函数名。
使用模型线性化电路:在线性分析选项卡,在操作点下拉列表,单击调整模型.在“修剪模型”对话框中,在选项选项卡,在自定义优化函数节中,指定函数名。
下面的示例展示了如何创建自定义优化函数,以及如何使用这些自定义函数在命令行上修剪模型。
金宝app仿真软件模型
对于这个例子,使用一个由孔相连的三个罐的模型。
mdl =“scdTanks”;open_system (mdl)
Tank1和Tank2之间的流动是理想的。Tank2和Tank3之间的流动是不希望的不可避免的泄漏。
在系统的期望稳态下:
tan1和tan2的压强是一样的。
tan2和Tank3的压差几乎恒定
1
这就补偿了负荷。
由于Tank1和Tank2之间的连通性较弱,很难对模型进行裁剪,使Tank1和Tank2的压力相等。
没有定制的修剪模型
为模型创建一个默认的操作点规范。该规范将所有三个油罐压力都配置为自由状态,必须在调整的工作点处于稳定状态。
Opspec = operspec(mdl);
创建一个用于修整模型的选项集,抑制操作点搜索报告的命令窗口显示。具体的修剪选项取决于您的应用程序。对于这个例子,使用非线性最小二乘优化。
opt = findopOptions(“OptimizerType”,“lsqnonlin”);opt.DisplayReport =“关闭”;
修剪模型,并查看修剪后的罐压力。
[op0,rpt0] = findop(mdl,opspec,opt);op0。州
ans = x ____ (1.) scdTanks/惯性0 (2.)scdTanks/Tank1 9 (3.) scdTanks/Tank2 9.5 (4.) scdTanks/Tank3 10.5
坦克1和坦克2的压缩压力不匹配。因此,默认的工作点规范无法找到满足预期的稳态要求的工作点。如果减小约束公差,opt.OptimizationOptions.TolCon
,由于Tank2和Tank3之间存在泄漏,无法实现可行的稳态解。
添加自定义约束
要指定自定义约束,请在当前工作文件夹或MATLAB路径中定义一个函数,并带输入参数:
x
-工作点规格状态,指定为矢量。u
-工作点规格输入,指定为矢量。y
-工作点规格输出,指定为矢量。
和输出参数:
c_ineq
-必须满足的不等式约束C_ineq <= 0
在修整期间,作为向量返回。c_eq
-必须满足的等式约束C_eq = 0
在修整期间,作为向量返回。
的每个元素c_ineq
而且c_eq
指定单个约束。将应用程序的特定约束定义为状态、输入和输出的代数组合。如果没有自定义等式或不等式约束,则返回对应的输出参数为[]
.
对于本例,为了满足预期稳态的条件,定义以下自定义约束函数。
函数[c_ineq, c_eq] = myConstraints (x, y) c_ineq = [];C_eq = [x(2)-x(3);%坦克1压力-坦克2压力x (3) - x (4) + 1];%坦克二压力-坦克三压力+ 1结束
的第一个条目c_eq
将Tank1和Tank2的压力限制为相同的值。第二个相等约束定义了Tank2和Tank3之间的压降。
将自定义约束函数添加到工作点规范中。
opspec。CustomConstrFcn = @myConstraints;
使用包含自定义约束的修改后的工作点规范修剪模型,并查看修剪后的状态值。
[op1,rpt1] = findop(mdl,opspec,opt);op1。州
ans = x _______ (1.) scdTanks/惯性0 (2.)scdTanks/Tank1 9.3333 (3.) scdTanks/Tank2 9.3333 (4.) scdTanks/Tank3 10.3333
用自定义约束函数修整模型,如预期的那样,在第一个和第二个储罐中产生一个具有相同压力的工作点。而且,正如预期的那样,有一个压差1
在第三和第二罐之间。
要检查指定约束的最终值,可以检查CustomEqualityConstr
而且CustomInequalityConstr
操作点搜索报告的属性。
rpt1。CustomEqualityConstr
Ans = 1.0e-06 * -0.0001 -0.1540
接近零的值表示满足相等约束。
添加自定义目标函数
若要指定自定义目标函数,请定义具有与自定义约束函数相同输入参数的函数(x
,u
,y
),并输出参数F
.F
是修剪期间要最小化的目标函数值,作为标量返回。
将应用程序的目标函数定义为状态、输入和输出的代数组合。
对于这个例子,假设你想要保持Tank3的压力在范围[16,20]。然而,这个条件并不总是可行的。因此,如果压力不在[16,20]范围内,添加一个目标函数来招致惩罚,而不是施加硬性约束。为此,定义以下自定义目标函数。
函数F = myObjective (x, y) F = max (x(4) -20,0) +马克斯(16 x (4), 0);结束
将自定义目标函数添加到工作点规范对象。
opspec。CustomObjFcn = @myObjective;
使用自定义约束和自定义目标函数修剪工作点,并查看修剪后的状态值。
[op2,rpt2] = findop(mdl,opspec,opt);《凤凰社》第2章。州
ans = x __ (1.) scdTanks/惯性0 (2.)scdTanks/Tank1 15 (3.) scdTanks/Tank2 15 (4.) scdTanks/Tank3 16
在修剪后的工作点,Tank3的压力在自定义目标函数指定的[16,20]范围内。
若要查看标量目标函数的最终值,请检查CustomObj
操作点搜索报告的属性。
rpt2。CustomObj
Ans = 0
添加自定义映射
对于复杂的模型,您可以定义一个自定义映射,它选择模型状态、输入和输出的子集来传递给自定义约束和目标函数。这样做通过消除不需要的状态、输入和输出简化了约束和目标函数。
要指定自定义映射,请使用操作点规范定义一个函数,opspec
,作为输入参数,输出参数:
indx
—映射状态的索引indu
—映射输入的索引印第
—映射输出的索引
要根据块路径和状态名获取状态、输入和输出索引,请使用getStateIndex
,getInputIndex
,getOutputIndex
.使用这些命令对于未来的模型更改(比如模型状态的添加)是稳健的。或者,您也可以手动指定索引。的格式的详细信息indx
,indu
,印第
,请参阅getStateIndex
,getInputIndex
,getOutputIndex
.
如果自定义约束和目标函数没有使用的状态、输入或输出,则返回相应的输出参数为[]
.
对于本例,创建一个映射,其中仅包括三个罐的压力状态。为此,定义以下自定义映射函数。
函数[indx,indu,indy] = myMapping(opspec) indx = [getStateIndex(opspec,“scdTanks / Tank1”);getStateIndex (opspec“scdTanks / Tank2”);getStateIndex (opspec“scdTanks / Tank3”));Indu = [];Indy = [];结束
将自定义映射添加到工作点规范。
opspec。CustomMappingFcn = @myMapping;
使用自定义映射函数时,自定义约束和目标函数中状态、输入和输出的索引必须相对于映射函数中指定的顺序。使用新的映射更新自定义约束和目标函数。
函数[c_ineq,c_eq] = myConstraintsMap(x,u,y) c_ineq = [];C_eq = [x(1)-x(2);%坦克1压力-坦克2压力x (2) - x (3) + 1];%坦克二压力-坦克三压力+ 1结束
函数F = myObjectiveMap (x, y) F = max (x(3) -20,0) +马克斯(16 x (3), 0);结束
在这里,x
,u
,y
分别是映射状态、输入和输出的向量。中指定的映射值indx
,indu
,印第
,分别。
将更新的自定义函数添加到工作点规范中。
opspec。CustomConstrFcn = @myConstraintsMap;opspec。CustomObjFcn = @myObjectiveMap;
使用自定义映射修剪模型,并查看修剪后的状态,这些状态与前面的结果相匹配《凤凰社》第2章
.
[op3,rpt3] = findop(mdl,opspec,opt);op3。州
ans = x __ (1.) scdTanks/惯性0 (2.)scdTanks/Tank1 15 (3.) scdTanks/Tank2 15 (4.) scdTanks/Tank3 16
添加分析梯度自定义函数
为了更快或更可靠的计算,您可以向自定义约束和目标函数添加分析梯度。添加梯度可以减少优化过程中函数调用的数量,并可能提高优化结果的准确性。如果指定梯度,则必须为自定义约束和目标函数指定梯度。(Simscape™模型不支持自定义修剪的梯度。)金宝app
要定义给定约束或目标函数的梯度,取函数对给定状态、输入或输出的导数。例如,如果目标函数是
F = (u(1)+3)²+ y(1)²
的梯度F
关于u (1)
是
G = 2*(u(1)+3)
要向自定义约束函数添加渐变,请指定以下额外的输出参数:
G_ineq
-不等式约束的梯度数组G_eq
-相等约束的梯度数组
的每一列G_ineq
而且G_eq
包含一个约束的梯度,列的顺序与相应约束向量中的行顺序匹配。两者的行数G_ineq
而且G_eq
等于状态,输入和输出的总数x
,u
,y
.每一列都包含相对于的状态的梯度x
的输入u
,则输入输出y
.
对于本例,向使用自定义映射的约束函数添加渐变。使用渐变时,不必指定自定义映射。然而,当使用状态、输入和输出的映射子集时,定义梯度更简单。
函数[c_ineq,c_eq,G_ineq,G_eq] = myConstraintsGrad(x,u,y) c_ineq = [];C_eq = [x(1)-x(2);%坦克1压力-坦克2压力x (2) - x (3) + 1];%坦克二压力-坦克三压力+ 1G_ineq = [];G_eq = [10 0;1 1;0 1];结束
在这个函数中,行我
的G_eq
包含关于状态的渐变x(我)
.
类似地,要向自定义目标函数添加渐变,请指定一个额外的输出参数G
,其中包含的渐变F
.G
返回的列向量与的列的格式相同G_ineq
而且G_eq
.
函数(F, G) = myObjectiveGrad (x, y) F = max (x(3) -20,0) +马克斯(16 x (3), 0);如果x(3) >= 20 G = [0 0 1]';elseifx(3) <= 16 G = [0 0 -1]';其他的G = [0 0 0]';结束结束
因为这个例子中的目标函数是分段可微的,所以的值G
取决于Tank3中的压力值。
将更新的自定义函数添加到工作点规范中。
opspec。CustomConstrFcn = @myConstraintsGrad;opspec。CustomObjFcn = @myObjectiveGrad;
若要在优化算法中启用梯度,请启用雅可比矩阵
优化选择。
opt.OptimizationOptions.Jacobian =“上”;
在修剪模型时使用分析雅可比矩阵稳态管理器或者是模型线性化电路,选择启用解析雅可比矩阵调整选项。
使用带有渐变的自定义函数修剪模型,并查看修剪后的状态。
[op4,rpt4] = findop(mdl,opspec,opt);op4。州
ans = x __ (1.) scdTanks/惯性0 (2.)scdTanks/Tank1 15 (3.) scdTanks/Tank2 15 (4.) scdTanks/Tank3 16
优化结果与非梯度解的结果相同。
要查看梯度是否提高了优化效率,请查看工作点搜索报告。例如,比较解的数函数求值:
没有梯度:
rpt3.OptimizationOutput.funcCount
Ans = 25
与梯度:
rpt4.OptimizationOutput.funcCount
Ans = 5
对于本例,添加分析梯度减少了优化期间函数调用的数量。
另请参阅
findop
|operspec
|getStateIndex
|getInputIndex
|getOutputIndex