Block that outputs the zone group status. This sequence sums up the zone level status calculation to find the outputs that are
needed to define the zone group operation mode.

within Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups;
block GroupStatus "Block that outputs the zone group status"

  parameter Integer nBuiZon(
    final min=1)=5
    "Total number of zones in building"
  parameter Integer nGroZon(
    final min=1)=nBuiZon
    "Total number of zones in the group"
  parameter Boolean zonGroMsk[nBuiZon]=fill(true, nBuiZon)
    "Boolean array mask of zones included in group"
  parameter Real uLow(
    final unit="K",
    final quantity="TemperatureDifference")=-0.1
    "Low limit of the hysteresis for checking temperature difference"
  parameter Real uHigh(
    final unit="K",
    final quantity="TemperatureDifference")=0.1
    "High limit of the hysteresis for checking temperature difference"

  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput zonOcc[nBuiZon]
    "True when the zone is set to be occupied due to the override"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Occ[nBuiZon]
    "True when the zone is occupied according to the occupancy schedule"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput tNexOcc[nBuiZon](
    final unit=fill("s", nBuiZon),
    final quantity=fill("Time", nBuiZon)) "Time to next occupied period"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput uCooTim[nBuiZon](
    final unit=fill("s", nBuiZon),
    final quantity=fill("Time", nBuiZon)) "Cool down time"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput uWarTim[nBuiZon](
    final unit=fill("s", nBuiZon),
    final quantity=fill("Time", nBuiZon)) "Warm-up time"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1OccHeaHig[nBuiZon]
    "True when the zone temperature is lower than the occupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1HigOccCoo[nBuiZon]
    "True when the zone temperature is higher than the occupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1UnoHeaHig[nBuiZon]
    "True when the zone temperature is lower than the unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput THeaSetOff[nBuiZon](
    final unit=fill("K", nBuiZon),
    displayUnit=fill("degC", nBuiZon),
    final quantity=fill("ThermodynamicTemperature", nBuiZon))
    "Zone unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1EndSetBac[nBuiZon]
    "True when the zone could end the setback mode"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1HigUnoCoo[nBuiZon]
    "True when the zone temperature is higher than its unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TCooSetOff[nBuiZon](
    final unit=fill("K", nBuiZon),
    displayUnit=fill("degC", nBuiZon),
    final quantity=fill("ThermodynamicTemperature", nBuiZon))
    "Zone unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1EndSetUp[nBuiZon]
    "True when the zone could end the setup mode"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TZon[nBuiZon](
    final unit=fill("K", nBuiZon),
    displayUnit=fill("degC", nBuiZon),
    final quantity=fill("ThermodynamicTemperature", nBuiZon)) "Zone temperature"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Win[nBuiZon]
    "Window status, normally closed (true), when windows open, it becomes false. For zone without sensor, it is true"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput uGroOcc
    "True when the zone group is in occupied mode"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput nexOcc(
    final quantity="Time",
    final unit="s") "Time to next occupied period"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yCooTim(
    final unit="s",
    final quantity="Time") "Cool down time"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yWarTim(
    final unit="s",
    final quantity="Time") "Warm-up time"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yOccHeaHig
    "True when there is zone with temperature being lower than the occupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yHigOccCoo
    "True when there is zone with temperature being higher than the occupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput yColZon
    "Total number of cold zones"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput ySetBac
    "Run setback mode"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yEndSetBac
    "True when the group should end setback mode"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput yHotZon
    "Total number of hot zones"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput ySetUp
    "Run setup mode"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yEndSetUp
    "True when the group should end setup mode"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput TZonMax(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature")
    "Maximum zone temperature in the zone group"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput TZonMin(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature")
    "Minimum zone temperature in the zone group"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput yOpeWin
    "Total number of open windows"
  Buildings.Controls.OBC.CDL.Logical.Not not1[nGroZon] "Logical not"
protected
  Buildings.Controls.OBC.CDL.Reals.MultiMax cooDowTim(
    final nin=nGroZon)
    "Longest cooldown time"
  Buildings.Controls.OBC.CDL.Reals.MultiMax warUpTim(
    final nin=nGroZon)
    "Longest warm up time"
  Buildings.Controls.OBC.CDL.Logical.MultiOr mulOr(
    final nin=nGroZon)
    "Check if there is any zone that the zone temperature is lower than its occupied heating setpoint"
  Buildings.Controls.OBC.CDL.Logical.MultiOr mulOr1(
    final nin=nGroZon)
    "Check if there is any zone that the zone temperature is higher than its occupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Reals.MultiMax maxTem(
    final nin=nGroZon)
    "Maximum zone temperature in the zone group"
  Buildings.Controls.OBC.CDL.Reals.MultiMin minTem(
    final nin=nGroZon)
    "Minimum zone temperature in the zone group"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt[nGroZon]
    "Convert boolean to integer"
  Buildings.Controls.OBC.CDL.Integers.MultiSum totColZon(
    final nin=nGroZon) "Total number of cold zone"
  Buildings.Controls.OBC.CDL.Logical.MultiAnd endSetBac(
    final nin=nGroZon)
    "Check if all zones have ended the setback mode"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt1[nGroZon]
    "Convert boolean to integer"
  Buildings.Controls.OBC.CDL.Integers.MultiSum totHotZon(
    final nin=nGroZon) "Total number of hot zones"
  Buildings.Controls.OBC.CDL.Logical.MultiAnd endSetUp(
    final nin=nGroZon)
    "Check if all zones have ended the setup mode"
  Buildings.Controls.OBC.CDL.Reals.MultiSum sumUnoHea(
    final nin=nGroZon)
    "Sum of all zones unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Reals.Subtract difUnoHea
    "Difference between unoccupied heating setpoint and zone temperature"
  Buildings.Controls.OBC.CDL.Reals.Divide div1 "Average difference"
  Buildings.Controls.OBC.CDL.Integers.Sources.Constant totZon(
    final k=nBuiZon) "Total number of zones"
  Buildings.Controls.OBC.CDL.Conversions.IntegerToReal intToRea "Convert integer to real"
  Buildings.Controls.OBC.CDL.Reals.MultiSum sumUnoCoo(
    final nin=nGroZon)
    "Sum of all zones unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Reals.MultiSum sumTem(
    final nin=nGroZon)
    "Sum of all zones temperature"
  Buildings.Controls.OBC.CDL.Reals.Subtract difUnoCoo
    "Difference between unoccupied cooling setpoint and zone temperature"
  Buildings.Controls.OBC.CDL.Reals.Divide div2 "Average difference"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys(
    final uLow=uLow,
    final uHigh=uHigh)
    "Hysteresis that outputs if the group should run in setback mode"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys1(
    final uLow=uLow,
    final uHigh=uHigh)
    "Hysteresis that outputs if the group should run in setup mode"
  Buildings.Controls.OBC.CDL.Reals.MultiMin minToNexOcc(
    final nin=nGroZon)
    "Minimum time to next occupied period"
  Buildings.Controls.OBC.CDL.Logical.MultiOr schOcc(
    final nin=nGroZon)
    "Check if the group should be in occupied mode according to the schedule"
  Buildings.Controls.OBC.CDL.Logical.MultiOr oveRidOcc(
    final nin=nGroZon)
    "Check if the group should be in occupied mode according to the zone override"
  Buildings.Controls.OBC.CDL.Logical.Or groOcc
    "Check if the group should be in occupied mode according to the schedule or the zone override"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt2[nGroZon]
    "Convert boolean to integer"
  Buildings.Controls.OBC.CDL.Integers.MultiSum totOpeWin(
    final nin=nGroZon)
    "Total number of opening windows"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea(
    final realTrue=0,
    final realFalse=1)
    "When any zone becomes occpuied, output zero"
  Buildings.Controls.OBC.CDL.Reals.Multiply pro
    "When it is occupied, output zero"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorFilter zonOccFil(
    final nin=nBuiZon,
    final nout=nGroZon,
    final msk=zonGroMsk) "Zone group filter"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorFilter uOccFil(
    final nin=nBuiZon,
    final nout=nGroZon,
    final msk=zonGroMsk) "Zone group filter"
  Buildings.Controls.OBC.CDL.Routing.RealVectorFilter tNexOccFil(
    final nin=nBuiZon,
    final nout=nGroZon,
    final msk=zonGroMsk) "Zone group filter"
  Buildings.Controls.OBC.CDL.Routing.RealVectorFilter uCooTimFil(
    final nin=nBuiZon,
    final nout=nGroZon,
    final msk=zonGroMsk) "Zone group filter"
  Buildings.Controls.OBC.CDL.Routing.RealVectorFilter uWarTimFil(
    final nin=nBuiZon,
    final nout=nGroZon,
    final msk=zonGroMsk) "Zone group filter"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorFilter uOccHeaHigFil(
    final nin=nBuiZon,
    final nout=nGroZon,
    final msk=zonGroMsk) "Zone group filter"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorFilter uHigOccCooFil(
    final nin=nBuiZon,
    final nout=nGroZon,
    final msk=zonGroMsk) "Zone group filter"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorFilter uUnoHeaHigFil(
    final nin=nBuiZon,
    final nout=nGroZon,
    final msk=zonGroMsk) "Zone group filter"
  Buildings.Controls.OBC.CDL.Routing.RealVectorFilter THeaSetOffFil(
    final nin=nBuiZon,
    final nout=nGroZon,
    final msk=zonGroMsk) "Zone group filter"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorFilter uEndSetBacFil(
    final nin=nBuiZon,
    final nout=nGroZon,
    final msk=zonGroMsk) "Zone group filter"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorFilter uHigUnoCooFil(
    final nin=nBuiZon,
    final nout=nGroZon,
    final msk=zonGroMsk) "Zone group filter"
  Buildings.Controls.OBC.CDL.Routing.RealVectorFilter TCooSetOffFil(
    final nin=nBuiZon,
    final nout=nGroZon,
    final msk=zonGroMsk) "Zone group filter"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorFilter uEndSetUpFil(
    final nin=nBuiZon,
    final nout=nGroZon,
    final msk=zonGroMsk) "Zone group filter"
  Buildings.Controls.OBC.CDL.Routing.RealVectorFilter TZonFil(
    final nin=nBuiZon,
    final nout=nGroZon,
    final msk=zonGroMsk) "Zone group filter"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorFilter uWinFil(
    final nin=nBuiZon,
    final nout=nGroZon,
    final msk=zonGroMsk) "Zone group filter"
equation
  connect(maxTem.y, TZonMax)
  connect(minTem.y, TZonMin)
  connect(cooDowTim.y, yCooTim)
  connect(warUpTim.y, yWarTim)
  connect(mulOr.y, yOccHeaHig)
  connect(mulOr1.y, yHigOccCoo)
  connect(totColZon.y, yColZon)
  connect(endSetBac.y, yEndSetBac)
  connect(totHotZon.y, yHotZon)
  connect(endSetUp.y, yEndSetUp)
  connect(booToInt.y, totColZon.u)
  connect(booToInt1.y, totHotZon.u)
  connect(totZon.y, intToRea.u)
  connect(sumTem.y, difUnoCoo.u1)
  connect(sumUnoHea.y, difUnoHea.u1)
  connect(intToRea.y, div1.u2)
  connect(intToRea.y, div2.u2)
  connect(difUnoHea.y, div1.u1)
  connect(difUnoCoo.y, div2.u1)
  connect(div1.y, hys.u)
  connect(hys.y, ySetBac)
  connect(div2.y, hys1.u)
  connect(hys1.y, ySetUp)
  connect(groOcc.y, uGroOcc)
  connect(oveRidOcc.y, groOcc.u1)
  connect(schOcc.y, groOcc.u2)
  connect(totOpeWin.y, yOpeWin)
  connect(booToInt2.y, totOpeWin.u)
  connect(schOcc.y, booToRea.u)
  connect(minToNexOcc.y, pro.u2)
  connect(booToRea.y, pro.u1)
  connect(pro.y, nexOcc)
  connect(sumTem.y, difUnoHea.u2)
  connect(sumUnoCoo.y, difUnoCoo.u2)
  connect(u1Occ, uOccFil.u)
  connect(uWarTim, uWarTimFil.u)
  connect(u1Win, uWinFil.u)
  connect(zonOcc, zonOccFil.u)
  connect(zonOccFil.y, oveRidOcc.u)
  connect(uOccFil.y, schOcc.u)
  connect(tNexOccFil.y, minToNexOcc.u)
  connect(tNexOcc, tNexOccFil.u)
  connect(uCooTim, uCooTimFil.u)
  connect(uCooTimFil.y, cooDowTim.u)
  connect(uWarTimFil.y, warUpTim.u)
  connect(u1OccHeaHig, uOccHeaHigFil.u)
  connect(uOccHeaHigFil.y, mulOr.u)
  connect(u1HigOccCoo, uHigOccCooFil.u)
  connect(uHigOccCooFil.y, mulOr1.u)
  connect(u1UnoHeaHig, uUnoHeaHigFil.u)
  connect(uUnoHeaHigFil.y, booToInt.u)
  connect(THeaSetOff, THeaSetOffFil.u)
  connect(THeaSetOffFil.y, sumUnoHea.u)
  connect(u1EndSetBac, uEndSetBacFil.u)
  connect(uEndSetBacFil.y, endSetBac.u)
  connect(u1HigUnoCoo, uHigUnoCooFil.u)
  connect(uHigUnoCooFil.y, booToInt1.u)
  connect(TCooSetOff, TCooSetOffFil.u)
  connect(TCooSetOffFil.y, sumUnoCoo.u)
  connect(u1EndSetUp, uEndSetUpFil.u)
  connect(uEndSetUpFil.y, endSetUp.u)
  connect(TZon, TZonFil.u)
  connect(TZonFil.y, maxTem.u)
  connect(TZonFil.y, sumTem.u)
  connect(TZonFil.y, minTem.u)
  connect(uWinFil.y, not1.u)
  connect(not1.y, booToInt2.u)
end GroupStatus;


Block that outputs the operation mode. This block outputs VAV system operating mode. It is implemented according to
ASHRAE guideline G36, section 5.4.3, section 5.4.4, section 5.4.5 and section 5.4.6.

within Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups;
block OperationMode "Block that outputs the operation mode"

  parameter Integer nZon(min=1) "Number of zones";
  parameter Real preWarCooTim(
    final unit="s",
    final quantity="Time") = 10800
    "Maximum cool-down or warm-up time"
  parameter Real TZonFreProOn(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature")=277.15
    "Threshold temperature to activate the freeze protection mode"
  parameter Real TZonFreProOff(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature")=280.15
    "Threshold temperature to end the freeze protection mode"

  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Occ
    "True: zone scheduled to be occupied"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput tNexOcc(
    final unit="s",
    final quantity="Time")
    "Time to next occupied period"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput maxCooDowTim(
    final unit="s",
    final quantity="Time") "Maximum cool-down time among all the zones"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1HigOccCoo
    "True when there is zone with the temperature being higher than the occupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput maxWarUpTim(
    final unit="s",
    final quantity="Time") "Maximum warm-up time among all the zones"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1OccHeaHig
    "True when there is zone with the temperature being lower than the occupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput uOpeWin
    "Total number of zones with opening window"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput totColZon
    "Total number of cold zone"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1SetBac
    "True when the average zone temperature falls below the average unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1EndSetBac
    "True when the setback mode could end"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TZonMin(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature")
    "Minimum zone temperature"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput totHotZon
    "Total number of hot zone"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1SetUp
    "True when the average zone temperature rises above the average unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1EndSetUp
    "True when the setup mode could end"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput yOpeMod
    "Operation mode"

protected
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant occModInd(
    final k=Buildings.Controls.OBC.ASHRAE.G36.Types.OperationModes.occupied)
    "Occupied mode "
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant unoPerInd(final k=0.0)
    "Index to indicate unoccupied period"
  Buildings.Controls.OBC.CDL.Reals.Switch corCooDowTim "Corrected cool down period"
  Buildings.Controls.OBC.CDL.Reals.Switch corWarUpTim "Corrected warm-up period"
  Buildings.Controls.OBC.CDL.Integers.GreaterThreshold intGreThr(
    final t=4) "Check if the number of cold zones is not less than than 5"
  Buildings.Controls.OBC.CDL.Logical.Latch lat
    "If all zone temperature are higher than unoccupied heating setpoint by a given limit, then the setback mode should be off"
  Buildings.Controls.OBC.CDL.Logical.Latch lat1
    "If all zone temperature are higher than threshold temperature of ending freeze protection, then freeze protection setback mode should be off"
  Buildings.Controls.OBC.CDL.Logical.Latch lat2
    "If all zone temperature are lower than unoccupied cooling setpoint by a given limit, then the setup mode should be off"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys2(
    final pre_y_start=true,
    final uHigh=0,
    final uLow=-60)
    "Hysteresis that outputs if the maximum cool-down time is more than the allowed cool-down time"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys3(
    final pre_y_start=true,
    final uHigh=0,
    final uLow=-60)
    "Hysteresis that outputs if the maximum warm-up time is more than allowed warm-up time"
  Buildings.Controls.OBC.CDL.Reals.Subtract sub5
    "Calculate differential between time-to-next-occupancy and the cool-down time"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys4(
    final pre_y_start=false,
    final uHigh=0,
    final uLow=-60)
    "Hysteresis to check if the cooldown mode could be activated"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys5(
    final pre_y_start=false,
    final uHigh=0,
    final uLow=-60)
    "Hysteresis to activate the warm-up model"
  Buildings.Controls.OBC.CDL.Reals.Subtract sub6
    "Calculate differential between time-to-next-occupancy and the warm-up time"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys9(
    final pre_y_start=false,
    final uLow=-0.1,
    final uHigh=0.1)
    "Hysteresis that outputs if any zone temperature is lower than freeze protection threshold temperature"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys10(
    final pre_y_start=false,
    final uLow=-0.1,
    final uHigh=0.1)
    "Hysteresis that outputs if all zone temperature are higher than threshold temperature of ending freeze protection"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant maxWarCooTime(
    final k=preWarCooTim)
    "Allowed maximum warm-up or cool-down time"
  Buildings.Controls.OBC.CDL.Integers.GreaterThreshold intGreThr2(
    final t=4) "Check if the number of hot zones is not less than than 5"
  Buildings.Controls.OBC.CDL.Integers.Add addInt "Sum of two integer inputs"
  Buildings.Controls.OBC.CDL.Integers.Add addInt1 "Sum of two integer inputs"
  Buildings.Controls.OBC.CDL.Integers.Add addInt2 "Sum of two integer inputs"
  Buildings.Controls.OBC.CDL.Integers.Add addInt3 "Sum of two integer inputs"
  Buildings.Controls.OBC.CDL.Integers.Add addInt4 "Sum of two integer inputs"
  Buildings.Controls.OBC.CDL.Integers.Add addInt5 "Sum of two integer inputs"
  Buildings.Controls.OBC.CDL.Conversions.RealToInteger occMod
    "Convert Real number to Integer number"
  Buildings.Controls.OBC.CDL.Conversions.RealToInteger setBacMod
    "Convert Real number to Integer number"
  Buildings.Controls.OBC.CDL.Conversions.RealToInteger freProSetBacMod
    "Convert Real number to Integer number"
  Buildings.Controls.OBC.CDL.Conversions.RealToInteger setUpMod
    "Convert Real number to Integer number"
  Buildings.Controls.OBC.CDL.Logical.Edge edg
    "Get the moment when the warm up time starts "
  Buildings.Controls.OBC.CDL.Logical.TrueFalseHold truFalHol(
    final trueHoldDuration=preWarCooTim)
    "Hold the start time true signal"
  Buildings.Controls.OBC.CDL.Logical.Edge edg1
    "Get the moment when cool down time starts"
  Buildings.Controls.OBC.CDL.Logical.TrueFalseHold truFalHol1(
    final trueHoldDuration=preWarCooTim)
    "Hold the start time true signal"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea1(
    final realTrue=Buildings.Controls.OBC.ASHRAE.G36.Types.OperationModes.warmUp)
    "Convert Boolean to Integer number"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea(
    final realTrue=Buildings.Controls.OBC.ASHRAE.G36.Types.OperationModes.coolDown)
    "Convert Boolean to Integer number"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt3(
    final integerTrue=Buildings.Controls.OBC.ASHRAE.G36.Types.OperationModes.unoccupied)
    "Convert Boolean to Integer "
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea6(
    final realTrue=Buildings.Controls.OBC.ASHRAE.G36.Types.OperationModes.setUp)
    "Convert Boolean to Real "
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea4(
    final realTrue=Buildings.Controls.OBC.ASHRAE.G36.Types.OperationModes.freezeProtection)
    "Convert Boolean to Real "
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea3(
    final realTrue=Buildings.Controls.OBC.ASHRAE.G36.Types.OperationModes.setBack)
    "Convert Boolean to Real "
  Buildings.Controls.OBC.CDL.Utilities.Assert assMes(
    final message="Level 3 alarm: freeze protection setback")
    "Generate alarm message"
  Buildings.Controls.OBC.CDL.Logical.Not not2 "Logical not"
  Buildings.Controls.OBC.CDL.Logical.And and1 "Warm-up period"
  Buildings.Controls.OBC.CDL.Logical.And and2
    "Get the start of the cool-down time"
  Buildings.Controls.OBC.CDL.Logical.Or or1
    "Check if the number of cold zone is more than 5 or all zones are cold"
  Buildings.Controls.OBC.CDL.Logical.Or or9
    "Check if it is in occupied, cooldown, or warm-up mode"
  Buildings.Controls.OBC.CDL.Logical.Or or4
    "Check if the number of hot zone is more than 5 or all zones are hot"
  Buildings.Controls.OBC.CDL.Logical.Or or5
    "Check if it is in Setback, Setback_freezeProtection, or Setup mode"
  Buildings.Controls.OBC.CDL.Logical.Or or6
    "Check if it is in any of the 6 modes except unoccupied mode"
  Buildings.Controls.OBC.CDL.Reals.Switch swi
    "Switch between occupied mode index and unoccupied period index"
  Buildings.Controls.OBC.CDL.Reals.Switch swi3
    "If the Cool-down, warm-up, or Occupied mode is on, then setback mode should not be activated."
  Buildings.Controls.OBC.CDL.Reals.Switch swi4
    "If the Cool-down, warm-up, or Occupied mode is on, then freeze protection setback mode should not be activated."
  Buildings.Controls.OBC.CDL.Reals.Switch swi5
    "If the Cool-down, warm-up, or Occupied mode is on, then setup mode should not be activated."
  Buildings.Controls.OBC.CDL.Logical.Not not5 "Logical not"
  Buildings.Controls.OBC.CDL.Integers.GreaterThreshold notOcc(
    final t=1)
    "Check if the operation mode is other than occupied mode"
  Buildings.Controls.OBC.CDL.Logical.And and3
    "True if window open during modes other than occupied mode"
  Buildings.Controls.OBC.CDL.Logical.Not not1 "Logical not"
  Buildings.Controls.OBC.CDL.Utilities.Assert winOpe(
    final message="Level 4 alarm: window open during modes other than occupied mode")
    "Generate alarm message when window open during modes other than occupied mode"
  Buildings.Controls.OBC.CDL.Reals.Switch swi1
    "If occupied mode is on, then cool down mode should not be activated"
  Buildings.Controls.OBC.CDL.Conversions.RealToInteger setBacMod1
    "Convert Real number to Integer number"
  Buildings.Controls.OBC.CDL.Reals.Switch swi2
    "If occupied mode is on, then warm-up mode should not be activated."
  Buildings.Controls.OBC.CDL.Conversions.RealToInteger setBacMod2
    "Convert Real number to Integer number"
  Buildings.Controls.OBC.CDL.Logical.And and4 "Cool-down period"
  Buildings.Controls.OBC.CDL.Logical.And and5
    "Get the start of the warm-up time"
  Buildings.Controls.OBC.CDL.Integers.Sources.Constant totZon(
    final k=nZon) "Total number of zones"
  Buildings.Controls.OBC.CDL.Integers.Equal allCol
    "Check if all zones are cold zone"
  Buildings.Controls.OBC.CDL.Integers.Equal allHot
    "Check if all zones are hot zone"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant actFreProTem(
    final k=TZonFreProOn)
    "Threshold temperature to activate the freeze protection mode"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant endFreProTem(
    final k=TZonFreProOff)
    "Threshold temperature to end the freeze protection mode"
  Buildings.Controls.OBC.CDL.Reals.Subtract sub2
    "Calculate differential between minimum zone temperature and freeze protection threshold temperature"
  Buildings.Controls.OBC.CDL.Reals.Subtract sub1
    "Calculate differential between maximum zone temperature and threshold temperature of ending freeze protection"
  Buildings.Controls.OBC.CDL.Logical.Or or2
    "Enough cold zone or the low average zone temperature"
  Buildings.Controls.OBC.CDL.Logical.Or or7
    "Enough hot zone or the high average zone temperature"
  Buildings.Controls.OBC.CDL.Reals.Subtract sub3
    "Calculate the difference between maximum cool down time and the allowed maximum cool down time"
  Buildings.Controls.OBC.CDL.Reals.Subtract sub4
    "Calculate the differential between maximum warm-up time and the allowed maximum warm-up time"
  Buildings.Controls.OBC.CDL.Logical.Edge endSetBac
    "End setback mode when the input becomes true"
  Buildings.Controls.OBC.CDL.Logical.Edge endSetUp
    "End setup mode when the input becomes true"
  Buildings.Controls.OBC.CDL.Integers.GreaterThreshold intGreThr1(
    final  t=1) "Check if there is any zone with opening window"
  Buildings.Controls.OBC.CDL.Integers.Add addInt6
    "Total cold zone and zones with opening window"
  Buildings.Controls.OBC.CDL.Integers.Add addInt7
    "Total hot zone and zones with opening window"
  Buildings.Controls.OBC.CDL.Logical.Or or8
    "Check if it is in occupied, cooldown, or warm-up mode"
  Buildings.Controls.OBC.CDL.Logical.Or or10
    "Check if it is in Setback, Setback_freezeProtection, or Setup mode"

equation
  connect(swi.y, occMod.u)
  connect(occModInd.y, swi.u1)
  connect(unoPerInd.y, swi.u3)
  connect(intGreThr.y, or1.u1)
  connect(lat.y, booToRea3.u)
  connect(unoPerInd.y, swi3.u1)
  connect(lat1.y, booToRea4.u)
  connect(unoPerInd.y, swi4.u1)
  connect(lat2.y, booToRea6.u)
  connect(unoPerInd.y, swi5.u1)
  connect(swi3.y, setBacMod.u)
  connect(swi4.y, freProSetBacMod.u)
  connect(swi5.y, setUpMod.u)
  connect(or6.y, not2.u)
  connect(not2.y,booToInt3. u)
  connect(and1.y,booToRea1. u)
  connect(and1.y,or9. u1)
  connect(u1Occ, swi.u2)
  connect(hys2.y, corCooDowTim.u2)
  connect(hys3.y, corWarUpTim.u2)
  connect(sub5.y, hys4.u)
  connect(sub6.y, hys5.u)
  connect(hys9.y, lat1.u)
  connect(hys10.y, lat1.clr)
  connect(maxWarCooTime.y, corCooDowTim.u3)
  connect(maxWarCooTime.y, corWarUpTim.u3)
  connect(booToRea3.y, swi3.u3)
  connect(booToRea4.y, swi4.u3)
  connect(booToRea6.y, swi5.u3)
  connect(lat1.y, not5.u)
  connect(not5.y, assMes.u)
  connect(maxCooDowTim, corCooDowTim.u1)
  connect(maxWarUpTim, corWarUpTim.u1)
  connect(totColZon, intGreThr.u)
  connect(totHotZon, intGreThr2.u)
  connect(intGreThr2.y, or4.u1)
  connect(setBacMod.y, addInt2.u1)
  connect(freProSetBacMod.y, addInt2.u2)
  connect(setUpMod.y, addInt3.u2)
  connect(addInt2.y, addInt3.u1)
  connect(addInt3.y, addInt4.u1)
  connect(booToInt3.y, addInt4.u2)
  connect(addInt5.y, yOpeMod)
  connect(notOcc.y, and3.u2)
  connect(and3.y, not1.u)
  connect(addInt5.y, notOcc.u)
  connect(not1.y, winOpe.u)
  connect(booToRea.y, swi1.u3)
  connect(u1Occ, swi1.u2)
  connect(swi1.y, setBacMod1.u)
  connect(setBacMod1.y, addInt.u1)
  connect(addInt.y, addInt1.u2)
  connect(occMod.y, addInt1.u1)
  connect(addInt1.y, addInt5.u1)
  connect(addInt4.y, addInt5.u2)
  connect(booToRea1.y, swi2.u3)
  connect(unoPerInd.y, swi1.u1)
  connect(unoPerInd.y, swi2.u1)
  connect(swi2.y, setBacMod2.u)
  connect(setBacMod2.y, addInt.u2)
  connect(and4.y, booToRea.u)
  connect(and4.y,or9. u2)
  connect(hys4.y, and2.u1)
  connect(u1OccHeaHig, and5.u2)
  connect(hys5.y, and5.u1)
  connect(truFalHol1.u, edg.y)
  connect(and5.y, edg.u)
  connect(and2.y, edg1.u)
  connect(edg1.y, truFalHol.u)
  connect(lat2.y, or5.u1)
  connect(lat1.y, or5.u2)
  connect(allCol.y, or1.u2)
  connect(allHot.y, or4.u2)
  connect(totZon.y, allCol.u2)
  connect(totZon.y, allHot.u2)
  connect(sub2.y, hys9.u)
  connect(sub1.y, hys10.u)
  connect(TZonMin, sub1.u1)
  connect(endFreProTem.y, sub1.u2)
  connect(or1.y, or2.u1)
  connect(or2.y, lat.u)
  connect(u1SetBac, or2.u2)
  connect(or4.y, or7.u1)
  connect(or7.y, lat2.u)
  connect(u1SetUp, or7.u2)
  connect(u1Occ, swi2.u2)
  connect(truFalHol.y, and4.u2)
  connect(hys4.y, and4.u1)
  connect(truFalHol1.y, and1.u2)
  connect(hys5.y, and1.u1)
  connect(u1HigOccCoo, and2.u2)
  connect(maxWarCooTime.y, sub4.u1)
  connect(maxWarUpTim, sub4.u2)
  connect(sub3.y, hys2.u)
  connect(sub4.y, hys3.u)
  connect(u1EndSetBac, endSetBac.u)
  connect(endSetBac.y, lat.clr)
  connect(u1EndSetUp, endSetUp.u)
  connect(endSetUp.y, lat2.clr)
  connect(uOpeWin, intGreThr1.u)
  connect(intGreThr1.y, and3.u1)
  connect(totColZon, addInt6.u2)
  connect(uOpeWin, addInt6.u1)
  connect(addInt6.y, allCol.u1)
  connect(totHotZon, addInt7.u2)
  connect(uOpeWin, addInt7.u1)
  connect(addInt7.y, allHot.u1)
  connect(maxWarCooTime.y, sub3.u1)
  connect(maxCooDowTim, sub3.u2)
  connect(tNexOcc, sub5.u2)
  connect(corCooDowTim.y, sub5.u1)
  connect(corWarUpTim.y, sub6.u1)
  connect(tNexOcc, sub6.u2)
  connect(actFreProTem.y, sub2.u1)
  connect(TZonMin, sub2.u2)
  connect(u1Occ, or8.u2)
  connect(or8.y, or6.u2)
  connect(or8.y, swi5.u2)
  connect(or8.y, swi4.u2)
  connect(or8.y, swi3.u2)
  connect(or9.y, or8.u1)
  connect(or10.y, or6.u1)
  connect(or5.y, or10.u1)
  connect(lat.y, or10.u2)
end OperationMode;


within Buildings.Controls.OBC.ASHRAE.G36;
package ZoneGroups "Package of sequences in zone group level"
end ZoneGroups;


Compute the AHU operating mode from the group operating mode. This sequence specifies the operation mode of a AHU system, which may serve
multiple zone group. It is implemented according
to Section 5.15.1 of ASHRAE Guideline G36, May 2020.

within Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups;
block ZoneGroupSystem
  "Compute the AHU operating mode from the group operating mode"

  parameter Integer nGro
    "Total number of groups";

  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput uOpeMod[nGro]
    "Groups operation mode"
  Buildings.Controls.OBC.CDL.Conversions.IntegerToReal intToRea[nGro]
    "Convert integer to real"
  Buildings.Controls.OBC.CDL.Reals.MultiMin mulMin(nin=nGro)
    "Find the highest priotity operating mode"
  Buildings.Controls.OBC.CDL.Conversions.RealToInteger ahuMod
    "Air handling operating mode"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput yAhuOpeMod
    "Operation mode for AHU operation"

equation
  connect(intToRea.y, mulMin.u)
  connect(mulMin.y, ahuMod.u)
  connect(ahuMod.y, yAhuOpeMod)
  connect(uOpeMod, intToRea.u)
end ZoneGroupSystem;


Block that outputs zone temperature status. This block outputs single zone status. It includes outputs as following:

within Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups;
block ZoneStatus "Block that outputs zone temperature status"

  parameter Real bouLim(
    final unit="K",
    displayUnit="K",
    final quantity="TemperatureDifference",
    final min=0.5) = 1
    "Threshold of temperature difference for indicating the end of setback or setup mode"
  parameter Boolean have_winSen=false
    "Check if the zone has window status sensor"
  parameter Real uLow(
    final unit="K",
    final quantity="TemperatureDifference")=-0.1
    "Low limit of the hysteresis for checking temperature difference"
  parameter Real uHigh(
    final unit="K",
    final quantity="TemperatureDifference")=0.1
    "High limit of the hysteresis for checking temperature difference"

  Buildings.Controls.OBC.CDL.Interfaces.RealInput cooDowTim(
    final unit="s",
    final quantity="Time")
    "Cool-down time retrieved from optimal cool-down block"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput warUpTim(
    final unit="s",
    final quantity="Time")
    "Warm-up time retrieved from optimal warm-up block"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Win if have_winSen
    "Window status, normally closed (true), when windows open, it becomes false"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TZon(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature") "Single zone temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TOccHeaSet(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature") "Occupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TOccCooSet(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature") "Occupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TUnoHeaSet(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature") "Unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TUnoCooSet(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature") "Unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yCooTim(
    final unit="s",
    final quantity="Time") "Cool-down time"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yWarTim(
    final unit="s",
    final quantity="Time") "Warm-up time"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yOccHeaHig
    "True when the zone temperature is lower than the occupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yHigOccCoo
    "True when the zone temperature is higher than the occupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yUnoHeaHig
    "True when the zone temperature is lower than the unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yEndSetBac
    "True when the zone could end setback mode"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yHigUnoCoo
    "True when the zone temperature is higher than the unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yEndSetUp
    "True when the zone could end setup mode"

protected
  Buildings.Controls.OBC.CDL.Reals.Multiply pro
    "Decide if the cool down time of one zone should be ignored: if window is open,
    then output zero, otherwise, output cool-down time from optimal cool-down block"
  Buildings.Controls.OBC.CDL.Reals.Multiply pro1
    "Decide if the warm-up time of one zone should be ignored: if window is open,
    then output zero, otherwise, output warm-up time from optimal warm-up block"
  Buildings.Controls.OBC.CDL.Reals.Subtract sub
    "Calculate difference between zone temperature and the occupied heating setpoint"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys(
    final uLow=uLow,
    final uHigh=uHigh)
    "Hysteresis that outputs if the system should run in warm-up mode"
  Buildings.Controls.OBC.CDL.Reals.Subtract sub1
    "Calculate difference between zone temperature and the occupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys1(
    final uLow=uLow,
    final uHigh=uHigh)
    "Hysteresis that outputs if the system should run in cool-down mode"
  Buildings.Controls.OBC.CDL.Reals.Subtract sub2
    "Calculate zone temperature difference to unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys2(
    final uLow=uLow,
    final uHigh=uHigh)
    "Hysteresis that outputs if the zone temperature is lower than unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Reals.Subtract sub5
    "Calculate zone temperature difference to unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys5(
    final uLow=uLow,
    final uHigh=uHigh)
    "Hysteresis that outputs if the zone temperature is higher than unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Logical.Not not1 "Logical not"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea "Convert Boolean to Real number"
  Buildings.Controls.OBC.CDL.Logical.Sources.Constant con(
    final k=false) if not have_winSen
    "Constant false"
  Buildings.Controls.OBC.CDL.Reals.Subtract sub3
    "Calculate zone temperature difference to unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys3(
    final uLow=0,
    final uHigh=bouLim)
    "Hysteresis that outputs if the zone temperature is higher than its unoccupied heating setpoint by a given limit"
  Buildings.Controls.OBC.CDL.Reals.Subtract sub4
    "Calculate zone temperature difference to unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys4(
    final uLow=0,
    final uHigh=bouLim)
    "Hysteresis that outputs if the zone temperature is lower than its unoccupied cooling setpoint by a given limit"
  Buildings.Controls.OBC.CDL.Logical.And and2
    "When window is open, it should output false"
  Buildings.Controls.OBC.CDL.Logical.And and1
    "When window is open, it should output false"
  Buildings.Controls.OBC.CDL.Logical.And and3
    "When window is open, it should output false"
  Buildings.Controls.OBC.CDL.Logical.Or or2
    "When window is open, it should output true"
  Buildings.Controls.OBC.CDL.Logical.And and5
    "When window is open, it should output false"
  Buildings.Controls.OBC.CDL.Logical.Or or1
    "When window is open, it should output true"
  Buildings.Controls.OBC.CDL.Logical.Not winOpe if have_winSen "Window is open"
equation
  connect(cooDowTim, pro.u1)
  connect(warUpTim, pro1.u1)
  connect(booToRea.y, pro.u2)
  connect(booToRea.y, pro1.u2)
  connect(sub.y, hys.u)
  connect(sub1.y, hys1.u)
  connect(sub2.y, hys2.u)
  connect(sub5.y, hys5.u)
  connect(not1.y, booToRea.u)
  connect(pro.y, yCooTim)
  connect(pro1.y, yWarTim)
  connect(con.y, not1.u)
  connect(TZon, sub.u2)
  connect(sub3.y, hys3.u)
  connect(sub4.y, hys4.u)
  connect(TZon, sub2.u2)
  connect(TZon, sub3.u1)
  connect(and2.y, yOccHeaHig)
  connect(hys.y, and2.u1)
  connect(hys1.y, and1.u1)
  connect(hys2.y, and3.u1)
  connect(hys3.y, or2.u1)
  connect(hys5.y, and5.u1)
  connect(hys4.y, or1.u1)
  connect(not1.y, and2.u2)
  connect(not1.y, and1.u2)
  connect(and1.y, yHigOccCoo)
  connect(and3.y, yUnoHeaHig)
  connect(or2.y, yEndSetBac)
  connect(and5.y, yHigUnoCoo)
  connect(or1.y, yEndSetUp)
  connect(con.y, or2.u2)
  connect(con.y, or1.u2)
  connect(not1.y, and3.u2)
  connect(not1.y, and5.u2)
  connect(TZon, sub1.u1)
  connect(TZon, sub5.u1)
  connect(TZon, sub4.u2)
  connect(TOccHeaSet, sub.u1)
  connect(TOccCooSet, sub1.u2)
  connect(TUnoHeaSet, sub2.u1)
  connect(TUnoHeaSet, sub3.u2)
  connect(TUnoCooSet, sub5.u2)
  connect(TUnoCooSet, sub4.u1)
  connect(u1Win, winOpe.u)
  connect(winOpe.y, not1.u)
  connect(winOpe.y, or2.u2)
  connect(winOpe.y, or1.u2)
end ZoneStatus;


Duplicate zone status output. This block duplicates the signals of nZon by converting the
input vector-valued signals of dimension nZon to a matrix-valued
output of dimension [nZonGro, nZon].

within Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups;
block ZoneStatusDuplicator "Duplicate zone status output"

  parameter Integer nZon(final min=1)=1
    "Number of zones in input"
  parameter Integer nZonGro(final min=1)=1
    "Number of groups in output"

  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput zonOcc[nZon]
    "True when the zone is set to be occupied due to the override"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Occ[nZon]
    "True when the zone is occupied according to the occupancy schedule"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput tNexOcc[nZon](
    final unit=fill("s", nZon),
    final quantity=fill("Time", nZon))
    "Time to next occupied period"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput uCooTim[nZon](
    final unit=fill("s", nZon),
    final quantity=fill("Time", nZon))
    "Cool down time"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput uWarTim[nZon](
    final unit=fill("s", nZon),
    final quantity=fill("Time", nZon))
    "Warm-up time"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1OccHeaHig[nZon]
    "True when the zone temperature is lower than the occupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1HigOccCoo[nZon]
    "True when the zone temperature is higher than the occupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1UnoHeaHig[nZon]
    "True when the zone temperature is lower than the unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput THeaSetOff[nZon](
    final unit=fill("K", nZon),
    displayUnit=fill("degC", nZon),
    final quantity=fill("ThermodynamicTemperature", nZon))
    "Zone unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1EndSetBac[nZon]
    "True when the zone could end the setback mode"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1HigUnoCoo[nZon]
    "True when the zone temperature is higher than its unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TCooSetOff[nZon](
    final unit=fill("K", nZon),
    displayUnit=fill("degC", nZon),
    final quantity=fill("ThermodynamicTemperature", nZon))
    "Zone unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1EndSetUp[nZon]
    "True when the zone could end the setup mode"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TZon[nZon](
    final unit=fill("K", nZon),
    displayUnit=fill("degC", nZon),
    final quantity=fill("ThermodynamicTemperature", nZon)) "Zone temperature"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Win[nZon]
    "Window status, normally closed (true), when windows open, it becomes false. For zone without sensor, it is true"

  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1ZonOcc[nZonGro,nZon]
    "True when the zone is set to be occupied due to the override"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1Occ[nZonGro,nZon]
    "True when the zone is occupied according to the occupancy schedule"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput ytNexOcc[nZonGro, nZon](
    final unit=fill("s", nZonGro, nZon),
    final quantity=fill("Time", nZonGro, nZon)) "Time to next occupied period"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yCooTim[nZonGro,nZon](
    final unit=fill("s", nZonGro, nZon),
    final quantity=fill("Time", nZonGro, nZon)) "Cool down time"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yWarTim[nZonGro,nZon](
    final unit=fill("s", nZonGro, nZon),
    final quantity=fill("Time", nZonGro, nZon)) "Warm-up time"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1OccHeaHig[nZonGro,nZon]
    "True when the zone temperature is lower than the occupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1HigOccCoo[nZonGro,nZon]
    "True when the zone temperature is higher than the occupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1UnoHeaHig[nZonGro,nZon]
    "True when the zone temperature is lower than the unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yTHeaSetOff[nZonGro, nZon](
    final unit=fill("K", nZonGro, nZon),
    displayUnit=fill("degC", nZonGro, nZon),
    final quantity=fill("ThermodynamicTemperature", nZonGro, nZon))
    "Zone unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1EndSetBac[nZonGro,nZon]
    "True when the zone could end the setback mode"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1HigUnoCoo[nZonGro,nZon]
    "True when the zone temperature is higher than its unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yTCooSetOff[nZonGro, nZon](
    final unit=fill("K", nZonGro, nZon),
    displayUnit=fill("degC", nZonGro, nZon),
    final quantity=fill("ThermodynamicTemperature", nZonGro, nZon))
    "Zone unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1EndSetUp[nZonGro,nZon]
    "True when the zone could end the setup mode"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yTZon[nZonGro, nZon](
    final unit=fill("K", nZonGro, nZon),
    displayUnit=fill("degC", nZonGro, nZon),
    final quantity=fill("ThermodynamicTemperature", nZonGro, nZon)) "Zone temperature"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1Win[nZonGro,nZon]
    "True when the window is open, false when the window is close or the zone does not have window status sensor"

protected
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorReplicator zonOccDup(
    final nin=nZon,
    final nout=nZonGro)
    "Duplicator"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorReplicator uOccDup(
    final nin=nZon,
    final nout=nZonGro)
    "Duplicator"
  Buildings.Controls.OBC.CDL.Routing.RealVectorReplicator tNexOccDup(
    final nin=nZon,
    final nout=nZonGro)
    "Duplicator"
  Buildings.Controls.OBC.CDL.Routing.RealVectorReplicator uCooTimDup(
    final nin=nZon,
    final nout=nZonGro)
    "Duplicator"
  Buildings.Controls.OBC.CDL.Routing.RealVectorReplicator uWarTimDup(
    final nin=nZon,
    final nout=nZonGro)
    "Duplicator"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorReplicator uOccHeaHigDup(
    final nin=nZon,
    final nout=nZonGro)
    "Duplicator"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorReplicator uHigOccCooDup(
    final nin=nZon,
    final nout=nZonGro)
    "Duplicator"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorReplicator uUnoHeaHigDup(
    final nin=nZon,
    final nout=nZonGro)
    "Duplicator"
  Buildings.Controls.OBC.CDL.Routing.RealVectorReplicator THeaSetOffDup(
    final nin=nZon,
    final nout=nZonGro)
    "Duplicator"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorReplicator uEndSetBacDup(
    final nin=nZon,
    final nout=nZonGro)
    "Duplicator"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorReplicator uHigUnoCooDup(
    final nin=nZon,
    final nout=nZonGro)
    "Duplicator"
  Buildings.Controls.OBC.CDL.Routing.RealVectorReplicator TCooSetOffDup(
    final nin=nZon,
    final nout=nZonGro)
    "Duplicator"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorReplicator uEndSetUpDup(
    final nin=nZon,
    final nout=nZonGro)
    "Duplicator"
  Buildings.Controls.OBC.CDL.Routing.RealVectorReplicator TZonDup(
    final nin=nZon,
    final nout=nZonGro) "Duplicator"
  Buildings.Controls.OBC.CDL.Routing.BooleanVectorReplicator uWinDup(
    final nin=nZon,
    final nout=nZonGro)
    "Duplicator"

equation
  connect(zonOcc, zonOccDup.u)
  connect(u1Occ, uOccDup.u)
  connect(tNexOcc, tNexOccDup.u)
  connect(uCooTim, uCooTimDup.u)
  connect(uWarTim, uWarTimDup.u)
  connect(u1OccHeaHig, uOccHeaHigDup.u)
  connect(u1HigOccCoo, uHigOccCooDup.u)
  connect(u1UnoHeaHig, uUnoHeaHigDup.u)
  connect(THeaSetOff, THeaSetOffDup.u)
  connect(u1EndSetBac, uEndSetBacDup.u)
  connect(u1HigUnoCoo, uHigUnoCooDup.u)
  connect(TCooSetOff, TCooSetOffDup.u)
  connect(u1EndSetUp, uEndSetUpDup.u)
  connect(TZon, TZonDup.u)
  connect(u1Win, uWinDup.u)
  connect(zonOccDup.y, y1ZonOcc)
  connect(uOccDup.y, y1Occ)
  connect(ytNexOcc, tNexOccDup.y)
  connect(yCooTim, uCooTimDup.y)
  connect(uWarTimDup.y, yWarTim)
  connect(uOccHeaHigDup.y, y1OccHeaHig)
  connect(uHigOccCooDup.y, y1HigOccCoo)
  connect(uUnoHeaHigDup.y, y1UnoHeaHig)
  connect(THeaSetOffDup.y, yTHeaSetOff)
  connect(uEndSetBacDup.y, y1EndSetBac)
  connect(uHigUnoCooDup.y, y1HigUnoCoo)
  connect(TCooSetOffDup.y, yTCooSetOff)
  connect(uEndSetUpDup.y, y1EndSetUp)
  connect(TZonDup.y, yTZon)
  connect(uWinDup.y, y1Win)
end ZoneStatusDuplicator;


Validate block for checking temperatures in the group. This example validates

Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.GroupStatus
for checking group temperature status.

within Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.Validation;
model GroupStatus
  "Validate block for checking temperatures in the group"

  Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.GroupStatus zonGroSta(
    final nBuiZon=3,
    final nGroZon=2,
    final zonGroMsk={true,false,true}) "Calculate zone group status"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant warUpTim[3](
    final k={1800,1700,1900})
    "Warm-up time"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant cooDowTim[3](
    final k={1600,1700,1800})
    "Cooling down time"
  Buildings.Controls.OBC.CDL.Logical.Sources.Pulse winSta[3](
    final width={0.3,0.2,0.1},
    final period=fill(3600, 3),
    final shift={150,130,120})
    "Window status"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp2(
    final offset=0,
    final height=6.2831852,
    final duration=24*3600) "Block that generates ramp signal"
  Buildings.Controls.OBC.CDL.Reals.Sin sin2
    "Block that outputs the sine of the input"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai(
    final k=6)
    "Current zone temperature"
  Buildings.Controls.OBC.CDL.Reals.AddParameter zonTem(
    final p=273.15 + 22.5)
    "Current zone temperature"
  Buildings.Controls.OBC.CDL.Logical.Sources.Constant uOccOve[3](
    final k=fill(false,3))
    "Occupancy local override"
  Buildings.Controls.OBC.CDL.Logical.Sources.Pulse zonOcc1(
    final width=0.8,
    final period=7200,
    shift=1800)
    "Zone 1 occupied status"
  Buildings.Controls.OBC.CDL.Logical.Sources.Pulse zonOcc3(
    final width=0.8,
    final period=7200,
    shift=2100) "Zone 3 occupied status"
  Buildings.Controls.OBC.CDL.Logical.Not not1 "Logical not"
  Buildings.Controls.OBC.CDL.Logical.Not not3 "Logical not"
  Buildings.Controls.OBC.CDL.Logical.Timer tim1 "Time after input becomes true"
  Buildings.Controls.OBC.CDL.Logical.Timer tim3 "Time after input becomes true"
  Buildings.Controls.OBC.CDL.Reals.Subtract addPar1
    "Time to occupied period"
  Buildings.Controls.OBC.CDL.Reals.Subtract addPar3
    "Time to occupied period"
  Buildings.Controls.OBC.CDL.Logical.Sources.Pulse lowOccHea[3](
    final width=fill(0.5, 3),
    final period=fill(3600, 3),
    final shift=fill(1000, 3)) "Lower than occupied heating setpoint"
  Buildings.Controls.OBC.CDL.Logical.Sources.Constant higOccCoo[3](
    final k=fill(false, 3))
    "Higher than occupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Logical.And and2[3]
    "Lower than occupied heating setpoint when it is not occupied"
  Buildings.Controls.OBC.CDL.Logical.Sources.Pulse lowUnoHea1[3](
    final width=fill(0.1, 3),
    final period=fill(3600, 3))
    "Lower than unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant heaSetOff[3](
    final k={285.15,282.15,283.15})
    "Unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Logical.Sources.Pulse endSetBac[3](
    final width=fill(0.8, 3),
    final period=fill(3600, 3),
    final shift=fill(900, 3)) "End setback"
  Buildings.Controls.OBC.CDL.Logical.Sources.Constant higUnoCoo[3](
    final k=fill(false, 3))
    "HIgher than unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant cooSetOff[3](
    final k={303.15,304.15,305.15})
    "Unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Logical.Sources.Constant endSetUp[3](
    final k=fill(false,3))
    "End setup mode"
  Buildings.Controls.OBC.CDL.Reals.Sources.Pulse zonTem3(
    final amplitude=7,
    final period=600,
    final offset=273.15 + 19) "Zone 3 temperature"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant zonTem2(
    final k=273.15 + 20)
    "Zone 2 temperature"
  Buildings.Controls.OBC.CDL.Logical.Sources.Constant zonOcc2(
    final k=true)
    "Zone 2 occupied status"
  Buildings.Controls.OBC.CDL.Logical.Not not2
    "Logical not"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant tNexOcc2(
    final k=0) "Zone 2 next occupancy time"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant con(
    final k=1800)
    "Constant"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant con1(
    final k=2100)
    "Constant"

equation
  connect(ramp2.y,sin2. u)
  connect(not1.y, tim1.u)
  connect(not3.y,tim3. u)
  connect(uOccOve.y, zonGroSta.zonOcc)
  connect(zonOcc1.y, not1.u)
  connect(zonOcc3.y,not3. u)
  connect(zonOcc1.y, zonGroSta.u1Occ[1])
  connect(zonOcc3.y, zonGroSta.u1Occ[3])
  connect(addPar1.y, zonGroSta.tNexOcc[1])
  connect(addPar3.y, zonGroSta.tNexOcc[3])
  connect(cooDowTim.y, zonGroSta.uCooTim)
  connect(warUpTim.y, zonGroSta.uWarTim)
  connect(not1.y, and2[1].u2)
  connect(not3.y, and2[3].u2)
  connect(lowOccHea.y, and2.u1)
  connect(and2.y, zonGroSta.u1OccHeaHig)
  connect(higOccCoo.y, zonGroSta.u1HigOccCoo)
  connect(lowUnoHea1.y, zonGroSta.u1UnoHeaHig)
  connect(heaSetOff.y, zonGroSta.THeaSetOff)
  connect(endSetBac.y, zonGroSta.u1EndSetBac)
  connect(higUnoCoo.y, zonGroSta.u1HigUnoCoo)
  connect(cooSetOff.y, zonGroSta.TCooSetOff)
  connect(endSetUp.y, zonGroSta.u1EndSetUp)
  connect(zonTem.y, zonGroSta.TZon[1])
  connect(zonTem3.y, zonGroSta.TZon[3])
  connect(winSta.y, zonGroSta.u1Win)
  connect(zonTem2.y, zonGroSta.TZon[2])
  connect(zonOcc2.y, not2.u)
  connect(not2.y, and2[2].u2)
  connect(zonOcc2.y, zonGroSta.u1Occ[2])
  connect(tNexOcc2.y, zonGroSta.tNexOcc[2])
  connect(con.y, addPar1.u1)
  connect(tim1.y, addPar1.u2)
  connect(con1.y, addPar3.u1)
  connect(tim3.y, addPar3.u2)
  connect(sin2.y, gai.u)
  connect(gai.y, zonTem.u)
end GroupStatus;


Validate block for selecting operation mode. This example validates

Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.OperationMode
for a change of zone temperature and occupancy schedule.

within Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.Validation;
model OperationMode "Validate block for selecting operation mode"

  Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.OperationMode
    opeModSel(final nZon=1) "Operation mode selection"

  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp1(
    final height=6.2831852,
    final duration=172800)
    "Block that generates ramp signal"
  Buildings.Controls.OBC.CDL.Reals.Sin sin1
    "Block that outputs the sine of the input"
  Buildings.Controls.OBC.CDL.Reals.AddParameter zonTem(
    final p=295.65) "Zone temperarure"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TZonHeaSetUno(
    final k=285.15)  "Unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TZonCooSetUno(
    final k=303.15)  "Unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TZonHeaSetOcc(
    final k=293.15)  "Occupied heating setpoint"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TZonCooSetOcc(
    final k=297.15)  "Occupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant warUpTim(
    final k=1800) "Warm-up time"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant cooDowTim(
    final k=1800) "Cooling down time"
  Buildings.Controls.OBC.CDL.Integers.Sources.Constant cloWin(
    final k=0) "No window is open"
  Buildings.Controls.OBC.CDL.Reals.Greater lowThaHeaSet
    "True when the zone temperature is lower than the occupied heating setpoint"
  Buildings.Controls.OBC.CDL.Reals.Greater higThaCooSet
    "True when the zone temperature is higher than the occupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Reals.Greater greEqu2
    "True when the zone temperature is lower than unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt "Convert boolean to integer"
  Buildings.Controls.OBC.CDL.Reals.Greater greEqu3
    "True when the zone temperature is lower than unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt1 "Convert boolean to integer"
  Buildings.Controls.SetPoints.OccupancySchedule occSch "Occupancy schedule"
  Buildings.Controls.OBC.CDL.Reals.Subtract dif2
    "Calculate zone temperature difference to unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys3(
    final uLow=-0.5,
    final uHigh=0.5)
    "Hysteresis that outputs if the zone temperature is higher than its unoccupied heating setpoint by a given limit"
  Buildings.Controls.OBC.CDL.Reals.Subtract dif1
    "Calculate zone temperature difference to unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Reals.Hysteresis hys1(
    final uLow=-0.5,
    final uHigh=0.5)
    "Hysteresis that outputs if the zone temperature is lower than its unoccupied cooling setpoint by a given limit"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai(
    final k=14.5) "Gain factor"
equation
  connect(ramp1.y, sin1.u)
  connect(cooDowTim.y, opeModSel.maxCooDowTim)
  connect(warUpTim.y, opeModSel.maxWarUpTim)
  connect(TZonHeaSetOcc.y, lowThaHeaSet.u1)
  connect(zonTem.y, lowThaHeaSet.u2)
  connect(zonTem.y, higThaCooSet.u1)
  connect(TZonCooSetOcc.y, higThaCooSet.u2)
  connect(TZonHeaSetUno.y, greEqu2.u1)
  connect(zonTem.y, greEqu2.u2)
  connect(greEqu2.y, booToInt.u)
  connect(booToInt.y, opeModSel.totColZon)
  connect(zonTem.y, opeModSel.TZonMin)
  connect(zonTem.y, greEqu3.u1)
  connect(TZonCooSetUno.y, greEqu3.u2)
  connect(greEqu3.y, booToInt1.u)
  connect(booToInt1.y, opeModSel.totHotZon)
  connect(occSch.occupied, opeModSel.u1Occ)
  connect(occSch.tNexOcc, opeModSel.tNexOcc)
  connect(higThaCooSet.y, opeModSel.u1HigOccCoo)
  connect(lowThaHeaSet.y, opeModSel.u1OccHeaHig)
  connect(cloWin.y, opeModSel.uOpeWin)
  connect(greEqu2.y, opeModSel.u1SetBac)
  connect(greEqu3.y, opeModSel.u1SetUp)
  connect(zonTem.y,dif2. u1)
  connect(TZonHeaSetUno.y,dif2. u2)
  connect(dif2.y, hys3.u)
  connect(hys3.y, opeModSel.u1EndSetBac)
  connect(dif1.y, hys1.u)
  connect(hys1.y, opeModSel.u1EndSetUp)
  connect(sin1.y, gai.u)
  connect(gai.y, zonTem.u)
  connect(TZonCooSetUno.y, dif1.u1)
  connect(zonTem.y, dif1.u2)
end OperationMode;


Collection of validation models

within Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups;
package Validation "Collection of validation models"
end Validation;


Validate block for calculating AHU mode from the zone group modes. This example validates

Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.ZoneGroupSystem
for specifing the AHU operating mode when the system serves multiple zone groups.

within Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.Validation;
model ZoneGroupSystem
  "Validate block for calculating AHU mode from the zone group modes"

  Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.ZoneGroupSystem ahuMod(
    final nGro=3)
    "AHU operation mode selection"

  Buildings.Controls.OBC.CDL.Integers.Sources.Pulse groOne(
    final period=4,
    final offset=1)
    "Group 1 mode"
  Buildings.Controls.OBC.CDL.Integers.Sources.Pulse groTwo(
    final amplitude=2,
    final period=10,
    final offset=1)
    "Group 2 mode"
  Buildings.Controls.OBC.CDL.Integers.Sources.Constant groThr(
    final k=3) "Group 3 mode"

equation
  connect(groOne.y, ahuMod.uOpeMod[1])
  connect(groTwo.y, ahuMod.uOpeMod[2])
  connect(groThr.y, ahuMod.uOpeMod[3])
end ZoneGroupSystem;


Validate block for checking temperatures in the zone. This example validates

Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.ZoneStatus
for checking zone temperature status.

within Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.Validation;
model ZoneStatus
  "Validate block for checking temperatures in the zone"

  Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.ZoneStatus noWinZonSta(
    final have_winSen=false)
    "Status of zone when there is no window operation sensor"
  Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.ZoneStatus witWinZonSta(
    final have_winSen=true)
    "Status of zone when there is window operation sensor"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant warUpTim(
    final k=1800) "Warm-up time"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant cooDowTim(
    final k=1800) "Cooling down time"
  Buildings.Controls.OBC.CDL.Logical.Sources.Pulse uWinSta(
    final width=0.3,
    final period=43200,
    final shift=1800)
    "Window on/off status"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp2(
    final offset=0,
    final height=6.2831852,
    final duration=24*3600) "Block that generates ramp signal"
  Buildings.Controls.OBC.CDL.Reals.Sin sin2
    "Block that outputs the sine of the input"
  Buildings.Controls.OBC.CDL.Reals.AddParameter zonTem(
    final p=273.15 + 22.5)
    "Current zone temperature"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai(
    final k=12.5) "Gain factor"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaSetOcc(
    final k=293.15)
    "Occupied heating setpoint"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TCooSetOcc(
    final k=297.15)
    "Occupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaSetUno(
    final k=285.15)
    "Unoccupied heating setpoint"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TCooSetUno(
    final k=303.15)
    "Unoccupied cooling setpoint"
  Buildings.Controls.OBC.CDL.Logical.Not not2 "Logical not"
equation
  connect(cooDowTim.y, noWinZonSta.cooDowTim)
  connect(warUpTim.y, noWinZonSta.warUpTim)
  connect(ramp2.y,sin2. u)
  connect(zonTem.y, noWinZonSta.TZon)
  connect(cooDowTim.y, witWinZonSta.cooDowTim)
  connect(warUpTim.y, witWinZonSta.warUpTim)
  connect(zonTem.y, witWinZonSta.TZon)
  connect(sin2.y, gai.u)
  connect(gai.y, zonTem.u)
  connect(THeaSetOcc.y,noWinZonSta.TOccHeaSet)
  connect(TCooSetOcc.y,noWinZonSta.TOccCooSet)
  connect(THeaSetUno.y,noWinZonSta.TUnoHeaSet)
  connect(TCooSetUno.y,noWinZonSta.TUnoCooSet)
  connect(THeaSetOcc.y,witWinZonSta.TOccHeaSet)
  connect(TCooSetOcc.y,witWinZonSta.TOccCooSet)
  connect(THeaSetUno.y,witWinZonSta.TUnoHeaSet)
  connect(TCooSetUno.y,witWinZonSta.TUnoCooSet)
  connect(uWinSta.y, not2.u)
  connect(not2.y, witWinZonSta.u1Win)
end ZoneStatus;


Validate block for duplicating zone status. This example validates

Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.ZoneStatusDuplicator
for duplicating zone status.

within Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.Validation;
model ZoneStatusDuplicator
  "Validate block for duplicating zone status"

  Buildings.Controls.OBC.ASHRAE.G36.ZoneGroups.ZoneStatusDuplicator zonStaDup(
    final nZon=5, final nZonGro=2) "Zone status duplicator"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant reaInp[6,5](
    final k=fill({1,2,3,4,5}, 6))
    "Real inputs"
  Buildings.Controls.OBC.CDL.Logical.Sources.Constant booInp[9,5](
    final k=fill({true,true,false,true,false},9))
    "Boolean inputs"

equation
  connect(reaInp[1, :].y, zonStaDup.tNexOcc)
  connect(reaInp[2, :].y, zonStaDup.uCooTim)
  connect(reaInp[3, :].y, zonStaDup.uWarTim)
  connect(reaInp[4, :].y, zonStaDup.THeaSetOff)
  connect(reaInp[5, :].y, zonStaDup.TCooSetOff)
  connect(reaInp[6, :].y, zonStaDup.TZon)
  connect(booInp[1, :].y, zonStaDup.zonOcc)
  connect(booInp[2, :].y, zonStaDup.u1Occ)
  connect(booInp[3, :].y, zonStaDup.u1OccHeaHig)
  connect(booInp[4, :].y, zonStaDup.u1HigOccCoo)
  connect(booInp[5, :].y, zonStaDup.u1UnoHeaHig)
  connect(booInp[6, :].y, zonStaDup.u1EndSetBac)
  connect(booInp[7, :].y, zonStaDup.u1HigUnoCoo)
  connect(booInp[8, :].y, zonStaDup.u1EndSetUp)
  connect(booInp[9, :].y, zonStaDup.u1Win)
end ZoneStatusDuplicator;


Package with constants

within Buildings.Controls.OBC.CDL;
package Constants
  "Package with constants"
  // Machine dependent constants
  final constant Real eps=1E-15
    "Biggest number such that 1.0 + eps = 1.0";
  final constant Real small=1E-37
    "Smallest number such that small and -small are representable on the machine";
  final constant Real pi=2*Modelica.Math.asin(
    1.0)
    "Constant number pi, 3.14159265358979";
end Constants;


within Buildings.Controls.OBC;
package CDL "Package with blocks, examples and validation tests for control description language"
end CDL;


Convert Boolean to Integer signal. Block that outputs the Integer
equivalent of the Boolean input.

within Buildings.Controls.OBC.CDL.Conversions;
block BooleanToInteger
  "Convert Boolean to Integer signal"
  parameter Integer integerTrue=1
    "Output signal for true Boolean input";
  parameter Integer integerFalse=0
    "Output signal for false Boolean input";
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u
    "Connector of Boolean input signal"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y
    "Connector of Integer output signal"

equation
  y=if u then
      integerTrue
    else
      integerFalse;
end BooleanToInteger;


Convert Boolean to Real signal. Block that outputs the Real
equivalent of the Boolean input.

within Buildings.Controls.OBC.CDL.Conversions;
block BooleanToReal
  "Convert Boolean to Real signal"
  parameter Real realTrue=1.0
    "Output signal for true Boolean input";
  parameter Real realFalse=0.0
    "Output signal for false Boolean input";
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u
    "Connector of Boolean input signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput y
    "Connector of Real output signal"

equation
  y=if u then
      realTrue
    else
      realFalse;
end BooleanToReal;


Convert Integer to Real signals. Block that outputs the Real
equivalent of the Integer input.

within Buildings.Controls.OBC.CDL.Conversions;
block IntegerToReal
  "Convert Integer to Real signals"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u
    "Connector of Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput y
    "Connector of Real output signal"

equation
  y=u;
end IntegerToReal;


Package with blocks for type conversion

within Buildings.Controls.OBC.CDL;
package Conversions "Package with blocks for type conversion"
end Conversions;


Convert Real to Integer signal. Block that outputs y
as the nearest integer value of the input u.

within Buildings.Controls.OBC.CDL.Conversions;
block RealToInteger
  "Convert Real to Integer signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput u
    "Connector of Real input signal"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y
    "Connector of Integer output signal"

equation
  y=if
      (u > 0) then
      integer(
        floor(
          u+0.5))
    else
      integer(
        ceil(
          u-0.5));
end RealToInteger;


Validation model for the BooleanToInteger block. Validation test for the block

Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger.

within Buildings.Controls.OBC.CDL.Conversions.Validation;
model BooleanToInteger
  "Validation model for the BooleanToInteger block"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt
    "Block that converts Boolean to Integer signal"
  Buildings.Controls.OBC.CDL.Logical.Sources.Pulse booPul(
    period=1)
    "Generate cyclic on-and-off output"

equation
  connect(booPul.y,booToInt.u)
end BooleanToInteger;


Validation model for the BooleanToReal block. Validation test for the block

Buildings.Controls.OBC.CDL.Conversions.BooleanToReal.

within Buildings.Controls.OBC.CDL.Conversions.Validation;
model BooleanToReal
  "Validation model for the BooleanToReal block"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea
    "Block that converts Boolean to Real signal"
  Buildings.Controls.OBC.CDL.Logical.Sources.Pulse booPul(
    period=1)
    "Generate cyclic on-and-off output"

equation
  connect(booPul.y,booToRea.u)
end BooleanToReal;


Validation model for the IntegerToReal block. Validation test for the block

Buildings.Controls.OBC.CDL.Conversions.IntegerToReal.

within Buildings.Controls.OBC.CDL.Conversions.Validation;
model IntegerToReal
  "Validation model for the IntegerToReal block"
  Buildings.Controls.OBC.CDL.Conversions.IntegerToReal intToRea
    "Block that converts Integer to Real signal"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp1(
    duration=1,
    offset=-3.5,
    height=7.0)
    "Block that generates ramp signal"
  Buildings.Controls.OBC.CDL.Reals.Round round2(
    n=0)
    "Round real number to given digits"
  Buildings.Controls.OBC.CDL.Conversions.RealToInteger reaToInt1
    "Convert real to integer"

equation
  connect(ramp1.y,round2.u)
  connect(round2.y,reaToInt1.u)
  connect(reaToInt1.y,intToRea.u)
end IntegerToReal;


within Buildings.Controls.OBC.CDL.Conversions;
package Validation "Collection of models that validate the conversion blocks of the CDL"
end Validation;


Validation model for the RealToInteger block. Validation test for the block

Buildings.Controls.OBC.CDL.Conversions.RealToInteger.

within Buildings.Controls.OBC.CDL.Conversions.Validation;
model RealToInteger
  "Validation model for the RealToInteger block"
  Buildings.Controls.OBC.CDL.Conversions.RealToInteger reaToInt
    "Block that converts Real to Integer signal"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp1(
    duration=1,
    offset=-3.5,
    height=7.0)
    "Block that generates ramp signal"

equation
  connect(ramp1.y,reaToInt.u)
end RealToInteger;


First order hold of a sampled-data system. Block that outputs the extrapolation through the
values of the last two sampled input signals.

within Buildings.Controls.OBC.CDL.Discrete;
block FirstOrderHold
  "First order hold of a sampled-data system"
  parameter Real samplePeriod(
    final quantity="Time",
    final unit="s",
    min=1E-3)
    "Sample period of component";
  Buildings.Controls.OBC.CDL.Interfaces.RealInput u
    "Continuous input signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput y
    "Continuous output signal"

protected
  parameter Real t0(
    final quantity="Time",
    final unit="s",
    fixed=false)
    "First sample time instant";
  output Boolean sampleTrigger
    "True, if sample time instant";
  output Boolean firstTrigger(
    start=false,
    fixed=true)
    "Rising edge signals first sample instant";
  Real tSample(
    final quantity="Time",
    final unit="s")
    "Time of sample";
  Real uSample
    "Value of sample";
  Real pre_uSample
    "Value of previous sample";
  Real c
    "Slope";

initial equation
  t0=Buildings.Utilities.Math.Functions.round(
    x=integer(time/samplePeriod)*samplePeriod,
    n=6);
  pre(tSample)=t0;
  pre(uSample)=u;
  pre(pre_uSample)=u;
  pre(c)=0.0;

equation
  // Declarations that are used for all discrete blocks
  sampleTrigger=sample(
    t0,
    samplePeriod);
  when sampleTrigger then
    firstTrigger=time <= t0+samplePeriod/2;
    tSample=time;
    uSample=u;
    pre_uSample=pre(uSample);
    c=if firstTrigger then
        0
      else
        (uSample-pre_uSample)/samplePeriod;
  end when;
  /* Use pre_uSample and pre(c) to break potential algebraic loops by an
       infinitesimal delay if both the continuous and the discrete part
       have direct feedthrough.
    */
      y=pre_uSample+pre(c)*(time-tSample);
end FirstOrderHold;


Package with discrete blocks

within Buildings.Controls.OBC.CDL;
package Discrete "Package with discrete blocks"
end Discrete;


Ideal sampler of a continuous signal. Block that outputs the input signal, sampled at a sampling rate defined
via parameter samplePeriod.

within Buildings.Controls.OBC.CDL.Discrete;
block Sampler
  "Ideal sampler of a continuous signal"
  parameter Real samplePeriod(
    final quantity="Time",
    final unit="s",
    min=1E-3)
    "Sample period of component";
  Buildings.Controls.OBC.CDL.Interfaces.RealInput u
    "Continuous input signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput y
    "Continuous output signal"

protected
  parameter Real t0(
    final quantity="Time",
    final unit="s",
    fixed=false)
    "First sample time instant";
  output Boolean sampleTrigger
    "True, if sample time instant";
  output Boolean firstTrigger(
    start=false,
    fixed=true)
    "Rising edge signals first sample instant";

initial equation
  t0=Buildings.Utilities.Math.Functions.round(
    x=integer(time/samplePeriod)*samplePeriod,
    n=6);

equation
  // Declarations that are used for all discrete blocks
  sampleTrigger=sample(
    t0,
    samplePeriod);
  when sampleTrigger then
    firstTrigger=time <= t0+samplePeriod/2;
  end when;
  // Declarations specific to this type of discrete block
  when {sampleTrigger,initial()} then
    y=u;
  end when;
end Sampler;


Output the maximum, absolute value of a continuous signal at trigger instants. Block that outputs the input signal whenever the trigger input
signal is rising (i.e., trigger changes to
true). The maximum, absolute value of the input signal
at the sampling point is provided as the output signal.

within Buildings.Controls.OBC.CDL.Discrete;
block TriggeredMax
  "Output the maximum, absolute value of a continuous signal at trigger instants"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput u
    "Connector with a Real input signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput trigger
    "Connector for trigger"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput y
    "Connector with a Real output signal"

initial equation
  y=u;

equation
  when trigger then
    y=max(
      pre(y),
      abs(u));
  end when;
end TriggeredMax;


Triggered discrete moving mean of an input signal. Block that outputs the triggered moving mean value of an input signal.

within Buildings.Controls.OBC.CDL.Discrete;
block TriggeredMovingMean
  "Triggered discrete moving mean of an input signal"
  parameter Integer n(
    min=1)
    "Number of samples over which the input is averaged";
  Buildings.Controls.OBC.CDL.Interfaces.RealInput u
    "Continuous input signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput trigger
    "Boolean signal that triggers the block"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput y
    "Discrete averaged signal"

protected
  Integer iSample(
    start=0,
    fixed=true)
    "Sample numbering in the calculation";
  Integer counter(
    start=0,
    fixed=true)
    "Number of samples used for averaging calculation";
  Integer index(
    start=0,
    fixed=true)
    "Index of the vector ySample";
  discrete Real ySample[n](
    start=zeros(n),
    each fixed=true)
    "Vector of samples to be averaged";

equation
  when {initial(),trigger} then
    index=mod(
      pre(iSample),
      n)+1;
    ySample={
      if
        (i == index) then
        u
      else
        pre(ySample[i]) for i in 1:n};
    counter=
      if pre(counter) == n then
        n
      else
        pre(counter)+1;
    y=sum(ySample)/counter;
    iSample=pre(iSample)+1;
  end when;
end TriggeredMovingMean;


Triggered sampling of continuous signals. Samples the continuous input signal whenever the trigger input
signal is rising (i.e., trigger changes from false to
true) and provides the sampled input signal as output.
Before the first sampling, the output signal is equal to
the initial value defined via parameter y_start.

within Buildings.Controls.OBC.CDL.Discrete;
block TriggeredSampler
  "Triggered sampling of continuous signals"
  parameter Real y_start=0
    "Initial value of output signal";
  Buildings.Controls.OBC.CDL.Interfaces.RealInput u
    "Connector with a Real input signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput trigger
    "Signal that triggers the sampler"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput y
    "Connector with a Real output signal"

initial equation
  y=y_start;

equation
  when trigger then
    y=u;
  end when;
end TriggeredSampler;


Output the input signal with a unit delay. Block that outputs the input signal with a unit delay:

within Buildings.Controls.OBC.CDL.Discrete;
block UnitDelay
  "Output the input signal with a unit delay"
  parameter Real samplePeriod(
    final quantity="Time",
    final unit="s",
    min=1E-3)
    "Sample period of component";
  parameter Real y_start=0
    "Initial value of output signal";
  Buildings.Controls.OBC.CDL.Interfaces.RealInput u
    "Continuous input signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput y
    "Continuous output signal"

protected
  parameter Real t0(
    final quantity="Time",
    final unit="s",
    fixed=false)
    "First sample time instant";
  output Boolean sampleTrigger
    "True, if sample time instant";
  discrete Real u_internal
    "Input value at each sampling moment";

initial equation
  t0=Buildings.Utilities.Math.Functions.round(
    x=integer(time/samplePeriod)*samplePeriod,
    n=6);
  y=y_start;
  u_internal=y_start;

equation
  // Declarations that are used for all discrete blocks
  sampleTrigger=sample(
    t0,
    samplePeriod);
  when sampleTrigger then
    u_internal=u;
    y=pre(u_internal);
  end when;
end UnitDelay;


Output the input signal with a zero order hold. Block that outputs the sampled input signal at sample
time instants. The output signal is held at the value of the last
sample instant during the sample points.
At initial time, the block feeds the input directly to the output.

within Buildings.Controls.OBC.CDL.Discrete;
block ZeroOrderHold
  "Output the input signal with a zero order hold"
  parameter Real samplePeriod(
    final quantity="Time",
    final unit="s",
    min=1E-3)
    "Sample period of component";
  Buildings.Controls.OBC.CDL.Interfaces.RealInput u
    "Continuous input signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput y
    "Continuous output signal"

protected
  parameter Real t0(
    final quantity="Time",
    final unit="s",
    fixed=false)
    "First sample time instant";
  output Real ySample(
    fixed=true,
    start=0)
    "Sampled value of input";
  output Boolean sampleTrigger
    "True, if sample time instant";
  output Boolean firstTrigger(
    start=false,
    fixed=true)
    "Rising edge signals first sample instant";

initial equation
  t0=Buildings.Utilities.Math.Functions.round(
    x=integer(time/samplePeriod)*samplePeriod,
    n=6);

equation
  // Declarations that are used for all discrete blocks
  sampleTrigger=sample(
    t0,
    samplePeriod);
  when sampleTrigger then
    firstTrigger=time <= t0+samplePeriod/2;
  end when;
  // Declarations specific to this type of discrete block
  when {sampleTrigger,initial()} then
    ySample=u;
  end when;
  /* Define y=ySample with an infinitesimal delay to break potential
       algebraic loops if both the continuous and the discrete part have
       direct feedthrough
   */
  y=pre(ySample);
end ZeroOrderHold;


Example model for the FirstOrderHold block. Validation test for the block

Buildings.Controls.OBC.CDL.Discrete.FirstOrderHold.

within Buildings.Controls.OBC.CDL.Discrete.Validation;
model FirstOrderHold
  "Example model for the FirstOrderHold block"
  Buildings.Controls.OBC.CDL.Discrete.FirstOrderHold firOrdHol(
    samplePeriod=0.2)
    "Block that first order hold of a sampled-data system"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp1(
    duration=1,
    offset=0,
    height=6.2831852)
    "Block that generates ramp signal"
  Buildings.Controls.OBC.CDL.Reals.Cos cos1
    "Block that outputs the cosine of the input"

equation
  connect(ramp1.y,cos1.u)
  connect(cos1.y,firOrdHol.u)
end FirstOrderHold;


within Buildings.Controls.OBC.CDL.Discrete;
package Validation "Collection of models that validate the discrete blocks of the CDL"
end Validation;


Example model for the Sampler block. Validation test for the block

Buildings.Controls.OBC.CDL.Discrete.Sampler.

within Buildings.Controls.OBC.CDL.Discrete.Validation;
model Sampler
  "Example model for the Sampler block"
  Buildings.Controls.OBC.CDL.Discrete.Sampler sampler1(
    samplePeriod=0.2)
    "Ideal sampler of a continuous signal"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp1(
    duration=1,
    offset=0,
    height=6.2831852)
    "Block that generates ramp signal"
  Buildings.Controls.OBC.CDL.Reals.Sin sin1
    "Block that outputs the sine of the input"

equation
  connect(ramp1.y,sin1.u)
  connect(sin1.y,sampler1.u)
end Sampler;


Example model for the TriggeredMax block. Validation test for the block

Buildings.Controls.OBC.CDL.Discrete.TriggeredMax.

within Buildings.Controls.OBC.CDL.Discrete.Validation;
model TriggeredMax
  "Example model for the TriggeredMax block"
  Buildings.Controls.OBC.CDL.Discrete.TriggeredMax triggeredMax
    "Output the maximum, absolute value of a continuous signal at trigger instants"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp1(
    duration=1,
    offset=0,
    height=6.2831852)
    "Block that generates ramp signal"
  Buildings.Controls.OBC.CDL.Reals.Sin sin1
    "Block that outputs the sine of the input"
  Buildings.Controls.OBC.CDL.Logical.Sources.Pulse booPul(
    width=0.5,
    period=0.2)
    "Block that outputs cyclic on and off"

equation
  connect(ramp1.y,sin1.u)
  connect(sin1.y,triggeredMax.u)
  connect(booPul.y,triggeredMax.trigger)
end TriggeredMax;


Validation model for the TriggeredMovingMean block. Validation test for the block

Buildings.Controls.OBC.CDL.Discrete.TriggeredMovingMean.

within Buildings.Controls.OBC.CDL.Discrete.Validation;
model TriggeredMovingMean
  "Validation model for the TriggeredMovingMean block"
  Buildings.Controls.OBC.CDL.Reals.Sources.Sin sin(
    freqHz=1/8,
    phase=0.5235987755983,
    startTime=-0.5)
    "Example input signal"
  Buildings.Controls.OBC.CDL.Logical.Sources.Pulse booPul(
    width=0.5,
    period=1,
    shift=-0.5)
    "Block that outputs trigger signals"
  Buildings.Controls.OBC.CDL.Discrete.TriggeredMovingMean triMovMea(
    n=3)
    "Triggered moving mean with 3 samples to average"
  Buildings.Controls.OBC.CDL.Discrete.TriggeredMovingMean triMovMea1(
    n=1)
    "Triggered moving mean with 1 sample to average"
  Buildings.Controls.OBC.CDL.Discrete.TriggeredMovingMean triMovMea2(
    n=3)
    "Triggered moving mean with 3 samples to average with a different trigger period"
  Buildings.Controls.OBC.CDL.Logical.Sources.Pulse booPul1(
    width=0.5,
    period=1)
    "Block that outputs trigger signals"

equation
  connect(sin.y,triMovMea.u)
  connect(booPul.y,triMovMea.trigger)
  connect(booPul.y,triMovMea1.trigger)
  connect(sin.y,triMovMea1.u)
  connect(booPul1.y,triMovMea2.trigger)
  connect(sin.y,triMovMea2.u)
end TriggeredMovingMean;


Example model for the TriggeredSampler block. Validation test for the block

Buildings.Controls.OBC.CDL.Discrete.TriggeredSampler.

within Buildings.Controls.OBC.CDL.Discrete.Validation;
model TriggeredSampler
  "Example model for the TriggeredSampler block"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp1(
    duration=1,
    offset=0,
    height=6.2831852)
    "Block that generates ramp signal"
  Buildings.Controls.OBC.CDL.Reals.Sin sin1
    "Block that outputs the sine of the input"
  Buildings.Controls.OBC.CDL.Logical.Sources.Pulse booPul(
    width=0.5,
    period=0.2)
    "Block that outputs cyclic on and off"
  Buildings.Controls.OBC.CDL.Discrete.TriggeredSampler triSam
    "Triggered sampler wity y_start = 0"
  Buildings.Controls.OBC.CDL.Discrete.TriggeredSampler triSam1(
    y_start=1)
    "Triggered sampler with y_start = 1"

equation
  connect(ramp1.y,sin1.u)
  connect(sin1.y,triSam.u)
  connect(booPul.y,triSam.trigger)
  connect(sin1.y,triSam1.u)
  connect(booPul.y,triSam1.trigger)
end TriggeredSampler;


Example model for the UnitDelay block. Validation test for the block

Buildings.Controls.OBC.CDL.Discrete.UnitDelay.

within Buildings.Controls.OBC.CDL.Discrete.Validation;
model UnitDelay
  "Example model for the UnitDelay block"
  Buildings.Controls.OBC.CDL.Discrete.UnitDelay unitDelay1(
    samplePeriod=0.2)
    "Sample period of component"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp1(
    duration=1,
    offset=0,
    height=6.2831852)
    "Block that generates ramp signal"
  Buildings.Controls.OBC.CDL.Reals.Sin sin1
    "Block that outputs the sine of the input"

equation
  connect(ramp1.y,sin1.u)
  connect(sin1.y,unitDelay1.u)
end UnitDelay;


Example model for the ZeroOrderHold block. Validation test for the block

Buildings.Controls.OBC.CDL.Discrete.ZeroOrderHold.

within Buildings.Controls.OBC.CDL.Discrete.Validation;
model ZeroOrderHold
  "Example model for the ZeroOrderHold block"
  Buildings.Controls.OBC.CDL.Discrete.ZeroOrderHold zerOrdHol(
    samplePeriod=0.2)
    "Output the input signal with a zero order hold"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp1(
    duration=1,
    offset=0,
    height=6.2831852)
    "Block that generates ramp signal"
  Buildings.Controls.OBC.CDL.Reals.Cos cos1
    "Block that outputs the cosine of the input"

equation
  connect(ramp1.y,cos1.u)
  connect(cos1.y,zerOrdHol.u)
end ZeroOrderHold;


Output the absolute value of the input. Block that outputs y = abs(u),
where
u is an Integer input.

within Buildings.Controls.OBC.CDL.Integers;
block Abs
  "Output the absolute value of the input"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u
    "Connector of Integer input signals"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y
    "Connector of Integer output signals"

equation
  y=if u >= 0 then
      u
    else
      -u;
end Abs;


Output the sum of the two inputs. Block that outputs y as the sum of the
two Integer input signals u1 and u2,

within Buildings.Controls.OBC.CDL.Integers;
block Add
  "Output the sum of the two inputs"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u1
    "Connector of Integer input signal 1"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u2
    "Connector of Integer input signal 2"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y
    "Connector of Integer output signal"

equation
  y=u1+u2;
end Add;


Output the sum of an input plus a parameter. Block that outputs y = u + p,
where p is parameter and u is an input.

within Buildings.Controls.OBC.CDL.Integers;
block AddParameter "Output the sum of an input plus a parameter"
  parameter Integer p
    "Value to be added";
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u "Connector of Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y "Connector of Integer output signal"

equation
  y=u+p;
end AddParameter;


Output whether the Integer input changes values, increases or decreases. Block that evaluates the integer input u to check if its value
changes.

within Buildings.Controls.OBC.CDL.Integers;
block Change
  "Output whether the Integer input changes values, increases or decreases"
  parameter Integer pre_u_start=0
    "Start value of pre(u) at initial time";
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u
    "Connector of Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y
    "Connector of Boolean output signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput up
    "Connector of Boolean output signal indicating input increase"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput down
    "Connector of Boolean output signal indicating input decrease"

initial equation
  pre(u)=pre_u_start;

equation
  y=change(u);
  up=u > pre(u);
  down=u < pre(u);
end Change;


Output y is true, if input u1 is equal to input u2. Block that outputs true if the Integer input u1
is equal to the Integer input u2.
Otherwise the output is false.

within Buildings.Controls.OBC.CDL.Integers;
block Equal
  "Output y is true, if input u1 is equal to input u2"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u1
    "Connector of first Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u2
    "Connector of second Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y
    "Connector of Boolean output signal"

equation
  y=u1 == u2;
end Equal;


Output y is true, if input u1 is greater than input u2. Block that outputs true if the Integer input u1
is greater than the Integer input u2.
Otherwise the output is false.

within Buildings.Controls.OBC.CDL.Integers;
block Greater
  "Output y is true, if input u1 is greater than input u2"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u1
    "Connector of first Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u2
    "Connector of second Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y
    "Connector of Boolean output signal"

equation
  y=u1 > u2;
end Greater;


Output y is true, if input u1 is greater or equal than input u2. Block that outputs true if Integer the input u1
is greater than or equal to the Integer input u2.
Otherwise the output is false.

within Buildings.Controls.OBC.CDL.Integers;
block GreaterEqual
  "Output y is true, if input u1 is greater or equal than input u2"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u1
    "Connector of first Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u2
    "Connector of second Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y
    "Connector of Boolean output signal"

equation
  y=u1 >= u2;
end GreaterEqual;


Output y is true, if input u is greater or equal than threshold. Block that outputs true if the Integer input is greater than or equal to
the parameter t.
Otherwise the output is false.

within Buildings.Controls.OBC.CDL.Integers;
block GreaterEqualThreshold
  "Output y is true, if input u is greater or equal than threshold"
  parameter Integer t=0
    "Comparison with respect to a threshold";
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u
    "Connector of Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y
    "Connector of Boolean output signal"

equation
  y=u >= t;
end GreaterEqualThreshold;


Output y is true, if input u is greater than a threshold. Block that outputs true if the Integer input is greater than
the parameter t.
Otherwise the output is false.

within Buildings.Controls.OBC.CDL.Integers;
block GreaterThreshold
  "Output y is true, if input u is greater than a threshold"
  parameter Integer t=0
    "Threshold for comparison";
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u
    "Connector of Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y
    "Connector of Boolean output signal"

equation
  y=u > t;
end GreaterThreshold;


Output y is true, if input u1 is less than input u2. Block that outputs true if the Integer input u1
is less than the Integer input u2.
Otherwise the output is false.

within Buildings.Controls.OBC.CDL.Integers;
block Less
  "Output y is true, if input u1 is less than input u2"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u1
    "Connector of first Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u2
    "Connector of second Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y
    "Connector of Boolean output signal"

equation
  y=u1 < u2;
end Less;


Output y is true, if input u1 is less or equal than input u2. Block that outputs true if the Integer input u1
is less than or equal to the Integer input u2.
Otherwise the output is false.

within Buildings.Controls.OBC.CDL.Integers;
block LessEqual
  "Output y is true, if input u1 is less or equal than input u2"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u1
    "Connector of first Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u2
    "Connector of second Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y
    "Connector of Boolean output signal"

equation
  y=u1 <= u2;
end LessEqual;


Output y is true, if input u is less or equal than a threshold. Block that outputs true if the Integer input is less than or equal to
the parameter t.
Otherwise the output is false.

within Buildings.Controls.OBC.CDL.Integers;
block LessEqualThreshold
  "Output y is true, if input u is less or equal than a threshold"
  parameter Integer t=0
    "Threshold for comparison";
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u
    "Connector of Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y
    "Connector of Boolean output signal"

equation
  y=u <= t;
end LessEqualThreshold;


Output y is true, if input u is less than a threshold. Block that outputs true if the Integer input is less than
the parameter t.
Otherwise the output is false.

within Buildings.Controls.OBC.CDL.Integers;
block LessThreshold
  "Output y is true, if input u is less than a threshold"
  parameter Integer t=0
    "Threshold for comparison";
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u
    "Connector of Integer input signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y
    "Connector of Boolean output signal"

equation
  y=u < t;
end LessThreshold;


Pass through the largest signal. Block that outputs y = max(u1, u2),
where
u1 and u2 are inputs.

within Buildings.Controls.OBC.CDL.Integers;
block Max
  "Pass through the largest signal"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u1
    "Connector of Integer input signal 1"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u2
    "Connector of Integer input signal 2"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y
    "Connector of Integer output signal"

equation
  y=max(
    u1,
    u2);
end Max;


Pass through the smallest signal. Block that outputs y = min(u1, u2),
where
u1 and u2 are inputs.

within Buildings.Controls.OBC.CDL.Integers;
block Min
  "Pass through the smallest signal"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u1
    "Connector of Integer input signal 1"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u2
    "Connector of Integer input signal 2"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y
    "Connector of Integer output signal"

equation
  y=min(
    u1,
    u2);
end Min;


Output product of the two inputs. Block that outputs y = u1 * u2,
where
u1 and u2 are Integer inputs.

within Buildings.Controls.OBC.CDL.Integers;
block Multiply "Output product of the two inputs"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u1
    "Connector of Integer input signal 1"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u2
    "Connector of Integer input signal 2"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y
    "Connector of Integer output signal"

equation
  y=u1*u2;
end Multiply;


Sum of Integers, y = k[1]*u[1] + k[2]*u[2] + ... + k[n]*u[n]. Block that outputs

within Buildings.Controls.OBC.CDL.Integers;
block MultiSum
  "Sum of Integers, y = k[1]*u[1] + k[2]*u[2] + ... + k[n]*u[n]"
  parameter Integer nin(
    min=0)=0
    "Number of input connections"
  parameter Integer k[nin]=fill(
    1,
    nin)
    "Input gains";
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u[nin]
    "Connector of Integer input signals"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y
    "Connector of Integer output signal"

equation
  if size(
    u,
    1) > 0 then
    y=k*u;
  else
    y=0;
  end if;
end MultiSum;


Increment the output if the input switches to true. Block that outputs how often the trigger input changed to true
since the last invocation of reset.

within Buildings.Controls.OBC.CDL.Integers;
block OnCounter
  "Increment the output if the input switches to true"
  parameter Integer y_start=0
    "Initial and reset value of y if input reset switches to true";
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput trigger
    "Boolean input signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput reset
    "Reset the counter"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y
    "Integer output signal"

initial equation
  pre(y)=y_start;

equation
  when {trigger,reset} then
    y=if reset then
        y_start
      else
        pre(y)+1;
  end when;
end OnCounter;


within Buildings.Controls.OBC.CDL;
package Integers "Package with blocks for integer variables"
end Integers;


Output total stages that should be enabled. Block that outputs the total number of stages to be enabled.

within Buildings.Controls.OBC.CDL.Integers;
block Stage "Output total stages that should be enabled"

  parameter Integer n(final min=1)
    "Number of stages that could be enabled";

  parameter Real holdDuration(
    final quantity="Time",
    final unit="s",
    min=0)
    "Minimum time that the output needs to be held constant. Set to 0 to disable hold time";

  parameter Real h(
    min=0.001/n,
    max=0.5/n) = 0.02/n "Hysteresis for comparing input with threshold";

  parameter Integer pre_y_start = 0
    "Value of pre(y) at initial time";

  Buildings.Controls.OBC.CDL.Interfaces.RealInput u(
    final min=0,
    final max=1)
    "Real input for specifying stages"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y(
    final min=1,
    final max=n)
    "Total number of stages that should be enabled"

protected
  final parameter Real staThr[n]={(i - 1)/n for i in 1:n}
    "Stage thresholds";
  discrete Real tNext(
    final unit="s")
    "Next instant at which the block checks if it has passed the minimum hold time";
  discrete Real upperThreshold
    "Current upper bound of the stage range which the input is in";
  discrete Real lowerThreshold
    "Current lower bound of the stage range which the input is in";
  Boolean checkUpper
    "Check if the input value is greater than the upper bound";
  Boolean checkLower
    "Check if the input value is greater than the lower bound";

initial equation
  upperThreshold = 0;
  lowerThreshold = 0;
  pre(checkUpper) = false;
  pre(checkLower) = true;
  tNext =time + holdDuration;
  pre(y)=pre_y_start;

equation
  checkUpper = not pre(checkUpper) and (u > (pre(upperThreshold) + h)) or pre(checkUpper) and (u >= (pre(upperThreshold) - h));
  checkLower = not pre(checkLower) and (u > (pre(lowerThreshold) + h)) or pre(checkLower) and (u >= (pre(lowerThreshold) - h));

  when (time >= pre(tNext) and (checkUpper or not checkLower)) then
    tNext =time + holdDuration;
    y =if (u >= staThr[n])
      then
        n
      else
        sum({(if ((u < staThr[i]) and (u >= staThr[i - 1])) then i - 1 else 0) for i in 2:n});
    upperThreshold = if (y == n) then staThr[n] else staThr[y + 1];
    lowerThreshold = if (y == 0) then pre(lowerThreshold) else staThr[y];
  end when;
end Stage;


Output the difference of the two inputs. Block that outputs y as the difference of the
two input signals u1 and u2,

within Buildings.Controls.OBC.CDL.Integers;
block Subtract "Output the difference of the two inputs"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u1
    "Connector of Integer input signal 1"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u2
    "Connector of Integer input signal 2"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y
    "Connector of Integer output signal"

equation
  y=u1-u2;
end Subtract;