%% Explicit MPC Control of a Single-Input-Single-Output Plant
% This example shows how to control a double integrator plant under input
% saturation in Simulink(R) using explicit MPC.
%
% For an example that controls a double integrator with an implicit MPC
% controller, see <docid:mpc_gs#mw_768e6d27-8e7c-42a3-93a6-51289c5dc856>.

% Copyright 1990-2014 The MathWorks, Inc.

%% Define Plant Model
% The linear open-loop dynamic model is a double integrator.
plant = tf(1,[1 0 0]);

%% Design MPC Controller
% Create the controller object with sampling period, prediction and control
% horizons.
Ts = 0.1;   
p = 10;
m = 3;
mpcobj = mpc(plant, Ts, p, m);
%%
% Specify actuator saturation limits as MV constraints.
mpcobj.MV = struct('Min',-1,'Max',1); 

%% Generate Explicit MPC Controller
% Explicit MPC executes the equivalent explicit piecewise affine version of
% the MPC control law defined by traditional implicit MPC. To generate an
% Explicit MPC from a traditional MPC, you must specify range for each
% controller state, reference signal, manipulated variable and measured
% disturbance so that the multi-parametric quadratic programming problem is
% solved in the parameter space defined by these ranges.
    
%%
% Use the |generateExplicitRange| function to obtain a range structure
% where you can specify parameter ranges.
range = generateExplicitRange(mpcobj);

%%
% MPC controller states include states from plant model, disturbance model
% and noise model in that order. Setting the range of a state variable is
% sometimes difficult when the state does not correspond to a physical
% parameter. In that case, multiple runs of open-loop plant simulation
% with typical reference and disturbance signals are recommended in order
% to collect data that reflect the ranges of states.
range.State.Min(:) = [-10;-10];
range.State.Max(:) = [10;10];

%%
% Usually you know the practical range of the reference signals being used
% at the nominal operating point in the plant. The ranges used to generate
% an explicit MPC controller must be at least as large as the practical
% range.
range.Reference.Min = -2;
range.Reference.Max = 2;

%%
% Specify manipulated variable ranges. If the manipulated variables are
% constrained, the ranges used to generate the explicit MPC controller must
% be at least as large as these limits.
range.ManipulatedVariable.Min = -1.1;
range.ManipulatedVariable.Max = 1.1;

%%
% Use |generateExplicitMPC| command to obtain an explicit MPC controller 
% with the specified parameter ranges.
mpcobjExplicit = generateExplicitMPC(mpcobj, range)

%%
% Use the |simplify| function with the |'exact'| method to join pairs of
% regions whose corresponding gains are the same and whose union is a
% convex set. Doing so can reduce memory footprint of the explicit MPC
% controller without sacrificing any performance.
mpcobjExplicitSimplified = simplify(mpcobjExplicit, 'exact')

%%
% The number of piecewise affine regions has been reduced.

%% Plot Piecewise Affine Partition
% You can review any 2-D section of the piecewise affine partition defined
% by the explicit MPC control law.

%%
% Use |generatePlotParameters| command to obtain a parameter structure
% where you can specify which 2-D section to plot afterwards.
params = generatePlotParameters(mpcobjExplicitSimplified);

%%
% In this example, you plot the first state variable against the second
% state variable. All the other parameters must be fixed at a value within
% their respective ranges.
params.State.Index = []; 
params.State.Value = [];

%%
% Fix other reference signals.
params.Reference.Index = 1;
params.Reference.Value = 0;

%%
% Fix manipulated variables.
params.ManipulatedVariable.Index = 1;
params.ManipulatedVariable.Value = 0;

%%
% Use |plotSection| command to plot the 2-D section defined previously.
plotSection(mpcobjExplicitSimplified, params);
axis([-4 4 -4 4]);
grid
xlabel('State #1');
ylabel('State #2');

%% Simulate Using |mpcmove| Function
% Compare closed-loop simulations for traditional implicit MPC and explicit
% MPC using the |mpcmove| and |mpcmoveExplicit| functions respectively.
%
% Prepare to store the closed-loop MPC responses.
Tf = round(5/Ts);
YY = zeros(Tf,1);
YYExplicit = zeros(Tf,1);
UU = zeros(Tf,1);
UUExplicit = zeros(Tf,1);

%% 
% Prepare the real plant used in simulation
sys = c2d(ss(plant),Ts);
xsys = [0;0];
xsysExplicit = xsys;

%%
% Use an |mpcstate| object to specify the initial states for both
% controllers.
xmpc = mpcstate(mpcobj);  
xmpcExplicit = mpcstate(mpcobjExplicitSimplified);

%%
% Iteratively simulate the closed-loop response for both controllers.
for t = 0:Tf
    % update plant measurement
    ysys = sys.C*xsys;
    ysysExplicit = sys.C*xsysExplicit;
    % compute traditional MPC action
    u = mpcmove(mpcobj,xmpc,ysys,1);
    % compute Explicit MPC action
    uExplicit = mpcmoveExplicit(mpcobjExplicit,xmpcExplicit,ysysExplicit,1);
    % store signals
    YY(t+1)=ysys;
    YYExplicit(t+1)=ysysExplicit;
    UU(t+1)=u;
    UUExplicit(t+1)=uExplicit;
    % update plant state
    xsys = sys.A*xsys + sys.B*u;
    xsysExplicit = sys.A*xsysExplicit + sys.B*uExplicit;
end

fprintf('\nDifference between traditional and Explicit MPC responses using MPCMOVE command is %g\n',...
    norm(UU-UUExplicit)+norm(YY-YYExplicit));

%% Simulate Using |sim| Function
% Compare closed-loop simulation between traditional MPC and Explicit MPC
% using |sim| commands respectively.
Tf = 5/Ts;                      % simulation iterations
[y1,t1,u1] = sim(mpcobj,Tf,1);  % simulation with tradition MPC
[y2,t2,u2] = sim(mpcobjExplicitSimplified,Tf,1); % simulation with Explicit MPC

%%
% The simulation results are identical.
fprintf('\nDifference between traditional and Explicit MPC responses using SIM command is %g\n',...
    norm(u2-u1)+norm(y2-y1));

%% Simulate Using Simulink
% To run this example, Simulink is required.
if ~mpcchecktoolboxinstalled('simulink')
    disp('Simulink is required to run this example.')
    return
end

%%
% Simulate the traditional MPC controller in Simulink. The MPC Controller
% block is configured to use |mpcobj| as its controller.
mdl = 'mpc_doubleint';
open_system(mdl)
sim(mdl)

%%
% Simulate the explicit MPC controller in Simulink. The Explicit MPC
% Controller block is configured to use |mpcobjExplicitSimplified| as its
% controller.
mdlExplicit = 'empc_doubleint';
open_system(mdlExplicit)
sim(mdlExplicit)

%%
% The closed-loop responses are identical.
fprintf('\nDifference between traditional and Explicit MPC responses in Simulink is %g\n',...
    norm(uExplicit-u)+norm(yExplicit-y));

%%
bdclose(mdl)
bdclose(mdlExplicit)
