Thermal circuit to state-space#
This notebook is a go through complete example of how to obtain a state-space representation from the building described by walls and the thermal circuits. The steps are:
in a folder, describe the walls (wall type and wall data), the thermal circuits and give the assembling matrix or lists;
from walls and thermal circuits obtain the set of disassembled circuits (function
dm4bem.bldg2TCd()
);assemble the set of disassembled thermal circuits (function
dm4bem.assemble_TCd_matrix()
);transform the thermal circuit into state-space representation (function
dm4bem.tc2ss()
).
import numpy as np
import pandas as pd
import dm4bem
Assembling and converting the thermal circuits to state-space#
Consider the disassembled thermal circuits shown in Figure 1 that we want to assemble as shown in Figure 2 and then obtain the state-space representation.
Figure 1. Four disassembled thermal circuits: wall_out, TC0, TC1, TC2, TC3.
Figure 2. The assembling of the four circuits from Figure 1.
The steps to obtain a state-space model from thermal circuits described in a folder (link) are:
Obtain the disassembled set of thermal circuits from data given in a folder.
# Disassembled thermal circuits
folder_path = './pd/bldg'
TCd = dm4bem.bldg2TCd(folder_path,
TC_auto_number=True)
# For non auto-numbering of thermal circuits TC
# TCd = dm4bem.bldg2TCd(folder_path, TC_auto_number=False)
Assemble the set of thermal circuits
# Assembled thermal circuit:
# from 'assembly_matrix.csv'
ass_mat = pd.read_csv(folder_path + '/assembly_matrix.csv')
TCm = dm4bem.assemble_TCd_matrix(TCd, ass_mat)
# from 'assembly_lists.csv'
ass_lists = pd.read_csv(folder_path + '/assembly_lists.csv')
ass_mat = dm4bem.assemble_lists2matrix(ass_lists)
TCl = dm4bem.assemble_TCd_matrix(TCd, ass_mat)
Transform the thermal circuit into state-space representation.
# State-space from TC
[As, Bs, Cs, Ds, us] = dm4bem.tc2ss(TCl)
The state-space representation is characterized by the matrices A (state), B (input), C (output) and D (feedthrough) and by the input vector u. Note the use of ‘s’ (from state-space) in the names of As, Bs, Cs, Ds, us in order to avoid confusion with the notation for differential-algebraic equations (A, G, C, b, f).
As
c1_θ0 | c2_θ0 | ow0_θ1 | ow0_θ3 | |
---|---|---|---|---|
c1_θ0 | -0.000240 | 0.000085 | 0.000000 | 0.000002 |
c2_θ0 | 0.002857 | -0.003925 | 0.000000 | 0.000790 |
ow0_θ1 | 0.000000 | 0.000000 | -0.000024 | 0.000002 |
ow0_θ3 | 0.000011 | 0.000107 | 0.000121 | -0.000239 |
Bs
c1_q0 | c2_q0 | c3_q0 | ow0_q0 | c1_θ0 | c2_θ0 | ow0_θ0 | ow0_θ4 | |
---|---|---|---|---|---|---|---|---|
c1_θ0 | 0.000152 | 0.000000 | 0.0 | 0.000000 | 9.182736e-07 | 0.000000 | 0.000000e+00 | 8.022399e-08 |
c2_θ0 | 0.000000 | 0.000278 | 0.0 | 0.000000 | 0.000000e+00 | 0.000031 | 0.000000e+00 | 2.600003e-05 |
ow0_θ1 | 0.000000 | 0.000000 | 0.0 | 0.000022 | 0.000000e+00 | 0.000000 | 1.970654e-08 | 0.000000e+00 |
ow0_θ3 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000e+00 | 0.000000 | 0.000000e+00 | 2.931595e-07 |
Cs
c1_θ0 | c2_θ0 | ow0_θ1 | ow0_θ3 | |
---|---|---|---|---|
c2_θ0 | 0.0 | 1.0 | 0.0 | 0.0 |
Ds
c1_q0 | c2_q0 | c3_q0 | ow0_q0 | c1_θ0 | c2_θ0 | ow0_θ0 | ow0_θ4 | |
---|---|---|---|---|---|---|---|---|
c2_θ0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
pd.DataFrame({'u': us})
u | |
---|---|
c1_q0 | To |
c2_q0 | To |
c3_q0 | Ti_sp |
ow0_q0 | To |
c1_θ0 | Φa |
c2_θ0 | Qa |
ow0_θ0 | Φo |
ow0_θ4 | Φi |
The state-space representation allows us to do the eigenvalues analysis and to find the maximum time step \(\Delta t_{max} = 2 \min (-1 / \lambda_i) \), where \(\lambda_i\) are the eigenvalues of the state matrix \(A_s\).
λ = np.linalg.eig(As)[0] # eigenvalues of matrix As
λ = np.sort(λ)
print('Time constants:', [f'{T:.2f} s' for T in -1 / λ])
# maximum time step
dtmax = 2 * min(-1. / λ)
dm4bem.print_rounded_time('Max. time step: ', dtmax)
# settling time
t_settle = 4 * max(-1 / λ)
dm4bem.print_rounded_time('Setting time: ', t_settle)
Time constants: ['249.30 s', '4093.21 s', '6729.13 s', '44033.06 s']
Max. time step: = 498 s = 8.3 min
Setting time: = 176132 s = 48.9 h
Comparing the results#
The model used in this notebook is similar to that used in Jupyter Notebook on Toy model house. The notations in the two models are different (see Figure 2 and Figure 3).
Figure 3. Thermal circuit for the cubic building used in Toy model house
The correspondences between the notations in the two models (i.e., this notebook and Toy model house) is shown in Tables 1, 2, and 3.
Table 1. Correspondence between states (i.e., temperature nodes with capacities) in Figures 2 and 3.
Fig. 2 |
ow0_θ1 |
ow0_θ3 |
c2_θ0 |
c1_θ0 |
---|---|---|---|---|
Fig. 3 |
θ1 |
θ3 |
θ6 |
θ7 |
Table 2. Correspondence between temperature sources in Figures 2 and 3.
Fig. 2 |
ow0_q0 |
c1_q0 |
c2_q0 |
c3_q0 |
---|---|---|---|---|
Fig. 3 |
q0 |
q8 |
q10 |
q11 |
Table 3. Correspondence between flow sources in Figures 2 and 3.
Fig. 2 |
ow0_θ0 |
ow0_θ4 |
c2_θ0 |
c1_θ0 |
---|---|---|---|---|
Fig. 3 |
θ0 |
θ4 |
θ6 |
θ7 |
θ_order = ['ow0_θ1', 'ow0_θ3', 'c2_θ0', 'c1_θ0']
uT_order = ['ow0_q0', 'c1_q0', 'c2_q0', 'c3_q0']
uQ_order = ['ow0_θ0', 'ow0_θ4', 'c2_θ0', 'c1_θ0']
u_order = uT_order + uQ_order
y_order = ['c2_θ0']
By reindexing the matrices of the state-space model, it becomes easier to compare the results from this notebook and Toy model house.
As.reindex(index=θ_order, columns=θ_order)
ow0_θ1 | ow0_θ3 | c2_θ0 | c1_θ0 | |
---|---|---|---|---|
ow0_θ1 | -0.000024 | 0.000002 | 0.000000 | 0.000000 |
ow0_θ3 | 0.000121 | -0.000239 | 0.000107 | 0.000011 |
c2_θ0 | 0.000000 | 0.000790 | -0.003925 | 0.002857 |
c1_θ0 | 0.000000 | 0.000002 | 0.000085 | -0.000240 |
Bs.reindex(index=θ_order, columns=u_order)
ow0_q0 | c1_q0 | c2_q0 | c3_q0 | ow0_θ0 | ow0_θ4 | c2_θ0 | c1_θ0 | |
---|---|---|---|---|---|---|---|---|
ow0_θ1 | 0.000022 | 0.000000 | 0.000000 | 0.0 | 1.970654e-08 | 0.000000e+00 | 0.000000 | 0.000000e+00 |
ow0_θ3 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000e+00 | 2.931595e-07 | 0.000000 | 0.000000e+00 |
c2_θ0 | 0.000000 | 0.000000 | 0.000278 | 0.0 | 0.000000e+00 | 2.600003e-05 | 0.000031 | 0.000000e+00 |
c1_θ0 | 0.000000 | 0.000152 | 0.000000 | 0.0 | 0.000000e+00 | 8.022399e-08 | 0.000000 | 9.182736e-07 |
Cs.reindex(index=y_order, columns=θ_order)
ow0_θ1 | ow0_θ3 | c2_θ0 | c1_θ0 | |
---|---|---|---|---|
c2_θ0 | 0.0 | 0.0 | 1.0 | 0.0 |
Ds.reindex(index=y_order, columns=u_order)
ow0_q0 | c1_q0 | c2_q0 | c3_q0 | ow0_θ0 | ow0_θ4 | c2_θ0 | c1_θ0 | |
---|---|---|---|---|---|---|---|---|
c2_θ0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
Types of notation#
The notation used for the nodes and flow rates can be symbols or numbers (in the case of autonumbering).
The data used in the next examples is extracted from the paper:
Ghiaus, C. (2013). Causality issue in the heat balance method for calculating the design heating and cooling load. Energy, 50, 292-301.
Thermal circuit file to state-space#
File describing the thermal circuit with symbols#
Let’s consider a thermal circuit that uses symbols for numbering the temperature nodes and the oriented flow branches (Figure 4).
Figure 4. Thermal circuit with symbols.
The thermal circuit from Figure 4 is defined in the file ./TC_tc2ss/TC_tc2ss_sym.csv
(link). In this case, symbols are used for the nodes and the branches.
pd.read_csv('./pd/TC_tc2ss/TC_tc2ss_sym.csv')
A | θso | θw | θsi | θa | G | b | |
---|---|---|---|---|---|---|---|
0 | qw0 | -1 | 1.0 | NaN | NaN | 2.9 | NaN |
1 | qw1 | NaN | -1.0 | 1 | NaN | 2.9 | NaN |
2 | qv | NaN | NaN | NaN | 1 | 38.3 | Tov |
3 | qco | 1 | NaN | NaN | NaN | 250.0 | Tow |
4 | qci | NaN | NaN | -1 | 1 | 125.0 | NaN |
5 | C | NaN | 4000000.0 | NaN | 8.2E+04 | NaN | NaN |
6 | f | Qo | NaN | Qi | Qg | NaN | NaN |
7 | y | NaN | NaN | 1 | 1 | NaN | NaN |
Auto-numbering#
The nodes and the oriented branches can be auto-numbered. The names of the nodes and branches are composed by the name of the circuit and θ0, θ1, … , for nodes and q0, q1, … for branches, e.g., a_θ1 stands for temperature node θ1 of circuit a.
TC_file = "pd/TC_tc2ss/TC_tc2ss_sym.csv"
TC = dm4bem.file2TC(TC_file, name="a",
auto_number=True)
[Asa, Bsa, Csa, Dsa, ua] = dm4bem.tc2ss(TC)
Asa
a_θ1 | a_θ3 | |
---|---|---|
a_θ1 | -0.000001 | 7.085614e-07 |
a_θ3 | 0.000035 | -5.016371e-04 |
Symbols#
Alternatively, the nodes and the branches can keep the names given in the TC
file (the default value of auto_number
is False
).
TC_file = "pd/TC_tc2ss/TC_tc2ss_sym.csv"
TC = dm4bem.file2TC(TC_file, name="s")
[Ass, Bss, Css, Dss, us] = dm4bem.tc2ss(TC)
Ass
sθw | sθa | |
---|---|---|
sθw | -0.000001 | 7.085614e-07 |
sθa | 0.000035 | -5.016371e-04 |
Note that the order of symbols correspond to the order given in the description file ./TC_tc2ss/TC_tc2ss_num.csv
not to the alphabetical order.
File describing the thermal circuit with numbers#
Instead of using symbols, the thermal circuit can be numbered (Figure 5).
Figure 5. Numbered thermal circuit
The thermal circuit from Figure 5 is defined in the file ./TC_tc2ss/TC_tc2ss_num.csv
(link). In this case, the nodes and the branches are numbered.
pd.read_csv('./pd/TC_tc2ss/TC_tc2ss_num.csv')
A | θ0 | θ1 | θ2 | θ3 | G | b | |
---|---|---|---|---|---|---|---|
0 | q0 | NaN | NaN | 1 | NaN | 38.3 | Tov |
1 | q1 | 1 | NaN | NaN | NaN | 250.0 | Tow |
2 | q2 | -1 | NaN | NaN | 1.0 | 2.9 | NaN |
3 | q3 | NaN | 1 | NaN | -1.0 | 2.9 | NaN |
4 | q4 | NaN | -1 | 1 | NaN | 125.0 | NaN |
5 | C | NaN | NaN | 8.2E+04 | 4000000.0 | NaN | NaN |
6 | f | Qo | Qi | Qg | NaN | NaN | NaN |
7 | y | NaN | 1 | 1 | NaN | NaN | NaN |
TC_file = "pd/TC_tc2ss/TC_tc2ss_num.csv"
TC = dm4bem.file2TC(TC_file, name="n")
[Asn, Bsn, Csn, Dsn, un] = dm4bem.tc2ss(TC)
Asn
nθ2 | nθ3 | |
---|---|---|
nθ2 | -5.016371e-04 | 0.000035 |
nθ3 | 7.085614e-07 | -0.000001 |
Note that the values of the state-space representations are the same but the order is different. The order is given by the .cvs
files that define the thermal circuit.