Skip to content
Snippets Groups Projects

Master

18 files
+ 1848
205
Compare changes
  • Side-by-side
  • Inline

Files

+ 292
0
%% Cell type:markdown id:7d6b628352d925e2 tags:
# DEV Excercise 3
Task 2 - Battery storage optimization
In this task, an energy system consisting of a building with an electrical load (e.g. household appliances), PV system, battery storage and electricity grid connection is considered.
24 time steps are considered, corresponding to the 24 hours of a day.
Complete the code snippets where needed at places market with "!!!".
%% Cell type:markdown id:7c9c80da0ef98b06 tags:
Definition of the individual components:
%% Cell type:code id:b0157151aac2977a tags:
``` python
# Time series of electrical load [kW]
el_demand_kW = [0.3, 0.4, 0.3, 0.3, 0.3, 0.3, 0.6, 0.7, 0.5, 0.4, 0.4, 0.7, 1.1, 0.8, 0.3, 0.3, 0.3, 0.3, 0.5, 0.7, 1.2, 1, 0.8, 0.4]
# Time series for costs of electricity from the grid [€/kWh]
c_euro_kWh = [0.24, 0.32, 0.26, 0.25, 0.23, 0.32, 0.33, 0.35, 0.32, 0.32, 0.31, 0.28, 0.24, 0.33, 0.22, 0.27, 0.32, 0.32, 0.35, 0.32, 0.3, 0.33, 0.32, 0.31]
# PV system
pv_pu = [0, 0, 0, 0, 0, 0, 0.1, 0.3, 0.6, 0.7, 0.8, 0.9, 1, 1, 0.9, 0.8, 0.7, 0.6, 0.3, 0.1, 0, 0, 0, 0] # Generation time series per unit [p.u.]
pv_kWp = 8 # peak power [kW]
# Battery storage system
E_bat_kWh = 3 # capacity [kWh]
P_bat_max_charge_kW = 1 # max charging power [kW] (charging efficiency of 100 % is assumed)
P_bat_max_discharge_kW = 1 # max discharging power [kW] (discharging efficiency of 100 % is assumed)
```
%% Cell type:markdown id:259a9633f492299a tags:
# Task 2 a)
Plot the electrical demand, the electricity price as well as the PV generation for a 8 kWp plant. Use the python library matplotlib. You can find a user guide under the following [link](https://matplotlib.org/stable/users/index).
%% Cell type:code id:a291137bccc17837 tags:
``` python
import matplotlib.pyplot as plt
import numpy as np
# define the function
def plot_time_series(el_demand_kW, c_euro_kWh, pv_pu, pv_kWp):
"""
Plots the curves for electrical demand, the electricity price and the PV generation for a 8kWp plant.
:param el_demand_kW: time series of electrical load
:param c_euro_kWh: time series for costs of electricity from the grid
:param pv_pu: generation time series per unit [p.u.]
:param pv_kWp: peak power
"""
# !!! complete the code
pass
# Call the function
plot_time_series(el_demand_kW, c_euro_kWh, pv_pu, pv_kWp)
```
%% Cell type:markdown id:b3f112adafd4323a tags:
# Task 2 b)
Calculate the costs of electricity supply assuming the PV plant and battery storage system are not operating. (Using numpy might be helpfull. You can find a user guide under the following [link](https://numpy.org/doc/stable/).)
%% Cell type:code id:72143018a6eed25 tags:
``` python
# define function
def get_total_costs(energy, costs):
"""
Returns the costs of electricity supply assuming the PV plant and battery storage system are not operating
:param energy: time series of electrical load
:param costs: time series for costs of electricity from the grid
:return: total cost value
"""
c_total = 0 # !!! <-- insert calculation
return c_total
# call function
c_total = get_total_costs(el_demand_kW, c_euro_kWh)
print(f"The total electricity costs are {round(c_total,2)}")
```
%% Output
The total electricity costs are 0 €
%% Cell type:markdown id:13535b9a1577d9fb tags:
Result: The total electricity costs are 3.9 €
%% Cell type:markdown id:af8783fe2a5abeba tags:
# Task 2 c)
Calculate the costs of electricity considering a 8 kWp PV plant, but no battery storage system. Assume that no income is generated by feeding the PV generated electricity into the grid.
%% Cell type:code id:eab981a9d9c604fe tags:
``` python
# calculate residuum
residuum_kW = 0 # !!! <-- insert calculation
# call cost calculating function
c_total_residuum = get_total_costs(residuum_kW, c_euro_kWh)
print(f"The total electricity costs are {round(c_total_residuum,2)}")
```
%% Cell type:markdown id:15d46ddd46dbad9b tags:
Result: The total electricity costs are 1.59 €
%% Cell type:markdown id:a34b5d21c3844d90 tags:
# Task 2d)
In the following, an optimization problem is set up to optimize the operation of the battery in such a way that the electricity supply for the house is as cost-effective as possible.
%% Cell type:code id:9bc932d40fa4a87f tags:
``` python
import sys
!{sys.executable} -m pip install pulp
# Import of necessary packages
from pulp import LpProblem, LpVariable, lpSum, LpMinimize
# Create a new model
def optimze_battery_operation(el_demand_kW, pv_kWp, pv_pu, E_bat_kWh, P_bat_max_charge_kW, P_bat_max_discharge_kW, c_euro_kWh):
model = LpProblem("charging_optimization", LpMinimize)
# Decision Variables
buy = LpVariable.dicts("buy", range(24), lowBound=0) # The amount of electricity (in kW) bought from the grid at time t
soc = LpVariable.dicts("soc", range(25), lowBound=0, upBound=E_bat_kWh) # The State of Charge (in kWh) of the battery at time t
discharge = LpVariable.dicts("discharge", range(24), lowBound=0, upBound=P_bat_max_discharge_kW) # Discharge rate (in kW) at time t
charge = LpVariable.dicts("charge", range(24), lowBound=0, upBound=P_bat_max_charge_kW) # Charge rate (in kW) at time t
feedin = LpVariable.dicts("feedin", range(24), lowBound=0) # The amount of electricity (in kW) sold to the grid at time t
consumed_pv = LpVariable.dicts("consumed_pv", range(24), lowBound=0) # The amount of electricity (in kW) consumed directly from PV at time t
# Objective Function
model += lpSum(c_euro_kWh[t] * buy[t] for t in range(24))
# Constraints
model += soc[0] == E_bat_kWh/2
model += soc[23] == E_bat_kWh/2
# Energy balance for consumed electricity
for t in range(24):
model += el_demand_kW[t] == consumed_pv[t] + buy[t] + discharge[t]
# Energy balance for generated electricity
for t in range(24):
model += pv_kWp * pv_pu[t] == charge[t] + feedin[t] + consumed_pv[t]
# State of Charge
for t in range(23):
model += soc[t+1] == soc[t] + charge[t] - discharge[t]
# Solve the optimization problem
model.solve()
return model, buy, soc, feedin
```
%% Cell type:markdown id:4716844fbe8d1a33 tags:
Calculate the costs of electricity considering a 8 kWp PV plant and 3 kWh battery storage system. Assume that no income is generated by feeding the PV generated electricity into the grid. Plot the resulting state of charge (SOC) and buy time series and compare them to the other time series.
%% Cell type:code id:36908ba960de9d4b tags:
``` python
## call the optimization function
model, buy, soc, feedin_cost_minimizing = optimze_battery_operation(el_demand_kW, pv_kWp, pv_pu, E_bat_kWh, P_bat_max_charge_kW, P_bat_max_discharge_kW, c_euro_kWh)
# read results
buy_results = []
soc_results = []
feedin_cost_minimizing_results = []
for i in range(0,24):
buy_results.append(buy[i].value())
soc_results.append(soc[i].value())
feedin_cost_minimizing_results.append(feedin_cost_minimizing[i].value())
# print results calculated with time series
c_total_optimal = get_total_costs(buy_results, c_euro_kWh)
print(f"The total electricity costs are {round(c_total_optimal,2)}")
# print results from objective value (validation)
c_total_optimal = model.objective.value()
print(f"The total electricity costs are {round(c_total_optimal,2)}")
# plots
plot_time_series(el_demand_kW, c_euro_kWh, pv_pu, pv_kWp)
# !!! insert plot for Battery SOC
# !!! insert plot for electricity bought
plt.show()
```
%% Cell type:markdown id:f7e51d061cdba850 tags:
The SOC of the battery starts and ends at 50% of the maximum capacity, as this is specified by the constraints. Initially, the battery discharges as no PV power is generated. It is sufficient to charge the battery in the last hours of the day, as the size of the battery is comparatively small. It can be seen that the grid power is drawn in the time steps when the grid power is most favorable.
%% Cell type:markdown id:e323c8dc005ac6c6 tags:
# Task 2 e)
Change the battery optimization function (1 Variable, 1 Objective, 1 Constraint) below so that the maximium (single peak value, not sum of all values!) feed in from the pv plant to the grid gets minimized. How much was the maximum feed in without battery operation, with cost minimizing battery operation and with feed-in minimizing battery operation? Plot the resulting feed-in time series. You can take a look at the user guide of the library Pulp under the following [link](https://coin-or.github.io/pulp/main/includeme.html).
%% Cell type:code id:649d87d692c5365 tags:
``` python
# Import of necessary packages
from pulp import LpProblem, LpVariable, lpSum, LpMinimize
# Create a new model
def optimze_battery_operation_PV(el_demand_kW, pv_kWp, pv_pu, E_bat_kWh, P_bat_max_charge_kW, P_bat_max_discharge_kW, c_euro_kWh):
model = LpProblem("charging_optimization", LpMinimize)
# Decision Variables
buy = LpVariable.dicts("buy", range(24), lowBound=0) # The amount of electricity (in kW) bought from the grid at time t
soc = LpVariable.dicts("soc", range(25), lowBound=0, upBound=E_bat_kWh) # The State of Charge (in kWh) of the battery at time t
discharge = LpVariable.dicts("discharge", range(24), lowBound=0, upBound=P_bat_max_discharge_kW) # Discharge rate (in kW) at time t
charge = LpVariable.dicts("charge", range(24), lowBound=0, upBound=P_bat_max_charge_kW) # Charge rate (in kW) at time t
feedin = LpVariable.dicts("feedin", range(24), lowBound=0) # The amount of electricity (in kW) sold to the grid at time t
consumed_pv = LpVariable.dicts("consumed_pv", range(24), lowBound=0) # The amount of electricity (in kW) consumed directly from PV at time t
# !!! insert new variable
max_pv_feed_in = 0
# !!! insert new Objective Function
model += lpSum(0)
# Constraints
model += soc[0] == E_bat_kWh/2
model += soc[23] == E_bat_kWh/2
# Energy balance for consumed electricity
for t in range(24):
model += el_demand_kW[t] == consumed_pv[t] + buy[t] + discharge[t]
# Energy balance for generated electricity
for t in range(24):
model += pv_kWp * pv_pu[t] == charge[t] + feedin[t] + consumed_pv[t]
# State of Charge
for t in range(23):
model += soc[t+1] == soc[t] + charge[t] - discharge[t]
# !!! insert new constraint
for t in range(23):
model += max_pv_feed_in[0] >= feedin[t]
# Solve the optimization problem
model.solve()
return model, buy, soc, feedin
# call optimization function
model, buy, soc, feedin = optimze_battery_operation_PV(el_demand_kW, pv_kWp, pv_pu, E_bat_kWh, P_bat_max_charge_kW, P_bat_max_discharge_kW, c_euro_kWh)
# read results
feedin_results = []
for i in range(0,24):
feedin_results.append(feedin[i].value())
# max feed-in without battery:
max_feedin_1 = 0 # !!! <-- insert calculation
print(f"The maximum feed-in without battery operation is {max_feedin_1} kW.")
# max feed-in with cost minimizing battery operation:
max_feedin_2 = 0 # !!! <-- insert calculation
print(f"The maximum feed-in with cost minimizing battery operation is {max_feedin_2} kW.")
# max feed-in with feed-in minimizing battery operation:
max_feedin_3 = 0 # !!! <-- insert calculation
print(f"The maximum feed-in with feed-in minimizing battery operation is {max_feedin_3} kW.")
# !!! insert plots
plt.show()
```
%% Cell type:code id:21ab0d83302acf04 tags:
``` python
```
Loading