Appendix
The code in an office setting is PCM-HX.
Dependencies on Load:
import math import matplotlib import numpy as [Link] as PLT
import matplotlib as mpl import pandas as pd import [Link]('figure',
figsize=(8, 6)
Temperature-dependent capacitance: Cp(T)
Temperature-dependent capacitance: Cp(T) Capacitance that changes with
temperature: Cp(T) Temperature-dependent capacitance: Cp(T) Capacitance
that changes with temperature: Cp(T)
Temperature-dependent capacitance: Cp(T) Capacitance that changes with
temperature: Cp(T) Temperature-dependent capacitance: Cp(T) #F: Nodes'
conductance vector that is linked to a temperature source that is known; #C is
the capacitance vector; #U is the symmetric conductance matrix.
#q: Heat flow vector with solely outside influences # VF: View factor matrix #
Node that indexing begins at "0" in Python (instead of "1" like in Matlab) #nN:
Number of nodes # Q: Heat flow vector from the previous timestep, external
sources, and capacitance # Node Number: The top front wall, or Surface #0,
is opaque; the left, back, and right surfaces are Surfaces #1, #2, and #3, in
that order.
Temperature-dependent capacitance: Cp(T) Capacitance that changes
with temperature: Cp(T) Variable capacitance according to temperature:
Cp(T) Cp(T) #4: middle transparent front wall #5: bottom of front wall ->
opaque Temperature-dependent capacitance of the flooring surface (#6)
The seventh surface of the ceiling is Air Node #8 #9: the inside side; this node
is connected to the left and right surfaces.
#11: interior floor; interior ceiling; #2: the inside back, which is believed to be
adiabatic behind this layer; #3: central window, outer pane
The air temperature at the PCM inlet is denoted by ## P0. P1 is the air
temperature following the initial PCM setting. The air temperature after the
second PCM set is denoted by # P2. The first PCM set, node, is ## 14. The first
PCM set is #15, surface. The first PCM set, air stream, is ## 16. ## 17 is the
subsequent
Shape and additional characteristics
A_sid = 12.8 A_cei = 16.0 A_bck = 12.8 A_ftp = 4.8 A_ftm = 4.8 A_fbt = 3.2 A =
[Link]([A_sid, A_sid, A_bck, A_ftp, A_ftm, A_fbt, A_cei, A_cei, 0, A_sid,
A_cei, A_cei, A_bck, A_ftm]) Vol = 51.2 A_total = 2*(A_sid + A_bck + A_cei)
R_curt = 3. # m^2K/W
purge = 0 # nocturnal ventilation with on/off switching
VF = [Link]([ [0, 0.1827, 0.1491, 0.0685, 0.0685, 0.0457, 0.2429, 0.2429], \
[0.1827, 0, 0.1491, 0.0685, 0.0685, 0.0457, 0.2429, 0.2429], \ [0.1766, 0.1766,
0, 0.0662, 0.0662, 0.0442, 0.2350, 0.235], \ [0.1827, 0.1827, 0.1491, 0, 0, 0,
0.2429, 0.2429], \ [0.1827, 0.1827, 0.1491, 0, 0, 0, 0.2429, 0.2429], \ [0.1827,
0.1827, 0.1491, 0, 0, 0, 0.2429, 0.2429], \ [0.1944, 0.1944, 0.1588, 0.0729,
0.0729, 0.0486, 0, 0.2582], \ [0.1944, 0.1944, 0.1588, 0.0729, 0.0729, 0.0486,
0.2582, 0] ]) nR = [Link](VF,0)
Radiosity
e_glas = 0.868, e_surf = 0.9, sig = 5.67e-8
(nR,1)) = *e_surf # emissivity vector emis[4] = e_lowe = 0.013 emis =
np.onese_glas
uRad = [Link]((nR,nR)) for iR in range(0,nR): if VF[iR,jR]!= 0: for jR in
range(0,nR): ((1-emis[iR])/(A[iR]*emis[iR]) + 1/(A[iR]*VF[iR,jR]) + (1-
emis[jR])/(A[jR]*emis[jR]))**-1 is the value of uRad[iR,jR].
Solar radiation
direct_60.pkl' as f: #[Link](f) q_st, q_sa_ext_pane, q_sa_int_pane; #with
open('[Link]') as f:
index_col=0, data = pd.read_csv('F:\PCM Journal/[Link]'), parse_dates=True,
infer_datetime_format=True)
Data['q_st'] equals Q_st....guidelines
q_sa_ext_pane..principles = data['q_sa_ext_pane']
Q_sa_int_pane.principles = Data['q_sa_int_pane']
# Presume that q_st_overcast = 0.20 * q_st # Cloudy and overcast sky
Q_st = q_st_overcast; Q_sa_ext_pane = 0.20*q_sa_ext_pane
Q_sa_int_pane = 0.20*Int_pane_q_sa
[Link]('g', label='q_sa_ext_pane'),q_sa_ext_pane, [Link](q_st,'b',
label='q_st'), [Link]()
[Link]('Heat, W'),q_sa_int_pane, [Link]('r', label='q_sa_int_pane')
[Link]('Timestep') with loc set to 'best' [Link]
#%%# ASHRAE values; the total of convection, conduction, and radiation is
the h-value. [Link]() [Link]()
# W/m^2K #H_int = 4. #W/m^2K #h_out = 34. #h_gap = 3.35 #k_gla = 1. #
W/mK
Glass thickness: 4 mm; h_gap_conv = 1.50; #x_gla = 0.004 # m
Material properties
Concrete
Where J = kgm^2/s^2, rho_conc = 2240 # kg/m^3, and Cp_conc = 840 #
J/(kg*K), we get k_conc = # W/(m*K) = 1.731.
50 mm (2") of effective slab thickness, split into two nodes; dx_conc = 0.050/2
#m
Gypsum
k_gyps = # W/(m*K) = 0.810
Where J = kgm^2/s^2, rho_gyps = 1680 # kg/m^3 and Cp_gyps = 840 # J/(kg*K).
k_air = 0.0255 # W/(m*K), 1 node # Air, 2 layers of gympsum 25 mm total (1"),
and dx_gyps = 0.025 # m
Cp_air = 1006 # J/(kg*K) and rho_air = 1.184 # kg/m^3.
20. #Mass multiplier multiplication
DuPont Energain PCM
Utilize use_PCM = True # when using the PCM-TES Option.
There are six instances that the PCM-TES system needs to be turned on. The
PCM-TES system must be turned off fifteen times.
toggle = 0 # Press "1" or "on" to activate the PCM-TES fan; if not, press "0";
W/(m*K) = 0.20 # k_PCM
dx_PCM = 0.0052 # m; rho_PCM = 850. # kg/m^3 T_PCM = #degC, the
temperature of the PCM-TES at full charge (hot) m_PCM_total =
n_PCM*m_PCM # kg/s, total massflow rate in PCM-TES A_PCM = 2.4 # m^2,
area of PCM panel ehAmCp = [Link](-
h_PCM*2*6*A_PCM/(10*m_PCM*Cp_air)), convection in PCM-TES channel
n_PCM = 16 # number of PCM panels * 2 m_PCM = 50./3600. # kg/s
Melting Cp Parameters
PCMm_T_peak = 23.6 #temperature of peak phase change, C PCMm_skew =
#skew – -10
Range of PCMm_rng = 4.5 #, C for phase change
PCMm_dh is 13100. Enthalpy of phase transition, J/kg 13100 87
PCMm_Cp_avg = 3500. #average solid and liquid specific heat (full quality),
J/kg
Freezing Cp Parameters
PCMf skew = -4, PCMf rng = 4.68, and PCMf T peak = 20.8
PCMf_dh is 12600, while PCMf_Cp_avg is 3500.
Simulation control
N = 20 st / h = 60 steps
H is the number of simulated hours (24 # hr).
nt = int(st*H) #dt = 3600/st #s (3600 sec = 1 hour) is the number of timesteps.
days = 1 # number of maximum simulated days overallItt = 1. # maximum
number of iterations allowedErr = 1e-5 represents the maximum temperature
difference between iterations and the subsequent critical_dt = rho_conc *
Cp_conc*(dx_conc/2)**2/(2*k_conc).
Known temperatures
([Link]((nt*days,1)) = T_out #degC
T_out_m = -15. #degC; T_out = 10 for the outside temperature.
T out theta = -5 * np / 4 and w = 2 * np / 86400
Temperature setpoint
Heating; time-step-specific interior temperature setpoint; [Link]((nt,1))
#degC = T_SP. 22 is T_SP_day_heating.
Time is equivalent to t*dt/3600 for t in range(0,nt): T_SP_dT = 4.88
setback_beg = 18. setback_end = 6. ramp_dur = 0 # hours.
If (setback_beg <= time and time < (setback_beg+ramp_dur)): # begin the
regression (time \ (setback_end-ramp_dur) or time \ (setback_beg+ramp_dur))
elif *T_SP_dT/ramp_dur # - (time-setback_beg)*T_SP_day elif ((setback_end-
ramp_dur) <= time and time < setback_end) at night: Day-to-day T_SP_dT =
T_SP[t] # undo the loss
*T_SP[t] - (setback_end-time)*T_SP_dT/ramp_dur*T_SP_day
Alternatively: #daytime
T_SP[t] = T_SP_day
Cooling
hours for t in the interval (0,nt): Setback_end_Cool = 6, ramp_dur_Cool = 0,
and time = t*dt/3600 determine T_SP_Cool[t] = T_SP_day_Cool -
(time~setback_beg_Cool). T_SP_Cool[t] = T_SP_day_Cool if (time <
(setback_beg_Cool+ramp_dur_Cool) and setback_beg_Cool \=
time)*T_SP_dT_Cool/ramp_dur_Cool elif
((setback_beg_Cool+ramp_dur_Cool)= time or time \
(setback_end_Cool}ramp_dur_Cool)): - T_SP_dT_Cool = T_SP_day_Cool -
(setback_end_Cool}time) elif ((setback_end_Cool-ramp_dur_Cool) \= time
and time \ setback_end_Cool)*ramp_dur_Cool/T_SP_dT_Cool, otherwise:
(Days,1) T_SP_Day_Cool = T_SP_Cool[t] T_Setpoint_Heating) -
T_Setpoint_Cooling - [Link](T_SP) (days,1) - [Link](T_SP_Cool)
#System of heating and cooling Heat_output = [Link]((delay_nt,1)) = q_aux
[Link]((nt*days,1)) = W SP_Err delay_nt = 5 # W; Heater size min_Cap = 0 #
degC max_Cap = 3000 # W; minimum heat Kp = max_Cap/0.5 Ki = 0. Kp_Cool
= max_Cap_Cool/2 Ki_Cool = 0.0; iTerm = 0; cool_aux = 0; SP_Err_Cool =
[Link]((nt*days,1)) and heat_aux = 0. #degC min_Cap_Cool = 0.
max_Cap_Cool = 3000.
Declare variables
The formula for [Link]((nN,1)) = C # J/K T is [Link]((t*days,nN)) #degC.
P0 #degC = [Link]((nt*days,1))
P1 #degC = [Link]((nt*days,1))
(nt*days,1)) [Link] = P2 [Link]((nt*days,1)) = #degC q_PCM
Count of nodes with capacitance
Air*Cp*(Vol*multi) Rho = C[8]
90
(dx_gyps*A[9]) * Rho_gyps*Cp_gyps* = C[9]
C[10] = Rho_conc*Cp_conc*(2*dx_conc*A[10])
C[11] = Rho_conc*Cp_conc*(2*dx_conc*A[11])
C[12] = Rho_gyps*Cp_gyps*(dx_gyps*A[12])
Initial condition
T[0,] = 20. T[0,] = T_SP_day - T_SP_dT
Loop for number of days
For the duration of a day, loop for d in range(0,days):
# Continue looping for the entire day.
t within the range 0–nt:
It adds up to 1.
Err = 100.
Tp = T[d*nt+t,] "Tpis :", Tp) copy
Time has the formula t*dt/3600.
# If (time < time_off_PCM and toggle == 0 and use_PCM == True): then activate
the PCM-TES system: toggle = 1 T_PCM = T[d*nt+t,14:20] # Adjust the
temperature back to normal.
Toggle = 1 and time >= time_off_PCM and use_PCM == True, then toggle = 0
and itt <= maxItt and Err > maxErr, respectively. U = [Link]((nN,nN)) to turn
off the PCM-TES system. # Identify the variables The formula for W/K F is
[Link]((nN,1)). [Link]((nt*days,1)) = #TK #W/K
PCM-TES U[14,15] = 2*A_PCM*k_PCM/dx_PCM # initial set F[13] =
(1/(h_out*A[4]))**-1
A_PCM*h_PCM = U[15,16]
#second set U[17,18] = 2*A_PCM*k_PCM/dx_PCM
A_PCM*h_PCM = U[18,19]
rho_PCM*A_PCM*dx_PCM*fCp = C[14](T[d*nt+t,14], PCMf_rng, PCMf_dh,
PCMf_Cp_avg, PCMf_skew, PCMf_T_peak)
rho_PCM*A_PCM*dx_PCM*fCp = C[17](T[d*nt+t,16], PCMf_rng, PCMf_dh,
PCMf_Cp_avg, PCMf_skew, PCMf_T_peak)
*nt+t[P0] = T[nt+t,8]
[d*nt+t] P1[= P0[d*nt+t]]*t[d*nt+t,15]* + ehAmCp(1-ehAmCp)
P1[d*nt+t]*ehAmCp + T[d*nt+t,18]* = P2[d*nt+t]Q_PCM[d*nt+t] =
toggle*m_PCM_total*Cp_air* (1-ehAmCp)From P0[d*nt+t] to P2[d*nt+t]
print(P1), "q PCM is: "
# U-matrix and the opposite
U + U.T = Ue #print(U)
# U exhibits symmetry, and non-diagonals For each i in range(0,nN), -ve s = -
[Link](Ue,1):
Del i, s = Ue[i,i] = s[i] - [Link](F[i,]) + C[i]/dt
#print ("U =",U) Und = U + U.T
Auxiliary heat, PI control
T_Setpoint_Heating[d*nt+t] = errHeatSP - T[d*nt+t,8]
T[d*nt+t,8] = errCoolSP - [d*nt+t] T_Setpoint_Cooling
err = 0.5*(abs(errCoolSP)+errCoolSP) - 0.5*(abs(errHeatSP)+errHeatSP)
#SP_Err[d*nt+t] = (T_SP[t]-T[d*nt+t,8]) + (T_SP[t]-T[d*nt+t,8]))/2 #iTerm +=
Ki*SP_Err[d*nt+t]
if output > max_Cap, then #iTerm -= output - max_Cap; otherwise, output =
Kp*err #+ iTerm.
if output < min_Cap, output = max_CapCap: # iTerm += min_Cap - output
heat_output[-1] = output heat_aux = heat_output[-1] output = min_Cap
#[Link](output_heat)
Heat flow into the node
= T_out_m + dT_out/2*[Link](w*t*dt + T_out_theta) = T_out[d*nt+t] # Outside
TK equals T_out.
[Link]((nN,1)) = q # = Qin in the Jupyter notebook's 1.2 file
A[0]/(A[0]+A[1]+A[2]) = q[0] * (A[4]*q_st[t]) * 0.30 30% of the sun's total
radiation strikes the walls and sides.
A[1]/(A[0]+A[1]+A[2]) = q[1] * (A[4]*q_st[t]) * 0.30 30% of the sun's total
radiation strikes the walls and sides.
A[2]/(A[0]+A[1]+A[2]) = q[2] * (A[4]*q_st[t]) * 0.30 30% of the sun's total
radiation strikes the walls and sides.
F[3] = q[3]*T_out[d*nt+t]
A[4] = q[4]*q_sa_int_pane[t]
F[5]*T_out[d*nt+t] = q[5]
A[4]*q_st[t] = 0.70 * q[6] #The floor receives 70% of the total sun radiation.
Heat_aux-cool_aux + q_int[t] + q_PCM[d*nt+t] equals q[8].
# Radiant ceiling, off q[13] = A[13], and heated floor, off q[11] =
0.*T_out[d*nt+t] + F[13]*q_sa_ext_pane[t]
(P1[d*nt+t]-P0[d*nt+t]) = -m_PCM*Cp_air* q[16]
(P2[d*nt+t]-P1[d*nt+t]) = -m_PCM*Cp_air* q[19]
Q-vector
[Link]((nN,1)) #Q
In range (0,nN), #for i:
#q[i] + C[i]*T[d*nt+t,i]/dt equals Q[i].
#print ("QQ is :", Q) #del i
print ("q = ",q)) #Qin = [Link]((nN,1))
# Q equals [Link]((nN,1))
Q is equal to q + [Link]([Link](F, TK[d*nt+t,]),(nN,1))
For each i in range(0,nN): # #print ("Q = ", Q) #
# q[i] + C[i]*T[d*nt+t,i]/dt = Q[i]
Q = q + [Link]([Link](F, TK[d*nt+t,]),(nN,1)) # del i
# Calculate the temperature for c in range(nN) if (days*nt) > (d*nt+t+1):
T[d*nt+t+1,c] = dt/C[c] * if (C[c]!= 0) ([Link](T[d*nt+t,] + Q[c]) + Ue[c,]
Alternatively, T[d*nt+t+1,c] = ([Link](Und[c,],T[d*nt+t,]) +
[Link](F[c,],TK[d*nt+t,]) + q[c])/([Link](Und[c,]) + [Link](F[c,]))
# Save statistics on auxiliary heat
Q_aux[d*nt+t+1,] = heat_aux - cool_aux and print ("Both heating and cooling
are on at timestep: %i, heating: %.0f W, cooling: %.0f W") if both heat_aux and
cool_aux are more than 20.
#Error computing iterations for (d*nt+t, heat_aux, cool_aux)) %.0f W" %
Tp equals T[d*nt+t+1,] [Link]([Link](T[d*nt+t+1,]-Tp)) = Err
# Iterate Itt += 1 95 if Itt == [Link]:
% (d*nt+t) % print "%i" % "Max iteration occurred at timestep"
# T[d*nt+t+1,] = [Link](U,Q).T #else:
[Link](U[c,]) + [Link](F[c,]) + (q[c,])/([Link](U[c,],T[t,]) equals #T[t+1,c].
Heat_output = [Link](-(delay_nt-1):],0) print ("done") # Adjust the heat
output delay by adding a 0 at the end and advancing everything by a timestep.
Setpoints with internal temperature
ax = [Link](True) fig.add_subplot(1,1,1)
[Link](T_SP,'k--', linewidth=3),[Link](dt/3600.,range(0,nt)),
[Link]('k:', linewidth=3),T_SP_Cool,[Link](dt/3600.,range(0,nt)),
plotT = T[(days-1)]*nt:(days)*nt:]
[Link](plotT[:,8],'k', linewidth=3),plotT[[Link](dt/3600.,range(0,nt))
[Link]([0,2])
[Link](0,25,3) ticks = ax.set_xticks(ticks)
[Link]([15,28])
[Link]()
[Link](loc='lower right', fontsize='medium'],['Heating setpoint','Cooling
setpoint','Room air'])
[Link]('Hour, Time')
[Link]('Celsius, degrees Celsius')
[Link]('Climatic Zone')
Heating/cooling
plotQ = (days-1) q_aux*nt:(days)*nt:]
fig = [Link]() print ("plotQ = ", plotQ)
Fig.add_subplot(1,1,1) = 96 ax
[Link](True)
[Link](plotQ,'k', linewidth=3),[Link](dt/3600.,range(0,nt)),plot
[Link]([0,24])
[Link](0,25,3) = ticks
Set_xticks(ticks) in ax
[Link]('Hour, Time')
[Link]('Heating or Cooling Assistance, W')
[Link]('Air node receives supplemental heating or cooling')
[Link](True)
[Link]()
Savefig #[Link]('[Link]')
[Link](q_aux) #[Link]([-2000,1100]) #fig = [Link]()
Outside temperature
T_out[(days-1)] = plotTout*nt:(days)*nt:]
fig = [Link]()
ax = add_subplot(1,1,1) in fig.
[Link](True)
[Link](plotTout, 'k', linewidth=3),[Link](dt/3600.,range(0,nt))
[Link]([0,24])
[Link](0,25,3) = ticks
Set_xticks(ticks) in ax
ax2 = [Link]()
[Link](0,25,3) = ticks2
Set_xticks(ticks2) in ax2.
[Link](q_st*5,'y--', linewidth=3),[Link](dt/3600.,range(0,nt)
Set_ylim(0, 120) in ax2.
ax.set_ylim(-20,-8)
"Time, h"; ax.set_xlabel( )
('Outside temperature, degC') ax.set_ylabel
Set_xlabel('Time, h') in ax2.
Set_ylabel('Solar') in ax2.
#[Link]('Hour, period')
[Link]('South-facing façade illumination, W/M^2')
PlotTout, 'k', label = 'Outside temperature', lns1 = [Link]
(q_st*5,'y--', label = 'Irradiance - south facing facade') = lns2 = [Link](
lns = lns1 + lns2; l.get_label() for l in lns; labs =
[Link](loc=0, lns, labs)
Solar radiation transmitted
fig = [Link]()
ax = [Link](True) fig.add_subplot(1,1,1)
[q_st, q_sa_ext_pane],'y', linewidth=2) #[Link]([Link](dt/3600.,range(0,nt))
[Link](q_st,'k', linewidth=3),[Link](dt/3600.,range(0,nt)),
[Link](q_sa_int_pane,'k--', linewidth=3),[Link](dt/3600.,range(0,nt))
[Link](q_sa_ext_pane,'k:', linewidth=3),[Link](dt/3600.,range(0,nt))
[Link]([0,24])
[Link](0,25,3) ticks = ax.set_xticks(ticks)
[Link]('Hour, Time')
[Link]('W/m^2 of irradiance')
[Link](['Absorbed Exterior Pane', 'Transmitted', 'Absorbed Interior
Pane'],loc='best', fontsize='medium')
[Link]("Heat From the Sun")
[Link](True)
[Link]() ##[Link]('[Link]')
plotT = T[(days-1)]*nt:(days)*nt:]
fig = [Link]()
ax = add_subplot(1,1,1) in fig.
[Link](True)
plotT[:,[0,1,2,6,7,10,11]]) [Link]([Link](dt/3600.,range(0,nt))
[Link]([0,24])
[19.2,20]) #[Link]
[Link](0,25,3) ticks = ax.set_xticks(ticks)
[Link]('Hour, Time')
[Link]('Celsius, degrees Celsius')
Office temperature: periodic steady state, [Link]
[Link](True)
[Link](['Back Surface', 'Left Surface', 'Right Surface', 'Floor Surface',\
'Ceiling Surface', 'Floor Inside', 'Ceiling Inside'],loc=0)
[Link]()