diff --git a/brewpi.py b/brewpi.py
index da076c4..4635472 100755
--- a/brewpi.py
+++ b/brewpi.py
@@ -9,6 +9,7 @@ from components.pid import PidFactory
from components.plant import Pot
from components.actor import HeaterFactory, StirrerFactory
from tasks import TaskManager, TempSensorTask, HeaterTask, PotTask, TcTask, StirrerTask, TracerTask
+from tracer import Tracer
if __name__ == '__main__':
config = json.load(open("config.json"))
@@ -40,13 +41,24 @@ if __name__ == '__main__':
tc_task = TcTask(tc, DT_TASK, dispatcher.msgio_get("TempCtrl"))
taskmgr.add(tc_task)
+ tc_trace_vars = [
+ {'variable': 'theta_ist_plant', 'name': 'theta_ist_plant', 'unit': ''},
+ {'variable': 'dtheta_ist_plant', 'name': 'dtheta_ist_plant', 'unit': ''},
+ {'variable': 'theta_ist_model', 'name': 'theta_ist_model', 'unit': ''},
+ {'variable': 'dtheta_ist_model', 'name': 'dtheta_ist_model', 'unit': ''},
+ {'variable': 'theta_ist_model_delay', 'name': 'theta_ist_model_delay', 'unit': ''},
+ {'variable': 'dtheta_ist_model_delay', 'name': 'dtheta_ist_model_delay', 'unit': ''}
+ ]
+
+ trace_tc = Tracer(tc, tc_trace_vars, name='tc_trace')
+
# Stirrer
stirrer = StirrerFactory.create(config['Controller']['stirrer_name'], DT, config['Stirrer'])
stirrer_task = StirrerTask(stirrer, DT_TASK, dispatcher.msgio_get("Stirrer"))
taskmgr.add(stirrer_task)
# Tracer
- taskmgr.add(TracerTask(sensor, heater, tc, DT_TASK_TRACER, dispatcher.msgio_get("Tracer")))
+ taskmgr.add(TracerTask(sensor, heater, tc, trace_tc, DT_TASK_TRACER, dispatcher.msgio_get("Tracer")))
# Assign data flow
tc.set_on_changed("y", heater_task.actor)
diff --git a/components/pid/temp_controller_smith.py b/components/pid/temp_controller_smith.py
index ad41f45..e2ad709 100755
--- a/components/pid/temp_controller_smith.py
+++ b/components/pid/temp_controller_smith.py
@@ -100,9 +100,9 @@ class TempController(APid):
self.heatrate_soll = self.heatrate_soll_set * self.pid_hold.get_y()
- print ("Model : T_ist={:2.2f}, dT_ist={:2.2f}".format(theta_ist_model, heatrate_ist_model))
- print ("Model*z-1: T_ist={:2.2f}, dT_ist={:2.2f}".format(theta_ist_model_delay, dtheta_ist_model_delay))
- print ("Plant : T_ist={:2.2f}, dT_ist={:2.2f}".format(theta_ist_plant, heatrate_ist_plant))
+# print ("Model : T_ist={:2.2f}, dT_ist={:2.2f}".format(theta_ist_model, heatrate_ist_model))
+# print ("Model*z-1: T_ist={:2.2f}, dT_ist={:2.2f}".format(theta_ist_model_delay, dtheta_ist_model_delay))
+# print ("Plant : T_ist={:2.2f}, dT_ist={:2.2f}".format(theta_ist_plant, heatrate_ist_plant))
if 0:
theta_err = self.theta_soll_set - (theta_ist_plant - theta_ist_model_delay + theta_ist_model)
else:
diff --git a/results_tc.m b/results_tc.m
new file mode 100644
index 0000000..8d2ec37
--- /dev/null
+++ b/results_tc.m
@@ -0,0 +1,45 @@
+## Copyright (C) 2020 Jens
+##
+## This program is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program. If not, see
+## .
+
+## -*- texinfo -*-
+## @deftypefn {} {@var{retval} =} results (@var{input1}, @var{input2})
+##
+## @seealso{}
+## @end deftypefn
+
+## Author: Jens
+## Created: 2020-12-20
+
+function retval = results_tc()
+
+load ('logs/tc_trace.mat')
+
+close all;
+
+figure(1)
+
+set(0, "defaultlinelinewidth", 1.5);
+subplot(2,1,1)
+plot(time, theta_ist_plant, time, theta_ist_model, theta_ist_model_delay); grid
+title("Temperature [°C]")
+legend("Plant","Model","Model*z")
+
+subplot(2,1,2)
+plot(time, dtheta_ist_plant, time, dtheta_ist_model, dtheta_ist_model_delay); grid
+title("Heatrate [°C/min]")
+legend("Plant","Model","Model*z")
+
+endfunction
diff --git a/tasks/tracer.py b/tasks/tracer.py
index 5a6398d..8ef61bb 100644
--- a/tasks/tracer.py
+++ b/tasks/tracer.py
@@ -5,6 +5,7 @@ from ws.message import MsgIo
from components import ATemperatureSensor
from components import AHeater
from components import APid
+from tracer import Tracer
import numpy as np
import scipy.io
@@ -12,7 +13,7 @@ import os
class TracerTask(ATask):
- def __init__(self, sensor: ATemperatureSensor, heater: AHeater, temp_ctrl: APid, interval, msg_handler: MsgIo, path= './logs'):
+ def __init__(self, sensor: ATemperatureSensor, heater: AHeater, temp_ctrl: APid, tracer: Tracer, interval, msg_handler: MsgIo, path= './logs'):
ATask.__init__(self, interval)
if not os.path.exists(path):
os.makedirs(path)
@@ -23,6 +24,7 @@ class TracerTask(ATask):
self.sensor = sensor
self.heater = heater
self.temp_ctrl = temp_ctrl
+ self.tracer = tracer
self.path = path
async def recv(self, data):
@@ -44,8 +46,13 @@ class TracerTask(ATask):
_tc_dtemp_soll = np.empty(0)
_tc_dtemp_commanded = np.empty(0)
- filename = os.path.join(self.path, '') + "brewpi." + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".mat"
+ name = 'brewpi'
+ filename = os.path.join(self.path, '') + name + ".mat"
+ filename_full = os.path.join(self.path, '') + name + "." + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".mat"
+
while True:
+ self.tracer.process()
+
_timestamp = np.append(_timestamp, timestamp)
_sensor_temp = np.append(_sensor_temp, self.sensor.temperature())
_heater_power = np.append(_heater_power, self.heater.get_power())
@@ -57,8 +64,8 @@ class TracerTask(ATask):
data = {'time': _timestamp, 'sensor_temp': _sensor_temp, 'heater_power': _heater_power, 'tc_temp_ist': _tc_temp_ist, 'tc_dtemp_ist': _tc_dtemp_ist, 'tc_temp_soll': _tc_temp_soll, 'tc_dtemp_soll': _tc_dtemp_soll, 'tc_dtemp_commanded': _tc_dtemp_commanded}
- scipy.io.savemat('brewpi.mat', data)
scipy.io.savemat(filename, data)
+ scipy.io.savemat(filename_full, data)
timestamp += 1
await asyncio.sleep(self.interval)
diff --git a/tracer.py b/tracer.py
new file mode 100644
index 0000000..58aad7a
--- /dev/null
+++ b/tracer.py
@@ -0,0 +1,67 @@
+from typing import TypedDict
+import numpy as np
+import scipy.io
+import os
+import time
+
+
+class Entry(TypedDict):
+ variable: str
+ name: str
+ unit: str
+
+
+class Tracer:
+ def __init__(self, obj, var_list: Entry, name='default', path='./logs'):
+ if not os.path.exists(path):
+ os.makedirs(path)
+ self.obj = obj
+ self.var_list = var_list
+ self.timestamp = 0
+ self.timestamp_data = np.empty(0)
+ self.filename_full = os.path.join(path, '') + name + "." + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".mat"
+ self.filename = os.path.join(path, '') + name + ".mat"
+ self.data_list = {}
+ for var in self.var_list:
+ self.data_list[var['name']] = np.empty(0)
+
+ def process(self):
+ data = {}
+ self.timestamp_data = np.append(self.timestamp_data, self.timestamp)
+ data['time'] = self.timestamp_data
+
+ for var in self.var_list:
+ key_name = var['name']
+ key_variable = var['variable']
+ self.data_list[key_name] = np.append(self.data_list[key_name], self.obj.__getattribute__(key_variable))
+ data[key_name] = self.data_list[key_name]
+
+ scipy.io.savemat(self.filename, data)
+ scipy.io.savemat(self.filename_full, data)
+ self.timestamp += 1
+
+
+class Test:
+ def __init__(self):
+ self.a = 0
+ self.b = 0
+
+ def process(self):
+ self.a += 1
+ self.b += 10
+
+ @staticmethod
+ def get_entry():
+ a: Entry = [{'variable': 'a', 'name' : 'v_a', 'unit': 'u_a'}]
+ b: Entry = [{'variable': 'b', 'name' : 'v_b', 'unit': 'u_b'}]
+ return a + b
+
+
+if __name__ == '__main__':
+ test = Test()
+
+ dut = Tracer(test, Test.get_entry(), name='TracerTest')
+
+ for i in range(0, 10):
+ dut.process()
+ test.process()