function dyduvar(block)
%DYDUVAR   Partial derivative of output Y with respect to input U.
% 
%   This function calculates the partial derivative of the output Y respect
%   to the input U. It is intended to be used with the function ptest2sim2
%   of the Neural Network Predictive Controller.
    
%   Orlando De Jesus, Martin Hagan, 1-30-00
%   Copyright 1992-2022 The MathWorks, Inc.

setup(block)

end

function setup(block)
block.NumDialogPrms = 9;
mdlInitializeSizes(block);
block.RegBlockMethod('InitializeConditions',@mdlInitConditions);
block.RegBlockMethod('Outputs', @mdlOutputs);
block.RegBlockMethod('Update', @mdlUpdate);
block.RegBlockMethod('PostPropagationSetup', @mdlSetWorkWidths);
end

function mdlSetWorkWidths(block)
Nu = block.DialogPrm(1).Data;
Ni = block.DialogPrm(2).Data;
Nj = block.DialogPrm(3).Data;

block.NumDworks                = 1;
block.Dwork(1).Name            = 'x0';
block.Dwork(1).Dimensions      = Nu*(Ni+Nj);
block.Dwork(1).DatatypeID      = 0;
block.Dwork(1).Complexity      = 'Real';
block.Dwork(1).UsedAsDiscState = true;
end

function mdlInitializeSizes(block)
Nu = block.DialogPrm(1).Data;
Ni = block.DialogPrm(2).Data;
Nj = block.DialogPrm(3).Data;
Ts = block.DialogPrm(4).Data;

block.SampleTimes = [Ts 0];
block.NumInputPorts = 1;
block.NumOutputPorts = 1;

block.InputPort(1).Dimensions = Ni+Nj;

block.OutputPort(1).DatatypeID = 0;
block.OutputPort(1).Dimensions = Nu;
block.OutputPort(1).SamplingMode = 'Sample';
end

function mdlInitConditions(block)
Nu = block.DialogPrm(1).Data;
Ni = block.DialogPrm(2).Data;
Nj = block.DialogPrm(3).Data;

x0 = zeros(Nu*(Ni+Nj),1);
x0(1)=1;

block.Dwork(1).Data = x0;
end

function mdlOutputs(block)
Nu = block.DialogPrm(1).Data;
Ni = block.DialogPrm(2).Data;
Nj = block.DialogPrm(3).Data;
minp = block.DialogPrm(5).Data;
maxp = block.DialogPrm(6).Data;
mint = block.DialogPrm(7).Data;
maxt = block.DialogPrm(8).Data;
Normalize = block.DialogPrm(9).Data;

x = block.Dwork(1).Data;

sysout = x(Ni+1);
for k=1:Nu-1
    sysout = [sysout; x(k*(Ni+Nj)+Ni+1)]; %#ok<AGROW>
    if Normalize
        sysout=sysout*(maxt-mint)/(maxp-minp);
    end
end

block.OutputPort(1).Data = sysout;
end

function mdlUpdate(block)
Nu = block.DialogPrm(1).Data;
Ni = block.DialogPrm(2).Data;
Nj = block.DialogPrm(3).Data;

x = block.Dwork(1).Data;
u = block.InputPort(1).Data;

kk=(Nu-1)*(Ni+Nj);
out=u(1:Ni)'*x(kk+1:kk+Ni)+u(Ni+1:Ni+Nj)'*x(kk+Ni+1:kk+Ni+Nj);
x(kk+2:kk+Ni)=x(kk+1:kk+Ni-1);
if x((Nu-2)*(Ni+Nj)+1)==1 || x(kk+1)==1
    x(kk+1)=1;
else
    x(kk+1)=0;
end
x(kk+Ni+2:kk+(Ni+Nj))=x(kk+Ni+1:kk+(Ni+Nj)-1);
x(kk+Ni+1)=out;

for k=Nu-1:-1:1
    kk=(k-1)*(Ni+Nj);
    out=u(1:Ni)'*x(kk+1:kk+Ni)+u(Ni+1:Ni+Nj)'*x(kk+Ni+1:kk+Ni+Nj);
    if k~=1
        x(kk+1:kk+Ni)=x((k-2)*(Ni+Nj)+1:(k-2)*(Ni+Nj)+Ni);
    else
        x(kk+2:kk+Ni)=x(kk+1:kk+Ni-1);
        x(kk+1)=0;
    end
    x(kk+Ni+2:kk+Ni+Nj)=x(kk+Ni+1:kk+Ni+Nj-1);
    x(kk+Ni+1)=out;
end

block.Dwork(1).Data = x;
end