+This file contains classes for simulating, controlling and observing a fridge.
+@author: Stefan Scherfke
+@contact: stefan.scherfke at uni-oldenburg.de
+Updated for simpy 3 by Ben Howes of Zoetrope Labs (https://zoetrope.io)
+from collections import namedtuple
+log = logging.getLogger('Processes')
+FridgeInternalState = namedtuple("FridgeInternalState", ["temp", "current"])
+def fridge(env, data_output, T_O = 20.0, A = 3.21, m_c = 15.97, tau = 1.0/60,
+ eta = 3.0, q_i = 0.0, q_max = 70.0,
+ T_i = 5.0, T_range = [5.0, 8.0], noise = False,
+ This generator represents a simulated fridge.
+ It's temperature T for and equidistant series of time steps is computed by
+ $T_{i+1} = \epsilon \cdot T_i + (1 - \epsilon) \cdot \left(T^O - \eta
+ \cdot \frac{q_i}{A}\right)$ with $\epsilon = e^{-\frac{\tau A}{m_c}}$.
+ @param env: The SimPy simulation this process belongs to
+ @type env: SimPy.Environment instance
+ @param data_output A list which we can append to
+ @param T_O: Outside temperature
+ @param m_c: Thermal mass/thermal storage capacity
+ @param tau: Time span between t_i and t_{i+1}
+ @param eta: Efficiency of the cooling device
+ @param q_i: Initial/current electrical power
+ @param q_max: Power required during cool-down
+ @param T_i: Initial/current temperature
+ @param T_range: Allowed range for T_i
+ @param noise: Add noise to the fridge's parameters, if True
+ epsilon = exp(-(tau * A) / m_c)
+ T_i = epsilon * T_i + (1 - epsilon) \
+ * (T_O - eta * (q_i / A))
+ q_i = q_max # Cool down
+ elif T_i <= T_range[0]:
+ q_i = 0.0 # Stop cooling
+ log.debug('T_i: %2.2f°C at %.2f' % (T_i, env.now))
+ data_output.append(FridgeInternalState(T_i, q_i))
+def fridge_observer(env, fridges, fridges_data, output, tau, aggSteps):
+ This process observes the temperature and power consumption of a set of
+ @param fridges: A list of fridges (not used)
+ @param fridges_data: A list of lists containing FridgeInternalState output from each fridge
+ @param output: The observable output aggregation
+ @param tau: Timestep size
+ @aggSteps: The number of steps per aggregation
+ #prog = env.now * 100 / self.sim._endtime
+ #if int(prog) > lastProgUpdate:
+ # log.info('Progress: %d%%' % prog)
+ # lastProgUpdate = prog
+ if (aggSteps >= _aggSteps):
+ log.debug('Aggregating at %.2f' % env.now)
+ output.append(consumption/_aggSteps)
+ for fridge_data in fridges_data:
+ consumption += fridge_data[-1].current
+if __name__ == '__main__':
+ format = '%(levelname)-8s %(asctime)s %(name)s: %(message)s')
+ tau = 1./60 # Step size 1min
+ aggSteps = 15 # Aggregate consumption in 15min blocks
+ env = simpy.Environment()
+ fridge = fridge(env, data_output)
+ observer = fridge_observer(env, [fridge], [data_output], agg_output, tau, aggSteps)
+ env.run(until = 4 + tau)