├── py ├── README.md ├── 10deg_h_day_night.py ├── 09_nat_ventilation_1fig.py ├── 09_nat_ventilation_2fig.py ├── 01WeatherData.py ├── 02SimpleWall.py └── 03CubicBuilding.py ├── pd ├── bldg │ ├── TC3.csv │ ├── TC2.csv │ ├── TC0.csv │ ├── assembly_matrix.csv │ ├── walls_out.csv │ ├── TC1.csv │ ├── assembly_lists.csv │ └── wall_types.csv ├── inputs │ ├── bldg │ │ ├── TC3.csv │ │ ├── TC0.csv │ │ ├── TC2.csv │ │ ├── assembly_matrix.csv │ │ ├── walls_out.csv │ │ ├── TC1.csv │ │ ├── assembly_lists.csv │ │ └── wall_types.csv │ ├── __pycache__ │ │ └── pd_dm4bem.cpython-39.pyc │ ├── 01_obtain_input_files.py │ ├── step_input.py │ └── step_input_01.py ├── __pycache__ │ └── pd_dm4bem.cpython-39.pyc ├── bldg_wall2TC │ ├── wall_types.csv │ ├── walls_in.csv │ ├── walls_out.csv │ └── walls_generic.csv ├── TC_tc2ss │ ├── TC_tc2ss_num.csv │ ├── TC_tc2ss_num_sym.csv │ └── TC_tc2ss_sym.csv ├── README.md └── 03assembleTCd.ipynb ├── M ├── M │ ├── fReadWeather.m │ ├── t01ReadWeather.m │ ├── fTC2SSold.m │ ├── fSolRadTiltSurf.m │ ├── fTC2SS.m │ ├── fTCAssAll.m │ ├── t02SimpleWall.m │ ├── t02SimpleWall01.m │ ├── t03CubeFB.m │ ├── t04CubeFBmesh.m │ ├── t07ControlHeat.m │ ├── t08ControlHVAC.m │ ├── t05CubeFBAss.m │ ├── t06CubeHeat.m │ ├── t06CubeHeatCool.m │ ├── t08ControlHeatCool.m │ └── t06Controller.m ├── TutorialsPDF_M │ ├── t02SimpleWall.pdf │ ├── t03Cube2wFB.pdf │ ├── t05CubeFBAss.pdf │ ├── t06CubeFBHeat.pdf │ ├── t01ReadWeather.pdf │ ├── t04Cube2wFBmesh.pdf │ └── README.md └── README.md ├── environment.yml ├── weather_data └── README.md ├── LICENSE ├── A03_DAE2SS.ipynb ├── README.md ├── A02_TC2DAE.ipynb └── figures └── 03_cube_principle.svg /py/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /pd/bldg/TC3.csv: -------------------------------------------------------------------------------- 1 | A,θ0,G,b 2 | q0,1,0,Ti_sp 3 | C,,, 4 | f,,, 5 | y,,, -------------------------------------------------------------------------------- /pd/bldg/TC2.csv: -------------------------------------------------------------------------------- 1 | A,θ0,G,b 2 | q0,1,9.0,To 3 | C,32400,, 4 | f,Qa,, 5 | y,1,, -------------------------------------------------------------------------------- /pd/inputs/bldg/TC3.csv: -------------------------------------------------------------------------------- 1 | A,θ0,G,b 2 | q0,1,0,Ti_sp 3 | C,,, 4 | f,,, 5 | y,,, -------------------------------------------------------------------------------- /pd/bldg/TC0.csv: -------------------------------------------------------------------------------- 1 | A,θ0,θ1,G,b 2 | q0,-1,1,44.7868, 3 | C,,,, 4 | f,,,, 5 | y,,,, -------------------------------------------------------------------------------- /M/M/fReadWeather.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cghiaus/dm4bem/HEAD/M/M/fReadWeather.m -------------------------------------------------------------------------------- /pd/inputs/bldg/TC0.csv: -------------------------------------------------------------------------------- 1 | A,θ0,θ1,G,b 2 | q0,-1,1,44.7868, 3 | C,,,, 4 | f,,,, 5 | y,,,, -------------------------------------------------------------------------------- /pd/inputs/bldg/TC2.csv: -------------------------------------------------------------------------------- 1 | A,θ0,G,b 2 | q0,1,9.0,To 3 | C,32400,, 4 | f,Qa,, 5 | y,1,, -------------------------------------------------------------------------------- /M/TutorialsPDF_M/t02SimpleWall.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cghiaus/dm4bem/HEAD/M/TutorialsPDF_M/t02SimpleWall.pdf -------------------------------------------------------------------------------- /M/TutorialsPDF_M/t03Cube2wFB.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cghiaus/dm4bem/HEAD/M/TutorialsPDF_M/t03Cube2wFB.pdf -------------------------------------------------------------------------------- /M/TutorialsPDF_M/t05CubeFBAss.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cghiaus/dm4bem/HEAD/M/TutorialsPDF_M/t05CubeFBAss.pdf -------------------------------------------------------------------------------- /M/TutorialsPDF_M/t06CubeFBHeat.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cghiaus/dm4bem/HEAD/M/TutorialsPDF_M/t06CubeFBHeat.pdf -------------------------------------------------------------------------------- /M/TutorialsPDF_M/t01ReadWeather.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cghiaus/dm4bem/HEAD/M/TutorialsPDF_M/t01ReadWeather.pdf -------------------------------------------------------------------------------- /M/TutorialsPDF_M/t04Cube2wFBmesh.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cghiaus/dm4bem/HEAD/M/TutorialsPDF_M/t04Cube2wFBmesh.pdf -------------------------------------------------------------------------------- /pd/__pycache__/pd_dm4bem.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cghiaus/dm4bem/HEAD/pd/__pycache__/pd_dm4bem.cpython-39.pyc -------------------------------------------------------------------------------- /pd/bldg/assembly_matrix.csv: -------------------------------------------------------------------------------- 1 | TC0,node0,TC1,node1 2 | ow0,4,c0,0 3 | c1,-2,c0,1 4 | c2,0,ow0,-1 5 | c2,0,c3,0 6 | c2,0,c1,-1 -------------------------------------------------------------------------------- /pd/bldg/walls_out.csv: -------------------------------------------------------------------------------- 1 | ID,type,Area,β,γ,T0,Q0,Q1,h0,h1,α0,α1,ε0,ε1,y 2 | w0,0,45,90,0,To,Φo,Φi,25,8,0.25,0.30,0.85,0.70,"[-1]" -------------------------------------------------------------------------------- /pd/inputs/bldg/assembly_matrix.csv: -------------------------------------------------------------------------------- 1 | TC0,node0,TC1,node1 2 | ow0,4,c0,0 3 | c1,-2,c0,1 4 | c2,0,ow0,-1 5 | c2,0,c3,0 6 | c2,0,c1,-1 -------------------------------------------------------------------------------- /pd/inputs/bldg/walls_out.csv: -------------------------------------------------------------------------------- 1 | ID,type,Area,β,γ,T0,Q0,Q1,h0,h1,α0,α1,ε0,ε1,y 2 | w0,0,45,90,0,To,Φo,Φi,25,8,0.25,0.30,0.85,0.70,"[-1]" -------------------------------------------------------------------------------- /pd/bldg/TC1.csv: -------------------------------------------------------------------------------- 1 | A,θg,θwi,θai,G,b 2 | qgo,1,,,165.789,To 3 | qgi,-1,1,,630, 4 | qai,,-1,1,72, 5 | C,1089000.0,,,, 6 | f,Φa,,,, 7 | y,,,1,, -------------------------------------------------------------------------------- /pd/inputs/__pycache__/pd_dm4bem.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cghiaus/dm4bem/HEAD/pd/inputs/__pycache__/pd_dm4bem.cpython-39.pyc -------------------------------------------------------------------------------- /pd/bldg/assembly_lists.csv: -------------------------------------------------------------------------------- 1 | node0,nodes 2 | "['c2', 0]","['ow0', -1], ['c3', 0], ['c1', -1]" 3 | "['ow0', 4]","['c0', 0]," 4 | "['c1', -2]","['c0', 1]," -------------------------------------------------------------------------------- /pd/inputs/bldg/TC1.csv: -------------------------------------------------------------------------------- 1 | A,θg,θwi,θai,G,b 2 | qgo,1,,,165.789,To 3 | qgi,-1,1,,630, 4 | qai,,-1,1,72, 5 | C,1089000.0,,,, 6 | f,Φa,,,, 7 | y,,,1,, -------------------------------------------------------------------------------- /pd/inputs/bldg/assembly_lists.csv: -------------------------------------------------------------------------------- 1 | node0,nodes 2 | "['c2', 0]","['ow0', -1], ['c3', 0], ['c1', -1]" 3 | "['ow0', 4]","['c0', 0]," 4 | "['c1', -2]","['c0', 1]," -------------------------------------------------------------------------------- /pd/bldg/wall_types.csv: -------------------------------------------------------------------------------- 1 | type,Material,Conductivity,Specific heat,Density,Width,Mesh 2 | 0,Concrete,1.4,880,2300,0.2,1 3 | 0,Insulation,0.027,1210,55,0.08,1 4 | 1,Glass,1.4,750,2500,0.004,1 -------------------------------------------------------------------------------- /pd/bldg_wall2TC/wall_types.csv: -------------------------------------------------------------------------------- 1 | type,Material,Conductivity,Specific heat,Density,Width,Mesh 2 | 0,Concrete,1.4,880,2300,0.2,1 3 | 0,Insulation,0.027,1210,55,0.08,2 4 | 1,Glass,1.4,750,2500,0.004,1 -------------------------------------------------------------------------------- /pd/inputs/bldg/wall_types.csv: -------------------------------------------------------------------------------- 1 | type,Material,Conductivity,Specific heat,Density,Width,Mesh 2 | 0,Concrete,1.4,880,2300,0.2,1 3 | 0,Insulation,0.027,1210,55,0.08,1 4 | 1,Glass,1.4,750,2500,0.004,1 -------------------------------------------------------------------------------- /pd/TC_tc2ss/TC_tc2ss_num.csv: -------------------------------------------------------------------------------- 1 | A,θ0,θ1,θ2,θ3,G,b 2 | q0,,,1,,38.3,Tov 3 | q1,1,,,,250,Tow 4 | q2,-1,,,1,2.9, 5 | q3,,1,,-1,2.9, 6 | q4,,-1,1,,125, 7 | C,,,8.2E+04,4E+06,, 8 | f,Qo,Qi,Qg,,, 9 | y,,1,1,,, -------------------------------------------------------------------------------- /pd/TC_tc2ss/TC_tc2ss_num_sym.csv: -------------------------------------------------------------------------------- 1 | A,θso,θsi,θa,θw,G,b 2 | qv,,,1,,38.3,Tov 3 | qco,1,,,,250,Tow 4 | qw1,-1,,,1,2.9, 5 | qw2,,1,,-1,2.9, 6 | qci,,-1,1,,125, 7 | C,,,8.2E+04,4E+06,, 8 | f,Qo,Qi,Qg,,, 9 | y,,,1,,, -------------------------------------------------------------------------------- /pd/TC_tc2ss/TC_tc2ss_sym.csv: -------------------------------------------------------------------------------- 1 | A,θso,θw,θsi,θa,G,b 2 | qw0,-1,1,,,2.9, 3 | qw1,,-1,1,,2.9, 4 | qv,,,,1,38.3,Tov 5 | qco,1,,,,250.0,Tow 6 | qci,,,-1,1,125, 7 | C,,4E+06,,8.2E+04,, 8 | f,Qo,,Qi,Qg,, 9 | y,,,1,1,, -------------------------------------------------------------------------------- /M/README.md: -------------------------------------------------------------------------------- 1 | # MATLAB®/Octave scripts 2 | 3 | The scripts are written for MATLAB® v.6 or GNU Octave v. 6. 4 | 5 | **Contents** 6 | 7 | - `M`: MATLAB®/Octave scripts 8 | - `TutorialsPDF_M`: tutorials for MATLAB®/Octave scripts. 9 | 10 | -------------------------------------------------------------------------------- /pd/bldg_wall2TC/walls_in.csv: -------------------------------------------------------------------------------- 1 | ID,type,Area,Q0,Q1,h0,h1,α0,α1,ε0,ε1,y 2 | w0,1,1,Qo,Qi,20,10,0.25,0.30,0.85,0.70,"[0, -1]" 3 | w1,1,1,Qo,Qi,20,10,0.25,0.30,0.85,0.70,1 4 | w2,0,10,Qo,Qi,21,11,0.25,0.30,0.85,0.70,"[1, 2, -1]" 5 | w3,0,20,Qo,Qi,22,12,0.25,0.30,0.85,0.70,"[2, 1, 3]" -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: dm4bem-env 2 | 3 | channels: 4 | - conda-forge 5 | 6 | dependencies: 7 | - python=3.8.8 8 | - jupyter=1.0.0 9 | - jupyterlab>=3.1 10 | - ipywidgets=7.5.1 11 | - matplotlib=3.4.1 12 | - numpy=1.20.2 13 | - scipy=1.6.2 14 | - pandas=1.2.4 15 | - voila>=0.2.11 16 | -------------------------------------------------------------------------------- /pd/bldg_wall2TC/walls_out.csv: -------------------------------------------------------------------------------- 1 | ID,type,Area,β,γ,T0,Q0,Q1,h0,h1,α0,α1,ε0,ε1,y 2 | w0,1,1,90,0,To,Qo,Qi,20,10,0.25,0.30,0.85,0.70,"[0, -1]" 3 | w1,1,1,90,0,To,Qo,Qi,20,10,0.25,0.30,0.85,0.70,1 4 | w2,0,10,0,90,To,Qo,Qi,21,11,0.25,0.30,0.85,0.70,"[1, 2, -1]" 5 | w3,0,20,0,90,Tsoil,Qo,Qi,22,12,0.25,0.30,0.85,0.70,"[2, 1, 3]" -------------------------------------------------------------------------------- /pd/bldg_wall2TC/walls_generic.csv: -------------------------------------------------------------------------------- 1 | ID,type,Area,β,γ,T0,T1,Q0,Q1,h0,h1,α0,α1,ε0,ε1,y 2 | w0,1,1,90,0,To,,Qo,Qi,20,10,0.25,0.30,0.85,0.70,"[0, -1]" 3 | w1,1,1,90,0,To,Ti,Qo,Qi,20,10,0.25,0.30,0.85,0.70,1 4 | w2,0,10,0,90,To,,Qo,Qi,21,11,0.25,0.30,0.85,0.70,"[1, 2, -1]" 5 | w3,0,20,,,,,Qo,Qi,22,12,0.25,0.30,0.85,0.70,"[2, 1, 3]" -------------------------------------------------------------------------------- /weather_data/README.md: -------------------------------------------------------------------------------- 1 | # Weather data and solar radiation on a tilted surface 2 | 3 | **Objectives**: 4 | 5 | - Download weather data in EnergyPlus format 6 | - Read weather data 7 | - Find solar radiation on a tilted surface 8 | - Visualize the data 9 | 10 | The weather file with the extension `.epw` can be dowloaded from: 11 | - [Climate.OneBuilding.Org](http://climate.onebuilding.org): folder of files at the repository of free climate data for building performance simulation, 12 | - [EnergyPlus](https://energyplus.net/weather): interactive map with locations, 13 | - [LadyBug Tools](http://www.ladybug.tools/epwmap/): interactive map with locations, 14 | - [PV GIS](https://re.jrc.ec.europa.eu/pvg_tools/en/tools.html): interractive map with interpollated data. 15 | 16 | For example, this folder contains the files: 17 | - `FRA_AR_Lyon-Bron.AP.074800_TMYx.2004-2018.epw` 18 | - `FRA_Lyon.074810_IWEC.epw` 19 | 20 | for the airport Lyon-Bron, France (N45.73, E5.08). -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Christian Ghiaus (cghiaus) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /M/TutorialsPDF_M/README.md: -------------------------------------------------------------------------------- 1 | # Tutorials for MATLAB®/Octave scripts 2 | 3 | The scripts are written for MATLAB® v.6 or GNU Octave v. 6. 4 | 5 | 1. `t01ReadWeather.pdf` *Weather data and solar radiation*: obtain weather data from Energy Plus weather files and find solar radiation on a tilted surface. 6 | 2. `t02SimpleWall.pdf` *Simple wall*: Differential-algebraic equations (DAE) model of a two layer wall with Dirichelt end von Neumann boundary conditions. 7 | 3. `t03Cube2wFB.pdf` *Cube with two different walls: feed-back indoor temperature control*: model of a cubic building with 5 identical walls and one glass wall. HVAC controller, air infiltration and internal sources are modeled. 8 | 4. `t04Cube2wFBmesh.pdf` *Cube with two different walls with variable meshgrid*: similar to `t03Cube2wFB.pdf`with the difference that the meshing of the wall layers is variable. 9 | 5. `t05CubeFBAss.pd` *Assembling thermal circuits*: similar to `t03Cube2wFB.pdf` with the difference that the thermal model is obtained by assembling thermal networks. 10 | 6. `t06CubeFBHeat.pdf` *Cubic room heated by a fan-coil*: similar to `t03Cube2wFB.pdf`with the difference that the controler has a dead-band (non-linear controller). -------------------------------------------------------------------------------- /M/M/t01ReadWeather.m: -------------------------------------------------------------------------------- 1 | clear all 2 | clc %clear console 3 | % Load weather data 4 | fileName = 'FRA_Lyon.csv'; 5 | from = 1*30*24; % start time: from 30 Jan. 6 | period = 5*24; % simulation period: in hours 7 | [Time,Temp,RadNDir,RadHDif,WDir,WSpeed,month,day,hour,minute]... 8 | = fReadWeather(fileName,from,period); 9 | 10 | % Solar radiadion on a tilted surface 11 | B = 90; % slope (tilt) angle in deg: [0 180]; 90-vertical; >90-downward facing 12 | Z = 0; % surface azimuth in deg: [-180 180]; 0-south; west-positive 13 | L = 45; % local latitude in deg: [-90 90], north positive 14 | albedo = 0.2; % albedo of ground = 0.2 15 | [PhiDir, PhiDif, PhiRef] = fSolRadTiltSurf(month, day, hour, minute,... 16 | RadNDir, RadHDif, B, Z, L, albedo); 17 | 18 | plot(Time/(24*3600), PhiDir,'b'), hold on %direct on surface 19 | % plot(Time/(24*3600), RadNDir,'g') % direct on normal to sun 20 | plot(Time/(24*3600), PhiDif,'r') % diffusif on surface 21 | % plot(Time/(24*3600), RadHDif,'k') % diffusif on horizontal surface 22 | plot(Time/(24*3600), PhiRef,'m') % reflected on surface 23 | title('Solar radiation') 24 | xlabel('Time [days]'), ylabel('\Phi [W/m^2]') 25 | legend('\Phi_d_i_r','\Phi_N_d_i_r','\Phi_D_i_f', '\Phi_N_D_i_f') -------------------------------------------------------------------------------- /pd/inputs/01_obtain_input_files.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Fri Jul 14 08:36:28 2023 5 | 6 | @author: cghiaus 7 | 8 | Obtain the .csv file for inputs from 03CubicBuilding.py 9 | This inputs file is to be used to know what to obtain from weather file and 10 | information on walls the solar radiation on walls 11 | 12 | 13 | For step input: 14 | in 03CubicBuilding.py: 15 | u = np.zeros([8, n]) # u = [To To To Tisp Φo Φi Qa Φa] 16 | u[0:3, :] = 10 * np.ones([3, n]) # To = 10 for n time steps 17 | u[3, :] = 20 * np.ones([1, n]) # Tisp = 20 for n time steps 18 | 19 | pd.DataFrame(u).to_csv('u_step.csv', index=False) 20 | ... 21 | in this file 22 | u_read = pd.read_csv('u_step.csv') 23 | 24 | For weather data: 25 | in 03CubicBuilding.py: 26 | data.rename(columns={'temp_air': 'To'}).to_csv('u_weather.csv', index=False) 27 | ... 28 | 29 | For input u for weather data: 30 | in 03CubicBuilding.py: 31 | 32 | # input vector 33 | To = data['To'] 34 | Ti = data['Ti'] 35 | Φo = α_wSW * wall['Surface']['Layer_out'] * data['Φtot'] 36 | Φi = τ_gSW * α_wSW * wall['Surface']['Glass'] * data['Φtot'] 37 | Qa = data['Qa'] 38 | Φa = α_gSW * wall['Surface']['Glass'] * data['Φtot'] 39 | 40 | u = pd.concat([To, To, To, Ti, Φo, Φi, Qa, Φa], axis=1) 41 | u.columns.values[[4, 5, 7]] = ['Φo', 'Φi', 'Φa'] 42 | 43 | pd.DataFrame(u).to_csv('u_weather.csv', index=False) 44 | pd.DataFrame(u).to_csv('u_weather.csv', index=False) 45 | ... 46 | """ 47 | import pandas as pd 48 | 49 | file_path = 't03CubicBuilding.py' 50 | # Read the contents of the script_to_run.py file 51 | with open(file_path, 'r') as file: 52 | script_contents = file.read() 53 | 54 | # Execute the script 55 | exec(script_contents) 56 | 57 | 58 | # Run the Python file using subprocess 59 | u = pd.read_csv('u_step.csv') 60 | -------------------------------------------------------------------------------- /M/M/fTC2SSold.m: -------------------------------------------------------------------------------- 1 | function [As,Bs,Cs,Ds] = fTC2SS(A,G,b,C,f,y) 2 | % transforms a model from thermal circuit (TC) to state-space (SS) 3 | % 4 | %Inputs 5 | % A adjancecy (TC connection ) matrix: 6 | % #cols = #temperature nodes; #rows = #heat flow rates 7 | % G sqaure matrix of conductances 8 | % b vector: 1 for branches with temperature sources, otherwise 0 9 | % C square matrix of capacities 10 | % f vector: 1 for nodes with heat sources, otherwise 0 11 | % y vector: 1 for output nodes, otherwise 0 12 | % 13 | %Outputs 14 | % As state matrix in state equation 15 | % Bs input matrix in state equation 16 | % Cs output matrix in observation equation for thC 17 | % Ds input matrix in obs eq for thC 18 | %******************** 19 | b = b'; f = f'; y = y'; 20 | rC = find(diag(C)); r0 = find(not(diag(C))); % find C which is: not-zero; zero 21 | if isempty(rC); error('diag(C) is zero'); end 22 | CC = C(rC,rC); % non-zero C 23 | K = -A'*G*A; 24 | K11 = K(r0,r0); 25 | K12 = K(r0,rC); 26 | K21 = K(rC,r0); 27 | K22 = K(rC,rC); 28 | 29 | Kb = A'*G; 30 | Kb1 = Kb(r0,:); 31 | Kb2 = Kb(rC,:); 32 | 33 | % state equation 34 | As = inv(CC)*(-K21*inv(K11)*K12 + K22); 35 | Bs = inv(CC)*[-K21*inv(K11)*Kb1+Kb2 -K21*inv(K11) eye(size(CC))]; 36 | 37 | f = [f(r0) f(rC)]; %rearange inputs according to zero-block matrix C 38 | in = [find(b) size(A,1)+find(f)]; %effective inputs [temp_on_branches flow_in_nodes] 39 | Bs= Bs(:,in); %extract actual inputs (inputs <> 0) 40 | 41 | % observation equation for y: a set of states thC 42 | Ds = zeros(size(y(rC),2),size([b f],2)); 43 | 44 | % observation equation for y: a set of non-states th0 45 | Cso = -inv(K11)*K12; 46 | Dso = -inv(K11)*[Kb1 eye(size(r0,1)) zeros(size(r0,1),size(CC,1))]; 47 | 48 | Cx = zeros(size(y,2),size(As,1)); 49 | Cs = diag(y(rC)); 50 | Cx(rC,:) = Cs; 51 | Cx(r0,:) = Cso; 52 | Cs = Cx(find(y),:); 53 | 54 | Dx = zeros(size(y,2),size([b f],2)); 55 | Dx(r0,:) = Dso; 56 | Ds = Dx(find(y),in); 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /M/M/fSolRadTiltSurf.m: -------------------------------------------------------------------------------- 1 | function [PhiDir, PhiDif, PhiRef]... 2 | = fSolRadTiltSurf(month, day, hour, minute, RadNDir, RadHDif, B, Z, L, albedo) 3 | % J.A. Duffie, W. A. Beckman (2013) Solar Engineering of Thermal Processes 4 | % 5 | % Data = [month day hour minute HorizRad] 6 | % month number of the month, from 1 to 12 7 | % day day in the month, from 1 to 31 8 | % hour hour in the 24 hour system (e.g. 13 for 1 p.m.) 9 | % minute minute from 0 to 59 10 | % DirNRad direct normal radiation, Wh/m2 11 | % DifHRad diffuse horizontal radiation, Wh/m2 12 | % 13 | % B slope (tilt) angle in deg: [0 180]; 90-vertical; >90-downward facing 14 | % L local latitude in deg: [-90 90], north positive 15 | % Z surface azimuth in deg: [-180 180]; 0-south; west-positive 16 | % albedo albedo of ground = 0.2 Th-CE 2005 pg. 50 17 | % 18 | % Outputs 19 | % PhiDir direct radiation on the surface in Wh/m2 20 | % PhiDif diffuse radiation on the surfaca in Wh/m2 21 | % PhiRef reflected rariation in Wh/m2 22 | 23 | B = B*pi/180; % slope 24 | Z = Z*pi/180; % azimuth 25 | L = L*pi/180; % latitude 26 | 27 | n = datenum(0, month, day); % day number in the year 28 | 29 | declination_angle=23.45*sin(360*(284+n)/365*pi/180); % eq. 1.6.1a 30 | d=declination_angle*pi/180; 31 | 32 | hour_angle=((hour+minute/60)-12)*15; % Example 1.6.1 33 | h=hour_angle*pi/180; 34 | 35 | theta = acos(sin(d)*sin(L)*cos(B) - sin(d)*cos(L)*sin(B)*cos(Z) ... 36 | + cos(d)*cos(L)*cos(B).*cos(h) + cos(d)*sin(L)*sin(B)*cos(Z).*cos(h)... 37 | + cos(d)*sin(B)*sin(Z).*sin(h)); % incidence angle eq. 1.6.2 38 | 39 | theta(theta>pi/2) = pi/2; 40 | PhiDir = RadNDir.*cos(theta); %Th-CE 2005 Eq. 41 | PhiDir(PhiDir<0) = 0; 42 | 43 | PhiDif = RadHDif.*(1 + cos(theta))/2; %Th-CE 2005 Eq. 79 44 | 45 | gamma = asin(cos(d)*cos(L).*cos(h) + sin(d)*sin(L)); 46 | gamma(gamma<10e-5) = 10e-5; 47 | RadDh = RadNDir.*sin(gamma); 48 | % radiation reflected by the ground: 49 | PhiRef = (RadDh + RadHDif)*albedo*(1 - cos(B)/2); 50 | % endfunction -------------------------------------------------------------------------------- /M/M/fTC2SS.m: -------------------------------------------------------------------------------- 1 | function [As,Bs,Cs,Ds,Idx] = fTC2SS(A,G,b,C,f,y) 2 | % transforms a model from thermal circuit (TC) to state-space (SS) 3 | % 4 | %Inputs 5 | % A adjancecy (TC connection ) matrix: 6 | % #cols = #temperature nodes; #rows = #heat flow rates 7 | % G sqaure matrix of conductances 8 | % b vector: 1 for branches with temperature sources, otherwise 0 9 | % C square matrix of capacities 10 | % f vector: 1 for nodes with heat sources, otherwise 0 11 | % y vector: 1 for output nodes, otherwise 0 12 | % 13 | %Outputs 14 | % As state matrix in state equation 15 | % Bs input matrix in state equation 16 | % Cs output matrix in observation equation for thC 17 | % Ds input matrix in obs eq for thC 18 | % Idx{1} nodes with capacities 19 | % {2} branches with temp. sources 20 | % {3} nodes with flow sources 21 | % {4} nodes output temperatures 22 | 23 | %******************** 24 | b = b'; f = f'; y = y'; 25 | rC = find(diag(C)); r0 = find(not(diag(C))); % find C which is: not-zero; zero 26 | Idx{1} = rC'; Idx{2} = find(b); Idx{3} = find(f); Idx{4} = find(y); 27 | if isempty(rC); error('diag(C) is zero'); end 28 | CC = C(rC,rC); % non-zero C 29 | K = -A'*G*A; 30 | K11 = K(r0,r0); 31 | K12 = K(r0,rC); 32 | K21 = K(rC,r0); 33 | K22 = K(rC,rC); 34 | 35 | Kb = A'*G; 36 | Kb1 = Kb(r0,:); 37 | Kb2 = Kb(rC,:); 38 | 39 | % state equation 40 | As = inv(CC)*(-K21*inv(K11)*K12 + K22); 41 | Bs = inv(CC)*[-K21*inv(K11)*Kb1+Kb2 -K21*inv(K11) eye(size(CC))]; 42 | sb = size(b,2); 43 | Bs(:,[1:sb sb+r0' sb+rC']) = Bs; % rearange in order of f-sources 44 | in = [find(b) size(A,1)+find(f)]; %effective inputs [temp_on_branches flow_in_nodes] 45 | Bs= Bs(:,in); %extract actual inputs (inputs <> 0) 46 | 47 | % observation equation for y: a set of states thC 48 | Ds = zeros(size(y(rC),2),size([b f],2)); 49 | 50 | % observation equation for y: a set of non-states th0 51 | Cso = -inv(K11)*K12; 52 | Dso = -inv(K11)*[Kb1 eye(size(r0,1)) zeros(size(r0,1),size(CC,1))]; 53 | 54 | Cx = zeros(size(y,2),size(As,1)); 55 | Cs = diag(y(rC)); 56 | Cx(rC,:) = Cs; 57 | Cx(r0,:) = Cso; 58 | Cs = Cx(find(y),:); 59 | 60 | Dx = zeros(size(y,2),size([b f],2)); 61 | Dx(r0,:) = Dso; % feed-through if no capacity 62 | Dx(:,[1:sb sb+r0' sb+rC']) = Dx; % rearange in order of f-sources 63 | Ds = Dx(find(y),in); -------------------------------------------------------------------------------- /py/10deg_h_day_night.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Fri Sep 29 14:47:05 2023 5 | 6 | @author: cghiaus 7 | """ 8 | import pandas as pd 9 | from dm4bem import read_epw 10 | 11 | # Inputs 12 | # ====== 13 | filename = './weather_data/FRA_Lyon.074810_IWEC.epw' 14 | 15 | θ = 18 # °C, indoor temperature all time 16 | θday = θ # °C, indoor temperature during day: 06:00 - 23:00 17 | θnight = 16 # °C, indoor temperature during night 23:00 - 06:00 18 | 19 | period_start = '2000-01-01' 20 | period_end = '2000-12-31' 21 | 22 | daytime_start = '06:00:00+01:00' 23 | daytime_end = '22:00:00+01:00' 24 | 25 | # Computation 26 | # =========== 27 | # read Energy Plus Weather data (file .EPW) 28 | [data, meta] = read_epw(filename, coerce_year=2000) 29 | 30 | # select outdoor air temperature; call it θout 31 | df = data[["temp_air"]] 32 | del data 33 | df = df.rename(columns={'temp_air': 'θout'}) 34 | 35 | # Select the data for a period of the year 36 | df = df.loc[period_start:period_end] 37 | 38 | # Compute degree-hours for fixed set-point 39 | # ---------------------------------------- 40 | df['Δθfix'] = θ - df['θout'].where(θ > df['θout'], θ) 41 | 42 | # Compute degree-hours for variable (day/night) set-point 43 | # ------------------------------------------------------- 44 | # Define start time for day and night 45 | day_start = pd.to_datetime(daytime_start).time() 46 | day_end = pd.to_datetime(daytime_end).time() 47 | 48 | # Daytime should be between 00:00 and 24:00 49 | # Daytime including midnight is not allowed, e.g., 22:00 till 06:00 50 | day = (df.index.time >= day_start) & (df.index.time <= day_end) 51 | night = ~day 52 | 53 | # Degree-hours for daytime 54 | df['Δθday'] = θday - df['θout'].where( 55 | (θday > df['θout']) & day, 56 | θday) 57 | 58 | # Degree-hours for nighttime 59 | df['Δθnight'] = θnight - df['θout'].where( 60 | (θnight > df['θout']) & night, 61 | θnight) 62 | 63 | # Sum of degree-hours for fix indoor temperature 64 | dh_fix = df['Δθfix'].sum() 65 | 66 | # Sum of degree-hours for intermitent heating 67 | dh_interm = df['Δθday'].sum() + df['Δθnight'].sum() 68 | 69 | # Results 70 | # ======= 71 | print(f"degree-hours fix set-point: {dh_fix:.1f}") 72 | print(f"degree-hours variable set-point: {dh_interm:.1f}") 73 | print(f"Estimated savings: {(dh_fix - dh_interm) / dh_interm * 100:.0f} %") 74 | -------------------------------------------------------------------------------- /pd/README.md: -------------------------------------------------------------------------------- 1 | # State-space models for building simulation by using Pandas [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/cmg-git/pd_dm4bem/HEAD) ## Work flow 1. `wall2TC`: Describe disassembled thermal networks: - Thermal network: A, G, C, b, f, y - files `wall_types` & `walls_data` -> thermal networks 2. `bldg_folder2TC`: Put all disassembled thermal circuit in disassebled thermal cirsuit TCd. 3. `assembly`: Assemble disassembled thermal networks. - Use two methods: assembling matrix and assembling lists 4. `TC2SS`: Thermal circuit -> state-space __To do:__ 5. `State-space with input` - Inputs: `bldg` folder and `weather` for a period of time - Outputs: state-space A, B, C, D and input u vector (in time) composed of: weather files and schedule files in the input vector. _To do_: input vector by considring to resample the inputs for the simulation time-step. 6. Numerical integration: explicit and/or implicit Euler ## Wall to disassembled thermal circuits Input files in `\bldg_data`: - type: material thermal properties and width of a type of building element - element: type, boundary conditions and surface - assembly: common nodes of elements Output: - thermal circuit of the building: TC = {A, G, C, b, f, y} Intermediary outputs: - thermal circuit TC = {A, G, C, b, f, y} of each component Contents of file ..._type.csv: Type: str same for different materials in the same element-type Material: str Conductivity: float of Material, W⋅K⁻¹ Specific heat: float of Material, J⋅kg⁻¹⋅K⁻¹ Density:float of Material, kg⋅m⁻³ Width: float of material, m Mesh: int number of meshes for layer discretization Contents of file ..._element.csv: Component: str name of the building component (wall, floor, window, etc.) Type: same as "Type" from file `..._type.csv` Area: float area surface of the wall, m² ho: float surface heat coefficient, surface 0, W⋅m⁻²⋅K⁻¹ hi: float surface heat coefficient, surface 1, W⋅m⁻²⋅K⁻¹ α0: float [0, 1] short-wave radiation absortivity, surface 0, - α1: float [0, 1] short-wave radiation absortivity, surface 1, - ε0: float [0, 1] long-wave radiation emmisivity, surface 0, - ε1: float [0, 1] long-wave radiation emmisivity, surface 1, - To: str name of the out temperature source; " " if no source Ti: str name of the in temperature source; " " if no source Qo: str name of the out flow source; " " if no source Qi: str name of the in flow source; " " if no source -------------------------------------------------------------------------------- /pd/inputs/step_input.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Wed Sep 20 11:32:24 2023 5 | 6 | @author: cghiaus 7 | 8 | Simulate the model from /dm4bem/03CubicBuilding.ipynb for step inputs 9 | 10 | Steps: 11 | - from /bldg -> disassambled TCd -> assembled TC -> state-space 12 | - create step inputs: To, Ti_sp, Φo, Φi, Qa, Φa 13 | - obtain input vector u = [TO, To, To, Ti_sp, Φo, Φi, Qa, Φa] 14 | - simulate ss-model for u 15 | """ 16 | import numpy as np 17 | import pandas as pd 18 | import pd_dm4bem 19 | 20 | # Obtain state-space representation 21 | # ================================= 22 | # Disassembled thermal circuits 23 | folder_path = "bldg" 24 | TCd = pd_dm4bem.bldg2TCd(folder_path, 25 | TC_auto_number=True) 26 | 27 | # Assembled thermal circuit using assembly_lists.csv' 28 | ass_lists = pd.read_csv(folder_path + '/assembly_lists.csv') 29 | ass_matrix = pd_dm4bem.assemble_lists2matrix(ass_lists) 30 | TC = pd_dm4bem.assemble_TCd_matrix(TCd, ass_matrix) 31 | 32 | # State-space 33 | [As, Bs, Cs, Ds, us] = pd_dm4bem.tc2ss(TC) 34 | 35 | # Obtain input vector in time 36 | # =========================== 37 | # Eigenvalue analysis 38 | λ = np.linalg.eig(As)[0] # eigenvalues of matrix As 39 | λ = np.sort(λ) 40 | 41 | print('Time constants:') 42 | print([f'{T:.2f} s' for T in -1 / λ]) 43 | 44 | dt_max = 2 * min(-1. / λ) 45 | print(f'\nMaximum time step: {dt_max:.2f} s = {dt_max / 60:.2f} min') 46 | 47 | t_settle = 4 * max(-1. / λ) 48 | print(f'Minimum settling time: \ 49 | {t_settle:.0f} s = \ 50 | {t_settle / 60:.1f} min = \ 51 | {t_settle / 3600:.2f} h = \ 52 | {t_settle / (3600 * 24):.2f} days') 53 | 54 | # time step 55 | dt = np.floor(dt_max / 60) * 60 # s 56 | print(f'dt = {dt} s = {dt / 60:.0f} min') 57 | 58 | # duration: next multiple of 3600 s that is larger than t_settle 59 | duration = np.ceil(t_settle / 3600) * 3600 60 | print(f'Duration = {duration} s') 61 | 62 | # Create input_data_set 63 | # --------------------- 64 | # time vector 65 | n = int(np.floor(duration / dt)) # number of time steps 66 | 67 | # Create a DateTimeIndex starting at "00:00:00" with a time step of dt 68 | time = pd.date_range(start="2000-01-01 00:00:00", 69 | periods=n, freq=f"{int(dt)}S") 70 | 71 | To = 10 * np.ones(n) 72 | Ti_sp = 20 * np.ones(n) 73 | Φa = 0 * np.ones(n) 74 | Qa = Φo = Φi = Φa 75 | 76 | data = {'To': To, 'Ti_sp': Ti_sp, 'Qa': Qa, 'Φo': Φo, 'Φi': Φi, 'Φa': Φa} 77 | input_data_set = pd.DataFrame(data, index=time) 78 | 79 | # Get input from input_data_set 80 | u = pd_dm4bem.inputs_in_time(us, input_data_set) 81 | 82 | # Simulation 83 | # ========== 84 | # Initial conditions 85 | θ0 = 0 # initial temperatures 86 | θ_exp = pd.DataFrame(index=u.index) 87 | θ_exp[As.columns] = θ0 # Fill θ with initial valeus θ0 88 | θ_imp = θ_exp 89 | 90 | I = np.eye(As.shape[0]) # identity matrix 91 | 92 | for k in range(n - 1): 93 | θ_exp.iloc[k + 1] = (I + dt * As)\ 94 | @ θ_exp.iloc[k] + dt * Bs @ u.iloc[k] 95 | θ_imp.iloc[k + 1] = np.linalg.inv(I - dt * As)\ 96 | @ (θ_imp.iloc[k] + dt * Bs @ u.iloc[k]) 97 | 98 | # outputs 99 | y_exp = (Cs @ θ_exp.T + Ds @ u.T).T 100 | y_imp = (Cs @ θ_imp.T + Ds @ u.T).T 101 | 102 | # Plot resukts 103 | y = pd.concat([y_exp, y_imp], axis=1, keys=['Explicit', 'Implicit']) 104 | # Flatten the two-level column labels into a single level 105 | y.columns = y.columns.get_level_values(0) 106 | y.plot() 107 | -------------------------------------------------------------------------------- /M/M/fTCAssAll.m: -------------------------------------------------------------------------------- 1 | function [TCa, Idx] = fTCAssAll(TCd, AssX) 2 | % Assembled circuit TCa from dissambled circuit TCd and assembling matrix Ass 3 | % 4 | % Inputs 5 | % TCd cell array of cell arrays of [A,G,b,C,f,y] of each TC 6 | % AssX assembly matrix: 4 elem/row = TC#node TC#node (2nd node collapse in 1st) 7 | % TCa cell array of [A,G,b,C,f,y] of assembled TC 8 | % Idx Idx{1}: nodes; Idx{2}: branches; 9 | % 1st row: local therm. circ.; 10 | % 2nd row: local indexes; 11 | % 3rd row: global indexes 12 | 13 | % Create assembing matrix Ass from AssX 14 | nf(1) = 0; 15 | nth = length(TCd{1}{5}); % no of temp nodes 16 | tcth = ones(1,nth); % index for nodes of thermal circ. 17 | nq = length(TCd{1}{3}); % no of flow branches 18 | tcq = ones(1,nq); % index for branches of thermal circ. 19 | gq(1) = length(TCd{1}{3}); 20 | gth(1) = length(TCd{1}{5}); 21 | for n = 2:size(TCd,2) 22 | nf(n) = nf(n-1) + length(TCd{n-1}{5}); % 23 | nth = nth + length(TCd{n}{5}); % total # nodes 24 | tcth = [tcth n*ones(1,length(TCd{n}{5}))]; % index for nodes of thermal circ. 25 | nq = nq + length(TCd{n}{3}); % total # branches 26 | tcq = [tcq n*ones(1,length(TCd{n}{3}))]; % index for branches of thermal circ. 27 | gq(n) = gq(n-1) + length(TCd{n}{3}); % global dissambled indexes q 28 | gth(n) = gth(n-1) + length(TCd{n}{5}); % global dissambled indexes th 29 | end 30 | gth = gq(end)+gth; % th counted after q 31 | 32 | % Assembly matrix 2 columns 1st <- 2nd: global dissembled temp idx 33 | Ass = [nf(AssX(:,1))'+AssX(:,2) nf(AssX(:,3))'+AssX(:,4)]; 34 | 35 | % Create dissembling matrix Ad (from Adth themperature + Adq flows) 36 | Adth = eye(nth); % a) create diagonal matrix 37 | for n = 1:size(Ass,1) % for each line of Ass 38 | % add 2 columns of Ass indicated by Ass 39 | Adth(:,Ass(n,1)) = Adth(:,Ass(n,1)) + Adth(:,Ass(n,2)); 40 | end 41 | Adth(:,Ass(:,2)) = []; % c) delete the columns corresponding to 2nd node in merging 42 | 43 | Adq = eye(nq); 44 | 45 | Adg = blkdiag(Adq, Adth); 46 | 47 | Ad = [Adg(1:gq(1),:); Adg(gq(end)+1:gth(1),:)]; % rearrange Ad 48 | for n = 2:size(TCd,2) 49 | Ad = [Ad;... 50 | Adg(gq(n-1)+1:gq(n),:); Adg(gth(n-1)+1:gth(n),:)]; 51 | end 52 | 53 | % Assemble circuits 54 | Kd = [inv(TCd{1}{2}) TCd{1}{1}; -TCd{1}{1}' TCd{1}{4}]; % Kd = [inv(G1) A1; -A1' C1] 55 | ubf = [TCd{1}{3}; TCd{1}{5}]; % ubf = [b1; f1] 56 | uby = [TCd{1}{3}; TCd{1}{6}]; % uby = [b1; y1] 57 | for n = 2:size(TCd,2) 58 | Kd = blkdiag(Kd,[inv(TCd{n}{2}) TCd{n}{1}; -TCd{n}{1}' TCd{n}{4}]); 59 | ubf = [ubf; TCd{n}{3}; TCd{n}{5}]; 60 | uby = [uby; TCd{n}{3}; TCd{n}{6}]; 61 | end 62 | 63 | Ka = Ad'*Kd*Ad; 64 | Ga = inv(Ka(1:nq,1:nq)); 65 | Aa = Ka(1:nq,nq+1:end); 66 | Ca = Ka(nq+1:end, nq+1:end); 67 | 68 | u = Ad'*ubf; % inputs 69 | ba = u(1:nq); 70 | fa = u(nq+1:end); 71 | fa = fa~=0; % % 1 <- values >=1 72 | u = Ad'*uby; %outputs 73 | ya = u(nq+1:end); 74 | ya = ya~=0; % 1 <- values >=1 75 | 76 | TCa = {Aa,Ga,ba,Ca,fa,ya}; % cell array of assembled TC 77 | 78 | % Find indexes local - global 79 | [i,j] = find(Adth); % global indexes: i -before assembling; j -after assembling 80 | thag = sortrows([i j],1); 81 | qag = 1:nq; 82 | 83 | thl = 1:length(TCd{1}{5}); % local index of temperatures 84 | ql = 1:length(TCd{1}{3}); % local indexes of flow 85 | for n = 2:size(TCd,2) 86 | thl = [thl 1:length(TCd{n}{5})]; 87 | ql = [ql 1:length(TCd{n}{3})]; 88 | end 89 | % temp 1st row: index of local therm. circ; 90 | % 2nd rox: local indexes; 3nd row global idx of assembled 91 | thidx = [tcth; thl; thag(:,2)']; 92 | % flow 1st row: index of local therm. circ; 93 | % 2nd row: local indexes; 3rd row global idx of assembled 94 | qidx = [tcq; ql; qag]; 95 | Idx = {thidx,qidx}; 96 | -------------------------------------------------------------------------------- /M/M/t02SimpleWall.m: -------------------------------------------------------------------------------- 1 | % Simple wall with capacities in all temperature nodes 2 | % Inputs: outdoor temperature, indoor convection heat flow rate (from HVAC)) 3 | clc, clear all 4 | 5 | % Physical properties 6 | % ******************* 7 | Sw = 3*3; %wall surface [m2] 8 | Va = 3*3*3; %air volume[m3] 9 | % 1: concrete ; 2: insulation ; 3: air 10 | lam1 = 1.4; lam2 = 0.04; %[W/m K] 11 | rho1c1 = 2.02e6; rho2c2 = 0.02e6; rho3c3 = 1.2e3; %[J/K m3] 12 | w1 = 0.2; w2 = 0.08; %[m] wall width 13 | x1 = 0.05; x2 = 0.04; %[m] discretizaton slice width 14 | % convection coefficents 15 | ho = 10; hi = 4; %[W/m2 K] 16 | % Thermal resistances 17 | % concrete 18 | Rc = w1/(lam1*Sw); Cc = Sw*w1*rho1c1; 19 | % insulation 20 | Ri = w2/(lam2*Sw); Ci = Sw*w2*rho2c2; 21 | % convection 22 | Rvi = 1/(hi*Sw); Rvo = 1/(ho*Sw); 23 | 24 | % Dynamic model 25 | %**************** 26 | % Thermal circuit 27 | nth = 7; nq = 7; % # of temperature node, # of flow nodes 28 | % resistances 29 | R = zeros(nq,nq); 30 | R(1,1) = Rvo + Rc/8; 31 | R(2,2) = Rc/4; R(3,3)=R(2,2); R(4,4)=R(2,2); 32 | R(5,5) = Rc/8 + Ri/4; 33 | R(6,6) = Ri/2; 34 | R(7,7) = Ri/4 + Rvi; 35 | G = inv(R); 36 | % capacitances 37 | C = zeros(nth,nth); 38 | C(1,1) = 1/4*Sw*w1*rho1c1; C(2,2)=C(1,1); C(3,3)=C(1,1); C(4,4)=C(1,1); 39 | C(5,5) = 1/2*Sw*w2*rho2c2; C(6,6)=C(5,5); 40 | C(7,7) = Va*rho3c3; 41 | % arc-node incidence matrix 42 | A = eye(nq+1,nth); 43 | A = -diff(A,1,1)'; 44 | 45 | b = [1 0 0 0 0 0 0]'; f = [0 0 0 0 0 0 0]'; 46 | thSteadyTo = inv(A'*G*A)*(A'*G*b + f) % steady-state temperature: input To = 1 47 | b = [0 0 0 0 0 0 0]'; f = [0 0 0 0 0 0 1]'; % idem, for Qh = 1 48 | thSteadyQh = inv(A'*G*A)*(A'*G*b + f) 49 | 50 | % State-space representation 51 | B = inv(C)*[A'*G eye(nth,nth)]; % inputs u = [b; f] size(b)=nq, size(f)=nth; 52 | B = B(:,[1 14]); % select the 2 relevant inputs: 1->To and 14->Qh 53 | A = inv(C)*(-A'*G*A); 54 | C = zeros(1,7);C(7)=1; % output: th(7) 55 | D = [0 0]; 56 | 57 | % Time integration using Euler forward 58 | % ************************************ 59 | % Step response 60 | disp(['max dt = ',num2str(min(-2./eig(A))),'[s]']) 61 | dt = 360 62 | n = 3600/dt*24*30; % no of time samples for 30 days 63 | n = floor(n); 64 | Time = 0:dt:(n-1)*dt; % time 65 | u = [ones(1,n); zeros(1,n)]; 66 | th = zeros(nth,n); thi = zeros(nth,n); 67 | for k = 1:n-1 68 | th(:,k+1) = (eye(nth) + dt*A)*th(:,k) + dt*B*u(:,k); 69 | thi(:,k+1) = inv((eye(nth) - dt*A))*(thi(:,k) + dt*B*u(:,k)); 70 | end 71 | subplot(2,2,1) 72 | plot(Time/3600,th(7,1:n),'r', Time/3600,thi(7,1:n),'b') 73 | xlabel('Time [hours]'), ylabel('T [C]') 74 | title('Step response for T_o = 1 C') 75 | 76 | u = [zeros(1,n); ones(1,n)]; 77 | for k = 1:n-1 78 | th(:,k+1) = (eye(nth) + dt*A)*th(:,k) + dt*B*u(:,k); 79 | thi(:,k+1) = inv((eye(nth) - dt*A))*(thi(:,k) + dt*B*u(:,k)); 80 | end 81 | subplot(2,2,2) 82 | plot(Time/3600,th(7,1:n),'r', Time/3600,thi(7,1:n),'b') 83 | xlabel('Time [h]'), ylabel('T [C]') 84 | title('Step response for Q_h = 1 W') 85 | 86 | % Simulation with outoor temperature 87 | % Load weather data 88 | fileName = 'FRA_Lyon.csv'; 89 | from = 6*30*24 + 25*24; % start time 90 | period = 30*24; % simulation period 91 | 92 | [Time,Temp,RadNDir,RadHDif,WDir,WSpeed,month,day,hour,minute]... 93 | = fReadWeather(fileName,from,period); 94 | 95 | b = 90; z = 0; l = 45; albedo = 0.2; 96 | [PhiDir, PhiDif, PhiRef] = fSolRadTiltSurf(month, day, hour, minute, ... 97 | RadNDir, RadHDif, b, z, l, albedo); 98 | 99 | Temp = interp1(Time, Temp, [Time(1):dt:Time(end)]'); %interpolate for dt 100 | Time = [Time(1):dt:Time(end)]'; 101 | 102 | n = size(Time,1); 103 | th = zeros(nth,n);thi = zeros(nth,n); 104 | Qh = zeros(n,1); 105 | u = [Temp'; Qh']; 106 | for k = 1:n-1 107 | th(:,k+1) = (eye(nth) + dt*A)*th(:,k) + dt*B*u(:,k); 108 | thi(:,k+1) = inv((eye(nth) - dt*A))*(thi(:,k) + dt*B*u(:,k)); 109 | end 110 | 111 | subplot(2,2,3) 112 | plot(Time/3600/24,th(7,1:n),'r', Time/3600/24, Temp,'b') 113 | xlabel('Time [days]'), ylabel('T [C]') 114 | title('Simulation explicit Euler') 115 | 116 | subplot(2,2,4) 117 | plot(Time/3600/24,thi(7,1:n),'r', Time/3600/24, Temp,'b') 118 | xlabel('Time [days]'), ylabel('T [C]') 119 | title('Simulation implicit Euler') -------------------------------------------------------------------------------- /py/09_nat_ventilation_1fig.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Fri Feb 24 08:45:51 2023 5 | 6 | @author: cghiaus 7 | 8 | Estimate the flow rate by ventilation 9 | 10 | References 11 | ASHARE Fundamentals (2009) Chapter 16 Ventilation and infiltration SI_F9_Ch16 12 | Solve one nonliear equation 13 | https://faculty.math.illinois.edu/~hirani/cbmg/nonlinear.html 14 | """ 15 | 16 | import matplotlib.pyplot as plt 17 | import numpy as np 18 | from scipy.optimize import fsolve 19 | 20 | # Data 21 | # standard acceleration due to gravity, m/s² 22 | g = 9.8 23 | # pressure exponent, dimensionless 24 | no, nc = 0.64, 0.50 # orrifice, cheminée 25 | # flow coefficients, m³/(s·Paⁿ) 26 | Ko, Kc = 10 / 3600, 50 / 3600 # orrifice, chimney 27 | # density, kg/m³ 28 | ρi, ρo = 1.191, 1.315 # indoor, outdoor 29 | # pressure coefficients, dimensioneless 30 | Cpn, Cps, Cpc = 0.4, -0.55, -0.7 # north, south, chimney 31 | # hignt, m 32 | z = 8 33 | 34 | # Static pressure, Pa 35 | Psi = -ρi * g * z # indoors 36 | Pso = -ρo * g * z # outdoors 37 | 38 | 39 | def f(pi): 40 | """ 41 | Error in mass balance equation as a function of indoor pressure. 42 | Used to find indoor pressure pi which makes the mass balance zero. 43 | The north and south flows are enteriing. 44 | 45 | Parameters 46 | ---------- 47 | pi : float 48 | Indoor pressure, Pa. 49 | 50 | Returns 51 | ------- 52 | y : float 53 | Mass flow rate unbalanced in the mass balance equation 54 | """ 55 | y = 2 * ρo * Ko * (Pdn - pi)**no \ 56 | + 2 * ρo * Ko * (Pds - pi)**no \ 57 | - ρi * Kc * (pi + Psi - Pdc - Pso)**nc 58 | return y 59 | 60 | 61 | # Without wind 62 | # ================================================ 63 | print('Without wind') 64 | v = 0 # m/s, wind speed 65 | 66 | # dynamic pressures, Pa 67 | Pdn = Cpn * 0.5 * ρo * v**2 # north face 68 | Pds = Cps * 0.5 * ρo * v**2 # south face 69 | Pdc = Cpc * 0.5 * ρo * v**2 # chimney 70 | 71 | pi_min, pi_max = -(Psi - Pdc - Pso), min(Pdn, Pds) 72 | print(f"Pressure domain: {pi_min:.2f} Pa < pi < {pi_max:.2f} Pa") 73 | 74 | # plot error in mass balance 75 | pi = np.linspace(pi_min, pi_max, 100) 76 | 77 | fig, ax = plt.subplots() 78 | 79 | without_wind, = ax.plot(pi, f(pi), 'b') 80 | ax.axvline(x=pi_min, color='b', **{'linestyle': 'dashed'}) 81 | ax.axvline(x=pi_max, color='b', **{'linestyle': 'dashed'}) 82 | 83 | # numerical solution 84 | root = float(fsolve(f, np.mean([pi_min, pi_max]))) 85 | print(f"pi = {root:.2f} Pa") 86 | 87 | # verification of mass balance, kg/s 88 | mn = ρo * Ko * (Pdn - root)**no 89 | ms = ρo * Ko * (Pds - root)**no 90 | mc = ρi * Kc * (root + Psi - Pdc - Pso)**nc 91 | print("Verify mass balance:") 92 | print(f"mass flow: north: {2 * mn:.2f} kg/s, south: {2 * ms:.2f} kg/s") 93 | print(f"mass flow chimney: {mc:.2f} kg/s") 94 | print(f"error in mass flow balance: {2 * mn + 2 * ms - mc:.2f} kg/s\n") 95 | 96 | # With wind 97 | # ================================================ 98 | print('With wind') 99 | v = 18 * 1000 / 3600 # m/s, wind speed 100 | 101 | # dynamic pressures, Pa 102 | Pdn = Cpn * 0.5 * ρo * v**2 # north face 103 | Pds = Cps * 0.5 * ρo * v**2 # south face 104 | Pdc = Cpc * 0.5 * ρo * v**2 # chimney 105 | 106 | pi_min, pi_max = -(Psi - Pdc - Pso), min(Pdn, Pds) 107 | print(f"Pressure domain with wind: {pi_min:.2f} Pa < pi < {pi_max:.2f} Pa") 108 | 109 | # plot error in mass balance 110 | pi = np.linspace(pi_min, pi_max, 100) 111 | 112 | with_wind, = ax.plot(pi, f(pi), 'g') 113 | ax.axhline(color='k') 114 | ax.axvline(x=pi_min, color='g', **{'linestyle': 'dashed'}) 115 | ax.axvline(x=pi_max, color='g', **{'linestyle': 'dashed'}) 116 | ax.set_ylabel(r'Error in mass balance $\dot{m}$ [kg/s]') 117 | ax.set_xlabel(r'Indoor pressure $p_i$ [Pa]') 118 | 119 | ax.axhline(color='k') 120 | ax.set_ylabel(r'Error in mass balance $\dot{m}$ [kg/s]') 121 | ax.set_xlabel(r'Indoor pressure $p_i$ [Pa]') 122 | ax.grid() 123 | ax.legend((without_wind, with_wind), ('Without wind', 'With wind')) 124 | # fig.tight_layout() 125 | 126 | # numerical solution 127 | root = float(fsolve(f, np.mean([pi_min, pi_max]))) 128 | print(f"pi = {root:.2f} Pa") 129 | 130 | mn = ρo * Ko * (Pdn - root)**no 131 | ms = ρo * Ko * (Pds - root)**no 132 | mc = ρi * Kc * (root + Psi - Pdc - Pso)**nc 133 | print("Verify mass balance:") 134 | print(f"mass flow: north: {2 * mn:.2f} kg/s, south: {2 * ms:.2f} kg/s") 135 | print(f"mass flow chimney: {mc:.2f} kg/s") 136 | print(f"error in mass flow balance: {2 * mn + 2 * ms - mc:.2f} kg/s\n") 137 | -------------------------------------------------------------------------------- /M/M/t02SimpleWall01.m: -------------------------------------------------------------------------------- 1 | % Simple wall with capacities in all temperature nodes 2 | % Inputs: outdoor temperature, indoor convection heat flow rate (from HVAC)) 3 | clc, clear all 4 | 5 | % Physical properties 6 | % ******************* 7 | Sw = 3*3; %wall surface [m2] 8 | Va = 3*3*3; %air volume[m3] 9 | % 1: concrete ; 2: insulation ; 3: air 10 | lam1 = 1.4; lam2 = 0.04; %[W/m K] 11 | rho1c1 = 2.02e6; rho2c2 = 0.02e6; rho3c3 = 1.2e3; %[J/K m3] 12 | w1 = 0.2; w2 = 0.08; %[m] wall width 13 | x1 = 0.05; x2 = 0.04; %[m] discretizaton slice width 14 | % convection coefficents 15 | ho = 10; hi = 4; %[W/m2 K] 16 | % Thermal resistances 17 | % concrete 18 | Rc = w1/(lam1*Sw); Cc = Sw*w1*rho1c1; 19 | % insulation 20 | Ri = w2/(lam2*Sw); Ci = Sw*w2*rho2c2; 21 | % convection 22 | Rvi = 1/(hi*Sw); Rvo = 1/(ho*Sw); 23 | 24 | % Dynamic model 25 | %**************** 26 | % Thermal circuit 27 | nth = 7; nq = 7; % # of temperature node, # of flow nodes 28 | % resistances 29 | R = zeros(nq,nq); 30 | R(1,1) = Rvo + Rc/8; 31 | R(2,2) = Rc/4; R(3,3)=R(2,2); R(4,4)=R(2,2); 32 | R(5,5) = Rc/8 + Ri/4; 33 | R(6,6) = Ri/2; 34 | R(7,7) = Ri/4 + Rvi; 35 | G = inv(R); 36 | % capacitances 37 | C = zeros(nth,nth); 38 | C(1,1) = 1/4*Sw*w1*rho1c1; C(2,2)=C(1,1); C(3,3)=C(1,1); C(4,4)=C(1,1); 39 | C(5,5) = 1/2*Sw*w2*rho2c2; C(6,6)=C(5,5); 40 | C(7,7) = Va*rho3c3; 41 | % arc-node incidence matrix 42 | A = eye(nq+1,nth); 43 | A = -diff(A,1,1)'; 44 | 45 | b = [1 0 0 0 0 0 0]'; f = [0 0 0 0 0 0 0]'; 46 | thSteadyTo = inv(A'*G*A)*(A'*G*b + f) % steady-state temperature: input To = 1 47 | b = [0 0 0 0 0 0 0]'; f = [0 0 0 0 0 0 1]'; % idem, for Qh = 1 48 | thSteadyQh = inv(A'*G*A)*(A'*G*b + f) 49 | 50 | % State-space representation 51 | B = inv(C)*[A'*G eye(nth,nth)]; % inputs u = [b; f] size(b)=nq, size(f)=nth; 52 | B = B(:,[1 14]); % select the 2 relevant inputs: 1->To and 14->Qh 53 | A = inv(C)*(-A'*G*A); 54 | C = zeros(1,7);C(7)=1; % output: th(7) 55 | D = [0 0]; 56 | 57 | % Time integration using Euler forward 58 | % ************************************ 59 | % Step response 60 | dh = 1.98; % if dh = 1.98, stable; if dh = 1.97, instable 61 | dt = 3600/dh; % simulation step 1h/dt = 3600s / dt] 62 | n = dh*24*30; % no of time samples for 30 days 63 | n = floor(n); 64 | Time = 0:dt:(n-1)*dt; % time 65 | th = zeros(nth,n); thi = zeros(nth,n); 66 | u = [ones(1,n); zeros(1,n)]; 67 | for k = 1:n-1 68 | th(:,k+1) = (eye(nth) + dt*A)*th(:,k) + dt*B*u(:,k); 69 | thi(:,k+1) = inv((eye(nth) - dt*A))*(thi(:,k) + dt*B*u(:,k)); 70 | end 71 | subplot(2,2,1) 72 | plot(Time/3600,th(7,1:n),'r', Time/3600,thi(7,1:n),'b') 73 | xlabel('Time [h]'), ylabel('T [C]') 74 | title('Step response for T_o = 1 C') 75 | 76 | u = [zeros(1,n); ones(1,n)]; 77 | for k = 1:n-1 78 | th(:,k+1) = (eye(nth) + dt*A)*th(:,k) + dt*B*u(:,k); 79 | thi(:,k+1) = inv((eye(nth) - dt*A))*(thi(:,k) + dt*B*u(:,k)); 80 | end 81 | subplot(2,2,2) 82 | plot(Time/3600,th(7,1:n),'r', Time/3600,thi(7,1:n),'b') 83 | xlabel('Time [h]'), ylabel('T [C]') 84 | title('Step response for Q_h = 1 W') 85 | 86 | %Stability 87 | lambda = eig(A); 88 | min(lambda)*dt; %needs to be in [-2 0] 89 | disp('Stability: min eigenvalue of A * dt in [-2 0]'), disp(min(min(lambda))*dt) 90 | disp('lam/(rho*c)/w^2 :') 91 | [(lam1/rho1c1)/(w1/4)^2*dt lam2/rho2c2/(w2/2)^2*dt] %needs to be <1/2 92 | 93 | % Simulation with outoor temperature 94 | % Load weather data 95 | fileName = 'FRA_Lyon.csv'; 96 | from = 6*30*24 + 25*24; % start time 97 | period = 30*24; % simulation period 98 | 99 | [Time,Temp,RadNDir,RadHDif,WDir,WSpeed,month,day,hour,minute]... 100 | = fReadWeather(fileName,from,period); 101 | 102 | b = 90; z = 0; l = 45; albedo = 0.2; 103 | [PhiDir, PhiDif, PhiRef] = fSolRadTiltSurf(month, day, hour, minute, ... 104 | RadNDir, RadHDif, b, z, l, albedo); 105 | 106 | Temp = interp1(Time, Temp, [Time(1):dt:Time(end)]'); %interpolate for dt 107 | Time = [Time(1):dt:Time(end)]'; 108 | 109 | n = size(Time,1); 110 | th = zeros(nth,n);thi = zeros(nth,n); 111 | Qh = zeros(n,1); 112 | u = [Temp'; Qh']; 113 | for k = 1:n-1 114 | th(:,k+1) = (eye(nth) + dt*A)*th(:,k) + dt*B*u(:,k); 115 | thi(:,k+1) = inv((eye(nth) - dt*A))*(thi(:,k) + dt*B*u(:,k)); 116 | end 117 | 118 | subplot(2,2,3) 119 | plot(Time/3600/24,th(7,1:n),'r', Time/3600/24, Temp,'b') 120 | xlabel('Time [days]'), ylabel('T [C]') 121 | title('Simulation explicit Euler') 122 | 123 | subplot(2,2,4) 124 | plot(Time/3600/24,thi(7,1:n),'r', Time/3600/24, Temp,'b') 125 | xlabel('Time [days]'), ylabel('T [C]') 126 | title('Simulation implicit Euler') 127 | 128 | disp('Mean temperatures In Out') 129 | disp([mean(th(7,:)) mean(Temp)]) -------------------------------------------------------------------------------- /pd/inputs/step_input_01.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Wed Sep 20 11:32:24 2023 5 | 6 | @author: cghiaus 7 | 8 | Simulate the model from /dm4bem/03CubicBuilding.ipynb for step inputs 9 | 10 | Steps: 11 | - from /bldg -> disassambled TCd -> assembled TC -> state-space 12 | - create step inputs: To, Ti_sp, Φo, Φi, Qa, Φa 13 | - obtain input vector u = [TO, To, To, Ti_sp, Φo, Φi, Qa, Φa] 14 | - simulate ss-model for u 15 | """ 16 | import numpy as np 17 | import pandas as pd 18 | import matplotlib.pyplot as plt 19 | import pd_dm4bem 20 | 21 | # Disassembled thermal circuits 22 | folder_path = "bldg" 23 | TCd = pd_dm4bem.bldg2TCd(folder_path, 24 | TC_auto_number=True) 25 | 26 | # Assembled thermal circuit using assembly_lists.csv' 27 | ass_lists = pd.read_csv(folder_path + '/assembly_lists.csv') 28 | ass_matrix = pd_dm4bem.assemble_lists2matrix(ass_lists) 29 | TC = pd_dm4bem.assemble_TCd_matrix(TCd, ass_matrix) 30 | 31 | # State-space 32 | [As, Bs, Cs, Ds, us] = pd_dm4bem.tc2ss(TC) 33 | 34 | # Eigenvalue analysis 35 | λ = np.linalg.eig(As)[0] # eigenvalues of matrix As 36 | λ = np.sort(λ) 37 | 38 | print('Time constants:') 39 | print([f'{T:.2f} s' for T in -1 / λ]) 40 | 41 | dt_max = 2 * min(-1. / λ) 42 | print(f'\nMaximum time step: {dt_max:.2f} s = {dt_max / 60:.2f} min') 43 | 44 | t_settle = 4 * max(-1. / λ) 45 | print(f'Minimum settling time: \ 46 | {t_settle:.0f} s = \ 47 | {t_settle / 60:.1f} min = \ 48 | {t_settle / 3600:.2f} h = \ 49 | {t_settle / (3600 * 24):.2f} days') 50 | 51 | # time step 52 | dt = np.floor(dt_max / 60) * 60 # s 53 | print(f'dt = {dt} s = {dt / 60:.0f} min') 54 | 55 | # duration: next multiple of 3600 s that is larger than t_settle 56 | duration = np.ceil(t_settle / 3600) * 3600 57 | print(f'Duration = {duration} s') 58 | 59 | # time vector 60 | n = int(np.floor(duration / dt)) # number of time steps 61 | 62 | # Create a DateTimeIndex starting at "00:00:00" with a time step of dt 63 | time = pd.date_range(start="2000-01-01 00:00:00", 64 | periods=n, freq=f"{int(dt)}S") 65 | 66 | # # Create the Pandas Series 'To' with constant values 67 | # To = pd.Series(10 * np.ones(n), index=time) 68 | # Ti_sp = pd.Series(20 * np.ones(n), index=time) 69 | # Φa = pd.Series(0 * np.ones(n), index=time) 70 | # Qa = Φo = Φi = Φa 71 | 72 | 73 | # # Create the DataFrame 'u' based on the 'us' Series 74 | # u = pd.DataFrame({col: globals()[us[col]] for col in us.index}) 75 | 76 | # # is achieving 77 | # # u = pd.DataFrame({'c1_q0': To, 'c2_q0': To, 'c3_q0': Ti_sp, 'ow0_q0': To, 78 | # # 'c1_θ0': Φa, 'c2_θ0': Qa, 'ow0_θ0': Φo, 'ow0_θ4': Φi}) 79 | # # from 80 | # # us = 81 | # # c1_q0 To 82 | # # c2_q0 To 83 | # # c3_q0 Ti_sp 84 | # # ow0_q0 To 85 | # # c1_θ0 Φa 86 | # # c2_θ0 Qa 87 | # # ow0_θ0 Φo 88 | # # ow0_θ4 Φi 89 | 90 | 91 | To = 10 * np.ones(n) 92 | Ti_sp = 20 * np.ones(n) 93 | Φa = 0 * np.ones(n) 94 | Qa = Φo = Φi = Φa 95 | 96 | data = {'To': To, 'Ti_sp': Ti_sp, 'Qa': Qa, 'Φo': Φo, 'Φi': Φi, 'Φa': Φa} 97 | u_set = pd.DataFrame(data, index=time) 98 | 99 | # # Construct the DataFrame 100 | # u1 = pd.DataFrame({'c1_q0': u_set['To'], 'c2_q0': u_set['To'], 101 | # 'c3_q0': u_set['Ti_sp'], 'ow0_q0': u_set['To'], 102 | # 'c1_θ0': u_set['Φa'], 'c2_θ0': u_set['Qa'], 103 | # 'ow0_θ0': u_set['Φo'], 'ow0_θ4': u_set['Φi']}) 104 | 105 | # u1 = pd.DataFrame({'c1_q0': u_set['To'], 'c2_q0': u_set['To']}) 106 | # u2 = pd.DataFrame({'c1_q0': u_set[us['c1_q0']], 'c2_q0': u_set['To']}) 107 | 108 | # u3 = pd.DataFrame({col: u_set[us[col]] for col in us.index}) 109 | 110 | u4 = pd_dm4bem.inputs_in_time(us, u_set) 111 | 112 | 113 | # u_list = [u_set[column] for column in u_set.columns] 114 | 115 | 116 | # # Time integration 117 | # # initial conditions 118 | # n_s = As.shape[0] # number of state variables 119 | # θ_exp = np.zeros([n_s, time.shape[0]]) # explicit Euler in time t 120 | # θ_imp = np.zeros([n_s, time.shape[0]]) # implicit Euler in time t 121 | 122 | # # time integration 123 | # I = np.eye(n_s) # identity matrix 124 | 125 | # for k in range(n - 1): 126 | # θ_exp[:, k + 1] = (I + dt * As) @ θ_exp[:, k]\ 127 | # + dt * Bs @ u.iloc[k, :] 128 | # θ_imp[:, k + 1] = np.linalg.inv(I - dt * As) @ (θ_imp[:, k]\ 129 | # + dt * Bs @ u.iloc[k, :]) 130 | # # outputs 131 | # y_exp = Cs @ θ_exp + Ds @ u.T 132 | # y_imp = Cs @ θ_imp + Ds @ u.T 133 | 134 | # fig, ax = plt.subplots() 135 | # ax.plot(time / 3600, y_exp.T, time / 3600, y_imp.T) 136 | # ax.set(xlabel='Time, $t$ / h', 137 | # ylabel='Temperatue, $θ_i$ / °C', 138 | # title='Step input: outdoor temperature $T_o$') 139 | # ax.legend(['Explicit', 'Implicit']) 140 | # ax.grid() 141 | # plt.show() 142 | -------------------------------------------------------------------------------- /py/09_nat_ventilation_2fig.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Fri Feb 24 08:45:51 2023 5 | 6 | @author: cghiaus 7 | 8 | Estimate the flow rate by ventilation 9 | 10 | References 11 | ASHARE Fundamentals (2009) Chapter 16 Ventilation and infiltration SI_F9_Ch16 12 | Solve one nonliear equation 13 | https://faculty.math.illinois.edu/~hirani/cbmg/nonlinear.html 14 | """ 15 | 16 | import matplotlib.pyplot as plt 17 | import numpy as np 18 | from scipy.optimize import fsolve 19 | 20 | # Data 21 | # standard acceleration due to gravity, m/s² 22 | g = 9.8 23 | # flow coefficients, m³/(s·Paⁿ) 24 | Ko, Kc = 10 / 3600, 50 / 3600 # orrifice, chimney 25 | # pressure exponent, dimensionless 26 | no, nc = 0.64, 0.50 # orrifice, cheminée 27 | # density, kg/m³ 28 | ρi, ρe = 1.191, 1.315 # indoor, outdoor 29 | # pressure coefficients, dimensioneless 30 | Cpn, Cps, Cpc = 0.4, -0.55, -0.7 # north, south, chimney 31 | # hignt, m 32 | z = 8 33 | 34 | # Static pressure, Pa 35 | Psi = -ρi * g * z # indoor 36 | Pso = -ρe * g * z # outdoor 37 | 38 | 39 | def f(Pi): 40 | """ 41 | Error in mass balance equation as a function of indoor pressure. 42 | Used to find indoor pressure Pi which makes the mass balance zero. 43 | The north and south flows are enteriing. 44 | 45 | Parameters 46 | ---------- 47 | Pi : float 48 | Indoor pressure, Pa. 49 | 50 | Returns 51 | ------- 52 | y : float 53 | Mass flow rate unbalance in the mass balance equation 54 | """ 55 | y = 2 * ρe * Ko * (Pdn - Pi)**no \ 56 | + 2 * ρe * Ko * (Pds - Pi)**no \ 57 | - ρi * Kc * (Pi + Psi - Pdc - Pso)**nc 58 | return y 59 | 60 | 61 | # Without wind 62 | # ================================================ 63 | print('Without wind') 64 | v = 0 # m/s, wind speed 65 | 66 | # dynamic pressures, Pa 67 | Pdn = Cpn * 0.5 * ρe * v**2 # north face 68 | Pds = Cps * 0.5 * ρe * v**2 # south face 69 | Pdc = Cpc * 0.5 * ρe * v**2 # chimney 70 | 71 | Pi_min, Pi_max = -(Psi - Pdc - Pso), min(Pdn, Pds) 72 | print(f"Pressure domain: {Pi_min:.2f} Pa < Pi < {Pi_max:.2f} Pa") 73 | 74 | # plot error in mass balance 75 | Pi = np.linspace(Pi_min, Pi_max, 100) 76 | 77 | fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2) 78 | ax1.axhline(color='k') 79 | ax1.axvline(x=Pi_min, color='r', **{'linestyle': 'dashed'}) 80 | ax1.axvline(x=Pi_max, color='r', **{'linestyle': 'dashed'}) 81 | ax1.set_ylabel(r'Error in mass balance $\dot{m}$ [kg/s]') 82 | ax1.set_xlabel(r'Indoor pressure $p_i$ [Pa]') 83 | ax1.grid() 84 | ax1.plot(Pi, f(Pi), 'blue') 85 | ax1.set_title('Without wind') 86 | 87 | # numerical solution 88 | root = float(fsolve(f, np.mean([Pi_min, Pi_max]))) 89 | print(f"Pi = {root:.2f} Pa") 90 | 91 | # verification of mass balance, kg/s 92 | mn = ρe * Ko * (Pdn - root)**no 93 | ms = ρe * Ko * (Pds - root)**no 94 | mc = ρi * Kc * (root + Psi - Pdc - Pso)**nc 95 | print("Verify mass balance:") 96 | print(f"mass flow: north: {2 * mn:.2f} kg/s, south: {2 * ms:.2f} kg/s") 97 | print(f"mass flow chimney: {mc:.2f} kg/s") 98 | print(f"error in mass flow balance: {2 * mn + 2 * ms - mc:.2f} kg/s\n") 99 | 100 | # With wind 101 | # ================================================ 102 | print('With wind') 103 | v = 18 * 1000 / 3600 # m/s, wind speed 104 | 105 | # dynamic pressures, Pa 106 | Pdn = Cpn * 0.5 * ρe * v**2 # north face 107 | Pds = Cps * 0.5 * ρe * v**2 # south face 108 | Pdc = Cpc * 0.5 * ρe * v**2 # chimney 109 | 110 | Pi_min, Pi_max = -(Psi - Pdc - Pso), min(Pdn, Pds) 111 | print(f"Pressure domain with wind: {Pi_min:.2f} Pa < Pi < {Pi_max:.2f} Pa") 112 | 113 | # plot error in mass balance 114 | Pi = np.linspace(Pi_min, Pi_max, 100) 115 | 116 | ax2.axhline(color='k') 117 | ax2.axvline(x=Pi_min, color='r', **{'linestyle': 'dashed'}) 118 | ax2.axvline(x=Pi_max, color='r', **{'linestyle': 'dashed'}) 119 | ax2.set_ylabel(r'Error in mass balance $\dot{m}$ [kg/s]') 120 | ax2.set_xlabel(r'Indoor pressure $p_i$ [Pa]') 121 | ax2.grid() 122 | ax2.plot(Pi, f(Pi), 'blue') 123 | ax2.set_title('With wind') 124 | 125 | # fig, ax = plt.subplots(nrows=1, ncols=1) 126 | # ax.plot(Pi, f(Pi), 'blue') 127 | # ax.legned('With wind') 128 | 129 | # ax.axhline(color='k') 130 | # ax.axvline(x=Pi_min, color='r', **{'linestyle': 'dashed'}) 131 | # ax.axvline(x=Pi_max, color='r', **{'linestyle': 'dashed'}) 132 | # ax.set_ylabel(r'Error in mass balance $\dot{m}$ [kg/s]') 133 | # ax.set_xlabel(r'Indoor pressure $p_i$ [Pa]') 134 | # ax.grid() 135 | 136 | # numerical solution 137 | root = float(fsolve(f, np.mean([Pi_min, Pi_max]))) 138 | print(f"Pi = {root:.2f} Pa") 139 | 140 | mn = ρe * Ko * (Pdn - root)**no 141 | ms = ρe * Ko * (Pds - root)**no 142 | mc = ρi * Kc * (root + Psi - Pdc - Pso)**nc 143 | print("Verify mass balance:") 144 | print(f"mass flow: north: {2 * mn:.2f} kg/s, south: {2 * ms:.2f} kg/s") 145 | print(f"mass flow chimney: {mc:.2f} kg/s") 146 | print(f"error in mass flow balance: {2 * mn + 2 * ms - mc:.2f} kg/s\n") 147 | 148 | fig.tight_layout() 149 | plt.savefig("Figure_1.svg") 150 | -------------------------------------------------------------------------------- /py/01WeatherData.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Sat Mar 11 17:56:05 2023 5 | 6 | @author: cghiaus 7 | 8 | This script imports various libraries and modules such as numpy, pandas, and 9 | matplotlib.pyplot. It then reads a file in EnergyPlus Weather Format (epw) 10 | containing weather data for Lyon, France. 11 | 12 | The script then selects three columns from the weather data, namely 13 | air temperature, direct radiation, and diffuse radiation, 14 | and replaces the year in the index with 2000. 15 | 16 | The script defines a start date and an end date and filters the weather data 17 | based on these dates. 18 | 19 | The script then creates three plots using the filtered weather data: 20 | - A line plot of outdoor air temperature over time. 21 | - A line plot of solar radiation (normal direct and horizontal diffuse) 22 | over time. 23 | - A line plot of solar radiation on a tilted surface over time, 24 | calculated using the filtered weather data and the slope, azimuth, 25 | and latitude of the surface. 26 | 27 | Finally, the script calculates the solar radiation on a tilted surface 28 | by computing the direct radiation, diffuse radiation, and reflected radiation. 29 | It then stores the calculated solar radiation as a new column 30 | in the filtered weather data. 31 | """ 32 | 33 | import numpy as np 34 | import pandas as pd 35 | import matplotlib.pyplot as plt 36 | 37 | from ..py.dm4bem import read_epw, sol_rad_tilt_surf 38 | 39 | filename = './weather_data/FRA_Lyon.074810_IWEC.epw' 40 | # filename = './weather_data/FRA_AR_Lyon-Bron.AP.074800_TMYx.2004-2018.epw' 41 | 42 | [data, meta] = read_epw(filename, coerce_year=None) 43 | 44 | # Extract the month and year from the DataFrame index with the format 'MM-YYYY' 45 | month_year = data.index.strftime('%m-%Y') 46 | 47 | # Create a set of unique month-year combinations 48 | unique_month_years = sorted(set(month_year)) 49 | 50 | # Create a DataFrame from the unique month-year combinations 51 | print(pd.DataFrame(unique_month_years, columns=['Month-Year'])) 52 | 53 | 54 | # select columns of interest 55 | weather_data = data[["temp_air", "dir_n_rad", "dif_h_rad"]] 56 | 57 | # replace year of the index with 2000 58 | weather_data.index = weather_data.index.map( 59 | lambda t: t.replace(year=2000)) 60 | 61 | # Define start and end dates 62 | start_date = '2000-06-29' 63 | end_date = '2000-07-02' 64 | 65 | # Filter the data based on the start and end dates 66 | weather_data = weather_data.loc[start_date:end_date] 67 | 68 | del data 69 | weather_data.head() 70 | 71 | # Plot outdoor air temperature 72 | weather_data['temp_air'].plot() 73 | plt.xlabel("Time") 74 | plt.ylabel("Dry-bulb air temperature (°C)") 75 | plt.legend([]) 76 | plt.show() 77 | 78 | # Plot solar radiation: normal direct and horizontal diffuse 79 | weather_data[['dir_n_rad', 'dif_h_rad']].plot() 80 | plt.xlabel("Time") 81 | plt.ylabel("Solar radiation (W/m²)") 82 | plt.legend(['$Φ_{direct}$', '$Φ_{diffuse}$']) 83 | plt.show() 84 | 85 | # Solar radiation on a tilted surface 86 | surface_orientation = {'slope': 90, # 90° is vertical; > 90° downward 87 | 'azimuth': 0, # 0° South, positive westward 88 | 'latitude': 45} # °, North Pole 90° positive 89 | albedo = 0.2 90 | 91 | rad_surf = sol_rad_tilt_surf( 92 | weather_data, surface_orientation, albedo) 93 | 94 | rad_surf.plot() 95 | plt.xlabel("Time") 96 | plt.ylabel("Solar radiation (W/m²)") 97 | plt.show() 98 | 99 | # Calculation of solar radiation on a tilted surface from weather data 100 | β = surface_orientation['slope'] 101 | γ = surface_orientation['azimuth'] 102 | ϕ = surface_orientation['latitude'] 103 | 104 | # Transform degrees in radians 105 | β = β * np.pi / 180 106 | γ = γ * np.pi / 180 107 | ϕ = ϕ * np.pi / 180 108 | 109 | n = weather_data.index.dayofyear 110 | 111 | declination_angle = 23.45 * np.sin(360 * (284 + n) / 365 * np.pi / 180) 112 | δ = declination_angle * np.pi / 180 113 | 114 | # Direct radiation 115 | hour = weather_data.index.hour 116 | minute = weather_data.index.minute + 60 117 | hour_angle = 15 * ((hour + minute / 60) - 12) # deg 118 | ω = hour_angle * np.pi / 180 # rad 119 | 120 | theta = np.sin(δ) * np.sin(ϕ) * np.cos(β) \ 121 | - np.sin(δ) * np.cos(ϕ) * np.sin(β) * np.cos(γ) \ 122 | + np.cos(δ) * np.cos(ϕ) * np.cos(β) * np.cos(ω) \ 123 | + np.cos(δ) * np.sin(ϕ) * np.sin(β) * np.cos(γ) * np.cos(ω) \ 124 | + np.cos(δ) * np.sin(β) * np.sin(γ) * np.sin(ω) 125 | 126 | theta = np.array(np.arccos(theta)) 127 | theta = np.minimum(theta, np.pi / 2) 128 | 129 | dir_rad = weather_data["dir_n_rad"] * np.cos(theta) 130 | dir_rad[dir_rad < 0] = 0 131 | 132 | # Diffuse radiation 133 | dif_rad = weather_data["dif_h_rad"] * (1 + np.cos(β)) / 2 134 | 135 | # Solar radiation reflected by the ground 136 | gamma = np.cos(δ) * np.cos(ϕ) * np.cos(ω) \ 137 | + np.sin(δ) * np.sin(ϕ) 138 | 139 | gamma = np.array(np.arcsin(gamma)) 140 | gamma[gamma < 1e-5] = 1e-5 141 | 142 | dir_h_rad = weather_data["dir_n_rad"] * np.sin(gamma) 143 | 144 | ref_rad = (dir_h_rad + weather_data["dif_h_rad"]) * albedo \ 145 | * (1 - np.cos(β) / 2) 146 | -------------------------------------------------------------------------------- /M/M/t03CubeFB.m: -------------------------------------------------------------------------------- 1 | % Cube with 2 walls and feed-back 2 | clc, clear all 3 | 4 | %Physical values 5 | %**************************** 6 | Kp = 1e5; %P-controller gain: large for precision 7 | Sc = 5*3*3; Si = Sc; Sg = 3*3; %surface [m2]: concrete, insulation, glass 8 | Va = 3*3*3; %air volume[m3] 9 | rhoa = 1.2; ca = 1000; %indoor air density; heat capacity 10 | Vpa = 1*Va/3600; %infiltration and ventilation air: volume/hour 11 | 12 | % c: concrete; i: insulation; g: glass 13 | lamc = 2; lami = 0.04; lamg = 1.2; %[W/m K] 14 | rhoccc = 2.5e6; rhoici = 0.02e6; rhogcg = 2.0e6; %[J/m3 K] 15 | wc = 0.2; wi = 0.08; wg = 0.01; %[m] 16 | epswLW = 0.9; %long wave wall emmisivity 17 | epswSW = 0.5; %short wave wall emmisivity 18 | 19 | epsgLW = 0.6; %long wave glass emmisivity 20 | taugSW = 0.7; %short wave glass transmitance 21 | alphagSW = 0.1; %short wave glass absortivity 22 | 23 | sigma = 5.67e-8;%[W/m2 K4] 24 | Fwg = 1/5; %view factor wall - glass 25 | Tm = 20 + 273; %mean temp for radiative exchange 26 | 27 | % convection coefficients 28 | ho = 10; hi = 4; %[W/m2 K] 29 | %*************************** 30 | 31 | % Conductances and capacities 32 | Gc = lamc/wc*Sc; Cc = Sc*wc*rhoccc; %concrete 33 | Gi = lami/wi*Si; Ci = Si*wi*rhoici; %insulation 34 | Gg = lamg/wg*Sg; Cg = Sg*wg*rhogcg; %glass 35 | Ca = Va*rhoa*ca; 36 | % Convection 37 | Gwo = ho*Sc; Gwi = hi*Si; %convection wall out; wall in 38 | Ggo = ho*Sg; Ggi = hi*Sg; %convection glass out; glass in 39 | % Long wave radiative exchange 40 | GLW1 = epswLW/(1-epswLW)*Si*4*sigma*Tm^3; 41 | GLW2 = Fwg*Si*4*sigma*Tm^3; 42 | GLW3 = epsgLW/(1-epsgLW)*Sg*4*sigma*Tm^3; 43 | GLW = 1/(1/GLW1 + 1/GLW2 +1/GLW3); %long-wave exg. wall-glass 44 | % ventilation & advection 45 | Gv = Vpa*rhoa*ca; %air ventilation 46 | % glass: convection outdoor & conduction 47 | Ggs = 1/(1/Ggo + 1/(2*Gg)); %cv+cd glass 48 | 49 | % Thermal network 50 | % ***************************************************************** 51 | A(1,1) = 1; 52 | A(2,1) = -1; A(2,2) = 1; 53 | A(3,2) = -1; A(3,3) = 1; 54 | A(4,3) = -1; A(4,4) = 1; 55 | A(5,4) = -1; A(5,5) = 1; 56 | A(6,5) = -1; A(6,6) = 1; 57 | A(7,5) = -1; A(7,7) = 1; 58 | A(8,6) = -1; A(8,7) = 1; 59 | A(9,8) = 1; 60 | A(10,6) = 1; A(10,8) = -1; 61 | A(11,7) = 1; 62 | A(12,7) = 1; 63 | 64 | G = diag([Gwo 2*Gc 2*Gc 2*Gi 2*Gi GLW Gwi Ggi Ggs 2*Gg Gv Kp]'); 65 | b = zeros(12,1); b(1) = 1; b(9) = 1; b(11) = 1; b(12) = 1; 66 | C = diag([0 Cc 0 Ci 0 0 Ca Cg]); 67 | C = diag([0 Cc 0 Ci 0 0 0 0]); 68 | f = zeros(8,1); f(1) = 1; f(5) = 1; f(7) = 1; f(8) = 1; 69 | y = zeros(8,1); 70 | y(7) = 1; 71 | 72 | % Thermal circuit -> state-space 73 | % ********************************************************************* 74 | [As,Bs,Cs,Ds] = fTC2SS(A,G,b,C,f,y); 75 | 76 | % Maximum time-step 77 | dtmax = min(-2./eig(As))% [s] 78 | dt = 5 % [s] time step 79 | 80 | % Step response 81 | % ********************************************************************* 82 | duration = 3600*24*3; % [s] time duration 83 | n = floor(duration/dt); % no of time samples 84 | 85 | Time = 0:dt:(n-1)*dt; % time 86 | nth = size(As,1); % no of state variables 87 | th = zeros(nth,n); % zero initial conditions 88 | u = zeros(8,n); % u = [To To To Tsp Phio Phii Qaux Phia] 89 | u(1:3,:) = ones(3,n); % To = step variation 90 | 91 | for k = 1:n-1 92 | th(:,k+1) = (eye(nth) + dt*As)*th(:,k) + dt*Bs*u(:,k); 93 | end 94 | y = Cs*th + Ds*u; 95 | subplot(3,1,1) 96 | plot(Time/3600,y) 97 | xlabel('Time [h]'),ylabel('T [C]') 98 | title('Step response for T_o = 1 C'), 99 | 100 | % Simulation with weather data 101 | % Load weather data 102 | fileName = 'FRA_Lyon.csv'; 103 | from = 6*30*24 + 25*24; % start time: from 24 Jan. 104 | period = 10*24; % simulatio, period: for 10 days 105 | 106 | [Time,Temp,RadNDir,RadHDif,WDir,WSpeed,month,day,hour,minute]... 107 | = fReadWeather(fileName,from,period); 108 | 109 | B = 90; Z = 0; L = 45; albedo = 0.2; 110 | [PhiDir, PhiDif, PhiRef] = fSolRadTiltSurf(month, day, hour, minute, ... 111 | RadNDir, RadHDif, B, Z, L, albedo); 112 | 113 | % interpolate weather data for time step dt 114 | Temp = interp1(Time, Temp, [Time(1):dt:Time(end)]'); 115 | PhiDir = interp1(Time, PhiDir, [Time(1):dt:Time(end)]'); 116 | PhiDif = interp1(Time, PhiDif, [Time(1):dt:Time(end)]'); 117 | PhiRef = interp1(Time, PhiRef, [Time(1):dt:Time(end)]'); 118 | Time = [Time(1):dt:Time(end)]'; 119 | 120 | n = size(Time,1); 121 | th = zeros(nth,n); 122 | Qa = zeros(n,1); %auxiliary sources (electrical, persons, etc.) 123 | TintSP = 20*ones(n,1); 124 | 125 | % Inputs 126 | PhiTot = PhiDir + PhiDif + PhiRef; 127 | u = [Temp Temp Temp TintSP ... 128 | epswSW*Sc*PhiTot taugSW*epswSW*Sg*PhiTot Qa alphagSW*Sg*PhiTot]'; 129 | % Memory alocation and initial value 130 | th = zeros(size(As,2),n); 131 | 132 | for k = 1:n-1 133 | th(:,k+1) = (eye(nth) + dt*As)*th(:,k) + dt*Bs*u(:,k); 134 | end 135 | y = Cs*th + Ds*u; 136 | subplot(3,1,2) 137 | plot(Time/3600,y,'b',Time/3600,Temp,'g') 138 | xlabel('Time [h]'),ylabel('T [C]') 139 | title('Simulation for weather') 140 | 141 | % Solar radiation 142 | subplot(3,1,3) 143 | plot(Time/(24*3600), PhiDir,'b'), hold on %direct on surface 144 | plot(Time/(24*3600), PhiDif,'r') % diffusif on surface 145 | plot(Time/(24*3600), PhiRef,'m') % reflected on surface 146 | xlabel('Time [days]'), ylabel('\Phi [W/m^2]') 147 | legend('\Phi_d_i_r','\Phi_D_i_f', '\Phi_R_e_f_D_i_f') 148 | title('Solar radiation') -------------------------------------------------------------------------------- /M/M/t04CubeFBmesh.m: -------------------------------------------------------------------------------- 1 | % Cube with 2 walls and feed-back: variable mesh grid 2 | clc, clear all 3 | 4 | % Input data 5 | %**************************** 6 | % Parameters 7 | Kp = 1e4; % P-controller gain: large for precision 8 | nc = 3; % number of concrete meshes 9 | ni = 1; % number of insulation meshes 10 | dt = 3.600 % [s] simulation time step 11 | dt = 6.4 12 | 13 | % nc = 15 14 | % ni = 15 15 | % dt = 6 16 | 17 | % Physical values 18 | Sc = 5*3*3; Si = Sc; Sg = 3*3; %surface [m2]: concrete, insulation, glass 19 | Va = 3*3*3; %air volume[m3] 20 | rhoa = 1.2; ca = 1000; %indoor air density; heat capacity 21 | Vpa = 2*Va/3600; %infiltration and ventilation air: volume/hour 22 | 23 | % c: concrete; i: insulation; g: glass 24 | lamc = 2; lami = 0.04; lamg = 1.2; %[W/m K] 25 | rhoccc = 2.5e6; rhoici = 0.02e6; rhogcg = 2.0e6; %[J/m3 K] 26 | wc = 0.2; wi = 0.08; wg = 0.01; %[m] 27 | epswLW = 0.9; %long wave wall emmisivity 28 | epswSW = 0.8; %short wave wall emmisivity 29 | 30 | epsgLW = 0.9; %long wave glass emmisivity 31 | taugSW = 0.8; %short wave glass transmitance 32 | alphagSW = 0.2; %short wave glass absortivity 33 | 34 | sigma = 5.67e-8;%[W/m2 K4] 35 | Fwg = 1/5; %view factor wall - glass 36 | Tm = 20 + 273; %mean temp for radiative exchange 37 | 38 | % convection coefficients 39 | hi = 4; ho = 10; %[W/m2 K] 40 | %*************************** 41 | 42 | % Conductances and capacities 43 | Gc = lamc/wc*Sc; Cc = Sc*wc*rhoccc; %concrete 44 | Gcm = 2*nc*Gc*ones(1,2*nc); %meshed concrete 45 | Ccm = Cc/nc*mod(0:2*nc-1,2); 46 | 47 | Gi = lami/wi*Si; Ci = Si*wi*rhoici; %insulation 48 | Gim = 2*ni*Gi*ones(1,2*ni); %meshed insulation 49 | Cim = Ci/ni*mod(0:2*ni-1,2); 50 | 51 | Gg = lamg/wg*Sg; Cg = Sg*wg*rhogcg; %glass 52 | Ca = Va*rhoa*ca; 53 | % Convection 54 | Gwo = ho*Sc; Gwi = hi*Si; %convection wall out; wall in 55 | Ggo = ho*Sg; Ggi = hi*Sg; %convection glass out; glass in 56 | % Long wave radiative exchange 57 | GLW1 = epswLW/(1-epswLW)*Si*4*sigma*Tm^3; 58 | GLW2 = Fwg*Si*4*sigma*Tm^3; 59 | GLW3 = epsgLW/(1-epsgLW)*Sg*4*sigma*Tm^3; 60 | GLW = 1/(1/GLW1 + 1/GLW2 +1/GLW3); %long-wave exg. wall-glass 61 | % advection 62 | Gv = Vpa*rhoa*ca; %air ventilation 63 | % glass: convection outdoor & conduction 64 | Ggs = 1/(1/Ggo + 1/(2*Gg)); %cv+cd glass 65 | 66 | % Thermal network 67 | % ***************************************************************** 68 | nq = 2*(nc+ni); nt = 2*(nc+ni); % no of flows & temps 69 | A = eye(nq+1,nt); % (#flows+1, #temp) 70 | A = -diff(A,1,1)'; 71 | 72 | A(nq+1,nt) = -1; A(nq+1,nt+1) = 1; 73 | A(nq+2,nt+1) = -1; A(nq+2,nt+2) = 1; 74 | A(nq+3,nt+1) = -1; A(nq+3,nt+3) = 1; 75 | A(nq+4,nt+2) = -1; A(nq+4,nt+3) = 1; 76 | A(nq+5,nt+4) = 1; 77 | A(nq+6,nt+2) = 1; A(nq+6,nt+4) = -1; 78 | A(nq+7,nt+3) = 1; 79 | A(nq+8,nt+3) = 1; 80 | 81 | G = diag([Gwo Gcm Gim GLW Gwi Ggi Ggs 2*Gg Gv Kp]'); 82 | b = zeros(8+nq,1); 83 | b(1) = 1; b(5+nq) = 1; b(7+nq) = 1; b(8+nq) = 1; 84 | 85 | C = diag([Ccm Cim 0 0 Ca Cg]); 86 | % C = diag([Ccm Cim 0 0 0 0]); 87 | f = zeros(4+nt,1); 88 | f(1) = 1; f(1+nt) = 1; f(3+nt) = 1; f(4+nt) = 1; 89 | y = zeros(4+nt,1); %y(1:5) = ones(1,5); 90 | y(3+nt) = 1; 91 | 92 | % Thermal model -> state-space 93 | % ********************************************************************* 94 | [As,Bs,Cs,Ds] = fTC2SS(A,G,b,C,f,y); 95 | 96 | % Maximum time-step 97 | dtmax = min(-2./eig(As))% [s] 98 | 99 | % Step response 100 | % ********************************************************************* 101 | duration = 3600*24*3; % [s] time duration 102 | n = floor(duration/dt); % no of time samples 103 | 104 | Time = 0:dt:(n-1)*dt; % time 105 | nth = size(As,1); % no of state variables 106 | th = zeros(nth,n); % zero initial conditions 107 | u = zeros(8,n); % u = [To To To Tsp Phio Phii Qaux Phia] 108 | u(1:3,:) = ones(3,n); % To = step variation 109 | 110 | for k = 1:n-1 111 | th(:,k+1) = (eye(nth) + dt*As)*th(:,k) + dt*Bs*u(:,k); 112 | end 113 | y = Cs*th + Ds*u; 114 | subplot(3,1,1) 115 | plot(Time/3600,y) 116 | xlabel('Time [h]'),ylabel('T [C]') 117 | title('Step response for T_o = 1 C'), 118 | 119 | % Simulation with weather data 120 | % Load weather data 121 | fileName = 'FRA_Lyon.csv'; 122 | from = 6*30*24 + 25*24; % start time: from 24 Jan. 123 | period = 10*24; % simulatio, period: for 10 days 124 | 125 | [Time,Temp,RadNDir,RadHDif,WDir,WSpeed,month,day,hour,minute]... 126 | = fReadWeather(fileName,from,period); 127 | 128 | B = 90; Z = 0; L = 45; albedo = 0.2; 129 | [PhiDir, PhiDif, PhiRef] = fSolRadTiltSurf(month, day, hour, minute, ... 130 | RadNDir, RadHDif, B, Z, L, albedo); 131 | 132 | % interpolate weather data for time step dt 133 | Temp = interp1(Time, Temp, [Time(1):dt:Time(end)]'); 134 | PhiDir = interp1(Time, PhiDir, [Time(1):dt:Time(end)]'); 135 | PhiDif = interp1(Time, PhiDif, [Time(1):dt:Time(end)]'); 136 | PhiRef = interp1(Time, PhiRef, [Time(1):dt:Time(end)]'); 137 | Time = [Time(1):dt:Time(end)]'; 138 | 139 | n = size(Time,1); 140 | th = zeros(nth,n); 141 | Qa = zeros(n,1); %auxiliary sources (electrical, persons, etc.) 142 | TintSP = 20*ones(n,1); 143 | 144 | % Inputs 145 | PhiTot = PhiDir + PhiDif + PhiRef; 146 | u = [Temp Temp Temp TintSP ... 147 | epswSW*Sc*PhiTot taugSW*epswSW*Sg*PhiTot alphagSW*Sg*PhiTot ... 148 | Qa]'; 149 | % Memory alocation and initial value 150 | th = zeros(size(As,2),n); 151 | 152 | for k = 1:n-1 153 | th(:,k+1) = (eye(nth) + dt*As)*th(:,k) + dt*Bs*u(:,k); 154 | end 155 | y = Cs*th + Ds*u; 156 | subplot(3,1,2) 157 | plot(Time/3600,y,Time/3600,Temp) 158 | xlabel('Time [h]'),ylabel('T [C]') 159 | title('Simulation for weather') 160 | 161 | % Solar radiation 162 | subplot(3,1,3) 163 | plot(Time/(24*3600), PhiDir,'b'), hold on %direct on surface 164 | plot(Time/(24*3600), PhiDif,'r') % diffusif on surface 165 | plot(Time/(24*3600), PhiRef,'m') % reflected on surface 166 | xlabel('Time [days]'), ylabel('\Phi [W/m^2]') 167 | title('Solar radiation') 168 | legend('\Phi_d_i_r','\Phi_D_i_f', '\Phi_R_e_f_D_i_f') -------------------------------------------------------------------------------- /M/M/t07ControlHeat.m: -------------------------------------------------------------------------------- 1 | % Cube with 2 walls: assembly 2 | clc, clear all 3 | 4 | % Input data 5 | %**************************** 6 | % Parameters 7 | Kp = 1e1; % P-controller gain: large for precision 8 | nc = 4; % number of concrete meshes 9 | ni = 3; % number of insulation meshes 10 | dt = 5 % [s] simulation time step 11 | 12 | % Physical values 13 | Sc = 5*3*3; Si = Sc; % surface : concrete, insulation [m2] 14 | Sg = 3*3; % surface glass 15 | Va = 3*3*3; % air volume [m3] 16 | rhoa = 1.2; ca = 1000; % indoor air density; heat capacity 17 | ACH = 3; % air changes per hour 18 | Vda = ACH*Va/3600; % infiltration and ventilation air: volume/hour 19 | 20 | % c: concrete; i: insulation; g: glass 21 | lamc = 2; lami = 0.04; lamg = 1.2; % conductivity [W/m K] 22 | rhoccc = 2.5e6; rhoici = 2.0e6; rhogcg = 2.0e6; % [J/m3 K] 23 | wc = 0.2; wi = 0.08; wg = 0.01; % width [m] 24 | epswLW = 0.8; % long wave wall emmisivity 25 | epswSW = 0.8; % short wave wall emmisivity 26 | 27 | epsgLW = 0.9; % long wave glass emmisivity 28 | taugSW = 0.7; % short wave glass transmitance 29 | alphagSW = 0.2; % short wave glass absortivity 30 | 31 | sigma = 5.67e-8;% [W/m2 K4] 32 | Fwg = 1/5; % view factor wall - glass 33 | Tm = 20 + 273; % mean temp for radiative exchange 34 | 35 | 36 | hi = 4; ho = 10;% convection coefficients [W/m2 K] 37 | %*************************** 38 | 39 | % Conductances and capacities 40 | Gc = lamc/wc*Sc; Cs = Sc*wc*rhoccc; % concrete 41 | Gcm = 2*nc*Gc*ones(1,2*nc); % meshed concrete 42 | Ccm = Cs/nc*mod(0:2*nc-1,2); 43 | 44 | Gi = lami/wi*Si; Ci = Si*wi*rhoici; % insulation 45 | Gim = 2*ni*Gi*ones(1,2*ni); % meshed insulation 46 | Cim = Ci/ni*mod(0:2*ni-1,2); 47 | 48 | Gg = lamg/wg*Sg; Cg = Sg*wg*rhogcg; %glass 49 | Ca = Va*rhoa*ca; 50 | % Ca =0; Cg = 0; % if air and glass are neglected 51 | 52 | % Convection 53 | Gwo = ho*Sc; Gwi = hi*Si; %convection wall out; wall in 54 | Ggo = ho*Sg; Ggi = hi*Sg; %convection glass out; glass in 55 | % Long wave radiative exchange 56 | GLW1 = epswLW/(1-epswLW)*Si*4*sigma*Tm^3; 57 | GLW2 = Fwg*Si*4*sigma*Tm^3; 58 | GLW3 = epsgLW/(1-epsgLW)*Sg*4*sigma*Tm^3; 59 | GLW = 1/(1/GLW1 + 1/GLW2 +1/GLW3); %long-wave exg. wall-glass 60 | % advection 61 | Gv = Vda*rhoa*ca; %air ventilation 62 | % glass: convection outdoor & conduction 63 | Ggs = 1/(1/Ggo + 1/(2*Gg)); %cv+cd glass 64 | 65 | 66 | % Thermal network 67 | % ***************************************************************** 68 | % Dissembled circuit 69 | nq = 1+2*(nc+ni); nt = 1+2*(nc+ni); % no of flows & temps 70 | A1 = eye(nq+1,nt); % (#flows+1, #temp) 71 | A1 = -diff(A1,1,1)'; 72 | G1 = diag([Gwo Gcm Gim]'); 73 | b1 = zeros(nq,1); b1(1) = 1; 74 | C1 = diag([Ccm Cim 0]); 75 | f1 = zeros(nt,1); f1(1) = 1; f1(end) = 1; 76 | y1 = zeros(nt,1); 77 | TCd{1} = {A1,G1,b1,C1,f1,y1}; 78 | 79 | A2 = [-1 1 0; -1 0 1; 0 -1 1]; 80 | G2 = diag([GLW Gwi Ggi]'); 81 | b2 = [0 0 0]'; 82 | C2 = diag([0 0 Ca/2]'); 83 | f2 = [1 0 1]'; 84 | y2 = [0 0 1]'; 85 | TCd{2} = {A2,G2,b2,C2,f2,y2}; 86 | 87 | A3 = [1 0;-1 1]; 88 | G3 = diag([Ggs 2*Gg]); 89 | b3 = [1 0]'; 90 | C3 = diag([Cg 0]); 91 | f3 = [1 0]'; 92 | y3 = [0 0]'; 93 | TCd{3} = {A3,G3,b3,C3,f3,y3}; 94 | 95 | A4(1,1) = 1; 96 | A4(2,1) = 1; 97 | G4 = diag([Gv Kp]); 98 | b4 = [1 1]'; 99 | C4 = diag([Ca/2]); 100 | f4 = 1; 101 | y4 = 1; 102 | TCd{4} = {A4,G4,b4,C4,f4,y4}; 103 | 104 | % Assembling matrix 105 | AssX = [1 nt 2 1;...% TC1#5 <- TC2#1 106 | 2 2 3 2;... % TC2#2 <- TC3#2 107 | 2 3 4 1]; % TC2#3 <- TC4#1 108 | 109 | % Call Assembling function 110 | [TCa, Idx] = fTCAssAll(TCd, AssX); 111 | A = TCa{1}; G = TCa{2}; b = TCa{3}; C = TCa{4}; f = TCa{5}; y = TCa{6}; 112 | 113 | % Thermal model -> state-space 114 | % ********************************************************************* 115 | [As,Bs,Cs,Ds] = fTC2SS(A,G,b,C,f,y); % model with controller 116 | 117 | % Maximum time-step 118 | dtmax = min(-2./eig(As))% [s] 119 | 120 | % Simulation 121 | % ********************************************************************* 122 | % Load weather data 123 | fileName = 'FRA_Lyon.csv'; 124 | from = 1*30*24 + 25*24; % start time: from 24 Jan. 125 | period = 10*24; % simulation period: for 10 days 126 | 127 | [Time,Temp,RadNDir,RadHDif,WDir,WSpeed,month,day,hour,minute]... 128 | = fReadWeather(fileName,from,period); 129 | 130 | B = 90; Z = 0; L = 45; albedo = 0.2; 131 | [PhiDir, PhiDif, PhiRef] = fSolRadTiltSurf(month, day, hour, minute, ... 132 | RadNDir, RadHDif, B, Z, L, albedo); 133 | 134 | % interpolate weather data for time step dt 135 | Temp = interp1(Time, Temp, [Time(1):dt:Time(end)]'); 136 | PhiDir = interp1(Time, PhiDir, [Time(1):dt:Time(end)]'); 137 | PhiDif = interp1(Time, PhiDif, [Time(1):dt:Time(end)]'); 138 | PhiRef = interp1(Time, PhiRef, [Time(1):dt:Time(end)]'); 139 | Time = [Time(1):dt:Time(end)]'; 140 | 141 | n = size(Time,1); 142 | nth = size(As,1); % no of state variables 143 | Qa = zeros(n,1); %auxiliary sources (electrical, persons, etc.) 144 | TintSP = 20*ones(n,1); 145 | 146 | % Inputs 147 | PhiTot = PhiDir + PhiDif + PhiRef; 148 | u = [Temp Temp Temp TintSP/2 ... 149 | epswSW*Sc*PhiTot taugSW*epswSW*Sg*PhiTot alphagSW*Sg*PhiTot ... 150 | Qa]'; 151 | % Memory alocation and initial value 152 | % th = 20*ones(size(Ac,2),n); 153 | th = zeros(size(As,2),n); 154 | y = zeros(1,n); y(1) = TintSP(1); 155 | qHVAC = zeros(1,n); 156 | 157 | for k = 1:n-1 158 | if y(k) < TintSP(k) 159 | u(8,k) = 10000*(TintSP(k) - y(k)); 160 | th(:,k+1) = (eye(nth) + dt*As)*th(:,k) + dt*Bs*u(:,k); 161 | y(:,k+1) = Cs*th(:,k+1) + Ds*u(:,k+1); 162 | %qHVAC(:,k+1) = Kp*(TintSP(k+1) - y(k+1)); 163 | else 164 | u(8,k) = 0; 165 | th(:,k+1) = (eye(nth) + dt*As)*th(:,k) + dt*Bs*u(:,k); 166 | y(:,k+1) = Cs*th(:,k+1) + Ds*u(:,k+1); 167 | end 168 | end 169 | subplot(3,1,1) 170 | plot(Time/3600,y,'g',Time/3600,TintSP,'r', Time/3600,Temp,'b') 171 | xlabel('Time [h]'),ylabel('T [C]') 172 | title('Simulation for weather') 173 | 174 | subplot(3,1,2) 175 | plot(Time/3600,u(8,:)) 176 | xlabel('Time [h]'),ylabel('Q_h [W]') 177 | title('Q_h') 178 | axis([0 inf -1000 1e3]) 179 | 180 | % Solar radiation 181 | subplot(3,1,3) 182 | plot(Time/(24*3600), PhiDir,'b'), hold on %direct on surface 183 | plot(Time/(24*3600), PhiDif,'r') % diffusif on surface 184 | plot(Time/(24*3600), PhiRef,'m') % reflected on surface 185 | xlabel('Time [days]'), ylabel('\Phi [W/m^2]') 186 | title('Solar radiation') 187 | legend('\Phi_d_i_r','\Phi_D_i_f', '\Phi_R_e_f_D_i_f') -------------------------------------------------------------------------------- /M/M/t08ControlHVAC.m: -------------------------------------------------------------------------------- 1 | % Cube with 2 walls: assembly 2 | clc, clear all 3 | 4 | % Input data 5 | %**************************** 6 | % Parameters 7 | Kp = 1e1; % P-controller gain: large for precision 8 | nc = 4; % number of concrete meshes 9 | ni = 3; % number of insulation meshes 10 | dt = 5 % [s] simulation time step 11 | 12 | % Physical values 13 | Sc = 5*3*3; Si = Sc; % surface : concrete, insulation [m2] 14 | Sg = 3*3; % surface glass 15 | Va = 3*3*3; % air volume [m3] 16 | rhoa = 1.2; ca = 1000; % indoor air density; heat capacity 17 | ACH = 3; % air changes per hour 18 | Vda = ACH*Va/3600; % infiltration and ventilation air: volume/hour 19 | 20 | % c: concrete; i: insulation; g: glass 21 | lamc = 2; lami = 0.04; lamg = 1.2; % conductivity [W/m K] 22 | rhoccc = 2.5e6; rhoici = 0.02e6; rhogcg = 2.0e6; % [J/m3 K] 23 | wc = 0.2; wi = 0.08; wg = 0.01; % width [m] 24 | epswLW = 0.8; % long wave wall emmisivity 25 | epswSW = 0.8; % short wave wall emmisivity 26 | 27 | epsgLW = 0.9; % long wave glass emmisivity 28 | taugSW = 0.7; % short wave glass transmitance 29 | alphagSW = 0.2; % short wave glass absortivity 30 | 31 | sigma = 5.67e-8;% [W/m2 K4] 32 | Fwg = 1/5; % view factor wall - glass 33 | Tm = 20 + 273; % mean temp for radiative exchange 34 | 35 | 36 | hi = 4; ho = 10;% convection coefficients [W/m2 K] 37 | %*************************** 38 | 39 | % Conductances and capacities 40 | Gc = lamc/wc*Sc; Cs = Sc*wc*rhoccc; % concrete 41 | Gcm = 2*nc*Gc*ones(1,2*nc); % meshed concrete 42 | Ccm = Cs/nc*mod(0:2*nc-1,2); 43 | 44 | Gi = lami/wi*Si; Ci = Si*wi*rhoici; % insulation 45 | Gim = 2*ni*Gi*ones(1,2*ni); % meshed insulation 46 | Cim = Ci/ni*mod(0:2*ni-1,2); 47 | 48 | Gg = lamg/wg*Sg; Cg = Sg*wg*rhogcg; %glass 49 | Ca = Va*rhoa*ca; 50 | Ca =0; Cg = 0; % if air and glass are neglected 51 | 52 | % Convection 53 | Gwo = ho*Sc; Gwi = hi*Si; %convection wall out; wall in 54 | Ggo = ho*Sg; Ggi = hi*Sg; %convection glass out; glass in 55 | % Long wave radiative exchange 56 | GLW1 = epswLW/(1-epswLW)*Si*4*sigma*Tm^3; 57 | GLW2 = Fwg*Si*4*sigma*Tm^3; 58 | GLW3 = epsgLW/(1-epsgLW)*Sg*4*sigma*Tm^3; 59 | GLW = 1/(1/GLW1 + 1/GLW2 +1/GLW3); %long-wave exg. wall-glass 60 | % advection 61 | Gv = Vda*rhoa*ca; %air ventilation 62 | % glass: convection outdoor & conduction 63 | Ggs = 1/(1/Ggo + 1/(2*Gg)); %cv+cd glass 64 | 65 | 66 | % Thermal network 67 | % ***************************************************************** 68 | % Dissembled circuit 69 | nq = 1+2*(nc+ni); nt = 1+2*(nc+ni); % no of flows & temps 70 | A1 = eye(nq+1,nt); % (#flows+1, #temp) 71 | A1 = -diff(A1,1,1)'; 72 | G1 = diag([Gwo Gcm Gim]'); 73 | b1 = zeros(nq,1); b1(1) = 1; 74 | C1 = diag([Ccm Cim 0]); 75 | f1 = zeros(nt,1); f1(1) = 1; f1(end) = 1; 76 | y1 = zeros(nt,1); 77 | TCd{1} = {A1,G1,b1,C1,f1,y1}; 78 | 79 | A2 = [-1 1 0; -1 0 1; 0 -1 1]; 80 | G2 = diag([GLW Gwi Ggi]'); 81 | b2 = [0 0 0]'; 82 | C2 = diag([0 0 Ca/2]'); 83 | f2 = [1 0 1]'; 84 | y2 = [0 0 1]'; 85 | TCd{2} = {A2,G2,b2,C2,f2,y2}; 86 | 87 | A3 = [1 0;-1 1]; 88 | G3 = diag([Ggs 2*Gg]); 89 | b3 = [1 0]'; 90 | C3 = diag([Cg 0]); 91 | f3 = [1 0]'; 92 | y3 = [0 0]'; 93 | TCd{3} = {A3,G3,b3,C3,f3,y3}; 94 | 95 | A4(1,1) = 1; 96 | A4(2,1) = 1; 97 | G4 = diag([Gv Kp]); 98 | b4 = [1 1]'; 99 | C4 = diag([Ca/2]); 100 | f4 = 1; 101 | y4 = 1; 102 | TCd{4} = {A4,G4,b4,C4,f4,y4}; 103 | 104 | % Assembling matrix 105 | AssX = [1 nt 2 1;...% TC1#5 <- TC2#1 106 | 2 2 3 2;... % TC2#2 <- TC3#2 107 | 2 3 4 1]; % TC2#3 <- TC4#1 108 | 109 | % Call Assembling function 110 | [TCa, Idx] = fTCAssAll(TCd, AssX); 111 | A = TCa{1}; G = TCa{2}; b = TCa{3}; C = TCa{4}; f = TCa{5}; y = TCa{6}; 112 | 113 | % Thermal model -> state-space 114 | % ********************************************************************* 115 | [As,Bs,Cs,Ds] = fTC2SS(A,G,b,C,f,y); 116 | 117 | % Maximum time-step 118 | dtmax = min(-2./eig(As))% [s] 119 | 120 | % Simulation 121 | % ********************************************************************* 122 | % Load weather data 123 | fileName = 'FRA_Lyon.csv'; 124 | from = 1*30*24 + 25*24; % start time: from 24 Jan. 125 | period = 10*24; % simulation period: for 10 days 126 | 127 | [Time,Temp,RadNDir,RadHDif,WDir,WSpeed,month,day,hour,minute]... 128 | = fReadWeather(fileName,from,period); 129 | 130 | B = 90; Z = 0; L = 45; albedo = 0.2; 131 | [PhiDir, PhiDif, PhiRef] = fSolRadTiltSurf(month, day, hour, minute, ... 132 | RadNDir, RadHDif, B, Z, L, albedo); 133 | 134 | % interpolate weather data for time step dt 135 | Temp = interp1(Time, Temp, [Time(1):dt:Time(end)]'); 136 | PhiDir = interp1(Time, PhiDir, [Time(1):dt:Time(end)]'); 137 | PhiDif = interp1(Time, PhiDif, [Time(1):dt:Time(end)]'); 138 | PhiRef = interp1(Time, PhiRef, [Time(1):dt:Time(end)]'); 139 | Time = [Time(1):dt:Time(end)]'; 140 | 141 | n = size(Time,1); 142 | nth = size(As,1); % no of state variables 143 | Qa = zeros(n,1); %auxiliary sources (electrical, persons, etc.) 144 | TintSP = 20*ones(n,1); 145 | 146 | % Inputs 147 | PhiTot = PhiDir + PhiDif + PhiRef; 148 | u = [Temp Temp Temp TintSP/2 ... 149 | epswSW*Sc*PhiTot taugSW*epswSW*Sg*PhiTot alphagSW*Sg*PhiTot ... 150 | Qa]'; 151 | % Memory alocation and initial value 152 | % th = 20*ones(size(Ac,2),n); 153 | th = zeros(size(As,2),n); 154 | y = zeros(1,n); y(1) = TintSP(1); 155 | qHVAC = zeros(1,n); 156 | 157 | for k = 1:n-1 158 | if y(k) < TintSP(k) 159 | u(8,k) = 10000*(TintSP(k) - y(k)); 160 | 161 | %qHVAC(:,k+1) = Kp*(TintSP(k+1) - y(k+1)); 162 | elseif y(k) > 6 + TintSP(k) 163 | if Temp(k) > TintSP(k) 164 | u(8,k) = 5*Vda*(TintSP(k) - y(k))^2; 165 | else 166 | u(8,k) = 10000*(TintSP(k) - y(k)); 167 | end 168 | else 169 | u(8,k) = 0; 170 | end 171 | th(:,k+1) = (eye(nth) + dt*As)*th(:,k) + dt*Bs*u(:,k); 172 | y(:,k+1) = Cs*th(:,k+1) + Ds*u(:,k+1); 173 | end 174 | subplot(3,1,1) 175 | plot(Time/3600,y,'g',Time/3600,TintSP,'r', Time/3600,Temp,'b') 176 | xlabel('Time [h]'),ylabel('T [C]') 177 | title('Simulation for weather') 178 | 179 | subplot(3,1,2) 180 | plot(Time/3600,u(8,:)) 181 | xlabel('Time [h]'),ylabel('Q_h [W]') 182 | title('Q_h') 183 | axis([0 inf -1000 1e3]) 184 | 185 | % Solar radiation 186 | subplot(3,1,3) 187 | plot(Time/(24*3600), PhiDir,'b'), hold on %direct on surface 188 | plot(Time/(24*3600), PhiDif,'r') % diffusif on surface 189 | plot(Time/(24*3600), PhiRef,'m') % reflected on surface 190 | xlabel('Time [days]'), ylabel('\Phi [W/m^2]') 191 | title('Solar radiation') 192 | legend('\Phi_d_i_r','\Phi_D_i_f', '\Phi_R_e_f_D_i_f') -------------------------------------------------------------------------------- /M/M/t05CubeFBAss.m: -------------------------------------------------------------------------------- 1 | % Cube with 2 walls: assembly 2 | clc, clear all 3 | 4 | % Input data 5 | %**************************** 6 | % Parameters 7 | Kp = 1e4; % P-controller gain: large for precision 8 | nc = 4; % number of concrete meshes 9 | ni = 3; % number of insulation meshes 10 | dt = 5 % [s] simulation time step 11 | 12 | % Physical values 13 | Sc = 5*3*3; Si = Sc; Sg = 3*3; %surface [m2]: concrete, insulation, glass 14 | Va = 3*3*3; %air volume[m3] 15 | rhoa = 1.2; ca = 1000; %indoor air density; heat capacity 16 | Vpa = 2*Va/3600; %infiltration and ventilation air: volume/hour 17 | 18 | % c: concrete; i: insulation; g: glass 19 | lamc = 2; lami = 0.04; lamg = 1.2; %[W/m K] 20 | rhoccc = 2.5e6; rhoici = 0.02e6; rhogcg = 2.0e6; %[J/m3 K] 21 | wc = 0.2; wi = 0.08; wg = 0.01; %[m] 22 | epswLW = 0.9; %long wave wall emmisivity 23 | epswSW = 0.8; %short wave wall emmisivity 24 | 25 | epsgLW = 0.9; %long wave glass emmisivity 26 | taugSW = 0.8; %short wave glass transmitance 27 | alphagSW = 0.2; %short wave glass absortivity 28 | 29 | sigma = 5.67e-8;%[W/m2 K4] 30 | Fwg = 1/5; %view factor wall - glass 31 | Tm = 20 + 273; %mean temp for radiative exchange 32 | 33 | % convection coefficients 34 | hi = 4; ho = 10; %[W/m2 K] 35 | %*************************** 36 | 37 | % Conductances and capacities 38 | Gc = lamc/wc*Sc; Cc = Sc*wc*rhoccc; %concrete 39 | Gcm = 2*nc*Gc*ones(1,2*nc); %meshed concrete 40 | Ccm = Cc/nc*mod(0:2*nc-1,2); 41 | 42 | Gi = lami/wi*Si; Ci = Si*wi*rhoici; %insulation 43 | Gim = 2*ni*Gi*ones(1,2*ni); %meshed insulation 44 | Cim = Ci/ni*mod(0:2*ni-1,2); 45 | 46 | Gg = lamg/wg*Sg; Cg = Sg*wg*rhogcg; %glass 47 | Ca = Va*rhoa*ca; 48 | % Convection 49 | Gwo = ho*Sc; Gwi = hi*Si; %convection wall out; wall in 50 | Ggo = ho*Sg; Ggi = hi*Sg; %convection glass out; glass in 51 | % Long wave radiative exchange 52 | GLW1 = epswLW/(1-epswLW)*Si*4*sigma*Tm^3; 53 | GLW2 = Fwg*Si*4*sigma*Tm^3; 54 | GLW3 = epsgLW/(1-epsgLW)*Sg*4*sigma*Tm^3; 55 | GLW = 1/(1/GLW1 + 1/GLW2 +1/GLW3); %long-wave exg. wall-glass 56 | % advection 57 | Gv = Vpa*rhoa*ca; %air ventilation 58 | % glass: convection outdoor & conduction 59 | Ggs = 1/(1/Ggo + 1/(2*Gg)); %cv+cd glass 60 | 61 | % Ca = 0; Cg = 0 62 | % Thermal network 63 | % ***************************************************************** 64 | % Dissembled circuit 65 | nq = 1+2*(nc+ni); nt = 1+2*(nc+ni); % no of flows & temps 66 | A1 = eye(nq+1,nt); % (#flows+1, #temp) 67 | A1 = -diff(A1,1,1)'; 68 | G1 = diag([Gwo Gcm Gim]'); 69 | b1 = zeros(nq,1); b1(1) = 1; 70 | C1 = diag([Ccm Cim 0]); 71 | f1 = zeros(nt,1); f1(1) = 1; f1(end) = 1; 72 | y1 = zeros(nt,1); 73 | TCd{1} = {A1,G1,b1,C1,f1,y1}; % concrete & insulation 74 | 75 | A2 = [-1 1 0; -1 0 1; 0 -1 1]; 76 | G2 = diag([GLW Gwi Ggi]'); 77 | b2 = [0 0 0]'; 78 | C2 = diag([0 0 Ca/2]'); 79 | f2 = [1 0 1]'; 80 | y2 = [0 0 1]'; 81 | TCd{2} = {A2,G2,b2,C2,f2,y2}; % air 82 | 83 | A3 = [1 0;-1 1]; 84 | G3 = diag([Ggs 2*Gg]); 85 | b3 = [1 0]'; 86 | C3 = diag([Cg 0]); 87 | f3 = [1 0]'; 88 | y3 = [0 0]'; 89 | TCd{3} = {A3,G3,b3,C3,f3,y3}; % glass 90 | 91 | A4(1,1) = 1; 92 | A4(2,1) = 1; 93 | G4 = diag([Gv Kp]); 94 | b4 = [1 1]'; 95 | C4 = diag([Ca/2]); 96 | f4 = 1; 97 | y4 = 1; 98 | TCd{4} = {A4,G4,b4,C4,f4,y4}; % infiltration & controller 99 | 100 | % Assembling matrix 101 | AssX = [1 nt 2 1;...% TC1#5 <- TC2#1 102 | 2 2 3 2;... % TC2#2 <- TC3#2 103 | 2 3 4 1]; % TC2#3 <- TC4#1 104 | 105 | % Call assembling function 106 | [TCa, Idx] = fTCAssAll(TCd, AssX); 107 | A = TCa{1}; G = TCa{2}; b = TCa{3}; C = TCa{4}; f = TCa{5}; y = TCa{6}; 108 | 109 | disp('Local and global indexes of nodes'); disp(Idx{1}) 110 | disp('Local and global indexes of branches'); disp(Idx{2}) 111 | 112 | % Thermal model -> state-space 113 | % ********************************************************************* 114 | [As,Bs,Cs,Ds] = fTC2SS(A,G,b,C,f,y); 115 | 116 | % Maximum time-step 117 | dtmax = min(-2./eig(As))% [s] 118 | 119 | % Step response 120 | % ********************************************************************* 121 | duration = 3600*24*3; % [s] time duration 122 | n = floor(duration/dt); % no of time samples 123 | 124 | Time = 0:dt:(n-1)*dt; % time 125 | nth = size(As,1); % no of state variables 126 | th = zeros(nth,n); % zero initial conditions 127 | u = zeros(8,n); % u = [To To To Tsp Phio Phii Qaux Phia] 128 | u(1:3,:) = ones(3,n); % To = step variation 129 | 130 | for k = 1:n-1 131 | th(:,k+1) = (eye(nth) + dt*As)*th(:,k) + dt*Bs*u(:,k); 132 | end 133 | y = Cs*th + Ds*u; 134 | subplot(3,1,1) 135 | plot(Time/3600,y) 136 | xlabel('Time [h]'),ylabel('T [C]') 137 | title('Step response for T_o = 1 C'), 138 | 139 | % Simulation with weather data 140 | % Load weather data 141 | fileName = 'FRA_Lyon.csv'; 142 | from = 6*30*24 + 25*24; % start time: from 24 Jan. 143 | period = 10*24; % simulatio, period: for 10 days 144 | 145 | [Time,Temp,RadNDir,RadHDif,WDir,WSpeed,month,day,hour,minute]... 146 | = fReadWeather(fileName,from,period); 147 | 148 | B = 90; Z = 0; L = 45; albedo = 0.2; 149 | [PhiDir, PhiDif, PhiRef] = fSolRadTiltSurf(month, day, hour, minute, ... 150 | RadNDir, RadHDif, B, Z, L, albedo); 151 | 152 | % interpolate weather data for time step dt 153 | Temp = interp1(Time, Temp, [Time(1):dt:Time(end)]'); 154 | PhiDir = interp1(Time, PhiDir, [Time(1):dt:Time(end)]'); 155 | PhiDif = interp1(Time, PhiDif, [Time(1):dt:Time(end)]'); 156 | PhiRef = interp1(Time, PhiRef, [Time(1):dt:Time(end)]'); 157 | Time = [Time(1):dt:Time(end)]'; 158 | 159 | n = size(Time,1); 160 | th = zeros(nth,n); 161 | Qa = zeros(n,1); %auxiliary sources (electrical, persons, etc.) 162 | TintSP = 20*ones(n,1); 163 | 164 | % Inputs 165 | PhiTot = PhiDir + PhiDif + PhiRef; 166 | u = [Temp Temp Temp TintSP ... 167 | epswSW*Sc*PhiTot taugSW*epswSW*Sg*PhiTot alphagSW*Sg*PhiTot Qa]'; 168 | % Memory alocation and initial value 169 | th = zeros(size(As,2),n); 170 | thi = th; 171 | 172 | for k = 1:n-1 173 | th(:,k+1) = (eye(nth) + dt*As)*th(:,k) + dt*Bs*u(:,k); 174 | %thi(:,k+1) = inv((eye(nth) - dt*A))*(thi(:,k) + dt*B*u(:,k)); 175 | end 176 | 177 | y = Cs*th + Ds*u; 178 | subplot(3,1,2) 179 | plot(Time/3600,y,Time/3600,Temp) 180 | xlabel('Time [h]'),ylabel('T [C]') 181 | title('Simulation for weather') 182 | 183 | % Solar radiation 184 | subplot(3,1,3) 185 | plot(Time/(24*3600), PhiDir,'b'), hold on %direct on surface 186 | plot(Time/(24*3600), PhiDif,'r') % diffusif on surface 187 | plot(Time/(24*3600), PhiRef,'m') % reflected on surface 188 | xlabel('Time [days]'), ylabel('\Phi [W/m^2]') 189 | title('Solar radiation') 190 | legend('\Phi_d_i_r','\Phi_D_i_f', '\Phi_R_e_f_D_i_f') -------------------------------------------------------------------------------- /M/M/t06CubeHeat.m: -------------------------------------------------------------------------------- 1 | % Cube with 2 walls: assembly 2 | clc, clear all 3 | 4 | % Input data 5 | %**************************** 6 | % Parameters 7 | Kp = 1e4; % P-controller gain: large for precision 8 | nc = 4; % number of concrete meshes 9 | ni = 3; % number of insulation meshes 10 | dt = 5 % [s] simulation time step 11 | 12 | % Physical values 13 | Sc = 5*3*3; Si = Sc; Sg = 3*3; %surface [m2]: concrete, insulation, glass 14 | Va = 3*3*3; %air volume[m3] 15 | rhoa = 1.2; ca = 1000; %indoor air density; heat capacity 16 | Vpa = 2*Va/3600; %infiltration and ventilation air: volume/hour 17 | 18 | % c: concrete; i: insulation; g: glass 19 | lamc = 2; lami = 0.04; lamg = 1.2; %[W/m K] 20 | rhoccc = 2.5e6; rhoici = 2.0e6; rhogcg = 2.0e6; %[J/m3 K] 21 | wc = 0.2; wi = 0.08; wg = 0.01; %[m] 22 | epswLW = 0.9; %long wave wall emmisivity 23 | epswSW = 0.8; %short wave wall emmisivity 24 | 25 | epsgLW = 0.9; %long wave glass emmisivity 26 | taugSW = 0.8; %short wave glass transmitance 27 | alphagSW = 0.2; %short wave glass absortivity 28 | 29 | sigma = 5.67e-8;%[W/m2 K4] 30 | Fwg = 1/5; %view factor wall - glass 31 | Tm = 20 + 273; %mean temp for radiative exchange 32 | 33 | % convection coefficients 34 | hi = 4; ho = 10; %[W/m2 K] 35 | %*************************** 36 | 37 | % Conductances and capacities 38 | Gc = lamc/wc*Sc; Cc = Sc*wc*rhoccc; %concrete 39 | Gcm = 2*nc*Gc*ones(1,2*nc); %meshed concrete 40 | Ccm = Cc/nc*mod(0:2*nc-1,2); 41 | 42 | Gi = lami/wi*Si; Ci = Si*wi*rhoici; %insulation 43 | Gim = 2*ni*Gi*ones(1,2*ni); %meshed insulation 44 | Cim = Ci/ni*mod(0:2*ni-1,2); 45 | 46 | Gg = lamg/wg*Sg; Cg = Sg*wg*rhogcg; %glass 47 | Ca = Va*rhoa*ca; 48 | % Ca =0; Cg = 0; % if air and glass are neglected 49 | 50 | % Convection 51 | Gwo = ho*Sc; Gwi = hi*Si; %convection wall out; wall in 52 | Ggo = ho*Sg; Ggi = hi*Sg; %convection glass out; glass in 53 | % Long wave radiative exchange 54 | GLW1 = epswLW/(1-epswLW)*Si*4*sigma*Tm^3; 55 | GLW2 = Fwg*Si*4*sigma*Tm^3; 56 | GLW3 = epsgLW/(1-epsgLW)*Sg*4*sigma*Tm^3; 57 | GLW = 1/(1/GLW1 + 1/GLW2 +1/GLW3); %long-wave exg. wall-glass 58 | % advection 59 | Gv = Vpa*rhoa*ca; %air ventilation 60 | % glass: convection outdoor & conduction 61 | Ggs = 1/(1/Ggo + 1/(2*Gg)); %cv+cd glass 62 | 63 | 64 | % Thermal network 65 | % ***************************************************************** 66 | % Dissembled circuit 67 | nq = 1+2*(nc+ni); nt = 1+2*(nc+ni); % no of flows & temps 68 | A1 = eye(nq+1,nt); % (#flows+1, #temp) 69 | A1 = -diff(A1,1,1)'; 70 | G1 = diag([Gwo Gcm Gim]'); 71 | b1 = zeros(nq,1); b1(1) = 1; 72 | C1 = diag([Ccm Cim 0]); 73 | f1 = zeros(nt,1); f1(1) = 1; f1(end) = 1; 74 | y1 = zeros(nt,1); 75 | TCd{1} = {A1,G1,b1,C1,f1,y1}; 76 | 77 | A2 = [-1 1 0; -1 0 1; 0 -1 1]; 78 | G2 = diag([GLW Gwi Ggi]'); 79 | b2 = [0 0 0]'; 80 | C2 = diag([0 0 Ca/2]'); 81 | f2 = [1 0 1]'; 82 | y2 = [0 0 1]'; 83 | TCd{2} = {A2,G2,b2,C2,f2,y2}; 84 | 85 | A3 = [1 0;-1 1]; 86 | G3 = diag([Ggs 2*Gg]); 87 | b3 = [1 0]'; 88 | C3 = diag([Cg 0]); 89 | f3 = [1 0]'; 90 | y3 = [0 0]'; 91 | TCd{3} = {A3,G3,b3,C3,f3,y3}; 92 | 93 | A4(1,1) = 1; 94 | A4(2,1) = 1; 95 | G4 = diag([Gv Kp]); 96 | b4 = [1 1]'; 97 | C4 = diag([Ca/2]); 98 | f4 = 1; 99 | y4 = 1; 100 | TCd{4} = {A4,G4,b4,C4,f4,y4}; 101 | 102 | % Assembling matrix 103 | AssX = [1 nt 2 1;...% TC1#5 <- TC2#1 104 | 2 2 3 2;... % TC2#2 <- TC3#2 105 | 2 3 4 1]; % TC2#3 <- TC4#1 106 | 107 | % Call Assembling function 108 | [TCa, Idx] = fTCAssAll(TCd, AssX); 109 | A = TCa{1}; G = TCa{2}; b = TCa{3}; C = TCa{4}; f = TCa{5}; y = TCa{6}; 110 | 111 | % Thermal model -> state-space 112 | % ********************************************************************* 113 | [Ac,Bc,Cc,Dc] = fTC2SS(A,G,b,C,f,y); % model with controller 114 | 115 | G4 = diag([Gv 1e-1]); % no controller: practically Kp = 0 116 | TCd{4} = {A4,G4,b4,C4,f4,y4}; 117 | [TCa, Idx] = fTCAssAll(TCd, AssX); 118 | A = TCa{1}; G = TCa{2}; b = TCa{3}; C = TCa{4}; f = TCa{5}; y = TCa{6}; 119 | [Af,Bf,Cf,Df] = fTC2SS(A,G,b,C,f,y); % model free-running 120 | 121 | % Maximum time-step 122 | dtmax = min([-2./eig(Ac) -2./eig(Af)])% [s] 123 | 124 | % Simulation 125 | % ********************************************************************* 126 | % Load weather data 127 | fileName = 'FRA_Lyon.csv'; 128 | from = 1*30*24 + 25*24; % start time: from 24 Jan. 129 | period = 10*24; % simulation period: for 10 days 130 | 131 | [Time,Temp,RadNDir,RadHDif,WDir,WSpeed,month,day,hour,minute]... 132 | = fReadWeather(fileName,from,period); 133 | 134 | B = 90; Z = 0; L = 45; albedo = 0.2; 135 | [PhiDir, PhiDif, PhiRef] = fSolRadTiltSurf(month, day, hour, minute, ... 136 | RadNDir, RadHDif, B, Z, L, albedo); 137 | 138 | % interpolate weather data for time step dt 139 | Temp = interp1(Time, Temp, [Time(1):dt:Time(end)]'); 140 | PhiDir = interp1(Time, PhiDir, [Time(1):dt:Time(end)]'); 141 | PhiDif = interp1(Time, PhiDif, [Time(1):dt:Time(end)]'); 142 | PhiRef = interp1(Time, PhiRef, [Time(1):dt:Time(end)]'); 143 | Time = [Time(1):dt:Time(end)]'; 144 | 145 | n = size(Time,1); 146 | nth = size(Ac,1); % no of state variables 147 | Qa = zeros(n,1); %auxiliary sources (electrical, persons, etc.) 148 | TintSP = 20*ones(n,1); 149 | 150 | % Inputs 151 | PhiTot = PhiDir + PhiDif + PhiRef; 152 | u = [Temp Temp Temp TintSP ... 153 | epswSW*Sc*PhiTot taugSW*epswSW*Sg*PhiTot alphagSW*Sg*PhiTot ... 154 | Qa]'; 155 | % Memory alocation and initial value 156 | % th = 20*ones(size(Ac,2),n); 157 | th = zeros(size(Ac,2),n); 158 | y = zeros(1,n); y(1) = TintSP(1); 159 | qHVAC = zeros(1,n); 160 | for k = 1:n-1 161 | if y(k) < TintSP(k) 162 | th(:,k+1) = (eye(nth) + dt*Ac)*th(:,k) + dt*Bc*u(:,k); 163 | y(:,k+1) = Cc*th(:,k+1) + Dc*u(:,k+1); 164 | qHVAC(:,k+1) = Kp*(TintSP(k+1) - y(k+1)); 165 | else 166 | th(:,k+1) = (eye(nth) + dt*Af)*th(:,k) + dt*Bf*u(:,k); 167 | y(:,k+1) = Cf*th(:,k+1) + Df*u(:,k+1); 168 | qHVAC(:,k+1) = 1e-1*(TintSP(k+1) - y(k+1)); 169 | end 170 | end 171 | subplot(3,1,1) 172 | plot(Time/3600,y,Time/3600,TintSP, Time/3600,Temp) 173 | xlabel('Time [h]'),ylabel('T [C]') 174 | title('Simulation for weather') 175 | 176 | subplot(3,1,2) 177 | plot(Time/3600, qHVAC) 178 | xlabel('Time [h]'),ylabel('Q_h [W]') 179 | title('Q_h') 180 | axis([0 inf -200 inf]) 181 | 182 | % Solar radiation 183 | subplot(3,1,3) 184 | plot(Time/(24*3600), PhiDir,'b'), hold on %direct on surface 185 | plot(Time/(24*3600), PhiDif,'r') % diffusif on surface 186 | plot(Time/(24*3600), PhiRef,'m') % reflected on surface 187 | xlabel('Time [days]'), ylabel('\Phi [W/m^2]') 188 | title('Solar radiation') 189 | legend('\Phi_d_i_r','\Phi_D_i_f', '\Phi_R_e_f_D_i_f') -------------------------------------------------------------------------------- /M/M/t06CubeHeatCool.m: -------------------------------------------------------------------------------- 1 | % Cube with 2 walls: assembly 2 | clc, clear all 3 | 4 | % Input data 5 | %**************************** 6 | % Parameters 7 | Kp = 1e3; % P-controller gain: large for precision 8 | nc = 4; % number of concrete meshes 9 | ni = 3; % number of insulation meshes 10 | dt = 5 % [s] simulation time step 11 | 12 | % Physical values 13 | Sc = 5*3*3; Si = Sc; Sg = 3*3; %surface [m2]: concrete, insulation, glass 14 | Va = 3*3*3; %air volume[m3] 15 | rhoa = 1.2; ca = 1000; %indoor air density; heat capacity 16 | Vpa = 2*Va/3600; %infiltration and ventilation air: volume/hour 17 | 18 | % c: concrete; i: insulation; g: glass 19 | lamc = 2; lami = 0.04; lamg = 1.2; %[W/m K] 20 | rhoccc = 2.5e6; rhoici = 0.02e6; rhogcg = 2.0e6; %[J/m3 K] 21 | wc = 0.2; wi = 0.08; wg = 0.01; %[m] 22 | epswLW = 0.9; %long wave wall emmisivity 23 | epswSW = 0.8; %short wave wall emmisivity 24 | 25 | epsgLW = 0.9; %long wave glass emmisivity 26 | taugSW = 0.8; %short wave glass transmitance 27 | alphagSW = 0.2; %short wave glass absortivity 28 | 29 | sigma = 5.67e-8;%[W/m2 K4] 30 | Fwg = 1/5; %view factor wall - glass 31 | Tm = 20 + 273; %mean temp for radiative exchange 32 | 33 | % convection coefficients 34 | hi = 4; ho = 10; %[W/m2 K] 35 | %*************************** 36 | 37 | % Conductances and capacities 38 | Gc = lamc/wc*Sc; Cc = Sc*wc*rhoccc; %concrete 39 | Gcm = 2*nc*Gc*ones(1,2*nc); %meshed concrete 40 | Ccm = Cc/nc*mod(0:2*nc-1,2); 41 | 42 | Gi = lami/wi*Si; Ci = Si*wi*rhoici; %insulation 43 | Gim = 2*ni*Gi*ones(1,2*ni); %meshed insulation 44 | Cim = Ci/ni*mod(0:2*ni-1,2); 45 | 46 | Gg = lamg/wg*Sg; Cg = Sg*wg*rhogcg; %glass 47 | Ca = Va*rhoa*ca; 48 | % Ca =0; Cg = 0; % if air and glass are neglected 49 | 50 | % Convection 51 | Gwo = ho*Sc; Gwi = hi*Si; %convection wall out; wall in 52 | Ggo = ho*Sg; Ggi = hi*Sg; %convection glass out; glass in 53 | % Long wave radiative exchange 54 | GLW1 = epswLW/(1-epswLW)*Si*4*sigma*Tm^3; 55 | GLW2 = Fwg*Si*4*sigma*Tm^3; 56 | GLW3 = epsgLW/(1-epsgLW)*Sg*4*sigma*Tm^3; 57 | GLW = 1/(1/GLW1 + 1/GLW2 +1/GLW3); %long-wave exg. wall-glass 58 | % advection 59 | Gv = Vpa*rhoa*ca; %air ventilation 60 | % glass: convection outdoor & conduction 61 | Ggs = 1/(1/Ggo + 1/(2*Gg)); %cv+cd glass 62 | 63 | 64 | % Thermal network 65 | % ***************************************************************** 66 | % Dissembled circuit 67 | nq = 1+2*(nc+ni); nt = 1+2*(nc+ni); % no of flows & temps 68 | A1 = eye(nq+1,nt); % (#flows+1, #temp) 69 | A1 = -diff(A1,1,1)'; 70 | G1 = diag([Gwo Gcm Gim]'); 71 | b1 = zeros(nq,1); b1(1) = 1; 72 | C1 = diag([Ccm Cim 0]); 73 | f1 = zeros(nt,1); f1(1) = 1; f1(end) = 1; 74 | y1 = zeros(nt,1); 75 | TCd{1} = {A1,G1,b1,C1,f1,y1}; 76 | 77 | A2 = [-1 1 0; -1 0 1; 0 -1 1]; 78 | G2 = diag([GLW Gwi Ggi]'); 79 | b2 = [0 0 0]'; 80 | C2 = diag([0 0 Ca/2]'); 81 | f2 = [1 0 1]'; 82 | y2 = [0 0 1]'; 83 | TCd{2} = {A2,G2,b2,C2,f2,y2}; 84 | 85 | A3 = [1 0;-1 1]; 86 | G3 = diag([Ggs 2*Gg]); 87 | b3 = [1 0]'; 88 | C3 = diag([Cg 0]); 89 | f3 = [1 0]'; 90 | y3 = [0 0]'; 91 | TCd{3} = {A3,G3,b3,C3,f3,y3}; 92 | 93 | A4(1,1) = 1; 94 | A4(2,1) = 1; 95 | G4 = diag([Gv Kp]); 96 | b4 = [1 1]'; 97 | C4 = diag([Ca/2]); 98 | f4 = 1; 99 | y4 = 1; 100 | TCd{4} = {A4,G4,b4,C4,f4,y4}; 101 | 102 | % Assembling matrix 103 | AssX = [1 nt 2 1;...% TC1#5 <- TC2#1 104 | 2 2 3 2;... % TC2#2 <- TC3#2 105 | 2 3 4 1]; % TC2#3 <- TC4#1 106 | 107 | % Call Assembling function 108 | [TCa, Idx] = fTCAssAll(TCd, AssX); 109 | A = TCa{1}; G = TCa{2}; b = TCa{3}; C = TCa{4}; f = TCa{5}; y = TCa{6}; 110 | 111 | % Thermal model -> state-space 112 | % ********************************************************************* 113 | [Ac,Bc,Cc,Dc] = fTC2SS(A,G,b,C,f,y); % model with controller 114 | 115 | G4 = diag([Gv 1e-1]); % no controller: practically Kp = 0 116 | TCd{4} = {A4,G4,b4,C4,f4,y4}; 117 | [TCa, Idx] = fTCAssAll(TCd, AssX); 118 | A = TCa{1}; G = TCa{2}; b = TCa{3}; C = TCa{4}; f = TCa{5}; y = TCa{6}; 119 | [Af,Bf,Cf,Df] = fTC2SS(A,G,b,C,f,y); % model free-running 120 | 121 | % Maximum time-step 122 | dtmax = min([-2./eig(Ac) -2./eig(Af)])% [s] 123 | 124 | % Simulation 125 | % ********************************************************************* 126 | % Load weather data 127 | fileName = 'FRA_Lyon.csv'; 128 | from = 1*30*24 + 25*24; % start time: from 24 Jan. 129 | period = 10*24; % simulation period: for 10 days 130 | 131 | [Time,Temp,RadNDir,RadHDif,WDir,WSpeed,month,day,hour,minute]... 132 | = fReadWeather(fileName,from,period); 133 | 134 | B = 90; Z = 0; L = 45; albedo = 0.2; 135 | [PhiDir, PhiDif, PhiRef] = fSolRadTiltSurf(month, day, hour, minute, ... 136 | RadNDir, RadHDif, B, Z, L, albedo); 137 | 138 | % interpolate weather data for time step dt 139 | Temp = interp1(Time, Temp, [Time(1):dt:Time(end)]'); 140 | PhiDir = interp1(Time, PhiDir, [Time(1):dt:Time(end)]'); 141 | PhiDif = interp1(Time, PhiDif, [Time(1):dt:Time(end)]'); 142 | PhiRef = interp1(Time, PhiRef, [Time(1):dt:Time(end)]'); 143 | Time = [Time(1):dt:Time(end)]'; 144 | 145 | n = size(Time,1); 146 | nth = size(Ac,1); % no of state variables 147 | Qa = zeros(n,1); %auxiliary sources (electrical, persons, etc.) 148 | TintSP = 20*ones(n,1); 149 | 150 | % Inputs 151 | PhiTot = PhiDir + PhiDif + PhiRef; 152 | u = [Temp Temp Temp TintSP ... 153 | epswSW*Sc*PhiTot taugSW*epswSW*Sg*PhiTot alphagSW*Sg*PhiTot ... 154 | Qa]'; 155 | % Memory alocation and initial value 156 | % th = 20*ones(size(Ac,2),n); 157 | th = zeros(size(Ac,2),n); 158 | y = zeros(1,n); y(1) = TintSP(1); 159 | qHVAC = zeros(1,n); 160 | for k = 1:n-1 161 | if y(k) < TintSP(k) || y(k) > 4 + TintSP(k) 162 | th(:,k+1) = (eye(nth) + dt*Ac)*th(:,k) + dt*Bc*u(:,k); 163 | y(:,k+1) = Cc*th(:,k+1) + Dc*u(:,k+1); 164 | qHVAC(:,k+1) = Kp*(TintSP(k+1) - y(k+1)); 165 | else 166 | th(:,k+1) = (eye(nth) + dt*Af)*th(:,k) + dt*Bf*u(:,k); 167 | y(:,k+1) = Cf*th(:,k+1) + Df*u(:,k+1); 168 | qHVAC(:,k+1) = 1e-1*(TintSP(k+1) - y(k+1)); 169 | end 170 | end 171 | subplot(3,1,1) 172 | plot(Time/3600,y,Time/3600,TintSP, Time/3600,Temp) 173 | xlabel('Time [h]'),ylabel('T [C]') 174 | title('Simulation for weather') 175 | 176 | subplot(3,1,2) 177 | plot(Time/3600,qHVAC) 178 | xlabel('Time [h]'),ylabel('Q_h [W]') 179 | title('Q_h') 180 | axis([0 inf -10000 inf]) 181 | 182 | % Solar radiation 183 | subplot(3,1,3) 184 | plot(Time/(24*3600), PhiDir,'b'), hold on %direct on surface 185 | plot(Time/(24*3600), PhiDif,'r') % diffusif on surface 186 | plot(Time/(24*3600), PhiRef,'m') % reflected on surface 187 | xlabel('Time [days]'), ylabel('\Phi [W/m^2]') 188 | title('Solar radiation') 189 | legend('\Phi_d_i_r','\Phi_D_i_f', '\Phi_R_e_f_D_i_f') -------------------------------------------------------------------------------- /M/M/t08ControlHeatCool.m: -------------------------------------------------------------------------------- 1 | % Cube with 2 walls: assembly 2 | clc, clear all 3 | 4 | % Input data 5 | %**************************** 6 | % Parameters 7 | Kp = 1e1; % P-controller gain: large for precision 8 | nc = 4; % number of concrete meshes 9 | ni = 3; % number of insulation meshes 10 | dt = 5 % [s] simulation time step 11 | 12 | % Physical values 13 | Sc = 5*3*3; Si = Sc; % surface : concrete, insulation [m2] 14 | Sg = 3*3; % surface glass 15 | Va = 3*3*3; % air volume [m3] 16 | rhoa = 1.2; ca = 1000; % indoor air density; heat capacity 17 | ACH = 3; % air changes per hour 18 | Vda = ACH*Va/3600; % infiltration and ventilation air: volume/hour 19 | 20 | % c: concrete; i: insulation; g: glass 21 | lamc = 2; lami = 0.04; lamg = 1.2; % conductivity [W/m K] 22 | rhoccc = 2.5e6; rhoici = 2.0e6; rhogcg = 2.0e6; % [J/m3 K] 23 | wc = 0.2; wi = 0.08; wg = 0.01; % width [m] 24 | epswLW = 0.8; % long wave wall emmisivity 25 | epswSW = 0.8; % short wave wall emmisivity 26 | 27 | epsgLW = 0.9; % long wave glass emmisivity 28 | taugSW = 0.7; % short wave glass transmitance 29 | alphagSW = 0.2; % short wave glass absortivity 30 | 31 | sigma = 5.67e-8;% [W/m2 K4] 32 | Fwg = 1/5; % view factor wall - glass 33 | Tm = 20 + 273; % mean temp for radiative exchange 34 | 35 | 36 | hi = 4; ho = 10;% convection coefficients [W/m2 K] 37 | %*************************** 38 | 39 | % Conductances and capacities 40 | Gc = lamc/wc*Sc; Cs = Sc*wc*rhoccc; % concrete 41 | Gcm = 2*nc*Gc*ones(1,2*nc); % meshed concrete 42 | Ccm = Cs/nc*mod(0:2*nc-1,2); 43 | 44 | Gi = lami/wi*Si; Ci = Si*wi*rhoici; % insulation 45 | Gim = 2*ni*Gi*ones(1,2*ni); % meshed insulation 46 | Cim = Ci/ni*mod(0:2*ni-1,2); 47 | 48 | Gg = lamg/wg*Sg; Cg = Sg*wg*rhogcg; %glass 49 | Ca = Va*rhoa*ca; 50 | Ca =0; Cg = 0; % if air and glass are neglected 51 | 52 | % Convection 53 | Gwo = ho*Sc; Gwi = hi*Si; %convection wall out; wall in 54 | Ggo = ho*Sg; Ggi = hi*Sg; %convection glass out; glass in 55 | % Long wave radiative exchange 56 | GLW1 = epswLW/(1-epswLW)*Si*4*sigma*Tm^3; 57 | GLW2 = Fwg*Si*4*sigma*Tm^3; 58 | GLW3 = epsgLW/(1-epsgLW)*Sg*4*sigma*Tm^3; 59 | GLW = 1/(1/GLW1 + 1/GLW2 +1/GLW3); %long-wave exg. wall-glass 60 | % advection 61 | Gv = Vda*rhoa*ca; %air ventilation 62 | % glass: convection outdoor & conduction 63 | Ggs = 1/(1/Ggo + 1/(2*Gg)); %cv+cd glass 64 | 65 | 66 | % Thermal network 67 | % ***************************************************************** 68 | % Dissembled circuit 69 | nq = 1+2*(nc+ni); nt = 1+2*(nc+ni); % no of flows & temps 70 | A1 = eye(nq+1,nt); % (#flows+1, #temp) 71 | A1 = -diff(A1,1,1)'; 72 | G1 = diag([Gwo Gcm Gim]'); 73 | b1 = zeros(nq,1); b1(1) = 1; 74 | C1 = diag([Ccm Cim 0]); 75 | f1 = zeros(nt,1); f1(1) = 1; f1(end) = 1; 76 | y1 = zeros(nt,1); 77 | TCd{1} = {A1,G1,b1,C1,f1,y1}; 78 | 79 | A2 = [-1 1 0; -1 0 1; 0 -1 1]; 80 | G2 = diag([GLW Gwi Ggi]'); 81 | b2 = [0 0 0]'; 82 | C2 = diag([0 0 Ca/2]'); 83 | f2 = [1 0 1]'; 84 | y2 = [0 0 1]'; 85 | TCd{2} = {A2,G2,b2,C2,f2,y2}; 86 | 87 | A3 = [1 0;-1 1]; 88 | G3 = diag([Ggs 2*Gg]); 89 | b3 = [1 0]'; 90 | C3 = diag([Cg 0]); 91 | f3 = [1 0]'; 92 | y3 = [0 0]'; 93 | TCd{3} = {A3,G3,b3,C3,f3,y3}; 94 | 95 | A4(1,1) = 1; 96 | A4(2,1) = 1; 97 | G4 = diag([Gv Kp]); 98 | b4 = [1 1]'; 99 | C4 = diag([Ca/2]); 100 | f4 = 1; 101 | y4 = 1; 102 | TCd{4} = {A4,G4,b4,C4,f4,y4}; 103 | 104 | % Assembling matrix 105 | AssX = [1 nt 2 1;...% TC1#5 <- TC2#1 106 | 2 2 3 2;... % TC2#2 <- TC3#2 107 | 2 3 4 1]; % TC2#3 <- TC4#1 108 | 109 | % Call Assembling function 110 | [TCa, Idx] = fTCAssAll(TCd, AssX); 111 | A = TCa{1}; G = TCa{2}; b = TCa{3}; C = TCa{4}; f = TCa{5}; y = TCa{6}; 112 | 113 | % Thermal model -> state-space 114 | % ********************************************************************* 115 | [As,Bs,Cs,Ds] = fTC2SS(A,G,b,C,f,y); 116 | 117 | % Maximum time-step 118 | dtmax = min(-2./eig(As))% [s] 119 | 120 | % Simulation 121 | % ********************************************************************* 122 | % Load weather data 123 | fileName = 'FRA_Lyon.csv'; 124 | from = 1*30*24 + 25*24; % start time: from 24 Jan. 125 | period = 10*24; % simulation period: for 10 days 126 | 127 | [Time,Temp,RadNDir,RadHDif,WDir,WSpeed,month,day,hour,minute]... 128 | = fReadWeather(fileName,from,period); 129 | 130 | B = 90; Z = 0; L = 45; albedo = 0.2; 131 | [PhiDir, PhiDif, PhiRef] = fSolRadTiltSurf(month, day, hour, minute, ... 132 | RadNDir, RadHDif, B, Z, L, albedo); 133 | 134 | % interpolate weather data for time step dt 135 | Temp = interp1(Time, Temp, [Time(1):dt:Time(end)]'); 136 | PhiDir = interp1(Time, PhiDir, [Time(1):dt:Time(end)]'); 137 | PhiDif = interp1(Time, PhiDif, [Time(1):dt:Time(end)]'); 138 | PhiRef = interp1(Time, PhiRef, [Time(1):dt:Time(end)]'); 139 | Time = [Time(1):dt:Time(end)]'; 140 | 141 | n = size(Time,1); 142 | nth = size(As,1); % no of state variables 143 | Qa = zeros(n,1); %auxiliary sources (electrical, persons, etc.) 144 | TintSP = 20*ones(n,1); 145 | 146 | % Inputs 147 | PhiTot = PhiDir + PhiDif + PhiRef; 148 | u = [Temp Temp Temp TintSP/2 ... 149 | epswSW*Sc*PhiTot taugSW*epswSW*Sg*PhiTot alphagSW*Sg*PhiTot ... 150 | Qa]'; 151 | % Memory alocation and initial value 152 | % th = 20*ones(size(Ac,2),n); 153 | th = zeros(size(As,2),n); 154 | y = zeros(1,n); y(1) = TintSP(1); 155 | qHVAC = zeros(1,n); 156 | 157 | for k = 1:n-1 158 | if y(k) < TintSP(k) 159 | u(8,k) = 10000*(TintSP(k) - y(k)); 160 | th(:,k+1) = (eye(nth) + dt*As)*th(:,k) + dt*Bs*u(:,k); 161 | y(:,k+1) = Cs*th(:,k+1) + Ds*u(:,k+1); 162 | %qHVAC(:,k+1) = Kp*(TintSP(k+1) - y(k+1)); 163 | elseif y(k) > 6 + TintSP(k) 164 | u(8,k) = 10000*(TintSP(k) - y(k)); 165 | th(:,k+1) = (eye(nth) + dt*As)*th(:,k) + dt*Bs*u(:,k); 166 | y(:,k+1) = Cs*th(:,k+1) + Ds*u(:,k+1); 167 | else 168 | u(8,k) = 0; 169 | th(:,k+1) = (eye(nth) + dt*As)*th(:,k) + dt*Bs*u(:,k); 170 | y(:,k+1) = Cs*th(:,k+1) + Ds*u(:,k+1); 171 | end 172 | end 173 | subplot(3,1,1) 174 | plot(Time/3600,y,'g',Time/3600,TintSP,'r', Time/3600,Temp,'b') 175 | xlabel('Time [h]'),ylabel('T [C]') 176 | title('Simulation for weather') 177 | 178 | subplot(3,1,2) 179 | plot(Time/3600,u(8,:)) 180 | xlabel('Time [h]'),ylabel('Q_h [W]') 181 | title('Q_h') 182 | axis([0 inf -1000 1e3]) 183 | 184 | % Solar radiation 185 | subplot(3,1,3) 186 | plot(Time/(24*3600), PhiDir,'b'), hold on %direct on surface 187 | plot(Time/(24*3600), PhiDif,'r') % diffusif on surface 188 | plot(Time/(24*3600), PhiRef,'m') % reflected on surface 189 | xlabel('Time [days]'), ylabel('\Phi [W/m^2]') 190 | title('Solar radiation') 191 | legend('\Phi_d_i_r','\Phi_D_i_f', '\Phi_R_e_f_D_i_f') -------------------------------------------------------------------------------- /M/M/t06Controller.m: -------------------------------------------------------------------------------- 1 | % Cube with 2 walls: assembly 2 | % clc, clear all 3 | 4 | % Input data 5 | %**************************** 6 | % Parameters 7 | Kp = 1e4; % P-controller gain: large for precision 8 | nc = 4; % number of concrete meshes 9 | ni = 3; % number of insulation meshes 10 | dt = 5 % [s] simulation time step 11 | 12 | % Physical values 13 | Sc = 5*3*3; Si = Sc; Sg = 3*3; %surface [m2]: concrete, insulation, glass 14 | Va = 3*3*3; %air volume[m3] 15 | rhoa = 1.2; ca = 1000; %indoor air density; heat capacity 16 | Vpa = 2*Va/3600; %infiltration and ventilation air: volume/hour 17 | 18 | % c: concrete; i: insulation; g: glass 19 | lamc = 2; lami = 0.04; lamg = 1.2; %[W/m K] 20 | rhoccc = 2.5e6; rhoici = 0.02e6; rhogcg = 2.0e6; %[J/m3 K] 21 | wc = 0.2; wi = 0.08; wg = 0.01; %[m] 22 | epswLW = 0.9; %long wave wall emmisivity 23 | epswSW = 0.8; %short wave wall emmisivity 24 | 25 | epsgLW = 0.9; %long wave glass emmisivity 26 | taugSW = 0.8; %short wave glass transmitance 27 | alphagSW = 0.2; %short wave glass absortivity 28 | 29 | sigma = 5.67e-8;%[W/m2 K4] 30 | Fwg = 1/5; %view factor wall - glass 31 | Tm = 20 + 273; %mean temp for radiative exchange 32 | 33 | % convection coefficients 34 | hi = 4; ho = 10; %[W/m2 K] 35 | %*************************** 36 | 37 | % Conductances and capacities 38 | Gc = lamc/wc*Sc; Cc = Sc*wc*rhoccc; %concrete 39 | Gcm = 2*nc*Gc*ones(1,2*nc); %meshed concrete 40 | Ccm = Cc/nc*mod(0:2*nc-1,2); 41 | 42 | Gi = lami/wi*Si; Ci = Si*wi*rhoici; %insulation 43 | Gim = 2*ni*Gi*ones(1,2*ni); %meshed insulation 44 | Cim = Ci/ni*mod(0:2*ni-1,2); 45 | 46 | Gg = lamg/wg*Sg; Cg = Sg*wg*rhogcg; %glass 47 | Ca = Va*rhoa*ca; 48 | % Ca =0; Cg = 0; % if air and glass are neglected 49 | 50 | % Convection 51 | Gwo = ho*Sc; Gwi = hi*Si; %convection wall out; wall in 52 | Ggo = ho*Sg; Ggi = hi*Sg; %convection glass out; glass in 53 | % Long wave radiative exchange 54 | GLW1 = epswLW/(1-epswLW)*Si*4*sigma*Tm^3; 55 | GLW2 = Fwg*Si*4*sigma*Tm^3; 56 | GLW3 = epsgLW/(1-epsgLW)*Sg*4*sigma*Tm^3; 57 | GLW = 1/(1/GLW1 + 1/GLW2 +1/GLW3); %long-wave exg. wall-glass 58 | % advection 59 | Gv = Vpa*rhoa*ca; %air ventilation 60 | % glass: convection outdoor & conduction 61 | Ggs = 1/(1/Ggo + 1/(2*Gg)); %cv+cd glass 62 | 63 | 64 | % Thermal network 65 | % ***************************************************************** 66 | % Dissembled circuit 67 | nq = 1+2*(nc+ni); nt = 1+2*(nc+ni); % no of flows & temps 68 | A1 = eye(nq+1,nt); % (#flows+1, #temp) 69 | A1 = -diff(A1,1,1)'; 70 | G1 = diag([Gwo Gcm Gim]'); 71 | b1 = zeros(nq,1); b1(1) = 1; 72 | C1 = diag([Ccm Cim 0]); 73 | f1 = zeros(nt,1); f1(1) = 1; f1(end) = 1; 74 | y1 = zeros(nt,1); 75 | TCd{1} = {A1,G1,b1,C1,f1,y1}; 76 | 77 | A2 = [-1 1 0; -1 0 1; 0 -1 1]; 78 | G2 = diag([GLW Gwi Ggi]'); 79 | b2 = [0 0 0]'; 80 | C2 = diag([0 0 Ca/2]'); 81 | f2 = [1 0 1]'; 82 | y2 = [0 0 1]'; 83 | TCd{2} = {A2,G2,b2,C2,f2,y2}; 84 | 85 | A3 = [1 0;-1 1]; 86 | G3 = diag([Ggs 2*Gg]); 87 | b3 = [1 0]'; 88 | C3 = diag([Cg 0]); 89 | f3 = [1 0]'; 90 | y3 = [0 0]'; 91 | TCd{3} = {A3,G3,b3,C3,f3,y3}; 92 | 93 | A4(1,1) = 1; 94 | A4(2,1) = 1; 95 | G4 = diag([Gv Kp]); 96 | b4 = [1 1]'; 97 | C4 = diag([Ca/2]); 98 | f4 = 1; 99 | y4 = 1; 100 | TCd{4} = {A4,G4,b4,C4,f4,y4}; 101 | 102 | % Assembling matrix 103 | AssX = [1 nt 2 1;...% TC1#5 <- TC2#1 104 | 2 2 3 2;... % TC2#2 <- TC3#2 105 | 2 3 4 1]; % TC2#3 <- TC4#1 106 | 107 | % Call Assembling function 108 | [TCa, Idx] = fTCAssAll(TCd, AssX); 109 | A = TCa{1}; G = TCa{2}; b = TCa{3}; C = TCa{4}; f = TCa{5}; y = TCa{6}; 110 | 111 | % Thermal model -> state-space 112 | % ********************************************************************* 113 | [Ac,Bc,Cc,Dc] = fTC2SS(A,G,b,C,f,y); % model with controller 114 | 115 | G4 = diag([Gv 1e-1]); % no controller: practically Kp = 0 116 | TCd{4} = {A4,G4,b4,C4,f4,y4}; 117 | [TCa, Idx] = fTCAssAll(TCd, AssX); 118 | A = TCa{1}; G = TCa{2}; b = TCa{3}; C = TCa{4}; f = TCa{5}; y = TCa{6}; 119 | [Af,Bf,Cf,Df] = fTC2SS(A,G,b,C,f,y); % model free-running 120 | 121 | % Maximum time-step 122 | dtmax = min([-2./eig(Ac) -2./eig(Af)])% [s] 123 | 124 | % Simulation 125 | % ********************************************************************* 126 | % Load weather data 127 | fileName = 'FRA_Lyon.csv'; 128 | from = 1*30*24 + 25*24; % start time: from 24 Jan. 129 | period = 10*24; % simulation period: for 10 days 130 | 131 | [Time,Temp,RadNDir,RadHDif,WDir,WSpeed,month,day,hour,minute]... 132 | = fReadWeather(fileName,from,period); 133 | 134 | B = 90; Z = 0; L = 45; albedo = 0.2; 135 | [PhiDir, PhiDif, PhiRef] = fSolRadTiltSurf(month, day, hour, minute, ... 136 | RadNDir, RadHDif, B, Z, L, albedo); 137 | 138 | % interpolate weather data for time step dt 139 | Temp = interp1(Time, Temp, [Time(1):dt:Time(end)]'); 140 | PhiDir = interp1(Time, PhiDir, [Time(1):dt:Time(end)]'); 141 | PhiDif = interp1(Time, PhiDif, [Time(1):dt:Time(end)]'); 142 | PhiRef = interp1(Time, PhiRef, [Time(1):dt:Time(end)]'); 143 | Time = [Time(1):dt:Time(end)]'; 144 | 145 | n = size(Time,1); 146 | nth = size(Ac,1); % no of state variables 147 | Qa = zeros(n,1); %auxiliary sources (electrical, persons, etc.) 148 | TintSP = 20*ones(n,1); 149 | 150 | % Inputs 151 | PhiTot = PhiDir + PhiDif + PhiRef; 152 | u = [Temp Temp Temp TintSP ... 153 | epswSW*Sc*PhiTot taugSW*epswSW*Sg*PhiTot alphagSW*Sg*PhiTot ... 154 | Qa]'; 155 | % Memory alocation and initial value 156 | % th = 20*ones(size(Ac,2),n); 157 | th = zeros(size(Ac,2),n); 158 | y = zeros(1,n); y(1) = TintSP(1); 159 | qHVAC = zeros(1,n); 160 | 161 | for k = 1:n-1 162 | if y(k) < TintSP(k) 163 | th(:,k+1) = (eye(nth) + dt*Ac)*th(:,k) + dt*Bc*u(:,k); 164 | y(:,k+1) = Cc*th(:,k+1) + Dc*u(:,k+1); 165 | % u(8,k) = 10000*(TintSP(k) - y(k)); 166 | % th(:,k+1) = (eye(nth) + dt*Af)*th(:,k) + dt*Bf*u(:,k); 167 | % y(:,k+1) = Cf*th(:,k+1) + Df*u(:,k+1); 168 | qHVAC(:,k+1) = Kp*(TintSP(k+1) - y(k+1)); 169 | else 170 | th(:,k+1) = (eye(nth) + dt*Af)*th(:,k) + dt*Bf*u(:,k); 171 | y(:,k+1) = Cf*th(:,k+1) + Df*u(:,k+1); 172 | qHVAC(:,k+1) = 1e-1*(TintSP(k+1) - y(k+1)); 173 | end 174 | % if y(k) < TintSP(k) 175 | % u(8,k) = K*(TintSP(k) - y(k)); 176 | % else 177 | % u(8,k) = 0; 178 | % end 179 | % th(:,k+1) = (eye(nth) + dt*Ac)*th(:,k) + dt*Bc*u(:,k); 180 | end 181 | subplot(3,1,1) 182 | plot(Time/3600,y,'g',Time/3600,TintSP,'r', Time/3600,Temp,'b') 183 | xlabel('Time [h]'),ylabel('T [C]') 184 | title('Simulation for weather') 185 | 186 | subplot(3,1,2) 187 | qHVAC = Kp.*(TintSP' - y); 188 | plot(Time/3600,qHVAC) 189 | xlabel('Time [h]'),ylabel('Q_h [W]') 190 | title('Q_h') 191 | %axis([0 inf -200 inf]) 192 | 193 | % Solar radiation 194 | subplot(3,1,3) 195 | plot(Time/(24*3600), PhiDir,'b'), hold on %direct on surface 196 | plot(Time/(24*3600), PhiDif,'r') % diffusif on surface 197 | plot(Time/(24*3600), PhiRef,'m') % reflected on surface 198 | xlabel('Time [days]'), ylabel('\Phi [W/m^2]') 199 | title('Solar radiation') 200 | legend('\Phi_d_i_r','\Phi_D_i_f', '\Phi_R_e_f_D_i_f') -------------------------------------------------------------------------------- /A03_DAE2SS.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "c699e824-98aa-4f81-a9a1-225c8560f8be", 6 | "metadata": {}, 7 | "source": [ 8 | "# From differential-algebraic equations to state-space representation" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "7baf2627-bf87-439c-b688-26d990f0d6f8", 14 | "metadata": {}, 15 | "source": [ 16 | "This demonstration is taken from [Ghiaus (2013)](https://doi.org/10.1016/j.energy.2012.10.024).\n", 17 | "\n", 18 | "Let's consider the system of diferential-algebraic equations (DAE) obtained from a thermal circuit:\n", 19 | "\n", 20 | "$$C \\dot{\\theta} = -A^T G A \\theta + A^T G b + f$$\n", 21 | "\n", 22 | "We want to transform these equation into [state-space representation](https://en.m.wikipedia.org/wiki/State-space_representation):\n", 23 | "\n", 24 | "$$\\begin{cases}\n", 25 | "\\dot{\\theta}_C = A_s \\theta_C + B_s u\\\\\n", 26 | "y = C_s \\theta_C + D_s u\n", 27 | "\\end{cases}$$\n", 28 | "\n", 29 | "We write the DAE as:\n", 30 | "\n", 31 | "$$C \\dot{\\theta} = K \\theta + K_b b + f$$\n", 32 | "\n", 33 | "where $K = -A^T G A$ and $K_b = A^T G$.\n", 34 | "\n", 35 | "We write this equation in block matrices corresponding to nodes without capacities, $\\theta_0$, and to nodes with capacities, $\\theta_C$:\n", 36 | "\n", 37 | "$\\begin{bmatrix}\n", 38 | "0 & 0\\\\ \n", 39 | "0 & C_C\n", 40 | "\\end{bmatrix}$\n", 41 | "$\\begin{bmatrix}\n", 42 | "\\dot{\\theta}_0\\\\ \n", 43 | "\\dot{\\theta}_C\n", 44 | "\\end{bmatrix}$\n", 45 | "=\n", 46 | "$\\begin{bmatrix}\n", 47 | "K_{11} & K_{12}\\\\ \n", 48 | "K_{21} & K_{22} \n", 49 | "\\end{bmatrix}$\n", 50 | "$\\begin{bmatrix}\n", 51 | "\\theta_0\\\\ \n", 52 | "\\theta_C\n", 53 | "\\end{bmatrix} +$\n", 54 | "$\\begin{bmatrix}\n", 55 | "K_{b1}\\\\ \n", 56 | "K_{b2} \n", 57 | "\\end{bmatrix}b +$\n", 58 | "$\\begin{bmatrix}\n", 59 | "I_{11} & 0\\\\ \n", 60 | "0 & I_{22} \n", 61 | "\\end{bmatrix}$\n", 62 | "$\\begin{bmatrix}\n", 63 | "f_0\\\\ \n", 64 | "f_C \n", 65 | "\\end{bmatrix}$\n", 66 | "\n", 67 | "where:\n", 68 | "\n", 69 | "$C = \\begin{bmatrix}\n", 70 | "0 & 0\\\\ \n", 71 | "0 & C_C\n", 72 | "\\end{bmatrix}$ - matrix of capacities separated in blocks of capacities equal to zero and capacities different of zero, grouped in the diagonal matrix $C_C$.\n", 73 | "\n", 74 | "$K = -A^T G A = \\begin{bmatrix}\n", 75 | "K_{11} & K_{12}\\\\ \n", 76 | "K_{21} & K_{22} \n", 77 | "\\end{bmatrix}$\n", 78 | "\n", 79 | "$K_b = A^T G = \\begin{bmatrix}\n", 80 | "K_{b1}\\\\ \n", 81 | "K_{b2} \n", 82 | "\\end{bmatrix}$\n", 83 | "\n", 84 | "$I_{11}$ and $I_{22}$ are [identity matrices](https://en.m.wikipedia.org/wiki/Identity_matrix) of size of $\\theta_0$ and $\\theta_C$,, respectively.\n", 85 | "\n", 86 | "By multiplying the first row with $-K_{21}K_{11}^{-1}$, we obtain:\n", 87 | "\n", 88 | "$\\begin{bmatrix}\n", 89 | "0 & 0\\\\ \n", 90 | "0 & C_C\n", 91 | "\\end{bmatrix}$\n", 92 | "$\\begin{bmatrix}\n", 93 | "\\dot{\\theta}_0\\\\ \n", 94 | "\\dot{\\theta}_C\n", 95 | "\\end{bmatrix}=$\n", 96 | "$\\begin{bmatrix}\n", 97 | "-K_{21} & -K_{21} K_{11}^{-1} K_{12}\\\\ \n", 98 | "K_{21} & K_{22} \n", 99 | "\\end{bmatrix}$\n", 100 | "$\\begin{bmatrix}\n", 101 | "\\theta_0\\\\ \n", 102 | "\\theta_C\n", 103 | "\\end{bmatrix}+$\n", 104 | "$\\begin{bmatrix}\n", 105 | "-K_{21} K_{11}^{-1} K_{b1}\\\\ \n", 106 | "K_{b2} \n", 107 | "\\end{bmatrix}b +$\n", 108 | "$\\begin{bmatrix}\n", 109 | "-K_{21} K_{11}^{-1} & 0\\\\ \n", 110 | "0 & I_{22} \n", 111 | "\\end{bmatrix}$\n", 112 | "$\\begin{bmatrix}\n", 113 | "f_0\\\\ \n", 114 | "f_C \n", 115 | "\\end{bmatrix}$\n", 116 | "\n", 117 | "By adding the two rows, we obtain:\n", 118 | "\n", 119 | "$\\begin{bmatrix} \n", 120 | "0 & C_C\n", 121 | "\\end{bmatrix}$\n", 122 | "$\\begin{bmatrix}\n", 123 | "\\dot{\\theta}_0\\\\ \n", 124 | "\\dot{\\theta}_C\n", 125 | "\\end{bmatrix} =$\n", 126 | "$\\begin{bmatrix}\n", 127 | "0 & -K_{21} K_{11}^{-1} K_{12} + K_{22} \n", 128 | "\\end{bmatrix}$\n", 129 | "$\\begin{bmatrix}\n", 130 | "\\theta_0\\\\ \n", 131 | "\\theta_C\n", 132 | "\\end{bmatrix}+$\n", 133 | "$\\begin{bmatrix} \n", 134 | "-K_{21} K_{11}^{-1} K_{b1} + K_{b2} \n", 135 | "\\end{bmatrix}b+$\n", 136 | "$\\begin{bmatrix} \n", 137 | "-K_{21} K_{11}^{-1} & I_{22} \n", 138 | "\\end{bmatrix}$\n", 139 | "$\\begin{bmatrix}\n", 140 | "f_0\\\\ \n", 141 | "f_C \n", 142 | "\\end{bmatrix}$\n", 143 | "\n", 144 | "Since the matrix $C_C$ is [invertible](https://en.m.wikipedia.org/wiki/Invertible_matrix),\n", 145 | "the above equation becomes:\n", 146 | "\n", 147 | "$\\dot{\\theta}_C = C_C^{—1}$\n", 148 | "$\\begin{bmatrix}\n", 149 | "-K_{21} K_{11}^{-1} K_{12} + K_{22}\n", 150 | "\\end{bmatrix}\\theta_C$ + \n", 151 | "$C^{-1}(-K_{21} K_{11}^{-1} K_{b1} + K_{b2})b$ +\n", 152 | "$\\begin{bmatrix} \n", 153 | "-K_{21} K_{11}^{-1} & I_{22} \n", 154 | "\\end{bmatrix}$\n", 155 | "$\\begin{bmatrix}\n", 156 | "f_0\\\\ \n", 157 | "f_C \n", 158 | "\\end{bmatrix}$\n", 159 | "\n", 160 | "By grouping all sources into a vector of inputs,\n", 161 | "$u = \\begin{bmatrix}\n", 162 | "b \\\\ f_0 \\\\ f_C\n", 163 | "\\end{bmatrix}$,\n", 164 | "\n", 165 | "we obtain:\n", 166 | "\n", 167 | "$\\dot{\\theta}_C = C_C^{—1}$\n", 168 | "$\\begin{bmatrix}\n", 169 | "-K_{21} K_{11}^{-1} K_{12} + K_{22}\n", 170 | "\\end{bmatrix}\\theta_C$+ \n", 171 | "$C_C^{-1}$\n", 172 | "$\\begin{bmatrix} \n", 173 | "-K_{21} K_{11}^{-1} K_{b1} + K_{b2} &\n", 174 | "-K_{21} K_{11}^{-1} & I_{22}\n", 175 | "\\end{bmatrix}$\n", 176 | "$\\begin{bmatrix}\n", 177 | "b\\\\\n", 178 | "f_0\\\\ \n", 179 | "f_C \n", 180 | "\\end{bmatrix}$\n", 181 | "\n", 182 | "which represents the state equation of the [state-space representation](https://en.m.wikipedia.org/wiki/State-space_representation):\n", 183 | "\n", 184 | "$$\\begin{cases}\n", 185 | "\\dot{\\theta}_C = A_s \\theta_C + B_s u\\\\\n", 186 | "\\theta_0 = C_s \\theta_C + D_s u\n", 187 | "\\end{cases}$$\n", 188 | "\n", 189 | "where:\n", 190 | "\n", 191 | "$A_s= C_C^{—1}[-K_{21} K_{11}^{-1} K_{12} + K_{22}]$\n", 192 | "\n", 193 | "$B_s = C_C^{-1}$\n", 194 | "$\\begin{bmatrix} \n", 195 | "-K_{21} K_{11}^{-1} K_{b1} + K_{b2} &\n", 196 | "-K_{21} K_{11}^{-1} & I_{22}\n", 197 | "\\end{bmatrix}$\n", 198 | "\n", 199 | "$C_s = -K_{11}^{-1} K_{12}$\n", 200 | "\n", 201 | "$D_s = -K_{11}^{-1} \\begin{bmatrix} K_{b1} & I_{11} & 0 \\end{bmatrix}$\n", 202 | "\n", 203 | "$\\theta_C$ - vector of temperatures in nodes with capacities.\n", 204 | "\n", 205 | "$\\theta_0$ - vector of temperatures in nodes without capacities.\n", 206 | "\n", 207 | "$u = \\begin{bmatrix}\n", 208 | "b \\\\ f_0 \\\\ f_C\n", 209 | "\\end{bmatrix}$, vector of inputs, where $b$ is the vector of temperature sources, $f_0$ and $f_C$ are the vector of flow-rate sources in the nodes without capacities and the nodes with capacities, respectively.\n", 210 | "\n", 211 | "After solving for temperatures, the flows can be obtained:\n", 212 | "\n", 213 | "$$q = G(-A \\theta + b)$$\n", 214 | "\n", 215 | "The transformation from the system of differential-algebraic equations (DAE) to state-space representation is implemented in the function `tc2ss` of module `dm4bem`." 216 | ] 217 | }, 218 | { 219 | "cell_type": "markdown", 220 | "id": "716967ce-95a4-4e7d-a8f0-d6fbeb770187", 221 | "metadata": {}, 222 | "source": [ 223 | "## References\n", 224 | "\n", 225 | "Ghiaus, C. (2013) Causality issue in the heat balance method for calculating the design heating and cooling loads, *Energy* 50: 292-301, https://doi.org/10.1016/j.energy.2012.10.024, [hal-03605823](https://hal.archives-ouvertes.fr/hal-03605823/document)\n", 226 | "\n", 227 | "C. Ghiaus (2021). Dynamic Models for Energy Control of Smart Homes, in *S. Ploix M. Amayri, N. Bouguila (eds.) Towards Energy Smart Homes*, Online ISBN: 978-3-030-76477-7, Print ISBN: 978-3-030-76476-0, Springer, pp. 163-198 (ref.)\n", 228 | "[DOI 10.1007/978-3-030-76477-7_5](https://doi.org/10.1007/978-3-030-76477-7_5), [HAL 03578578](https://hal.archives-ouvertes.fr/hal-03578578/document)" 229 | ] 230 | }, 231 | { 232 | "cell_type": "code", 233 | "execution_count": null, 234 | "id": "838911b4-2341-4e8a-9b02-41df70e8217a", 235 | "metadata": {}, 236 | "outputs": [], 237 | "source": [] 238 | } 239 | ], 240 | "metadata": { 241 | "kernelspec": { 242 | "display_name": "Python 3 (ipykernel)", 243 | "language": "python", 244 | "name": "python3" 245 | }, 246 | "language_info": { 247 | "codemirror_mode": { 248 | "name": "ipython", 249 | "version": 3 250 | }, 251 | "file_extension": ".py", 252 | "mimetype": "text/x-python", 253 | "name": "python", 254 | "nbconvert_exporter": "python", 255 | "pygments_lexer": "ipython3", 256 | "version": "3.9.7" 257 | } 258 | }, 259 | "nbformat": 4, 260 | "nbformat_minor": 5 261 | } 262 | -------------------------------------------------------------------------------- /pd/03assembleTCd.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "57654529-c23a-46d7-a54b-dbb1d0f7351e", 6 | "metadata": {}, 7 | "source": [ 8 | "# Assembled thermal circuits (from matrix and lists)\n", 9 | "\n", 10 | "This notebook shows how a set of _disassembled thermal circuits_ is assembled into a single thermal circuit. The assembling can be by using assembling matrix or assembling lits. The assembling from matrix is implemented in the functions `assemble_TCd_matrix`. To assemble from lists, first the assembling lists are transformed in assembly matrix." 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "id": "13d93595-c53e-4840-a864-965e6588ad05", 17 | "metadata": { 18 | "tags": [] 19 | }, 20 | "outputs": [], 21 | "source": [ 22 | "import pandas as pd\n", 23 | "import pd_dm4bem" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "id": "01c03148-cf6e-4b7a-9de0-62568691909d", 29 | "metadata": {}, 30 | "source": [ 31 | "## Stating the problem\n", 32 | "Consider the disassembled thermal circuits shown in Figure 1 that we want to assemble as shown in Figure 2.\n", 33 | "\n", 34 | "![disassambled_TC](./bldg/ass_TCd.svg)\n", 35 | "> Figure 1. Four disassembled thermal circuits: wall_out, TC0, TC1, TC2, TC3.\n", 36 | "\n", 37 | "![disassambled_TC](./bldg/ass_TC.svg)\n", 38 | "> Figure 2. The assembling of the four circuits from Figure 1." 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "id": "e49c8b32-a6d3-43b6-81d5-fa21625ca4c0", 44 | "metadata": {}, 45 | "source": [ 46 | "## Description of the folder containing the circuits\n", 47 | "The disassembled circuits and the indications on how to assemble them are given in the folder `.\\bldg` composed by the files (see _Walls data_ in [01wall2TC.ipynb](01wall2TC.ipynb)):\n", 48 | "- assembly:\n", 49 | " - `assembly_lists.csv`: lists with the nodes that merge;\n", 50 | " - `assembly_matrix.csv`: matrix with the nodes that merge;\n", 51 | "- thermal circuits: `TC0.csv, ... , TC3.csv`;\n", 52 | "- walls:\n", 53 | " - `wall_types.csv`: physical properties and width of each mayerial; \n", 54 | " - `walls_out.csv`: geometric and surface characteristics of each wall. " 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "id": "4f35b81e-aa34-40cc-85dd-033ba700736f", 60 | "metadata": {}, 61 | "source": [ 62 | "## Assembling\n", 63 | "\n", 64 | "In order to obtain the assembled circuit, first we need to construct the disassembled thermal circuits `TCd`. The numbering of the thermal circuits `TC` can be automatic or the symbols given in `TC_.csv` files can be used." 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": 2, 70 | "id": "f5f04393-cd31-4492-b621-31e71b8345dc", 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "folder_path = 'bldg'\n", 75 | "\n", 76 | "# Disassembled thermal circuits\n", 77 | "TCd = pd_dm4bem.bldg2TCd(folder_path,\n", 78 | " TC_auto_number=True)" 79 | ] 80 | }, 81 | { 82 | "cell_type": "markdown", 83 | "id": "a2e2f0e7-9f8e-43c2-9ff1-11127ef449d9", 84 | "metadata": {}, 85 | "source": [ 86 | "### Use of assembling matrix\n", 87 | "Then, we can obtain the assembled thermal circuits by using the assembly matrix." 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": 3, 93 | "id": "2a6d7d72-55a8-4513-ac88-598803e40745", 94 | "metadata": {}, 95 | "outputs": [], 96 | "source": [ 97 | "# Assembled thermal circuit from assembly_matrix.csv\n", 98 | "ass_mat = pd.read_csv(folder_path + '/assembly_matrix.csv')\n", 99 | "TCm = pd_dm4bem.assemble_TCd_matrix(TCd, ass_mat)\n", 100 | "# pd_dm4bem.print_TC(TCm)" 101 | ] 102 | }, 103 | { 104 | "cell_type": "markdown", 105 | "id": "f438bc00-c8b6-4582-a356-3534d0633f7d", 106 | "metadata": {}, 107 | "source": [ 108 | "### Use of assembling lists\n", 109 | "Alternatively, we can obtain the assembled circuit by using the assembly lists." 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": 4, 115 | "id": "92c0aad5-7d22-4670-ad2e-c10592f187e7", 116 | "metadata": {}, 117 | "outputs": [], 118 | "source": [ 119 | "# Assembled thermal circuit from assembly_lists.csv\n", 120 | "ass_lists = pd.read_csv(folder_path + '/assembly_lists.csv')\n", 121 | "ass_mat = pd_dm4bem.assemble_lists2matrix(ass_lists)\n", 122 | "TCl = pd_dm4bem.assemble_TCd_matrix(TCd, ass_mat)" 123 | ] 124 | }, 125 | { 126 | "cell_type": "markdown", 127 | "id": "a3abfe4a-6860-4b45-ab4a-481ed5c5236e", 128 | "metadata": {}, 129 | "source": [ 130 | "The otained thermal circuit has all the branches of the set of disassembled circuits but fewer nodes (Figure 2). " 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 5, 136 | "id": "76184b44-6208-4b20-8b17-1add777ccc0e", 137 | "metadata": {}, 138 | "outputs": [ 139 | { 140 | "name": "stdout", 141 | "output_type": "stream", 142 | "text": [ 143 | "A:\n", 144 | " c1_θ0 c1_θ1 c2_θ0 ow0_θ0 ow0_θ1 ow0_θ2 ow0_θ3 ow0_θ4\n", 145 | "c0_q0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 -1.0\n", 146 | "c1_q0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 147 | "c1_q1 -1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0\n", 148 | "c1_q2 0.0 -1.0 1.0 0.0 0.0 0.0 0.0 0.0\n", 149 | "c2_q0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0\n", 150 | "c3_q0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0\n", 151 | "ow0_q0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0\n", 152 | "ow0_q1 0.0 0.0 0.0 -1.0 1.0 0.0 0.0 0.0\n", 153 | "ow0_q2 0.0 0.0 0.0 0.0 -1.0 1.0 0.0 0.0\n", 154 | "ow0_q3 0.0 0.0 0.0 0.0 0.0 -1.0 1.0 0.0\n", 155 | "ow0_q4 0.0 0.0 0.0 0.0 0.0 0.0 -1.0 1.0\n", 156 | "ow0_q5 0.0 0.0 1.0 0.0 0.0 0.0 0.0 -1.0 \n", 157 | "\n", 158 | "G:\n", 159 | "c0_q0 44.7868\n", 160 | "c1_q0 165.7890\n", 161 | "c1_q1 630.0000\n", 162 | "c1_q2 72.0000\n", 163 | "c2_q0 9.0000\n", 164 | "c3_q0 1000000.0000\n", 165 | "ow0_q0 1125.0000\n", 166 | "ow0_q1 630.0000\n", 167 | "ow0_q2 630.0000\n", 168 | "ow0_q3 30.3750\n", 169 | "ow0_q4 30.3750\n", 170 | "ow0_q5 360.0000\n", 171 | "dtype: float64 \n", 172 | "\n", 173 | "C:\n", 174 | "c1_θ0 1089000.0\n", 175 | "c1_θ1 0.0\n", 176 | "c2_θ0 32400.0\n", 177 | "ow0_θ0 0.0\n", 178 | "ow0_θ1 18216000.0\n", 179 | "ow0_θ2 0.0\n", 180 | "ow0_θ3 239580.0\n", 181 | "ow0_θ4 0.0\n", 182 | "dtype: float64 \n", 183 | "\n", 184 | "b:\n", 185 | "c0_q0 0\n", 186 | "c1_q0 To\n", 187 | "c1_q1 0\n", 188 | "c1_q2 0\n", 189 | "c2_q0 To\n", 190 | "c3_q0 Ti_sp\n", 191 | "ow0_q0 To\n", 192 | "ow0_q1 0\n", 193 | "ow0_q2 0\n", 194 | "ow0_q3 0\n", 195 | "ow0_q4 0\n", 196 | "ow0_q5 0\n", 197 | "dtype: object \n", 198 | "\n", 199 | "f:\n", 200 | "c1_θ0 Φ\n", 201 | "c1_θ1 0\n", 202 | "c2_θ0 Qa\n", 203 | "ow0_θ0 Qo\n", 204 | "ow0_θ1 0\n", 205 | "ow0_θ2 0\n", 206 | "ow0_θ3 0\n", 207 | "ow0_θ4 Qi\n", 208 | "dtype: object \n", 209 | "\n", 210 | "y:\n", 211 | "c1_θ0 0.0\n", 212 | "c1_θ1 0.0\n", 213 | "c2_θ0 3.0\n", 214 | "ow0_θ0 1.0\n", 215 | "ow0_θ1 0.0\n", 216 | "ow0_θ2 0.0\n", 217 | "ow0_θ3 0.0\n", 218 | "ow0_θ4 0.0\n", 219 | "dtype: float64 \n", 220 | "\n" 221 | ] 222 | } 223 | ], 224 | "source": [ 225 | "pd_dm4bem.print_TC(TCl)" 226 | ] 227 | }, 228 | { 229 | "cell_type": "markdown", 230 | "id": "a735839c-a3fb-44d7-a9d8-ac19bebf0a27", 231 | "metadata": {}, 232 | "source": [ 233 | "Note that the nodes which are faded in Figure 2 (c0_θ0, c0_θ1, c1_θ2, c3_θ0 and ow0_θ5) do not exist anymore in the assembeled thermal circuit since they were merged with the primary nodes." 234 | ] 235 | }, 236 | { 237 | "cell_type": "code", 238 | "execution_count": null, 239 | "id": "c76f634b-b9e2-4237-aa82-1f149f9bd5e9", 240 | "metadata": {}, 241 | "outputs": [], 242 | "source": [] 243 | } 244 | ], 245 | "metadata": { 246 | "kernelspec": { 247 | "display_name": "Python 3 (ipykernel)", 248 | "language": "python", 249 | "name": "python3" 250 | }, 251 | "language_info": { 252 | "codemirror_mode": { 253 | "name": "ipython", 254 | "version": 3 255 | }, 256 | "file_extension": ".py", 257 | "mimetype": "text/x-python", 258 | "name": "python", 259 | "nbconvert_exporter": "python", 260 | "pygments_lexer": "ipython3", 261 | "version": "3.9.7" 262 | }, 263 | "toc-autonumbering": true 264 | }, 265 | "nbformat": 4, 266 | "nbformat_minor": 5 267 | } 268 | -------------------------------------------------------------------------------- /py/02SimpleWall.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Sat Mar 11 21:26:29 2023 5 | 6 | @author: cghiaus 7 | """ 8 | 9 | import numpy as np 10 | import pandas as pd 11 | import matplotlib.pyplot as plt 12 | import dm4bem 13 | 14 | 15 | # Physical characteristics 16 | # ======================== 17 | concrete = {'Conductivity': 1.400, # W/(m⋅K) 18 | 'Density': 2300.0, # kg/m³ 19 | 'Specific heat': 880, # J/(kg⋅K) 20 | 'Width': 0.2} # m 21 | 22 | insulation = {'Conductivity': 0.040, # W/(m⋅K) 23 | 'Density': 16.0, # kg/m³ 24 | 'Specific heat': 1210, # J/(kg⋅K) 25 | 'Width': 0.08} # m 26 | 27 | wall = pd.DataFrame.from_dict({'Layer_1': concrete, 28 | 'Layer_2': insulation}, 29 | orient='index') 30 | 31 | air = {'Density': 1.2, # kg/m³ 32 | 'Specific heat': 1000} # J/(kg⋅K) 33 | 34 | # convection coefficients, W/(m²·K) 35 | h = pd.DataFrame([{'in': 4., 'out': 10.}], index=['h']) 36 | 37 | S_wall = 3 * 3 # m², wall surface area 38 | V_air = 3 * 3 * 3 # m³, indoor air volume 39 | 40 | # Resistances 41 | # conduction 42 | R_cd = wall['Width'] / (wall['Conductivity'] * S_wall) # K/W 43 | # convection 44 | R_cv = 1 / (h * S_wall) # K/W 45 | 46 | # Capacities 47 | C_wall = wall['Density'] * wall['Specific heat'] * wall['Width'] * S_wall 48 | C_air = air['Density'] * air['Specific heat'] * V_air 49 | 50 | # Differential-algebraic equations (DAE) 51 | # ===================================== 52 | # number of temperature nodes and flow branches 53 | no_θ = no_q = 7 54 | 55 | # Conductance matrix 56 | R = np.zeros([no_q]) 57 | R[0] = R_cv['out'] + R_cd['Layer_1'] / 8 58 | R[1] = R[2] = R[3] = R_cd['Layer_1'] / 4 59 | R[4] = R_cd['Layer_1'] / 8 + R_cd['Layer_2'] / 4 60 | R[5] = R_cd['Layer_2'] / 2 61 | R[6] = R_cd['Layer_2'] / 4 + R_cv['in'] 62 | G = np.diag(np.reciprocal(R)) 63 | 64 | # Capacity matrix 65 | C = np.zeros(no_θ) 66 | C[0] = C[1] = C[2] = C[3] = C_wall['Layer_1'] / 4 67 | C[4] = C[5] = C_wall['Layer_2'] / 2 68 | C[6] = C_air 69 | C = np.diag(C) 70 | 71 | # Arc-node incidence matrix 72 | A = np.eye(no_q, no_θ + 1) 73 | A = -np.diff(A, n=1, axis=1) 74 | 75 | # Input vectors 76 | b = np.zeros(no_q) # temperatures 77 | f = np.zeros(no_θ) # flow rates 78 | 79 | # Steady-state solution from DAE) 80 | b[0] = 1 81 | θ_steady_To = np.linalg.inv(A.T @ G @ A) @ (A.T @ G @ b + f) 82 | np.set_printoptions(precision=3) 83 | print('When To = 1°C, temperatures in steady-state are:', θ_steady_To, '°C') 84 | print(f'The indoor temperature is: {θ_steady_To[-1]:.3f} °C') 85 | 86 | b[0] = 0 87 | f[-1] = 1 88 | θ_steady_Qh = np.linalg.inv(A.T @ G @ A) @ (A.T @ G @ b + f) 89 | print('When Qh = 1W, temperatures in steady-state are:', θ_steady_Qh, '°C') 90 | print(f'The indoor temperature is: {θ_steady_Qh[-1]:.3f} °C') 91 | 92 | # State-space representation 93 | # ========================== 94 | # State matrix 95 | As = -np.linalg.inv(C) @ A.T @ G @ A 96 | 97 | # Input matrix 98 | Bs = np.linalg.inv(C) @ np.block([A.T @ G, np.eye(no_θ)]) 99 | # Select columns for which the input vector is not zero 100 | # 1st for To and last for Qh 101 | Bs = Bs[:, [0, -1]] 102 | 103 | # Output matrix 104 | Cs = np.zeros((1, no_θ)) 105 | # output: last temperature node 106 | Cs[:, -1] = 1 107 | 108 | # Feedthrough (or feedforward) matrix 109 | Ds = np.zeros(Bs.shape[1]) 110 | 111 | # Eigenvalues 112 | λ = np.linalg.eig(As)[0] # minimum eigenvalue of matrix A 113 | max_Δt = min(-2 / λ) 114 | 115 | np.set_printoptions(precision=1) 116 | print('Time constants: \n', -1 / λ, 's \n') 117 | print('3 x Time constants: \n', -3 / λ, 's \n') 118 | print(f'Max time step Δt = {max_Δt:.2f} s') 119 | 120 | # time step 121 | Δt = np.floor(max_Δt / 60) * 60 # s 122 | print(f'Δt = {Δt} s') 123 | 124 | # settling time 125 | t_settle = 4 * max(-1 / λ) 126 | print(f'Settling time: {t_settle:.2f} s = {t_settle / 3600:.2f} h') 127 | 128 | # Time integration 129 | # ================ 130 | 131 | # Step input 132 | # ---------- 133 | 134 | # number of time steps 135 | n = int(np.ceil(t_settle / Δt)) 136 | # time vector 137 | t = np.arange(0, n * Δt, Δt) 138 | pd.DataFrame(t, columns=['time']) 139 | 140 | # outdoor temperature 141 | # ------------------- 142 | u = np.block([[np.ones([1, n])], # To = [1, 1, ... , 1] 143 | [np.zeros([1, n])]]) # Qh = [0, 0, ... , 0] 144 | 145 | # initial values for temperatures obtained by explicit and implicit Euler 146 | θ_exp = np.zeros([no_θ, t.shape[0]]) 147 | θ_imp = np.zeros([no_θ, t.shape[0]]) 148 | 149 | # time integration: Euler explicit & implicit 150 | for k in range(t.shape[0] - 1): 151 | θ_exp[:, k + 1] = (np.eye(no_θ) + Δt * As) @\ 152 | θ_exp[:, k] + Δt * Bs @ u[:, k] 153 | θ_imp[:, k + 1] = np.linalg.inv(np.eye(no_θ) - Δt * As) @\ 154 | (θ_imp[:, k] + Δt * Bs @ u[:, k]) 155 | 156 | # plot results 157 | fig, ax = plt.subplots() 158 | ax.plot(t / 3600, θ_exp[-1, :], t / 3600, θ_imp[-1, :]) 159 | ax.set(xlabel='Time [h]', 160 | ylabel='Air temperature [°C]', 161 | title='Step input: $T_o$') 162 | ax.legend(['Explicit', 'Implicit']) 163 | plt.show() 164 | 165 | # indoor heat flow rate 166 | # --------------------- 167 | u = np.block([[np.zeros([1, n])], # To = [0, 0, ... , 0] 168 | [np.ones([1, n])]]) # Qh = [1, 1, ... , 1] 169 | 170 | # initial values for temperatures obtained by explicit and implicit Euler 171 | θ_exp = np.zeros([no_θ, t.shape[0]]) 172 | θ_imp = np.zeros([no_θ, t.shape[0]]) 173 | 174 | # time integration: Euler explicit & implicit 175 | for k in range(t.shape[0] - 1): 176 | θ_exp[:, k + 1] = (np.eye(no_θ) + Δt * As) @\ 177 | θ_exp[:, k] + Δt * Bs @ u[:, k] 178 | θ_imp[:, k + 1] = np.linalg.inv(np.eye(no_θ) - Δt * As) @\ 179 | (θ_imp[:, k] + Δt * Bs @ u[:, k]) 180 | 181 | # plot results 182 | fig, ax = plt.subplots() 183 | ax.plot(t / 3600, θ_exp[-1, :], t / 3600, θ_imp[-1, :]) 184 | ax.set(xlabel='Time [h]', 185 | ylabel='Air temperature [°C]', 186 | title='Step input: $T_o$') 187 | ax.legend(['Explicit', 'Implicit']) 188 | plt.show() 189 | 190 | # Simulation with outdoor temperature from weather data 191 | # ----------------------------------------------------- 192 | # Outdoor temperature from weather data 193 | filename = './weather_data/FRA_Lyon.074810_IWEC.epw' 194 | start_date = '2000-04-10' 195 | end_date = '2000-05-15' 196 | 197 | [data, meta] = dm4bem.read_epw(filename, coerce_year=None) 198 | weather = data[["temp_air", "dir_n_rad", "dif_h_rad"]] 199 | del data 200 | weather.index = weather.index.map(lambda t: t.replace(year=2000)) 201 | weather = weather[( 202 | weather.index >= start_date) & ( 203 | weather.index < end_date)] 204 | 205 | # time vector for weather data at 1 h time step 206 | tw = np.arange(0, 3600 * weather.shape[0], 3600) 207 | 208 | # time vector for simulation 209 | t = np.arange(0, 3600 * weather.shape[0], Δt) 210 | 211 | # resample outdoor temperature at timestep Δt 212 | θ_out = np.interp(t, tw, weather['temp_air']) 213 | 214 | # input vector [To, Qh] 215 | u = np.block([[θ_out], 216 | [np.zeros(θ_out.shape[0])]]) 217 | 218 | # initial coditions 219 | θ_exp = 20 * np.ones([no_θ, t.shape[0]]) 220 | θ_imp = 20 * np.ones([no_θ, t.shape[0]]) 221 | 222 | # time integration: Euler explicit & implicit 223 | for k in range(u.shape[1] - 1): 224 | θ_exp[:, k + 1] = (np.eye(no_θ) + Δt * As) @\ 225 | θ_exp[:, k] + Δt * Bs @ u[:, k] 226 | θ_imp[:, k + 1] = np.linalg.inv(np.eye(no_θ) - Δt * As) @\ 227 | (θ_imp[:, k] + Δt * Bs @ u[:, k]) 228 | 229 | # plot results 230 | fig, ax = plt.subplots() 231 | ax.plot(t / 3600 / 24, θ_out, label='Outdoor temperature') 232 | ax.plot(t / 3600 / 24, θ_exp[-1, :], label='Indoor temperature') 233 | ax.set(xlabel='Time [days]', 234 | ylabel='Air temperature [°C]', 235 | title='Explicit Euler') 236 | ax.legend() 237 | plt.show() 238 | 239 | # Simulation with outdoor temperature from weather data with Pandas 240 | # ----------------------------------------------------------------- 241 | start_date = '2000-04-10' 242 | end_date = '2000-05-15' 243 | 244 | # read data and keep air temperature 245 | filename = './weather_data/FRA_Lyon.074810_IWEC.epw' 246 | [data, meta] = dm4bem.read_epw(filename, coerce_year=None) 247 | weather = data[["temp_air"]].copy() 248 | del data 249 | 250 | # replace years with year 2000 and select time interval 251 | weather.index = weather.index.map(lambda t: t.replace(year=2000)) 252 | weather = weather.loc[start_date:end_date] 253 | 254 | # resample weather data 255 | data = weather['temp_air'] 256 | data = data.resample(str(Δt) + 'S').interpolate(method='linear') 257 | data = data.rename('To').to_frame() 258 | 259 | # indoor auxiliary heat 260 | data['Qa'] = 0 * np.ones(data.shape[0]) 261 | 262 | # input vector 263 | u = data[['To', 'Qa']] 264 | 265 | # initial conditions 266 | θ_exp = 20 * np.ones([As.shape[0], u.shape[0]]) 267 | θ_imp = 20 * np.ones([As.shape[0], u.shape[0]]) 268 | 269 | # time integration: Euler explicit & implicit 270 | n_states = As.shape[0] 271 | I = np.eye(n_states) 272 | 273 | for k in range(u.shape[0] - 1): 274 | θ_exp[:, k + 1] = (I + Δt * As) @ θ_exp[:, k]\ 275 | + Δt * Bs @ u.iloc[k, :] 276 | θ_imp[:, k + 1] = np.linalg.inv(I - Δt * As) @\ 277 | (θ_imp[:, k] + Δt * Bs @ u.iloc[k, :]) 278 | 279 | data['θi_exp'] = θ_exp[-1, :] 280 | data['θi_imp'] = θ_imp[-1, :] 281 | 282 | ax = data[['To', 'θi_exp']].plot() 283 | # data[['To', 'θi_exp', 'θi_imp']].plot() 284 | ax.legend(['Outdoor temperature', 'Indoor temperature']) 285 | ax.set(xlabel='Time', 286 | ylabel='Air temperature [°C]', 287 | title='Explicit Euler') 288 | plt.show() 289 | -------------------------------------------------------------------------------- /py/03CubicBuilding.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Sun Mar 12 21:31:57 2023 5 | 6 | @author: cghiaus 7 | 8 | Thermal circuit and state-space representation for a thermal circuit 9 | with capacities in some nodes: cubic building 10 | """ 11 | 12 | import numpy as np 13 | import pandas as pd 14 | import matplotlib.pyplot as plt 15 | import dm4bem 16 | 17 | 18 | # Physical analysis 19 | # ================= 20 | l = 3 # m length of the cubic room 21 | Sg = l**2 # m² surface of the glass wall 22 | Sc = Si = 5 * Sg # m² surface of concrete & insulation of the 5 walls 23 | 24 | # Thermo-physical properties 25 | air = {'Density': 1.2, # kg/m³ 26 | 'Specific heat': 1000} # J/(kg·K) 27 | 28 | wall = {'Conductivity': [1.4, 0.027, 1.4], # W/(m·K) 29 | 'Density': [2300, 55, 2500], # kg/m³ 30 | 'Specific heat': [880, 1210, 750], # J/(kg·K) 31 | 'Width': [0.2, 0.08, 0.004], 32 | 'Surface': [5 * l**2, 5 * l**2, l**2], # m² 33 | 'Slices': [1, 1, 1]} # number of slices 34 | wall1 = pd.DataFrame(wall, index=['Concrete', 'Insulation', 'Glass']) 35 | 36 | concrete = {'Conductivity': 1.400, 37 | 'Density': 2300.0, 38 | 'Specific heat': 880, 39 | 'Width': 0.2, 40 | 'Surface': 5 * l**2} 41 | 42 | insulation = {'Conductivity': 0.027, 43 | 'Density': 55.0, 44 | 'Specific heat': 1210, 45 | 'Width': 0.08, 46 | 'Surface': 5 * l**2} 47 | 48 | glass = {'Conductivity': 1.4, 49 | 'Density': 2500, 50 | 'Specific heat': 1210, 51 | 'Width': 0.04, 52 | 'Surface': l**2} 53 | 54 | wall = pd.DataFrame.from_dict({'Layer_out': concrete, 55 | 'Layer_in': insulation, 56 | 'Glass': glass}, 57 | orient='index') 58 | 59 | # radiative properties 60 | ε_wLW = 0.85 # long wave emmisivity: wall surface (concrete) 61 | ε_gLW = 0.90 # long wave emmisivity: glass pyrex 62 | α_wSW = 0.25 # short wave absortivity: white smooth surface 63 | α_gSW = 0.38 # short wave absortivity: reflective blue glass 64 | τ_gSW = 0.30 # short wave transmitance: reflective blue glass 65 | 66 | σ = 5.67e-8 # W/(m²⋅K⁴) Stefan-Bolzmann constant 67 | 68 | Fwg = 1 / 5 # view factor wall - glass 69 | 70 | # convection coefficients 71 | h = pd.DataFrame([{'in': 8., 'out': 25}], index=['h']) # W/(m²⋅K) 72 | 73 | # Thermal circuit 74 | # =============== 75 | # thermal conductances 76 | # conduction 77 | G_cd = wall['Conductivity'] / wall['Width'] * wall['Surface'] 78 | 79 | # convection 80 | Gw = h * wall['Surface'][0] # wall 81 | Gg = h * wall['Surface'][2] # glass 82 | 83 | # long wave radiation 84 | Tm = 20 + 273 # K, mean temp for radiative exchange 85 | 86 | GLW1 = 4 * σ * Tm**3 * ε_wLW / (1 - ε_wLW) * wall['Surface']['Layer_in'] 87 | GLW12 = 4 * σ * Tm**3 * Fwg * wall['Surface']['Layer_in'] 88 | GLW2 = 4 * σ * Tm**3 * ε_gLW / (1 - ε_gLW) * wall['Surface']['Glass'] 89 | 90 | GLW = 1 / (1 / GLW1 + 1 / GLW12 + 1 / GLW2) 91 | 92 | # ventilation & advection 93 | Va = l**3 # m³, volume of air 94 | ACH = 1 # air changes per hour 95 | Va_dot = ACH / 3600 * Va # m³/s, air infiltration 96 | 97 | Gv = air['Density'] * air['Specific heat'] * Va_dot 98 | 99 | # P-controler gain 100 | Kp = 1e4 # almost perfect controller Kp -> ∞ 101 | Kp = 1e-3 # no controller Kp -> 0 102 | Kp = 0 103 | 104 | # glass: convection outdoor & conduction 105 | Ggs = float(1 / (1 / Gg['out'] + 1 / (2 * G_cd['Glass']))) 106 | 107 | # Thermal capacities 108 | C = wall['Density'] * wall['Specific heat'] * wall['Surface'] * wall['Width'] 109 | C['Air'] = air['Density'] * air['Specific heat'] * Va 110 | 111 | # System of algebraic-differential equations (DAE) 112 | # ================================================ 113 | A = np.zeros([12, 8]) # n° of branches X n° of nodes 114 | A[0, 0] = 1 # branch 0: -> node 0 115 | A[1, 0], A[1, 1] = -1, 1 # branch 1: node 0 -> node 1 116 | A[2, 1], A[2, 2] = -1, 1 # branch 2: node 1 -> node 2 117 | A[3, 2], A[3, 3] = -1, 1 # branch 3: node 2 -> node 3 118 | A[4, 3], A[4, 4] = -1, 1 # branch 4: node 3 -> node 4 119 | A[5, 4], A[5, 5] = -1, 1 # branch 5: node 4 -> node 5 120 | A[6, 4], A[6, 6] = -1, 1 # branch 6: node 4 -> node 6 121 | A[7, 5], A[7, 6] = -1, 1 # branch 7: node 5 -> node 6 122 | A[8, 7] = 1 # branch 8: -> node 7 123 | A[9, 5], A[9, 7] = 1, -1 # branch 9: node 5 -> node 7 124 | A[10, 6] = 1 # branch 10: -> node 6 125 | A[11, 6] = 1 # branch 11: -> node 6 126 | 127 | G = np.diag(np.hstack( 128 | [Gw['out'], 2 * G_cd['Layer_out'], 2 * G_cd['Layer_out'], 129 | 2 * G_cd['Layer_in'], 2 * G_cd['Layer_in'], GLW, 130 | Gw['in'], Gg['in'], Ggs, 2 * G_cd['Glass'], Gv, Kp])) 131 | 132 | neglect_air_glass = False 133 | 134 | if neglect_air_glass: 135 | C = np.diag([0, C['Layer_out'], 0, C['Layer_in'], 0, 0, 136 | 0, 0]) 137 | else: 138 | C = np.diag([0, C['Layer_out'], 0, C['Layer_in'], 0, 0, 139 | C['Air'], C['Glass']]) 140 | 141 | b = np.zeros(12) # branches 142 | b[[0, 8, 10, 11]] = 1 # branches with temperature sources 143 | 144 | f = np.zeros(8) # nodes 145 | f[[0, 4, 6, 7]] = 1 # nodes with heat-flow sources 146 | 147 | y = np.zeros(8) # nodes 148 | y[[6]] = 1 # nodes (temperatures) of interest 149 | 150 | # State-space representation 151 | # ========================== 152 | [As, Bs, Cs, Ds] = dm4bem.tc2ss(A, G, b, C, f, y) 153 | 154 | # Steady-state 155 | # ============ 156 | # from system of DAE 157 | b = np.zeros(12) # temperature sources 158 | b[[0, 8, 10]] = 10 # outdoor temperature 159 | b[[11]] = 20 # indoor set-point temperature 160 | 161 | f = np.zeros(8) # flow-rate sources 162 | 163 | θ = np.linalg.inv(A.T @ G @ A) @ (A.T @ G @ b + f) 164 | print(f'θ = {θ} °C') 165 | 166 | # from state-space representation 167 | bT = np.array([10, 10, 10, 20]) # [To, To, To, Tisp] 168 | fQ = np.array([0, 0, 0, 0]) # [Φo, Φi, Qa, Φa] 169 | u = np.hstack([bT, fQ]) 170 | yss = (-Cs @ np.linalg.inv(As) @ Bs + Ds) @ u 171 | print(f'yss = {yss} °C') 172 | 173 | # Dynamic simulation 174 | # ================== 175 | λ = np.linalg.eig(As)[0] # eigenvalues of matrix As 176 | 177 | print('Time constants: \n', -1 / λ, 's \n') 178 | print('2 x Time constants: \n', -2 / λ, 's \n') 179 | dtmax = 2 * min(-1. / λ) 180 | print(f'Maximum time step: {dtmax:.2f} s = {dtmax / 60:.2f} min') 181 | 182 | # time step 183 | dt = np.floor(dtmax / 60) * 60 # s 184 | print(f'dt = {dt} s = {dt / 60:.0f} min') 185 | 186 | # settling time 187 | time_const = np.array([int(x) for x in sorted(-1 / λ)]) 188 | print('4 * Time constants: \n', 4 * time_const, 's \n') 189 | 190 | t_settle = 4 * max(-1 / λ) 191 | print(f'Settling time: \ 192 | {t_settle:.0f} s = \ 193 | {t_settle / 60:.1f} min = \ 194 | {t_settle / (3600):.2f} h = \ 195 | {t_settle / (3600 * 24):.2f} days') 196 | 197 | # Step response 198 | # ------------- 199 | # Find the next multiple of 3600 s that is larger than t_settle 200 | duration = np.ceil(t_settle / 3600) * 3600 201 | n = int(np.floor(duration / dt)) # number of time steps 202 | t = np.arange(0, n * dt, dt) # time vector for n time steps 203 | 204 | print(f'Duration = {duration} s') 205 | print(f'Number of time steps = {n}') 206 | 207 | u = np.zeros([8, n]) # u = [To To To Tisp Φo Φi Qa Φa] 208 | u[0:3, :] = 10 * np.ones([3, n]) # To = 10 for n time steps 209 | u[3, :] = 20 * np.ones([1, n]) # Tisp = 20 for n time steps 210 | 211 | n_s = As.shape[0] # number of state variables 212 | θ_exp = np.zeros([n_s, t.shape[0]]) # explicit Euler in time t 213 | θ_imp = np.zeros([n_s, t.shape[0]]) # implicit Euler in time t 214 | 215 | I = np.eye(n_s) # identity matrix 216 | 217 | for k in range(n - 1): 218 | θ_exp[:, k + 1] = (I + dt * As) @\ 219 | θ_exp[:, k] + dt * Bs @ u[:, k] 220 | θ_imp[:, k + 1] = np.linalg.inv(I - dt * As) @\ 221 | (θ_imp[:, k] + dt * Bs @ u[:, k]) 222 | 223 | y_exp = Cs @ θ_exp + Ds @ u 224 | y_imp = Cs @ θ_imp + Ds @ u 225 | 226 | fig, ax = plt.subplots() 227 | ax.plot(t / 3600, y_exp.T, t / 3600, y_imp.T) 228 | ax.set(xlabel='$Time$ [h]', 229 | ylabel='$T_i$ [°C]', 230 | title='Step input: To') 231 | ax.legend(['Explicit', 'Implicit']) 232 | ax.grid() 233 | plt.show() 234 | 235 | print('Steady-state indoor temperature obtained with:') 236 | print(f'- DAE model: {float(θ[6]):.4f} °C') 237 | print(f'- state-space model: {float(yss):.4f} °C') 238 | print(f'- steady-state response to step input: {float(y_exp[:, -2]):.4f} °C') 239 | 240 | # Simulation with weather data 241 | # ---------------------------- 242 | # Input vector 243 | # weather data 244 | start_date = '01-03 12:00:00' 245 | end_date = '02-05 18:00:00' 246 | 247 | start_date = '2000-' + start_date 248 | end_date = '2000-' + end_date 249 | print(f'{start_date} \tstart date') 250 | print(f'{end_date} \tend date') 251 | 252 | filename = './weather_data/FRA_Lyon.074810_IWEC.epw' 253 | [data, meta] = dm4bem.read_epw(filename, coerce_year=None) 254 | weather = data[["temp_air", "dir_n_rad", "dif_h_rad"]] 255 | del data 256 | weather.index = weather.index.map(lambda t: t.replace(year=2000)) 257 | weather = weather[( 258 | weather.index >= start_date) & ( 259 | weather.index < end_date)] 260 | 261 | # solar radiatiion on the walls 262 | surface_orientation = {'slope': 90, 263 | 'azimuth': 0, 264 | 'latitude': 45} 265 | albedo = 0.2 266 | rad_surf = dm4bem.sol_rad_tilt_surf( 267 | weather, surface_orientation, albedo) 268 | rad_surf['Etot'] = rad_surf.sum(axis=1) 269 | 270 | # resample the weather data 271 | data = pd.concat([weather['temp_air'], rad_surf['Etot']], axis=1) 272 | data = data.resample(str(dt) + 'S').interpolate(method='linear') 273 | data = data.rename(columns={'temp_air': 'To'}) 274 | 275 | # other inputs 276 | data['Ti'] = 20 * np.ones(data.shape[0]) 277 | data['Qa'] = 0 * np.ones(data.shape[0]) 278 | 279 | # input vector 280 | To = data['To'] 281 | Ti = data['Ti'] 282 | Φo = α_wSW * wall['Surface']['Layer_out'] * data['Etot'] 283 | Φi = τ_gSW * α_wSW * wall['Surface']['Glass'] * data['Etot'] 284 | Qa = data['Qa'] 285 | Φa = α_gSW * wall['Surface']['Glass'] * data['Etot'] 286 | 287 | u = pd.concat([To, To, To, Ti, Φo, Φi, Qa, Φa], axis=1) 288 | u.columns.values[[4, 5, 7]] = ['Φo', 'Φi', 'Φa'] 289 | 290 | # Initial conditions 291 | θ_exp = 20 * np.ones([As.shape[0], u.shape[0]]) 292 | 293 | # Time integration 294 | for k in range(u.shape[0] - 1): 295 | θ_exp[:, k + 1] = (I + dt * As) @ θ_exp[:, k]\ 296 | + dt * Bs @ u.iloc[k, :] 297 | 298 | for k in range(u.shape[0] - 1): 299 | θ_exp[:, k + 1] = (I + dt * As) @ θ_exp[:, k]\ 300 | + dt * Bs @ u.iloc[k, :] 301 | 302 | # outputs 303 | y_exp = Cs @ θ_exp + Ds @ u.to_numpy().T 304 | q_HVAC = Kp * (data['Ti'] - y_exp[0, :]) 305 | 306 | # plot 307 | t = dt * np.arange(data.shape[0]) # time vector 308 | 309 | fig, axs = plt.subplots(2, 1) 310 | # plot indoor and outdoor temperature 311 | axs[0].plot(t / 3600 / 24, y_exp[0, :], label='$T_{indoor}$') 312 | axs[0].plot(t / 3600 / 24, data['To'], label='$T_{outdoor}$') 313 | axs[0].set(xlabel='Time [days]', 314 | ylabel='Temperatures [°C]', 315 | title='Simulation for weather') 316 | axs[0].legend(loc='upper right') 317 | 318 | # plot total solar radiation and HVAC heat flow 319 | axs[1].plot(t / 3600 / 24, q_HVAC, label='$q_{HVAC}$') 320 | axs[1].plot(t / 3600 / 24, data['Etot'], label='$Φ_{total}$') 321 | axs[1].set(xlabel='Time [days]', 322 | ylabel='Heat flows [W]') 323 | axs[1].legend(loc='upper right') 324 | 325 | fig.tight_layout() 326 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dynamic Models for Building Energy Management 2 | 3 | [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/cghiaus/dm4bem/HEAD) 4 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/cghiaus/dm4bem/blob/main/LICENSE) 5 | 6 | 7 | These tutorials present a complete example of thermal dynamic simulation of a building. For the sake of simplicity, a [toy model](https://en.m.wikipedia.org/wiki/Toy_model) is used for the [building](./figures/03_cube_principle.png) in which 5 identical two-layer walls, a glass wall, air infiltration, and an indoor temperature control system are modelled. 8 | 9 | The tutorials go through obtaining weather data from internet, modelling the thermal transfer with thermal networks, transforming the thermal networks into systems of differential algebraic equations and state-space representation, and implementing customized control algorithms into the numerical integration loop. 10 | 11 | The advantage of the method, as compared with other existing alternatives, is that the state-space representation is obtained; therefore eigenvalues analysis is achievable. 12 | 13 | The disadvantage is that, in the current implementation, application on large models is tedious and prone to errors. 14 | 15 | The notebooks can be run interactively on `MyBinder.org` by clicking on the button [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/cghiaus/dm4bem/HEAD). 16 | 17 | *Note*: In the folder `M`, the repository containes the MATLAB® v. 6 scripts and the PDFs of the tutorials for MATLAB® implementation. 18 | 19 | ## Tutorials 20 | 1. [Weather data and solar radiation on a tilted surface](01WeatherData.ipynb). 21 | 2. [Thermal circuit and state-space representation for a thermal circuit with capacities in every node: simple wall](02SimpleWall.ipynb). 22 | 3. [Thermal circuit and state-space representation for a thermal circuit with capacities in some nodes: cubic building](03CubicBuilding.ipynb). 23 | 4. [Thermal circuits assembling](04AssemblingCircuits.ipynb). 24 | 5. [Switch between models: heating & cooling and free-running](05SwitchModels.ipynb). 25 | 6. [Control input: heating & cooling and free-running](06Control_Input.ipynb). 26 | 7. [Radiation coupled with convection](07Coupled_rad_convection.ipynb). 27 | 8. [Sensible thermal load in steady-state](08Thermal_load.ipynb). 28 | 9. [Air flow by ventilation](09Air_flow_ventilation.ipynb). 29 | 30 | **Annexes** 31 | 1. [Thermal networks for heat trasfer in buildings](A01_Heat_transfer.ipynb) 32 | 33 | ## Project sessions 34 | The assignments are written in *Jupyter* notebooks and posted on Github in the repository indicated in each assignment. Each repository needs to have: 35 | - `README.md` file that contains at least the names of the members of the team and a link to `mybinder.org`. 36 | - `environment.yml` file that lists the dependencies required for the project. 37 | 38 | The *Jupyter* notebooks need to contain [Markdown cells](https://jupyter-notebook.readthedocs.io/en/stable/examples/Notebook/Working%20With%20Markdown%20Cells.html) structured with [headings](https://www.markdownguide.org/basic-syntax/#headings) and equations need to be written in [LaTeX](https://jupyter-notebook.readthedocs.io/en/stable/examples/Notebook/Working%20With%20Markdown%20Cells.html#LaTeX-equations). 39 | 40 | 41 | ### Model 42 | - Draw the plan of a two-zone building. 43 | - Formulate the hypothesis for boundary conditions. 44 | - Chose the types of windows, doors, and walls. 45 | - Draw the thermal circuit: 46 | - temperature nodes, 47 | - flow-rate paths, 48 | - thermal conductances for conduction, convection, long-wave radiation, advection, and P-controllers, 49 | - sources of temperature and flow-rate, 50 | - Number the temperature nodes and the flow-rate branches (starting from 0). 51 | - Calculate the thermal conductances for conduction, convection, long-wave radiation, and advection. 52 | - Calculate the thermal capacities. 53 | - Write down the incidence matrix $A$, the conductance matrix $G$ and the capacity matrix $C$ of the system of Algebraic Differential Equations (DAE). 54 | - Define the inputs: temperature sources (vector $b$) and flow rate sources (vector $f$). 55 | - Write in Pyhthon the incidence matrix $A$, the conductance matrix $G$ and the capacity matrix $C$ of the system of Algebraic Differential Equations (DAE). 56 | - Write in Pyhthon the vectors of pointers to the temperature sources $b$, flow-rate sources $f$, and outputs $y$. 57 | - **Assignment 1**: Model 58 | 59 | ### Steady-state 60 | - Implement in Python the matrices $A$, $G$ and $C$ of the system of Diferential Algebraic Equations (DAE). 61 | - Give values to inputs (temperature sources, $b$, and flow rate sources $f$). 62 | - Calculate steady-state response of the system of Diferential Algebraic Equations (DAE). 63 | - From the systems of Diferential Algebraic Equations (DAE), obtain the matrices $A_s$, $B_s$, $C_s$, and $D_s$ of the state-space representation. 64 | - Give the values of the input vector $u = [b_T^T, f_Q^T]^T$. 65 | - Obtain the steady-state response of the state-space representation. 66 | - Compare the results obtained for the system of Diferential Algebraic Equations (DAE) with the results obtained for the state-space representation. 67 | - **Assignment 2**: Steady-state 68 | 69 | ### Simulate step response 70 | - Determine the time step and the settling time. 71 | - Give the input vector $u$. 72 | - Integrate in time the differential equations. 73 | - Plot the results. 74 | - Discuss the results. 75 | - **Assignment 3**: Simulate step response 76 | 77 | ### Simulate response to weather 78 | - Define start and end time. 79 | - Prepare the inputs: 80 | - read weather data, 81 | - calculate the solar irradiance on the walls, 82 | - resample the weather data 83 | - give the other inputs (e.g., internal gains), 84 | - give the input vector in time. 85 | - Define the initial conditions. 86 | - Integrate in time. 87 | - Plot the results. 88 | - Discuss the results. 89 | - Implement other controllers (dead-band, model predictive control). 90 | - Discuss the results. 91 | - **Assignment 4**: Simulate response to weather 92 | 93 | ### Reproducible report 94 | - Write the report in *Jupyter* notebooks. 95 | - Publish the report on *GitHub* and *MyBinder*. 96 | - **Assignment 5**: [Reproducible report](https://classroom.github.com/a/DMXliQ2x) 97 | 98 | **Support** 99 | 100 | 1. [GitHub Docs](https://docs.github.com/en): 101 | - [Getting started with your GitHub account](https://docs.github.com/en/get-started/onboarding/getting-started-with-your-github-account) 102 | - [Accepting the assignement](https://www.youtube.com/watch?v=jXpT8eOzzCM) 103 | - [How to add files to Github Repository](https://www.youtube.com/watch?v=-rcz_CZe2Ec) 104 | 2. [Anaconda cheetsheet](https://docs.continuum.io/anaconda/user-guide/cheatsheet/) 105 | 3. Python 106 | - [Python tutorial](https://docs.python.org/3/tutorial/#the-python-tutorial) 107 | - [Python course CS50 (Harvard)](https://cs50.harvard.edu/python/2022/weeks/) 108 | 4. [Jupyter notebook cheatsheet](https://medium.com/ibm-data-science-experience/markdown-for-jupyter-notebooks-cheatsheet-386c05aeebed) 109 | 5. [NumPy for MATLAB users](http://mathesaurus.sourceforge.net/matlab-numpy.html) 110 | 6. [Get started with Binder](https://mybinder.readthedocs.io/en/latest/introduction.html) 111 | 7. [Markdown and LaTeX introduction](https://ashki23.github.io/markdown-latex.html) 112 | - [LaTeX equation editor](https://latex.codecogs.com/eqneditor/editor.php) 113 | - [Markdown table generator](https://www.tablesgenerator.com/markdown_tables#) 114 | 115 | 116 | ## References 117 | 118 | 1. C. Ghiaus (2013). Causality issue in the heat balance method for calculating the design heating and cooling load. *Energy* 50: 292-301 119 | [DOI 10.1016/j.energy.2012.10.024](http://dx.doi.org/10.1016/j.energy.2012.10.024), [HAL 03605823]( https://hal.archives-ouvertes.fr/hal-03605823/document) 120 | 121 | 2. C. Ghiaus, N. Ahmad (2020). Thermal circuits assembling and state-space extraction for modelling heat transfer in buildings, *Energy*, 195:117019 122 | [DOI 10.1016/j.energy.2020.117019](https://doi.org/10.1016/j.energy.2020.117019), [HAL 03600778](https://hal.archives-ouvertes.fr/hal-03600778/document) 123 | 124 | 3. C. Ghiaus (2021). Dynamic Models for Energy Control of Smart Homes, in *S. Ploix M. Amayri, N. Bouguila (eds.) Towards Energy Smart Homes*, Online ISBN: 978-3-030-76477-7, Print ISBN: 978-3-030-76476-0, Springer, pp. 163-198 (ref.) 125 | [DOI 10.1007/978-3-030-76477-7_5](https://doi.org/10.1007/978-3-030-76477-7_5), [HAL 03578578](https://hal.archives-ouvertes.fr/hal-03578578/document) 126 | 127 | 4. J. Kneifel (2013). Annual Whole Building Energy Simulation of the NIST Net Zero Energy Residential Test Facility Design, *NIST Technical Note 1767*, [DOI 10.6028/NIST.TN.1767](https://doi.org/10.6028/NIST.TN.1767) 128 | 129 | 5. U.S. Department of Energy (2022). EnergyPlus v.22.1.0 Documentation, Engineering Reference ([link](https://energyplus.net/assets/nrel_custom/pdfs/pdfs_v22.1.0/EngineeringReference.pdf)) 130 | 131 | 6. Solar Energy Laboratory, University of Wisconsin-Madison (2009). TRNSYS 17 Volume 4 Mathematical Reference ([link](https://web.mit.edu/parmstr/Public/TRNSYS/04-MathematicalReference.pdf)) 132 | 133 | 7. NIST (2008) Guide for the Use of the International System of Units (SI) ([link](https://physics.nist.gov/cuu/pdf/sp811.pdf)) 134 | 135 | 8. BIPM (2008) Evaluation of measurement data — Guide to the expression of uncertainty in measurement ([link](https://www.bipm.org/documents/20126/2071204/JCGM_100_2008_E.pdf/cb0ef43f-baa5-11cf-3f85-4dcd86f77bd6)) 136 | 137 | 9. BIPM (2019) The International System of Units (SI), 9th edition 138 | ([link](https://www.bipm.org/documents/20126/41483022/SI-Brochure-9.pdf)) 139 | 140 | 141 | # Exam questions 142 | 143 | **Thermal comfort** 144 | 1. Sensible and latent heat. 145 | 2. Variation of internal (stored energy). 146 | 3. Average heat rate generated by human metabolisme. 147 | 4. Environmental factors that influence the thermal comfort. 148 | 5. Relationship between Predicted Mean Vote (PMV) and Predicted Percentage of Dissatisfied (PPD). 149 | 6. Mean radiant temperature and operative temperature. 150 | 151 | **Modeling** 152 | 1. Definition of science. 153 | 2. Shortly describe the four paradigms of science (empirical, theoretical, computational and data science). 154 | 3. Reproducibility crises: definition and how to overcome it. 155 | 4. Describe the reproducibility spectrum in Computational Science. 156 | 5. What is a (mathematical) model? 157 | 6. Definition of physical and computational causality. 158 | 7. Definition of inputs, outputs and states of a dynamic model. 159 | 8. Conservation laws: two examples. 160 | 9. Relation between conservation laws and symmetry in physics. 161 | 10. Constitutive laws: one example of a universal law and one of a phenomenological law. 162 | 11. Explain why there are only seven fundamental units in the SI system of units. 163 | 12. What is the difference between the classical SI system of units and the system adopted on 20 May 2019? Why is this difference important? 164 | 13. What is the relationship between energy and temperature? 165 | 14. Draw the basic network for heat transfer modelling. Explain each element of the network: 166 | - temperature nodes, 167 | - flow branches, 168 | - conductances, 169 | - capacities, 170 | - temperature sources, 171 | - flow sources. 172 | 15. Show the analogy between: 173 | - heat transfer, 174 | - mass transfer, 175 | - electrical conduction. 176 | 16. Draw the framework for obtaining models for transport phenomena (i.e., heat trasfer, mass transfer, momentum transfer, electrical conduction). 177 | 17. Define the modes of heat transfer and give the expression of conductance for: 178 | - conduction, 179 | - convection, 180 | - radiation, 181 | - advection. 182 | 18. Conservation of energy in steady-state and in dynamics. 183 | 29. Definition of sensible heat. 184 | 20. Surface phenomena and volume phenomena in energy balance equation. 185 | 21. Draw a wall and a window. Make a thermal network model of this system. 186 | 22. Explain the difference between *Differential Algebraic Equations* model and *state-space* representation. 187 | 23. Explain the shape and the elements of the following matrices and vectors of a *Differential Algebraic Equations* model $C \dot{\theta} = -A^T G A \theta + A^T G b + f$: 188 | - $A$ - incidence marix; 189 | - $G$ - conductance matrix; 190 | - $C$ - capacity matrix; 191 | - $b$ - temperature source vector; 192 | - $f$ - flow-rate source vector. 193 | 24. What is the relationship between the eigenvalues of the state matrix and the time constants of the thermal model? 194 | 25. Define the numerical stability. What is the condition for the numerical stability of Euler explicit method of integration in time? 195 | 26. Explain the differences between Euler implicit and explicit methods. 196 | 27. Comment on the advantages and the disadvantages of Euler implicit and explicit methods. 197 | 28. Consider the the model of heat transfert through a simple wall (tutorial 29). Explain the qualitative differences between the step response to outdoor temperature input and the step response to indoor heat flow rate. 198 | 29. Discuss the influence of the initial conditions on the dynamic response. 199 | 30. How can be estimated the response (or settling) time of a dynamic system? What is the usefulness of the response time in dynamic simulation? 200 | 31. How can be estimated the time step for the dynamic simulation? What can be done if the time step is too small as compared to the time step needed for the problem? 201 | 202 | # Written report 203 | The report will be written in *Jupyter* notebook, posted on *GitHub.com* and liked to *MyBinder.org*. 204 | 205 | The general structure of the report: 206 | - Front page: title, author(s), date. 207 | - Contents. 208 | - Description of the building: drawing, dimensions, materials, material properties, etc. 209 | - Hypothesis: location, boundary conditions, schedule for usage, etc. 210 | - Thermal model (with justifications). 211 | - Mathematical model: Differential Algebraic Equations (matrices $A$, $G$, and $C$, vectors $b$ and $f$) and state-space representation (matrices $A$, $B$, $C$ and $D$ and vector $u$). 212 | - Model implementation in Python. 213 | - Steady-state results. 214 | - Dynamic simulation results. 215 | - Optimization (e.g., insulation, HVAC control, ventilation rate, solar shading). 216 | 217 | 218 | **Licence** 219 | 220 | Code is released under [MIT Lincence](https://choosealicense.com/licenses/mit/). 221 | 222 | [![Creative Commons License](http://i.creativecommons.org/l/by/4.0/88x31.png)](http://creativecommons.org/licenses/by/4.0/) 223 | -------------------------------------------------------------------------------- /A02_TC2DAE.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "07cb5619-fda9-4a33-a326-b628d16f07c0", 6 | "metadata": {}, 7 | "source": [ 8 | "# From thermal networks to differential-algebraic equations" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "73735e7d-35fd-49d0-96a3-85e7dc8ce7d5", 14 | "metadata": {}, 15 | "source": [ 16 | "The framework for obtaing the differential-algebraic system of equations (DAE) describing the thermal network is illustrated in Figure 1a ([Strang, 2007](https://www.cambridge.org/fr/universitypress/subjects/mathematics/computational-science/computational-science-and-engineering?format=HB&isbn=9780961408817); [Ghiaus, 2013](https://www.sciencedirect.com/science/article/pii/S0360544212007864?casa_token=ZOI6B8Osp8cAAAAA:ITZmxHE4dDNb2aNpQ-Z3oGpjqY0Oeik76rdkClTA-MHjmEyihe9zpYbkewjkfHBSQl-U1-SfHw)).\n", 17 | "\n", 18 | "First, we obtain the temperature differences over the conductances (Figure 1b). Then, we obtain the flow-rates through the conductances (Figure 1c). Finally, we obtain the DAE by energy balance in temperature nodes.\n", 19 | "\n", 20 | "![procedure](./figures/A02_calc_procedure.svg)\n", 21 | "> Figure 1. Obtaining the system of differential-algebraic equations from a thermal network: a) General framework. b) Temperature differences. c) Flow rates. d) Energy balance.\n", 22 | "\n", 23 | "![T2DAE](./figures/A02_TC2DAE.svg)\n", 24 | "> Figure 2. Example of differential-algebraic system of equations for a thermal network: a) Thermal network. b) Matrices and vectors. c) Differencial-algebraic equations (DAE).\n", 25 | "\n", 26 | "\n", 27 | "The system of differential-algebraic equations is obtained by calculating the temperature differences on conductances, then the flow rates, and finally the energy balance (Figure 1)." 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "id": "fd825649-f85c-4e75-9e53-5be022405482", 33 | "metadata": {}, 34 | "source": [ 35 | "## Temperature differences\n", 36 | "\n", 37 | "Let's define the temperature difference $e$ over a conductance $G$ as being the difference between the temperatures in the direction of the flow rate; e.g., in Figure 2a, the flow rate is from $\\theta_0$ to $\\theta_1$, so the temperature difference over the conductance $G_1$ is $e_1 = \\theta_0 - \\theta_1$.\n", 38 | "\n", 39 | "For the thermal circuit represented in Figure 2a, the temperature differences over the conductances $G_0, G_1, G_2$ are (Figure 1b):\n", 40 | "\n", 41 | "$\\begin{cases}\n", 42 | "e_0 = (0 - \\theta_0) + T_1 \\\\ \n", 43 | "e_1 = \\theta_0 - \\theta_1 \\\\\n", 44 | "e_2 = \\theta_1 - 0 - T_1 \n", 45 | "\\end{cases}$,\n", 46 | "\n", 47 | "where $0$ stands for the reference temperature. Or, in matrix form:\n", 48 | "\n", 49 | "$\\begin{bmatrix}\n", 50 | "e_0\\\\ \n", 51 | "e_1\\\\ \n", 52 | "e_2\n", 53 | "\\end{bmatrix}$ =\n", 54 | "$\\begin{bmatrix}\n", 55 | "-1 & 0 \\\\ \n", 56 | " 1 & -1 \\\\ \n", 57 | " 0 & 1 \n", 58 | "\\end{bmatrix}$\n", 59 | "$\\begin{bmatrix}\n", 60 | "\\theta_0 \\\\ \n", 61 | "\\theta_1\n", 62 | "\\end{bmatrix}$\n", 63 | "$+ \\begin{bmatrix}\n", 64 | "T_0\\\\ \n", 65 | "0\\\\ \n", 66 | "-T_2\n", 67 | "\\end{bmatrix}$\n", 68 | "\n", 69 | "or:\n", 70 | "\n", 71 | "$$e = \\Delta \\theta + b = -A \\theta + b$$\n", 72 | "\n", 73 | "where:\n", 74 | "\n", 75 | "$e = \\begin{bmatrix}\n", 76 | "e_0\\\\ \n", 77 | "e_1\\\\ \n", 78 | "e_2\n", 79 | "\\end{bmatrix}$ - vector of temperature differences over the conductances $G_0, G_1, G_2$;\n", 80 | "\n", 81 | "$\\Delta = \\begin{bmatrix}\n", 82 | "-1 & 0 \\\\ \n", 83 | " 1 & -1 \\\\ \n", 84 | " 0 & 1 \n", 85 | "\\end{bmatrix}$ - difference operator;\n", 86 | "\n", 87 | "$A = -\\Delta = \\begin{bmatrix}\n", 88 | "1 & 0 \\\\ \n", 89 | "-1 & 1 \\\\ \n", 90 | " 0 & -1 \n", 91 | "\\end{bmatrix}$ - [incidence matrix](https://en.m.wikipedia.org/wiki/Incidence_matrix);\n", 92 | "$A_{kl} = \\begin{cases}\\phantom{-}\n", 93 | "0 & \\text{if branch } q_k \\text{ is not connected to node } \\theta_l \\\\ \n", 94 | "+1 & \\text{if branch } q_k \\text{ enters into node } \\theta_l\\\\ \n", 95 | "-1 & \\text{if branch } q_k \\text{ gets out of node } \\theta_l \n", 96 | "\\end{cases}$\n", 97 | "\n", 98 | "$b = \\begin{bmatrix}\n", 99 | "T_0\\\\ \n", 100 | "0\\\\ \n", 101 | "-T_2\n", 102 | "\\end{bmatrix}$ - vector of temperature sources.\n", 103 | "\n", 104 | "Note that the value of $b_2$ in vector $b$ is $b_2 = -T_2$. This is in accordance with the [sign convention](https://en.wikipedia.org/wiki/Passive_sign_convention) for active and passive components:\n", 105 | "- in a thermal resistance, the flow is positif from high temperature to low temperature;\n", 106 | "- in a temperature source, the flow is positif from low temperature to high temperature." 107 | ] 108 | }, 109 | { 110 | "cell_type": "markdown", 111 | "id": "346623cb-299e-4ff0-ae82-44658edf1278", 112 | "metadata": {}, 113 | "source": [ 114 | "## Flow rates\n", 115 | "\n", 116 | "For the thermal circuit represented in Figure 2a, the flow rates through the conductances are (Figure 2c):\n", 117 | "\n", 118 | "$\\begin{cases}\n", 119 | "q_0 = G_0 e_0 \\\\ \n", 120 | "q_1 = G_1 e_1 \\\\\n", 121 | "q_2 = G_2 e_2 \n", 122 | "\\end{cases}$\n", 123 | "\n", 124 | "or, in matrix form:\n", 125 | "\n", 126 | "$\\begin{bmatrix}\n", 127 | "q_0\\\\ \n", 128 | "q_1\\\\ \n", 129 | "q_2\n", 130 | "\\end{bmatrix}$ =\n", 131 | "$\\begin{bmatrix}\n", 132 | "G_0 & 0 & 0 \\\\ \n", 133 | " 0 & G_1 & 0 \\\\ \n", 134 | " 0 & 0 & G_2 \n", 135 | "\\end{bmatrix}$\n", 136 | "$\\begin{bmatrix}\n", 137 | "e_0\\\\ \n", 138 | "e_1\\\\ \n", 139 | "e_2\n", 140 | "\\end{bmatrix}$\n", 141 | "\n", 142 | "or:\n", 143 | "\n", 144 | "$$q = Ge$$\n", 145 | "\n", 146 | "where:\n", 147 | "\n", 148 | "$q = \\begin{bmatrix}\n", 149 | "q_0\\\\ \n", 150 | "q_1\\\\ \n", 151 | "q_2\n", 152 | "\\end{bmatrix}$ - vector of flow rates through conductances;\n", 153 | "\n", 154 | "$G = \\begin{bmatrix}\n", 155 | "G_0 & 0 & 0 \\\\ \n", 156 | " 0 & G_1 & 0 \\\\ \n", 157 | " 0 & 0 & G_2 \n", 158 | "\\end{bmatrix}$ - diagonal matrix of conductances;\n", 159 | "\n", 160 | "$e = \\begin{bmatrix}\n", 161 | "e_0\\\\ \n", 162 | "e_1\\\\ \n", 163 | "e_2\n", 164 | "\\end{bmatrix}$ - vector of temperature differences over the conductances $G_0, G_1, G_2$." 165 | ] 166 | }, 167 | { 168 | "cell_type": "markdown", 169 | "id": "15e827c0-e352-4f6a-98ea-1375b4b6c0e6", 170 | "metadata": {}, 171 | "source": [ 172 | "## Energy balance\n", 173 | "\n", 174 | "For the thermal circuit represented in Figure 2a, the energy balance equations in the two temperature nodes are (Figure 2d):\n", 175 | "\n", 176 | "$\\begin{cases}\n", 177 | "C_0 \\dot{\\theta}_0 = q_0 - q_1 + \\dot{Q_0} \\\\ \n", 178 | "C_1 \\dot{\\theta}_1 = q_1 - q_2 + \\dot{Q_1}\n", 179 | "\\end{cases}$\n", 180 | "\n", 181 | "or, in matrix form:\n", 182 | "\n", 183 | "$\\begin{bmatrix}\n", 184 | "C_0 & 0 \\\\ \n", 185 | "0 & C_1 \n", 186 | "\\end{bmatrix}$\n", 187 | "$\\begin{bmatrix}\n", 188 | "\\dot{\\theta}_0 \\\\ \n", 189 | "\\dot{\\theta}_1\n", 190 | "\\end{bmatrix}$\n", 191 | "$= \\begin{bmatrix}\n", 192 | "1 & -1 & 0 \\\\ \n", 193 | "0 & 1 & -1\n", 194 | "\\end{bmatrix}$\n", 195 | "$\\begin{bmatrix}\n", 196 | "q_0\\\\ \n", 197 | "q_1\\\\ \n", 198 | "q_2\n", 199 | "\\end{bmatrix}$\n", 200 | "$+ \\begin{bmatrix}\n", 201 | "\\dot{Q}_0\\\\ \n", 202 | "\\dot{Q}_1\n", 203 | "\\end{bmatrix}$\n", 204 | "\n", 205 | "or,\n", 206 | "\n", 207 | "$$C \\dot{\\theta} = -\\Delta^T q + f = A^T q + f$$\n", 208 | "\n", 209 | "where:\n", 210 | "\n", 211 | "$C = \\begin{bmatrix}\n", 212 | "C_0 & 0 \\\\ \n", 213 | "0 & C_1 \n", 214 | "\\end{bmatrix}$ - diagonal matrix of capacities;\n", 215 | "\n", 216 | "$\\dot{\\theta} = \\begin{bmatrix}\n", 217 | "\\dot{\\theta}_0 \\\\ \n", 218 | "\\dot{\\theta}_1\n", 219 | "\\end{bmatrix}$ - vector of time derivatives of temperatures;\n", 220 | "\n", 221 | "$\\Delta^T = \\begin{bmatrix}\n", 222 | "-1 & 1 & 0 \\\\ \n", 223 | "0 & -1 & 1\n", 224 | "\\end{bmatrix}$ - transpose of difference matrix;\n", 225 | "\n", 226 | "$A^T = -\\Delta^T$ - transpose of incidence matrix;\n", 227 | "\n", 228 | "$f = \\begin{bmatrix}\n", 229 | "\\dot{Q}_0\\\\ \n", 230 | "\\dot{Q}_1\n", 231 | "\\end{bmatrix}$ - vector of flow-rate sources." 232 | ] 233 | }, 234 | { 235 | "cell_type": "markdown", 236 | "id": "7ed57d31-6702-43fe-9dc6-c6578ed43da9", 237 | "metadata": {}, 238 | "source": [ 239 | "## System of differential-algebraic equations\n", 240 | "\n", 241 | "By substituting the flow-rates $q$ from:\n", 242 | "$$q = Ge = G(- A \\theta + b) = G(\\Delta \\theta + b)$$\n", 243 | "into \n", 244 | "$$C \\dot{\\theta} = A^T q + f$$\n", 245 | "or into\n", 246 | "$$C \\dot{\\theta} = -\\Delta^T q + f$$\n", 247 | "we obtain the system of differential-algebraic equations:\n", 248 | "\n", 249 | "$$C \\dot{\\theta} = -A^T G A \\theta + A^T G b + f$$\n", 250 | "\n", 251 | "or\n", 252 | "$$C \\dot{\\theta} = -\\Delta^T G \\Delta \\theta - \\Delta^T G b + f$$\n", 253 | "\n", 254 | "After solving for temperature vector $\\theta$, the flow rates are found by:\n", 255 | "\n", 256 | "$$q = G(-A \\theta + b)$$\n", 257 | "or\n", 258 | "$$q = G(\\Delta \\theta + b)$$\n", 259 | "\n", 260 | "Note that the operators $\\Delta$ and $-\\Delta^T$ for vectors correspond to gradient (__grad__) and divergenve (_div_) operators for functions, respectively ([Strang, 2007](https://www.cambridge.org/fr/universitypress/subjects/mathematics/computational-science/computational-science-and-engineering?format=HB&isbn=9780961408817) pp. 255). Equation\n", 261 | "\n", 262 | "$$C \\dot{\\theta} = -\\Delta^T G \\Delta \\theta - \\Delta^T G b + f$$\n", 263 | "\n", 264 | "has a form similar to [heat diffusion equation](https://en.wikipedia.org/wiki/Heat_equation):\n", 265 | "\n", 266 | "$$\\rho c_p \\dot{\\theta} = -\\mathrm{div}(-\\lambda \\mathbf{grad}\\theta) + p$$\n", 267 | "where:\n", 268 | "\n", 269 | "$\\rho c_p$ - massic specific heat capacity of the unit volume, J/(m³·K), where $\\rho$ is the [density](https://en.wikipedia.org/wiki/Density) in kg/m³ and $c_p$ is the [specific heat capacity](https://en.wikipedia.org/wiki/Specific_heat_capacity) in J/(kg·K).\n", 270 | "\n", 271 | "$\\lambda$ - [thermal conductivity](https://en.wikipedia.org/wiki/Thermal_conductivity_and_resistivity) in W/(m·K).\n", 272 | "\n", 273 | "$p$ - thermal energy generated per unit of volume, W/m³.\n", 274 | "\n", 275 | "$\\mathrm{div}$ - [divergence](https://en.wikipedia.org/wiki/Del#Divergence) of the heat density field.\n", 276 | "\n", 277 | "$\\mathbf{grad}$ - [gradient](https://en.m.wikipedia.org/wiki/Gradient?searchToken=9rqqbuz7wuxvbp6gq3b4iignd) of temperature $\\theta$.\n", 278 | "\n", 279 | "As opposed to the differential form, the discrete form\n", 280 | "\n", 281 | "$$C \\dot{\\theta} = -\\Delta^T G \\Delta \\theta - \\Delta^T G b + f$$\n", 282 | "\n", 283 | "contains the boundary conditions (in terms $- \\Delta^T G b$ and $f$)." 284 | ] 285 | }, 286 | { 287 | "cell_type": "markdown", 288 | "id": "7a4a72f2-17c1-4c30-a37c-6f2851825b91", 289 | "metadata": {}, 290 | "source": [ 291 | "## Example\n", 292 | "\n", 293 | "__Problem__\n", 294 | "\n", 295 | "Let's consider a wall with a thickness $w$ = 0.20 m and a surface area $S$ = 20.00 m², with outside air temperature $\\theta_o$ = -5.0 °C and inside air temperature maintained at $\\theta_i$ = 24.0 °C. We assume that heat transfer is one-dimensional, in [steady state](https://en.m.wikipedia.org/wiki/Steady_state), and there's no internal heat generation. The material has [thermal conductivity](https://en.m.wikipedia.org/wiki/Thermal_conductivity_and_resistivity) $\\lambda$ = 1.00 W/(m·K), and the [heat transfer coefficients](https://en.m.wikipedia.org/wiki/Heat_transfer_coefficient) by convection outside and inside are $h_o$ = 25.00 W/(m²·K) and $h_i$ = 8.00 W/(m²·K), respectively. The outer surface, with an [absorptance](https://en.m.wikipedia.org/wiki/Absorptance) $\\alpha$ = 0.70, receives solar [irradiance](Irradiance) $E$ = 200.0 W/m².\n", 296 | "\n", 297 | "Calculate the following values:\n", 298 | "\n", 299 | "- $\\theta_o$: the temperature of the external surface.\n", 300 | "\n", 301 | "- $\\theta_i$: the temperature of the internal surface.\n", 302 | "\n", 303 | "- $q_{o,e}$: the thermal flow-rate through the wall from the outside to the inside.\n", 304 | "\n", 305 | "__Solution__\n", 306 | "\n", 307 | "In [steady state](https://en.m.wikipedia.org/wiki/Steady_state), the capacities are considered zero.\n", 308 | "The thermal network is given in Figure 2a. The matrices and the vectors of the model are (Figure 2b):\n", 309 | "\n", 310 | "$A = \\begin{bmatrix}\n", 311 | "1 & 0 \\\\ \n", 312 | "-1 & 1 \\\\ \n", 313 | " 0 & -1 \n", 314 | "\\end{bmatrix}$ - [incidence matrix](https://en.m.wikipedia.org/wiki/Incidence_matrix);\n", 315 | "\n", 316 | "$G = \\begin{bmatrix}\n", 317 | "h_o S & 0 & 0 \\\\ \n", 318 | " 0 & (\\lambda / w) S & 0 \\\\ \n", 319 | " 0 & 0 & h_i S \n", 320 | "\\end{bmatrix}$ - conductance matrix;\n", 321 | "\n", 322 | "$b = \\begin{bmatrix}\n", 323 | "T_0\\\\ \n", 324 | "0\\\\ \n", 325 | "-T_2\n", 326 | "\\end{bmatrix}$ - vector of temperature sources;\n", 327 | "\n", 328 | "$f = \\begin{bmatrix}\n", 329 | "\\alpha E S\\\\ \n", 330 | "0\n", 331 | "\\end{bmatrix}$ - vector of flow-rate sources.\n", 332 | "\n", 333 | "The steady-state solution is:\n", 334 | "\n", 335 | "$\\begin{cases}\n", 336 | "\\theta = (-A^T G A)^{-1} + A^T G b + f\\\\\n", 337 | "q = G(-A\\theta + b)\n", 338 | "\\end{cases}$\n", 339 | "\n", 340 | "obtained from \n", 341 | "$$C \\dot{\\theta} = -A^T G A \\theta + A^T G b + f$$\n", 342 | "for $C = 0$." 343 | ] 344 | }, 345 | { 346 | "cell_type": "code", 347 | "execution_count": 5, 348 | "id": "85b6d0af-38e3-4758-87ac-db1c18a4c85e", 349 | "metadata": {}, 350 | "outputs": [ 351 | { 352 | "name": "stdout", 353 | "output_type": "stream", 354 | "text": [ 355 | "Temperatures: θ0 = 3.16 °C, θ1 = 15.99 °C\n", 356 | "Flow-rates: q0 = -4082.19 W, q1 = -1282.19 W, q2 = -1282.19 W\n" 357 | ] 358 | } 359 | ], 360 | "source": [ 361 | "import numpy as np\n", 362 | "\n", 363 | "# Given data\n", 364 | "# ==========\n", 365 | "w = 0.2 # m, wall thickness\n", 366 | "S = 20.0 # m², wall surface area\n", 367 | "To = -5.0 # °C, outside air temperature\n", 368 | "Ti = 24.0 # °C, inside air temperature\n", 369 | "λ = 1.0 # W/(m·K), thermal conductivity\n", 370 | "ho = 25.0 # W/(m²·K), outside convection coefficients\n", 371 | "hi = 8.0 # W/(m²·K), outside convection coefficients\n", 372 | "α = 0.70 # -, absorbtance of outdoor surface\n", 373 | "E = 200.0 # W/m², solar irradiance on the outdoor surface\n", 374 | "\n", 375 | "# Calculations\n", 376 | "# ============\n", 377 | "# Incidence matrix\n", 378 | "A = np.array([[1, 0],\n", 379 | " [-1, 1],\n", 380 | " [0, -1]])\n", 381 | "\n", 382 | "# Conductance matrix\n", 383 | "G = np.diag([ho * S, λ / w * S, hi * S])\n", 384 | "\n", 385 | "# Temperature source vector\n", 386 | "b = np.array([To, 0, -Ti])\n", 387 | "\n", 388 | "# Flow-rate source vector\n", 389 | "f = np.array([α * E * S, 0])\n", 390 | "\n", 391 | "# Temperature vector in steady-state\n", 392 | "θ = np.linalg.inv(A.T @ G @ A) @ (A.T @ G @ b + f)\n", 393 | "\n", 394 | "# Flow-rate vector in steady-state\n", 395 | "q = G @ (-A @ θ + b)\n", 396 | "\n", 397 | "print(f\"Temperatures: θ0 = {θ[0]:.2f} °C, θ1 = {θ[1]:.2f} °C\")\n", 398 | "print(f\"Flow-rates: q0 = {q[0]:.2f} W, q1 = {q[1]:.2f} W, q2 = {q[2]:.2f} W\")" 399 | ] 400 | }, 401 | { 402 | "cell_type": "markdown", 403 | "id": "64bf34ff-483b-437a-9bc6-d737592f060f", 404 | "metadata": {}, 405 | "source": [ 406 | "## References\n", 407 | "Strang, G. (2007) Computational Science and Engineering. Wellesley, MA: Wellesley-Cambridge Press\n", 408 | "\n", 409 | "Ghiaus, C. (2013). Causality issue in the heat balance method for calculating the design heating and cooling load. Energy, 50, 292-301." 410 | ] 411 | }, 412 | { 413 | "cell_type": "code", 414 | "execution_count": null, 415 | "id": "69b1de58-d93a-460b-8677-ec3faeffa499", 416 | "metadata": {}, 417 | "outputs": [], 418 | "source": [] 419 | } 420 | ], 421 | "metadata": { 422 | "kernelspec": { 423 | "display_name": "Python 3 (ipykernel)", 424 | "language": "python", 425 | "name": "python3" 426 | }, 427 | "language_info": { 428 | "codemirror_mode": { 429 | "name": "ipython", 430 | "version": 3 431 | }, 432 | "file_extension": ".py", 433 | "mimetype": "text/x-python", 434 | "name": "python", 435 | "nbconvert_exporter": "python", 436 | "pygments_lexer": "ipython3", 437 | "version": "3.9.7" 438 | }, 439 | "toc-autonumbering": true 440 | }, 441 | "nbformat": 4, 442 | "nbformat_minor": 5 443 | } 444 | -------------------------------------------------------------------------------- /figures/03_cube_principle.svg: -------------------------------------------------------------------------------- 1 | 2 | 𝑇𝑖,𝑠𝑝-+Wall: concrete & insulationWindow: glassIndoor airHVAC systemVentilation 401 | --------------------------------------------------------------------------------