function [MPCstruct,SimOptions,Tf,r,v,d,ynoise,unoise,mv_signal,simBar] = mpc_simPreprocess(MPCstruct, Model, x0obj, isexplicit, varargin)
% Process input arguments including basic signals and options

% Authors:  A. Bemporad, N.L. Ricker, R. Chen
% Copyright 1994-2020 The MathWorks, Inc.

narg = length(varargin);
ny = MPCstruct.ny;
yoff = MPCstruct.yoff;
Yscale = MPCstruct.Yscale;
nmd = MPCstruct.nmd;
mdoff = MPCstruct.mdoff;
MDscale = MPCstruct.Uscale(MPCstruct.mdindex);
% simulation steps
if narg<1 || isempty(varargin{1})
    % simulation steps to be determined later
    Tf = []; 
else
    Tf = varargin{1};
    if isa(Tf,'double') && numel(Tf)==1 && isfinite(Tf) && Tf>=1
        Tf = round(Tf);
    else
        ctrlMsgUtils.error('MPC:computation:InvalidTfSim');
    end
end
% ref signal
refdefault = narg<2 || isempty(varargin{2});
if refdefault
    r = yoff';
else
    r = varargin{2};
    if ~isa(r,'double') || any(isinf(r(:))) || ~isreal(r) || size(r,2)~=ny
        ctrlMsgUtils.error('MPC:computation:InvalidSetpointSize','sim',ny);
    end
    r = r*diag(1./Yscale);
end
n_r = size(r,1);
% md signal or simopt
if narg<3
    % default v and default options
    v = [];
    SimOptions = [];
elseif narg<4 
    if isa(varargin{3},'mpcsimopt')
        % default v and custom options
        v = [];
        SimOptions = varargin{3};
    else
        % custom v and default options
        v = varargin{3};
        SimOptions = [];
    end
else
    % custom v and custom options
    v = varargin{3};
    SimOptions = varargin{4};
end
if isempty(v)
    v = mdoff';
else
    % Check correctness of measured disturbance signal
    if ~isa(v,'double') || any(isinf(v(:))) || ~isreal(v) || size(v,2)~=nmd
        ctrlMsgUtils.error('MPC:computation:InvalidMeasuredDisturbanceSize','sim',nmd);
    end
    v = v*diag(1./MDscale);    
end
n_v = size(v,1);
if isempty(SimOptions)
    SimOptions = mpcsimopt; % Empty mpcsimopt object
end

%% Check correctness of SimOptions and assign default values
try
    % mpcsimoptchk produces a new structure for variables not in MPCstruct
    [MPCstruct, params] = mpcsimoptchk(SimOptions,MPCstruct,Model,x0obj,isexplicit);
catch ME
    throw(ME);
end
% inform user if ref is specified for open loop simulation
if ~(length(varargin)<2 || isempty(varargin{2})) && MPCstruct.openloop
    if mpccheckverbose
        fprintf('-->%s\n',ctrlMsgUtils.message('MPC:computation:OpenLoopIgnoreRef'));
    end
end

%% get additional signals from options
n_d = params.n_d;
n_ny = params.n_ny;
n_nu = params.n_nu;
n_mv = params.n_mv;
d = params.d;
ynoise = params.ynoise;
unoise = params.unoise;
mv_signal = params.mv_signal;

%% Get default Tf if necessary
if isempty(Tf)
    Tf = max([n_r,n_v,n_d,n_ny,n_nu,n_mv,MPCstruct.p,10]);
end

%% Remove offsets
r = r-ones(n_r,1)*MPCstruct.yoff';
v = v-ones(n_v,1)*MPCstruct.mdoff';

%% Append signals if necessary
if n_r>0
    r = [r;ones(Tf-n_r,1)*r(n_r,:)];
end;
if n_v>0
    v = [v;ones(Tf-n_v,1)*v(n_v,:)];
end;
if n_d>0
    d = [d;ones(Tf-n_d,1)*d(n_d,:)];
end;
if n_ny>0
    ynoise = [ynoise;ones(Tf-n_ny,1)*ynoise(n_ny,:)];
end;
if n_nu>0
    unoise = [unoise;ones(Tf-n_nu,1)*unoise(n_nu,:)];
end;
if n_mv>0
    mv_signal = [mv_signal;ones(Tf-n_mv,1)*mv_signal(n_mv,:)];
end;

%% sim bar
simBar = params.simBar;