Main Content

Discrete-Valued Variables in Response Optimization (Code)

This example shows how to use response optimization to tune discrete-valued variables. Discrete-valued variables represent model parameters that are restricted to a finite set of values, instead of continuously varying. To use discrete-valued variables for response optimization or parameter estimation, you must use the surrogateopt solver for mixed-integer optimization.

Open the Model

In the sdoMotorPosition model, a PI controller enables the angular position of a DC motor to match a desired reference value. The load on the motor is subject to disturbances, and the controller must reject these disturbances.

open_system('sdoMotorPosition')

The sdoMotorPosition model

Within the Controller subsystem, the PI gains are set by a 12 V source divided down by resistors R1, R2, R3, and R4, as shown in the following diagram.

Controller circuit with R1, R2 in series and R3, R4 in series. These two pairs of resistors are parallel to each other.

The proportional gain, Kp, is given by 12*R2/(R1+R2) and the integral gain, Ki, is given by 12*R4/(R3+R4). The initial values of the resistances are R1 = 47 kΩ, R2 = 180 kΩ, R3 = 10 kΩ, and R4 = 10 kΩ.

Specify Discrete Design Variables

Those four resistor values are the model parameters to tune for the optimization. Because resistors are only available in discrete values, use discrete parameters to represent them. To do so, use third input argument to sdo.getParameterFromModel to specify discrete parameters.

DesignVars = sdo.getParameterFromModel('sdoMotorPosition',[],{'R1','R2','R3','R4'});

sdo.getParameterFromModel returns an array of param.Discrete parameter objects that correspond to the model parameters in the order you specified. Set the ValueSet property of each parameter to the set of discrete values allowed for the parameter. Set the Value property to the current value, which must be present in ValueSet.

% R1 values
DesignVars(1).ValueSet = [39 43 47 51 56] * 1e3;
DesignVars(1).Value    = 47*1e3;
% R2 values
DesignVars(2).ValueSet = [150 160 180 200 220] * 1e3;
DesignVars(2).Value    = 180*1e3;
% R3 values
DesignVars(3).ValueSet = [8.2 9.1 10 11 12] * 1e3;
DesignVars(3).Value    = 10*1e3;
% R4 values
DesignVars(4).ValueSet = [8.2 9.1 10 11 12] * 1e3;
DesignVars(4).Value    = 10*1e3;

Specify Design Requirements and Signals

The model applies a step disturbance at 1 second. With the initial resistance values specified in the model, the disturbance causes the motor to deviate by about 20°. The response then settles back to within ±5° of the reference position by 4 seconds after the disturbance. For this example, find new resistor values to improve this specification by 10%, so that the motor deviates no more than 18°, and settles back to within ±4.5° degrees of the reference position by 4 seconds after the disturbance. First, specify these new design requirements using sdo.requirements.SignalBound.

Requirements = struct;
Requirements.UpperBound = sdo.requirements.SignalBound(...
    'BoundMagnitudes', [18 18 ; 4.5 4.5], ...
    'BoundTimes', [1 5 ; 5 15]);
Requirements.LowerBound = sdo.requirements.SignalBound(...
    'BoundMagnitudes', [-4.5 -4.5], ...
    'BoundTimes', [5 15], ...
    'Type', '>=');

To visualize the initial performance against the requirement, first specify signals to log during simulation. In particular, log the output of the Integrator block, which is the angular position of the model, the signal you want to optimize. To do so, create a simulation scenario with sdo.SimulationTest and configure its LoggingInfo property. Also, to prepare the scenario for later use in the optimization, assign the design variables you created as its Parameters property.

Simulator = sdo.SimulationTest('sdoMotorPosition');

Sig_Info = Simulink.SimulationData.SignalLoggingInfo;
Sig_Info.BlockPath = 'sdoMotorPosition/Integrator';
Sig_Info.LoggingInfo.LoggingName = 'Sig';
Sig_Info.LoggingInfo.NameMode = 1;

Simulator.LoggingInfo.Signals = Sig_Info;

Simulator.Parameters = DesignVars;

Now create a plot of the disturbance-rejection requirements. Then, simulate the model and add the logged signal to the plot.

hRequirement = plot( ...
    Requirements.LowerBound.BoundTimes', ...
    Requirements.LowerBound.BoundMagnitudes', ...
    'color','black');
hold on
plot( ...
    Requirements.UpperBound.BoundTimes', ...
    Requirements.UpperBound.BoundMagnitudes', ...
    'color','black');
% Simulator.Parameters = DesignVars;
Simulator = sim(Simulator);
SimLog = find(Simulator.LoggedData, ...
    get_param('sdoMotorPosition','SignalLoggingName'));
Sig_Log = find(SimLog,'Sig');
clrs = colororder;
hOriginal = plot(Sig_Log.Values,'Color',clrs(2,:));
legend([hRequirement hOriginal],'Requirement','Original Variables');

Figure contains an axes object. The axes object contains 4 objects of type line. These objects represent Requirement, Original Variables.

The plot shows that the current resistor values do not quite satisfy the more stringent requirement.

Set up Optimization

The optimization process runs the model many times with different values for the resistor variables. To expedite this, configure the simulator for fast restart.

Simulator = setup(Simulator,FastRestart='on');

Optimization requires an objective or cost function that runs the model and determines whether the disturbance rejection requirements are satisfied. For this example, use the function sdoMotorPosition_optFcn, which is included at the end of the example. This function is called many times by the optimization solver. To pass the function to the optimizer, use an anonymous function with one argument that calls sdoMotorPosition_optFcn.

optimfcn = @(P) sdoMotorPosition_optFcn(P,Simulator,Requirements);

Specify optimization options. Set the optimization method to surrogateopt solver, which is the method that supports tuning of discrete parameters.

Options = sdo.OptimizeOptions;
Options.Method = 'surrogateopt';
Options.MethodOptions.MaxFunctionEvaluations = 100;
Options.MethodOptions.ObjectiveLimit = 0.001;
Options.OptimizedModel = Simulator;

Optimize the Design

To find resistance values optimized for the requirements, call sdo.optimize with the cost function handle, parameters to optimize, and options.

rng('default');   % for reproducibility
[Optimized_DesignVars,Info] = sdo.optimize(optimfcn,DesignVars,Options);
 Optimization started 2024-Sep-05, 19:17:05

                                       Current 
 F-count     max constraint     max constraint     Trial type
       1          0.0759805          0.0759805     initial
       2          0.0751287          0.0751287     random
       3          0.0751287           0.179179     random
       4          0.0447169          0.0447169     random
       5          0.0317818          0.0317818     random
       6          0.0317818           0.261353     random
       7          0.0257711          0.0257711     random
       8          0.0257711          0.0930365     random
       9          0.0257711          0.0971938     random
      10          0.0257711           0.200359     random
      11          0.0062997          0.0062997     random
      12          0.0062997           0.206374     random
      13          0.0062997          0.0818387     random
      14          0.0062997          0.0585416     random
      15          0.0062997           0.114002     random
      16          0.0062997           0.112485     random
      17          0.0062997          0.0759805     random
      18          0.0062997          0.0709489     random
      19          0.0062997           0.280136     random
      20          0.0062997           0.099985     random
      21        -0.00759693        -0.00759693     adaptive
      22        -0.00759693          0.0691728     random
      23        -0.00759693          0.0347164     random
      24        -0.00759693          0.0977682     random
      25        -0.00759693          0.0589627     random
      26        -0.00759693           0.131778     random
      27        -0.00759693           0.147347     random
      28        -0.00759693           0.104488     random
      29        -0.00759693          0.0534262     random
      30        -0.00759693             0.1643     random
      31        -0.00759693          0.0419731     random
      32        -0.00759693          0.0396579     random
      33        -0.00759693           0.077945     random
      34        -0.00759693          0.0883493     random
      35        -0.00762259        -0.00762259     random
      36        -0.00762259          0.0455853     random
      37        -0.00762259            0.13976     random
      38        -0.00762259           0.140634     random
      39        -0.00762259          0.0662368     random
      40        -0.00762259           0.256738     random
      41        -0.00762259          0.0348764     random
      42        -0.00762259            0.18995     random
      43        -0.00762259          0.0615952     random
      44        -0.00762259          0.0597358     random
      45        -0.00762259           0.015983     random
      46        -0.00762259          0.0770592     random
      47        -0.00762259           0.174666     random
      48        -0.00762259           0.081758     random
      49        -0.00762259          0.0240828     random
      50        -0.00762259           0.173292     random

                                       Current 
 F-count     max constraint     max constraint     Trial type
      51        -0.00762259           0.116519     random
      52        -0.00762259           0.217099     random
      53        -0.00762259           0.104371     random
      54        -0.00762259          0.0937562     random
      55        -0.00762259           0.104225     random
      56        -0.00762259          0.0380129     random
      57        -0.00762259           0.150819     random
      58        -0.00762259          0.0636666     random
      59        -0.00762259          0.0320499     random
      60        -0.00762259          0.0273158     random
      61        -0.00762259          0.0798937     random
      62        -0.00762259           0.174146     random
      63        -0.00762259          0.0166127     random
      64        -0.00762259         0.00433873     adaptive
      65        -0.00762259           0.294106     random
      66        -0.00518218        -0.00518218     adaptive
      67        -0.00518218          0.0319864     random
      68        -0.00518218           0.266843     random
      69        -0.00518218          0.0342618     random
      70        -0.00518218          0.0982987     random
      71        -0.00518218          0.0419731     random
      72        -0.00518218          0.0396579     random
      73        -0.00518218           0.299815     random
      74        -0.00518218          0.0712971     random
      75        -0.00518218          0.0709489     random
      76        -0.00518218          0.0589627     random
      77        -0.00518218           0.131778     random
      78        -0.00518218         0.00653156     random
      79        -0.00518218           0.211877     random
      80        -0.00518218          0.0967155     random
      81        -0.00518218          0.0689487     random
      82        -0.00518218          0.0257711     random
      83        -0.00518218          0.0930365     random
      84        -0.00518218           0.114002     random
      85        -0.00518218           0.112485     random
      86        -0.00518218            0.06706     random
      87        -0.00518218          0.0751287     random
      88        -0.00737024        -0.00737024     adaptive
      89        -0.00737024          0.0759805     random
      90        -0.00737024            0.10447     random
      91        -0.00737024           0.190644     random
      92        -0.00737024           0.142755     random
      93        -0.00737024           0.104193     random
      94        -0.00737024           0.100237     random
      95        -0.00737024           0.097787     random
      96        -0.00737024          0.0735855     random
      97        -0.00737024           0.137557     random
      98        -0.00737024          0.0783709     random
      99        -0.00737024          0.0875674     random
     100        -0.00737024          0.0794652     random
     101        -0.00737024        -0.00737024     best value
The current solution is feasible. surrogateopt stopped because it exceeded the function evaluation limit set by the 'MethodOptions.MaxFunctionEvaluations' property in the sdo.OptimizeOptions object.
If the solution needs to be improved, you could try increasing the function evaluation limit.

Evaluate Optimized Design

Plot the model response after optimization.

Simulator.Parameters = Optimized_DesignVars;
Simulator = sim(Simulator);
SimLog = find(Simulator.LoggedData, ...
    get_param('sdoMotorPosition','SignalLoggingName'));
Sig_Log = find(SimLog,'Sig');
clrs = colororder;
hOptimized = plot(Sig_Log.Values, 'Color', clrs(1,:));
legend([hRequirement hOriginal hOptimized], ...
    'Requirement','Original Variables','Optimized Variables');

Figure contains an axes object. The axes object contains 5 objects of type line. These objects represent Requirement, Original Variables, Optimized Variables.

Now the motor position is within the spec of the disturbance rejection requirement.

Update Model with Optimized Parameter Values

sdo.Optimize returns tuned versions of the parameters in the array Optimized_DesignVars. Each entry in this array is a param.Discrete parameter object whose Value property is set to the optimized value. For instance, examine the new value of R2.

Optimized_DesignVars(2).Value
ans = 
220000

Update the model with the optimized parameter values.

sdo.setValueInModel('sdoMotorPosition',Optimized_DesignVars);

Restore the simulator fast restart settings.

Simulator = restore(Simulator);

Conclusion

In this example you tuned variables to improve the disturbance rejection characteristics of a motor controller. The variables being tuned were electrical component parts that could only take on discrete values, rather than continuous values. You used sdo.getParameterFromModel to specify the variables as discrete, and used the surrogateopt solver to tune the parameters.

Objective Function

The function sdoMotorPosition_optFcn is called at each iteration of the optimization problem with a set of parameter values, P. The function returns the objective value and constraint violations, Vals, to the optimization solver. See sdo.optimize for a more detailed description of the function signature.

function Vals = sdoMotorPosition_optFcn(P,Simulator,Requirements)
%SDOMOTORPOSITION_OPTFCN
%

% Simulate the model.
Simulator.Parameters = P;
Simulator = sim(Simulator);

% Retrieve logged signal data.
SimLog = find(Simulator.LoggedData, ...
    get_param('sdoMotorPosition','SignalLoggingName'));
Sig_Log = find(SimLog,'Sig');

% Evaluate the design requirements.
Cleq_UpperBound = evalRequirement( ...
    Requirements.UpperBound,Sig_Log.Values);
Cleq_LowerBound = evalRequirement( ...
    Requirements.LowerBound,Sig_Log.Values);

% Collect the evaluated design requirement values in a structure to
% return to the optimization solver.
Vals.Cleq = [...
    Cleq_UpperBound(:); ...
    Cleq_LowerBound(:)];
end

See Also

| | |

Related Topics