-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathhouse_load_profiler.py
255 lines (174 loc) · 9.26 KB
/
house_load_profiler.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# -*- coding: utf-8 -*-
"""
Created on Wed Oct 28 18:37:58 2020
@author: giamm
"""
# from tictoc import tic, toc
import numpy as np
import datareader #routine created to properly read the files needed in the following
from load_profiler import load_profiler as lp
###############################################################################
# This file contains a method that, for a given household (considering its
# availability of each appliance considered in this study) returns the electric
# load profile for the household during one day (1440 min), with a resolution
# of 1 minute.
###############################################################################
########## Routine
def house_load_profiler(time_dict, apps_availability, day, season, appliances_data, **params):
''' The method returns a load profile for a given household in a total simulation time of 1440 min, with a timestep of 1 min.
Inputs:
apps_availability - 1d-array, availability of each appliance for the household is stored (1 if present, 0 if not)
day - str, type of day (weekday: 'wd'| weekend: 'we')
season - str, season (summer: 's', winter: 'w', autumn or spring: 'ap')
appliances_data - dict, various input data related to the appliances
params - dict, simulation parameters
Outputs:
house_load_profile - 1d-array, load profile for the household (W)
energy - 1d-array, energy consumed by each appliance in one day (Wh/day)
'''
## Time
# Time discretization for the simulation
# Time-step (min)
dt = time_dict['dt']
# Total time of simulation (min)
time = time_dict['time']
# Vector of time from 00:00 to 23:59 (one day) (min)
time_sim = time_dict['time_sim']
## Parameters
# Simulation parameters that can be changed from the user
# Contractual power for each household (W)
power_max = params['power_max']*1000
## Input data for the appliances
# Appliances' attributes, energy consumptions and user's coefficients
# apps is a 2d-array in which, for each appliance (rows) and attribute value is given (columns)
apps_ID = appliances_data['apps_ID']
# apps_attr is a dictionary in which the name of each attribute (value) is linked to its columns number in apps (key)
apps_attr = appliances_data['apps_attr']
## Household's load profile
# Generating the load profile for the house, considering which appliances are available
# Initializing the power vector for the load profile (W)
house_load_profile = np.zeros(np.shape(time_sim))
# Initializing the vector where to store the energy consumption from each appliance (Wh/day)
energy = np.zeros(len(apps_ID))
# Using the method load_profiler(lp) to get the load profile for each appliance
for app in apps_ID:
# The ID number of the appliance is stored in a variable since it will be used man times
app_ID = apps_ID[app][apps_attr['id_number']]
# Skipping appliances that are not present in the household
if apps_availability[app_ID] == 0:
continue
load_profile = lp(time_dict, app, day, season, appliances_data, **params) #load_profile has to outputs (time and power)
# In case the instantaneous power exceedes the maximum power, some tries
# are made in order to change the moment in which the next appliance is
# switched on (since it is evaluated randomly, according to the cumulative
# frequency of utilization for that appliance)
count = 0
maxtries = 10
duration_indices = np.size(load_profile[load_profile > 0])
while np.any(house_load_profile + load_profile > power_max) and count < maxtries:
switch_on_index = np.size((house_load_profile + load_profile)[house_load_profile + load_profile > power_max])
roll_step = int((duration_indices + switch_on_index)/2)
load_profile = np.roll(load_profile, roll_step)
count += 1
# Evaluating the energy consumption from each appliance by integrating
# the load profile over the time. Since the time is in minutes, the
# result is divided by 60 in order to obtain Wh.
energy[app_ID] = np.trapz(load_profile,time_sim)/60
# Injecting the power demand from each appliance into the load profile of the household
house_load_profile[:] = house_load_profile[:] + load_profile
# In case the which loop failed, the instantaneous power is saturated to the
# maximum power anyway. This may happen because the last appliance to be considered
# is the lighting, which is of "continuous" type, therefore its profile does
# not depend on a cumulative frequency (they are always on)
house_load_profile[house_load_profile > power_max] = power_max
return(house_load_profile,energy)
#####################################################################################################################
# ## Uncomment the following lines to test the function
# import matplotlib.pyplot as plt
# from tictoc import tic, toc
# # Time-step, total time and vector of time from 00:00 to 23:59 (one day) (min)
# dt = 1
# time = 1440
# time_sim = np.arange(0,time,dt)
# # Creating a dictionary to be passed to the various methods, containing the time discretization
# time_dict = {
# 'time': time,
# 'dt': dt,
# 'time_sim': time_sim,
# }
# apps, apps_ID, apps_attr = datareader.read_appliances('eltdome_report.csv',';','Input')
# ec_yearly_energy, ec_levels_dict = datareader.read_enclasses('classenerg_report.csv',';','Input')
# coeff_matrix, seasons_dict = datareader.read_enclasses('coeff_matrix.csv',';','Input')
# apps_avg_lps = {}
# apps_dcs = {}
# for app in apps_ID:
# # app_nickname is a 2 or 3 characters string identifying the appliance
# app_nickname = apps_ID[app][apps_attr['nickname']]
# # app_type depends from the work cycle for the appliance: 'continuous'|'no_duty_cycle'|'duty_cycle'|
# app_type = apps_ID[app][apps_attr['type']]
# # app_wbe (weekly behavior), different usage of the appliance in each type of days: 'wde'|'we','wd'
# app_wbe = apps_ID[app][apps_attr['week_behaviour']]
# # app_sbe (seasonal behavior), different usage of the appliance in each season: 'sawp'|'s','w','ap'
# app_sbe = apps_ID[app][apps_attr['season_behaviour']]
# # Building the name of the file to be opened and read
# fname_nickname = app_nickname
# fname_type = 'avg_loadprof'
# apps_avg_lps[app] = {}
# for season in app_sbe:
# fname_season = season
# for day in app_wbe:
# fname_day = day
# filename = '{}_{}_{}_{}.csv'.format(fname_type, fname_nickname, fname_day, fname_season)
# # Reading the time and power vectors for the load profile
# data_lp = datareader.read_general(filename,';','Input')
# # Time is stored in hours and converted to minutes
# time_lp = data_lp[:, 0]
# time_lp = time_lp*60
# # Power is already stored in Watts, it corresponds to the load profile
# power_lp = data_lp[:, 1]
# load_profile = power_lp
# # Interpolating the load profile if it has a different time-resolution
# if (time_lp[-1] - time_lp[0])/(np.size(time_lp) - 1) != dt:
# load_profile = np.interp(time_sim, time_lp, power_lp, period = time)
# apps_avg_lps[app][(season, day)] = load_profile
# if app_type == 'duty_cycle':
# fname_type = 'dutycycle'
# filename = '{}_{}.csv'.format(fname_type, fname_nickname)
# # Reading the time and power vectors for the duty cycle
# data_dc = datareader.read_general(filename, ';', 'Input')
# # Time is already stored in minutes
# time_dc = data_dc[:, 0]
# # Power is already stored in Watts, it corresponds to the duty cycle
# power_dc = data_dc[:, 1]
# duty_cycle = power_dc
# # Interpolating the duty-cycle, if it has a different time resolution
# if (time_dc[-1] - time_dc[0])/(np.size(time_dc) - 1) != dt:
# time_dc = np.arange(time_dc[0], time_dc[-1] + dt, dt)
# duty_cycle = np.interp(time_dc, power_dc)
# apps_dcs[app] = {'time_dc': time_dc,
# 'duty_cycle': duty_cycle}
# appliances_data = {
# 'apps': apps,
# 'apps_ID': apps_ID,
# 'apps_attr': apps_attr,
# 'ec_yearly_energy': ec_yearly_energy,
# 'ec_levels_dict': ec_levels_dict,
# 'coeff_matrix': coeff_matrix,
# 'seasons_dict': seasons_dict,
# 'apps_avg_lps': apps_avg_lps,
# 'apps_dcs': apps_dcs,
# }
# params = {
# 'power_max': 3,
# 'en_class': 'D',
# 'toll': 15,
# 'devsta': 2,
# 'ftg_avg': 100
# }
# apps_availability = np.ones(17)
# day = 'wd'
# season = 's'
# house_load_profile, energy = house_load_profiler(time_dict, apps_availability, day, season, appliances_data, **params)
# plt.bar(time_sim,house_load_profile,width=dt,align='edge')
# plt.show()
######################################################################################################################################