1
|
|
|
from emobpy import DataBase |
2
|
|
|
import pandas as pd |
3
|
|
|
import os |
4
|
|
|
import numpy as np |
5
|
|
|
from reegis import config as cfg |
6
|
|
|
from matplotlib import pyplot as plt |
7
|
|
|
|
8
|
|
|
def get_charging_profiles_from_database(path): |
9
|
|
|
""" |
10
|
|
|
This function can be used to process results obtained with the library emobpy by DIW Berlin. |
11
|
|
|
It takes a path to data as input and returns the summed charging power. |
12
|
|
|
|
13
|
|
|
Parameters |
14
|
|
|
---------- |
15
|
|
|
path: String |
16
|
|
|
Path to a folder with stored driving, availability and charging profiles |
17
|
|
|
|
18
|
|
|
Returns: DataFrame |
19
|
|
|
Summed charging power for 4 different charging strategies |
20
|
|
|
------- |
21
|
|
|
""" |
22
|
|
|
|
23
|
|
|
# Load profiles from Files |
24
|
|
|
manager = DataBase(path) |
25
|
|
|
manager.update() |
26
|
|
|
|
27
|
|
|
# Liste mit Availability Profilen |
28
|
|
|
keys_driving = [k for k, v in manager.db.items() if v['kind'] == 'driving'] |
29
|
|
|
keys_availability = [k for k, v in manager.db.items() if v['kind'] == 'availability'] |
30
|
|
|
keys_charging = [k for k, v in manager.db.items() if v['kind'] == 'charging'] |
31
|
|
|
keys_immediate = [k for k, v in manager.db.items() if v['kind'] == 'charging' and v['option'] == 'immediate' ] |
32
|
|
|
keys_balanced = [k for k, v in manager.db.items() if v['kind'] == 'charging' and v['option'] == 'balanced' ] |
33
|
|
|
keys_23to8 = [k for k, v in manager.db.items() if v['kind'] == 'charging' and v['option'] == 'from_23_to_8_at_home'] |
34
|
|
|
keys_0to24 = [k for k, v in manager.db.items() if v['kind'] == 'charging' and v['option'] == 'from_0_to_24_at_home'] |
35
|
|
|
|
36
|
|
|
# Summenprofil für Fahrleistung in kmd |
37
|
|
|
driving_profiles = pd.DataFrame() |
38
|
|
|
for k in keys_driving: |
39
|
|
|
test = manager.db[k]["timeseries"]["consumption"] |
40
|
|
|
driving_profiles = pd.concat([driving_profiles, test], axis=1) |
41
|
|
|
|
42
|
|
|
#cum_profile = driving_profiles.sum(axis=1) |
43
|
|
|
|
44
|
|
|
|
45
|
|
|
# Summenprofil für Ladeleistung (immediate) |
46
|
|
|
ch_profiles_immediate = pd.DataFrame() |
47
|
|
|
for k in keys_immediate: |
48
|
|
|
tmp = manager.db[k]["timeseries"]["charge_grid"] |
49
|
|
|
ch_profiles_immediate = pd.concat([ch_profiles_immediate, tmp], axis=1) |
50
|
|
|
|
51
|
|
|
P_immediate = ch_profiles_immediate.sum(axis=1) |
52
|
|
|
|
53
|
|
|
|
54
|
|
|
# Summenprofil für Ladeleistung (balanced) |
55
|
|
|
ch_profiles_balanced = pd.DataFrame() |
56
|
|
|
for k in keys_balanced: |
57
|
|
|
tmp = manager.db[k]["timeseries"]["charge_grid"] |
58
|
|
|
ch_profiles_balanced = pd.concat([ch_profiles_balanced, tmp], axis=1) |
59
|
|
|
|
60
|
|
|
P_balanced = ch_profiles_balanced.sum(axis=1) |
61
|
|
|
|
62
|
|
|
|
63
|
|
|
# Summenprofil für Ladeleistung (23 to 8) |
64
|
|
|
ch_profiles_23to8 = pd.DataFrame() |
65
|
|
|
for k in keys_23to8: |
66
|
|
|
tmp = manager.db[k]["timeseries"]["charge_grid"] |
67
|
|
|
ch_profiles_23to8 = pd.concat([ch_profiles_23to8, tmp], axis=1) |
68
|
|
|
|
69
|
|
|
P_23to8 = ch_profiles_23to8.sum(axis=1) |
70
|
|
|
|
71
|
|
|
|
72
|
|
|
# Summenprofil für Ladeleistung (0 to 24) |
73
|
|
|
ch_profiles_0to24 = pd.DataFrame() |
74
|
|
|
for k in keys_0to24: |
75
|
|
|
tmp = manager.db[k]["timeseries"]["charge_grid"] |
76
|
|
|
ch_profiles_0to24 = pd.concat([ch_profiles_0to24, tmp], axis=1) |
77
|
|
|
|
78
|
|
|
P_0to24 = ch_profiles_0to24.sum(axis=1) |
79
|
|
|
|
80
|
|
|
P_sum = pd.concat([P_immediate, P_balanced, P_23to8, P_0to24], axis=1) |
81
|
|
|
P_sum.columns = ['immediate', 'balanced', '23to8', '0to24'] |
82
|
|
|
|
83
|
|
|
return P_sum |
84
|
|
|
|
85
|
|
|
|
86
|
|
|
def return_normalized_charging_series(df): |
87
|
|
|
""" |
88
|
|
|
This function normalizes profiles so that the sum of the timeseries is 1. The profiles can then be scaled to |
89
|
|
|
a user defined energy consumption of BEV charging. |
90
|
|
|
|
91
|
|
|
Parameters |
92
|
|
|
---------- |
93
|
|
|
df: DataFrame |
94
|
|
|
Dataframe with 4 charging timereries |
95
|
|
|
|
96
|
|
|
Returns: DataFrame |
97
|
|
|
Normalized charging series |
98
|
|
|
------- |
99
|
|
|
""" |
100
|
|
|
|
101
|
|
|
# Cut off initial charging |
102
|
|
|
df.iloc[0:48] = df.iloc[48:96].values |
103
|
|
|
# Cut off end charging to intial SoC |
104
|
|
|
df.iloc[len(df)-48:len(df)] = df.iloc[len(df)-96:len(df)-48].values |
|
|
|
|
105
|
|
|
idx = pd.DatetimeIndex(df.index, freq='30min') |
106
|
|
|
df.set_index(idx, inplace=True) |
107
|
|
|
p_immediate = df['immediate'] |
108
|
|
|
p_balanced = df['balanced'] |
109
|
|
|
p_23to8 = df['23to8'] |
110
|
|
|
p_0to24 = df['0to24'] |
111
|
|
|
|
112
|
|
|
# Resample to hourly values |
113
|
|
|
immediate_hourly = p_immediate.resample('H').sum() |
114
|
|
|
balanced_hourly = p_balanced.resample('H').sum() |
115
|
|
|
hourly_23to8 = p_23to8.resample('H').sum() |
116
|
|
|
hourly_0to24 = p_0to24.resample('H').sum() |
117
|
|
|
|
118
|
|
|
# Normalize Yearly energy use to 1 |
119
|
|
|
immediate_norm = immediate_hourly * (1 / immediate_hourly.sum()) |
120
|
|
|
balanced_norm = balanced_hourly * (1 / balanced_hourly.sum()) |
121
|
|
|
norm_23to8 = hourly_23to8 * (1 / hourly_23to8 .sum()) |
122
|
|
|
norm_0to24 = hourly_0to24 * (1 / hourly_0to24.sum()) |
123
|
|
|
|
124
|
|
|
P_sum_norm = pd.concat([immediate_norm, balanced_norm, norm_23to8, norm_0to24], axis=1) |
125
|
|
|
smaller_zero = P_sum_norm < 0 |
126
|
|
|
P_sum_norm[smaller_zero] = 0 |
127
|
|
|
|
128
|
|
|
for n in ['immediate', 'balanced', '23to8', '0to24']: |
129
|
|
|
inc_fac = 1 / P_sum_norm[n].sum() |
130
|
|
|
P_sum_norm[n] = P_sum_norm[n].multiply(inc_fac) |
131
|
|
|
|
132
|
|
|
return P_sum_norm |
133
|
|
|
|
134
|
|
|
|
135
|
|
|
def return_sum_charging_power(path=None): |
136
|
|
|
""" |
137
|
|
|
This function returns a DataFrame with summed charging power series. Prerequisite is the calculation of profiles |
138
|
|
|
with the library emobpy by DIW Berlin. If the function is run for the first time a path to data must be provided. |
139
|
|
|
|
140
|
|
|
Parameters |
141
|
|
|
---------- |
142
|
|
|
path: String |
143
|
|
|
Path to a directory containing at least one folder with charging power series files. |
144
|
|
|
|
145
|
|
|
Returns: DataFrame |
146
|
|
|
Summed charging profiles |
147
|
|
|
------- |
148
|
|
|
""" |
149
|
|
|
fn = os.path.join(cfg.get("paths", "scenario_data"), 'sum_charging_power.csv') |
150
|
|
|
|
151
|
|
|
if not os.path.isfile(fn): |
152
|
|
|
os.chdir(path) |
153
|
|
|
dirs = os.listdir(os.getcwd()) |
154
|
|
|
result_dict = dict.fromkeys(dirs) |
155
|
|
|
|
156
|
|
|
for dir in result_dict.keys(): |
157
|
|
|
path = os.path.join(os.getcwd(), dir) |
158
|
|
|
result_dict[dir] = get_charging_profiles_from_database(path) |
159
|
|
|
|
160
|
|
|
charging_types = result_dict[dir].columns |
|
|
|
|
161
|
|
|
idx = result_dict[dir].index |
162
|
|
|
P_sum = pd.DataFrame(index=idx, columns=charging_types) |
163
|
|
|
len_series = len(result_dict[list(result_dict.keys())[0]]['immediate']) |
164
|
|
|
|
165
|
|
|
for ch_type in charging_types: |
166
|
|
|
sum_temp = pd.Series(np.zeros(shape=len_series), index=idx) |
167
|
|
|
|
168
|
|
|
for key in result_dict.keys(): |
169
|
|
|
P_tmp = result_dict[key][ch_type] |
170
|
|
|
sum_temp = sum_temp.add(P_tmp, fill_value=0) |
171
|
|
|
|
172
|
|
|
P_sum[ch_type] = sum_temp |
173
|
|
|
|
174
|
|
|
P_sum.to_csv(fn) |
175
|
|
|
|
176
|
|
|
else: |
177
|
|
|
P_sum = pd.read_csv(fn) |
178
|
|
|
P_sum.set_index('Unnamed: 0', drop=True, inplace=True) |
179
|
|
|
|
180
|
|
|
return P_sum |
181
|
|
|
|
182
|
|
|
|
183
|
|
|
def return_averaged_charging_series(weight_im=0.4, weight_bal=0.4, weight_night=0.2): |
184
|
|
|
cs = return_sum_charging_power() |
185
|
|
|
cs_norm = return_normalized_charging_series(cs) |
186
|
|
|
|
187
|
|
|
im = cs_norm["immediate"] |
188
|
|
|
bal = cs_norm["balanced"] |
189
|
|
|
night = cs_norm["23to8"] |
190
|
|
|
|
191
|
|
|
P_charge = weight_im * im + weight_bal * bal + weight_night * night |
192
|
|
|
|
193
|
|
|
return P_charge |
194
|
|
|
|
195
|
|
|
|
196
|
|
|
def plot_charging_series_comparison(df, df_mean): |
197
|
|
|
fig, axs = plt.subplots(5) |
198
|
|
|
fig.suptitle('Charging strategy comparison') |
199
|
|
|
axs[0].plot(df["immediate"]), axs[0].set_title('Immediate') |
200
|
|
|
axs[1].plot(df["balanced"]), axs[1].set_title('balanced') |
201
|
|
|
axs[2].plot(df["0to24"]), axs[2].set_title('0to24') |
202
|
|
|
axs[3].plot(df["23to8"]), axs[3].set_title('23to8') |
203
|
|
|
axs[4].plot(df_mean), axs[4].set_title('Averaged series') |
204
|
|
|
|