Heating controller with neural thermal model written in Python
Jacek Kowalski
2018-06-24 66a9fb40efe1311b34a3cee3f83f10c6990759af
commit | author | age
425bf7 1 import abc
JK 2 from copy import deepcopy
3
4 from numpy import binary_repr
5 from .Env import CentralHeatingHistoryEnv
6 from .Model import Model
7 from .Cost import Cost
8 from .SlidingWindow import SlidingWindow
9
10
11 class Controller(abc.ABC):
12     def __init__(self):
13         pass
14
15     @abc.abstractmethod
16     def act(self, window: SlidingWindow) -> int:
17         pass
18
19
20 class StaticController(Controller):
21     def __init__(self, output: int):
22         self.output = output
23
24     def act(self, window: SlidingWindow) -> int:
25         return self.output
26
27
28 class ThermostatController(Controller):
29     def __init__(self, temp_min, temp_max):
30         self.temp_min = temp_min
31         self.temp_max = temp_max
32         self.mode = 0
33
34     def act(self, window: SlidingWindow):
35         temp_in = window.get_current_value('temp_in')
36
37         if self.mode:
38             if temp_in >= self.temp_max:
39                 self.mode = False
40                 return False
41             else:
42                 return True
43
44         if temp_in <= self.temp_min:
45             self.mode = True
46             return True
47
48         return False
49
50
51 class ReplayController(Controller):
52     def act(self, window: SlidingWindow):
53         return window.get_current_value('mode')
54
55
56 class CostController(Controller):
57     def __init__(self, model: Model, cost_calculator_class, *args, **kwargs):
58         self.model = model
59         self.cost_calculator_class = cost_calculator_class
60
61     def act(self, window: SlidingWindow):
62         saved_mode = window.get_current_value('mode')
63         saved_temp = window.get_next_value('temp_in')
64
65         window.set_current_value('mode', 0)
66         window.set_next_value('temp_in', self.model.get_temperature(window.get_model_values()))
67         cost_no = self.cost_calculator_class().compute_partial_cost(window)
68         cost_no = sum(cost_no.values())
69         window.set_current_value('mode', 1)
70         window.set_next_value('temp_in', self.model.get_temperature(window.get_model_values()))
71         cost_yes = self.cost_calculator_class().compute_partial_cost(window)
72         cost_yes = sum(cost_yes.values())
73
74         window.set_current_value('mode', saved_mode)
75         window.set_next_value('temp_in', saved_temp)
76         return cost_yes < cost_no
77
78
79 class BruteForceController(CostController):
80     def act(self, window: SlidingWindow):
81         future_values = window.future_values - window.model_future_values
82
83         last_mode = window.get_previous_value('mode')
84
85         best_cost = float('+inf')
86         best_option = None
87
88         for i in range(1 << future_values):
89             test_modes = binary_repr(i, future_values)
90             test_diffs = (-0.02, 0.02)
91             test_costs = [None] * len(test_diffs)
92             for i, diff in enumerate(test_diffs):
93                 test_window = window.copy(plot=False)
94                 test_costs[i] = self.cost_calculator_class()
95                 for mode in test_modes:
96                     mode = int(mode)
97                     test_window.set_current_value('mode', mode)
98                     model_calc = self.model.get_temperature(test_window.get_model_values())
99                     model_calc += diff
100                     test_window.set_next_value('temp_in', model_calc)
101                     test_window.set_next_value('temp_out', test_window.get_next_value('temperature'))
102                     test_costs[i].add_partial_cost(test_window)
103                     test_window.next()
104             test_cost = max(*test_costs)
105             if test_cost.total() < best_cost or (test_cost.total() == best_cost and int(test_modes[0]) == last_mode):
106                 best_cost = test_cost.total()
107                 best_option = test_modes
108         return int(best_option[0])
109
110
111 def simulate(env: CentralHeatingHistoryEnv, controller: Controller, render=True):
112     state, reward, done, info = env.reset(), 0, False, None
113     while not done:
114         action = controller.act(env.window)
115         state, reward, done, info = env.step(action)
116
117
118     print(env.cost)
119     if render:
120         env.render()