first commit
This commit is contained in:
commit
4b98219bf7
144 changed files with 31561 additions and 0 deletions
93
simulators/bots/chiller.py
Normal file
93
simulators/bots/chiller.py
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
import random
|
||||
import math
|
||||
from bots.base import BaseBot
|
||||
|
||||
|
||||
class ChillerBot(BaseBot):
|
||||
"""Water-cooled chiller plant — supplies chilled water to CRAC/CRAH units."""
|
||||
|
||||
interval = 60
|
||||
|
||||
RATED_COOLING_KW = 300.0 # total cooling capacity
|
||||
DESIGN_FLOW_GPM = 600.0 # nominal chilled water flow
|
||||
CHW_SETPOINT = 7.0 # chilled water supply setpoint (°C)
|
||||
CW_RETURN_DESIGN = 35.0 # condenser water return design temp (°C)
|
||||
|
||||
def __init__(self, site_id: str, chiller_id: str) -> None:
|
||||
super().__init__()
|
||||
self.site_id = site_id
|
||||
self.chiller_id = chiller_id
|
||||
self._fault = False
|
||||
self._run_hours = 8_000 + random.randint(0, 2_000)
|
||||
|
||||
def get_topic(self) -> str:
|
||||
return f"bms/{self.site_id}/cooling/chiller/{self.chiller_id}"
|
||||
|
||||
def set_scenario(self, name: str | None) -> None:
|
||||
super().set_scenario(name)
|
||||
self._fault = (name == "CHILLER_FAULT")
|
||||
|
||||
def get_payload(self) -> dict:
|
||||
hour_inc = self.interval / 3_600
|
||||
self._run_hours += hour_inc
|
||||
|
||||
if self._fault:
|
||||
return {
|
||||
"state": "fault",
|
||||
"chw_supply_c": None,
|
||||
"chw_return_c": None,
|
||||
"chw_delta_c": None,
|
||||
"flow_gpm": 0,
|
||||
"cooling_load_kw": 0,
|
||||
"cooling_load_pct": 0,
|
||||
"cop": 0,
|
||||
"compressor_load_pct": 0,
|
||||
"condenser_pressure_bar": None,
|
||||
"evaporator_pressure_bar": None,
|
||||
"cw_supply_c": None,
|
||||
"cw_return_c": None,
|
||||
"run_hours": round(self._run_hours, 1),
|
||||
}
|
||||
|
||||
# Normal operation
|
||||
load_pct = 55.0 + random.gauss(0, 5.0)
|
||||
load_pct = max(20.0, min(100.0, load_pct))
|
||||
load_kw = self.RATED_COOLING_KW * load_pct / 100.0
|
||||
|
||||
# CHW temperatures — supply held near setpoint, return rises with load
|
||||
chw_supply = self.CHW_SETPOINT + random.gauss(0, 0.15)
|
||||
chw_delta = 5.0 + (load_pct / 100.0) * 3.0 + random.gauss(0, 0.2)
|
||||
chw_return = chw_supply + chw_delta
|
||||
|
||||
# Condenser water
|
||||
cw_return = self.CW_RETURN_DESIGN - 3.0 + (load_pct / 100.0) * 4.0 + random.gauss(0, 0.5)
|
||||
cw_supply = cw_return - 5.0 + random.gauss(0, 0.3)
|
||||
|
||||
# Flow — slight variation from design
|
||||
flow_gpm = self.DESIGN_FLOW_GPM * (0.92 + random.gauss(0, 0.01))
|
||||
|
||||
# Refrigerant pressures (R134a-like)
|
||||
evap_p = 3.0 + (chw_supply / 10.0) + random.gauss(0, 0.05)
|
||||
cond_p = 12.0 + (cw_return / 10.0) + random.gauss(0, 0.1)
|
||||
|
||||
# COP
|
||||
comp_load = load_pct * 0.9 + random.gauss(0, 1.0)
|
||||
comp_power = (comp_load / 100.0) * (load_kw / 4.5) # ~4.5 COP design
|
||||
cop = load_kw / comp_power if comp_power > 0 else 0.0
|
||||
|
||||
return {
|
||||
"state": "online",
|
||||
"chw_supply_c": round(chw_supply, 2),
|
||||
"chw_return_c": round(chw_return, 2),
|
||||
"chw_delta_c": round(chw_delta, 2),
|
||||
"flow_gpm": round(flow_gpm, 0),
|
||||
"cooling_load_kw": round(load_kw, 1),
|
||||
"cooling_load_pct": round(load_pct, 1),
|
||||
"cop": round(cop, 2),
|
||||
"compressor_load_pct": round(comp_load, 1),
|
||||
"condenser_pressure_bar": round(cond_p, 2),
|
||||
"evaporator_pressure_bar": round(evap_p, 2),
|
||||
"cw_supply_c": round(cw_supply, 2),
|
||||
"cw_return_c": round(cw_return, 2),
|
||||
"run_hours": round(self._run_hours, 1),
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue