4.2. Two State Model for a Single Heater#
4.2.1. Dynamics of the Heater/Sensor System#
The previous results are not yet fully satisfactory. We’re still missing the initial ‘lag’ in response of the measured temperature.
For this third model, we consider the possibility that the heater and sensor may not be at the same temperature. In other words, that the heater/sensor assembly is not at a uniform temperature. To account for this possibility, we introduce \(T_{H,1}\) to denote the temperature of heater one and \(T_{S,1}\) to denote the temperature of the corresponding sensor. We’ll further assume that sensor mainly exchanges heat with the heater, and the dominant heat transfer to the surroundings is through the heat sink attached to the heater.
This motivates a model
where \(C^H_p\) and \(C^S_p\) are the gross heat capacities of the heater and sensor, respectively, and \(U_c\) is a new heat transfer coefficient characterizing the exchange of heat between the heater and sensor.
4.2.2. Model in deviation variables#
Following the approach demonstrated in the first two models, we construct a model in terms of deviation from ambient temperature.
Next we jump right to the step of tuning the model parameters to fit the step response data.
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
from scipy.integrate import odeint
from ipywidgets import interact
data = pd.read_csv('Step_Test_Data.csv').set_index('Time')[1:]
t = data.index
T1 = data['T1'].values
T2 = data['T2'].values
# known parameter values
P1 = 4
u1 = 0.5 # steady state value of u1 (fraction of total power)
P2 = 2
u2 = 0.0
T_ambient = 21
def compare(Ua, Uc, Cp_H, Cp_S):
def deriv(T,t):
T_H1, T_S1 = T
dT_H1 = -(Ua + Uc)*T_H1/Cp_H + Uc*T_S1/Cp_H + P1*u1/Cp_H
dT_S1 = Uc*T_H1/Cp_S - Uc*T_S1/Cp_S
return [dT_H1, dT_S1]
T = odeint(deriv, [0,0], t)
# plot
plt.figure(figsize=(10,6))
plt.subplot(2,1,1)
plt.plot(t, T[:,1] + T_ambient, t, T1)
plt.xlabel('Time / seconds')
plt.ylabel('Temperature / °C')
plt.title('Fitting model to Step Test Data for Heater 1')
plt.grid()
plt.text(300, 40, 'Ua = ' + str(Ua))
plt.text(300, 35, 'Uc = ' + str(Uc))
plt.text(300, 30, 'Cp_H = ' + str(Cp_H))
plt.text(300, 25, 'Cp_S = ' + str(Cp_S))
plt.subplot(2,1,2)
plt.plot(t, T[:,1] + T_ambient - T1)
plt.title('Model Error')
plt.xlabel('Time / seconds')
plt.ylabel('Temperature / °C')
plt.grid()
plt.tight_layout()
interact(compare,
Ua=(0,0.08,0.001),
Uc=(0,0.06,0.001),
Cp_H=(3,11,0.1),
Cp_S = (0.1,2,.01))
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
/var/folders/cm/z3t28j296f98jdp1vqyplkz00000gn/T/ipykernel_39317/3761358207.py in <module>
5 from ipywidgets import interact
6
----> 7 data = pd.read_csv('Step_Test_Data.csv').set_index('Time')[1:]
8 t = data.index
9 T1 = data['T1'].values
~/opt/anaconda3/lib/python3.9/site-packages/pandas/util/_decorators.py in wrapper(*args, **kwargs)
309 stacklevel=stacklevel,
310 )
--> 311 return func(*args, **kwargs)
312
313 return wrapper
~/opt/anaconda3/lib/python3.9/site-packages/pandas/io/parsers/readers.py in read_csv(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, squeeze, prefix, mangle_dupe_cols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, error_bad_lines, warn_bad_lines, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options)
584 kwds.update(kwds_defaults)
585
--> 586 return _read(filepath_or_buffer, kwds)
587
588
~/opt/anaconda3/lib/python3.9/site-packages/pandas/io/parsers/readers.py in _read(filepath_or_buffer, kwds)
480
481 # Create the parser.
--> 482 parser = TextFileReader(filepath_or_buffer, **kwds)
483
484 if chunksize or iterator:
~/opt/anaconda3/lib/python3.9/site-packages/pandas/io/parsers/readers.py in __init__(self, f, engine, **kwds)
809 self.options["has_index_names"] = kwds["has_index_names"]
810
--> 811 self._engine = self._make_engine(self.engine)
812
813 def close(self):
~/opt/anaconda3/lib/python3.9/site-packages/pandas/io/parsers/readers.py in _make_engine(self, engine)
1038 )
1039 # error: Too many arguments for "ParserBase"
-> 1040 return mapping[engine](self.f, **self.options) # type: ignore[call-arg]
1041
1042 def _failover_to_python(self):
~/opt/anaconda3/lib/python3.9/site-packages/pandas/io/parsers/c_parser_wrapper.py in __init__(self, src, **kwds)
49
50 # open handles
---> 51 self._open_handles(src, kwds)
52 assert self.handles is not None
53
~/opt/anaconda3/lib/python3.9/site-packages/pandas/io/parsers/base_parser.py in _open_handles(self, src, kwds)
220 Let the readers open IOHandles after they are done with their potential raises.
221 """
--> 222 self.handles = get_handle(
223 src,
224 "r",
~/opt/anaconda3/lib/python3.9/site-packages/pandas/io/common.py in get_handle(path_or_buf, mode, encoding, compression, memory_map, is_text, errors, storage_options)
700 if ioargs.encoding and "b" not in ioargs.mode:
701 # Encoding
--> 702 handle = open(
703 handle,
704 ioargs.mode,
FileNotFoundError: [Errno 2] No such file or directory: 'Step_Test_Data.csv'
4.2.3. Consequences of this Model#
An important consequence of this model is that temperature reported by sensor is not keep up with the heater temperature during rapid transients. To see this, below we plot the measured temperature and the predicted heater temperature.
# fitted parameters
Ua = 0.058
Uc = 0.051
Cp_H = 7.0
Cp_S = 1.12
# known parameter values
P1 = 4
u1 = 0.5 # steady state value of u1 (fraction of total power)
P2 = 2
u2 = 0.0
T_ambient = 21
def deriv(T,t):
T_H1, T_S1 = T
dT_H1 = -(Ua + Uc)*T_H1/Cp_H + Uc*T_S1/Cp_H + P1*u1/Cp_H
dT_S1 = Uc*T_H1/Cp_S - Uc*T_S1/Cp_S
return [dT_H1, dT_S1]
T = odeint(deriv, [0,0], t)
plt.figure(figsize=(10,6))
plt.subplot(2,1,1)
plt.plot(t, T1, t, T[:,0]+T_ambient)
plt.xlabel('Time / seconds')
plt.ylabel('Temperature / °C')
plt.legend(['Measured Temperature','Predicted Heater Temperature'])
plt.grid()
plt.subplot(2,1,2)
plt.plot(t, T[:,0] + T_ambient - T1)
plt.title('Sensor Error')
plt.xlabel('Time / seconds')
plt.ylabel('Temperature / °C')
plt.grid()
plt.tight_layout()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/var/folders/cm/z3t28j296f98jdp1vqyplkz00000gn/T/ipykernel_39317/1830847675.py in <module>
17 dT_S1 = Uc*T_H1/Cp_S - Uc*T_S1/Cp_S
18 return [dT_H1, dT_S1]
---> 19 T = odeint(deriv, [0,0], t)
20
21 plt.figure(figsize=(10,6))
NameError: name 't' is not defined
In some applications, such as crystallization, fermentation and separations, a mismatch of 4°C can be very significant.