Description: "Package with example for how to build a model for boiler with a heating load"

- Home > Modelica

## Buildings.Examples.Tutorial.Boiler

Package with example for how to build a model for boiler with a heating load

### Information

This package contains examples with step-by-step instructions for how to build a system model for a boiler with a heat load as shown in the figure below. The pressure drops of the individual flow branches and the temperatures correspond to design conditions. The heating system shall be designed to provide 20 kW, which is the load needed at -10°C outdoor temperature. This load already takes into account the heat required for air infiltration and ventilation. Using this load and the temperatures shown in the schematic drawing, the nominal mass flow rates of the individual flow branches should be computed. From 8:00 to 18:00, there is an internal heat gain of 4kW, which should not be accounted for when sizing the system.

The room volume is 180m3. To approximate the thermal storage effect of furniture and building constructions, the heat capacity of the room should be increased by a factor of three. (Modeling a detailed room heat transfer as implemented in Buildings.Rooms is out of scope for this tutorial.)

The space heating shall be switched on if the outdoor temperature is below 16°C and the room temperature is below 20°C. It shall be switched off if either the outdoor temperature is above 17°C or the room temperature is above 21°C.

The model consists of

1. a room with a heating load, approximated as steady-state heat transfer with the environment,
2. a heating loop with a constant bypass and a three-way valve, which is modulated to track the room temperature set point, and
3. a boiler loop with constant mass flow rate, boiler on/off control and control valve to ensure a minimum return water temperature.

To explain the implementation of this model, the model has been created in the following stages:

1. Buildings.Examples.Tutorial.Boiler.System1 implements the room model without any heating.
2. Buildings.Examples.Tutorial.Boiler.System2 adds a radiator that is fed with water at a constant temperature and flow rate. The pump is switched on and off depending on the room temperature.
3. Buildings.Examples.Tutorial.Boiler.System3 adds the boiler circuit with open loop control for the boiler and the mixing valves.
4. Buildings.Examples.Tutorial.Boiler.System4 adds closed loop control for the boiler and the pumps.
5. Buildings.Examples.Tutorial.Boiler.System5 adds closed loop control for the two valves.
6. Buildings.Examples.Tutorial.Boiler.System6 replaces the constant outdoor temperature with weather data from a file, and changes the valve control from P-control to PI-control.
7. Buildings.Examples.Tutorial.Boiler.System7 replaces the boiler and pump control using a state machine.

Extends from Modelica.Icons.ExamplesPackage (Icon for packages containing runnable examples).

### Package Content

Name | Description
--- | ---
System1 | 1st part of the system model, consisting of the room with heat transfer
System2 | 2nd part of the system model, consisting of the room with heat transfer and a radiator
System3 | 3rd part of the system model, which adds the boiler loop with open loop control
System4 | 4th part of the system model, which adds closed-loop control for the pumps and the boiler
System5 | 5th part of the system model, which adds closed-loop control for the valves
System6 | 6th part of the system model, which adds weather data and changes to PI control
System7 | 7th part of the system model, which implements the on/off control using a state machine

## Buildings.Examples.Tutorial.Boiler.System1

1st part of the system model, consisting of the room with heat transfer

### Information

This part of the system model implements the room with a heat gain. The room is simplified as a volume of air, a prescribed heat source for the internal convective heat gain, and a heat conductor for steady-state heat conduction to the outside. To increase the heat capacity of the room, such as due to heat stored in furniture and in building constructions, the heat capacity of the room air was increased by a factor of three. The convective heat transfer coefficient is lumped into the heat conductor model.

#### Implementation

This section describes step by step how we implemented the model.

1. First, to define the medium properties, we added the declaration

         replaceable package MediumA =
             Buildings.Media.Air;

   This will allow the propagation of the medium model to all models that contain air. In this example, there is only one model with air.

   We called the medium `MediumA` to distinguish it from `MediumW` that we will use in later versions of the model for components that have water as a medium. Because we do not anticipate saturated air, we used the medium model Buildings.Media.Air instead of Buildings.Media.GasesPTDecoupled.MoistAir as the latter is computationally more expensive. Because in this model, we are not interested in air humidification or dehumidification, we could have as well used the medium model Buildings.Media.GasesPTDecoupled.SimpleAir.

   We also defined the system-level parameters

         parameter Modelica.SIunits.Volume V=6*10*3 "Room volume";
         parameter Modelica.SIunits.MassFlowRate mA_flow_nominal = V*6/3600
           "Nominal mass flow rate";
         parameter Modelica.SIunits.HeatFlowRate QRooInt_flow = 4000
           "Internal heat gains of the room";

   to declare that the room volume is 180 m3, that the room has a nominal mass flow rate of 6 air changes per hour and that the internal heat gains of the room are 4000 Watts. These parameters have been declared at the top-level of the model as they will be used in several other models. Declaring them at the top-level allows to propagate them to other models, and to easily change them at one location should this be required when revising the model.

2. To model the room air, approximated as a completely mixed volume of air, an instance of Buildings.Fluid.MixingVolumes.MixingVolume has been used, as this model can be used with dry air or moist air. The medium model has been set to `MediumA`, and the nominal mass flow rate is set to `mA_flow_nominal`. The nominal mass flow rate is used for numerical reasons and should be set to the approximate order of magnitude. It only has an effect if the mass flow rate is near zero and what "near zero" means depends on the magnitude of `m_flow_nominal`, as it is used for the default value of the parameter `m_flow_small` on the `Assumptions` tag of the model. See also Buildings.Fluid.UsersGuide for an explanation of the purpose of `m_flow_small`.

3. Since we need to increase the heat capacity of the room air to approximate energy storage in furniture and building constructions, we connected the instance `heaCap` of Modelica.Thermal.HeatTransfer.Components.HeatCapacitor to the heat port of the room air. The model `heaCap` models energy storage. We set its capacity to C=2*V*1.2*1006 J/K. This will increase the total heat capacity of the room air by a factor of three.

4. We used the instance `theCon` of Modelica.Thermal.HeatTransfer.Components.ThermalConductor to model the thermal conductance to the ambient. Since our room should have a heat loss of 20 kW at a temperature difference of 30 Kelvin, we set the conductance to G=20000 ⁄ 30 W/K.

5. We used the instance `preHea` of Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow to model a prescribed heat gain, such as due to internal heat source. This model outputs the heat gain which is equal to the value of its input signal, which is obtained from a time table.

6. To define a time-dependent heat gain, we instantiated the block Modelica.Blocks.Sources.CombiTimeTable and set its name to `timTab`. We set the table parameters to

         Modelica.Blocks.Sources.CombiTimeTable timTab(
             extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
             smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments,
             table=[-6*3600, 0;
                     8*3600, QRooInt_flow;
                    18*3600, 0]) "Time table for internal heat gain";

   Note that we set the output to be a periodic signal by configuring `extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic.` The first time stamp is -6*3600 seconds in order to create a table that has a periodicity of one day. We also set the interpolation of the data to using piece-wise constant segments. See the documentation of Modelica.Blocks.Sources.CombiTimeTable for the various options of this time table.

7. Next, we connected its output to the input of the instance `preHea`.

This completes the initial version of the model. When simulating the model for 2 days, or 172800 seconds, the response shown below should be seen.

To verify the correctness of the model, we can compare the simulated results to the following analytical solutions:

1. When the internal heat gain is zero, the room temperature should be equal to the outside temperature.

2. At steady-state when the internal heat gain is 4000 Watts, the temperature difference to the outside should be Δ T = Q̇ ⁄ UA = 4000/(20000/30) = 6 Kelvin, which corresponds to a room temperature of -4°C.

Both analytical values agree with the simulation results shown in the above figure.

An alternative validation can be done by fixing the temperature of the volume to 20°C and plotting the heat flow rate that is needed to maintain this temperature. This can be implemented by connecting an instance of Modelica.Thermal.HeatTransfer.Sources.FixedTemperature as shown below.

When plotting the heat flow rate `fixTemp.port.Q_flow`, one can see that the required heat flow rate to keep the temperature at 20°C is 20 kW during night, and 16 kW during day when the heat gain is active.

#### Notes

For a more realistic model of a room, the model Buildings.Rooms.MixedAir could have been used. For transient heat conduction, models from the package Buildings.HeatTransfer.Conduction could have been used.

Extends from Modelica.Icons.Example (Icon for runnable examples).

### Parameters

Type | Name | Default | Description
--- | --- | --- | ---
replaceable package MediumA | Buildings.Media.Air |
Volume | V | 6*10*3 | Room volume [m3]
MassFlowRate | mA_flow_nominal | V*6/3600 | Nominal mass flow rate [kg/s]
HeatFlowRate | QRooInt_flow | 4000 | Internal heat gains of the room [W]

### Connectors

Type | Name | Description
--- | --- | ---
replaceable package MediumA |

### Modelica definition

model System1 "1st part of the system model, consisting of the room with heat transfer" extends Modelica.Icons.Example; replaceable package MediumA = Buildings.Media.Air; Fluid.MixingVolumes.MixingVolume vol( redeclare package Medium = MediumA, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mA_flow_nominal, V=V); Modelica.Thermal.HeatTransfer.Components.ThermalConductor theCon(G=20000/30) "Thermal conductance with the ambient"; parameter Modelica.SIunits.Volume V=6*10*3 "Room volume"; parameter Modelica.SIunits.MassFlowRate mA_flow_nominal = V*6/3600 "Nominal mass flow rate"; parameter Modelica.SIunits.HeatFlowRate QRooInt_flow = 4000 "Internal heat gains of the room"; Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TOut(T=263.15) "Outside temperature"; Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHea "Prescribed heat flow"; Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heaCap(C=2*V*1.2*1006) "Heat capacity for furniture and walls"; Modelica.Blocks.Sources.CombiTimeTable timTab( extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic, smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments, table=[-6*3600, 0; 8*3600, QRooInt_flow; 18*3600, 0]) "Time table for internal heat gain"; equation connect(TOut.port, theCon.port_a); connect(theCon.port_b, vol.heatPort); connect(preHea.port, vol.heatPort); connect(heaCap.port, vol.heatPort); connect(timTab.y[1], preHea.Q_flow); end System1;

## Buildings.Examples.Tutorial.Boiler.System2

2nd part of the system model, consisting of the room with heat transfer and a radiator

### Information

This part of the system model adds a radiator with a prescribed mass flow rate to the system that is implemented in Buildings.Examples.Tutorial.Boiler.System1.

#### Implementation

This model was built as follows:

1. First, we copied the model Buildings.Examples.Tutorial.Boiler.System1 and called it `Buildings.Examples.Tutorial.Boiler.System2`.

2. Since this model uses water as the medium, we declared the water medium model at the top-level of the model by adding the lines

         replaceable package MediumW =
             Buildings.Media.ConstantPropertyLiquidWater "Medium model";

3. To model the pump, a temperature sensor which we will need later for the control, and a flow sink, we made instances of the models Buildings.Fluid.Movers.FlowControlled_m_flow (instance `pumRad` for the pump that serves the radiators), Buildings.Fluid.Sensors.TemperatureTwoPort (instance `temSup`), Buildings.Fluid.HeatExchangers.Radiators.RadiatorEN442_2 (instance `rad`), and Buildings.Fluid.Sources.FixedBoundary (instance `sou` and `sin` for the sink and source reservoirs, which will later be replace by the boiler loop).

   In all of these instances, we set the medium model to `MediumW`. We also made an instance of the model Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor (instance `temRoo`) to measure the room temperature. We connected the model as shown in the figure below.

   Note that there are two connections from the radiator to the room volume: One connection is for the convective heat flow rate, and the other is for the radiative heat flow rate. For simplicity, we assumed that the air and radiative temperature of the room are equal. Furthermore, we simplified the model by using only one radiator instead of multiple radiators, although this radiator will be quite large as it needs to provide a heat flow rate of 20 kW.

4. Next, we computed the design mass flow rate for the radiator. According to the schematic drawing, the radiator should have at the design conditions a supply water temperature of 50°C and a return water temperature of 40°C. Thus, we define the radiator mass flow rate as

         parameter Modelica.SIunits.HeatFlowRate Q_flow_nominal = 20000
           "Nominal heat flow rate of radiator";
         parameter Modelica.SIunits.Temperature TRadSup_nominal = 273.15+50
           "Radiator nominal supply water temperature";
         parameter Modelica.SIunits.Temperature TRadRet_nominal = 273.15+40
           "Radiator nominal return water temperature";
         parameter Modelica.SIunits.MassFlowRate mRad_flow_nominal =
           Q_flow_nominal/4200/(TRadSup_nominal-TRadRet_nominal)
           "Radiator nominal mass flow rate";

5. Now, we set the mass flow rate of `pumRad` and `temSup` to `mRad_flow_nominal`. We also set the temperature of the fluid that flows out of `sou` to `TRadSup_nominal`. We configured the parameters of the radiator model as

         Buildings.Fluid.HeatExchangers.Radiators.RadiatorEN442_2 rad(
           redeclare package Medium = MediumW,
           energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
           Q_flow_nominal=Q_flow_nominal,
           T_a_nominal=TRadSup_nominal,
           T_b_nominal=TRadRet_nominal) "Radiator";

   We configured the parameters of the pump model as

         Buildings.Fluid.Movers.FlowControlled_m_flow pumRad(
           redeclare package Medium = MediumW,
           energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
           m_flow_nominal=mRad_flow_nominal)
           "Pump for radiator";

6. To enable the pump when the room temperature is below 19°C and to switch it off when the room temperature is below 21°C, we implemented the control blocks as shown in the figure below.

   In this control sequence, the first block is a hysteresis element, which is modeled by Modelica.Blocks.Logical.Hysteresis. It is configured as

         Modelica.Blocks.Logical.Hysteresis hysPum(
           uLow=273.15 + 19,
           uHigh=273.15 + 21)
           "Pump hysteresis";

   to output `false` when the input signal falls below 19°C, and `true` when the input signal raises above 21°C. Next, we send the output to the instance `not1`, which outputs

         y= not u

   to negate the signal. The output of this signal is a boolean value, but the pump input signal is the required mass flow rate. Thus, we used the block Modelica.Blocks.Math.BooleanToReal to convert the signal. We set the parameters of the boolean to real converter as

         Modelica.Blocks.Math.BooleanToReal booToReaRad(
               realTrue=mRad_flow_nominal,
               realFalse=0) "Radiator pump signal";

   For numerical reasons, in particular in large system models, it is recommended to continuously change the mass flow rate, as opposed to having a step change. Therefore, in the instance `pumRad`, we leave the parameter `filteredSpeed` at its default value `true`. This will approximate a continuous change in mass flow rate when the pump is switched on or off. Finally, we closed the control loop between the room temperature sensor and the pump input signal.

This completes the initial version of the model. When simulating the model for 2 days, or 172800 seconds, the response shown below should be seen.

The figure shows that the room temperature is maintained at 20°C when the internal heat gain is zero, and controlled around 19°C to 21°C when there is an internal heat gain. The temperature is slightly outside this temperature range because of the time lag that is caused by the thermal capacity of the radiator.

#### Notes

For a more realistic model of a room, the model Buildings.Rooms.MixedAir could have been used. For transient heat conduction, models from the package Buildings.HeatTransfer.Conduction could have been used.

Extends from Modelica.Icons.Example (Icon for runnable examples).

### Parameters

Type | Name | Default | Description
--- | --- | --- | ---
replaceable package MediumA | Buildings.Media.Air |
replaceable package MediumW | Buildings.Media.Water | Medium model
HeatFlowRate | Q_flow_nominal | 20000 | Nominal heat flow rate of radiator [W]
Temperature | TRadSup_nominal | 273.15 + 50 | Radiator nominal supply water temperature [K]
Temperature | TRadRet_nominal | 273.15 + 40 | Radiator nominal return water temperature [K]
MassFlowRate | mRad_flow_nominal | Q_flow_nominal/4200/(TRadSup... | Radiator nominal mass flow rate [kg/s]
Volume | V | 6*10*3 | Room volume [m3]
MassFlowRate | mA_flow_nominal | V*6/3600 | Nominal mass flow rate [kg/s]
HeatFlowRate | QRooInt_flow | 4000 | Internal heat gains of the room [W]

### Connectors

Type | Name | Description
--- | --- | ---
replaceable package MediumA |
replaceable package MediumW | Medium model

### Modelica definition

model System2 "2nd part of the system model, consisting of the room with heat transfer and a radiator" extends Modelica.Icons.Example; replaceable package MediumA = Buildings.Media.Air; //-------------------------Step 2: Water as medium-------------------------// replaceable package MediumW = Buildings.Media.Water "Medium model"; //-------------------------------------------------------------------------// //------------------------Step 4: Design conditions------------------------// parameter Modelica.SIunits.HeatFlowRate Q_flow_nominal = 20000 "Nominal heat flow rate of radiator"; parameter Modelica.SIunits.Temperature TRadSup_nominal = 273.15+50 "Radiator nominal supply water temperature"; parameter Modelica.SIunits.Temperature TRadRet_nominal = 273.15+40 "Radiator nominal return water temperature"; parameter Modelica.SIunits.MassFlowRate mRad_flow_nominal= Q_flow_nominal/4200/(TRadSup_nominal-TRadRet_nominal) "Radiator nominal mass flow rate"; //------------------------------------------------------------------------// Fluid.MixingVolumes.MixingVolume vol( redeclare package Medium = MediumA, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mA_flow_nominal, V=V); Modelica.Thermal.HeatTransfer.Components.ThermalConductor theCon(G=20000/30) "Thermal conductance with the ambient"; parameter Modelica.SIunits.Volume V=6*10*3 "Room volume"; parameter Modelica.SIunits.MassFlowRate mA_flow_nominal = V*6/3600 "Nominal mass flow rate"; parameter Modelica.SIunits.HeatFlowRate QRooInt_flow = 4000 "Internal heat gains of the room"; Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TOut(T=263.15) "Outside temperature"; Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHea "Prescribed heat flow"; Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heaCap(C=2*V*1.2*1006) "Heat capacity for furniture and walls"; Modelica.Blocks.Sources.CombiTimeTable timTab( extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic, smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments, table=[-6*3600, 0; 8*3600, QRooInt_flow; 18*3600, 0]) "Time table for internal heat gain"; //-------------------------Step 5: Radiator Model-------------------------// Buildings.Fluid.HeatExchangers.Radiators.RadiatorEN442_2 rad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, Q_flow_nominal=Q_flow_nominal, T_a_nominal=TRadSup_nominal, T_b_nominal=TRadRet_nominal) "Radiator"; //------------------------------------------------------------------------// Fluid.Sources.FixedBoundary sin(nPorts=1, redeclare package Medium = MediumW) "Sink for mass flow rate"; Fluid.Sensors.TemperatureTwoPort temSup(redeclare package Medium = MediumW, m_flow_nominal=mRad_flow_nominal) "Supply water temperature"; Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor temRoo "Room temperature"; //------------------------Step 5: Pump for radiator-----------------------// Buildings.Fluid.Movers.FlowControlled_m_flow pumRad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRad_flow_nominal) "Pump for radiator"; //------------------------------------------------------------------------// Fluid.Sources.FixedBoundary sou( nPorts=1, redeclare package Medium = MediumW, T=TRadSup_nominal) "Sink for mass flow rate"; //--------------------------Step 6: Pump control--------------------------// Modelica.Blocks.Logical.Hysteresis hysPum(uLow=273.15 + 19, uHigh=273.15 + 21) "Pump hysteresis"; Modelica.Blocks.Math.BooleanToReal booToReaRad(realTrue=mRad_flow_nominal) "Radiator pump signal"; Modelica.Blocks.Logical.Not not1 "Negate output of hysteresis"; //------------------------------------------------------------------------// equation connect(TOut.port, theCon.port_a); connect(theCon.port_b, vol.heatPort); connect(preHea.port, vol.heatPort); connect(heaCap.port, vol.heatPort); connect(timTab.y[1], preHea.Q_flow); connect(temSup.port_b, rad.port_a); connect(rad.port_b, sin.ports[1]); connect(temRoo.port, vol.heatPort); connect(rad.heatPortCon, vol.heatPort); connect(rad.heatPortRad, vol.heatPort); connect(sou.ports[1], pumRad.port_a); connect(pumRad.port_b, temSup.port_a); connect(temRoo.T, hysPum.u); connect(hysPum.y, not1.u); connect(not1.y, booToReaRad.u); connect(booToReaRad.y, pumRad.m_flow_in); end System2;

## Buildings.Examples.Tutorial.Boiler.System3

3rd part of the system model, which adds the boiler loop with open loop control

### Information

This part of the system model adds the boiler loop with open loop control to the model that is implemented in Buildings.Examples.Tutorial.Boiler.System2.

#### Implementation

This model was built as follows:

1. First, we copied the model Buildings.Examples.Tutorial.Boiler.System2 and called it `Buildings.Examples.Tutorial.Boiler.System3`.

2. Next, we deleted the sink and source models `sin` and `sou`, as these will be replaced by the boiler loop.

3. We made various instances of Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM to model flow splitter and mixers. We also made an instance of Buildings.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear to model the three-way valves, and an instance of Buildings.Fluid.Boilers.BoilerPolynomial to model the boiler.

   Note that we also made an instance of Buildings.Fluid.Sources.FixedBoundary, which we called `preSou`. This is required to set a pressure reference in the water loop, which is a closed system. For medium models that expand with increasing temperature, this is also required to accumulate, and to feed back into the system, the difference in mass due to the thermal expansion of water.

4. Next, we parameterized the medium of all these components by setting it to `MediumW`.

   Since the nominal mass flow rate for the boiler loop is required by several models, we introduced the following system-level parameters, where `TBoiRet_min` will be used to avoid condensation in the boiler:

         parameter Modelica.SIunits.Temperature TBoiSup_nominal = 273.15+80
           "Boiler nominal supply water temperature";
         parameter Modelica.SIunits.Temperature TBoiRet_min = 273.15+50
           "Boiler minimum return water temperature";
         parameter Modelica.SIunits.MassFlowRate mBoi_flow_nominal=
           Q_flow_nominal/4200/(TBoiSup_nominal-TBoiRet_min)
           "Boiler nominal mass flow rate";

Next, we set the parameters of the individual component models.

1. We lumped the pressure drop of the boiler loop into the boiler model and hence set

         Buildings.Fluid.Boilers.BoilerPolynomial boi(
           redeclare package Medium = MediumW,
           energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
           m_flow_nominal=mBoi_flow_nominal,
           dp_nominal=2000,
           Q_flow_nominal=Q_flow_nominal,
           fue=Buildings.Fluid.Data.Fuels.HeatingOilLowerHeatingValue()) "Boiler";

2. For the three-way valve in the radiator loop, we used the default pressure drop of 6000 Pa. For its mass flow rate, we introduced the parameter

         parameter Modelica.SIunits.MassFlowRate mRadVal_flow_nominal=
           Q_flow_nominal/4200/(TBoiSup_nominal-TRadRet_nominal)
           "Radiator nominal mass flow rate";

   This allowed us to configure the valve as

         Buildings.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valRad(
           redeclare package Medium = MediumW,
           m_flow_nominal=mRadVal_flow_nominal,
           l={0.01,0.01},
           dpValve_nominal=6000) "Three-way valve for radiator loop"

   where `l={0.01,0.01}` is a valve leakage of 1% and `dpValve_nominal=6000` is the pressure drop of the valve if it is fully open and if the mass flow rate is equal to `m_flow_nominal`. It is recommended to set the valve leakage to a non-zero value to avoid numerical problems. A non-zero value also represent a more realistic situation, as most valves have some leakage.

3. For the bypass between the valve and the radiator, we note that the mass flow rate is equal to `mRad_flow_nomial - mRadVal_flow_nominal`. This is a fixed bypass that is used to allow the valve to work across its full range. We decided to lump the pressure drop of this bypass, and the pressure drop of the radiator loop, into the instance `mix`. Hence, its parameters are

         Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM mix(
           redeclare package Medium =MediumW,
           energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
           m_flow_nominal={mRadVal_flow_nominal,
                          -mRad_flow_nominal,
                          mRad_flow_nominal-mRadVal_flow_nominal},
           dp_nominal={100,-8000,6750}) "Mixer between valve and radiators";

   Note the negative values, which are used for the ports where the medium is outflowing at nominal conditions. See also the documentation of the model Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM.

   We also set the pressure drop of port 3 of `mix` to the same value as the pressure drop of the valve in order to balance the flows. In practice, this can be done by using a balance valve, whose pressure drop we lumped into the component `mix`.

4. Next, we set the pressure drops and flow rates of all flow splitters and mixers. For the flow splitters and mixers that are connected to another flow splitter or mixer which already computes the pressure drop of the connecting flow leg, we set the nominal pressure drop to zero. This will remove the equation for the pressure drop calculation. However, we chose to still use the mixer and splitters to make sure that we properly defined the mixing points in the system.

5. Next, we connected all fluid ports, and we set open-loop control signals for the valves, pumps and boilers. This is implemented using the block Modelica.Blocks.Sources.Constant. Using open-loop signals allows testing the model prior to adding the complexity of closed loop control. To avoid that the boiler overheats, we set its control input to `0.5`. Otherwise, the boiler temperature would raise quickly when the radiator pump is off, and the simulation would stop with an error message that says that its medium temperature is outside the allowed range.

This completes the initial version of the model. When simulating the model for 2 days, or 172800 seconds, the response shown below should be seen.

The figure shows that the room temperature is around 5°C when the internal heat gain is zero, i.e., it is at the average of the outside temperature and the room design temperature. Since the boiler control signal is 0.5, this indicates that the model is correct.

Extends from Modelica.Icons.Example (Icon for runnable examples).

### Parameters

Type | Name | Default | Description
--- | --- | --- | ---
replaceable package MediumA | Buildings.Media.Air |
replaceable package MediumW | Buildings.Media.Water | Medium model
HeatFlowRate | Q_flow_nominal | 20000 | Nominal heat flow rate of radiator [W]
Temperature | TRadSup_nominal | 273.15 + 50 | Radiator nominal supply water temperature [K]
Temperature | TRadRet_nominal | 273.15 + 40 | Radiator nominal return water temperature [K]
MassFlowRate | mRad_flow_nominal | Q_flow_nominal/4200/(TRadSup... | Radiator nominal mass flow rate [kg/s]
Temperature | TBoiSup_nominal | 273.15 + 70 | Boiler nominal supply water temperature [K]
Temperature | TBoiRet_min | 273.15 + 60 | Boiler minimum return water temperature [K]
MassFlowRate | mBoi_flow_nominal | Q_flow_nominal/4200/(TBoiSup... | Boiler nominal mass flow rate [kg/s]
MassFlowRate | mRadVal_flow_nominal | Q_flow_nominal/4200/(TBoiSup... | Radiator nominal mass flow rate [kg/s]
Volume | V | 6*10*3 | Room volume [m3]
MassFlowRate | mA_flow_nominal | V*6/3600 | Nominal mass flow rate [kg/s]
HeatFlowRate | QRooInt_flow | 4000 | Internal heat gains of the room [W]

### Connectors

Type | Name | Description
--- | --- | ---
replaceable package MediumA |
replaceable package MediumW | Medium model

### Modelica definition

model System3 "3rd part of the system model, which adds the boiler loop with open loop control" extends Modelica.Icons.Example; replaceable package MediumA = Buildings.Media.Air; replaceable package MediumW = Buildings.Media.Water "Medium model"; parameter Modelica.SIunits.HeatFlowRate Q_flow_nominal = 20000 "Nominal heat flow rate of radiator"; parameter Modelica.SIunits.Temperature TRadSup_nominal = 273.15+50 "Radiator nominal supply water temperature"; parameter Modelica.SIunits.Temperature TRadRet_nominal = 273.15+40 "Radiator nominal return water temperature"; parameter Modelica.SIunits.MassFlowRate mRad_flow_nominal= Q_flow_nominal/4200/(TRadSup_nominal-TRadRet_nominal) "Radiator nominal mass flow rate"; //-------------------------Step 4: Boiler design values-------------------------// parameter Modelica.SIunits.Temperature TBoiSup_nominal = 273.15+70 "Boiler nominal supply water temperature"; parameter Modelica.SIunits.Temperature TBoiRet_min = 273.15+60 "Boiler minimum return water temperature"; parameter Modelica.SIunits.MassFlowRate mBoi_flow_nominal= Q_flow_nominal/4200/(TBoiSup_nominal-TBoiRet_min) "Boiler nominal mass flow rate"; //------------------------------------------------------------------------------// //----------------Radiator loop: Three-way valve: mass flow rate----------------// parameter Modelica.SIunits.MassFlowRate mRadVal_flow_nominal= Q_flow_nominal/4200/(TBoiSup_nominal-TRadRet_nominal) "Radiator nominal mass flow rate"; //------------------------------------------------------------------------------// Buildings.Fluid.MixingVolumes.MixingVolume vol( redeclare package Medium = MediumA, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mA_flow_nominal, V=V); Modelica.Thermal.HeatTransfer.Components.ThermalConductor theCon(G=20000/30) "Thermal conductance with the ambient"; parameter Modelica.SIunits.Volume V=6*10*3 "Room volume"; parameter Modelica.SIunits.MassFlowRate mA_flow_nominal = V*6/3600 "Nominal mass flow rate"; parameter Modelica.SIunits.HeatFlowRate QRooInt_flow = 4000 "Internal heat gains of the room"; Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TOut(T=263.15) "Outside temperature"; Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHea "Prescribed heat flow"; Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heaCap(C=2*V*1.2*1006) "Heat capacity for furniture and walls"; Modelica.Blocks.Sources.CombiTimeTable timTab( extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic, smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments, table=[-6*3600, 0; 8*3600, QRooInt_flow; 18*3600, 0]) "Time table for internal heat gain"; Buildings.Fluid.HeatExchangers.Radiators.RadiatorEN442_2 rad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, Q_flow_nominal=Q_flow_nominal, T_a_nominal=TRadSup_nominal, T_b_nominal=TRadRet_nominal) "Radiator"; Buildings.Fluid.Sensors.TemperatureTwoPort temSup(redeclare package Medium = MediumW, m_flow_nominal=mRad_flow_nominal) "Supply water temperature"; Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor temRoo "Room temperature"; Buildings.Fluid.Movers.FlowControlled_m_flow pumRad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRad_flow_nominal) "Pump for radiator"; //-------------------------Step 3: Splitter and mixers------------------------// Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM mix( redeclare package Medium =MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal={mRadVal_flow_nominal, -mRad_flow_nominal, mRad_flow_nominal-mRadVal_flow_nominal}, dp_nominal={100,-8000,6750}) "Mixer between valve and radiators"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal={mBoi_flow_nominal, -mRadVal_flow_nominal, -mBoi_flow_nominal}, dp_nominal={200,-200,-50}) "Splitter of boiler loop bypass"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl2(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, dp_nominal={0,0,0}, m_flow_nominal={mRad_flow_nominal,-mRadVal_flow_nominal,-mRad_flow_nominal + mRadVal_flow_nominal}); Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM mix2(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, dp_nominal={0,-200,0}, m_flow_nominal={mRadVal_flow_nominal,-mBoi_flow_nominal,mBoi_flow_nominal}) "Mixer"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl4(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRadVal_flow_nominal*{1,-1,-1}, dp_nominal=200*{1,-1,-1}) "Splitter for radiator loop valve bypass"; //----------------------------------------------------------------------------// Buildings.Fluid.Movers.FlowControlled_m_flow pumBoi( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mBoi_flow_nominal) "Pump for boiler"; //-------------------------------Step 3: Boiler-------------------------------// Buildings.Fluid.Boilers.BoilerPolynomial boi( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mBoi_flow_nominal, dp_nominal=2000, Q_flow_nominal=Q_flow_nominal, fue=Buildings.Fluid.Data.Fuels.HeatingOilLowerHeatingValue()) "Boiler"; //----------------------------------------------------------------------------// //--------------------------Step 3: Three-way Valve---------------------------// Buildings.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valRad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRadVal_flow_nominal, l={0.01,0.01}, dpValve_nominal=6000) "Three-way valve for radiator loop"; //----------------------------------------------------------------------------// Buildings.Fluid.Sources.FixedBoundary preSou(redeclare package Medium = MediumW, nPorts=1) "Source for pressure and to account for thermal expansion of water"; Buildings.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valBoi( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mBoi_flow_nominal, l={0.01,0.01}, dpValve_nominal=6000) "Three-way valve for boiler"; Buildings.Fluid.Sensors.TemperatureTwoPort temRet(redeclare package Medium = MediumW, m_flow_nominal=mBoi_flow_nominal) "Return water temperature"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl1(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal={mBoi_flow_nominal,-mBoi_flow_nominal,-mBoi_flow_nominal}, dp_nominal={0,0,-200}) "Splitter"; Modelica.Blocks.Sources.Constant const(k=1) "Constant control signal for valves"; Modelica.Blocks.Sources.Constant conBoi(k=mBoi_flow_nominal) "Constant mass flow rate for boiler pump"; Modelica.Blocks.Sources.Constant const1(k=0.5) "Constant control signal for valves"; Modelica.Blocks.Logical.Hysteresis hysPum(uLow=273.15 + 19, uHigh=273.15 + 21) "Pump hysteresis"; Modelica.Blocks.Math.BooleanToReal booToReaRad(realTrue=mRad_flow_nominal) "Radiator pump signal"; Modelica.Blocks.Logical.Not not1 "Negate output of hysteresis"; equation connect(TOut.port, theCon.port_a); connect(theCon.port_b, vol.heatPort); connect(preHea.port, vol.heatPort); connect(heaCap.port, vol.heatPort); connect(timTab.y[1], preHea.Q_flow); connect(temSup.port_b, rad.port_a); connect(temRoo.port, vol.heatPort); connect(rad.heatPortCon, vol.heatPort); connect(rad.heatPortRad, vol.heatPort); connect(pumRad.port_b, temSup.port_a); connect(boi.port_b, pumBoi.port_a); connect(pumBoi.port_b, spl1.port_1); connect(spl1.port_2, spl.port_1); connect(spl.port_2, valRad.port_1); connect(valRad.port_2, mix.port_1); connect(spl1.port_3, valBoi.port_3); connect(valBoi.port_2, temRet.port_a); connect(temRet.port_b, boi.port_a); connect(boi.port_a, preSou.ports[1]); connect(mix2.port_2, valBoi.port_1); connect(spl4.port_2, mix2.port_1); connect(spl2.port_2, spl4.port_1); connect(valRad.port_3, spl4.port_3); connect(spl.port_3, mix2.port_3); connect(mix.port_3, spl2.port_3); connect(mix.port_2, pumRad.port_a); connect(rad.port_b, spl2.port_1); connect(const.y, valRad.y); connect(conBoi.y, pumBoi.m_flow_in); connect(const.y, valBoi.y); connect(const1.y, boi.y); connect(temRoo.T,hysPum. u); connect(hysPum.y,not1. u); connect(not1.y,booToReaRad. u); connect(booToReaRad.y, pumRad.m_flow_in); end System3;

## Buildings.Examples.Tutorial.Boiler.System4

4th part of the system model, which adds closed-loop control for the pumps and the boiler

### Information

This part of the system model adds to the model that is implemented in Buildings.Examples.Tutorial.Boiler.System3 closed loop control for the pumps and the boiler. The control valves are still open loop control.

#### Implementation

This model was built as follows:

1. First, we copied the model Buildings.Examples.Tutorial.Boiler.System3 and called it `Buildings.Examples.Tutorial.Boiler.System4`.

2. Next, we added the outdoor temperature sensor `senTOut`, which we will use to disable the plant when the outdoor temperature is warmer than 17°C. This is implemented by the instances `hysTOut` and `not2`, whose output signal is connected to the block `and1` as shown in the figure below.

3. Similar to the control of the radiator pump, we used a boolean to real converter, followed by a first order filter, to set the mass flow rate of the boiler pump.

4. Next, for the boiler on/off control, we use again a hysteresis block (instance `hysTBoi`), which we configured as

         Modelica.Blocks.Logical.Hysteresis hysTBoi(uLow=273.15 + 70,
                                                    uHigh=273.15 + 90)
           "Hysteresis for on/off of boiler";

   The output of the hysteresis block is sent to the instance `not3`, which negates its input signal. The output signal of the `not3` instance is then sent to the `and2` block, which ensures that the boiler is only on when the pumps are on and the temperature is below 70°C, and that the boiler is off if its temperature reaches 90°C. Therefore, the boiler control sequence is as shown below.

This completes the closed loop control of the boiler and the pumps. When simulating the model for 2 days, or 172800 seconds, the response shown below should be seen.

The figure shows that the return water temperature `temRet.T` is below 50°C for quite some time when the system heats up. Furthermore, the supply water temperature `temSup.T` is oscillating with the boiler temperature. We will fix these issues by adding closed loop control for the valves in model Buildings.Examples.Tutorial.Boiler.System5.

Extends from Modelica.Icons.Example (Icon for runnable examples).

### Parameters

Type | Name | Default | Description
--- | --- | --- | ---
replaceable package MediumA | Buildings.Media.Air |
replaceable package MediumW | Buildings.Media.Water | Medium model
HeatFlowRate | Q_flow_nominal | 20000 | Nominal heat flow rate of radiator [W]
Temperature | TRadSup_nominal | 273.15 + 50 | Radiator nominal supply water temperature [K]
Temperature | TRadRet_nominal | 273.15 + 40 | Radiator nominal return water temperature [K]
MassFlowRate | mRad_flow_nominal | Q_flow_nominal/4200/(TRadSup... | Radiator nominal mass flow rate [kg/s]
Temperature | TBoiSup_nominal | 273.15 + 70 | Boiler nominal supply water temperature [K]
Temperature | TBoiRet_min | 273.15 + 60 | Boiler minimum return water temperature [K]
MassFlowRate | mBoi_flow_nominal | Q_flow_nominal/4200/(TBoiSup... | Boiler nominal mass flow rate [kg/s]
MassFlowRate | mRadVal_flow_nominal | Q_flow_nominal/4200/(TBoiSup... | Radiator nominal mass flow rate [kg/s]
Volume | V | 6*10*3 | Room volume [m3]
MassFlowRate | mA_flow_nominal | V*6/3600 | Nominal mass flow rate [kg/s]
HeatFlowRate | QRooInt_flow | 4000 | Internal heat gains of the room [W]

### Connectors

Type | Name | Description
--- | --- | ---
replaceable package MediumA |
replaceable package MediumW | Medium model

### Modelica definition

model System4 "4th part of the system model, which adds closed-loop control for the pumps and the boiler" extends Modelica.Icons.Example; replaceable package MediumA = Buildings.Media.Air; replaceable package MediumW = Buildings.Media.Water "Medium model"; parameter Modelica.SIunits.HeatFlowRate Q_flow_nominal = 20000 "Nominal heat flow rate of radiator"; parameter Modelica.SIunits.Temperature TRadSup_nominal = 273.15+50 "Radiator nominal supply water temperature"; parameter Modelica.SIunits.Temperature TRadRet_nominal = 273.15+40 "Radiator nominal return water temperature"; parameter Modelica.SIunits.MassFlowRate mRad_flow_nominal= Q_flow_nominal/4200/(TRadSup_nominal-TRadRet_nominal) "Radiator nominal mass flow rate"; //-------------------------Step 4: Boiler design values-------------------------// parameter Modelica.SIunits.Temperature TBoiSup_nominal = 273.15+70 "Boiler nominal supply water temperature"; parameter Modelica.SIunits.Temperature TBoiRet_min = 273.15+60 "Boiler minimum return water temperature"; parameter Modelica.SIunits.MassFlowRate mBoi_flow_nominal= Q_flow_nominal/4200/(TBoiSup_nominal-TBoiRet_min) "Boiler nominal mass flow rate"; //------------------------------------------------------------------------------// //----------------Radiator loop: Three-way valve: mass flow rate----------------// parameter Modelica.SIunits.MassFlowRate mRadVal_flow_nominal= Q_flow_nominal/4200/(TBoiSup_nominal-TRadRet_nominal) "Radiator nominal mass flow rate"; //------------------------------------------------------------------------------// Buildings.Fluid.MixingVolumes.MixingVolume vol( redeclare package Medium = MediumA, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mA_flow_nominal, V=V); Modelica.Thermal.HeatTransfer.Components.ThermalConductor theCon(G=20000/30) "Thermal conductance with the ambient"; parameter Modelica.SIunits.Volume V=6*10*3 "Room volume"; parameter Modelica.SIunits.MassFlowRate mA_flow_nominal = V*6/3600 "Nominal mass flow rate"; parameter Modelica.SIunits.HeatFlowRate QRooInt_flow = 4000 "Internal heat gains of the room"; Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TOut(T=263.15) "Outside temperature"; Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHea "Prescribed heat flow"; Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heaCap(C=2*V*1.2*1006) "Heat capacity for furniture and walls"; Modelica.Blocks.Sources.CombiTimeTable timTab( extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic, smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments, table=[-6*3600, 0; 8*3600, QRooInt_flow; 18*3600, 0]) "Time table for internal heat gain"; Buildings.Fluid.HeatExchangers.Radiators.RadiatorEN442_2 rad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, Q_flow_nominal=Q_flow_nominal, T_a_nominal=TRadSup_nominal, T_b_nominal=TRadRet_nominal) "Radiator"; Buildings.Fluid.Sensors.TemperatureTwoPort temSup(redeclare package Medium = MediumW, m_flow_nominal=mRad_flow_nominal) "Supply water temperature"; Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor temRoo "Room temperature"; Buildings.Fluid.Movers.FlowControlled_m_flow pumRad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRad_flow_nominal) "Pump for radiator"; //-------------------------Step 3: Splitter and mixers------------------------// Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM mix( redeclare package Medium =MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal={mRadVal_flow_nominal, -mRad_flow_nominal, mRad_flow_nominal-mRadVal_flow_nominal}, dp_nominal={100,-8000,6750}) "Mixer between valve and radiators"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal={mBoi_flow_nominal, -mRadVal_flow_nominal, -mBoi_flow_nominal}, dp_nominal={200,-200,-50}) "Splitter of boiler loop bypass"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl2(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, dp_nominal={0,0,0}, m_flow_nominal={mRad_flow_nominal,-mRadVal_flow_nominal,-mRad_flow_nominal + mRadVal_flow_nominal}); Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM mix2(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, dp_nominal={0,-200,0}, m_flow_nominal={mRadVal_flow_nominal,-mBoi_flow_nominal,mBoi_flow_nominal}) "Mixer"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl4(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRadVal_flow_nominal*{1,-1,-1}, dp_nominal=200*{1,-1,-1}) "Splitter for radiator loop valve bypass"; //----------------------------------------------------------------------------// Buildings.Fluid.Movers.FlowControlled_m_flow pumBoi( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mBoi_flow_nominal) "Pump for boiler"; //-------------------------------Step 3: Boiler-------------------------------// Buildings.Fluid.Boilers.BoilerPolynomial boi( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mBoi_flow_nominal, dp_nominal=2000, Q_flow_nominal=Q_flow_nominal, fue=Buildings.Fluid.Data.Fuels.HeatingOilLowerHeatingValue()) "Boiler"; //----------------------------------------------------------------------------// //--------------------------Step 3: Three-way Valve---------------------------// Buildings.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valRad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRadVal_flow_nominal, l={0.01,0.01}, dpValve_nominal=6000) "Three-way valve for radiator loop"; //----------------------------------------------------------------------------// Buildings.Fluid.Sources.FixedBoundary preSou(redeclare package Medium = MediumW, nPorts=1) "Source for pressure and to account for thermal expansion of water"; Buildings.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valBoi( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mBoi_flow_nominal, l={0.01,0.01}, dpValve_nominal=6000) "Three-way valve for boiler"; Buildings.Fluid.Sensors.TemperatureTwoPort temRet(redeclare package Medium = MediumW, m_flow_nominal=mBoi_flow_nominal) "Return water temperature"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl1(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal={mBoi_flow_nominal,-mBoi_flow_nominal,-mBoi_flow_nominal}, dp_nominal={0,0,-200}) "Splitter"; Modelica.Blocks.Sources.Constant const(k=1) "Constant control signal for valves"; //---------------------Step 2: Outdoor temperature sensor and control------------------// Modelica.Blocks.Logical.Hysteresis hysTOut(uLow=273.15 + 16, uHigh=273.15 + 17) "Hysteresis for on/off based on outside temperature"; Modelica.Blocks.Logical.Not not2; Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor senTOut "Outdoor temperature sensor"; //------------------------------------------------------------------------------------// //-------------------------------Step 4: Boiler hysteresis----------------------------// Modelica.Blocks.Logical.Hysteresis hysTBoi(uHigh=273.15 + 90, uLow=273.15 + 70) "Hysteresis for on/off of boiler"; Modelica.Blocks.Logical.Not not3; Modelica.Blocks.Logical.And and1; //------------------------------------------------------------------------------------// //-------------------------Step 3: Boolean to real: Boiler Pump-----------------------// Modelica.Blocks.Math.BooleanToReal booToReaRad1(realTrue=mBoi_flow_nominal) "Radiator pump signal"; //------------------------------------------------------------------------------------// Modelica.Blocks.Logical.And and2; //---------------------------------Step 4: Boiler signal------------------------------// Modelica.Blocks.Math.BooleanToReal booToReaRad2(realTrue=1) "Boiler signal"; //------------------------------------------------------------------------------------// Modelica.Blocks.Logical.Hysteresis hysPum(uLow=273.15 + 19, uHigh=273.15 + 21) "Pump hysteresis"; Modelica.Blocks.Math.BooleanToReal booToReaRad(realTrue=mRad_flow_nominal) "Radiator pump signal"; Modelica.Blocks.Logical.Not not1 "Negate output of hysteresis"; equation connect(TOut.port, theCon.port_a); connect(theCon.port_b, vol.heatPort); connect(preHea.port, vol.heatPort); connect(heaCap.port, vol.heatPort); connect(timTab.y[1], preHea.Q_flow); connect(temSup.port_b, rad.port_a); connect(temRoo.port, vol.heatPort); connect(rad.heatPortCon, vol.heatPort); connect(rad.heatPortRad, vol.heatPort); connect(pumRad.port_b, temSup.port_a); connect(boi.port_b, pumBoi.port_a); connect(pumBoi.port_b, spl1.port_1); connect(spl1.port_2, spl.port_1); connect(spl.port_2, valRad.port_1); connect(valRad.port_2, mix.port_1); connect(spl1.port_3, valBoi.port_3); connect(valBoi.port_2, temRet.port_a); connect(temRet.port_b, boi.port_a); connect(boi.port_a, preSou.ports[1]); connect(mix2.port_2, valBoi.port_1); connect(spl4.port_2, mix2.port_1); connect(spl2.port_2, spl4.port_1); connect(valRad.port_3, spl4.port_3); connect(spl.port_3, mix2.port_3); connect(mix.port_3, spl2.port_3); connect(mix.port_2, pumRad.port_a); connect(rad.port_b, spl2.port_1); connect(const.y, valRad.y); connect(const.y, valBoi.y); connect(hysTOut.y, not2.u); connect(senTOut.port, TOut.port); connect(hysTBoi.y, not3.u); connect(not2.y, and1.u2); connect(boi.T, hysTBoi.u); connect(senTOut.T, hysTOut.u); connect(and1.y, booToReaRad1.u); connect(and1.y, and2.u1); connect(not3.y, and2.u2); connect(and2.y, booToReaRad2.u); connect(booToReaRad2.y, boi.y); connect(temRoo.T,hysPum. u); connect(hysPum.y,not1. u); connect(not1.y, and1.u1); connect(and1.y, booToReaRad.u); connect(booToReaRad.y, pumRad.m_flow_in); connect(booToReaRad1.y, pumBoi.m_flow_in); end System4;

## Buildings.Examples.Tutorial.Boiler.System5

5th part of the system model, which adds closed-loop control for the valves

### Information

This part of the system model adds to the model that is implemented in Buildings.Examples.Tutorial.Boiler.System4 closed loop control for the valves.

#### Implementation

This model was built as follows:

1. First, we copied the model Buildings.Examples.Tutorial.Boiler.System4 and called it `Buildings.Examples.Tutorial.Boiler.System5`.

2. Next, we added closed loop control for the boiler valve as shown in the figure below.

   This is implemented using the constant block Modelica.Blocks.Sources.Constant for the set point, the PID controller with output limitation Buildings.Controls.Continuous.LimPID. We configured the controller as

         Buildings.Controls.Continuous.LimPID conPIDBoi(
           controllerType=Modelica.Blocks.Types.SimpleController.P,
           k=0.1,
           Ti=120,
           Td=1) "Controller for valve in boiler loop";

   We set the proportional band to 10 Kelvin, hence `k=0.1`. We set the integral time constant to 120 seconds, which is the same time as is required to open or close the valve. These settings turn out to give satisfactory closed loop control performance. Otherwise, we would need to retune the controller, which is usually easiest by configuring the controller as a P-controller, then tuning the proportional gain, and finally changing it to a PI-controller and tuning the integral time constant.

3. The valve control for the radiator loop is implemented similar to the boiler loop, with the exception that the setpoint is computed using the model Buildings.Controls.SetPoints.Table to implement a set point that shifts as a function of the room temperature. This instance is called `TSetSup` in the control sequence shown in the figure below.

   Its configuration is

         Controls.SetPoints.Table TSetSup(table=[273.15 + 19, 273.15 + 50;
                                                 273.15 + 21, 273.15 + 21])
                                                 "Setpoint for supply water temperature";

This completes the closed loop control. When simulating the model for 2 days, or 172800 seconds, the response shown below should be seen.

The figure shows that the return water temperature `temRet.T` quickly raises to 50°C and the supply water temperature `temSup.T` has smaller oscillations compared to Buildings.Examples.Tutorial.Boiler.System4.

Extends from Modelica.Icons.Example (Icon for runnable examples).

### Parameters

Type | Name | Default | Description
--- | --- | --- | ---
replaceable package MediumA | Buildings.Media.Air |
replaceable package MediumW | Buildings.Media.Water | Medium model
HeatFlowRate | Q_flow_nominal | 20000 | Nominal heat flow rate of radiator [W]
Temperature | TRadSup_nominal | 273.15 + 50 | Radiator nominal supply water temperature [K]
Temperature | TRadRet_nominal | 273.15 + 40 | Radiator nominal return water temperature [K]
MassFlowRate | mRad_flow_nominal | Q_flow_nominal/4200/(TRadSup... | Radiator nominal mass flow rate [kg/s]
Temperature | TBoiSup_nominal | 273.15 + 70 | Boiler nominal supply water temperature [K]
Temperature | TBoiRet_min | 273.15 + 60 | Boiler minimum return water temperature [K]
MassFlowRate | mBoi_flow_nominal | Q_flow_nominal/4200/(TBoiSup... | Boiler nominal mass flow rate [kg/s]
MassFlowRate | mRadVal_flow_nominal | Q_flow_nominal/4200/(TBoiSup... | Radiator nominal mass flow rate [kg/s]
Volume | V | 6*10*3 | Room volume [m3]
MassFlowRate | mA_flow_nominal | V*6/3600 | Nominal mass flow rate [kg/s]
HeatFlowRate | QRooInt_flow | 4000 | Internal heat gains of the room [W]

### Connectors

Type | Name | Description
--- | --- | ---
replaceable package MediumA |
replaceable package MediumW | Medium model

### Modelica definition

model System5 "5th part of the system model, which adds closed-loop control for the valves" extends Modelica.Icons.Example; replaceable package MediumA = Buildings.Media.Air; replaceable package MediumW = Buildings.Media.Water "Medium model"; parameter Modelica.SIunits.HeatFlowRate Q_flow_nominal = 20000 "Nominal heat flow rate of radiator"; parameter Modelica.SIunits.Temperature TRadSup_nominal = 273.15+50 "Radiator nominal supply water temperature"; parameter Modelica.SIunits.Temperature TRadRet_nominal = 273.15+40 "Radiator nominal return water temperature"; parameter Modelica.SIunits.MassFlowRate mRad_flow_nominal= Q_flow_nominal/4200/(TRadSup_nominal-TRadRet_nominal) "Radiator nominal mass flow rate"; //-------------------------Step 4: Boiler design values-------------------------// parameter Modelica.SIunits.Temperature TBoiSup_nominal = 273.15+70 "Boiler nominal supply water temperature"; parameter Modelica.SIunits.Temperature TBoiRet_min = 273.15+60 "Boiler minimum return water temperature"; parameter Modelica.SIunits.MassFlowRate mBoi_flow_nominal= Q_flow_nominal/4200/(TBoiSup_nominal-TBoiRet_min) "Boiler nominal mass flow rate"; //------------------------------------------------------------------------------// //----------------Radiator loop: Three-way valve: mass flow rate----------------// parameter Modelica.SIunits.MassFlowRate mRadVal_flow_nominal= Q_flow_nominal/4200/(TBoiSup_nominal-TRadRet_nominal) "Radiator nominal mass flow rate"; //------------------------------------------------------------------------------// Buildings.Fluid.MixingVolumes.MixingVolume vol( redeclare package Medium = MediumA, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mA_flow_nominal, V=V); Modelica.Thermal.HeatTransfer.Components.ThermalConductor theCon(G=20000/30) "Thermal conductance with the ambient"; parameter Modelica.SIunits.Volume V=6*10*3 "Room volume"; parameter Modelica.SIunits.MassFlowRate mA_flow_nominal = V*6/3600 "Nominal mass flow rate"; parameter Modelica.SIunits.HeatFlowRate QRooInt_flow = 4000 "Internal heat gains of the room"; Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TOut(T=263.15) "Outside temperature"; Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHea "Prescribed heat flow"; Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heaCap(C=2*V*1.2*1006) "Heat capacity for furniture and walls"; Modelica.Blocks.Sources.CombiTimeTable timTab( extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic, smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments, table=[-6*3600, 0; 8*3600, QRooInt_flow; 18*3600, 0]) "Time table for internal heat gain"; Buildings.Fluid.HeatExchangers.Radiators.RadiatorEN442_2 rad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, Q_flow_nominal=Q_flow_nominal, T_a_nominal=TRadSup_nominal, T_b_nominal=TRadRet_nominal) "Radiator"; Buildings.Fluid.Sensors.TemperatureTwoPort temSup(redeclare package Medium = MediumW, m_flow_nominal=mRad_flow_nominal) "Supply water temperature"; Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor temRoo "Room temperature"; Buildings.Fluid.Movers.FlowControlled_m_flow pumRad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRad_flow_nominal) "Pump for radiator"; //-------------------------Step 3: Splitter and mixers------------------------// Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM mix( redeclare package Medium =MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal={mRadVal_flow_nominal, -mRad_flow_nominal, mRad_flow_nominal-mRadVal_flow_nominal}, dp_nominal={100,-8000,6750}) "Mixer between valve and radiators"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal={mBoi_flow_nominal, -mRadVal_flow_nominal, -mBoi_flow_nominal}, dp_nominal={200,-200,-50}) "Splitter of boiler loop bypass"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl2(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, dp_nominal={0,0,0}, m_flow_nominal={mRad_flow_nominal,-mRadVal_flow_nominal,-mRad_flow_nominal + mRadVal_flow_nominal}); Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM mix2(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, dp_nominal={0,-200,0}, m_flow_nominal={mRadVal_flow_nominal,-mBoi_flow_nominal,mBoi_flow_nominal}) "Mixer"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl4(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRadVal_flow_nominal*{1,-1,-1}, dp_nominal=200*{1,-1,-1}) "Splitter for radiator loop valve bypass"; //----------------------------------------------------------------------------// Buildings.Fluid.Movers.FlowControlled_m_flow pumBoi( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mBoi_flow_nominal) "Pump for boiler"; //-------------------------------Step 3: Boiler-------------------------------// Buildings.Fluid.Boilers.BoilerPolynomial boi( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mBoi_flow_nominal, dp_nominal=2000, Q_flow_nominal=Q_flow_nominal, fue=Buildings.Fluid.Data.Fuels.HeatingOilLowerHeatingValue()) "Boiler"; //----------------------------------------------------------------------------// //--------------------------Step 3: Three-way Valve---------------------------// Buildings.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valRad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRadVal_flow_nominal, l={0.01,0.01}, dpValve_nominal=6000) "Three-way valve for radiator loop"; //----------------------------------------------------------------------------// Buildings.Fluid.Sources.FixedBoundary preSou(redeclare package Medium = MediumW, nPorts=1) "Source for pressure and to account for thermal expansion of water"; Buildings.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valBoi( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mBoi_flow_nominal, l={0.01,0.01}, dpValve_nominal=6000) "Three-way valve for boiler"; Buildings.Fluid.Sensors.TemperatureTwoPort temRet(redeclare package Medium = MediumW, m_flow_nominal=mBoi_flow_nominal) "Return water temperature"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl1(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal={mBoi_flow_nominal,-mBoi_flow_nominal,-mBoi_flow_nominal}, dp_nominal={0,0,-200}) "Splitter"; //---------------------Step 2: Outdoor temperature sensor and control------------------// Modelica.Blocks.Logical.Hysteresis hysTOut(uLow=273.15 + 16, uHigh=273.15 + 17) "Hysteresis for on/off based on outside temperature"; Modelica.Blocks.Logical.Not not2; Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor senTOut "Outdoor temperature sensor"; //------------------------------------------------------------------------------------// //-------------------------------Step 4: Boiler hysteresis----------------------------// Modelica.Blocks.Logical.Hysteresis hysTBoi(uHigh=273.15 + 90, uLow=273.15 + 70) "Hysteresis for on/off of boiler"; Modelica.Blocks.Logical.Not not3; Modelica.Blocks.Logical.And and1; //------------------------------------------------------------------------------------// //-------------------------Step 3: Boolean to real: Boiler Pump-----------------------// Modelica.Blocks.Math.BooleanToReal booToReaRad1(realTrue=mBoi_flow_nominal) "Radiator pump signal"; //------------------------------------------------------------------------------------// Modelica.Blocks.Logical.And and2; //---------------------------------Step 4: Boiler signal------------------------------// Modelica.Blocks.Math.BooleanToReal booToReaRad2(realTrue=1) "Boiler signal"; //------------------------------------------------------------------------------------// Modelica.Blocks.Logical.Hysteresis hysPum(uLow=273.15 + 19, uHigh=273.15 + 21) "Pump hysteresis"; Modelica.Blocks.Math.BooleanToReal booToReaRad(realTrue=mRad_flow_nominal) "Radiator pump signal"; Modelica.Blocks.Logical.Not not1 "Negate output of hysteresis"; //------------------------Step 2: Boiler loop valve control-----------------------// Modelica.Blocks.Sources.Constant TSetBoiRet(k=TBoiRet_min) "Temperature setpoint for boiler return"; Buildings.Controls.Continuous.LimPID conPIDBoi( Td=1, Ti=120, controllerType=Modelica.Blocks.Types.SimpleController.PI, k=0.1) "Controller for valve in boiler loop"; //--------------------------------------------------------------------------------// //----------------------Step 3: Radiator loop valve control-----------------------// Controls.SetPoints.Table TSetSup(table=[273.15 + 19, 273.15 + 50; 273.15 + 21, 273.15 + 21]) "Setpoint for supply water temperature"; Buildings.Controls.Continuous.LimPID conPIDRad( Td=1, Ti=120, controllerType=Modelica.Blocks.Types.SimpleController.PI, k=0.1) "Controller for valve in radiator loop"; //--------------------------------------------------------------------------------// equation connect(TOut.port, theCon.port_a); connect(theCon.port_b, vol.heatPort); connect(preHea.port, vol.heatPort); connect(heaCap.port, vol.heatPort); connect(timTab.y[1], preHea.Q_flow); connect(temSup.port_b, rad.port_a); connect(temRoo.port, vol.heatPort); connect(rad.heatPortCon, vol.heatPort); connect(rad.heatPortRad, vol.heatPort); connect(pumRad.port_b, temSup.port_a); connect(boi.port_b, pumBoi.port_a); connect(pumBoi.port_b, spl1.port_1); connect(spl1.port_2, spl.port_1); connect(spl.port_2, valRad.port_1); connect(valRad.port_2, mix.port_1); connect(spl1.port_3, valBoi.port_3); connect(valBoi.port_2, temRet.port_a); connect(temRet.port_b, boi.port_a); connect(boi.port_a, preSou.ports[1]); connect(mix2.port_2, valBoi.port_1); connect(spl4.port_2, mix2.port_1); connect(spl2.port_2, spl4.port_1); connect(valRad.port_3, spl4.port_3); connect(spl.port_3, mix2.port_3); connect(mix.port_3, spl2.port_3); connect(mix.port_2, pumRad.port_a); connect(rad.port_b, spl2.port_1); connect(hysTOut.y, not2.u); connect(senTOut.port, TOut.port); connect(hysTBoi.y, not3.u); connect(not2.y, and1.u2); connect(boi.T, hysTBoi.u); connect(senTOut.T, hysTOut.u); connect(and1.y, booToReaRad1.u); connect(and1.y, and2.u1); connect(not3.y, and2.u2); connect(and2.y, booToReaRad2.u); connect(booToReaRad2.y, boi.y); connect(temRoo.T,hysPum. u); connect(hysPum.y,not1. u); connect(not1.y, and1.u1); connect(and1.y, booToReaRad.u); connect(temRet.T,conPIDBoi. u_s); connect(TSetBoiRet.y,conPIDBoi. u_m); connect(temRoo.T, TSetSup.u); connect(TSetSup.y, conPIDRad.u_s); connect(temSup.T, conPIDRad.u_m); connect(conPIDRad.y, valRad.y); connect(booToReaRad.y, pumRad.m_flow_in); connect(booToReaRad1.y, pumBoi.m_flow_in); connect(conPIDBoi.y, valBoi.y); end System5;

## Buildings.Examples.Tutorial.Boiler.System6

6th part of the system model, which adds weather data and changes to PI control

### Information

This part of the system model adds to the model that is implemented in Buildings.Examples.Tutorial.Boiler.System5 weather data, and it changes the control to PI control.

#### Implementation

This model was built as follows:

1. First, we copied the model Buildings.Examples.Tutorial.Boiler.System5 and called it `Buildings.Examples.Tutorial.Boiler.System6`.

2. Next, we added the weather data as shown in the figure below.

   The weather data reader is implemented using

         BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
           filNam="modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos")
           "Weather data reader";

   The yellow icon in the middle of the figure is an instance of Buildings.BoundaryConditions.WeatherData.Bus. This is required to extract the dry bulb temperature from the weather data bus.

   Note that we changed the instance `TOut` from Modelica.Thermal.HeatTransfer.Sources.FixedTemperature to Modelica.Thermal.HeatTransfer.Sources.PrescribedTemperature in order to use the dry-bulb temperature as an input signal.

This completes the closed loop control. When simulating the model for 2 days, or 172800 seconds, the response shown below should be seen.

The figure shows that the boiler temperature is regulated between 70°C and 90°C, that the boiler inlet temperature is above 60°C, and that the room temperature and the supply water temperature are maintained at their set point.

Extends from Modelica.Icons.Example (Icon for runnable examples).

### Parameters

Type | Name | Default | Description
--- | --- | --- | ---
replaceable package MediumA | Buildings.Media.Air |
replaceable package MediumW | Buildings.Media.Water | Medium model
HeatFlowRate | Q_flow_nominal | 20000 | Nominal heat flow rate of radiator [W]
Temperature | TRadSup_nominal | 273.15 + 50 | Radiator nominal supply water temperature [K]
Temperature | TRadRet_nominal | 273.15 + 40 | Radiator nominal return water temperature [K]
MassFlowRate | mRad_flow_nominal | Q_flow_nominal/4200/(TRadSup... | Radiator nominal mass flow rate [kg/s]
Temperature | TBoiSup_nominal | 273.15 + 70 | Boiler nominal supply water temperature [K]
Temperature | TBoiRet_min | 273.15 + 60 | Boiler minimum return water temperature [K]
MassFlowRate | mBoi_flow_nominal | Q_flow_nominal/4200/(TBoiSup... | Boiler nominal mass flow rate [kg/s]
MassFlowRate | mRadVal_flow_nominal | Q_flow_nominal/4200/(TBoiSup... | Radiator nominal mass flow rate [kg/s]
Volume | V | 6*10*3 | Room volume [m3]
MassFlowRate | mA_flow_nominal | V*6/3600 | Nominal mass flow rate [kg/s]
HeatFlowRate | QRooInt_flow | 4000 | Internal heat gains of the room [W]

### Connectors

Type | Name | Description
--- | --- | ---
replaceable package MediumA |
replaceable package MediumW | Medium model
Bus | weaBus |

### Modelica definition

model System6 "6th part of the system model, which adds weather data and changes to PI control" extends Modelica.Icons.Example; replaceable package MediumA = Buildings.Media.Air; replaceable package MediumW = Buildings.Media.Water "Medium model"; parameter Modelica.SIunits.HeatFlowRate Q_flow_nominal = 20000 "Nominal heat flow rate of radiator"; parameter Modelica.SIunits.Temperature TRadSup_nominal = 273.15+50 "Radiator nominal supply water temperature"; parameter Modelica.SIunits.Temperature TRadRet_nominal = 273.15+40 "Radiator nominal return water temperature"; parameter Modelica.SIunits.MassFlowRate mRad_flow_nominal= Q_flow_nominal/4200/(TRadSup_nominal-TRadRet_nominal) "Radiator nominal mass flow rate"; parameter Modelica.SIunits.Temperature TBoiSup_nominal = 273.15+70 "Boiler nominal supply water temperature"; parameter Modelica.SIunits.Temperature TBoiRet_min = 273.15+60 "Boiler minimum return water temperature"; parameter Modelica.SIunits.MassFlowRate mBoi_flow_nominal= Q_flow_nominal/4200/(TBoiSup_nominal-TBoiRet_min) "Boiler nominal mass flow rate"; //------------------------------------------------------------------------------// //----------------Radiator loop: Three-way valve: mass flow rate----------------// parameter Modelica.SIunits.MassFlowRate mRadVal_flow_nominal= Q_flow_nominal/4200/(TBoiSup_nominal-TRadRet_nominal) "Radiator nominal mass flow rate"; Buildings.Fluid.MixingVolumes.MixingVolume vol( redeclare package Medium = MediumA, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mA_flow_nominal, V=V); Modelica.Thermal.HeatTransfer.Components.ThermalConductor theCon(G=20000/30) "Thermal conductance with the ambient"; parameter Modelica.SIunits.Volume V=6*10*3 "Room volume"; parameter Modelica.SIunits.MassFlowRate mA_flow_nominal = V*6/3600 "Nominal mass flow rate"; parameter Modelica.SIunits.HeatFlowRate QRooInt_flow = 4000 "Internal heat gains of the room"; Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHea "Prescribed heat flow"; Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heaCap(C=2*V*1.2*1006) "Heat capacity for furniture and walls"; Modelica.Blocks.Sources.CombiTimeTable timTab( extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic, smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments, table=[-6*3600, 0; 8*3600, QRooInt_flow; 18*3600, 0]) "Time table for internal heat gain"; Buildings.Fluid.HeatExchangers.Radiators.RadiatorEN442_2 rad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, Q_flow_nominal=Q_flow_nominal, T_a_nominal=TRadSup_nominal, T_b_nominal=TRadRet_nominal) "Radiator"; Buildings.Fluid.Sensors.TemperatureTwoPort temSup(redeclare package Medium = MediumW, m_flow_nominal=mRad_flow_nominal) "Supply water temperature"; Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor temRoo "Room temperature"; Buildings.Fluid.Movers.FlowControlled_m_flow pumRad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRad_flow_nominal) "Pump for radiator"; //----------------------------------------------------------------------------// Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM mix( redeclare package Medium =MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal={mRadVal_flow_nominal, -mRad_flow_nominal, mRad_flow_nominal-mRadVal_flow_nominal}, dp_nominal={100,-8000,6750}) "Mixer between valve and radiators"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal={mBoi_flow_nominal, -mRadVal_flow_nominal, -mBoi_flow_nominal}, dp_nominal={200,-200,-50}) "Splitter of boiler loop bypass"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl2(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, dp_nominal={0,0,0}, m_flow_nominal={mRad_flow_nominal,-mRadVal_flow_nominal,-mRad_flow_nominal + mRadVal_flow_nominal}); Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM mix2(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, dp_nominal={0,-200,0}, m_flow_nominal={mRadVal_flow_nominal,-mBoi_flow_nominal,mBoi_flow_nominal}) "Mixer"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl4(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRadVal_flow_nominal*{1,-1,-1}, dp_nominal=200*{1,-1,-1}) "Splitter for radiator loop valve bypass"; //----------------------------------------------------------------------------// Buildings.Fluid.Movers.FlowControlled_m_flow pumBoi( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mBoi_flow_nominal) "Pump for boiler"; //----------------------------------------------------------------------------// Buildings.Fluid.Boilers.BoilerPolynomial boi( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mBoi_flow_nominal, dp_nominal=2000, Q_flow_nominal=Q_flow_nominal, fue=Buildings.Fluid.Data.Fuels.HeatingOilLowerHeatingValue()) "Boiler"; //----------------------------------------------------------------------------// Buildings.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valRad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRadVal_flow_nominal, l={0.01,0.01}, dpValve_nominal=6000) "Three-way valve for radiator loop"; //----------------------------------------------------------------------------// Buildings.Fluid.Sources.FixedBoundary preSou(redeclare package Medium = MediumW, nPorts=1) "Source for pressure and to account for thermal expansion of water"; Buildings.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valBoi( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mBoi_flow_nominal, l={0.01,0.01}, dpValve_nominal=6000) "Three-way valve for boiler"; Buildings.Fluid.Sensors.TemperatureTwoPort temRet(redeclare package Medium = MediumW, m_flow_nominal=mBoi_flow_nominal) "Return water temperature"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl1(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal={mBoi_flow_nominal,-mBoi_flow_nominal,-mBoi_flow_nominal}, dp_nominal={0,0,-200}) "Splitter"; //--------------------------------------------------------------------------------// Modelica.Blocks.Logical.Hysteresis hysTOut(uLow=273.15 + 16, uHigh=273.15 + 17) "Hysteresis for on/off based on outside temperature"; Modelica.Blocks.Logical.Not not2; Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor senTOut "Outdoor temperature sensor"; //--------------------------------------------------------------------------------// Modelica.Blocks.Logical.Hysteresis hysTBoi(uHigh=273.15 + 90, uLow=273.15 + 70) "Hysteresis for on/off of boiler"; Modelica.Blocks.Logical.Not not3; Modelica.Blocks.Logical.And and1; //--------------------------------------------------------------------------------// Modelica.Blocks.Math.BooleanToReal booToReaRad1(realTrue=mBoi_flow_nominal) "Radiator pump signal"; //--------------------------------------------------------------------------------// Modelica.Blocks.Logical.And and2; Modelica.Blocks.Math.BooleanToReal booToReaRad2(realTrue=1) "Boiler signal"; //--------------------------------------------------------------------------------// Modelica.Blocks.Logical.Hysteresis hysPum(uLow=273.15 + 19, uHigh=273.15 + 21) "Pump hysteresis"; Modelica.Blocks.Math.BooleanToReal booToReaRad(realTrue=mRad_flow_nominal) "Radiator pump signal"; Modelica.Blocks.Logical.Not not1 "Negate output of hysteresis"; Modelica.Blocks.Sources.Constant TSetBoiRet(k=TBoiRet_min) "Temperature setpoint for boiler return"; Buildings.Controls.Continuous.LimPID conPIDBoi( Td=1, Ti=120, controllerType=Modelica.Blocks.Types.SimpleController.PI, k=0.1) "Controller for valve in boiler loop"; //--------------------------------------------------------------------------------// Controls.SetPoints.Table TSetSup(table=[273.15 + 19, 273.15 + 50; 273.15 + 21, 273.15 + 21]) "Setpoint for supply water temperature"; Buildings.Controls.Continuous.LimPID conPIDRad( Td=1, Ti=120, controllerType=Modelica.Blocks.Types.SimpleController.PI, k=0.1) "Controller for valve in radiator loop"; //------------------------------------------------------------------------------// //--- Weather data -------------------------------------------------------------// BoundaryConditions.WeatherData.ReaderTMY3 weaDat( filNam="modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos") "Weather data reader"; BoundaryConditions.WeatherData.Bus weaBus; Modelica.Thermal.HeatTransfer.Sources.PrescribedTemperature TOut "Outside temperature"; //------------------------------------------------------------------------------// equation connect(theCon.port_b, vol.heatPort); connect(preHea.port, vol.heatPort); connect(heaCap.port, vol.heatPort); connect(timTab.y[1], preHea.Q_flow); connect(temSup.port_b, rad.port_a); connect(temRoo.port, vol.heatPort); connect(rad.heatPortCon, vol.heatPort); connect(rad.heatPortRad, vol.heatPort); connect(pumRad.port_b, temSup.port_a); connect(boi.port_b, pumBoi.port_a); connect(pumBoi.port_b, spl1.port_1); connect(spl1.port_2, spl.port_1); connect(spl.port_2, valRad.port_1); connect(valRad.port_2, mix.port_1); connect(spl1.port_3, valBoi.port_3); connect(valBoi.port_2, temRet.port_a); connect(temRet.port_b, boi.port_a); connect(boi.port_a, preSou.ports[1]); connect(mix2.port_2, valBoi.port_1); connect(spl4.port_2, mix2.port_1); connect(spl2.port_2, spl4.port_1); connect(valRad.port_3, spl4.port_3); connect(spl.port_3, mix2.port_3); connect(mix.port_3, spl2.port_3); connect(mix.port_2, pumRad.port_a); connect(rad.port_b, spl2.port_1); connect(hysTOut.y, not2.u); connect(hysTBoi.y, not3.u); connect(not2.y, and1.u2); connect(boi.T, hysTBoi.u); connect(senTOut.T, hysTOut.u); connect(and1.y, booToReaRad1.u); connect(and1.y, and2.u1); connect(not3.y, and2.u2); connect(and2.y, booToReaRad2.u); connect(booToReaRad2.y, boi.y); connect(temRoo.T,hysPum. u); connect(hysPum.y,not1. u); connect(not1.y, and1.u1); connect(and1.y, booToReaRad.u); connect(temRet.T,conPIDBoi. u_s); connect(TSetBoiRet.y,conPIDBoi. u_m); connect(temRoo.T, TSetSup.u); connect(TSetSup.y, conPIDRad.u_s); connect(temSup.T, conPIDRad.u_m); connect(weaDat.weaBus, weaBus); connect(weaBus.TDryBul, TOut.T); connect(TOut.port, theCon.port_a); connect(TOut.port, senTOut.port); connect(booToReaRad.y, pumRad.m_flow_in); connect(conPIDRad.y, valRad.y); connect(booToReaRad1.y, pumBoi.m_flow_in); connect(conPIDBoi.y, valBoi.y); end System6;

## Buildings.Examples.Tutorial.Boiler.System7

7th part of the system model, which implements the on/off control using a state machine

### Information

This part of the system model changes the implementation of the control in Buildings.Examples.Tutorial.Boiler.System6 to use a state machine to switch the pumps and the boiler on and off. State machines provide an alternate way to implement discrete event, reactive and hybrid systems. The state machine that is implemented in this model is shown in the figure below.

In the figure above, the ovals depict states, and the arrows are transitions between the states. The transitions fire when the conditions are true.

#### Implementation

This model was built as follows:

1. First, we copied the model Buildings.Examples.Tutorial.Boiler.System6 and called it `Buildings.Examples.Tutorial.Boiler.System7`.

2. We implemented the state machine using blocks from the library Modelica_StateGraph2. How to use these blocks is explained in the user's guide of the Modelica_StateGraph2 library.

   The figure below shows the state machine. The oval icons are states, and the black bars are transitions. The transitions are enabled when their input signal is true. The red numbers to the right of the transition indicate the delay in seconds. If a delay is present, the input needs to be true during the entire duration of the delay for a transition to fire.

   In our implementation, the state `allOff` is the initial state, indicated by its black arrow. The transition `T1` is used to switch the pumps on. Once the pumps are on, transition `T2` may fire, which would switch the boiler on. Hence, the boiler can only be on when the pumps are on. From the state `boilerOn`, the only next step can be to transition to the state `pumpsOn`. Once this state has been reached (and hence the boiler is off), the pumps can be switched off when transition `T4` fires. Note that the transitions `T3` and `T4` only fire when their input is true for the entire duration of 10 seconds. Hence, the pumps and the boiler must run for at least 10 seconds before they can be switched off.

When simulating the model for 2 days, or 172800 seconds, the response shown below should be seen.

Extends from Modelica.Icons.Example (Icon for runnable examples).

### Parameters

Type | Name | Default | Description
--- | --- | --- | ---
replaceable package MediumA | Buildings.Media.Air |
replaceable package MediumW | Buildings.Media.Water | Medium model
HeatFlowRate | Q_flow_nominal | 20000 | Nominal heat flow rate of radiator [W]
Temperature | TRadSup_nominal | 273.15 + 50 | Radiator nominal supply water temperature [K]
Temperature | TRadRet_nominal | 273.15 + 40 | Radiator nominal return water temperature [K]
MassFlowRate | mRad_flow_nominal | Q_flow_nominal/4200/(TRadSup... | Radiator nominal mass flow rate [kg/s]
Temperature | TBoiSup_nominal | 273.15 + 70 | Boiler nominal supply water temperature [K]
Temperature | TBoiRet_min | 273.15 + 60 | Boiler minimum return water temperature [K]
MassFlowRate | mBoi_flow_nominal | Q_flow_nominal/4200/(TBoiSup... | Boiler nominal mass flow rate [kg/s]
MassFlowRate | mRadVal_flow_nominal | Q_flow_nominal/4200/(TBoiSup... | Radiator nominal mass flow rate [kg/s]
Volume | V | 6*10*3 | Room volume [m3]
MassFlowRate | mA_flow_nominal | V*6/3600 | Nominal mass flow rate [kg/s]
HeatFlowRate | QRooInt_flow | 4000 | Internal heat gains of the room [W]

### Connectors

Type | Name | Description
--- | --- | ---
replaceable package MediumA |
replaceable package MediumW | Medium model
Bus | weaBus |

### Modelica definition

model System7 "7th part of the system model, which implements the on/off control using a state machine" extends Modelica.Icons.Example; replaceable package MediumA = Buildings.Media.Air; replaceable package MediumW = Buildings.Media.Water "Medium model"; parameter Modelica.SIunits.HeatFlowRate Q_flow_nominal = 20000 "Nominal heat flow rate of radiator"; parameter Modelica.SIunits.Temperature TRadSup_nominal = 273.15+50 "Radiator nominal supply water temperature"; parameter Modelica.SIunits.Temperature TRadRet_nominal = 273.15+40 "Radiator nominal return water temperature"; parameter Modelica.SIunits.MassFlowRate mRad_flow_nominal= Q_flow_nominal/4200/(TRadSup_nominal-TRadRet_nominal) "Radiator nominal mass flow rate"; parameter Modelica.SIunits.Temperature TBoiSup_nominal = 273.15+70 "Boiler nominal supply water temperature"; parameter Modelica.SIunits.Temperature TBoiRet_min = 273.15+60 "Boiler minimum return water temperature"; parameter Modelica.SIunits.MassFlowRate mBoi_flow_nominal= Q_flow_nominal/4200/(TBoiSup_nominal-TBoiRet_min) "Boiler nominal mass flow rate"; //------------------------------------------------------------------------------// //----------------Radiator loop: Three-way valve: mass flow rate----------------// parameter Modelica.SIunits.MassFlowRate mRadVal_flow_nominal= Q_flow_nominal/4200/(TBoiSup_nominal-TRadRet_nominal) "Radiator nominal mass flow rate"; Buildings.Fluid.MixingVolumes.MixingVolume vol( redeclare package Medium = MediumA, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mA_flow_nominal, V=V); Modelica.Thermal.HeatTransfer.Components.ThermalConductor theCon(G=20000/30) "Thermal conductance with the ambient"; parameter Modelica.SIunits.Volume V=6*10*3 "Room volume"; parameter Modelica.SIunits.MassFlowRate mA_flow_nominal = V*6/3600 "Nominal mass flow rate"; parameter Modelica.SIunits.HeatFlowRate QRooInt_flow = 4000 "Internal heat gains of the room"; Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHea "Prescribed heat flow"; Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heaCap(C=2*V*1.2*1006) "Heat capacity for furniture and walls"; Modelica.Blocks.Sources.CombiTimeTable timTab( extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic, smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments, table=[-6*3600, 0; 8*3600, QRooInt_flow; 18*3600, 0]) "Time table for internal heat gain"; Buildings.Fluid.HeatExchangers.Radiators.RadiatorEN442_2 rad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, Q_flow_nominal=Q_flow_nominal, T_a_nominal=TRadSup_nominal, T_b_nominal=TRadRet_nominal) "Radiator"; Buildings.Fluid.Sensors.TemperatureTwoPort temSup(redeclare package Medium = MediumW, m_flow_nominal=mRad_flow_nominal) "Supply water temperature"; Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor temRoo "Room temperature"; Buildings.Fluid.Movers.FlowControlled_m_flow pumRad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRad_flow_nominal) "Pump for radiator"; //----------------------------------------------------------------------------// Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM mix( redeclare package Medium =MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal={mRadVal_flow_nominal, -mRad_flow_nominal, mRad_flow_nominal-mRadVal_flow_nominal}, dp_nominal={100,-8000,6750}) "Mixer between valve and radiators"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal={mBoi_flow_nominal, -mRadVal_flow_nominal, -mBoi_flow_nominal}, dp_nominal={200,-200,-50}) "Splitter of boiler loop bypass"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl2(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, dp_nominal={0,0,0}, m_flow_nominal={mRad_flow_nominal,-mRadVal_flow_nominal,-mRad_flow_nominal + mRadVal_flow_nominal}); Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM mix2(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, dp_nominal={0,-200,0}, m_flow_nominal={mRadVal_flow_nominal,-mBoi_flow_nominal,mBoi_flow_nominal}) "Mixer"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl4(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRadVal_flow_nominal*{1,-1,-1}, dp_nominal=200*{1,-1,-1}) "Splitter for radiator loop valve bypass"; //----------------------------------------------------------------------------// Buildings.Fluid.Movers.FlowControlled_m_flow pumBoi( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mBoi_flow_nominal) "Pump for boiler"; //----------------------------------------------------------------------------// Buildings.Fluid.Boilers.BoilerPolynomial boi( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mBoi_flow_nominal, dp_nominal=2000, Q_flow_nominal=Q_flow_nominal, fue=Buildings.Fluid.Data.Fuels.HeatingOilLowerHeatingValue()) "Boiler"; //----------------------------------------------------------------------------// Buildings.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valRad( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mRadVal_flow_nominal, l={0.01,0.01}, dpValve_nominal=6000) "Three-way valve for radiator loop"; //----------------------------------------------------------------------------// Buildings.Fluid.Sources.FixedBoundary preSou(redeclare package Medium = MediumW, nPorts=1) "Source for pressure and to account for thermal expansion of water"; Buildings.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valBoi( redeclare package Medium = MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal=mBoi_flow_nominal, l={0.01,0.01}, dpValve_nominal=6000) "Three-way valve for boiler"; Buildings.Fluid.Sensors.TemperatureTwoPort temRet(redeclare package Medium = MediumW, m_flow_nominal=mBoi_flow_nominal) "Return water temperature"; Buildings.Fluid.FixedResistances.SplitterFixedResistanceDpM spl1(redeclare package Medium=MediumW, energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, m_flow_nominal={mBoi_flow_nominal,-mBoi_flow_nominal,-mBoi_flow_nominal}, dp_nominal={0,0,-200}) "Splitter"; //------------------------------------------------------------------------------------// Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor senTOut "Outdoor temperature sensor"; Modelica.Blocks.Math.BooleanToReal booToReaRad1(realTrue=mBoi_flow_nominal) "Radiator pump signal"; Modelica.Blocks.Math.BooleanToReal booToReaRad2(realTrue=1) "Radiator pump signal"; Modelica.Blocks.Math.BooleanToReal booToReaRad(realTrue=mRad_flow_nominal) "Radiator pump signal"; Modelica.Blocks.Sources.Constant TSetBoiRet(k=TBoiRet_min) "Temperature setpoint for boiler return"; Buildings.Controls.Continuous.LimPID conPIDBoi( Td=1, controllerType=Modelica.Blocks.Types.SimpleController.PI, k=0.1, Ti=120) "Controller for valve in boiler loop"; Controls.SetPoints.Table TSetSup(table=[273.15 + 19, 273.15 + 50; 273.15 + 21, 273.15 + 21]) "Setpoint for supply water temperature"; Buildings.Controls.Continuous.LimPID conPIDRad( Td=1, controllerType=Modelica.Blocks.Types.SimpleController.PI, k=0.1, Ti=120) "Controller for valve in radiator loop"; BoundaryConditions.WeatherData.ReaderTMY3 weaDat( filNam="modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos") "Weather data reader"; BoundaryConditions.WeatherData.Bus weaBus; Modelica.Thermal.HeatTransfer.Sources.PrescribedTemperature TOut "Outside temperature"; //-------------------------Step 2: State machine implementation-------------------------// Modelica_StateGraph2.Step allOff( nOut=1, initialStep=true, use_activePort=true, nIn=1) "System off"; Modelica_StateGraph2.Transition T1(use_conditionPort=true, delayedTransition= false); Modelica.Blocks.Logical.LessThreshold lessThreshold(threshold=273.15 + 19); Modelica.Blocks.Logical.LessThreshold lessThreshold1(threshold=273.15 + 16); Modelica.Blocks.Logical.And and3; Modelica.Blocks.Logical.LessThreshold lessThreshold2(threshold=273.15 + 70) "Threshold for boiler control"; Modelica_StateGraph2.Step boilerOn( nIn=1, use_activePort=true, nOut=1) "Boiler is on"; Modelica_StateGraph2.Transition T2( use_conditionPort=true, delayedTransition=false); Modelica.Blocks.Logical.GreaterThreshold greThrBoi(threshold=273.15 + 90) "Threshold for boiler control"; Modelica_StateGraph2.Transition T3(use_conditionPort=true, delayedTransition=true, waitTime=10); Modelica.Blocks.Logical.GreaterThreshold greThrTRoo(threshold=273.15 + 21) "Threshold for room temperature"; Modelica.Blocks.Logical.GreaterThreshold greThrTROut(threshold=273.15 + 17) "Threshold for room temperature"; Modelica.Blocks.Logical.And and1; Modelica_StateGraph2.Transition T4(use_conditionPort=true, delayedTransition=true, waitTime=10); Modelica_StateGraph2.Step pumpsOn( nIn=2, use_activePort=false, nOut=2) "Pumps are on"; Modelica.Blocks.Logical.Not not1 "Negate output of hysteresis"; //--------------------------------------------------------------------------------------// equation connect(theCon.port_b, vol.heatPort); connect(preHea.port, vol.heatPort); connect(heaCap.port, vol.heatPort); connect(timTab.y[1], preHea.Q_flow); connect(temSup.port_b, rad.port_a); connect(temRoo.port, vol.heatPort); connect(rad.heatPortCon, vol.heatPort); connect(rad.heatPortRad, vol.heatPort); connect(pumRad.port_b, temSup.port_a); connect(boi.port_b, pumBoi.port_a); connect(pumBoi.port_b, spl1.port_1); connect(spl1.port_2, spl.port_1); connect(spl.port_2, valRad.port_1); connect(valRad.port_2, mix.port_1); connect(spl1.port_3, valBoi.port_3); connect(valBoi.port_2, temRet.port_a); connect(temRet.port_b, boi.port_a); connect(boi.port_a, preSou.ports[1]); connect(mix2.port_2, valBoi.port_1); connect(spl4.port_2, mix2.port_1); connect(spl2.port_2, spl4.port_1); connect(valRad.port_3, spl4.port_3); connect(spl.port_3, mix2.port_3); connect(mix.port_3, spl2.port_3); connect(mix.port_2, pumRad.port_a); connect(rad.port_b, spl2.port_1); connect(booToReaRad2.y, boi.y); connect(temRet.T,conPIDBoi. u_s); connect(TSetBoiRet.y,conPIDBoi. u_m); connect(temRoo.T, TSetSup.u); connect(TSetSup.y, conPIDRad.u_s); connect(temSup.T, conPIDRad.u_m); connect(weaDat.weaBus, weaBus); connect(weaBus.TDryBul, TOut.T); connect(TOut.port, theCon.port_a); connect(TOut.port, senTOut.port); connect(allOff.outPort[1], T1.inPort); connect(temRoo.T, lessThreshold.u); connect(lessThreshold1.u, senTOut.T); connect(lessThreshold.y, and3.u1); connect(lessThreshold1.y, and3.u2); connect(T1.conditionPort, and3.y); connect(boi.T, lessThreshold2.u); connect(lessThreshold2.y, T2.conditionPort); connect(T2.outPort, boilerOn.inPort[1]); connect(boi.T, greThrBoi.u); connect(boilerOn.outPort[1], T3.inPort); connect(greThrBoi.y, T3.conditionPort); connect(boilerOn.activePort, booToReaRad2.u); connect(temRoo.T, greThrTRoo.u); connect(senTOut.T, greThrTROut.u); connect(greThrTRoo.y, and1.u1); connect(greThrTROut.y, and1.u2); connect(and1.y, T4.conditionPort); connect(T1.outPort, pumpsOn.inPort[1]); connect(allOff.activePort, not1.u); connect(not1.y, booToReaRad.u); connect(not1.y, booToReaRad1.u); connect(T3.outPort, pumpsOn.inPort[2]); connect(T4.outPort, allOff.inPort[1]); connect(pumpsOn.outPort[1], T4.inPort); connect(pumpsOn.outPort[2], T2.inPort); connect(conPIDRad.y, valRad.y); connect(booToReaRad.y, pumRad.m_flow_in); connect(conPIDBoi.y, valBoi.y); connect(booToReaRad1.y, pumBoi.m_flow_in); end System7;