diff --git a/Buildings/Controls/OBC/ASHRAE/FanCoilUnit/Controller.mo b/Buildings/Controls/OBC/ASHRAE/FanCoilUnit/Controller.mo
new file mode 100644
index 00000000000..9dcfa1b17e8
--- /dev/null
+++ b/Buildings/Controls/OBC/ASHRAE/FanCoilUnit/Controller.mo
@@ -0,0 +1,1217 @@
+within Buildings.Controls.OBC.ASHRAE.FanCoilUnit;
+block Controller
+ "Fan coil unit controller that comprises subsequences for controlling fan speed and supply air temperature"
+
+ parameter Boolean have_cooCoi
+ "Does the fan coil unit have a cooling coil? True: Yes, False: No";
+
+ parameter Boolean have_hotWatCoi
+ "Does the fan coil unit have a hot-water heating coil? True: Yes, False: No";
+
+ parameter Boolean have_eleHeaCoi
+ "Does the fan coil unit have an electric heating coil? True: Yes, False: No";
+
+ parameter Boolean have_winSen
+ "Check if the zone has window status sensor";
+
+ parameter Boolean have_occSen
+ "Set to true if zones have occupancy sensor";
+
+ parameter Real heaDea(
+ final unit="1",
+ displayUnit="1")=0.05
+ "Heating loop signal limit above which controller operation changes from deadband mode to heating mode";
+
+ parameter Real cooDea(
+ final unit="1",
+ displayUnit="1")=0.05
+ "Cooling loop signal limit above which controller operation changes from deadband mode to cooling mode";
+
+ parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerTypeCoo=
+ Buildings.Controls.OBC.CDL.Types.SimpleController.PI
+ "Type of cooling loop signal controller"
+ annotation (Dialog(tab="PID parameters", group="Cooling loop control"));
+
+ parameter Real kCoo(final unit="1/K") = 0.1
+ "Gain for cooling control loop signal"
+ annotation(Dialog(tab="PID parameters", group="Cooling loop control"));
+
+ parameter Real TiCoo(
+ final unit="s",
+ final quantity="Time")=900
+ "Time constant of integrator block for cooling control loop signal"
+ annotation(Dialog(tab="PID parameters", group="Cooling loop control",
+ enable=controllerTypeCoo == Buildings.Controls.OBC.CDL.Types.SimpleController.PI
+ or controllerTypeCoo == Buildings.Controls.OBC.CDL.Types.SimpleController.PID));
+
+ parameter Real TdCoo(
+ final unit="s",
+ final quantity="Time")=0.1
+ "Time constant of derivative block for cooling control loop signal"
+ annotation (Dialog(tab="PID parameters", group="Cooling loop control",
+ enable=controllerTypeCoo == Buildings.Controls.OBC.CDL.Types.SimpleController.PD
+ or controllerTypeCoo == Buildings.Controls.OBC.CDL.Types.SimpleController.PID));
+
+ parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerTypeHea=
+ Buildings.Controls.OBC.CDL.Types.SimpleController.PI
+ "Type of heating loop signal controller"
+ annotation(Dialog(tab="PID parameters", group="Heating loop control"));
+
+ parameter Real kHea(final unit="1/K")=0.1
+ "Gain for heating control loop signal"
+ annotation(Dialog(tab="PID parameters", group="Heating loop control"));
+
+ parameter Real TiHea(
+ final unit="s",
+ final quantity="Time")=900
+ "Time constant of integrator block for heating control loop signal"
+ annotation(Dialog(tab="PID parameters", group="Heating loop control",
+ enable=controllerTypeHea == Buildings.Controls.OBC.CDL.Types.SimpleController.PI
+ or controllerTypeHea == Buildings.Controls.OBC.CDL.Types.SimpleController.PID));
+
+ parameter Real TdHea(
+ final unit="s",
+ final quantity="Time")=0.1
+ "Time constant of derivative block for heating control loop signal"
+ annotation (Dialog(tab="PID parameters", group="Heating loop control",
+ enable=controllerTypeHea == Buildings.Controls.OBC.CDL.Types.SimpleController.PD
+ or controllerTypeHea == Buildings.Controls.OBC.CDL.Types.SimpleController.PID));
+
+ parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerTypeCooCoi=
+ Buildings.Controls.OBC.CDL.Types.SimpleController.PI
+ "Type of cooling coil controller"
+ annotation(Dialog(tab="PID parameters", group="Cooling coil control"));
+
+ parameter Real kCooCoi(final unit="1/K")=0.1
+ "Gain for cooling coil control signal"
+ annotation(Dialog(tab="PID parameters", group="Cooling coil control"));
+
+ parameter Real TiCooCoi(
+ final unit="s",
+ final quantity="Time")=900
+ "Time constant of integrator block for cooling coil control signal"
+ annotation(Dialog(tab="PID parameters", group="Cooling coil control",
+ enable=controllerTypeCooCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PI
+ or controllerTypeCooCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PID));
+
+ parameter Real TdCooCoi(
+ final unit="s",
+ final quantity="Time")=0.1
+ "Time constant of derivative block for cooling coil control signal"
+ annotation (Dialog(tab="PID parameters", group="Cooling coil control",
+ enable=controllerTypeCooCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PD
+ or controllerTypeCooCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PID));
+
+ parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerTypeHeaCoi=
+ Buildings.Controls.OBC.CDL.Types.SimpleController.PI
+ "Type of heating coil controller"
+ annotation(Dialog(tab="PID parameters", group="Heating coil control"));
+
+ parameter Real kHeaCoi(
+ final unit="1/K")=0.1
+ "Gain for heating coil control signal"
+ annotation(Dialog(tab="PID parameters", group="Heating coil control"));
+
+ parameter Real TiHeaCoi(
+ final unit="s",
+ final quantity="Time")=900
+ "Time constant of integrator block for heating coil control signal"
+ annotation(Dialog(tab="PID parameters", group="Heating coil control",
+ enable=controllerTypeCooCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PI
+ or controllerTypeCooCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PID));
+
+ parameter Real TdHeaCoi(
+ final unit="s",
+ final quantity="Time")=0.1
+ "Time constant of derivative block for heatinging coil control signal"
+ annotation (Dialog(tab="PID parameters", group="Heating coil control",
+ enable=controllerTypeCooCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PD
+ or controllerTypeCooCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PID));
+
+ parameter Real uCooFan_min(
+ final min=0,
+ final max=1,
+ final unit="1")=0.5
+ "Cooling loop signal limit at which supply air temperature is at minimum and fan speed starts to be modified"
+ annotation (Dialog(tab="Supply air setpoints"));
+
+ parameter Real uHeaFan_min(
+ final min=0,
+ final max=1,
+ final unit="1")=0.5
+ "Heating loop signal limit at which supply air temperature is at maximum and fan speed starts to be modified"
+ annotation (Dialog(tab="Supply air setpoints"));
+
+ parameter Real TSupSet_max(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")
+ "Maximum supply air temperature for heating"
+ annotation (Dialog(tab="Supply air setpoints",group="Temperature limits"));
+
+ parameter Real TSupSet_min(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")
+ "Minimum supply air temperature for cooling"
+ annotation (Dialog(tab="Supply air setpoints",group="Temperature limits"));
+
+ parameter Real deaSpe(
+ final unit="1",
+ displayUnit="1")=0.1
+ "Deadband mode fan speed"
+ annotation (Dialog(tab="Supply air setpoints",group="Fan speed"));
+
+ parameter Real uHeaFan_max(
+ final min=0,
+ final max=1,
+ final unit="1")=1
+ "Maximum heating loop signal at which fan speed is modified"
+ annotation (Dialog(tab="Supply air setpoints",group="Fan speed - Heating"));
+
+ parameter Real heaSpe_max(
+ final min=0,
+ final max=1,
+ final unit="1")
+ "Maximum fan speed for heating"
+ annotation (Dialog(tab="Supply air setpoints",group="Fan speed - Heating"));
+
+ parameter Real heaSpe_min(
+ final min=0,
+ final max=1,
+ final unit="1")
+ "Minimum fan speed for heating"
+ annotation (Dialog(tab="Supply air setpoints",group="Fan speed - Heating"));
+
+ parameter Real uCooFan_max(
+ final min=0,
+ final max=1,
+ final unit="1")=1
+ "Maximum cooling loop signal at which fan speed is modified"
+ annotation (Dialog(tab="Supply air setpoints",group="Fan speed - Cooling"));
+
+ parameter Real cooSpe_max(
+ final min=0,
+ final max=1,
+ final unit="1") = 1
+ "Maximum fan speed for cooling"
+ annotation (Dialog(tab="Supply air setpoints",group="Fan speed - Cooling"));
+
+ parameter Real cooSpe_min(
+ final min=0,
+ final max=1,
+ final unit="1")
+ "Minimum fan speed for cooling"
+ annotation (Dialog(tab="Supply air setpoints",group="Fan speed - Cooling"));
+
+ parameter Boolean have_locAdj=false
+ "Flag, set to true if both cooling and heating setpoint are adjustable through a single common knob"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="General"));
+
+ parameter Boolean sepAdj=false
+ "True: cooling and heating setpoint can be adjusted separately"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="General"));
+
+ parameter Boolean ignDemLim=false
+ "Flag, set to true to exempt individual zone from demand limit setpoint adjustment"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="General"));
+
+ parameter Real bouLim=1
+ "Threshold of temperature difference for indicating the end of setback or setup mode"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="Advanced"));
+
+ parameter Real TActCoo_max(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")=300.15
+ "Maximum cooling setpoint during on"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="Limits"));
+
+ parameter Real TActCoo_min(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")=295.15
+ "Minimum cooling setpoint during on"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="Limits"));
+
+ parameter Real TActHea_max(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")=295.15
+ "Maximum heating setpoint during on"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="Limits"));
+
+ parameter Real TActHea_min(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")=291.15
+ "Minimum heating setpoint during on"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="Limits"));
+
+ parameter Real TWinOpeCooSet(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")=322.15
+ "Cooling setpoint when window is open"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="Limits"));
+
+ parameter Real TWinOpeHeaSet(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")=277.15
+ "Heating setpoint when window is open"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="Limits"));
+
+ parameter Real incTSetDem_1(
+ final unit="K",
+ displayUnit="K",
+ final quantity="TemperatureDifference")=0.56
+ "Cooling setpoint increase value (degC) when cooling demand limit level 1 is imposed"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="Demand control adjustment"));
+
+ parameter Real incTSetDem_2(
+ final unit="K",
+ displayUnit="K",
+ final quantity="TemperatureDifference")=1.1
+ "Cooling setpoint increase value (degC) when cooling demand limit level 2 is imposed"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="Demand control adjustment"));
+
+ parameter Real incTSetDem_3(
+ final unit="K",
+ displayUnit="K",
+ final quantity="TemperatureDifference")=2.2
+ "Cooling setpoint increase value (degC) when cooling demand limit level 3 is imposed"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="Demand control adjustment"));
+
+ parameter Real decTSetDem_1(
+ final unit="K",
+ displayUnit="K",
+ final quantity="TemperatureDifference")=0.56
+ "Heating setpoint decrease value (degC) when heating demand limit level 1 is imposed"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="Demand control adjustment"));
+
+ parameter Real decTSetDem_2(
+ final unit="K",
+ displayUnit="K",
+ final quantity="TemperatureDifference")=1.1
+ "Heating setpoint decrease value (degC) when heating demand limit level 2 is imposed"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="Demand control adjustment"));
+
+ parameter Real decTSetDem_3(
+ final unit="K",
+ displayUnit="K",
+ final quantity="TemperatureDifference")=2.2
+ "Heating setpoint decrease value (degC) when heating demand limit level 3 is imposed"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="Demand control adjustment"));
+
+ parameter Real chiWatPlaReqLim0(
+ final unit = "1",
+ displayUnit="1")=0.1
+ "Valve position limit below which zero chilled water plant requests are sent when one request was previously being sent"
+ annotation(Dialog(tab="Request limits", group="Chilled water requests", enable=have_cooCoi));
+
+ parameter Real chiWatResReqLim0(
+ final unit = "1",
+ displayUnit="1")=0.85
+ "Valve position limit below which zero chilled water reset requests are sent when one request was previously being sent"
+ annotation(Dialog(tab="Request limits", group="Chilled water requests", enable=have_cooCoi));
+
+ parameter Real chiWatPlaReqLim1(
+ final unit = "1",
+ displayUnit="1")=0.95
+ "Valve position limit above which one chilled water plant request is sent"
+ annotation(Dialog(tab="Request limits", group="Chilled water requests", enable=have_cooCoi));
+
+ parameter Real chiWatResReqLim2(
+ final unit="K",
+ displayUnit="K",
+ final quantity="TemperatureDifference")=2.78
+ "Temperature difference limit between setpoint and supply air temperature above which two chilled water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Chilled water requests", enable=have_cooCoi));
+
+ parameter Real chiWatResReqTimLim2(
+ final unit="s",
+ displayUnit="s",
+ final quantity="Time")=300
+ "Time period for which chiWatResReqLim2 has to be exceeded before two chilled water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Chilled water requests", enable=have_cooCoi));
+
+ parameter Real chiWatResReqLim3(
+ final unit="K",
+ displayUnit="K",
+ final quantity="TemperatureDifference")=5.56
+ "Temperature difference limit between setpoint and supply air temperature above which three chilled water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Chilled water requests", enable=have_cooCoi));
+
+ parameter Real chiWatResReqTimLim3(
+ final unit="s",
+ displayUnit="s",
+ final quantity="Time")=300
+ "Time period for which chiWatResReqLim3 has to be exceeded before three chilled water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Chilled water requests", enable=have_cooCoi));
+
+ parameter Real hotWatPlaReqLim0(
+ final unit = "1",
+ displayUnit="1")=0.1
+ "Valve position limit below which zero hot water plant requests are sent when one request was previously being sent"
+ annotation(Dialog(tab="Request limits", group="Hot water requests", enable=have_hotWatCoi));
+
+ parameter Real hotWatResReqLim0(
+ final unit = "1",
+ displayUnit="1")=0.85
+ "Valve position limit below which zero hot water reset requests are sent when one request was previously being sent"
+ annotation(Dialog(tab="Request limits", group="Hot water requests", enable=have_hotWatCoi));
+
+ parameter Real hotWatPlaReqLim1(
+ final unit = "1",
+ displayUnit="1")=0.95
+ "Valve position limit above which one hot water plant request is sent"
+ annotation(Dialog(tab="Request limits", group="Hot water requests", enable=have_hotWatCoi));
+
+ parameter Real hotWatResReqLim2(
+ final unit="K",
+ displayUnit="K",
+ final quantity="TemperatureDifference")=8
+ "Temperature difference limit between setpoint and supply air temperature above which two hot water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Hot water requests", enable=have_hotWatCoi));
+
+ parameter Real hotWatResReqTimLim2(
+ final unit="s",
+ displayUnit="s",
+ final quantity="Time")=300
+ "Time period for which hotWatResReqLim2 has to be exceeded before two hot water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Hot water requests", enable=have_hotWatCoi));
+
+ parameter Real hotWatResReqLim3(
+ final unit="K",
+ displayUnit="K",
+ final quantity="TemperatureDifference")=17
+ "Temperature difference limit between setpoint and supply air temperature above which three hot water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Hot water requests", enable=have_hotWatCoi));
+
+ parameter Real hotWatResReqTimLim3(
+ final unit="s",
+ displayUnit="s",
+ final quantity="Time")=300
+ "Time period for which hotWatResReqLim3 has to be exceeded before three hot water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Hot water requests", enable=have_hotWatCoi));
+
+ parameter Real uLow(
+ final unit="1",
+ displayUnit="1")=-0.1
+ "Lower limit of the hysteresis for checking temperature difference"
+ annotation (Dialog(tab="Advanced"));
+
+ parameter Real uHigh(
+ final unit="1",
+ displayUnit="1")=0.1
+ "Higher limit of the hysteresis for checking temperature difference"
+ annotation (Dialog(tab="Advanced"));
+
+ parameter Real deaHysLim(
+ final unit="1",
+ displayUnit="1")=0.01
+ "Hysteresis limits for cooling and heating loop signals for deadband mode transitions"
+ annotation (Dialog(tab="Advanced"));
+
+ parameter Real preWarCooTim(
+ final unit="s",
+ displayUnit="s",
+ final quantity="Time")=10800
+ "Maximum cool-down or warm-up time"
+ annotation(Dialog(tab="Advanced", group="Operation mode"));
+
+ parameter Real Thys(
+ final unit="1",
+ displayUnit="1")=0.1
+ "Hysteresis for checking temperature difference"
+ annotation(Dialog(tab="Advanced"));
+
+ parameter Real posHys(
+ final unit="1",
+ displayUnit="1")=0.05
+ "Hysteresis for checking valve position difference"
+ annotation(Dialog(tab="Advanced"));
+
+ parameter Real dFanSpe(
+ final unit="1",
+ displayUnit="1")=0.05
+ "Fan speed hysteresis difference"
+ annotation(Dialog(tab="Advanced"));
+
+ Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Occ
+ "Current occupancy period, true if it is in occupant period"
+ annotation (Placement(transformation(extent={{-260,50},{-220,90}}),
+ iconTransformation(extent={{-240,140},{-200,180}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Win if have_winSen
+ "Window status, true if open, false if closed"
+ annotation (Placement(transformation(extent={{-260,-320},{-220,-280}}),
+ iconTransformation(extent={{-240,-300},{-200,-260}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Fan
+ "Fan proven on signal"
+ annotation (Placement(transformation(extent={{-260,-290},{-220,-250}}),
+ iconTransformation(extent={{-240,-260},{-200,-220}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.IntegerInput uCooDemLimLev
+ "Cooling demand limit level"
+ annotation (Placement(transformation(extent={{-260,20},{-220,60}}),
+ iconTransformation(extent={{-240,100},{-200,140}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.IntegerInput uHeaDemLimLev
+ "Heating demand limit level"
+ annotation (Placement(transformation(extent={{-260,-10},{-220,30}}),
+ iconTransformation(extent={{-240,60},{-200,100}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.IntegerInput nOcc if have_occSen
+ "Number of occupants"
+ annotation (Placement(transformation(extent={{-260,-260},{-220,-220}}),
+ iconTransformation(extent={{-240,-220},{-200,-180}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput warUpTim(
+ final unit="s",
+ displayUnit="min",
+ final quantity="Time")
+ "Warm-up time retrieved from optimal warm-up block"
+ annotation (Placement(transformation(extent={{-260,170},{-220,210}}),
+ iconTransformation(extent={{-240,340},{-200,380}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput cooDowTim(
+ final unit="s",
+ displayUnit="min",
+ final quantity="Time")
+ "Cool-down time retrieved from optimal cool-down block"
+ annotation (Placement(transformation(extent={{-260,200},{-220,240}}),
+ iconTransformation(extent={{-240,300},{-200,340}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput tNexOcc(
+ final unit="s",
+ displayUnit="min",
+ final quantity="Time") "Time to next occupied period"
+ annotation (Placement(transformation(extent={{-260,140},{-220,180}}),
+ iconTransformation(extent={{-240,260},{-200,300}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput TZon(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature") "Measured zone temperatures"
+ annotation (Placement(transformation(extent={{-260,-70},{-220,-30}}),
+ iconTransformation(extent={{-240,-20},{-200,20}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput TSup(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")
+ "Measured supply air temperature"
+ annotation (Placement(transformation(extent={{-260,-40},{-220,0}}),
+ iconTransformation(extent={{-240,20},{-200,60}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput cooSetAdj(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="TemperatureDifference") if cooAdj or have_locAdj
+ "Cooling setpoint adjustment value"
+ annotation (Placement(transformation(extent={{-260,110},{-220,150}}),
+ iconTransformation(extent={{-240,220},{-200,260}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput heaSetAdj(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="TemperatureDifference") if heaAdj
+ "Heating setpoint adjustment value"
+ annotation (Placement(transformation(extent={{-260,80},{-220,120}}),
+ iconTransformation(extent={{-240,180},{-200,220}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput uHeaCoi(
+ final unit="1",
+ displayUnit="1") if have_hotWatCoi
+ "Measured heating coil control action"
+ annotation (Placement(transformation(extent={{-260,-360},{-220,-320}}),
+ iconTransformation(extent={{-240,-340},{-200,-300}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput uCooCoi(
+ final unit="1",
+ displayUnit="1") if have_cooCoi
+ "Measured cooling coil control action"
+ annotation (Placement(transformation(extent={{-260,-400},{-220,-360}}),
+ iconTransformation(extent={{-240,-380},{-200,-340}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput TOccHeaSet(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")
+ "Occupied heating setpoint temperature"
+ annotation (Placement(transformation(extent={{-260,-100},{-220,-60}}),
+ iconTransformation(extent={{-240,-60},{-200,-20}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput TOccCooSet(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")
+ "Occupied cooling setpoint temperature"
+ annotation (Placement(transformation(extent={{-260,-140},{-220,-100}}),
+ iconTransformation(extent={{-240,-100},{-200,-60}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput TUnoHeaSet(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")
+ "Unoccupied heating setpoint temperature"
+ annotation (Placement(transformation(extent={{-260,-180},{-220,-140}}),
+ iconTransformation(extent={{-240,-140},{-200,-100}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput TUnoCooSet(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")
+ "Unoccupied cooling setpoint temperature"
+ annotation (Placement(transformation(extent={{-260,-220},{-220,-180}}),
+ iconTransformation(extent={{-240,-180},{-200,-140}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1Fan
+ "Fan command on status"
+ annotation (Placement(transformation(extent={{200,180},{240,220}}),
+ iconTransformation(extent={{200,180},{240,220}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput yChiWatResReq if have_cooCoi
+ "Chilled water reset request"
+ annotation (Placement(transformation(extent={{200,-120},{240,-80}}),
+ iconTransformation(extent={{200,-100},{240,-60}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput yChiPlaReq if have_cooCoi
+ "Chiller plant requests"
+ annotation (Placement(transformation(extent={{200,-160},{240,-120}}),
+ iconTransformation(extent={{200,-140},{240,-100}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput yHotWatResReq if have_hotWatCoi
+ "Hot water reset requests"
+ annotation (Placement(transformation(extent={{200,-200},{240,-160}}),
+ iconTransformation(extent={{200,-180},{240,-140}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput yHotWatPlaReq if have_hotWatCoi
+ "Hot water plant requests"
+ annotation (Placement(transformation(extent={{200,-240},{240,-200}}),
+ iconTransformation(extent={{200,-220},{240,-180}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealOutput TSupSet(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")
+ "Supply air temperature setpoint"
+ annotation (Placement(transformation(extent={{200,-40},{240,0}}),
+ iconTransformation(extent={{200,-60},{240,-20}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealOutput yFan(
+ final min=0,
+ final max=1,
+ final unit="1")
+ "Fan command speed"
+ annotation (Placement(transformation(extent={{200,140},{240,180}}),
+ iconTransformation(extent={{200,140},{240,180}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealOutput TZonHeaSet(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")
+ "Heating setpoint temperature"
+ annotation (Placement(transformation(extent={{200,100},{240,140}}),
+ iconTransformation(extent={{200,100},{240,140}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealOutput TZonCooSet(
+ final unit="K",
+ displayUnit="degC",
+ final quantity="ThermodynamicTemperature")
+ "Cooling setpoint temperature"
+ annotation (Placement(transformation(extent={{200,60},{240,100}}),
+ iconTransformation(extent={{200,60},{240,100}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealOutput yCooCoi(
+ final min=0,
+ final max=1,
+ final unit="1") if have_cooCoi
+ "Cooling coil control signal"
+ annotation (Placement(transformation(extent={{200,-80},{240,-40}}),
+ iconTransformation(extent={{200,-20},{240,20}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealOutput yHeaCoi(
+ final min=0,
+ final max=1,
+ final unit="1") if have_heaCoi
+ "Heating coil control signal"
+ annotation (Placement(transformation(extent={{200,0},{240,40}}),
+ iconTransformation(extent={{200,20},{240,60}})));
+
+ Buildings.Controls.OBC.ASHRAE.G36.AHUs.SingleZone.VAV.SetPoints.ModeAndSetPoints
+ modSetPoi(
+ final have_winSen=have_winSen,
+ final have_occSen=have_occSen,
+ final sepAdj=sepAdj,
+ final TActCoo_max=TActCoo_max,
+ final TActCoo_min=TActCoo_min,
+ final TActHea_max=TActHea_max,
+ final TActHea_min=TActHea_min,
+ final TWinOpeCooSet=TWinOpeCooSet,
+ final TWinOpeHeaSet=TWinOpeHeaSet,
+ final have_locAdj=have_locAdj,
+ final ignDemLim=ignDemLim,
+ final incTSetDem_1=incTSetDem_1,
+ final incTSetDem_2=incTSetDem_2,
+ final incTSetDem_3=incTSetDem_3,
+ final decTSetDem_1=decTSetDem_1,
+ final decTSetDem_2=decTSetDem_2,
+ final decTSetDem_3=decTSetDem_3,
+ final bouLim=bouLim,
+ final uLow=uLow,
+ final uHigh=uHigh,
+ final preWarCooTim=preWarCooTim)
+ "Zone setpoint and operation mode"
+ annotation (Placement(transformation(extent={{-140,150},{-120,190}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.PIDWithReset cooPI(
+ final reverseActing=false,
+ final controllerType=controllerTypeCoo,
+ final k=kCoo,
+ final Ti=TiCoo,
+ final Td=TdCoo)
+ "Zone cooling control signal"
+ annotation (Placement(transformation(extent={{-40,156},{-20,176}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.PIDWithReset heaPI(
+ final controllerType=controllerTypeHea,
+ final k=kHea,
+ final Ti=TiHea,
+ final Td=TdHea)
+ "Zone heating control signal"
+ annotation (Placement(transformation(extent={{-80,210},{-60,230}})));
+
+protected
+ final parameter Boolean have_heaCoi = have_hotWatCoi or have_eleHeaCoi
+ "Does the fan coil unit have a heating coil?";
+
+ final parameter Boolean cooAdj=sepAdj
+ "Flag, set to true if both cooling and heating setpoint are adjustable separately"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="General"));
+
+ final parameter Boolean heaAdj=sepAdj
+ "Flag, set to true if heating setpoint is adjustable"
+ annotation (Dialog(tab="Adjust temperature setpoint", group="General"));
+
+ Buildings.Controls.OBC.ASHRAE.FanCoilUnit.Subsequences.PlantRequests fcuPlaReq(
+ final have_hotWatCoi=have_hotWatCoi,
+ final have_chiWatCoi=have_cooCoi,
+ final cooSpe_max=cooSpe_max,
+ final heaSpe_max=heaSpe_max,
+ final chiWatPlaReqLim0=chiWatPlaReqLim0,
+ final chiWatResReqLim0=chiWatResReqLim0,
+ final chiWatPlaReqLim1=chiWatPlaReqLim1,
+ final chiWatResReqLim2=chiWatResReqLim2,
+ final chiWatResReqTimLim2=chiWatResReqTimLim2,
+ final chiWatResReqLim3=chiWatResReqLim3,
+ final chiWatResReqTimLim3=chiWatResReqTimLim3,
+ final hotWatPlaReqLim0=hotWatPlaReqLim0,
+ final hotWatResReqLim0=hotWatResReqLim0,
+ final hotWatPlaReqLim1=hotWatPlaReqLim1,
+ final hotWatResReqLim2=hotWatResReqLim2,
+ final hotWatResReqTimLim2=hotWatResReqTimLim2,
+ final hotWatResReqLim3=hotWatResReqLim3,
+ final hotWatResReqTimLim3=hotWatResReqTimLim3,
+ final Thys=Thys,
+ final posHys=posHys,
+ final dFanSpe=dFanSpe) if have_cooCoi or have_hotWatCoi
+ "Block for generating chilled water requests and hot water requests for their respective plants"
+ annotation (Placement(transformation(extent={{100,-100},{120,-80}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Sources.Constant unOccMod(
+ final k=Buildings.Controls.OBC.ASHRAE.G36.Types.OperationModes.unoccupied)
+ "Unoccupied mode"
+ annotation (Placement(transformation(extent={{-160,-330},{-140,-310}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Equal isUnOcc
+ "Check if current operation mode is unoccupied mode"
+ annotation (Placement(transformation(extent={{-100,-330},{-80,-310}})));
+
+ Buildings.Controls.OBC.CDL.Logical.Not isOcc
+ "If in unoccupied mode, switch off"
+ annotation (Placement(transformation(extent={{-70,-330},{-50,-310}})));
+
+ Buildings.Controls.OBC.CDL.Logical.Sources.Constant win(
+ final k=false) if not have_winSen
+ "Window status"
+ annotation (Placement(transformation(extent={{-198,-230},{-178,-210}})));
+
+ Buildings.Controls.OBC.CDL.Integers.GreaterEqualThreshold havOcc(
+ final t=1) if have_occSen
+ "Check if there is occupant"
+ annotation (Placement(transformation(extent={{-100,50},{-80,70}})));
+
+ Buildings.Controls.OBC.ASHRAE.FanCoilUnit.Subsequences.SupplyAirTemperature TSupAir(
+ final have_cooCoi=have_cooCoi,
+ final have_heaCoi=have_heaCoi,
+ final TSupSet_max=TSupSet_max,
+ final uHea_max=uHeaFan_min,
+ final TSupSet_min=TSupSet_min,
+ final uCoo_max=uCooFan_min,
+ final heaDea=heaDea,
+ final cooDea=cooDea,
+ final controllerTypeCooCoi=controllerTypeCooCoi,
+ final kCooCoi=kCooCoi,
+ final TiCooCoi=TiCooCoi,
+ final TdCooCoi=TdCooCoi,
+ final controllerTypeHeaCoi=controllerTypeHeaCoi,
+ final kHeaCoi=kHeaCoi,
+ final TiHeaCoi=TiHeaCoi,
+ final TdHeaCoi=TdHeaCoi,
+ final deaHysLim=deaHysLim)
+ "Supply air temperature setpoint controller"
+ annotation (Placement(transformation(extent={{102,0},{122,24}})));
+
+ Buildings.Controls.OBC.ASHRAE.FanCoilUnit.Subsequences.FanSpeed fanSpe(
+ final have_cooCoi=have_cooCoi,
+ final have_heaCoi=have_heaCoi,
+ final deaSpe=deaSpe,
+ final heaSpe_min=heaSpe_min,
+ final uHea_min=uHeaFan_min,
+ final heaSpe_max=heaSpe_max,
+ final uHea_max=uHeaFan_max,
+ final cooSpe_min=cooSpe_min,
+ final uCoo_min=uCooFan_min,
+ final cooSpe_max=cooSpe_max,
+ final uCoo_max=uCooFan_max,
+ final heaDea=heaDea,
+ final cooDea=cooDea,
+ final deaHysLim=deaHysLim)
+ "Fan speed controller"
+ annotation (Placement(transformation(extent={{120,170},{140,190}})));
+
+equation
+ assert((not (have_hotWatCoi and have_eleHeaCoi)), "One of have_hotWatCoi and have_eleHeaCoi has to be set to false");
+
+ connect(unOccMod.y, isUnOcc.u2) annotation (Line(points={{-138,-320},{-120,-320},
+ {-120,-328},{-102,-328}}, color={255,127,0}));
+
+ connect(isUnOcc.y, isOcc.u)
+ annotation (Line(points={{-78,-320},{-72,-320}}, color={255,0,255}));
+
+ connect(TZon, cooPI.u_m) annotation (Line(points={{-240,-50},{-30,-50},{-30,154}},
+ color={0,0,127}));
+
+ connect(isOcc.y, heaPI.trigger) annotation (Line(points={{-48,-320},{-36,-320},
+ {-36,84},{-76,84},{-76,208}}, color={255,0,255}));
+
+ connect(isOcc.y, cooPI.trigger) annotation (Line(points={{-48,-320},{-36,-320},
+ {-36,154}}, color={255,0,255}));
+
+ connect(TZon, heaPI.u_m) annotation (Line(points={{-240,-50},{-70,-50},{-70,208}},
+ color={0,0,127}));
+
+ connect(modSetPoi.THeaSet, heaPI.u_s) annotation (Line(points={{-118,162},{-100,
+ 162},{-100,220},{-82,220}}, color={0,0,127}));
+
+ connect(modSetPoi.THeaSet, TZonHeaSet) annotation (Line(points={{-118,162},{-54,
+ 162},{-54,120},{220,120}}, color={0,0,127}));
+
+ connect(modSetPoi.TCooSet, cooPI.u_s) annotation (Line(points={{-118,170},{-50,
+ 170},{-50,166},{-42,166}},
+ color={0,0,127}));
+
+ connect(modSetPoi.TCooSet, TZonCooSet) annotation (Line(points={{-118,170},{-50,
+ 170},{-50,80},{220,80}}, color={0,0,127}));
+
+ connect(TZon, modSetPoi.TZon) annotation (Line(points={{-240,-50},{-188,-50},{
+ -188,180},{-142,180}}, color={0,0,127}));
+
+ connect(tNexOcc, modSetPoi.tNexOcc) annotation (Line(points={{-240,160},{-216,
+ 160},{-216,166},{-142,166}},
+ color={0,0,127}));
+
+ connect(u1Occ, modSetPoi.u1Occ) annotation (Line(points={{-240,70},{-194,70},{-194,
+ 168},{-142,168}}, color={255,0,255}));
+
+ connect(modSetPoi.yOpeMod, isUnOcc.u1) annotation (Line(points={{-118,178},{-110,
+ 178},{-110,-320},{-102,-320}}, color={255,127,0}));
+
+ connect(win.y, modSetPoi.u1Win) annotation (Line(points={{-176,-220},{-150,-220},
+ {-150,183},{-142,183}}, color={255,0,255}));
+
+ connect(u1Win, modSetPoi.u1Win) annotation (Line(points={{-240,-300},{-158,-300},
+ {-158,183},{-142,183}}, color={255,0,255}));
+
+ connect(havOcc.y, modSetPoi.u1OccSen) annotation (Line(points={{-78,60},{-60,60},
+ {-60,112},{-180,112},{-180,156},{-142,156}}, color={255,0,255}));
+
+ connect(modSetPoi.warUpTim, warUpTim) annotation (Line(points={{-142,186},{-200,
+ 186},{-200,190},{-240,190}}, color={0,0,127}));
+
+ connect(modSetPoi.cooDowTim, cooDowTim) annotation (Line(points={{-142,188},{-194,
+ 188},{-194,220},{-240,220}}, color={0,0,127}));
+
+ connect(modSetPoi.uCooDemLimLev, uCooDemLimLev) annotation (Line(points={{-142,
+ 154},{-182,154},{-182,40},{-240,40}}, color={255,127,0}));
+
+ connect(modSetPoi.uHeaDemLimLev, uHeaDemLimLev) annotation (Line(points={{-142,
+ 152},{-176,152},{-176,10},{-240,10}}, color={255,127,0}));
+
+ connect(TSupAir.yCooCoi, yCooCoi) annotation (Line(points={{124,6},{160,6},{160,
+ -60},{220,-60}}, color={0,0,127}));
+
+ connect(TSupAir.yHeaCoi, yHeaCoi) annotation (Line(points={{124,18},{160,18},{
+ 160,20},{220,20}}, color={0,0,127}));
+
+ connect(TSupAir.TSupSet, TSupSet) annotation (Line(points={{124,12},{180,12},
+ {180,-20},{220,-20}}, color={0,0,127}));
+
+ connect(fanSpe.yFan, yFan) annotation (Line(points={{142,178},{160,178},{160,160},
+ {220,160}}, color={0,0,127}));
+
+ connect(fanSpe.y1Fan, y1Fan) annotation (Line(points={{142,182},{160,182},{160,200},
+ {220,200}}, color={255,0,255}));
+
+ connect(modSetPoi.yOpeMod, fanSpe.opeMod) annotation (Line(points={{-118,178},
+ {-60,178},{-60,186},{118,186}}, color={255,127,0}));
+
+ connect(TSup, TSupAir.TAirSup) annotation (Line(points={{-240,-20},{-80,-20},{
+ -80,10},{100,10}},
+ color={0,0,127}));
+
+ connect(u1Fan, fanSpe.u1FanPro) annotation (Line(points={{-240,-270},{8,-270},
+ {8,182},{118,182}}, color={255,0,255}));
+
+ connect(heaPI.y, fanSpe.uHea) annotation (Line(points={{-58,220},{0,220},{0,178},
+ {118,178}}, color={0,0,127}));
+
+ connect(cooPI.y, fanSpe.uCoo) annotation (Line(points={{-18,166},{20,166},{20,
+ 174},{118,174}}, color={0,0,127}));
+
+ connect(modSetPoi.TCooSet,TSupAir.TZonCooSet) annotation (Line(points={{-118,
+ 170},{-50,170},{-50,2},{100,2}}, color={0,0,127}));
+
+ connect(modSetPoi.THeaSet,TSupAir.TZonHeaSet) annotation (Line(points={{-118,
+ 162},{-54,162},{-54,18},{100,18}}, color={0,0,127}));
+
+ connect(cooPI.y, TSupAir.uCoo) annotation (Line(points={{-18,166},{20,166},{20,
+ 6},{100,6}}, color={0,0,127}));
+
+ connect(heaPI.y, TSupAir.uHea) annotation (Line(points={{-58,220},{0,220},{0,14},
+ {100,14}}, color={0,0,127}));
+
+ connect(TZonHeaSet, TZonHeaSet)
+ annotation (Line(points={{220,120},{220,120}}, color={0,0,127}));
+
+ connect(u1Fan, TSupAir.u1Fan) annotation (Line(points={{-240,-270},{8,-270},{8,22},
+ {100,22}}, color={255,0,255}));
+
+ connect(nOcc, havOcc.u) annotation (Line(points={{-240,-240},{-140,-240},{-140,
+ 60},{-102,60}},
+ color={255,127,0}));
+
+ connect(cooSetAdj, modSetPoi.cooSetAdj) annotation (Line(points={{-240,130},{-212,
+ 130},{-212,161},{-142,161}}, color={0,0,127}));
+
+ connect(heaSetAdj, modSetPoi.heaSetAdj) annotation (Line(points={{-240,100},{-172,
+ 100},{-172,159},{-142,159}}, color={0,0,127}));
+
+ connect(TSup, fcuPlaReq.TAirSup) annotation (Line(points={{-240,-20},{-80,-20},
+ {-80,-86},{98,-86}}, color={0,0,127}));
+
+ connect(uCooCoi, fcuPlaReq.uCooCoi_actual) annotation (Line(points={{-240,-380},
+ {60,-380},{60,-93.8},{98,-93.8}}, color={0,0,127}));
+
+ connect(uHeaCoi, fcuPlaReq.uHeaCoi_actual) annotation (Line(points={{-240,-340},
+ {70,-340},{70,-98},{98,-98}}, color={0,0,127}));
+
+ connect(fcuPlaReq.yChiWatResReq, yChiWatResReq) annotation (Line(points={{122,-84},
+ {160,-84},{160,-100},{220,-100}}, color={255,127,0}));
+
+ connect(fcuPlaReq.yChiPlaReq, yChiPlaReq) annotation (Line(points={{122,-88},{
+ 156,-88},{156,-140},{220,-140}}, color={255,127,0}));
+
+ connect(fcuPlaReq.yHotWatResReq, yHotWatResReq) annotation (Line(points={{122,-92},
+ {150,-92},{150,-180},{220,-180}}, color={255,127,0}));
+
+ connect(fcuPlaReq.yHotWatPlaReq, yHotWatPlaReq) annotation (Line(points={{122,-96},
+ {144,-96},{144,-220},{220,-220}}, color={255,127,0}));
+
+ connect(TSupAir.TSupSet, fcuPlaReq.TSupSet) annotation (Line(points={{124,12},
+ {130,12},{130,-70},{94,-70},{94,-90},{98,-90}}, color={0,0,127}));
+
+ connect(fanSpe.yFan, fcuPlaReq.uFan) annotation (Line(points={{142,178},{150,178},
+ {150,-60},{90,-60},{90,-82},{98,-82}}, color={0,0,127}));
+
+ connect(TOccHeaSet, modSetPoi.TOccHeaSet) annotation (Line(points={{-240,-80},
+ {-164,-80},{-164,177},{-142,177}}, color={0,0,127}));
+
+ connect(TOccCooSet, modSetPoi.TOccCooSet) annotation (Line(points={{-240,-120},
+ {-168,-120},{-168,175},{-142,175}}, color={0,0,127}));
+
+ connect(TUnoHeaSet, modSetPoi.TUnoHeaSet) annotation (Line(points={{-240,-160},
+ {-200,-160},{-200,173},{-142,173}}, color={0,0,127}));
+
+ connect(TUnoCooSet, modSetPoi.TUnoCooSet) annotation (Line(points={{-240,-200},
+ {-206,-200},{-206,171},{-142,171}}, color={0,0,127}));
+annotation (defaultComponentName="conFCU",
+ Icon(coordinateSystem(preserveAspectRatio=false, extent={{-200,-380},{200,380}}),
+ graphics={Rectangle(
+ extent={{-200,-380},{200,380}},
+ lineColor={0,0,127},
+ fillColor={255,255,255},
+ fillPattern=FillPattern.Solid),
+ Text(
+ extent={{-200,460},{200,380}},
+ textString="%name",
+ textColor={0,0,255}),
+ Text(
+ extent={{-196,296},{-134,268}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="tNexOcc"),
+ Text(
+ extent={{-200,12},{-156,-8}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="TZon"),
+ Text(
+ extent={{-196,172},{-150,152}},
+ textColor={255,0,255},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="u1Occ"),
+ Text(
+ extent={{-200,52},{-152,30}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="TSup"),
+ Text(
+ extent={{-198,-212},{-152,-184}},
+ textColor={244,125,35},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="nOcc",
+ visible=have_occSen),
+ Text(
+ visible=have_winSen,
+ extent={{-196,-266},{-152,-288}},
+ textColor={255,0,255},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="u1Win"),
+ Text(
+ extent={{132,-22},{198,-56}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="TSupSet"),
+ Text(
+ extent={{148,172},{200,136}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="yFan"),
+ Text(
+ extent={{116,136},{194,102}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="TZonHeaSet"),
+ Text(
+ extent={{116,98},{196,60}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="TZonCooSet"),
+ Text(
+ extent={{142,60},{196,22}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="yHeaCoi",
+ visible=have_heaCoi),
+ Text(
+ extent={{142,20},{196,-18}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="yCooCoi",
+ visible=have_cooCoi),
+ Text(
+ extent={{-194,378},{-120,346}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="warUpTim"),
+ Text(
+ extent={{-194,338},{-114,306}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="cooDowTim"),
+ Text(
+ extent={{-194,134},{-82,112}},
+ textColor={255,127,0},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="uCooDemLimLev"),
+ Text(
+ extent={{-194,92},{-82,70}},
+ textColor={255,127,0},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="uHeaDemLimLev"),
+ Text(
+ extent={{-196,-230},{-150,-250}},
+ textColor={255,0,255},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="u1Fan"),
+ Text(
+ extent={{144,212},{188,190}},
+ textColor={255,0,255},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="y1Fan"),
+ Text(
+ extent={{-196,174},{-134,146}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="setAdj",
+ visible=cooAdj or have_locAdj),
+ Text(
+ extent={{-196,134},{-134,106}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="heaSetAdj",
+ visible=heaAdj),
+ Text(
+ extent={{-196,-308},{-148,-330}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="uHeaCoi",
+ visible=have_hotWatCoi),
+ Text(
+ extent={{-196,-348},{-148,-370}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="uCooCoi",
+ visible=have_cooCoi),
+ Text(
+ extent={{106,-90},{198,-66}},
+ textColor={244,125,35},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="yChiWatResReq",
+ visible=have_cooCoi),
+ Text(
+ extent={{132,-130},{198,-108}},
+ textColor={244,125,35},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="yChiPlaReq",
+ visible=have_cooCoi),
+ Text(
+ extent={{104,-170},{196,-146}},
+ textColor={244,125,35},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="yHotWatResReq",
+ visible=have_hotWatCoi),
+ Text(
+ extent={{106,-210},{198,-186}},
+ textColor={244,125,35},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="yHotWatPlaReq",
+ visible=have_hotWatCoi),
+ Text(
+ extent={{-196,-26},{-104,-54}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="TOccHeaSet"),
+ Text(
+ extent={{-194,-68},{-98,-92}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="TOccCooSet"),
+ Text(
+ extent={{-194,-108},{-98,-130}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="TUnoHeaSet"),
+ Text(
+ extent={{-200,-148},{-94,-170}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="TUnoCooSet"),
+ Text(
+ extent={{-196,256},{-124,228}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="cooSetAdj"),
+ Text(
+ extent={{-196,214},{-124,186}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="heaSetAdj")}),
+ Diagram(coordinateSystem(
+ preserveAspectRatio=false, extent={{-220,-400},{200,240}})),
+Documentation(info="
+
+Block for fan coil unit control. It outputs supply fan enable signal and speed signal,
+the supply air temperature setpoint, the zone air heating and cooling setpoints,
+and valve positions of heating and cooling coils.
+
+
+It is implemented according to the ASHRAE Guideline 36-2021, Part 5.22.
+
+
+The sequences consist of the following subsequences.
+
+The supply air temperature setpoint control sequences are implemented based on Part 5.22.4.
+The block outputs a supply air temperature setpoint signal TSupSet,
+and control signals for the heating coil yHeaCoi and the cooling coil
+yCooCoi. See
+
+Buildings.Controls.OBC.ASHRAE.FanCoilUnit.Subsequences.SupplyAirTemperature
+for more detailed description.
+
+March 22, 2022, by Karthik Devaprasad:
+First implementation.
+
+
+"));
+end Controller;
diff --git a/Buildings/Controls/OBC/ASHRAE/FanCoilUnit/Subsequences/FanSpeed.mo b/Buildings/Controls/OBC/ASHRAE/FanCoilUnit/Subsequences/FanSpeed.mo
new file mode 100644
index 00000000000..93c99a85db8
--- /dev/null
+++ b/Buildings/Controls/OBC/ASHRAE/FanCoilUnit/Subsequences/FanSpeed.mo
@@ -0,0 +1,423 @@
+within Buildings.Controls.OBC.ASHRAE.FanCoilUnit.Subsequences;
+block FanSpeed
+ "Fan speed setpoint subsequence"
+
+ parameter Boolean have_cooCoi
+ "Does the fan coil unit have a cooling coil? True: Yes, False: No";
+
+ parameter Boolean have_heaCoi
+ "Does the fan coil unit have a heating coil? True: Yes, False: No";
+
+ parameter Real deaSpe(
+ final unit="1",
+ displayUnit="1") = 0.1
+ "Deadband mode fan speed"
+ annotation(Dialog(group="Deadband"));
+
+ parameter Real heaSpe_min(
+ final unit="1",
+ displayUnit="1") = 0.1
+ "Minimum heating mode fan speed"
+ annotation(Dialog(group="Heating loop",
+ enable = have_heaCoi));
+
+ parameter Real uHea_min(
+ final unit="1",
+ displayUnit="1") = 0.5
+ "Minimum heating loop signal at which fan speed is modified"
+ annotation(Dialog(group="Heating loop",
+ enable = have_heaCoi));
+
+ parameter Real heaSpe_max(
+ final unit="1",
+ displayUnit="1") = 0.6
+ "Maximum heating mode fan speed"
+ annotation(Dialog(group="Heating loop",
+ enable = have_heaCoi));
+
+ parameter Real uHea_max(
+ final unit="1",
+ displayUnit="1") = 1
+ "Maximum heating loop signal at which fan speed is modified"
+ annotation(Dialog(group="Heating loop",
+ enable = have_heaCoi));
+
+ parameter Real cooSpe_min(
+ final unit="1",
+ displayUnit="1") = 0.2
+ "Minimum cooling mode fan speed"
+ annotation(Dialog(group="Cooling loop",
+ enable = have_cooCoi));
+
+ parameter Real uCoo_min(
+ final unit="1",
+ displayUnit="1") = 0.5
+ "Minimum cooling loop signal at which fan speed is modified"
+ annotation(Dialog(group="Cooling loop",
+ enable = have_cooCoi));
+
+ parameter Real cooSpe_max(
+ final unit="1",
+ displayUnit="1") = 1
+ "Maximum cooling mode fan speed"
+ annotation(Dialog(group="Cooling loop",
+ enable = have_cooCoi));
+
+ parameter Real uCoo_max(
+ final unit="1",
+ displayUnit="1") = 1
+ "Maximum cooling loop signal at which fan speed is modified"
+ annotation(Dialog(group="Cooling loop",
+ enable = have_cooCoi));
+
+ parameter Real heaDea(
+ final unit="1",
+ displayUnit="1") = 0.05
+ "Heating loop signal limit above which fan operation changes from deadband mode to heating mode"
+ annotation(Dialog(group="Deadband",
+ enable = have_heaCoi));
+
+ parameter Real cooDea(
+ final unit="1",
+ displayUnit="1") = 0.05
+ "Cooling loop signal limit above which fan operation changes from deadband mode to cooling mode"
+ annotation(Dialog(group="Deadband",
+ enable = have_cooCoi));
+
+ parameter Real deaHysLim(
+ final unit="1",
+ displayUnit="1") = 0.01
+ "Hysteresis limits for deadband mode transitions"
+ annotation(Dialog(tab="Advanced"));
+
+ Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1FanPro
+ "Fan proven on signal"
+ annotation (Placement(transformation(extent={{-140,20},{-100,60}}),
+ iconTransformation(extent={{-140,0},{-100,40}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.IntegerInput opeMod
+ "System operating mode"
+ annotation (Placement(transformation(extent={{-140,60},{-100,100}}),
+ iconTransformation(extent={{-140,40},{-100,80}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput uHea(
+ final unit="1",
+ displayUnit="1") if have_heaCoi
+ "Heating loop signal"
+ annotation (Placement(transformation(extent={{-140,-40},{-100,0}}),
+ iconTransformation(extent={{-140,-40},{-100,0}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput uCoo(
+ final unit="1",
+ displayUnit="1") if have_cooCoi
+ "Cooling loop signal"
+ annotation (Placement(transformation(extent={{-140,-140},{-100,-100}}),
+ iconTransformation(extent={{-140,-80},{-100,-40}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1Fan
+ "Fan command on status"
+ annotation (Placement(transformation(extent={{120,40},{160,80}}),
+ iconTransformation(extent={{100,0},{140,40}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealOutput yFan(
+ final unit="1",
+ displayUnit="1")
+ "Fan command speed"
+ annotation (Placement(transformation(extent={{120,-20},{160,20}}),
+ iconTransformation(extent={{100,-40},{140,0}})));
+
+protected
+ Buildings.Controls.OBC.CDL.Integers.Equal isUnOcc
+ "Check if zone is unoccupied"
+ annotation (Placement(transformation(extent={{-40,70},{-20,90}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Sources.Constant unOccMod(
+ final k=Buildings.Controls.OBC.ASHRAE.G36.Types.OperationModes.unoccupied)
+ "Constant unoccupied mode signal"
+ annotation (Placement(transformation(extent={{-80,50},{-60,70}})));
+
+ Buildings.Controls.OBC.CDL.Logical.Not notUno
+ "Enable only if zone is not in unoccupied mode"
+ annotation (Placement(transformation(extent={{-10,70},{10,90}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Switch swiFanPro
+ "Switch fan speed to deadband speed until the fan is proven ON"
+ annotation (Placement(transformation(extent={{80,-10},{100,10}})));
+
+ Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea
+ "Convert fan enable signal to Real"
+ annotation (Placement(transformation(extent={{30,-30},{50,-10}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Line linHeaFanSpe
+ "Heating fan speed signal"
+ annotation (Placement(transformation(extent={{-30,-30},{-10,-10}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conuHea_min(
+ final k=uHea_min)
+ "Minimum heating loop signal support point"
+ annotation (Placement(transformation(extent={{-90,-50},{-70,-30}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conheaSpe_min(
+ final k=heaSpe_min)
+ "Minimum heating fan speed limit signal"
+ annotation (Placement(transformation(extent={{-90,10},{-70,30}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant concooSpe_min(
+ final k=cooSpe_min)
+ "Minimum cooling fan speed limit signal"
+ annotation (Placement(transformation(extent={{-90,-110},{-70,-90}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Line linCooFanSpe
+ "Cooling fan speed signal"
+ annotation (Placement(transformation(extent={{-30,-130},{-10,-110}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conuCoo_min(
+ final k=uCoo_min)
+ "Minimum cooling loop signal support point"
+ annotation (Placement(transformation(extent={{-90,-150},{-70,-130}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conDeaFanSpe(
+ final k=deaSpe)
+ "Deadband mode fan speed signal"
+ annotation (Placement(transformation(extent={{-30,-70},{-10,-50}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Hysteresis hysDeaHea(
+ final uLow=heaDea-deaHysLim,
+ final uHigh=heaDea)
+ "Hysteresis for switching between deadband mode and heating mode"
+ annotation (Placement(transformation(extent={{0,-50},{20,-30}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Switch swiDeaHea
+ "Switch for turning on heating mode from deadband mode"
+ annotation (Placement(transformation(extent={{30,-70},{50,-50}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Hysteresis hysDeaCoo(
+ final uLow=cooDea-deaHysLim,
+ final uHigh=cooDea)
+ "Hysteresis for switching on cooling mode from deadband mode"
+ annotation (Placement(transformation(extent={{0,-110},{20,-90}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Switch swiDeaCoo
+ "Switch for turning on cooling mode from deadband mode"
+ annotation (Placement(transformation(extent={{60,-110},{80,-90}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Multiply mulFanSpe
+ "Multiply fan speed signal by fan enable signal"
+ annotation (Placement(transformation(extent={{90,-90},{110,-70}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conZerHeaMod(
+ final k=0) if not have_heaCoi
+ "Constant zero signal for heating mode"
+ annotation (Placement(transformation(extent={{-90,-80},{-70,-60}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conZerCooMod(
+ final k=0) if not have_cooCoi
+ "Constant zero signal for cooling mode"
+ annotation (Placement(transformation(extent={{-30,-160},{-10,-140}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conheaSpe_max(
+ final k=heaSpe_max)
+ "Maximum heating fan speed limit signal"
+ annotation (Placement(transformation(extent={{-60,10},{-40,30}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conuHea_max(
+ final k=uHea_max)
+ "Maximum heating loop signal support point"
+ annotation (Placement(transformation(extent={{-60,-50},{-40,-30}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant concooSpe_max(
+ final k=cooSpe_max)
+ "Maximum cooling fan speed limit signal"
+ annotation (Placement(transformation(extent={{-60,-100},{-40,-80}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conuCoo_max(
+ final k=uCoo_max)
+ "Maximum cooling loop signal support point"
+ annotation (Placement(transformation(extent={{-60,-160},{-40,-140}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Multiply mulDeaSpe
+ "Multiply deadband speed signal by fan enable signal"
+ annotation (Placement(transformation(extent={{80,-40},{100,-20}})));
+
+equation
+ connect(unOccMod.y, isUnOcc.u2) annotation (Line(points={{-58,60},{-50,60},{-50,
+ 72},{-42,72}}, color={255,127,0}));
+
+ connect(opeMod, isUnOcc.u1)
+ annotation (Line(points={{-120,80},{-42,80}}, color={255,127,0}));
+
+ connect(isUnOcc.y, notUno.u)
+ annotation (Line(points={{-18,80},{-12,80}}, color={255,0,255}));
+
+ connect(notUno.y, y1Fan) annotation (Line(points={{12,80},{20,80},{20,60},{140,
+ 60}}, color={255,0,255}));
+
+ connect(u1FanPro, swiFanPro.u2) annotation (Line(points={{-120,40},{30,40},{30,
+ 0},{78,0}}, color={255,0,255}));
+
+ connect(notUno.y, booToRea.u) annotation (Line(points={{12,80},{20,80},{20,-20},
+ {28,-20}}, color={255,0,255}));
+
+ connect(uHea, linHeaFanSpe.u)
+ annotation (Line(points={{-120,-20},{-32,-20}}, color={0,0,127}));
+
+ connect(uCoo, linCooFanSpe.u)
+ annotation (Line(points={{-120,-120},{-32,-120}}, color={0,0,127}));
+
+ connect(uHea, hysDeaHea.u) annotation (Line(points={{-120,-20},{-36,-20},{-36,
+ -40},{-2,-40}}, color={0,0,127}));
+
+ connect(hysDeaHea.y, swiDeaHea.u2) annotation (Line(points={{22,-40},{26,-40},
+ {26,-60},{28,-60}}, color={255,0,255}));
+
+ connect(conDeaFanSpe.y, swiDeaHea.u3) annotation (Line(points={{-8,-60},{20,-60},
+ {20,-68},{28,-68}}, color={0,0,127}));
+
+ connect(linHeaFanSpe.y, swiDeaHea.u1) annotation (Line(points={{-8,-20},{-4,-20},
+ {-4,-52},{28,-52}}, color={0,0,127}));
+
+ connect(hysDeaCoo.y, swiDeaCoo.u2)
+ annotation (Line(points={{22,-100},{58,-100}}, color={255,0,255}));
+
+ connect(uCoo, hysDeaCoo.u) annotation (Line(points={{-120,-120},{-34,-120},{-34,
+ -100},{-2,-100}}, color={0,0,127}));
+
+ connect(linCooFanSpe.y, swiDeaCoo.u1) annotation (Line(points={{-8,-120},{40,-120},
+ {40,-92},{58,-92}}, color={0,0,127}));
+
+ connect(swiDeaHea.y, swiDeaCoo.u3) annotation (Line(points={{52,-60},{54,-60},
+ {54,-108},{58,-108}}, color={0,0,127}));
+
+ connect(booToRea.y, mulFanSpe.u1) annotation (Line(points={{52,-20},{74,-20},{
+ 74,-74},{88,-74}}, color={0,0,127}));
+
+ connect(swiDeaCoo.y, mulFanSpe.u2) annotation (Line(points={{82,-100},{84,-100},
+ {84,-86},{88,-86}}, color={0,0,127}));
+
+ connect(mulFanSpe.y, swiFanPro.u1) annotation (Line(points={{112,-80},{114,-80},
+ {114,20},{74,20},{74,8},{78,8}}, color={0,0,127}));
+
+ connect(swiFanPro.y, yFan)
+ annotation (Line(points={{102,0},{140,0}}, color={0,0,127}));
+
+ connect(conZerHeaMod.y, linHeaFanSpe.u) annotation (Line(points={{-68,-70},{-36,
+ -70},{-36,-20},{-32,-20}}, color={0,0,127}));
+
+ connect(conZerCooMod.y, linCooFanSpe.u) annotation (Line(points={{-8,-150},{-6,
+ -150},{-6,-100},{-34,-100},{-34,-120},{-32,-120}}, color={0,0,127}));
+
+ connect(conZerHeaMod.y, hysDeaHea.u) annotation (Line(points={{-68,-70},{-36,-70},
+ {-36,-40},{-2,-40}}, color={0,0,127}));
+
+ connect(conZerCooMod.y, hysDeaCoo.u) annotation (Line(points={{-8,-150},{-6,-150},
+ {-6,-100},{-2,-100}}, color={0,0,127}));
+
+ connect(conheaSpe_max.y, linHeaFanSpe.f2) annotation (Line(points={{-38,20},{-34,
+ 20},{-34,-28},{-32,-28}}, color={0,0,127}));
+ connect(conuHea_max.y, linHeaFanSpe.x2)
+ annotation (Line(points={{-38,-40},{-38,-24},{-32,-24}}, color={0,0,127}));
+ connect(concooSpe_max.y, linCooFanSpe.f2) annotation (Line(points={{-38,-90},{-36,
+ -90},{-36,-128},{-32,-128}}, color={0,0,127}));
+ connect(conuCoo_max.y, linCooFanSpe.x2) annotation (Line(points={{-38,-150},{
+ -34,-150},{-34,-124},{-32,-124}}, color={0,0,127}));
+ connect(conheaSpe_min.y, linHeaFanSpe.f1) annotation (Line(points={{-68,20},{-66,
+ 20},{-66,-16},{-32,-16}}, color={0,0,127}));
+ connect(conuHea_min.y, linHeaFanSpe.x1) annotation (Line(points={{-68,-40},{-64,
+ -40},{-64,-12},{-32,-12}}, color={0,0,127}));
+ connect(conuCoo_min.y, linCooFanSpe.x1) annotation (Line(points={{-68,-140},{
+ -66,-140},{-66,-112},{-32,-112}}, color={0,0,127}));
+ connect(concooSpe_min.y, linCooFanSpe.f1) annotation (Line(points={{-68,-100},{
+ -64,-100},{-64,-116},{-32,-116}}, color={0,0,127}));
+ connect(mulDeaSpe.y, swiFanPro.u3) annotation (Line(points={{102,-30},{108,-30},
+ {108,-14},{74,-14},{74,-8},{78,-8}}, color={0,0,127}));
+ connect(booToRea.y, mulDeaSpe.u1) annotation (Line(points={{52,-20},{74,-20},{
+ 74,-24},{78,-24}}, color={0,0,127}));
+ connect(conDeaFanSpe.y, mulDeaSpe.u2) annotation (Line(points={{-8,-60},{20,-60},
+ {20,-74},{60,-74},{60,-36},{78,-36}}, color={0,0,127}));
+ annotation (defaultComponentName="fanSpe",
+ Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{100,100}}),
+ graphics={
+ Rectangle(
+ extent={{-100,-100},{100,100}},
+ lineColor={0,0,127},
+ fillColor={255,255,255},
+ fillPattern=FillPattern.Solid),
+ Text(
+ extent={{-100,140},{100,100}},
+ textColor={0,0,255},
+ textString="%name"),
+ Text(
+ extent={{-98,32},{-36,12}},
+ textColor={255,0,255},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="u1FanPro"),
+ Text(
+ extent={{48,32},{94,12}},
+ textColor={255,0,255},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="y1Fan"),
+ Text(
+ extent={{-100,70},{-36,50}},
+ textColor={255,127,0},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="opeMod"),
+ Text(
+ extent={{-100,-10},{-52,-32}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="uHea",
+ visible=have_heaCoi),
+ Text(
+ extent={{-100,-50},{-52,-72}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="uCoo",
+ visible=have_cooCoi),
+ Text(
+ extent={{46,-8},{100,-30}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="yFan")}),
+ Diagram(coordinateSystem(preserveAspectRatio=false,
+ extent={{-100,-180},{120,120}})),
+ Documentation(info="
+
+ Block that outputs the fan enable signal and the fan speed signal based on
+ the heating and cooling loop signals. The implemented sequence is based on
+ ASHRAE Guideline 36, 2021, Part 5.22.4.
+
+
+ The fan enable signal y1Fan is switched to false
+ when the operating mode signal opeMod is unoccupied,
+ and is set to true otherwise.
+
+ The fan speed signal yFan is varied from
+ the minimum cooling mode fan speed cooSpe_min to the maximum
+ cooling mode fan speed cooSpe_max,
+ when the cooling loop signal uCoo varies from the minimum limit
+ uCoo_min to the maximum limit uCoo_max.
+ Similarly, yFan is varied from the minimum heating mode fan speed
+ heaSpe_min to the maximum heating mode fan speed heaSpe_max,
+ when the heating loop signal uHea varies from the minimum limit
+ uHea_min to the maximum limit uHea_max.
+ The setpoint in deadband mode is equal to the deadband fan speed deaSpe.
+
+
+
+
+ ", revisions="
+
+
+ March 17, 2022, by Karthik Devaprasad:
+ First implementation.
+
+
+ "));
+end FanSpeed;
diff --git a/Buildings/Controls/OBC/ASHRAE/FanCoilUnit/Subsequences/PlantRequests.mo b/Buildings/Controls/OBC/ASHRAE/FanCoilUnit/Subsequences/PlantRequests.mo
new file mode 100644
index 00000000000..ede0b3c8397
--- /dev/null
+++ b/Buildings/Controls/OBC/ASHRAE/FanCoilUnit/Subsequences/PlantRequests.mo
@@ -0,0 +1,663 @@
+within Buildings.Controls.OBC.ASHRAE.FanCoilUnit.Subsequences;
+block PlantRequests
+ "Output plant requests for fan coil unit"
+
+ parameter Boolean have_hotWatCoi = true
+ "Does the fan coil unit have a hot-water heating coil? True: Yes, False: No";
+
+ parameter Boolean have_chiWatCoi = true
+ "Does the fan coil unit have a chilled-water cooling coil? True: Yes, False: No";
+
+ parameter Real cooSpe_max(
+ final unit="1",
+ displayUnit="1") = 1
+ "Maximum cooling mode fan speed";
+
+ parameter Real heaSpe_max(
+ final unit="1",
+ displayUnit="1") = 0.6
+ "Maximum heating mode fan speed";
+
+ parameter Real chiWatPlaReqLim0(
+ final unit="1",
+ displayUnit="1") = 0.1
+ "Valve position limit below which zero chilled water plant requests are sent when one request was previously being sent"
+ annotation(Dialog(tab="Request limits", group="Chilled water requests", enable=have_chiWatCoi));
+
+ parameter Real chiWatResReqLim0(
+ final unit="1",
+ displayUnit="1") = 0.85
+ "Valve position limit below which zero chilled water reset requests are sent when one request was previously being sent"
+ annotation(Dialog(tab="Request limits", group="Chilled water requests", enable=have_chiWatCoi));
+
+ parameter Real chiWatPlaReqLim1(
+ final unit="1",
+ displayUnit="1") = 0.95
+ "Valve position limit above which one chilled water plant request is sent"
+ annotation(Dialog(tab="Request limits", group="Chilled water requests", enable=have_chiWatCoi));
+
+ parameter Real chiWatResReqLim2(
+ final unit="K",
+ final quantity="TemperatureDifference") = 2.78
+ "Temperature difference limit between setpoint and supply air temperature above which two chilled water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Chilled water requests", enable=have_chiWatCoi));
+
+ parameter Real chiWatResReqTimLim2(
+ final unit="s",
+ displayUnit="s",
+ final quantity="Time") = 300
+ "Time period for which chiWatResReqLim2 has to be exceeded before two chilled water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Chilled water requests", enable=have_chiWatCoi));
+
+ parameter Real chiWatResReqLim3(
+ final unit="K",
+ final quantity="TemperatureDifference") = 5.56
+ "Temperature difference limit between setpoint and supply air temperature above which three chilled water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Chilled water requests", enable=have_chiWatCoi));
+
+ parameter Real chiWatResReqTimLim3(
+ final unit="s",
+ displayUnit="s",
+ final quantity="Time") = 300
+ "Time period for which chiWatResReqLim3 has to be exceeded before three chilled water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Chilled water requests", enable=have_chiWatCoi));
+
+ parameter Real hotWatPlaReqLim0(
+ final unit="1",
+ displayUnit="1") = 0.1
+ "Valve position limit below which zero hot water plant requests are sent when one request was previously being sent"
+ annotation(Dialog(tab="Request limits", group="Hot water requests", enable=have_hotWatCoi));
+
+ parameter Real hotWatResReqLim0(
+ final unit="1",
+ displayUnit="1") = 0.85
+ "Valve position limit below which zero hot water reset requests are sent when one request was previously being sent"
+ annotation(Dialog(tab="Request limits", group="Hot water requests", enable=have_hotWatCoi));
+
+ parameter Real hotWatPlaReqLim1(
+ final unit="1",
+ displayUnit="1") = 0.95
+ "Valve position limit above which one hot water plant request is sent"
+ annotation(Dialog(tab="Request limits", group="Hot water requests", enable=have_hotWatCoi));
+
+ parameter Real hotWatResReqLim2(
+ final unit="K",
+ final quantity="TemperatureDifference") = 8
+ "Temperature difference limit between setpoint and supply air temperature above which two hot water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Hot water requests", enable=have_hotWatCoi));
+
+ parameter Real hotWatResReqTimLim2(
+ final unit="s",
+ displayUnit="s",
+ final quantity="Time") = 300
+ "Time period for which hotWatResReqLim2 has to be exceeded before two hot water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Hot water requests", enable=have_hotWatCoi));
+
+ parameter Real hotWatResReqLim3(
+ final unit="K",
+ final quantity="TemperatureDifference") = 17
+ "Temperature difference limit between setpoint and supply air temperature above which three hot water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Hot water requests", enable=have_hotWatCoi));
+
+ parameter Real hotWatResReqTimLim3(
+ final unit="s",
+ displayUnit="s",
+ final quantity="Time") = 300
+ "Time period for which hotWatResReqLim3 has to be exceeded before three hot water reset requests are sent"
+ annotation(Dialog(tab="Request limits", group="Hot water requests", enable=have_hotWatCoi));
+
+ parameter Real Thys(
+ final unit="K",
+ final quantity = "TemperatureDifference") = 0.1
+ "Hysteresis for checking temperature difference"
+ annotation(Dialog(tab="Advanced"));
+
+ parameter Real posHys(
+ final unit="1",
+ displayUnit="1") = 0.05
+ "Hysteresis for checking valve position difference"
+ annotation(Dialog(tab="Advanced"));
+
+ parameter Real dFanSpe(
+ final unit="1",
+ displayUnit="1") = 0.05
+ "Fan speed hysteresis difference"
+ annotation(Dialog(tab="Advanced"));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput TAirSup(
+ final unit="K",
+ final displayUnit="degC",
+ final quantity="ThermodynamicTemperature")
+ "Measured supply air temperature"
+ annotation (Placement(transformation(extent={{-240,180},{-200,220}}),
+ iconTransformation(extent={{-140,20},{-100,60}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput TSupSet(
+ final unit="K",
+ final displayUnit="degC",
+ final quantity="ThermodynamicTemperature")
+ "Supply air temperature setpoint"
+ annotation (Placement(transformation(extent={{-240,140},{-200,180}}),
+ iconTransformation(extent={{-140,-20},{-100,20}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput uCooCoi_actual(
+ final unit="1",
+ final min=0,
+ final max=1) if have_chiWatCoi
+ "Actual cooling coil control action"
+ annotation (Placement(transformation(extent={{-240,80},{-200,120}}),
+ iconTransformation(extent={{-140,-58},{-100,-18}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput uHeaCoi_actual(
+ final unit="1",
+ final min=0,
+ final max=1) if have_hotWatCoi
+ "Actual heating coil control action"
+ annotation (Placement(transformation(extent={{-240,-160},{-200,-120}}),
+ iconTransformation(extent={{-140,-100},{-100,-60}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput uFan(
+ final unit="1",
+ final min=0,
+ final max=1)
+ "Fan speed signal"
+ annotation (Placement(transformation(extent={{-240,220},{-200,260}}),
+ iconTransformation(extent={{-140,60},{-100,100}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput yChiWatResReq if have_chiWatCoi
+ "Chilled water reset request"
+ annotation (Placement(transformation(extent={{200,180},{240,220}}),
+ iconTransformation(extent={{100,40},{140,80}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput yChiPlaReq if have_chiWatCoi
+ "Chiller plant request"
+ annotation (Placement(transformation(extent={{200,0},{240,40}}),
+ iconTransformation(extent={{100,0},{140,40}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput yHotWatResReq if have_hotWatCoi
+ "Hot water reset request"
+ annotation (Placement(transformation(extent={{200,-60},{240,-20}}),
+ iconTransformation(extent={{100,-40},{140,0}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput yHotWatPlaReq if have_hotWatCoi
+ "Hot water plant request"
+ annotation (Placement(transformation(extent={{200,-240},{240,-200}}),
+ iconTransformation(extent={{100,-80},{140,-40}})));
+
+protected
+ Buildings.Controls.OBC.CDL.Continuous.Hysteresis hysFanCoo(
+ final uLow=cooSpe_max - 2*dFanSpe,
+ final uHigh=cooSpe_max - dFanSpe) if have_chiWatCoi
+ "Check if fan is at max cooling mode speed"
+ annotation (Placement(transformation(extent={{-130,230},{-110,250}})));
+
+ Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToIntCoo if have_chiWatCoi
+ "Output integer 1 when fan is at max cooling mode speed"
+ annotation (Placement(transformation(extent={{-80,230},{-60,250}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Multiply mulIntCoo if have_chiWatCoi
+ "Output reset requests only if fan is at max cooling mode speed"
+ annotation (Placement(transformation(extent={{100,230},{120,250}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Hysteresis hysFanHea(
+ final uLow=heaSpe_max - 2*dFanSpe,
+ final uHigh=heaSpe_max - dFanSpe) if have_hotWatCoi
+ "Check if fan is at max heating mode speed"
+ annotation (Placement(transformation(extent={{-140,-20},{-120,0}})));
+
+ Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToIntHea if have_hotWatCoi
+ "Output integer 1 when fan is at max heating mode speed"
+ annotation (Placement(transformation(extent={{-90,-20},{-70,0}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Multiply mulIntHea if have_hotWatCoi
+ "Output reset requests only if fan is at max heating mode speed"
+ annotation (Placement(transformation(extent={{110,-10},{130,10}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Subtract cooSupTemDif
+ "Find the cooling supply temperature difference to the setpoint"
+ annotation (Placement(transformation(extent={{-140,190},{-120,210}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.GreaterThreshold greThr(
+ final t=chiWatResReqLim3,
+ final h=Thys) if have_chiWatCoi
+ "Check if the supply temperature is greater than the setpoint by a threshold value"
+ annotation (Placement(transformation(extent={{-80,190},{-60,210}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.GreaterThreshold greThr1(
+ final t=chiWatResReqLim2,
+ final h=Thys) if have_chiWatCoi
+ "Check if the supply temperature is greater than the setpoint by a threshold value"
+ annotation (Placement(transformation(extent={{-80,140},{-60,160}})));
+
+ Buildings.Controls.OBC.CDL.Logical.TrueDelay truDel(
+ final delayTime=chiWatResReqTimLim3) if have_chiWatCoi
+ "Check if the input has been true for a certain time"
+ annotation (Placement(transformation(extent={{-40,190},{-20,210}})));
+
+ Buildings.Controls.OBC.CDL.Logical.TrueDelay truDel1(
+ final delayTime=chiWatResReqTimLim2) if have_chiWatCoi
+ "Check if the input has been true for a certain time"
+ annotation (Placement(transformation(extent={{-40,140},{-20,160}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.GreaterThreshold greThr2(
+ final t=chiWatPlaReqLim1,
+ final h=posHys) if have_chiWatCoi
+ "Check if the chilled water valve position is greater than a threshold value"
+ annotation (Placement(transformation(extent={{-120,90},{-100,110}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Sources.Constant thr(
+ final k=3)
+ "Constant 3"
+ annotation (Placement(transformation(extent={{0,222},{20,242}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Switch chiWatRes3 if have_chiWatCoi
+ "Send 3 chilled water reset request"
+ annotation (Placement(transformation(extent={{160,190},{180,210}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Switch chiWatRes2 if have_chiWatCoi
+ "Send 2 chilled water reset request"
+ annotation (Placement(transformation(extent={{120,140},{140,160}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Sources.Constant two(
+ final k=2)
+ "Constant 2"
+ annotation (Placement(transformation(extent={{0,170},{20,190}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.LessThreshold lesThr(
+ final t=chiWatResReqLim0,
+ final h=posHys) if have_chiWatCoi
+ "Check if the chilled water valve position is less than a threshold value"
+ annotation (Placement(transformation(extent={{-120,50},{-100,70}})));
+
+ Buildings.Controls.OBC.CDL.Logical.Latch lat if have_chiWatCoi
+ "Keep true signal until other condition becomes true"
+ annotation (Placement(transformation(extent={{-40,90},{-20,110}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Switch chiWatRes1 if have_chiWatCoi
+ "Send 1 chilled water reset request"
+ annotation (Placement(transformation(extent={{80,90},{100,110}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Sources.Constant one(
+ final k=1)
+ "Constant 1"
+ annotation (Placement(transformation(extent={{0,110},{20,130}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Sources.Constant zer(
+ final k=0)
+ "Constant 0"
+ annotation (Placement(transformation(extent={{0,50},{20,70}})));
+
+ Buildings.Controls.OBC.CDL.Logical.Latch lat1 if have_chiWatCoi
+ "Keep true signal until other condition becomes true"
+ annotation (Placement(transformation(extent={{-40,10},{-20,30}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.LessThreshold lesThr1(
+ final t=chiWatPlaReqLim0,
+ final h=posHys) if have_chiWatCoi
+ "Check if the chilled water valve position is less than a threshold value"
+ annotation (Placement(transformation(extent={{-120,4},{-100,24}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Switch intSwi3 if have_chiWatCoi
+ "Send 1 chiller plant request"
+ annotation (Placement(transformation(extent={{80,10},{100,30}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Subtract heaSupTemDif if have_hotWatCoi
+ "Find the heating supply temperature difference to the setpoint"
+ annotation (Placement(transformation(extent={{-140,-50},{-120,-30}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.GreaterThreshold greThr3(
+ final t=hotWatResReqLim3,
+ final h=Thys) if have_hotWatCoi
+ "Check if the supply temperature is less than the setpoint by a threshold value"
+ annotation (Placement(transformation(extent={{-80,-50},{-60,-30}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.GreaterThreshold greThr4(
+ final t=hotWatResReqLim2,
+ final h=Thys) if have_hotWatCoi
+ "Check if the supply temperature is less than the setpoint by a threshold value"
+ annotation (Placement(transformation(extent={{-80,-100},{-60,-80}})));
+
+ Buildings.Controls.OBC.CDL.Logical.TrueDelay truDel2(
+ final delayTime=hotWatResReqTimLim3) if have_hotWatCoi
+ "Check if the input has been true for a certain time"
+ annotation (Placement(transformation(extent={{-40,-50},{-20,-30}})));
+
+ Buildings.Controls.OBC.CDL.Logical.TrueDelay truDel3(
+ final delayTime=hotWatResReqTimLim2) if have_hotWatCoi
+ "Check if the input has been true for a certain time"
+ annotation (Placement(transformation(extent={{-40,-100},{-20,-80}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Switch hotWatRes3 if have_hotWatCoi
+ "Send 3 hot water reset request"
+ annotation (Placement(transformation(extent={{160,-50},{180,-30}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Switch hotWatRes2 if have_hotWatCoi
+ "Send 2 hot water reset request"
+ annotation (Placement(transformation(extent={{120,-100},{140,-80}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.LessThreshold lesThr2(
+ final t=hotWatResReqLim0,
+ final h=posHys) if have_hotWatCoi
+ "Check if the hot water valve position is less than a threshold value"
+ annotation (Placement(transformation(extent={{-120,-190},{-100,-170}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.GreaterThreshold greThr5(
+ final t=hotWatPlaReqLim1,
+ final h=posHys) if have_hotWatCoi
+ "Check if the hot water valve position is greater than a threshold value"
+ annotation (Placement(transformation(extent={{-120,-150},{-100,-130}})));
+
+ Buildings.Controls.OBC.CDL.Logical.Latch lat2 if have_hotWatCoi
+ "Keep true signal until other condition becomes true"
+ annotation (Placement(transformation(extent={{-40,-150},{-20,-130}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Switch hotWatRes1 if have_hotWatCoi
+ "Send 1 hot water reset request"
+ annotation (Placement(transformation(extent={{80,-150},{100,-130}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.LessThreshold lesThr3(
+ final t=hotWatPlaReqLim0,
+ final h=posHys) if have_hotWatCoi
+ "Check if the hot water valve position is less than a threshold value"
+ annotation (Placement(transformation(extent={{-120,-236},{-100,-216}})));
+
+ Buildings.Controls.OBC.CDL.Logical.Latch lat3 if have_hotWatCoi
+ "Keep true signal until other condition becomes true"
+ annotation (Placement(transformation(extent={{-40,-230},{-20,-210}})));
+
+ Buildings.Controls.OBC.CDL.Integers.Switch intSwi1 if have_hotWatCoi
+ "Send 1 hot water plant request"
+ annotation (Placement(transformation(extent={{80,-230},{100,-210}})));
+
+equation
+ connect(TAirSup, cooSupTemDif.u1) annotation (Line(points={{-220,200},{-180,200},
+ {-180,206},{-142,206}}, color={0,0,127}));
+
+ connect(TSupSet, cooSupTemDif.u2) annotation (Line(points={{-220,160},{-190,160},
+ {-190,194},{-142,194}}, color={0,0,127}));
+
+ connect(cooSupTemDif.y, greThr.u)
+ annotation (Line(points={{-118,200},{-82,200}}, color={0,0,127}));
+
+ connect(greThr.y, truDel.u)
+ annotation (Line(points={{-58,200},{-42,200}}, color={255,0,255}));
+
+ connect(greThr1.y, truDel1.u)
+ annotation (Line(points={{-58,150},{-42,150}}, color={255,0,255}));
+
+ connect(cooSupTemDif.y, greThr1.u) annotation (Line(points={{-118,200},{-100,200},
+ {-100,150},{-82,150}}, color={0,0,127}));
+
+ connect(uCooCoi_actual, greThr2.u)
+ annotation (Line(points={{-220,100},{-122,100}}, color={0,0,127}));
+
+ connect(truDel.y, chiWatRes3.u2)
+ annotation (Line(points={{-18,200},{158,200}}, color={255,0,255}));
+
+ connect(thr.y, chiWatRes3.u1) annotation (Line(points={{22,232},{60,232},{60,208},
+ {158,208}}, color={255,127,0}));
+
+ connect(truDel1.y, chiWatRes2.u2)
+ annotation (Line(points={{-18,150},{118,150}}, color={255,0,255}));
+
+ connect(two.y, chiWatRes2.u1) annotation (Line(points={{22,180},{50,180},{50,158},
+ {118,158}}, color={255,127,0}));
+
+ connect(greThr2.y, lat.u)
+ annotation (Line(points={{-98,100},{-42,100}}, color={255,0,255}));
+
+ connect(uCooCoi_actual, lesThr.u) annotation (Line(points={{-220,100},{-140,100},
+ {-140,60},{-122,60}}, color={0,0,127}));
+
+ connect(lesThr.y, lat.clr) annotation (Line(points={{-98,60},{-60,60},{-60,94},
+ {-42,94}}, color={255,0,255}));
+
+ connect(one.y, chiWatRes1.u1) annotation (Line(points={{22,120},{40,120},{40,108},
+ {78,108}}, color={255,127,0}));
+
+ connect(lat.y, chiWatRes1.u2)
+ annotation (Line(points={{-18,100},{78,100}}, color={255,0,255}));
+
+ connect(chiWatRes1.y, chiWatRes2.u3) annotation (Line(points={{102,100},{110,100},
+ {110,142},{118,142}}, color={255,127,0}));
+
+ connect(chiWatRes2.y, chiWatRes3.u3) annotation (Line(points={{142,150},{150,150},
+ {150,192},{158,192}}, color={255,127,0}));
+
+ connect(zer.y, chiWatRes1.u3) annotation (Line(points={{22,60},{30,60},{30,92},
+ {78,92}}, color={255,127,0}));
+
+ connect(greThr2.y, lat1.u) annotation (Line(points={{-98,100},{-80,100},{-80,20},
+ {-42,20}}, color={255,0,255}));
+
+ connect(uCooCoi_actual, lesThr1.u) annotation (Line(points={{-220,100},{-140,100},
+ {-140,14},{-122,14}}, color={0,0,127}));
+
+ connect(lesThr1.y, lat1.clr)
+ annotation (Line(points={{-98,14},{-42,14}}, color={255,0,255}));
+
+ connect(lat1.y, intSwi3.u2)
+ annotation (Line(points={{-18,20},{78,20}}, color={255,0,255}));
+
+ connect(one.y, intSwi3.u1) annotation (Line(points={{22,120},{40,120},{40,28},
+ {78,28}}, color={255,127,0}));
+
+ connect(zer.y, intSwi3.u3) annotation (Line(points={{22,60},{30,60},{30,12},{78,
+ 12}}, color={255,127,0}));
+
+ connect(intSwi3.y, yChiPlaReq)
+ annotation (Line(points={{102,20},{220,20}}, color={255,127,0}));
+
+ connect(TAirSup, heaSupTemDif.u2) annotation (Line(points={{-220,200},{-180,200},
+ {-180,-46},{-142,-46}}, color={0,0,127}));
+
+ connect(greThr3.y, truDel2.u)
+ annotation (Line(points={{-58,-40},{-42,-40}}, color={255,0,255}));
+
+ connect(greThr4.y, truDel3.u)
+ annotation (Line(points={{-58,-90},{-42,-90}}, color={255,0,255}));
+
+ connect(heaSupTemDif.y, greThr3.u)
+ annotation (Line(points={{-118,-40},{-82,-40}}, color={0,0,127}));
+
+ connect(heaSupTemDif.y, greThr4.u) annotation (Line(points={{-118,-40},{-100,-40},
+ {-100,-90},{-82,-90}}, color={0,0,127}));
+
+ connect(truDel2.y, hotWatRes3.u2)
+ annotation (Line(points={{-18,-40},{158,-40}}, color={255,0,255}));
+
+ connect(thr.y, hotWatRes3.u1) annotation (Line(points={{22,232},{60,232},{60,-32},
+ {158,-32}}, color={255,127,0}));
+
+ connect(hotWatRes2.y, hotWatRes3.u3) annotation (Line(points={{142,-90},{150,-90},
+ {150,-48},{158,-48}}, color={255,127,0}));
+
+ connect(two.y, hotWatRes2.u1) annotation (Line(points={{22,180},{50,180},{50,-82},
+ {118,-82}}, color={255,127,0}));
+
+ connect(truDel3.y, hotWatRes2.u2)
+ annotation (Line(points={{-18,-90},{118,-90}}, color={255,0,255}));
+
+ connect(uHeaCoi_actual, greThr5.u)
+ annotation (Line(points={{-220,-140},{-122,-140}}, color={0,0,127}));
+
+ connect(greThr5.y, lat2.u)
+ annotation (Line(points={{-98,-140},{-42,-140}}, color={255,0,255}));
+
+ connect(uHeaCoi_actual, lesThr2.u) annotation (Line(points={{-220,-140},{-140,
+ -140},{-140,-180},{-122,-180}}, color={0,0,127}));
+
+ connect(lesThr2.y, lat2.clr) annotation (Line(points={{-98,-180},{-60,-180},{-60,
+ -146},{-42,-146}}, color={255,0,255}));
+
+ connect(lat2.y, hotWatRes1.u2)
+ annotation (Line(points={{-18,-140},{78,-140}}, color={255,0,255}));
+
+ connect(one.y, hotWatRes1.u1) annotation (Line(points={{22,120},{40,120},{40,-132},
+ {78,-132}}, color={255,127,0}));
+
+ connect(zer.y, hotWatRes1.u3) annotation (Line(points={{22,60},{30,60},{30,-148},
+ {78,-148}}, color={255,127,0}));
+
+ connect(hotWatRes1.y, hotWatRes2.u3) annotation (Line(points={{102,-140},{110,
+ -140},{110,-98},{118,-98}}, color={255,127,0}));
+
+ connect(uHeaCoi_actual, lesThr3.u) annotation (Line(points={{-220,-140},{-140,
+ -140},{-140,-226},{-122,-226}}, color={0,0,127}));
+
+ connect(lesThr3.y, lat3.clr)
+ annotation (Line(points={{-98,-226},{-42,-226}}, color={255,0,255}));
+
+ connect(greThr5.y, lat3.u) annotation (Line(points={{-98,-140},{-80,-140},{-80,
+ -220},{-42,-220}}, color={255,0,255}));
+
+ connect(lat3.y, intSwi1.u2)
+ annotation (Line(points={{-18,-220},{78,-220}}, color={255,0,255}));
+
+ connect(one.y, intSwi1.u1) annotation (Line(points={{22,120},{40,120},{40,-212},
+ {78,-212}}, color={255,127,0}));
+
+ connect(zer.y, intSwi1.u3) annotation (Line(points={{22,60},{30,60},{30,-228},
+ {78,-228}}, color={255,127,0}));
+
+ connect(intSwi1.y, yHotWatPlaReq)
+ annotation (Line(points={{102,-220},{220,-220}}, color={255,127,0}));
+
+ connect(yChiWatResReq, yChiWatResReq)
+ annotation (Line(points={{220,200},{220,200}}, color={255,127,0}));
+
+ connect(uFan, hysFanCoo.u)
+ annotation (Line(points={{-220,240},{-132,240}}, color={0,0,127}));
+
+ connect(hysFanCoo.y, booToIntCoo.u)
+ annotation (Line(points={{-108,240},{-82,240}}, color={255,0,255}));
+
+ connect(chiWatRes3.y, mulIntCoo.u2) annotation (Line(points={{182,200},{188,200},
+ {188,220},{90,220},{90,234},{98,234}}, color={255,127,0}));
+
+ connect(booToIntCoo.y, mulIntCoo.u1) annotation (Line(points={{-58,240},{-20,240},
+ {-20,252},{60,252},{60,246},{98,246}}, color={255,127,0}));
+
+ connect(mulIntCoo.y, yChiWatResReq) annotation (Line(points={{122,240},{194,240},
+ {194,200},{220,200}}, color={255,127,0}));
+
+ connect(hotWatRes3.y, mulIntHea.u2) annotation (Line(points={{182,-40},{186,-40},
+ {186,-20},{104,-20},{104,-6},{108,-6}}, color={255,127,0}));
+
+ connect(hysFanHea.y, booToIntHea.u)
+ annotation (Line(points={{-118,-10},{-92,-10}}, color={255,0,255}));
+
+ connect(booToIntHea.y, mulIntHea.u1) annotation (Line(points={{-68,-10},{100,-10},
+ {100,6},{108,6}}, color={255,127,0}));
+
+ connect(uFan, hysFanHea.u) annotation (Line(points={{-220,240},{-170,240},{
+ -170,-10},{-142,-10}}, color={0,0,127}));
+
+ connect(mulIntHea.y, yHotWatResReq) annotation (Line(points={{132,0},{192,0},{
+ 192,-40},{220,-40}}, color={255,127,0}));
+
+ connect(TSupSet, heaSupTemDif.u1) annotation (Line(points={{-220,160},{-190,160},
+ {-190,-34},{-142,-34}}, color={0,0,127}));
+
+annotation (
+ defaultComponentName="fcuPlaReq",
+ Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{100,100}}),
+ graphics={
+ Rectangle(
+ extent={{-100,-100},{100,100}},
+ lineColor={0,0,127},
+ fillColor={255,255,255},
+ fillPattern=FillPattern.Solid),
+ Text(
+ extent={{-98,48},{-76,32}},
+ textColor={0,0,127},
+ pattern=LinePattern.Dash,
+ textString="TSup"),
+ Text(
+ extent={{-100,160},{100,120}},
+ textColor={0,0,255},
+ textString="%name"),
+ Text(
+ extent={{-98,10},{-60,-8}},
+ textColor={0,0,127},
+ pattern=LinePattern.Dash,
+ textString="TSupSet"),
+ Text(
+ extent={{-98,-32},{-24,-46}},
+ textColor={0,0,127},
+ pattern=LinePattern.Dash,
+ textString="uCooCoi_actual",
+ visible=have_chiWatCoi),
+ Text(
+ extent={{34,72},{98,50}},
+ textColor={255,127,0},
+ pattern=LinePattern.Dash,
+ textString="yChiWatResReq",
+ visible=have_chiWatCoi),
+ Text(
+ extent={{52,32},{98,10}},
+ textColor={255,127,0},
+ pattern=LinePattern.Dash,
+ textString="yChiPlaReq",
+ visible=have_chiWatCoi),
+ Text(
+ extent={{34,-8},{98,-30}},
+ textColor={255,127,0},
+ pattern=LinePattern.Dash,
+ textString="yHotWatResReq",
+ visible=have_hotWatCoi),
+ Text(
+ extent={{38,-48},{98,-70}},
+ textColor={255,127,0},
+ pattern=LinePattern.Dash,
+ textString="yHotWatPlaReq",
+ visible=have_hotWatCoi),
+ Text(
+ extent={{-100,86},{-72,76}},
+ textColor={0,0,127},
+ pattern=LinePattern.Dash,
+ textString="uFan"),
+ Text(
+ extent={{-98,-72},{-24,-86}},
+ textColor={0,0,127},
+ pattern=LinePattern.Dash,
+ textString="uHeaCoi_actual",
+ visible=have_hotWatCoi)}),
+ Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-200,-260},{200,260}})),
+ Documentation(info="
+
This sequence outputs the system reset requests for fan coil unit. The implementation is according to the Section 5.22.8 of ASHRAE Guideline 36, 2021.
+
If there is a chilled-water coil (have_chiWatCoi=true), chilled water reset requests yChiWatResReq
+
+
If the supply air temperature TAirSup exceeds the supply air temperature set point TSupSet by 5.56 °C (10 °F) for 5 minutes, send 3 requests.
+
If the supply air temperature TAirSup exceeds TSupSet by by 2.78 °C (5 °F) for 5 minutes, send 2 requests.
+
Else if the chilled water valve position uCooCoi_actual is greater than 0.95, send 1 request until uCooCoi_actual is less than 0.85.
+
Else if the chilled water valve position uCooCoi_actual is less than 0.85, send 0 requests.
+
+
If there is a chilled-water coil and chilled water plant, chiller plant request yChiPlaReq
+
Send the chiller plant that serves the system a chiller plant request as follows:
+
+
If the chilled water valve position uCooCoi_actual is greater than 0.95, send 1 request until the uCooCoi_actual is less than 0.1.
+
Else if the chilled water valve position uCooCoi_actual is less than 0.1, send 0 request.
+
+
If there is a hot-water coil (have_hotWatCoi=true), hot-water reset requests yHotWatResReq
+
+
If the supply air temperature TAirSup is 17 °C (30 °F) less than the supply air temperature set point TSupSet for 5 minutes, send 3 requests.
+
Else if the supply air temperature TAirSup is 8 °C (15 °F) less than TSupSet for 5 minutes, send 2 requests.
+
Else if the hot water valve position uHeaCoi_actual is greater than 0.95, send 1 request until the uHeaCoi_actual is less than 0.85.
+
Else if the hot water valve position uHeaCoi_actual is less than 0.85, send 0 request.
+
+
If there is a hot-water coil and heating hot-water plant, heating hot-water plant requests yHotWatPlaReq
+
Send the heating hot-water plant that serves the air handling unit a heating hot-water plant request as follows:
+
+
If the hot water valve position uHeaCoi_actual is greater than 0.95, send 1 request until the hot water valve position is less than 0.1.
+
If the hot water valve position uHeaCoi_actual is less than 0.1, send 0 requests.
+
+", revisions="
+
+
+May 6, 2022, by Karthik Devaprasad:
+First implementation.
+
+
+"));
+end PlantRequests;
diff --git a/Buildings/Controls/OBC/ASHRAE/FanCoilUnit/Subsequences/SupplyAirTemperature.mo b/Buildings/Controls/OBC/ASHRAE/FanCoilUnit/Subsequences/SupplyAirTemperature.mo
new file mode 100644
index 00000000000..9357c81b9ba
--- /dev/null
+++ b/Buildings/Controls/OBC/ASHRAE/FanCoilUnit/Subsequences/SupplyAirTemperature.mo
@@ -0,0 +1,514 @@
+within Buildings.Controls.OBC.ASHRAE.FanCoilUnit.Subsequences;
+block SupplyAirTemperature
+ "Subsequence for calculating supply air temperature setpoint"
+
+ parameter Boolean have_cooCoi
+ "Does the fan coil unit have a cooling coil? True: Yes, False: No";
+
+ parameter Boolean have_heaCoi
+ "Does the fan coil unit have a heating coil? True: Yes, False: No";
+
+ parameter Real uHea_min(
+ final unit="1",
+ displayUnit="1") = heaDea
+ "Minimum heating loop signal at which supply air temperature is modified"
+ annotation(Dialog(group="Heating loop",
+ enable = have_heaCoi));
+
+ parameter Real TSupSet_max(
+ final unit="K",
+ displayUnit="degC") = 273.15 + 32
+ "Supply air temperature setpoint at maximum heating loop signal"
+ annotation(Dialog(group="Heating loop",
+ enable = have_heaCoi));
+
+ parameter Real uHea_max(
+ final unit="1",
+ displayUnit="1") = 0.5
+ "Maximum heating loop signal at which supply air temperature is modified"
+ annotation(Dialog(group="Heating loop",
+ enable = have_heaCoi));
+
+ parameter Real uCoo_min(
+ final unit="1",
+ displayUnit="1") = cooDea
+ "Minimum cooling loop signal at which supply air temperature is modified"
+ annotation(Dialog(group="Cooling loop",
+ enable = have_cooCoi));
+
+ parameter Real TSupSet_min(
+ final unit="K",
+ displayUnit="degC") = 273.15+12.8
+ "Supply air temperature setpoint at maximum cooling loop signal"
+ annotation(Dialog(group="Cooling loop",
+ enable = have_cooCoi));
+
+ parameter Real uCoo_max(
+ final unit="1",
+ displayUnit="1") = 0.5
+ "Maximum cooling loop signal at which supply air temperature is modified"
+ annotation(Dialog(group="Cooling loop",
+ enable = have_cooCoi));
+
+ parameter Real heaDea(
+ final unit="1",
+ displayUnit="1") = 0.05
+ "Heating loop signal limit above which setpoint operation changes from deadband mode to heating mode"
+ annotation(Dialog(group="Deadband",
+ enable = have_heaCoi));
+
+ parameter Real cooDea(
+ final unit="1",
+ displayUnit="1") = 0.05
+ "Cooling loop signal limit above which setpoint operation changes from deadband mode to cooling mode"
+ annotation(Dialog(group="Deadband",
+ enable = have_cooCoi));
+
+ parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerTypeCooCoi=Buildings.Controls.OBC.CDL.Types.SimpleController.PI
+ "Type of cooling coil controller"
+ annotation(Dialog(tab="PID controller parameters", group="Cooling coil"));
+
+ parameter Real kCooCoi(
+ final unit="1",
+ displayUnit="1")=1
+ "Controller gain"
+ annotation(Dialog(tab="PID controller parameters", group="Cooling coil"));
+
+ parameter Real TiCooCoi(
+ final unit="s",
+ displayUnit="s",
+ final quantity="time")=0.5
+ "Integrator time constant"
+ annotation(Dialog(tab="PID controller parameters", group="Cooling coil",
+ enable = controllerTypeCooCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PI or
+ controllerTypeCooCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PID));
+
+ parameter Real TdCooCoi(
+ final unit="s",
+ displayUnit="s",
+ final quantity="time")=0.1
+ "Derivative block time constant"
+ annotation(Dialog(tab="PID controller parameters", group="Cooling coil",
+ enable = controllerTypeCooCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PD or
+ controllerTypeCooCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PID));
+
+ parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerTypeHeaCoi=Buildings.Controls.OBC.CDL.Types.SimpleController.PI
+ "Type of heating coil controller"
+ annotation(Dialog(tab="PID controller parameters", group="Heating coil"));
+
+ parameter Real kHeaCoi(
+ final unit="1",
+ displayUnit="1")=1
+ "Controller gain"
+ annotation(Dialog(tab="PID controller parameters", group="Heating coil"));
+
+ parameter Real TiHeaCoi(
+ final unit="s",
+ displayUnit="s",
+ final quantity="time")=0.5
+ "Integrator block time constant"
+ annotation(Dialog(tab="PID controller parameters", group="Heating coil",
+ enable = controllerTypeHeaCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PI or
+ controllerTypeHeaCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PID));
+
+ parameter Real TdHeaCoi(
+ final unit="s",
+ displayUnit="s",
+ final quantity="time")=0.1
+ "Derivative block time constant"
+ annotation(Dialog(tab="PID controller parameters", group="Heating coil",
+ enable = controllerTypeHeaCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PD or
+ controllerTypeHeaCoi == Buildings.Controls.OBC.CDL.Types.SimpleController.PID));
+
+ parameter Real deaHysLim(
+ final unit="1",
+ displayUnit="1") = 0.01
+ "Hysteresis limits for deadband mode transitions"
+ annotation(Dialog(tab="Advanced"));
+
+ Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Fan
+ "Fan proven on signal"
+ annotation (Placement(transformation(extent={{-160,120},{-120,160}}),
+ iconTransformation(extent={{-140,80},{-100,120}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput uHea(
+ final unit="1",
+ displayUnit="1") if have_heaCoi
+ "Heating loop signal"
+ annotation (Placement(transformation(extent={{-160,20},{-120,60}}),
+ iconTransformation(extent={{-140,0},{-100,40}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput uCoo(
+ final unit="1",
+ displayUnit="1") if have_cooCoi
+ "Cooling loop signal"
+ annotation (Placement(transformation(extent={{-160,-60},{-120,-20}}),
+ iconTransformation(extent={{-140,-80},{-100,-40}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput TAirSup(
+ final unit="K",
+ displayUnit="K",
+ final quantity="ThermodynamicTemperature")
+ "Measured supply air temperature"
+ annotation (Placement(transformation(extent={{-160,-20},{-120,20}}),
+ iconTransformation(extent={{-140,-40},{-100,0}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput TZonHeaSet(
+ final unit="K",
+ displayUnit="K",
+ final quantity="ThermodynamicTemperature") if have_heaCoi
+ "Zone heating temperature setpoint"
+ annotation (Placement(transformation(extent={{-160,60},{-120,100}}),
+ iconTransformation(extent={{-140,40},{-100,80}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealInput TZonCooSet(
+ final unit="K",
+ displayUnit="K",
+ final quantity="ThermodynamicTemperature") if have_cooCoi
+ "Zone cooling temperature setpoint"
+ annotation (Placement(transformation(extent={{-160,-140},{-120,-100}}),
+ iconTransformation(extent={{-140,-120},{-100,-80}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealOutput yHeaCoi(
+ final unit="1",
+ displayUnit="1") if have_heaCoi
+ "Heating coil signal"
+ annotation (Placement(transformation(extent={{120,40},{160,80}}),
+ iconTransformation(extent={{100,40},{140,80}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealOutput yCooCoi(
+ final unit="1",
+ displayUnit="1") if have_cooCoi
+ "Cooling coil signal"
+ annotation (Placement(transformation(extent={{120,-80},{160,-40}}),
+ iconTransformation(extent={{100,-80},{140,-40}})));
+
+ Buildings.Controls.OBC.CDL.Interfaces.RealOutput TSupSet(
+ final unit="K",
+ displayUnit="K",
+ final quantity="ThermodynamicTemperature")
+ "Supply air temperature setpoint"
+ annotation (Placement(transformation(extent={{120,-20},{160,20}}),
+ iconTransformation(extent={{100,-20},{140,20}})));
+
+protected
+ Buildings.Controls.OBC.CDL.Continuous.Switch swiDeaCoo
+ "Switch for turning on cooling mode from deadband mode"
+ annotation (Placement(transformation(extent={{0,-30},{20,-10}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Switch swiCooCoi
+ "Switch cooling coil signal to zero in deadband mode"
+ annotation (Placement(transformation(extent={{70,-110},{90,-90}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Switch swiHeaCoi
+ "Switch heating coil signal to zero in deadband mode"
+ annotation (Placement(transformation(extent={{50,80},{70,100}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Line linTHeaSupAir
+ "Convert heating loop signal to supply air temperature setpoint"
+ annotation (Placement(transformation(extent={{-60,50},{-40,70}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Line linTCooSupAir
+ "Convert cooling loop signal to supply air temperature setpoint"
+ annotation (Placement(transformation(extent={{-60,-70},{-40,-50}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conTSupSet_max(
+ final k=TSupSet_max)
+ "Maximum heating supply air temperature setpoint limit signal"
+ annotation (Placement(transformation(extent={{-110,90},{-90,110}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conUHea_min(
+ final k=uHea_min)
+ "Minimum heating loop signal support point"
+ annotation (Placement(transformation(extent={{-110,10},{-90,30}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conTSupSet_min(
+ final k=TSupSet_min)
+ "Minimum cooling supply air temperature setpoint limit signal"
+ annotation (Placement(transformation(extent={{-110,-30},{-90,-10}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conUCoo_min(
+ final k=uCoo_min)
+ "Minimum cooling loop signal support point"
+ annotation (Placement(transformation(extent={{-110,-70},{-90,-50}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.PID conPIDHea(
+ final controllerType=controllerTypeHeaCoi,
+ final k=kHeaCoi,
+ final Ti=TiHeaCoi,
+ final Td=TdHeaCoi) "PID controller for heating coil"
+ annotation (Placement(transformation(extent={{20,50},{40,70}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.PID conPIDCoo(
+ final controllerType=controllerTypeCooCoi,
+ final k=kCooCoi,
+ final Ti=TiCooCoi,
+ final Td=TdCooCoi,
+ final reverseActing=false) "PID controller for cooling coil"
+ annotation (Placement(transformation(extent={{40,-70},{60,-50}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Hysteresis hysDeaHea(
+ final uLow=heaDea-deaHysLim,
+ final uHigh=heaDea)
+ "Hysteresis for switching between deadband mode and heating mode"
+ annotation (Placement(transformation(extent={{-40,90},{-20,110}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conZerHeaMod(
+ final k=0) if not have_heaCoi
+ "Constant zero signal for heating mode"
+ annotation (Placement(transformation(extent={{-70,90},{-50,110}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Switch swiDeaHea
+ "Switch for turning on heating mode from deadband mode"
+ annotation (Placement(transformation(extent={{-20,50},{0,70}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Hysteresis hysDeaCoo(
+ final uLow=cooDea-deaHysLim,
+ final uHigh=cooDea)
+ "Hysteresis for switching on cooling mode from deadband mode"
+ annotation (Placement(transformation(extent={{-40,-30},{-20,-10}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conZerCooMod(
+ final k=0) if not have_cooCoi
+ "Constant zero signal for cooling mode"
+ annotation (Placement(transformation(extent={{-100,-150},{-80,-130}})));
+
+ Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea2
+ "Boolean to Real conversion"
+ annotation (Placement(transformation(extent={{60,130},{80,150}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Multiply mul2
+ "Output heating coil signal only when fan is proven on"
+ annotation (Placement(transformation(extent={{90,50},{110,70}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Multiply mul3
+ "Output cooling coil signal only when fan is proven on"
+ annotation (Placement(transformation(extent={{90,-70},{110,-50}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conUHea_max(
+ final k=uHea_max)
+ "Maximum heating loop signal support point"
+ annotation (Placement(transformation(extent={{-80,10},{-60,30}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conUCoo_max(
+ final k=uCoo_max)
+ "Maximum cooling loop signal support point"
+ annotation (Placement(transformation(extent={{-110,-110},{-90,-90}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant conZer(
+ final k=0)
+ "Constant zero signal"
+ annotation (Placement(transformation(extent={{0,10},{20,30}})));
+
+equation
+ connect(uHea, linTHeaSupAir.u) annotation (Line(points={{-140,40},{-74,40},{-74,
+ 60},{-62,60}}, color={0,0,127}));
+
+ connect(uCoo, linTCooSupAir.u) annotation (Line(points={{-140,-40},{-66,-40},{
+ -66,-60},{-62,-60}}, color={0,0,127}));
+
+ connect(TAirSup, conPIDHea.u_m)
+ annotation (Line(points={{-140,0},{30,0},{30,48}}, color={0,0,127}));
+
+ connect(TAirSup, conPIDCoo.u_m) annotation (Line(points={{-140,0},{30,0},{30,-78},
+ {50,-78},{50,-72}}, color={0,0,127}));
+
+ connect(linTHeaSupAir.y, swiDeaHea.u1) annotation (Line(points={{-38,60},{-30,
+ 60},{-30,68},{-22,68}}, color={0,0,127}));
+
+ connect(conZerHeaMod.y, hysDeaHea.u)
+ annotation (Line(points={{-48,100},{-42,100}}, color={0,0,127}));
+
+ connect(conZerHeaMod.y, linTHeaSupAir.u) annotation (Line(points={{-48,100},{-46,
+ 100},{-46,76},{-74,76},{-74,60},{-62,60}}, color={0,0,127}));
+
+ connect(uHea, hysDeaHea.u) annotation (Line(points={{-140,40},{-74,40},{-74,76},
+ {-46,76},{-46,100},{-42,100}}, color={0,0,127}));
+
+ connect(hysDeaHea.y, swiDeaHea.u2) annotation (Line(points={{-18,100},{-10,100},
+ {-10,80},{-26,80},{-26,60},{-22,60}}, color={255,0,255}));
+
+ connect(conZerCooMod.y, linTCooSupAir.u) annotation (Line(points={{-78,-140},{
+ -66,-140},{-66,-60},{-62,-60}}, color={0,0,127}));
+
+ connect(hysDeaCoo.y, swiDeaCoo.u2)
+ annotation (Line(points={{-18,-20},{-2,-20}}, color={255,0,255}));
+
+ connect(uCoo, hysDeaCoo.u) annotation (Line(points={{-140,-40},{-66,-40},{-66,
+ -20},{-42,-20}}, color={0,0,127}));
+
+ connect(conZerCooMod.y, hysDeaCoo.u) annotation (Line(points={{-78,-140},{-66,
+ -140},{-66,-20},{-42,-20}}, color={0,0,127}));
+
+ connect(swiDeaHea.y, swiDeaCoo.u3) annotation (Line(points={{2,60},{8,60},{8,40},
+ {-10,40},{-10,-28},{-2,-28}}, color={0,0,127}));
+
+ connect(linTCooSupAir.y, swiDeaCoo.u1) annotation (Line(points={{-38,-60},{-14,
+ -60},{-14,-12},{-2,-12}}, color={0,0,127}));
+
+ connect(swiDeaCoo.y, conPIDHea.u_s) annotation (Line(points={{22,-20},{36,-20},
+ {36,40},{12,40},{12,60},{18,60}}, color={0,0,127}));
+
+ connect(swiDeaCoo.y, conPIDCoo.u_s) annotation (Line(points={{22,-20},{36,-20},
+ {36,-60},{38,-60}}, color={0,0,127}));
+
+ connect(conTSupSet_max.y, linTHeaSupAir.f2) annotation (Line(points={{-88,100},
+ {-80,100},{-80,52},{-62,52}}, color={0,0,127}));
+
+ connect(conTSupSet_min.y, linTCooSupAir.f2) annotation (Line(points={{-88,-20},
+ {-70,-20},{-70,-68},{-62,-68}}, color={0,0,127}));
+
+ connect(TZonHeaSet, linTHeaSupAir.f1) annotation (Line(points={{-140,80},{-74,
+ 80},{-74,64},{-62,64}}, color={0,0,127}));
+
+ connect(TZonCooSet, linTCooSupAir.f1) annotation (Line(points={{-140,-120},{-64,
+ -120},{-64,-56},{-62,-56}}, color={0,0,127}));
+
+ connect(TAirSup, swiDeaHea.u3) annotation (Line(points={{-140,0},{-30,0},{-30,
+ 52},{-22,52}}, color={0,0,127}));
+
+ connect(conZerHeaMod.y, linTHeaSupAir.f1) annotation (Line(points={{-48,100},{
+ -46,100},{-46,76},{-74,76},{-74,64},{-62,64}}, color={0,0,127}));
+
+ connect(conZerCooMod.y, linTCooSupAir.f1) annotation (Line(points={{-78,-140},
+ {-66,-140},{-66,-56},{-62,-56}}, color={0,0,127}));
+
+ connect(swiDeaCoo.y, TSupSet) annotation (Line(points={{22,-20},{36,-20},{36,0},
+ {140,0}}, color={0,0,127}));
+
+ connect(u1Fan, booToRea2.u)
+ annotation (Line(points={{-140,140},{58,140}}, color={255,0,255}));
+ connect(yHeaCoi, mul2.y)
+ annotation (Line(points={{140,60},{112,60}}, color={0,0,127}));
+ connect(booToRea2.y, mul2.u1) annotation (Line(points={{82,140},{86,140},{86,66},
+ {88,66}}, color={0,0,127}));
+ connect(mul3.y, yCooCoi) annotation (Line(points={{112,-60},{124,-60},{124,-60},
+ {140,-60}}, color={0,0,127}));
+ connect(booToRea2.y, mul3.u1) annotation (Line(points={{82,140},{86,140},{86,-54},
+ {88,-54}}, color={0,0,127}));
+ connect(conUHea_max.y, linTHeaSupAir.x2) annotation (Line(points={{-58,20},{-52,
+ 20},{-52,40},{-68,40},{-68,56},{-62,56}}, color={0,0,127}));
+ connect(conUHea_min.y, linTHeaSupAir.x1) annotation (Line(points={{-88,20},{-84,
+ 20},{-84,68},{-62,68}}, color={0,0,127}));
+ connect(conUCoo_min.y, linTCooSupAir.x1) annotation (Line(points={{-88,-60},{
+ -86,-60},{-86,-52},{-62,-52}}, color={0,0,127}));
+ connect(conUCoo_max.y, linTCooSupAir.x2) annotation (Line(points={{-88,-100},
+ {-80,-100},{-80,-64},{-62,-64}}, color={0,0,127}));
+ connect(conPIDCoo.y, swiCooCoi.u1) annotation (Line(points={{62,-60},{66,-60},
+ {66,-92},{68,-92}}, color={0,0,127}));
+ connect(swiCooCoi.y, mul3.u2) annotation (Line(points={{92,-100},{100,-100},{100,
+ -80},{86,-80},{86,-66},{88,-66}}, color={0,0,127}));
+ connect(hysDeaCoo.y, swiCooCoi.u2) annotation (Line(points={{-18,-20},{-6,-20},
+ {-6,-100},{68,-100}}, color={255,0,255}));
+ connect(swiHeaCoi.y, mul2.u2) annotation (Line(points={{72,90},{80,90},{80,54},
+ {88,54}}, color={0,0,127}));
+ connect(conPIDHea.y, swiHeaCoi.u1) annotation (Line(points={{42,60},{44,60},{44,
+ 98},{48,98}}, color={0,0,127}));
+ connect(hysDeaHea.y, swiHeaCoi.u2) annotation (Line(points={{-18,100},{-10,100},
+ {-10,90},{48,90}}, color={255,0,255}));
+ connect(conZer.y, swiHeaCoi.u3) annotation (Line(points={{22,20},{46,20},{46,82},
+ {48,82}}, color={0,0,127}));
+ connect(conZer.y, swiCooCoi.u3) annotation (Line(points={{22,20},{46,20},{46,-40},
+ {64,-40},{64,-108},{68,-108}}, color={0,0,127}));
+ annotation (defaultComponentName="TSupAir",
+ Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-120},{100,120}}),
+ graphics={
+ Rectangle(
+ extent={{-100,-120},{100,120}},
+ lineColor={0,0,127},
+ fillColor={255,255,255},
+ fillPattern=FillPattern.Solid),
+ Text(
+ extent={{-110,160},{110,120}},
+ textString="%name",
+ textColor={0,0,255}),
+ Text(
+ extent={{-96,110},{-50,90}},
+ textColor={255,0,255},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="u1Fan"),
+ Text(
+ extent={{-96,70},{-20,48}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="TZonHeaSet",
+ visible=have_heaCoi),
+ Text(
+ extent={{-100,30},{-52,10}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="uHea",
+ visible=have_heaCoi),
+ Text(
+ extent={{-96,-10},{-46,-28}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="TAirSup"),
+ Text(
+ extent={{-100,-50},{-52,-70}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="uCoo",
+ visible=have_cooCoi),
+ Text(
+ extent={{38,70},{96,50}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="yHeaCoi",
+ visible=have_heaCoi),
+ Text(
+ extent={{-96,-90},{-20,-112}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="TZonCooSet",
+ visible=have_cooCoi),
+ Text(
+ extent={{20,12},{96,-10}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="TSupSet"),
+ Text(
+ extent={{38,-50},{96,-70}},
+ textColor={0,0,127},
+ fillColor={0,0,0},
+ fillPattern=FillPattern.Solid,
+ textString="yCooCoi",
+ visible=have_cooCoi)}), Diagram(coordinateSystem(
+ preserveAspectRatio=false, extent={{-120,-160},{120,160}})),
+ Documentation(info="
+
Block that outputs the supply air temperature setpoint, as well as the control signals for the cooling and heating coils in a fan coil unit system.
+The implemented sequence is based on ASHRAE Guideline 36, 2021, Part 5.22.4.
+
The supply air temperature
+TSupSet is varied from the zone cooling setpoint temperature
+TZonCooSet to the minimum supply air temperature for cooling
+TSupSet_min, when the cooling loop signal
+uCoo varies from the minimum limit
+uCoo_min to the maximum limit
+uCoo_max.
+Similarly, TSupSet is varied from the zone heating setpoint temperature
+TZonHeaSet to the maximum supply air temperature for heating
+TSupSet_max, when the heating loop signal
+uHea varies from the minimum limit
+uHea_min to the maximum limit
+uHea_max. The setpoint in deadband mode is equal to the current
+measured supply air temperature TAirSup.
+yCooCoi and yHeaCoi are set to zero when the fan proven on signal
+u1Fan is false.
+
+", revisions="
+
+
+ March 17, 2022, by Karthik Devaprasad:
+ First implementation.
+
+ This example validates
+
+ Buildings.Controls.OBC.ASHRAE.FanCoilUnit.Subsequences.FanSpeed.
+ Each of the six instances of the controller represents operation with different
+ inputs for heating and cooling loop signals, as well as the operating mode
+ and fan proven on signal, and different configuration
+ parameters of fan coil unit with presence or absence of heating and cooling
+ coils, as described by the comment for each instance.
+
+ ", revisions="
+
+
+ March 18, 2022, by Karthik Devaprasad:
+ First implementation.
+
+
+ "));
+end FanSpeed;
diff --git a/Buildings/Controls/OBC/ASHRAE/FanCoilUnit/Subsequences/Validation/PlantRequests.mo b/Buildings/Controls/OBC/ASHRAE/FanCoilUnit/Subsequences/Validation/PlantRequests.mo
new file mode 100644
index 00000000000..30c40e97041
--- /dev/null
+++ b/Buildings/Controls/OBC/ASHRAE/FanCoilUnit/Subsequences/Validation/PlantRequests.mo
@@ -0,0 +1,202 @@
+within Buildings.Controls.OBC.ASHRAE.FanCoilUnit.Subsequences.Validation;
+model PlantRequests
+ "Validation model for subsequence for calculating the plant requests"
+
+ Buildings.Controls.OBC.ASHRAE.FanCoilUnit.Subsequences.PlantRequests plaReq
+ "Calculate plant request"
+ annotation (Placement(transformation(extent={{60,50},{80,70}})));
+
+ Buildings.Controls.OBC.ASHRAE.FanCoilUnit.Subsequences.PlantRequests plaReq1(
+ final have_hotWatCoi=false)
+ "Calculate plant request"
+ annotation (Placement(transformation(extent={{60,-80},{80,-60}})));
+
+ Buildings.Controls.OBC.ASHRAE.FanCoilUnit.Subsequences.PlantRequests plaReq2(
+ final have_chiWatCoi=false)
+ "Calculate plant request"
+ annotation (Placement(transformation(extent={{60,-160},{80,-140}})));
+
+protected
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Pulse fanSpe(
+ final width=0.8,
+ final period=3600)
+ "Fan speed signal"
+ annotation (Placement(transformation(extent={{10,70},{30,90}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Pulse fanSpe1(
+ final width=0.8,
+ final period=3600)
+ "Fan speed signal"
+ annotation (Placement(transformation(extent={{20,-30},{40,-10}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Pulse fanSpe2(
+ final width=0.8,
+ final period=3600)
+ "Fan speed signal"
+ annotation (Placement(transformation(extent={{20,-110},{40,-90}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Ramp supTem(
+ final height=16,
+ final offset=273.15 + 15,
+ final duration=3600)
+ "Supply air temperature"
+ annotation (Placement(transformation(extent={{-80,-50},{-60,-30}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Ramp supTemSet(
+ final height=6,
+ final offset=273.15 + 14.5,
+ final duration=3600)
+ "Supply air temperature setpoint"
+ annotation (Placement(transformation(extent={{-40,-70},{-20,-50}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Ramp cooCoi(
+ final height=-0.3,
+ final offset=0.96,
+ final duration=3600,
+ final startTime=1000)
+ "Cooling coil position"
+ annotation (Placement(transformation(extent={{-80,-90},{-60,-70}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Ramp heaCoi(
+ final height=-0.3,
+ final offset=0.96,
+ final duration=3600,
+ final startTime=1000)
+ "Heating coil position"
+ annotation (Placement(transformation(extent={{-80,-10},{-60,10}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Ramp supTem1(
+ final height=8,
+ final offset=273.15 + 12,
+ final duration=3600)
+ "Cooling supply air temperature"
+ annotation (Placement(transformation(extent={{-80,70},{-60,90}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Ramp supTemSet1(
+ final height=25,
+ final offset=273.15 + 20,
+ final duration=3600)
+ "Supply air temperature setpoint"
+ annotation (Placement(transformation(extent={{-40,50},{-20,70}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Constant cooCoi1(
+ final k=0)
+ "Cooling coil position"
+ annotation (Placement(transformation(extent={{-80,30},{-60,50}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Ramp supTem3(
+ final height=8,
+ final offset=273.15 + 15,
+ final duration=3600)
+ "Supply air temperature"
+ annotation (Placement(transformation(extent={{-80,-130},{-60,-110}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Ramp supTemSet2(
+ final height=6,
+ final offset=273.15 + 14.5,
+ final duration=3600)
+ "Supply air temperature setpoint"
+ annotation (Placement(transformation(extent={{-40,-150},{-20,-130}})));
+
+ Buildings.Controls.OBC.CDL.Continuous.Sources.Ramp heaCoi2(
+ final height=-0.3,
+ final offset=0.96,
+ final duration=3600,
+ final startTime=1000)
+ "Heating coil position"
+ annotation (Placement(transformation(extent={{-80,-170},{-60,-150}})));
+
+equation
+ connect(supTem.y, plaReq1.TAirSup) annotation (Line(points={{-58,-40},{20,-40},
+ {20,-66},{58,-66}}, color={0,0,127}));
+
+ connect(cooCoi.y, plaReq1.uCooCoi_actual) annotation (Line(points={{-58,-80},{
+ 20,-80},{20,-73.8},{58,-73.8}},
+ color={0,0,127}));
+
+ connect(supTem1.y, plaReq.TAirSup) annotation (Line(points={{-58,80},{0,80},{0,
+ 64},{58,64}}, color={0,0,127}));
+
+ connect(cooCoi1.y, plaReq.uCooCoi_actual) annotation (Line(points={{-58,40},{10,
+ 40},{10,56.2},{58,56.2}},color={0,0,127}));
+
+ connect(heaCoi.y, plaReq.uHeaCoi_actual) annotation (Line(points={{-58,0},{30,
+ 0},{30,52},{58,52}}, color={0,0,127}));
+
+ connect(supTemSet1.y,plaReq.TSupSet) annotation (Line(points={{-18,60},{0,60},
+ {0,60},{58,60}}, color={0,0,127}));
+
+ connect(supTemSet.y,plaReq1.TSupSet) annotation (Line(points={{-18,-60},{0,-60},
+ {0,-70},{58,-70}}, color={0,0,127}));
+
+ connect(fanSpe.y, plaReq.uFan) annotation (Line(points={{32,80},{50,80},{50,
+ 68},{58,68}}, color={0,0,127}));
+
+ connect(fanSpe1.y, plaReq1.uFan) annotation (Line(points={{42,-20},{52,-20},
+ {52,-62},{58,-62}}, color={0,0,127}));
+
+ connect(supTem3.y, plaReq2.TAirSup) annotation (Line(points={{-58,-120},{20,-120},
+ {20,-146},{58,-146}}, color={0,0,127}));
+
+ connect(supTemSet2.y, plaReq2.TSupSet) annotation (Line(points={{-18,-140},{0,
+ -140},{0,-150},{58,-150}}, color={0,0,127}));
+
+ connect(fanSpe2.y, plaReq2.uFan) annotation (Line(points={{42,-100},{52,-100},
+ {52,-142},{58,-142}}, color={0,0,127}));
+
+ connect(heaCoi2.y, plaReq2.uHeaCoi_actual) annotation (Line(points={{-58,-160},
+ {52,-160},{52,-158},{58,-158}}, color={0,0,127}));
+
+annotation (
+ experiment(StopTime=3600, Tolerance=1e-6),
+ __Dymola_Commands(file="modelica://Buildings/Resources/Scripts/Dymola/Controls/OBC/ASHRAE/FanCoilUnit/Subsequences/Validation/PlantRequests.mos"
+ "Simulate and plot"),
+ Documentation(info="
+
+plaReq represents a controller instance for a system with both
+heating and cooling coils.
+
+
+plaReq1 represents a controller instance for a system with just a
+cooling coil.
+
+
+plaReq2 represents a controller instance for a system with just a
+heating coil.
+
+
+
+
+Each instance is subjected to an increasing deviation of the measured supply
+temperature TAirSup from the supply temperature setpoint TSupSet
+that results in an increasing number of requests from the controllers.
+
+", revisions="
+
+
+May 5,2022 by Karthik Devaprasad:
+First implementation.
+
+ This example validates
+
+ Buildings.Controls.OBC.ASHRAE.FanCoilUnit.Subsequences.SupplyAirTemperature.
+ Each of the four instances of the controller represents operation with different
+ inputs for heating and cooling loop signals, and different configuration
+ parameters of fan coil unit with presence or absence of heating and cooling
+ coils, as described in the instance comments.
+
+ ", revisions="
+
+
+ March 18, 2022, by Karthik Devaprasad:
+ First implementation.
+
+This example validates
+
+Buildings.Controls.OBC.ASHRAE.FanCoilUnit.Controller.
+
+conFCU represents an instance of the controller with heating mode
+operation, with the open-loop signals for measured zone temperature and measured
+supply air temperature increasing with time.
+
+conFCU1 represents an instance of the controller with cooling mode
+operation, with the open-loop signals for measured zone temperature and measured
+supply air temperature decreasing with time.
+
+conFCU2 and conFCU3 represent instances of the controller
+with cooling mode operation, with different parameter settings for the window and occupancy sensors.
+
+", revisions="
+
+
+March 22, 2022, by Karthik Devaprasad:
+First implementation.
+
+ This package implements control modules for the fan coil unit as per the sequence
+ of operations defined in ASHRAE Guideline 36-2021, section 5.22.
+
+ ", revisions="
+
+
+ March 22, 2022, by Karthik Devaprasad:
+ First implementation.
+