Skip to content

Commit

Permalink
Merge pull request #3590 from SenHuang19/issue2884_PID_autotuning
Browse files Browse the repository at this point in the history
Issue2884 pid autotuning
  • Loading branch information
JayHuLBL authored Dec 14, 2023
2 parents 74dc25d + 7fd01d4 commit ceb42c8
Show file tree
Hide file tree
Showing 27 changed files with 821 additions and 182 deletions.
112 changes: 51 additions & 61 deletions Buildings/Controls/OBC/Utilities/PIDWithAutotuning/FirstOrderAMIGO.mo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ block FirstOrderAMIGO
parameter Buildings.Controls.OBC.Utilities.PIDWithAutotuning.Types.SimpleController controllerType=
Buildings.Controls.OBC.Utilities.PIDWithAutotuning.Types.SimpleController.PI
"Type of controller";

parameter Real k_start(
min=100*Buildings.Controls.OBC.CDL.Constants.eps)=1
"Start value of the gain of controller"
Expand All @@ -22,7 +21,6 @@ block FirstOrderAMIGO
"Start value of the time constant of derivative block"
annotation (Dialog(group="Initial control gains, used prior to first tuning",
enable=controllerType == Buildings.Controls.OBC.Utilities.PIDWithAutotuning.Types.SimpleController.PID));

parameter Real r(
min=100*Buildings.Controls.OBC.CDL.Constants.eps)=1
"Typical range of control error, used for scaling the control error";
Expand Down Expand Up @@ -93,7 +91,9 @@ block FirstOrderAMIGO
Buildings.Controls.OBC.Utilities.PIDWithAutotuning.Relay.Controller rel(
final yHig=yHig,
final yLow=yLow,
final deaBan=deaBan) "Relay controller"
final deaBan=deaBan,
final reverseActing=reverseActing)
"Relay controller"
annotation (Placement(transformation(extent={{-40,30},{-20,50}})));
Buildings.Controls.OBC.Utilities.PIDWithAutotuning.Relay.ResponseProcess resPro(
final yHig=yHig - yRef,
Expand Down Expand Up @@ -129,6 +129,12 @@ block FirstOrderAMIGO
message="An autotuning is ongoing and an autotuning request is ignored.")
"Error message when an autotuning tuning is ongoing while a new autotuning request is received"
annotation (Placement(transformation(extent={{148,-90},{168,-70}})));
Buildings.Controls.OBC.CDL.Logical.Edge edgReq
"True only when a new request is received"
annotation (Placement(transformation(extent={{80,-80},{100,-60}})));
Buildings.Controls.OBC.CDL.Logical.TrueDelay tunStaDel(final delayTime=0.001)
"A small time delay for the autotuning start time to avoid false alerts"
annotation (Placement(transformation(extent={{80,-40},{100,-20}})));

protected
final parameter Real yHig(min=1E-6) = 1
Expand All @@ -149,108 +155,92 @@ protected
"Type of controller";

equation
connect(con.u_s, u_s) annotation (Line(points={{-42,-40},{-48,-40},{-48,0},{-200,
connect(con.u_s, u_s) annotation (Line(points={{-42,-40},{-48,-40},{-48,0},{-200,
0}}, color={0,0,127}));
connect(rel.u_s, u_s) annotation (Line(points={{-42,40},{-122,40},{-122,0},{-200,
0}}, color={0,0,127}));
connect(con.trigger, triRes) annotation (Line(points={{-36,-52},{-36,-90},{-60,
-90},{-60,-120}},
color={255,0,255}));
-90},{-60,-120}},color={255,0,255}));
connect(samk.y,con. k) annotation (Line(points={{-98,-20},{-74,-20},{-74,-32},
{-42,-32}},color={0,0,127}));
connect(con.Ti, samTi.y) annotation (Line(points={{-42,-36},{-74,-36},{-74,-50},
{-98,-50}}, color={0,0,127}));
connect(samTd.y,con. Td) annotation (Line(points={{-98,-80},{-66,-80},{-66,-44},
{-42,-44}},color={0,0,127}));
connect(rel.u_m, u_m) annotation (Line(points={{-30,28},{-30,-22},{0,-22},{0,-120}},
color={0,0,127}));
color={0,0,127}));
connect(resPro.on, rel.yOn) annotation (Line(points={{-2,40},{-10,40},{-10,34},
{-18,34}},
color={255,0,255}));
{-18,34}},color={255,0,255}));
connect(modTim.y, resPro.tim) annotation (Line(points={{-18,70},{-10,70},{-10,
46},{-2,46}},
color={0,0,127}));
46},{-2,46}},color={0,0,127}));
connect(resPro.tau, conProMod.tau) annotation (Line(points={{22,40},{28,40},{28,
32},{38,32}}, color={0,0,127}));
32},{38,32}},color={0,0,127}));
connect(conProMod.tOff, resPro.tOff) annotation (Line(points={{38,36},{30,36},
{30,44},{22,44}}, color={0,0,127}));
{30,44},{22,44}},color={0,0,127}));
connect(resPro.tOn, conProMod.tOn) annotation (Line(points={{22,48},{32,48},{32,
44},{38,44}}, color={0,0,127}));
44},{38,44}},color={0,0,127}));
connect(rel.yErr, conProMod.u) annotation (Line(points={{-18,40},{-12,40},{-12,
60},{34,60},{34,48},{38,48}},
color={0,0,127}));
connect(PIDPar.kp, conProMod.k)
annotation (Line(points={{78,46},{62,46}}, color={0,0,127}));
connect(PIDPar.T, conProMod.T)
annotation (Line(points={{78,40},{62,40}}, color={0,0,127}));
connect(PIDPar.L, conProMod.L) annotation (Line(points={{78,34},{62,34}},
color={0,0,127}));
60},{34,60},{34,48},{38,48}},color={0,0,127}));
connect(PIDPar.kp, conProMod.k) annotation (Line(points={{78,46},{62,46}}, color={0,0,127}));
connect(PIDPar.T, conProMod.T) annotation (Line(points={{78,40},{62,40}}, color={0,0,127}));
connect(PIDPar.L, conProMod.L) annotation (Line(points={{78,34},{62,34}}, color={0,0,127}));
connect(PIDPar.k, samk.u) annotation (Line(points={{102,47},{110,47},{110,96},
{-148,96},{-148,-20},{-122,-20}},
color={0,0,127}));
{-148,96},{-148,-20},{-122,-20}},color={0,0,127}));
connect(PIDPar.Ti, samTi.u) annotation (Line(points={{102,40},{112,40},{112,98},
{-150,98},{-150,-50},{-122,-50}},
color={0,0,127}));
{-150,98},{-150,-50},{-122,-50}},color={0,0,127}));
connect(PIPar.kp, conProMod.k) annotation (Line(points={{78,76},{70,76},{70,46},
{62,46}}, color={0,0,127}));
{62,46}},color={0,0,127}));
connect(PIPar.T, conProMod.T) annotation (Line(points={{78,70},{72,70},{72,40},
{62,40}}, color={0,0,127}));
{62,40}}, color={0,0,127}));
connect(PIPar.L, conProMod.L) annotation (Line(points={{78,64},{74,64},{74,34},
{62,34}}, color={0,0,127}));
{62,34}},color={0,0,127}));
connect(PIPar.k, samk.u) annotation (Line(points={{102,76},{110,76},{110,96},{
-148,96},{-148,-20},{-122,-20}},
color={0,0,127}));
-148,96},{-148,-20},{-122,-20}}, color={0,0,127}));
connect(PIPar.Ti, samTi.u) annotation (Line(points={{102,64},{112,64},{112,98},
{-150,98},{-150,-50},{-122,-50}},
color={0,0,127}));
{-150,98},{-150,-50},{-122,-50}}, color={0,0,127}));
connect(resPro.triEnd, conProMod.triEnd) annotation (Line(points={{22,32},{24,
32},{24,20},{56,20},{56,28}},
color={255,0,255}));
32},{24,20},{56,20},{56,28}}, color={255,0,255}));
connect(resPro.triSta, conProMod.triSta) annotation (Line(points={{22,36},{26,
36},{26,22},{44,22},{44,28}},
color={255,0,255}));
36},{26,22},{44,22},{44,28}}, color={255,0,255}));
connect(resPro.triEnd, samTi.trigger) annotation (Line(points={{22,32},{24,32},
{24,20},{-126,20},{-126,-36},{-110,-36},{-110,-38}},
color={255,0,255}));
color={255,0,255}));
connect(resPro.triEnd, samk.trigger) annotation (Line(points={{22,32},{24,32},
{24,20},{-126,20},{-126,-6},{-110,-6},{-110,-8}},
color={255,0,255}));
color={255,0,255}));
connect(resPro.triEnd, samTd.trigger) annotation (Line(points={{22,32},{24,32},
{24,20},{-126,20},{-126,-66},{-110,-66},{-110,-68}},
color={255,0,255}));
color={255,0,255}));
connect(PIDPar.Td, samTd.u) annotation (Line(points={{102,33},{114,33},{114,94},
{-146,94},{-146,-80},{-122,-80}},
color={0,0,127}));
connect(swi.y, y)
annotation (Line(points={{162,0},{200,0}}, color={0,0,127}));
color={0,0,127}));
connect(swi.y, y) annotation (Line(points={{162,0},{200,0}}, color={0,0,127}));
connect(u_m,con. u_m) annotation (Line(points={{0,-120},{0,-90},{-30,-90},{-30,
-52}}, color={0,0,127}));
connect(rel.y, swi.u1) annotation (Line(points={{-18,46},{-16,46},{-16,88},{130,
88},{130,8},{138,8}},
color={0,0,127}));
connect(swi.u3,con. y) annotation (Line(points={{138,-8},{128,-8},{128,-40},{-18,
connect(swi.u3,con. y) annotation (Line(points={{138,-8},{60,-8},{60,-40},{-18,
-40}}, color={0,0,127}));
connect(inTunPro.y, swi.u2) annotation (Line(points={{42,-70},{50,-70},{50,0},
{138,0}}, color={255,0,255}));
{138,0}}, color={255,0,255}));
connect(inTunPro.u, triTun) annotation (Line(points={{18,-70},{8,-70},{8,-88},
{60,-88},{60,-120}}, color={255,0,255}));
connect(inTunPro.clr, resPro.triEnd) annotation (Line(points={{18,-76},{12,-76},
{12,20},{24,20},{24,32},{22,32}},
color={255,0,255}));
{12,20},{24,20},{24,32},{22,32}},color={255,0,255}));
connect(rel.trigger, triTun) annotation (Line(points={{-36,28},{-36,-20},{8,-20},
{8,-88},{60,-88},{60,-120}},
color={255,0,255}));
{8,-88},{60,-88},{60,-120}},color={255,0,255}));
connect(resPro.trigger, triTun) annotation (Line(points={{-2,34},{-8,34},{-8,-20},
{8,-20},{8,-88},{60,-88},{60,-120}},
color={255,0,255}));
connect(nand.y, assMes.u)
annotation (Line(points={{142,-80},{146,-80}},
color={255,0,255}));
connect(nand.u2, triTun) annotation (Line(points={{118,-88},{60,-88},{60,-120}},
color={255,0,255}));
connect(nand.u1, inTunPro.y) annotation (Line(points={{118,-80},{114,-80},{114,
-70},{42,-70}},
color={255,0,255}));
{8,-20},{8,-88},{60,-88},{60,-120}},color={255,0,255}));
connect(nand.y, assMes.u) annotation (Line(points={{142,-80},{146,-80}}, color={255,0,255}));
connect(nand.u2, edgReq.y) annotation (Line(points={{118,-88},{110,-88},{110,-70},
{102,-70}}, color={255,0,255}));
connect(edgReq.u, triTun) annotation (Line(points={{78,-70},{70,-70},{70,-88},
{60,-88},{60,-120}}, color={255,0,255}));
connect(tunStaDel.y, nand.u1) annotation (Line(points={{102,-30},{112,-30},{112,
-80},{118,-80}}, color={255,0,255}));
connect(tunStaDel.u, inTunPro.y) annotation (Line(points={{78,-30},{62,-30},{62,
-70},{42,-70}}, color={255,0,255}));
annotation (Documentation(info="<html>
<p>
This block implements a rule-based PID tuning method.
Expand All @@ -275,7 +265,7 @@ In addition, the output of this block is limited from <i>0</i> to <i>1</i>.
<h4>Brief guidance</h4>
<p>
To use this block, place it in an control loop as any other PI controller.
To use this block, place it in an control loop as any other PID controller.
Before the PID tuning process starts, this block is equivalent to <a href=\"modelica://Buildings.Controls.OBC.Utilities.PIDWithInputGains\">
Buildings.Controls.OBC.Utilities.PIDWithInputGains</a>.
This block starts the PID tuning process when a request for performing autotuning occurs, i.e.,
Expand All @@ -287,7 +277,7 @@ Buildings.Controls.OBC.Utilities.PIDWithAutotuning.Relay.Controller</a>).
The PID tuning process ends automatically
(see details in <a href=\"modelica://Buildings.Controls.OBC.Utilities.PIDWithAutotuning.Relay.BaseClasses.TuningMonitor\">
Buildings.Controls.OBC.Utilities.PIDWithAutotuning.BaseClasses.Relay.TunMonitor</a>),
at which point this block turns back to a PI controller but with tuned PI parameters.
at which point this block turns back to a PID controller but with tuned PID parameters.
</p>
<p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ block Controller
"Lower value for the output";
parameter Real deaBan(min=1E-6) = 0.5
"Deadband for holding the output value";
parameter Boolean reverseActing=true
"Set to true for reverse acting, or false for direct acting control action";

Buildings.Controls.OBC.CDL.Interfaces.RealInput u_s
"Setpoint input signal"
annotation (Placement(transformation(extent={{-140,-20},{-100,20}}),
Expand All @@ -31,29 +34,34 @@ block Controller
iconTransformation(extent={{100,-20},{140,20}})));

protected
Buildings.Controls.OBC.CDL.Logical.OnOffController greMeaSet(
final bandwidth=deaBan*2,
final pre_y_start=true)
"Check if the measured value is larger than the reference, by default the relay control is on"
Buildings.Controls.OBC.CDL.Logical.OnOffController greSetMea(
final bandwidth= deaBan*2,
final pre_y_start=true) if reverseActing
"Check if the reference is larger than the measured value, by default the relay control is on"
annotation (Placement(transformation(extent={{0,-10},{20,10}})));
Buildings.Controls.OBC.CDL.Reals.Switch swi
"Switch between a higher value and a lower value"
annotation (Placement(transformation(extent={{60,-10},{80,10}})));
Buildings.Controls.OBC.CDL.Reals.Sources.Constant higVal(
final k=yHig)
"Higher value for the output"
annotation (Placement(transformation(extent={{0,50},{20,70}})));
annotation (Placement(transformation(extent={{0,70},{20,90}})));
Buildings.Controls.OBC.CDL.Reals.Sources.Constant lowVal(
final k=-yLow)
"Lower value for the output"
annotation (Placement(transformation(extent={{0,-50},{20,-30}})));
annotation (Placement(transformation(extent={{0,-70},{20,-50}})));
Buildings.Controls.OBC.CDL.Reals.Subtract conErr
"Control error (set point - measurement)"
annotation (Placement(transformation(extent={{-60,10},{-40,30}})));
Buildings.Controls.OBC.CDL.Reals.Switch swi1
"Switch between a higher value and a lower value"
annotation (Placement(transformation(extent={{-10,-10},{10,10}},
origin={-50,-50})));
Buildings.Controls.OBC.CDL.Logical.OnOffController greMeaSet(
final bandwidth=deaBan*2,
final pre_y_start=true) if not reverseActing
"Check if the measured value is larger than the reference, by default the relay control is on"
annotation (Placement(transformation(extent={{0,-40},{20,-20}})));
initial equation
assert(
yHig-yLow>1E-6,
Expand All @@ -63,30 +71,38 @@ initial equation
equation
connect(swi.y, y)
annotation (Line(points={{82,0},{88,0},{88,60},{120,60}}, color={0,0,127}));
connect(greMeaSet.reference, u_s)
annotation (Line(points={{-2,6},{-40,6},{-40,0},{-120,0}}, color={0,0,127}));
connect(higVal.y, swi.u1)
annotation (Line(points={{22,60},{40,60},{40,8},{58,8}},color={0,0,127}));
connect(lowVal.y, swi.u3) annotation (Line(points={{22,-40},{40,-40},{40,-8},{
annotation (Line(points={{22,80},{30,80},{30,8},{58,8}},color={0,0,127}));
connect(lowVal.y, swi.u3) annotation (Line(points={{22,-60},{40,-60},{40,-8},{
58,-8}}, color={0,0,127}));
connect(yOn, swi.u2) annotation (Line(points={{120,-60},{50,-60},{50,0},{58,0}},
color={255,0,255}));
connect(conErr.y, yErr) annotation (Line(points={{-38,20},{120,20}},
color={0,0,127}));
connect(greMeaSet.y, swi.u2)
annotation (Line(points={{22,0},{58,0}},color={255,0,255}));
connect(conErr.u2, u_s) annotation (Line(points={{-62,14},{-90,14},{-90,0},{-120,
0}}, color={0,0,127}));
connect(greSetMea.y, swi.u2)
annotation (Line(points={{22,0},{58,0}}, color={255,0,255}));
connect(swi1.u3, u_s) annotation (Line(points={{-62,-58},{-90,-58},{-90,0},{-120,
0}}, color={0,0,127}));
connect(swi1.y, greMeaSet.u) annotation (Line(points={{-38,-50},{-20,-50},{-20,
-6},{-2,-6}}, color={0,0,127}));
connect(swi1.y, conErr.u1) annotation (Line(points={{-38,-50},{-20,-50},{-20,-6},
{-70,-6},{-70,26},{-62,26}}, color={0,0,127}));
connect(trigger, swi1.u2) annotation (Line(points={{-80,-120},{-80,-50},{-62,-50}},
color={255,0,255}));
connect(u_m, swi1.u1) annotation (Line(points={{0,-120},{0,-80},{-70,-80},{-70,
-42},{-62,-42}}, color={0,0,127}));
connect(swi1.y, conErr.u1) annotation (Line(points={{-38,-50},{-20,-50},{-20,
-4},{-70,-4},{-70,26},{-62,26}}, color={0,0,127}));
connect(conErr.u2, u_s) annotation (Line(points={{-62,14},{-90,14},{-90,0},{-120,
0}}, color={0,0,127}));
connect(greSetMea.reference, u_s) annotation (Line(points={{-2,6},{-40,6},{-40,
0},{-120,0}}, color={0,0,127}));
connect(swi1.y, greSetMea.u) annotation (Line(points={{-38,-50},{-20,-50},{-20,
-6},{-2,-6}}, color={0,0,127}));
connect(greMeaSet.reference, swi1.y) annotation (Line(points={{-2,-24},{-16,-24},
{-16,-50},{-38,-50}}, color={0,0,127}));
connect(greMeaSet.u, u_s) annotation (Line(points={{-2,-36},{-40,-36},{-40,0},
{-120,0}}, color={0,0,127}));
connect(greMeaSet.y, swi.u2) annotation (Line(points={{22,-30},{32,-30},{32,0},
{58,0}}, color={255,0,255}));
connect(greMeaSet.y, yOn) annotation (Line(points={{22,-30},{52,-30},{52,-60},
{120,-60}}, color={255,0,255}));
connect(greSetMea.y, yOn) annotation (Line(points={{22,0},{52,0},{52,-60},{120,
-60}}, color={255,0,255}));
annotation (defaultComponentName = "relCon",
Icon(coordinateSystem(preserveAspectRatio=false), graphics={
Rectangle(
Expand Down Expand Up @@ -120,8 +136,8 @@ equation
fillPattern=FillPattern.Solid,
fillColor={175,175,175},
textString="Relay"),
Line(points={{-70,24},{-34,24},{-34,58},{38,58},{38,24},{66,24}}, color
={28,108,200})}), Diagram(
Line(points={{-70,24},{-34,24},{-34,58},{38,58},{38,24},{66,24}}, color=
{28,108,200})}), Diagram(
coordinateSystem(preserveAspectRatio=false)),
Documentation(info="<html>
<p>
Expand All @@ -131,15 +147,29 @@ boolean relay switch output <code>yOn</code>, and the control error
</p>
<ul>
<li>
<code>yErr = u_s - u_m</code>,
if the parameter <code>reverseActing = false</code>
<ul>
<li>
<code>yErr = u_m - u_s</code>,
</li>
</ul>
</li>
<li>
else
<ul>
<li>
<code>yErr = u_s - u_m </code>,
</li>
</ul>
</li>
<li>
if <code>yErr &lt; -deaBan</code> and <code>trigger</code> is <code>true</code>,
then <code>y = yHig</code>, <code>yOn = true</code>,
</li>
<li>
if <code>yErr &gt; deaBan</code> and <code>trigger</code> is <code>true</code>,
then <code>y = -yLow</code>, <code>yOn = false</code>,
else if <code>yErr &gt; deaBan</code> and <code>trigger</code> is <code>true</code>,
then <code>y = -yLow</code>,
<code>yOn = false</code>,
</li>
<li>
else, <code>y</code> and <code>yOn</code> are kept as the initial values,
Expand All @@ -159,6 +189,12 @@ Department of Automatic Control, Lund Institute of Technology, Lund University.<
</html>", revisions="<html>
<ul>
<li>
December 1, 2023, by Sen Huang:<br/>
Add a parameter <code>reverseActing</code><br/>
</li>
</ul>
<ul>
<li>
June 1, 2022, by Sen Huang:<br/>
First implementation<br/>
</li>
Expand Down
Loading

0 comments on commit ceb42c8

Please sign in to comment.