function [newmodel,newts,newxp0,newu1,uoff,yoff,xoff,dxoff]=mpc_chkmodel(...
    model,ts,offsets,xp0,mv0,mvindex,myindex,Uscale,Yscale)
%MPC_CHKMODEL Check if 'model', 'ts', 'xp0', 'u0' are ok and scale the model.

%   Author: A. Bemporad
%   Copyright 1986-2013 The MathWorks, Inc.

verbose = mpccheckverbose;
sw = ctrlMsgUtils.SuspendWarnings('Control:transformation:C2dApproximate');

%% Convert any LTI to SS
if ~isa(model,'ss')
    if verbose
        fprintf('-->%s\n',ctrlMsgUtils.message('MPC:object:ConvertPlantToSS'));
    end
    model=ss(model);
    % Use DARE to test detectability:
    if ~mpc_chkdetectability(model.A,model.C(myindex,:),model.ts) % System is not detectable
        model=minreal(model);
    end
    % create offset X and DX
    offsets.X=zeros(size(model.A,1),1);
    offsets.DX=offsets.X;
    % error out if xp0 is provided
    if ~isempty(xp0)
        ctrlMsgUtils.error('MPC:utility:InvalidPlantModelInitialState');
    end
end

%% Delete input/output names
% To avoid conflicts when augmenting the plant
model.InputName = '';
model.OutputName = '';
model.InputUnit = '';
model.OutputUnit = '';
 
%% If plnat sample time is -1, assume it is the same as controller sample time
mts=model.ts;
if mts<0
    if ts>0
        if verbose
            fprintf('-->%s\n',ctrlMsgUtils.message('MPC:object:AssumeSampleTimePlantModel',sprintf('%g',ts)));
        end
        mts=ts;
        model.ts=ts;
    else
        ctrlMsgUtils.error('MPC:utility:NoSampleTimeForModel');
    end
end

%% Check consistency of xp0
xoff=offsets.X;
uoff=offsets.U;
yoff=offsets.Y;
dxoff=offsets.DX;
[~,nx]=size(model.c);
if nx==0
    ctrlMsgUtils.error('MPC:utility:NoStatesForModel');
end
xp0=mpc_chkx0u1(xp0,nx,xoff,ctrlMsgUtils.message('MPC:utility:InitialStatePlantModel'));
xp0=xp0-xoff; % Initial condition for linearized plant

%% Check consistency of last mv
nu=length(mvindex);
mv0=mpc_chkx0u1(mv0,nu,uoff(mvindex),ctrlMsgUtils.message('MPC:utility:LastMoveField'));
mv0=mv0-uoff(mvindex); % Initial condition for last MV
if norm(mv0)>0
    ctrlMsgUtils.warning('MPC:computation:U0Incorrect');        
end

%% Augment the model
% Add contribution of the dx offset term as a plant input
model = augmentMPCPlantModel(model, dxoff);
ingroup=mpc_getgroup(model.InputGroup);
ingroup.Offset=size(model.b,2);
set(model,'InputGroup',ingroup);

%% When model is continuous, discretize it with controller sample time
if mts==0
    if verbose
        fprintf('-->%s\n',ctrlMsgUtils.message('MPC:object:ConvertToDiscrete'));
    end
    newts=ts;
    try
        % Try is needed because C2D may give the error 'Initial state mapping G is not meaningful for
        % models with I/O delays.' when iodelays are present

        % Note: UserData field is lost during conversion !!!
        [model,TRmat]=c2d(model,ts);
        % TRmat maps continuous initial conditions
        % into discrete initial conditions.  Specifically, if x0,u0
        % are initial states and inputs for the continuous time model,
        % then equivalent initial conditions for the discrete time model
        % are given by  xd0 = TRmat * [x0;u0],  ud0 = u0 .
        nutot=size(model.b,2);
        u0=zeros(nutot,1);
        u0(mvindex)=mv0;        
        xp0=TRmat*[xp0;u0];
        % offset
        utoff=uoff;     % offsets for MVs+UDs
        utoff(end+1)=0; % offset for the offset MD=1        
        dxoff=dxoff*ts; % Maps continuous-time DX offset into discrete-time DX offset
        xoff=TRmat*[xoff(:);utoff(:)];
        dxoff=TRmat*[dxoff(:);0*utoff(:)];
        %if norm(xp0)>0 & norm(mv0)>0 & norm(TRmat(:,nx+1:size(TRmat,2)))>0,
        %   % Usually this never happens
        %   disp('Warning: initial state information might be wrong')
        %   disp('         because of continuous->discrete conversion.')
        %end
    catch ME
        % Note: UserData field is lost during conversion !!!
        if model.ts==0
            model=c2d(model,ts);    
        end
        if norm(xp0)>0
            if verbose
                fprintf('-->%s',ctrlMsgUtils.message('MPC:object:InitialX'));
            end
        end
        xp0=zeros(size(model.A,1),1);
        if norm(xoff)>0 || norm(dxoff)>0
            if verbose
                fprintf('-->%s',ctrlMsgUtils.message('MPC:object:InitialXffset'));
            end
        end
        xoff=xp0;
        dxoff=xp0;
    end
%% When controller time is not given, use the plant sample time
elseif isempty(ts) || abs(ts-mts)<=1e-10
    newts=mts; 
%% When plant and controller have different discrete sample time, resample plant model with d2d
elseif abs(ts-mts)>1e-10
    if verbose
        fprintf('-->%s\n',ctrlMsgUtils.message('MPC:object:ResamplePlantModel'));
    end
    try
        model=d2d(model,ts);
    catch ME
        throw(ME);
    end
    %takes out possible imaginary parts
    %set(model,'a',real(model.a),'b',real(model.b));
    newts=ts;
    % No, state dimension may not be consistent in case d2d augments the
    % order of the system
    xextra=zeros(size(model.A,1)-length(xp0),1);
    xp0=[xp0;xextra];
    xoff=[xoff(:);xextra];
    dxoff=[dxoff(:);xextra];
    if norm(xp0,'inf')>1e-10
        ctrlMsgUtils.warning('MPC:computation:X0Incorrect');    
    end
    if norm(xoff,'inf')>1e-10
        ctrlMsgUtils.warning('MPC:computation:XOffsetIncorrect');
    end
    if norm(dxoff,'inf')>1e-10
        ctrlMsgUtils.warning('MPC:computation:XDotIncorrect');
    end
end

%% Eventually absorb delay into poles in z=0
if hasdelay(model)
    if verbose
        fprintf('-->%s\n',ctrlMsgUtils.message('MPC:object:DelayToSS'));
    end
    [model, DELAYmat] = absorbDelay(model);
    aux=size(model.A,1)-length(xp0);    
    % pad xp0 with zeros
    xp0 = DELAYmat*xp0;
    % pad offset and augmentB
    xoff=[xoff(:);zeros(aux,1)];
    dxoff=[dxoff(:);zeros(aux,1)];
end

%% return after scaling
% Note:  need to account for added input
UscaleM = diag([Uscale; 1]);
YscaleM = diag(1./Yscale);
model.b = model.b*UscaleM;
model.c = YscaleM*model.c;
model.d = YscaleM*model.d*UscaleM;
newmodel=model;
newxp0=xp0;
newu1=mv0./Uscale(mvindex);

uoff=uoff./Uscale;
yoff=yoff./Yscale;