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.

In [1]:
import pypsa

import pandas as pd

%matplotlib inline
In [2]:
# NB: this example will use units of kW and kWh, unlike the PyPSA defaults

# 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.
In [3]:
bev_usage.plot()
pv_pu.plot()
charger_p_max_pu.plot()
Out[3]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f7ef4e3be10>
In [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.)
WARNING:pypsa.components:Attribute network.now is not in newly-defined snapshots. (network.now is only relevant if you call e.g. network.pf() without specifying snapshots.)
In [5]:
network.lopf(network.snapshots)
print("Objective:",network.objective)
INFO:pypsa.pf:Slack bus for sub-network 0 is place of work
WARNING:pypsa.pf:No generators in sub-network 1, better hope power is already balanced
INFO:pypsa.pf:Slack bus for sub-network 1 is battery
INFO:pypsa.opf:Performed preliminary steps
INFO:pypsa.opf:Building pyomo model using `angles` formulation
INFO:pypsa.opf:Solving model using glpk
INFO:pypsa.opf:Optimization successful
('Objective:', 7017.54385964912)
In [6]:
print("Pannel size [kW]:",network.generators.p_nom_opt["PV panel"])
('Pannel size [kW]:', 7.0175438596491198)
In [7]:
network.generators_t.p.plot()
Out[7]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f7ef28f9310>
In [8]:
pd.DataFrame({attr: network.stores_t[attr]["battery storage"] for attr in ["p","e"]}).plot(grid=True)
Out[8]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f7ef2843b50>
In [9]:
print("Losses [kWh/d]:",network.generators_t.p.loc[:,"PV panel"].sum() - network.loads_t.p.loc[:,"driving"].sum())
('Losses [kWh/d]:', 3.9999999999999716)
In [10]:
network.links_t.p0.plot()
Out[10]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f7ef277af10>