Note
You can download this example as a Jupyter notebook or start it in interactive mode.
Battery Electric Vehicle Charging
In this example a battery electric vehicle (BEV) is driven 100 km in the morning and 100 km in the evening, to simulate commuting, and charged during the day by a solar panel at the driver’s place of work. The size of the panel is computed by the optimisation.
The BEV has a battery of size 100 kWh and an electricity consumption of 0.18 kWh/km.
NB: this example will use units of kW and kWh, unlike the PyPSA defaults
[1]:
import pypsa
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
[2]:
# use 24 hour period for consideration
index = pd.date_range("2016-01-01 00:00","2016-01-01 23:00", freq="H")
# consumption pattern of BEV
bev_usage = pd.Series([0.]*7 + [9.]*2 + [0.]*8 + [9.]*2 + [0.]*5, index)
# solar PV panel generation per unit of capacity
pv_pu = pd.Series([0.]*7 + [0.2,0.4,0.6,0.75,0.85,0.9,0.85,0.75,0.6,0.4,0.2,0.1] + [0.]*5, index)
# availability of charging - i.e. only when parked at office
charger_p_max_pu = pd.Series(0, index=index)
charger_p_max_pu["2016-01-01 09:00":"2016-01-01 16:00"] = 1.
[3]:
df = pd.concat({'BEV': bev_usage, 'PV': pv_pu, 'Charger': charger_p_max_pu}, axis=1)
df.plot.area(subplots=True, figsize=(10,7))
plt.tight_layout()
Initialize the network
[4]:
network = pypsa.Network()
network.set_snapshots(index)
network.add("Bus",
"place of work",
carrier="AC")
network.add("Bus",
"battery",
carrier="Li-ion")
network.add("Generator",
"PV panel",
bus="place of work",
p_nom_extendable=True,
p_max_pu=pv_pu,
capital_cost=1000.)
network.add("Load",
"driving",
bus="battery",
p_set=bev_usage)
network.add("Link",
"charger",
bus0="place of work",
bus1="battery",
p_nom=120, #super-charger with 120 kW
p_max_pu=charger_p_max_pu,
efficiency=0.9)
network.add("Store",
"battery storage",
bus="battery",
e_cyclic=True,
e_nom=100.)
[5]:
network.lopf()
print("Objective:",network.objective)
INFO:pypsa.opf:Performed preliminary steps
INFO:pypsa.opf:Building pyomo model using `kirchhoff` formulation
INFO:pypsa.opf:Solving model using glpk
INFO:pypsa.opf:Optimization successful
# ==========================================================
# = Solver Results =
# ==========================================================
# ----------------------------------------------------------
# Problem Information
# ----------------------------------------------------------
Problem:
- Name: unknown
Lower bound: 7017.54385964912
Upper bound: 7017.54385964912
Number of objectives: 1
Number of constraints: 169
Number of variables: 98
Number of nonzeros: 277
Sense: minimize
# ----------------------------------------------------------
# Solver Information
# ----------------------------------------------------------
Solver:
- Status: ok
Termination condition: optimal
Statistics:
Branch and bound:
Number of bounded subproblems: 0
Number of created subproblems: 0
Error rc: 0
Time: 0.0032958984375
# ----------------------------------------------------------
# Solution Information
# ----------------------------------------------------------
Solution:
- number of solutions: 0
number of solutions displayed: 0
Objective: 7017.54385964912
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.19.1/lib/python3.10/site-packages/pypsa/opf.py:1293: FutureWarning: Using the level keyword in DataFrame and Series aggregations is deprecated and will be removed in a future version. Use groupby instead. df.sum(level=1) should use df.groupby(level=1).sum().
pd.concat({c.name:
The optimal panel size in kW is
[6]:
network.generators.p_nom_opt["PV panel"]
[6]:
7.01754385964912
[7]:
network.generators_t.p.plot.area(figsize = (9,4))
plt.tight_layout()
[8]:
df = pd.DataFrame({attr: network.stores_t[attr]["battery storage"] for attr in ["p","e"]})
df.plot(grid=True, figsize = (10,5))
plt.legend(labels=['Energy output', 'State of charge'])
plt.tight_layout()
The losses in kWh per pay are:
[9]:
network.generators_t.p.loc[:,"PV panel"].sum() - network.loads_t.p.loc[:,"driving"].sum()
[9]:
3.9999999999999716
[10]:
network.links_t.p0.plot.area(figsize = (9,5))
plt.tight_layout()