主要内容

使用自定义约束和目标函数计算操作点

通常,当使用基于优化的搜索计算Simulink®模型的稳态操作点时,指定已知的固定值或边界来约束模型状态、输入或输出。然而,有些系统或应用程序在定义优化搜索参数时需要额外的灵活性。

对于这样的系统,您可以指定自定义约束、一个额外的优化目标函数,或者两者兼有。当软件计算一个稳态操作点时,除了标准状态、输入和输出规范外,它还应用这些自定义约束和目标函数。

您可以将自定义的等式和不等式约束指定为模型状态、输入和输出的代数组合。通过指定输入、输出和状态之间的已知关系,这些约束可以限制操作点搜索空间。例如,您可以指定一个模型状态是其他两个状态的和。

您还可以指定一个自定义标量目标函数作为模型状态、输入和输出的代数组合。利用目标函数,可以根据应用需求优化稳态工作点。例如,假设你的模型有多个潜在平衡点。你可以指定一个目标函数来寻找输入能量最小的稳态点。

对于复杂模型,您可以指定一个自定义映射函数,该函数选择模型输入、输出和状态的一个子集,以传递给自定义成本和约束函数。

你可以在修剪模型时指定自定义优化函数:

  • 在命令行:使用创建操作点规范operspec方法指定自定义函数CustomConstrFcnCustomCostFcn,CustomMappingFcn规格的属性。

  • 使用稳态管理器:在规范选项卡上,单击削减选项.在“修剪选项”对话框中,在自定义优化函数部分,指定函数名。

  • 使用模型线性化电路:在线性分析选项卡,在操作点下拉列表,单击调整模型.在“修剪模型”对话框中,在选项选项卡,在自定义优化函数部分,指定函数名。

下面的示例展示了如何创建自定义优化函数,以及如何使用这些自定义函数在命令行上修剪模型。

仿真软件模型

对于这个例子,使用一个由三个水箱通过小孔相互连接的模型。

mdl =“scdTanks”;open_system (mdl)

需要的是Tank1和Tank2之间的流量。tan2和Tank3之间的流动是不希望的,不可避免的泄漏。

在系统的期望稳态下:

  • 坦克1和坦克2的压强是一样的。

  • 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/ inertial 0 (2.) scdTanks/Tank1 9 (3.) scdTanks/Tank2 9.5 (4.) scdTanks/Tank3 10.5 . ans = x ____ (1.

坦克1和坦克2的裁剪压力不匹配。因此,默认的操作点规范无法找到满足预期稳态需求的操作点。如果减少约束公差,opt.OptimizationOptions.TolCon,由于tan2和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];%坦克2压力-坦克3压力+ 1结束

的第一个条目c_eq约束tan1和tan2的压力为相同的值。第二个等式约束定义了Tank2和Tank3之间的压降。

将自定义约束函数添加到操作点规范中。

opspec。CustomConstrFcn = @myConstraints;

使用包含自定义约束的修改过的操作点规范修剪模型,并查看修剪过的状态值。

[op1,rpt1] = findop(mdl,opspec,opt);op1。州
ans = x _______ (1.) scdTanks/ inertial 0 (2.) scdTanks/Tank1 9.3333 (3.) scdTanks/Tank2 9.3333 (4.) scdTanks/Tank3 10.3333 . ans = x _______ (1.) scdTanks/惯性0 (2.)scdTanks/Tank1 9.3333 (3.

用自定义约束函数对模型进行修剪,如预期的那样,第一罐和第二罐的压力相等,产生一个工作点。此外,正如所料,有一个压差1在第三和第二辆坦克之间。

要检查指定约束的最终值,可以检查CustomEqualityConstr而且CustomInequalityConstr操作点搜索报告的属性。

rpt1。CustomEqualityConstr
Ans = 1.0e-06 * -0.0001 -0.1540

接近零的值表明等式约束得到满足。

添加自定义目标函数

要指定自定义目标函数,请定义与自定义约束函数具有相同输入参数的函数(xu,y)和输出参数FF是在裁剪期间最小化的目标函数值,作为标量返回。

将应用程序的目标函数定义为状态、输入和输出的代数组合。

在这个例子中,假设你想要保持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/ inertial 0 (2.) scdTanks/Tank1 15 (3.) scdTanks/Tank2 15 (4.) scdTanks/Tank3 16 .

在裁剪工作点,Tank3中的压力在自定义目标函数中指定的[16,20]范围内。

若要查看标量目标函数的最终值,请选中CustomObj操作点搜索报告的属性。

rpt2。CustomObj
Ans = 0

添加自定义映射

对于复杂的模型,您可以定义一个自定义映射,该映射选择模型状态、输入和输出的子集,以传递给自定义约束和目标函数。这样做可以通过消除不需要的状态、输入和输出来简化约束和目标函数。

要指定自定义映射,请使用操作点规范定义函数,opspec,作为输入参数和输出参数:

  • indx—映射的状态索引

  • indu—映射的输入的索引

  • 印第—映射输出的索引

获取基于块路径和状态名的状态、输入和输出索引getStateIndexgetInputIndex,getOutputIndex.使用这些命令对于未来的模型更改(例如模型状态的添加)是健壮的。或者,您也可以手动指定索引。的格式的更多信息indxindu,印第,请参阅getStateIndexgetInputIndex,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];%坦克2压力-坦克3压力+ 1结束
函数F = myObjectiveMap (x, y) F = max (x(3) -20,0) +马克斯(16 x (3), 0);结束

在这里,xu,y分别是映射状态、输入和输出的向量。中指定的映射值indxindu,印第,分别。

将更新的自定义函数添加到操作点规范中。

opspec。customconstraintsmap = @myConstraintsMap;opspec。CustomObjFcn = @myObjectiveMap;

使用自定义映射修剪模型,并查看修剪后的状态,这些状态与前面的结果相匹配《凤凰社》第2章

[op3,rpt3] = findop(mdl,opspec,opt);op3。州
ans = x __ (1.) scdTanks/ inertial 0 (2.) scdTanks/Tank1 15 (3.) scdTanks/Tank2 15 (4.) scdTanks/Tank3 16 .

添加分析梯度自定义函数

为了更快或更可靠的计算,您可以在自定义约束和目标函数中添加分析梯度。添加梯度可以减少优化过程中函数调用的数量,并可能提高优化结果的准确性。如果指定了梯度,则必须同时为自定义约束和目标函数指定它们。(Simscape™模型不支持自定义修剪的渐变。)

要定义给定约束或目标函数的梯度,请对函数对给定状态、输入或输出求导。例如,如果目标函数是

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等于状态、输入和输出的总数xu,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];%坦克2压力-坦克3压力+ 1G_ineq = [];G_eq = [1 0;1 1;0 1];结束

在这个函数中,行G_eq包含相对于状态的梯度x(我)

类似地,要向自定义目标函数添加渐变,请指定额外的输出参数G的梯度FG作为列向量返回,其格式与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/ inertial 0 (2.) scdTanks/Tank1 15 (3.) scdTanks/Tank2 15 (4.) scdTanks/Tank3 16 .

优化结果与非梯度解的结果一致。

要查看梯度是否提高了优化效率,可以查看操作点搜索报告。例如,比较解决方案的数字函数计算:

  • 没有梯度:

rpt3.OptimizationOutput.funcCount
Ans = 25
  • 与梯度:

rpt4.OptimizationOutput.funcCount
Ans = 5

对于本例,添加分析梯度减少了优化过程中函数调用的数量。

另请参阅

||||

相关的话题

Baidu
map