Buildings.Controls.OBC.Utilities

Package with utility functions

Information

This package contains utility blocks, base classes and validation models for the OpenBuildingControl (OBC) library.

Package Content

Name Description
Buildings.Controls.OBC.Utilities.OptimalStart OptimalStart Block that outputs the optimal start time for an HVAC system before occupancy
Buildings.Controls.OBC.Utilities.PIDWithInputGains PIDWithInputGains P, PI, PD, and PID controller with output reset and input gains
Buildings.Controls.OBC.Utilities.SetPoints SetPoints Package with blocks for setpoint resets
Buildings.Controls.OBC.Utilities.Validation Validation Collection of validation models
Buildings.Controls.OBC.Utilities.BaseClasses BaseClasses Package with base classes

Buildings.Controls.OBC.Utilities.OptimalStart Buildings.Controls.OBC.Utilities.OptimalStart

Block that outputs the optimal start time for an HVAC system before occupancy

Buildings.Controls.OBC.Utilities.OptimalStart

Information

This block predicts the shortest time for an HVAC system to meet the occupied setpoint prior to the scheduled occupancy. The block requires inputs of zone temperature, occupied zone setpoint(s) and next occupancy. The two outputs are the optimal start duration tOpt and the optimal start on signal optOn for the HVAC system.

The block estimates the thermal mass of a zone using its measured air temperature gradient with respect to time. Once the temperature slope of a zone is known, the optimal start time can be calculated by the difference between the zone temperature and the occupied setpoint divided by the temperature slope, assuming the zone responds as if all thermal mass were concentrated in the room air.

The temperature slope is self-tuned based on past data. The moving average of the temperature slope of the past nDay days is calculated and used for the prediction of the optimal start time in the current day.

Parameters

The parameter nDay is used to compute the moving average of the temperature slope; the first n days of simulation is therefore used to initialize the block.

The parameter tOptMax is the maximum allowed optimal start time.

The block includes two hysteresis parameters uLow and uHigh. The parameter uLow is used to determine if the zone temperature reaches the setpoint. The algorithm assumes that the zone temperature has reached the setpoint if TSetZonHea-TZon ≤ uLow for a heating system, or TZon-TSetZonCoo ≤ uLow for a cooling system, where TSetZonHea denotes the zone heating setpoint during occupancy, TSetZonCoo denotes the zone cooling setpoint during occupancy, and TZon denotes the zone temperature. The parameter uHigh is used by the algorithm to determine if there is a need to start the HVAC system prior to occupancy. If TSetZonHea-TZon ≤ uHigh for heating case or TZon-TSetZonCoo ≤ uHigh for cooling case, then there is no need for the system to start before the occupancy.

The optimal start is only active (i.e., the optimal start on signal optOn becomes true) if the optimal start time is larger than the parameter thrOptOn.

Configuration for HVAC systems

The block can be used for heating system only or cooling system only or for both heating and cooling system. The two parameters computeHeating and computeCooling are used to configure the block for these three scenarios.

The block calculates the optimal start time separately for heating and cooling systems. The base class Buildings.Controls.OBC.Utilities.BaseClasses.OptimalStartCalculation is used for the calculation.

Algorithm

The algorithm is as follows:

Step 1: Calculate temeperature slope TSlo

Once the HVAC system is started, a timer records the time duration Δt for the zone temperature to reach the setpoint. At the time when the timer starts, the zone temperature TSam1 is sampled. The temperature slope is approximated using the equation TSlo = |TSetZonOcc-TSam1|/Δt, where TSetZonOcc is the occupied zone setpoint. Note that if Δt is greater than the maximum optimal start time tOptMax, then tOptMax is used instead of Δt. This is to avoid corner cases where the setpoint is never reached, e.g., the HVAC system is undersized, or there is a steady-state error associated with the HVAC control.

Step 2: Calculate temperature slope moving average TSloMa

After computing the temperature slope of each day, the moving average of the temperature slope TSloMa during the previous nDay days is calculated. Please refer to Buildings.Controls.OBC.CDL.Discrete.TriggeredMovingMean for details about the moving average algorithm.

Step 3: Calculate optimal start time tOpt

Each day at a certain time before the occupancy, the algorithm takes another sample of the zone temperature, denoted as TSam2. The sample takes place tOptMax prior to occupancy start time.

The optimal start time is then calculated as tOpt = |TSetZonOcc-TSam2|/TSloMa.

Validation

Validation models can be found in the package Buildings.Controls.OBC.Utilities.Validation.

Parameters

TypeNameDefaultDescription
RealtOptMax10800Maximum optimal start time [s]
IntegernDay3Number of previous days used to compute the optimal start up time
BooleancomputeHeatingfalseSet to true to compute optimal start for heating
BooleancomputeCoolingfalseSet to true to compute optimal start for cooling
RealuLow0Threshold to determine if the zone temperature reaches the occupied setpoint, must be a non-negative number [K]
RealuHigh0.5Threshold to determine the need to start the HVAC system before occupancy, must be greater than uLow [K]
RealthrOptOn60Threshold time, optimal start on signal becomes true when tOpt larger than thrOptOn [s]

Connectors

TypeNameDescription
input RealInputTSetZonHeaZone heating setpoint temperature during occupancy [K]
input RealInputTZonZone temperature [K]
input RealInputTSetZonCooZone cooling setpoint temperature during occupancy [K]
input RealInputtNexOccTime until next occupancy [s]
output RealOutputtOptOptimal start time duration of HVAC system [s]
output BooleanOutputoptOnOutputs true if the HVAC system remains in the optimal start period

Modelica definition

block OptimalStart "Block that outputs the optimal start time for an HVAC system before occupancy" parameter Real tOptMax( final quantity="Time", final unit="s", displayUnit="h", final min=0, max=21600)=10800 "Maximum optimal start time"; parameter Integer nDay( min=1)=3 "Number of previous days used to compute the optimal start up time"; parameter Boolean computeHeating=false "Set to true to compute optimal start for heating"; parameter Boolean computeCooling=false "Set to true to compute optimal start for cooling"; parameter Real uLow( final quantity="TemperatureDifference", final unit="K", final min=0)=0 "Threshold to determine if the zone temperature reaches the occupied setpoint, must be a non-negative number"; parameter Real uHigh( final quantity="TemperatureDifference", final unit="K", final min=0)=0.5 "Threshold to determine the need to start the HVAC system before occupancy, must be greater than uLow"; parameter Real thrOptOn( final quantity="Time", final unit="s", displayUnit="h", final min=0, max=10800)=60 "Threshold time, optimal start on signal becomes true when tOpt larger than thrOptOn"; Buildings.Controls.OBC.CDL.Interfaces.RealInput TSetZonHea( final quantity="ThermodynamicTemperature", final unit="K", displayUnit="degC", min=200) if computeHeating "Zone heating setpoint temperature during occupancy"; Buildings.Controls.OBC.CDL.Interfaces.RealInput TZon( final quantity="ThermodynamicTemperature", final unit="K", displayUnit="degC", min=200) "Zone temperature"; Buildings.Controls.OBC.CDL.Interfaces.RealInput TSetZonCoo( final quantity="ThermodynamicTemperature", final unit="K", displayUnit="degC", min=200) if computeCooling "Zone cooling setpoint temperature during occupancy"; Buildings.Controls.OBC.CDL.Interfaces.RealInput tNexOcc( final quantity="Time", final unit="s", displayUnit="h") "Time until next occupancy"; Buildings.Controls.OBC.CDL.Interfaces.RealOutput tOpt( final quantity="Time", final unit="s", displayUnit="h") "Optimal start time duration of HVAC system"; Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput optOn "Outputs true if the HVAC system remains in the optimal start period"; Buildings.Controls.OBC.Utilities.BaseClasses.OptimalStartCalculation optHea( final tOptMax=tOptMax, final thrOptOn=thrOptOn, final nDay=nDay, final uLow=uLow, final uHigh=uHigh) if computeHeating "Optimal start time for heating system"; Buildings.Controls.OBC.Utilities.BaseClasses.OptimalStartCalculation optCoo( final tOptMax=tOptMax, final thrOptOn=thrOptOn, final nDay=nDay, final uLow=uLow, final uHigh=uHigh) if computeCooling "Optimal start time for cooling system"; Buildings.Controls.OBC.CDL.Reals.GreaterThreshold hysSta( t=60, h=60) "Hysteresis to activate the optimal start boolean output"; protected Buildings.Controls.OBC.CDL.Reals.Max max "Get the maximum optimal start time "; Buildings.Controls.OBC.CDL.Reals.AddParameter addPar( p=-tOptMax) "Maximum optimal start time"; Buildings.Controls.OBC.CDL.Logical.Or or2 "Get the optimal start boolean output"; Buildings.Controls.OBC.CDL.Reals.Subtract dTHea if computeHeating "Temperature difference between heating setpoint and zone temperature"; Buildings.Controls.OBC.CDL.Reals.Subtract dTCoo if computeCooling "Temperature difference between zone temperature and cooling setpoint"; Buildings.Controls.OBC.CDL.Logical.FallingEdge falEdg "Stop calculation"; Buildings.Controls.OBC.CDL.Reals.Sources.Constant con2( final k=0) if not computeHeating "Becomes effective when optimal start is only for heating"; Buildings.Controls.OBC.CDL.Reals.Sources.Constant con1( final k=0) if not computeCooling "Becomes effective when optimal start is only for cooling"; Buildings.Controls.OBC.CDL.Logical.Sources.Constant con( final k=false) if not computeHeating "Becomes effective when optimal start is only for heating"; Buildings.Controls.OBC.CDL.Logical.Sources.Constant con3( final k=false) if not computeCooling "Becomes effective when optimal start is only for cooling"; equation connect(TSetZonCoo,dTCoo.u2); connect(TZon,dTCoo.u1); connect(TZon,dTHea.u2); connect(TSetZonHea,dTHea.u1); connect(max.y,tOpt); connect(con2.y,max.u1); connect(con1.y,max.u2); connect(dTCoo.y,optCoo.TDif); connect(dTHea.y,optHea.TDif); connect(tNexOcc,addPar.u); connect(tNexOcc,optHea.tNexOcc); connect(optCoo.tOpt,max.u2); connect(optHea.tOpt,max.u1); connect(tNexOcc,optCoo.tNexOcc); connect(falEdg.y,optHea.staCal); connect(falEdg.y,optCoo.staCal); connect(or2.y,optOn); connect(con.y,or2.u1); connect(con3.y,or2.u2); connect(optCoo.optOn,or2.u2); connect(optHea.optOn,or2.u1); connect(falEdg.u,hysSta.y); connect(addPar.y,hysSta.u); end OptimalStart;

Buildings.Controls.OBC.Utilities.PIDWithInputGains Buildings.Controls.OBC.Utilities.PIDWithInputGains

P, PI, PD, and PID controller with output reset and input gains

Buildings.Controls.OBC.Utilities.PIDWithInputGains

Information

PID controller in the standard form

yu = k/r   (e(t) + 1 ⁄ Ti   ∫ e(τ) dτ + Td d⁄dt e(t)),

with output reset, where yu is the control signal before output limitation, e(t) = us(t) - um(t) is the control error, with us being the set point and um being the measured quantity, k is the gain, Ti is the time constant of the integral term, Td is the time constant of the derivative term, r is a scaling factor, with default r=1. The scaling factor should be set to the typical order of magnitude of the range of the error e. For example, you may set r=100 to r=1000 if the control input is a pressure of a heating water circulation pump in units of Pascal, or leave r=1 if the control input is a room temperature.

Note that the units of k are the inverse of the units of the control error, while the units of Ti and Td are seconds.

The actual control output is

y = min( ymax, max( ymin, y)),

where ymin and ymax are limits for the control signal.

This block is identical to Buildings.Controls.OBC.CDL.Reals.PIDWithReset, except that the controller gains k, Ti and Td are inputs rather than parameters.

P, PI, PD, or PID action

Through the parameter controllerType, the controller can be configured as P, PI, PD or PID controller. The default configuration is PI.

Reverse or direct action

Through the parameter reverseActing, the controller can be configured to be reverse or direct acting. The above standard form is reverse acting, which is the default configuration. For a reverse acting controller, for a constant set point, an increase in measurement signal u_m decreases the control output signal y (Montgomery and McDowall, 2008). Thus,

If reverseAction=false, then the error e above is multiplied by -1.

Anti-windup compensation

The controller anti-windup compensation is as follows: Instead of the above basic control law, the implementation is

yu = k   (e(t) ⁄ r + 1 ⁄ Ti   ∫ (-Δy + e(τ) ⁄ r) dτ + Td ⁄ r d⁄dt e(t)),

where the anti-windup compensation Δy is

Δy = (yu - y) ⁄ (k Ni),

where Ni > 0 is the time constant for the anti-windup compensation. To accelerate the anti-windup, decrease Ni.

Note that the anti-windup term (-Δy + e(τ) ⁄ r) shows that the range of the typical control error r should be set to a reasonable value so that

e(τ) ⁄ r = (us(τ) - um(τ)) ⁄ r

has order of magnitude one, and hence the anti-windup compensation should work well.

Reset of the controller output

Whenever the value of boolean input signal trigger changes from false to true, the controller output is reset by setting y to the value of the parameter y_reset.

Approximation of the derivative term

The derivative of the control error d ⁄ dt e(t) is approximated using

d⁄dt x(t) = (e(t)-x(t)) Nd ⁄ Td,

and

d⁄dt e(t) ≈ Nd (e(t)-x(t)),

where x(t) is an internal state.

Guidance for tuning the control gains

The parameters of the controller can be manually adjusted by performing closed loop tests (= controller + plant connected together) and using the following strategy:

  1. Set very large limits, e.g., set ymax = 1000.
  2. Select a P-controller and manually enlarge the parameter k (the total gain of the controller) until the closed-loop response cannot be improved any more.
  3. Select a PI-controller and manually adjust the parameters k and Ti (the time constant of the integrator). The first value of Ti can be selected such that it is in the order of the time constant of the oscillations occurring with the P-controller. If, e.g., oscillations in the order of 100 seconds occur in the previous step, start with Ti=1/100 seconds.
  4. If you want to make the reaction of the control loop faster (but probably less robust against disturbances and measurement noise) select a PID-controller and manually adjust parameters k, Ti, Td (time constant of derivative block).
  5. Set the limits yMax and yMin according to your specification.
  6. Perform simulations such that the output of the PID controller goes in its limits. Tune Ni (Ni Ti is the time constant of the anti-windup compensation) such that the input to the limiter block (= lim.u) goes quickly enough back to its limits. If Ni is decreased, this happens faster. If Ni is very large, the anti-windup compensation is not effective and the controller works bad.

References

R. Montgomery and R. McDowall (2008). "Fundamentals of HVAC Control Systems." American Society of Heating Refrigerating and Air-Conditioning Engineers Inc. Atlanta, GA.

Parameters

TypeNameDefaultDescription
SimpleControllercontrollerTypeBuildings.Controls.OBC.CDL.T...Type of controller
Realr1Typical range of control error, used for scaling the control error
BooleanreverseActingtrueSet to true for reverse acting, or false for direct acting control action
Limits
RealyMax1Upper limit of output
RealyMin0Lower limit of output
Integrator reset
Realy_resetxi_startValue to which the controller output is reset if the boolean trigger has a rising edge
Advanced
Integrator anti-windup
RealNi0.9Ni*Ti is time constant of anti-windup compensation
Derivative block
RealNd10The higher Nd, the more ideal the derivative block
Initialization
Realxi_start0Initial value of integrator state
Realyd_start0Initial value of derivative output

Connectors

TypeNameDescription
input RealInputu_sConnector for setpoint input signal
input RealInputu_mConnector for measurement input signal
input RealInputkConnector for control gain signal
input RealInputTiConnector for time constant signal for the integral term [s]
input RealInputTdConnector for time constant signal for the derivative term [s]
output RealOutputyConnector for actuator output signal
input BooleanInputtriggerResets the controller output when trigger becomes true

Modelica definition

block PIDWithInputGains "P, PI, PD, and PID controller with output reset and input gains" parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerType=Buildings.Controls.OBC.CDL.Types.SimpleController.PI "Type of controller"; parameter Real r( min=100*CDL.Constants.eps)=1 "Typical range of control error, used for scaling the control error"; parameter Real yMax=1 "Upper limit of output"; parameter Real yMin=0 "Lower limit of output"; parameter Real Ni( min=100*CDL.Constants.eps)=0.9 "Ni*Ti is time constant of anti-windup compensation"; parameter Real Nd( min=100*CDL.Constants.eps)=10 "The higher Nd, the more ideal the derivative block"; parameter Real xi_start=0 "Initial value of integrator state"; parameter Real yd_start=0 "Initial value of derivative output"; parameter Boolean reverseActing=true "Set to true for reverse acting, or false for direct acting control action"; parameter Real y_reset=xi_start "Value to which the controller output is reset if the boolean trigger has a rising edge"; Buildings.Controls.OBC.CDL.Interfaces.RealInput u_s "Connector for setpoint input signal"; Buildings.Controls.OBC.CDL.Interfaces.RealInput u_m "Connector for measurement input signal"; Buildings.Controls.OBC.CDL.Interfaces.RealInput k( min=100*Buildings.Controls.OBC.CDL.Constants.eps) "Connector for control gain signal"; Buildings.Controls.OBC.CDL.Interfaces.RealInput Ti( quantity="Time", unit="s", min=100*Buildings.Controls.OBC.CDL.Constants.eps) if with_I "Connector for time constant signal for the integral term"; Buildings.Controls.OBC.CDL.Interfaces.RealInput Td( quantity="Time", unit="s", min=100*Buildings.Controls.OBC.CDL.Constants.eps) if with_D "Connector for time constant signal for the derivative term"; Buildings.Controls.OBC.CDL.Interfaces.RealOutput y "Connector for actuator output signal"; Buildings.Controls.OBC.CDL.Interfaces.BooleanInput trigger "Resets the controller output when trigger becomes true"; Buildings.Controls.OBC.CDL.Reals.Subtract controlError "Control error (set point - measurement)"; Buildings.Controls.OBC.CDL.Reals.Multiply P "Proportional action"; Buildings.Controls.OBC.CDL.Reals.IntegratorWithReset I( final k=1, final y_start=xi_start) if with_I "Integral term"; Buildings.Controls.OBC.CDL.Reals.Derivative D( final y_start=yd_start) if with_D "Derivative term"; Buildings.Controls.OBC.CDL.Reals.Subtract errP "P error"; Buildings.Controls.OBC.CDL.Reals.Subtract errD if with_D "D error"; Buildings.Controls.OBC.CDL.Reals.Subtract errI1 if with_I "I error (before anti-windup compensation)"; Buildings.Controls.OBC.CDL.Reals.Subtract errI2 if with_I "I error (after anti-windup compensation)"; Buildings.Controls.OBC.CDL.Reals.Limiter lim( final uMax=yMax, final uMin=yMin) "Limiter"; Buildings.Controls.OBC.CDL.Reals.Divide antWinGai2 if with_I "Outputs of anti-windup compensation"; Buildings.Controls.OBC.CDL.Reals.Divide gaiI if with_I "Gain of the integral term"; Buildings.Controls.OBC.CDL.Reals.Multiply errIWithGai if with_I "I error (after multiplying with the gain of the integral term)"; Buildings.Controls.OBC.CDL.Reals.Multiply mulkTd if with_D "Product of k and Td"; Buildings.Controls.OBC.CDL.Reals.GreaterThreshold greThrkTd( t=1E-6, h=1E-6/2) if with_D "Check if k*Td is larger than 0"; protected final parameter Real revAct= if reverseActing then 1 else -1 "Switch for sign for reverse or direct acting controller"; final parameter Boolean with_I=controllerType == Buildings.Controls.OBC.CDL.Types.SimpleController.PI or controllerType == Buildings.Controls.OBC.CDL.Types.SimpleController.PID "Boolean flag to enable integral action"; final parameter Boolean with_D=controllerType == Buildings.Controls.OBC.CDL.Types.SimpleController.PD or controllerType == Buildings.Controls.OBC.CDL.Types.SimpleController.PID "Boolean flag to enable derivative action"; Buildings.Controls.OBC.CDL.Reals.Sources.Constant Dzero( final k=0) if not with_D "Zero input signal"; Buildings.Controls.OBC.CDL.Reals.Sources.Constant Izero( final k=0) if not with_I "Zero input signal"; Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter uS_revAct( final k=revAct/r) "Set point multiplied by reverse action sign"; Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter uMea_revAct( final k=revAct/r) "Set point multiplied by reverse action sign"; Buildings.Controls.OBC.CDL.Reals.Add addPD "Outputs P and D gains added"; Buildings.Controls.OBC.CDL.Reals.Add addPID "Outputs P, I and D gains added"; Buildings.Controls.OBC.CDL.Reals.Subtract antWinErr if with_I "Error for anti-windup compensation"; Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter antWinGai1(k=1/Ni) if with_I "Gain for anti-windup compensation without the proportional gain"; Buildings.Controls.OBC.CDL.Reals.Sources.Constant yResSig( final k=y_reset) if with_I "Signal for y_reset"; Buildings.Controls.OBC.CDL.Reals.Subtract addRes if with_I "Adder for integrator reset"; Buildings.Controls.OBC.CDL.Logical.Sources.Constant cheYMinMax( final k=yMin < yMax) "Check for values of yMin and yMax"; Buildings.Controls.OBC.CDL.Utilities.Assert assMesYMinMax( message="LimPID: Limits must be yMin < yMax") "Assertion on yMin and yMax"; Buildings.Controls.OBC.CDL.Utilities.Assert assMeskTd( message="LimPIDWithInputGains: Limits must be k*Td > 0") if with_D "Assertion on k and Td"; Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gaiT(final k=1/Nd) if with_D "Gain to compute time constant for derivative action"; equation connect(trigger,I.trigger); connect(u_s,uS_revAct.u); connect(u_m,uMea_revAct.u); connect(errD.u2,uMea_revAct.y); connect(D.u,errD.y); connect(errI1.u1,uS_revAct.y); connect(addPID.u1,addPD.y); connect(lim.y,y); connect(antWinErr.y, antWinGai1.u); connect(addPD.u2,Dzero.y); connect(D.y,addPD.u2); connect(addPID.u2,I.y); connect(addRes.y,I.y_reset_in); connect(antWinErr.u2,lim.y); connect(errI1.y,errI2.u1); connect(controlError.u1,u_s); connect(cheYMinMax.y,assMesYMinMax.u); connect(Izero.y,addPID.u2); connect(errP.u1,uS_revAct.y); connect(errD.u1,uS_revAct.y); connect(addPD.u1, P.y); connect(addPID.y, lim.u); connect(addPID.y, antWinErr.u1); connect(addRes.u1, yResSig.y); connect(u_m, controlError.u2); connect(uMea_revAct.y, errP.u2); connect(uMea_revAct.y, errI1.u2); connect(addPD.y, addRes.u2); connect(errP.y, P.u2); connect(P.u1, k); connect(antWinGai1.y, antWinGai2.u1); connect(antWinGai2.u2, k); connect(antWinGai2.y, errI2.u2); connect(gaiI.u1, k); connect(gaiI.u2, Ti); connect(gaiI.y, errIWithGai.u1); connect(errI2.y, errIWithGai.u2); connect(errIWithGai.y, I.u); connect(mulkTd.u1, k); connect(greThrkTd.y, assMeskTd.u); connect(mulkTd.y, greThrkTd.u); connect(mulkTd.u2, Td); connect(Td, gaiT.u); connect(gaiT.y, D.T); connect(mulkTd.y, D.k); end PIDWithInputGains;