主要内容

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

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

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

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

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

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

您可以指定自定义优化功能时,修剪您的模型:

  • 在命令行:使用operspec,并使用CustomConstrFcnCustomCostFcn,CustomMappingFcn属性。

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

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

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

金宝app仿真软件模型

对于这个例子,使用一个由孔板连接的三个储罐模型。

mdl =“scdTanks”;open_system (mdl)

油箱1和油箱2之间的流量是需要的。2号罐和3号罐之间的流动是不需要的,不可避免的泄漏。

在系统预期的稳定状态下:

  • 油箱1和油箱2的压力相同。

  • Tank2和Tank3的压差几乎是恒定的1这是对负载的补偿。

由于Tank1和Tank2之间的连接性较弱,很难修剪模型使Tank1和Tank2中的压力相等。

没有定制的修剪模型

为模型创建一个默认的操作点规范。该规范将所有三个储罐压力配置为自由状态,必须在修剪操作点处于稳定状态。

opspec = operspec (mdl);

创建一个用于调整模型的选项集,抑制操作点搜索报告的命令窗口显示。具体的微调选项取决于您的应用程序。对于这个例子,使用非线性最小二乘优化。

选择= findopOptions (“OptimizerType”“lsqnonlin”);opt.DisplayReport =“关闭”

修剪模型,并查看修剪后的油箱压力。

[op0, rpt0] = findop (mdl opspec,选择);op0。州
(1.) scdTanks/惯性x: 0 (2.) scdTanks/Tank1 x: 9 (3.) scdTanks/Tank2 x: 9.5 (4.) scdTanks/Tank3 x: 10.5

油箱1和油箱2的压力调整不匹配。因此,默认工作点规范无法找到一个满足预期稳态要求的工作点。如果你减少约束容限,opt.OptimizationOptions.TolCon,由于罐2和罐3之间的泄漏,无法实现可行的稳态解决方案。

添加自定义约束

要指定自定义约束,请在当前工作目录或MATLAB路径中使用输入参数定义一个函数:

  • x-工作点规范状态,指定为向量。

  • u-工作点规范输入,指定为向量。

  • y-工作点规范输出,指定为向量。

输出参数:

  • c_ineq-必须满足的不等式约束c_ineq < = 0在修整期间,返回为矢量。

  • c_eq-必须满足的等式约束c_eq = 0在修整期间,返回为矢量。

的每个元素c_ineqc_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;

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

(凤凰社第一章,rpt1) = findop (mdl opspec,选择);op1。州
(1.) scdTanks/惯性x: 0 (2.) scdTanks/Tank1 x: 9.33 (3.) scdTanks/Tank2 x: 9.33 (4.) scdTanks/Tank3 x: 10.3

用自定义约束函数对模型进行微调,就会像预期的那样在第一个和第二个储罐中产生一个压力相等的工作点。正如预期的那样,还有一个压差1在第三和第二辆坦克之间。

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

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

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

添加自定义目标函数

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

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

对于这个例子,假设您想要保持3号油箱的压力在[16,20]范围内。然而,这种情况并不总是可行的。因此,如果压力不在[16,20]范围内,可以添加一个目标函数来招致惩罚,而不是施加硬约束。为此,定义以下自定义目标函数。

函数F = myObjective (x, y) F = max (x(4) -20,0) +马克斯(16 x (4), 0);结束

将自定义目标函数添加到工作点规范对象中。

opspec。CustomObjFcn = @myObjective;

使用自定义约束和自定义目标函数对工作点进行修剪,并查看修剪后的状态值。

(《凤凰社》第2章,rpt2) = findop (mdl opspec,选择);《凤凰社》第2章。州
(1.) scdTanks/惯性x: 0 (2.) scdTanks/Tank1 x: 15 (3.) scdTanks/Tank2 x: 15 (4.) scdTanks/Tank3 x: 16 (3.) scdTanks/Tank2 x: 15 (4.) scdTanks/Tank3 x: 16

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

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

rpt2。CustomObj
ans = 0

添加自定义映射

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

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

  • indx—映射状态索引

  • indu-映射输入的索引

  • 印第—映射输出的索引

根据块路径和状态名获取状态、输入和输出索引getStateIndexgetInputIndex,getOutputIndex.使用这些命令对于未来的模型更改(如添加模型状态)是健壮的。或者,您可以手动指定索引。有关格式的更多信息indxindu,印第,请参阅getStateIndexgetInputIndex,getOutputIndex

如果没有自定义约束和目标函数使用的状态、输入或输出,则返回相应的输出参数为[]

对于本例,创建一个只包含三个容器的压力状态的映射。为此,定义以下自定义映射函数。

函数[indx,indu,indy] = myMapping(opspec)“scdTanks / Tank1”);getStateIndex (opspec“scdTanks / Tank2”);getStateIndex (opspec“scdTanks / Tank3”));indu = [];印地赛车= [];结束

将自定义映射添加到操作点规范。

opspec。CustomMappingFcn = @myMapping;

当您使用自定义映射函数时,自定义约束和目标函数中的状态、输入和输出的索引必须与映射函数中指定的顺序相关。使用新的映射更新自定义约束和目标函数。

函数[c_ineq,c_eq] = myConstraintsMap(x,u,y)c_eq = [x - x (1) (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。CustomConstrFcn = @myConstraintsMap;opspec。CustomObjFcn = @myObjectiveMap;

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

[op3, rpt3] = findop (mdl opspec,选择);op3。州
(1.) scdTanks/惯性x: 0 (2.) scdTanks/Tank1 x: 15 (3.) scdTanks/Tank2 x: 15 (4.) scdTanks/Tank3 x: 16 (3.) scdTanks/Tank2 x: 15 (4.) scdTanks/Tank3 x: 16

为自定义函数添加分析梯度

为了更快或更可靠的计算,您可以向自定义约束和目标函数添加分析梯度。添加梯度可以减少优化期间的函数调用次数,并可能提高优化结果的准确性。如果指定梯度,则必须同时为自定义约束和目标函数指定它们。(Simscape™模型不支持用于自定义微调的梯度。)金宝app

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

F = (u(1)+3)²+ y(1)²

然后是梯度F关于u (1)

G = 2 * (u (1) + 3)

要向自定义约束函数添加梯度,请指定以下额外的输出参数:

  • G_ineq-不等式约束的梯度数组

  • G_eq-等号约束的梯度数组

每一列的G_ineqG_eq包含一个约束的梯度,并且列的顺序与相应约束向量中的行的顺序相匹配。两者的行数G_ineqG_eq等于状态、输入和输出的总数xu,y.每一列包含相对于中的状态的梯度x,然后是输入u,然后输入输出y

对于本例,向使用自定义映射的约束函数添加梯度。当使用渐变时,您不必指定自定义映射。然而,当使用状态、输入和输出的映射子集时,定义梯度会更简单。

函数[c_ineq,c_eq,G_ineq,G_eq] = myConstraintsGrad(x,u,y) c_ineq = [];c_eq = [x - x (1) (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_ineqG_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取决于3号罐的压力值。

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

opspec。CustomConstrFcn = @myConstraintsGrad;opspec。CustomObjFcn = @myObjectiveGrad;

若要启用优化算法中的梯度,请启用雅可比矩阵优化选择。

opt.OptimizationOptions.Jacobian =“上”

用解析雅可比矩阵对模型进行裁剪时使用稳态经理或者是模型线性化电路,选择使雅可比矩阵分析调整选项。

使用带有梯度的自定义函数修剪模型,并查看修剪状态。

[op4, rpt4] = findop (mdl opspec,选择);op4。州
(1.) scdTanks/惯性x: 0 (2.) scdTanks/Tank1 x: 15 (3.) scdTanks/Tank2 x: 15 (4.) scdTanks/Tank3 x: 16 (3.) scdTanks/Tank2 x: 15 (4.) scdTanks/Tank3 x: 16

优化结果与非梯度解的结果相同。

要查看梯度是否提高了优化效率,请查看操作点搜索报告。例如,比较数值函数的求解结果:

  • 没有梯度:

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

rpt4.OptimizationOutput.funcCount
ans = 5

对于本例,添加分析梯度可以减少优化期间的函数调用数量。

另请参阅

||||

相关的话题