Undamped oscillator & PID for disturbance rejection & command tracking  (Problem 3.2)

• revised, Nov. 6, 2022:
  – miscellaneous code clean-up

Clear["Global`*"];
tmax=10;trange={t,0,tmax};d=DiracDelta[t]; (* d = input disturbance *)
step=UnitStep[t]; 
G=(1/((s^2)+1)); Gtf=TransferFunctionModel[G,s]; K1=Kp;

Proportional control

SG1=Together[(G/(1+K1 G))]; SG1tf=TransferFunctionModel[SG1,s];
negT1=Together[((-K1 G)/(1+K1 G))]; negT1tf=TransferFunctionModel[negT1,s];
y0=OutputResponse[Gtf,d,trange]; (* open-loop impulse resp. *)
y1a=OutputResponse[SG1tf/.Kp->3,d,trange]; 
y1b=OutputResponse[SG1tf/.Kp->10,d,trange]; y1c=OutputResponse[SG1tf/.Kp->30,d,trange]; (* closed-loop prop. control *)
p1a=Plot[{y0,y1a,y1b,y1c},trange];

u1a=OutputResponse[negT1tf/.Kp->3,d,trange];
u1b=OutputResponse[negT1tf/.Kp->10,d,trange]; (* [=2(t-1)(E^(-t))] *)
u1c=OutputResponse[negT1tf/.Kp->30,d,trange]; (* [=2(t-1)(E^(-t))] *)
p1b=Plot[{0,u1a,u1b,u1c},trange];

GraphicsRow[{p1a, p1b},ImageSize->Large]

FullSimplify[{OutputResponse[SG1tf,d,t],OutputResponse[negT1tf,d,t]},Kp>0]//TraditionalForm

FullSimplify[DSolveValue[{y''[t]+y[t]==-Kp y[t]+d,y[0]==0,y'[0]==0},y[t],t],Kp>0]//TraditionalForm

{SG1,negT1}

Pure derivative control

K2=Kd s; SG2=Together[(G/(1+K2 G))]; SG2tf=TransferFunctionModel[SG2,s];
negT2=Together[((-K2 G)/(1+K2 G))]; negT2tf=TransferFunctionModel[negT2,s];
y2a=OutputResponse[SG2tf/.Kd->1,d,trange];
y2b=OutputResponse[SG2tf/.Kd->2,d,trange]; 
p2a=Plot[{y0,y2a,y2b},trange];

u2a=OutputResponse[negT2tf/.Kd->1,d,trange];
u2b=OutputResponse[negT2tf/.Kd->2,d,trange]; (* [=2(t-1)(E^(-t))] *)
p2b=Plot[{0,u2a,u2b},trange];

GraphicsRow[{p2a, p2b},ImageSize->Large]

{SG2,negT2,Limit[s negT2,s -> ∞]}  (* = u((SuperPlus[0])) the initial value of the output *)

{OutputResponse[SG2tf/.Kd->1,d,t],OutputResponse[negT2tf/.Kd->1,d,t],OutputResponse[SG2tf/.Kd->2,d,t],OutputResponse[negT2tf/.Kd->2,d,t]}//Simplify//TraditionalForm

eqs2={y''[t]+y[t]==u[t]+d,u[t]==-Kd y'[t],y[0]==0,y'[0]==0}/.Kd->2;
DSolveValue[eqs2,{y[t],u[t]},t]//Simplify//TraditionalForm

PD control

K3=Kp+Kd s; SG3=Together[(G/(1+K3 G))]; SG3tf=TransferFunctionModel[SG3,s];
negT3=Together[((-K3 G)/(1+K3 G))]; negT3tf=TransferFunctionModel[negT3,s];
 y3a=OutputResponse[SG3tf/.{Kp->1,Kd->2(Sqrt[2])},d,trange];
y3b=OutputResponse[SG3tf/.{Kp->5,Kd->2(Sqrt[6])},d,trange]; 
p3a=Plot[{y2b,y3a,y3b,y0},trange,PlotRange->{-1,1}];

u3a=OutputResponse[negT3tf/.{Kp->1,Kd->2(Sqrt[2])},d,trange];
u3b=OutputResponse[negT3tf/.{Kp->5,Kd->2(Sqrt[6])},d,trange];
p3b=Plot[{u2b,u3a,,u3b},trange,PlotRange->{-5,0.5}];

GraphicsRow[{p3a, p3b},ImageSize->Large]

{SG3,negT3,Limit[s negT3,s -> ∞],Limit[ negT3,s -> 0]}  (* = u((SuperPlus[0])), the initial value of the output *)

{SG3,negT3}/.Kd->2(Sqrt[Kp+1])//FullSimplify//TraditionalForm

{OutputResponse[SG3tf/.Kd->2(Sqrt[Kp+1]),d,t],OutputResponse[negT3tf/.Kd->2(Sqrt[Kp+1]),d,t]}//Simplify//TraditionalForm

eqs3={y''[t]+y[t]==-Kp y[t]-Kd y'[t]+d,y[0]==0,y'[0]==0}/.Kd->2(Sqrt[Kp+1]);
{ysol1,usol1}=DSolveValue[eqs3,{y[t],-Kp y[t]-Kd y'[t]}/.Kd->2(Sqrt[Kp+1]),t]//Simplify;
{ysol1,usol1}/.{Kp->1}//TraditionalForm

PD control does not reject a step disturbance

y3c=OutputResponse[SG3tf/.{Kp->1,Kd->2(Sqrt[2])},step,trange];
 y3d=OutputResponse[SG3tf/.{Kp->3,Kd->2(Sqrt[4])},step,trange];
y3e=OutputResponse[SG3tf/.{Kp->9,Kd->2(Sqrt[10])},step,trange];
p3c=Plot[{y3c,y3d,y3e},trange]

{SG3,Limit[SG3,s->0]}  (* SG3(0) gives the step response for t->∞ *)

(* ysol=OutputResponse[SG3tf/.Kd->2(Sqrt[Kp+1]),step,t]//FullSimplify//TraditionalForm *)

PID control:  needed to reject a step disturbance

K4=Kp+(Ki/s)+Kd s; SG4=Together[(G/(1+K4 G))]; SG4tf=TransferFunctionModel[SG4,s];
negT4=Together[((-K4 G)/(1+K4 G))]; negT4tf=TransferFunctionModel[negT4,s];
 y4a=OutputResponse[SG4tf//.{Kp->3(a^2)-1,Ki->(a^3),Kd->3a,a->2},step,trange];
 y4b=OutputResponse[SG4tf//.{Kp->3(a^2)-1,Ki->(a^3),Kd->3a,a->2},d,trange] ;
p4a=Plot[{y4a,y4b,y0},trange,PlotRange->{-1,1}];

u4a=OutputResponse[negT4tf//.{Kp->3(a^2)-1,Ki->(a^3),Kd->3a,a->2},step,trange];
u4b=OutputResponse[negT4tf//.{Kp->3(a^2)-1,Ki->(a^3),Kd->3a,a->2},d,trange];
p4b=Plot[{u4a,u4b},trange];

GraphicsRow[{p4a, p4b},ImageSize->Large]

{SG4,negT4}

{SG4,negT4}//.{Kp->3(a^2)-1,Ki->(a^3),Kd->3a,a->2}//Simplify

{OutputResponse[SG4tf//.{Kp->3(a^2)-1,Ki->(a^3),Kd->3a,a->2},d,t]//TraditionalForm,
OutputResponse[SG4tf//.{Kp->3(a^2)-1,Ki->(a^3),Kd->3a,a->2},step,t]//TraditionalForm}

{OutputResponse[negT4tf//.{Kp->3(a^2)-1,Ki->(a^3),Kd->3a,a->2},d,t]//Simplify//TraditionalForm,
OutputResponse[negT4tf//.{Kp->3(a^2)-1,Ki->(a^3),Kd->3a,a->2},step,t]//Simplify//TraditionalForm}

PID control:  look at command tracking (step response)

T4=Together[((K4 G)/(1+K4 G))]; T4tf=TransferFunctionModel[T4,s];
SK4=Together[(K4/(1+K4 G))];SK4tf=TransferFunctionModel[SK4,s];

ypid=OutputResponse[T4tf//.{Kp->3(a^2)-1,Ki->(a^3),Kd->3a,a->2},step,trange];
upid=OutputResponse[SK4tf//.{Kp->3(a^2)-1,Ki->(a^3),Kd->3a,a->2},step,trange] ;
Plot[{ypid,upid},trange,PlotRange->{0,1.2}]

{K4,T4,SK4}//.{Kp->3(a^2)-1,Ki->(a^3),Kd->3a,a->2}//Simplify

T4tfa =T4tf /.{Kp->3(a^2)-1,Ki->(a^3),Kd->3a}/.a->2//Simplify

ytest=OutputResponse[T4tfa,step,t] //FullSimplify; ytest//TraditionalForm

SK4tfa=SK4tf/.{Kp->3(a^2)-1,Ki->(a^3),Kd->3a}/.a->2//Simplify

utest=OutputResponse[SK4tfa,1,t]//FullSimplify; utest//TraditionalForm

PID control: command tracking (step response), with feedforward

F4=(1/( T4 (((1+s/a))^2))); (* the feedforward element F4 needs to be biproper *)

T4a=F4 T4;
T4atf=TransferFunctionModel[T4a,s];
SFK4=SK4 F4; SFK4tf=TransferFunctionModel[SFK4,s];


ypida=OutputResponse[T4atf//.{Kp->3(a^2)-1,Ki->(a^3),Kd->3a,a->2},step,trange];
upida=OutputResponse[SFK4tf/.a->2,step,trange] ;
Plot[{ypida,upida},trange,PlotRange->{-0.1,4}]

{T4atf,SFK4}/.a->2//Simplify

{OutputResponse[T4atf/.a->2,step,t],OutputResponse[SFK4tf/.a->2,step,t]} //FullSimplify//TraditionalForm