This notebook is a go through complete example of obtaining a state-space representation from the bilding described by walls ans thermal circuits. The steps are:
bldg2TCd()
);assemble_TCd_matrix()
);tc2ss()
).import numpy as np
import pandas as pd
import pd_dm4bem
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 are:
# Disassembled thermal circuits
folder_path = "bldg"
TCd = pd_dm4bem.bldg2TCd(folder_path,
TC_auto_number=True)
# For non auto-numbering of thermal circuits TC
# TCd = pd_dm4bem.bldg2TCd(folder_path, TC_auto_number=False)
# Assembled thermal circuit:
# from 'assembly_matrix.csv'
ass_mat = pd.read_csv(folder_path + '/assembly_matrix.csv')
TCm = pd_dm4bem.assemble_TCd_matrix(TCd, ass_mat)
# from 'assembly_lists.csv'
ass_lists = pd.read_csv(folder_path + '/assembly_lists.csv')
ass_mat = pd_dm4bem.assemble_lists2matrix(ass_lists)
TCl = pd_dm4bem.assemble_TCd_matrix(TCd, ass_mat)
# State-space from TC
[As, Bs, Cs, Ds, us] = pd_dm4bem.tc2ss(TCl)
The state-space representation is characterized by the matrices A (state), B (input), C (ouput) 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.
λ = np.linalg.eig(As)[0] # eigenvalues of matrix As
λ = np.sort(λ)
print('Time constants:')
print([f'{T:.2f} s' for T in -1 / λ])
print('\n2 x Time constants:')
print([f'{T:.2f} s' for T in -2 / λ])
dtmax = 2 * min(-1. / λ)
print(f'\nMaximum time step: {dtmax:.2f} s = {dtmax / 60:.2f} min')
Time constants: ['249.30 s', '4093.21 s', '6729.13 s', '44033.06 s'] 2 x Time constants: ['498.60 s', '8186.41 s', '13458.25 s', '88066.12 s'] Maximum time step: 498.60 s = 8.31 min
The model used in this notebook is similar to that used in 03CubicBuilding.ipynb
. The notations in the two models are different (see Figure 2 and Figure 3).
Figure 3. Thermal circuit for the cubic building used in
03CubicBuilding.ipynb
The correspondences between the notations in the two models (i.e., this notebook and 03CubicBuilding.ipynb
) 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 03CubicBuilding.ipynb
.
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 |
The notation used for the nodes and flow 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.
import pandas as pd
import pd_dm4bem
Let's consider a thermal circuit that uses symbols for numbering the temperature nodes and the oriented flow branches (Figure 1).
Figure 1. Thermal circuit with symbols.
The thermal circuit from Figure 1 is defined in the file ./TC_tc2ss/TC_tc2ss_sym.csv
. In this case, symbols are used for the nodes and the branches.
pd.read_csv('./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 |
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 = "TC_tc2ss/TC_tc2ss_sym.csv"
TC = pd_dm4bem.file2TC(TC_file, name="a",
auto_number=True)
[Asa, Bsa, Csa, Dsa, ua] = pd_dm4bem.tc2ss(TC)
Asa
a_θ1 | a_θ3 | |
---|---|---|
a_θ1 | -0.000001 | 7.085614e-07 |
a_θ3 | 0.000035 | -5.016371e-04 |
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 = "TC_tc2ss/TC_tc2ss_sym.csv"
TC = pd_dm4bem.file2TC(TC_file, name="s")
[Ass, Bss, Css, Dss, us] = pd_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 corespond to the order given in the description file ./TC_tc2ss/TC_tc2ss_num.csv
not to the alphabetical order.
Instead of using symbols, the thermal circuit can be numbered (Figure 2).
Figure 2. Numbered thermal circuit
The thermal circuit from Figure 1 is defined in the file ./TC_tc2ss/TC_tc2ss_num.csv
. In this case, the nodes and the branches are numbered.
pd.read_csv('./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 = "TC_tc2ss/TC_tc2ss_num.csv"
TC = pd_dm4bem.file2TC(TC_file, name="n")
[Asn, Bsn, Csn, Dsn, un] = pd_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.