from pydantic import Field
from agentlib.core import Agent
from agentlib.modules.controller import SISOController, SISOControllerConfig
from agentlib.core.datamodels import AgentVariable
[docs]class BangBangConfig(SISOControllerConfig):
"""Special config for a BangBang-Controller"""
gain: float = Field(title="Gain of output", default=1)
[docs]class BangBang(SISOController):
"""
A bang–bang controller (2 step or on–off controller), also known as a
hysteresis controller, that switches abruptly between two states.
"""
config: BangBangConfig
def __init__(self, *, config: dict, agent: Agent):
super().__init__(config=config, agent=agent)
self._last_out_val = self.get(self.config.output.name).value
@property
def gain(self):
"""Get the gain of the BangBang controller"""
return self.config.gain
@property
def last_out_val(self):
"""Last output value of the controller"""
return self._last_out_val
@last_out_val.setter
def last_out_val(self, out_val):
"""Set the last output value of the controller"""
self._last_out_val = out_val
[docs] def loop_sim(self):
out_val = None
while True:
inp = yield out_val
out_val = self.do_step(inp_var=inp)
self.last_out_val = out_val
out_val *= self.gain
[docs] def do_step(self, inp_var: AgentVariable):
# y = not pre(y) and u > uHigh or pre(y) and u >= uLow
if inp_var.value <= self.ub and self.last_out_val == int(not self.reverse):
return int(not self.reverse)
if inp_var.value > self.ub and self.last_out_val == int(not self.reverse):
return int(self.reverse)
if inp_var.value < self.lb and self.last_out_val == int(self.reverse):
return int(not self.reverse)
if inp_var.value >= self.lb and self.last_out_val == int(self.reverse):
return int(self.reverse)