使用优化探索器并行优化 Simulink 模型
本示例演示了如何使用优化探索器并行优化一个 Simulink® 模型。若要使用优化探索器对 Simulink 模型进行优化,通常必须采用串行计算,而非并行计算。这一限制源于优化求解器的设计,该求解器通常通过使用 parfor 或 parfeval 函数进行并行计算。Simulink 模型不支持这些并行计算函数。
不过,如示例 并行优化 Simulink 模型 所示,您可以使用支持向量化函数计算的 Global Optimization Toolbox 求解器,以并行方式优化 Simulink 模型。这些求解器是 ga、patternsearch、surrogateopt 和 particleswarm。
要配置优化探索器以对 Simulink 模型进行并行优化,首先需要基于该模型编写一个向量化目标函数。然后,您需要在优化探索器中为向量化目标函数指定属性,并选择求解器和选项。
基于 Simulink 模型的向量化目标函数
要并行优化一个 Simulink 模型,请编写一个向量化目标函数,该函数应:
接受矩阵作为输入,其中矩阵的每一行都是一个参数向量
通过调用
parsim(Simulink) 函数进行并行仿真返回一个值向量,其中向量中的每个条目包含与输入矩阵一行中的参数相对应的目标函数的值
该图展示了向量化目标函数如何处理输入值矩阵,并生成一个输出值的列向量。

在此示例中,请使用 Lorenz_system.slx Simulink 模型。
目标函数是最小化从 0 到 1/10 的一组时间内洛伦兹系统和均匀圆周运动之间的差异的平方和。对于时间 xdata,目标函数是
objective = sum((fitlorenzfn(x,xdata) - lorenz(xdata)).^2) - (F(1) + F(end))/2
其中:
辅助函数
fitlorenzfn(见本示例末尾)用于计算匀速圆周路径上的点。lorenz(xdata)表示洛伦兹系统在时间点xdata时的三维演化。F表示圆坐标系与洛伦兹坐标系中对应点之间距离平方的向量。目标是减去端点处的一半值以最好地近似积分。
输入匀速圆周运动的数据。
x = zeros(8,1); x(1) = 1.2814; x(2) = -1.4930; x(3) = 24.9763; x(4) = 14.1870; x(5) = 0.0545; x(6:8) = [13.8061;1.5475;25.3616];
加载 Lorenz 系统并使用基本参数仿真。绘制该系统的三维绘图,并将该绘图与指定的匀速圆周运动进行比较。
model = "Lorenz_system"; open_system(model); in = Simulink.SimulationInput(model); % params [X0,Y0,Z0,Sigma,Beta,Rho] params = [10,20,10,10,8/3,28]; % Original parameters Sigma, Beta, Rho in = setparams(in,model,params); out = sim(in); yout = out.yout; tlist = yout{1}.Values.Time; YDATA = fitlorenzfn(x,tlist); figure; plot3(yout{1}.Values.Data,yout{2}.Values.Data,yout{3}.Values.Data,"x"); view([-30 -70]) hold on plot3(YDATA(:,1),YDATA(:,2),YDATA(:,3),"o") legend("Lorenz","Uniform circular motion") hold off

下文所示的 parobjfun 辅助函数接受一个参数矩阵,其中矩阵的每一行代表一组参数。该函数调用 setparams 辅助函数(见本示例末尾),用于为 Simulink.SimulationInput 向量设置参数。然后,parobjfun 函数调用 parsim 并行评估模型的参数。parobjfun 函数:
接受一个包含 N 个元素的参数向量
为模型创建一个包含 N 个仿真输入的向量
将输出初始化为包含 N 个零的向量
将优化参数映射到每个仿真输入
设置
parsim属性并并行执行仿真获取仿真输出(阻塞调用),并计算最终输出
function f = parobjfun(params,YDATA,model) N = size(params,1); simIn(1:N) = Simulink.SimulationInput(model); f = zeros(N,1); for i = 1:N simIn(i) = setparams(simIn(i),model,params(i,:)); end simOut = parsim(simIn,ShowProgress="off", ... UseFastRestart="on"); for i = 1:N yout = simOut(i).yout; vals = [yout{1}.Values.Data,yout{2}.Values.Data,yout{3}.Values.Data]; g = sum((YDATA - vals).^2,2); f(i) = sum(g) - (g(1) + g(end))/2; end end
将求解器的界限设置为高于和低于当前参数值的 20%。
lb = 0.8*params; ub = 1.2*params;
为了提高速度,请将模拟设置为使用快速重启。
set_param(model,FastRestart="on");使用 closeModel 辅助函数(见本示例末尾)定义一个用于关闭模型的函数。
c = onCleanup(@()closeModel(model));
为了实现可再现性,请设置随机流。
rng(1)
将目标函数定义为 parobjfun 及其额外参数。
fitobjective = @(params)parobjfun(params,YDATA,model);
优化探索器中的向量化目标函数
在命令行中输入以下内容以启动优化探索器:
optimizationExplorer
由于需要使用向量化函数计算,请通过求解器输入指定问题。

对于目标函数,请选择 fitobjective。点击高级,然后选择向量化。您可以将求解器的选项保留为默认设置;您将在下一节中指定求解器。

对于这个问题,请选择 params 作为初始点 (x0) 的值。在约束中,选择边界,并将边界 lb 和 ub 分别设置为 lb 和 ub。点击下一个继续。
手动调动求解器配置
若要并行优化 Simulink 模型,必须运行手动配置,而非自动配置。因此,您无需选择任何问题属性,例如凸、非光滑、计算成本高或仿真。点击下一个继续。
指定以手动模式运行优化探索器。

点击开始会话。
关闭并行功能
尽管您将在优化探索器中并行运行 Simulink,但请勿使用 App 的默认并行模式。使用并行按钮不适用于优化 Simulink 模型。

选择求解器和选项
要安排求解器配置,请使用工具栏中的选择求解器部分。选择求解器后,App 会打开一个包含该求解器选项的选项卡。首先选择 ga 求解器。

使用添加按钮可显示可设置的求解器选项。对于某些求解器(例如 patternsearch),您首先需要为该求解器选择算法。要设置其他选项,请点击已设置选项右侧出现的加号。
请安排以下求解器算法,这些算法均可采用向量化方式运行:ga、patternsearch (nups)、patternsearch (classic)、surrogateopt 和 particleswarm。为了使示例能够相对快速地运行,请将每个求解器的函数计算最大次数设置为 300(对于 ga 和 particleswarm,设置种群规模为 12,运行 25 次迭代)。设置以下选项:
ga
种群设置 > 种群大小
12运行时间限制 > 最大代数
25指定初始点:来自工作区 >
params
模式搜索
算法 >
nups运行时间限制 > 最大函数执行次数
300指定初始点:来自工作区 >
params
模式搜索
算法 >
classic运行时间限制 > 最大函数执行次数
300轮询设置 > 进行完整轮询选中该复选框
注意:要以向量化方式运行 patternsearch(经典版),必须使用完整的轮询。
4.指定初始点:来自工作区 > params
surrogateopt
算法设置 > 替代更新和函数计算的批量大小
12运行时间限制 > 最大函数执行次数
300指定初始点:来自工作区 >
params
粒子群
运行时间限制 > 最大迭代次数
25群设置 > 群规模
12指定初始点:来自工作区 >
params

完成求解器选择后,请点击工具栏上的运行按钮,以运行优化探索器。求解器配置面板显示当前正在运行的求解器以及计划运行的求解器。
结果
优化探索器完成后,您将看到如下或类似的结果。

如这些结果所示:
最佳(最小)目标函数值约为
23.016,由patternsearch(nups)求解器返回。无论是
ga求解器还是patternsearch(classic)求解器,最快的运行时间都约为112秒。除
ga之外的所有求解器,其目标函数值均小于 24。所有求解器都从目标函数值fitobjective(params)=26.9975开始。
辅助函数
以下代码创建 fitlorenzfn 辅助函数。
function f = fitlorenzfn(x,xdata) % Lorenz function theta = x(1:2); R = x(3); V = x(4); t0 = x(5); delta = x(6:8); f = zeros(length(xdata),3); f(:,3) = R*sin(theta(1))*sin(V*(xdata - t0)) + delta(3); f(:,1) = R*cos(V*(xdata - t0))*cos(theta(2)) ... - R*sin(V*(xdata - t0))*cos(theta(1))*sin(theta(2)) + delta(1); f(:,2) = R*sin(V*(xdata - t0))*cos(theta(1))*cos(theta(2)) ... - R*cos(V*(xdata - t0))*sin(theta(2)) + delta(2); end
以下代码创建 setparams 辅助函数。
function pp = setparams(in,model,params) % parameters [X0,Y0,Z0,Sigma,Beta,Rho] pp = in.setVariable("X0",params(1),"Workspace",model); pp = pp.setVariable("Y0",params(2),"Workspace",model); pp = pp.setVariable("Z0",params(3),"Workspace",model); pp = pp.setVariable("Sigma",params(4),"Workspace",model); pp = pp.setVariable("Beta",params(5),"Workspace",model); pp = pp.setVariable("Rho",params(6),"Workspace",model); end
以下代码创建 closeModel 辅助函数。要关闭模型,必须首先禁用快速重启。
function closeModel(model) set_param(model,FastRestart="off"); close_system(model) end