In [1]:
import sys
import os
import contextlib
import pandas as pd 
import altair as alt
alt.data_transformers.enable("vegafusion")
sys.path.append(os.path.abspath(os.path.join('..', 'src')))
from gridSavers import (
    optimize_battery_schedule_df_flexible_end,
    run_weekly_optimization_with_daily_usage,
    simulate_all_nodes, 
    prepare_visualization, 
    plot_altair_separate
)

Grid Savers: Potential Benifits to Utilize V2G¶

By Rafe Chang, Manjari Asawa, Ruben Darancou

Repo Link: https://github.com/rafecchang/gridSavers

Using a Vehicle to Grid (V2G) system, utilities can benifit from lower residential demands during peak hours, which cuts the cost of purchasing electricity in the wholesale power market. In this report, we are interested in simulating the potential financial profit from implementing such technology.

Table of Contents¶

  • Introduction
  • Analysis
  • Discussion

Introduction¶

In modern connected power grids, electricity flows across regions, and in deregulated markets, energy generators and consumers engage in transactions through competitive power markets. Independent System Operators (ISOs) play a key role in overseeing these markets, ensuring reliable electricity delivery and providing fair access for all participants.

V2G is an innovative technology that enables electric vehicles (EVs) not only to draw power from the grid for charging but also to send stored energy back when needed. This bidirectional energy flow helps balance supply and demand, contributing to grid stability.

With V2G, EVs can participate in energy arbitrage—selling electricity back to the grid during high-demand, high-price periods—creating a potential revenue stream for EV owners. However, most residential EV owners cannot directly access wholesale energy markets due to challenges such as differences in voltage levels, market rules, and the small scale of individual vehicles. Hopefully, through utilities or aggregators, many EVs can be bundled together to meet the requirements of large-scale power markets, allowing residential users to benefit from V2G without needing direct access to complex energy trading systems.

California's electricity grid heavily integrates renewable energy sources, making it an ideal setting for exploring V2G technology. The grid requires flexible solutions like V2G to balance renewable energy generation with demand. By leveraging California's market data, this project can assess how V2G systems help support renewable energy integration and grid stability.

Assumptions¶

  • The charging rate is constant across all states of charge (SoC)
  • The change in demand and supply will not effect wholesale electricity pricing
  • The simulation does not account for voltage differences, which could impact the integration of V2G technology

Data¶

  • Local Marginal Price (LMP) of the Day Ahead Market (DAM) in CAISO on May 5th and May6th
    • Retrieved throught CAISO's OASIS Website
      • PRICES/ Energy Prices/ Locational Marginal Prices
      • Date From 05/05/2025 to 05/06/2025; Market: DAM; Group: ALL_APNODES
    • Loaded as allNodes in this notebook
  • LMP of DAM at POD_ADLIN_1_UNITS-APND
    • Retrieved throught CAISO's OASIS Website
      • PRICES/ Energy Prices/ Locational Marginal Prices
      • Date From 04/07/2025 to 05/06/2025; Market: DAM; Group: POD_ADLIN_1_UNITS-APND
    • Loaded as monthly in this notebook
  • On average, American drivers drive 30.1 miles everyday
  • For the charger side: We are using the Tesla Wall Connector that has a 11.5 kW output, which is equal to 44 miles. We assume the power input is the same rate
  • For the EV/ battery side: Below is the Useable Battery Capacity of Full Electric Vehicles (Tesla)
Model Useable Battery Capacity (kWh)
S Dual Motor 95
S Plaid 95
X Dual Motor 95
X Plaid 95
Y Long Range AWD 75
Y Long Range AWD Launch Series 75
Y Long Range RWD 75
3 Performance 75
3 Long Range Dual Motor 75
3 Long Range RWD 75
Y RWD 60
3 57.5

Preprocessing¶

allNodes and monthly is preprocess with /src/preprocess.py.

Analysis¶

EDA¶

allNodes has 116,112 rows, each role contains the electricity price per MW in the given hour at the given node.

In [2]:
allNodes = pd.read_csv('../data/preprocessed/0506pre.csv')
allNodes['INTERVALSTARTTIME'] = pd.to_datetime(allNodes['INTERVALSTARTTIME'])
allNodes.head() 
Out[2]:
OPR_DT NODE MW INTERVALSTARTTIME INTERVALENDTIME Hour_Label
0 2025-05-05 AFPR_1_TOT_GEN-APND 34.41489 2025-05-05 00:00:00 2025-05-05 01:00:00 00:00-01:00
1 2025-05-05 AFPR_1_TOT_GEN-APND 34.37762 2025-05-05 01:00:00 2025-05-05 02:00:00 01:00-02:00
2 2025-05-05 AFPR_1_TOT_GEN-APND 34.11542 2025-05-05 02:00:00 2025-05-05 03:00:00 02:00-03:00
3 2025-05-05 AFPR_1_TOT_GEN-APND 33.97113 2025-05-05 03:00:00 2025-05-05 04:00:00 03:00-04:00
4 2025-05-05 AFPR_1_TOT_GEN-APND 34.23300 2025-05-05 04:00:00 2025-05-05 05:00:00 04:00-05:00
In [3]:
chart_allNode = alt.Chart(allNodes).mark_line(interpolate='step-after').encode(
    x=alt.X('INTERVALSTARTTIME:T', title='Time Interval'),
    y=alt.Y('MW:Q', title='Price ($/MWh)'),
    color='NODE:N',
    tooltip=['NODE', 'Hour_Label', 'MW']
).properties(
    title='Day-Ahead LMP ($/MWh) Over Time by Node',
    width=800,
    height=400
).interactive()

chart_allNode
Out[3]:

From the plot, we found high variability across different nodes. We want to find the ones with higher profitability to illustrate the benifit of V2G implementation.

V2G Modeling¶

Case Specifications:¶

  • The resident has an EV with a battery of 95 kWh
  • The resident has a charger of 11.5 kWh/h output
  • The resident uses the EV from 8:00 - 18:00 and is participated in V2G program controled by the utility from 18:00 - 8:00
  • The resident travels 30.1 miles a day

Method:¶

We used dynamic programming to compute the optimal schedule of charging and discharging a battery over a series of discrete time intervals (i.e., hours in a day) to maximize profit from electricity price arbitrage. Accounted for battery constraints (capacity, minimum state of charge, max charge/discharge rates.)

Applied the algorithm across all nodes in allNodes.

Results:¶

In [4]:
with contextlib.redirect_stdout(open(os.devnull, 'w')):
    node_profit_df = simulate_all_nodes(allNodes)
    
chart_allsim = alt.Chart(node_profit_df).mark_bar(color = '#3A7DC1').encode(
    x=alt.X('Total Profit ($):Q', title='Total Profit ($)'),
    y=alt.Y('count()', title='Count'),
    tooltip=[
        alt.Tooltip('Total Profit ($):Q', title='Total Profit ($)', format='.2f'),
        alt.Tooltip('count()', title='Node Count')
    ]
).properties(
    width=600,
    height=400,
    title='Count of Nodes by Arbitrage Profit'
)
chart_allsim
Out[4]:
In [ ]:
profit_counts = node_profit_df['Total Profit ($)'].apply(lambda x: 'negative' if x < 0 else 'zero' if x == 0 else 'positive').value_counts(normalize=True) * 100

print(f"Total Profit accounts for the electricity used to charge EVs; on a single night simulation- \n"
      f"V2G system at {profit_counts.get('negative', 0):.2f}% of the nodes didn't made enough to make EV charging free\n"
      f"V2G system at {profit_counts.get('zero', 0):.2f}% of the nodes made enough to make EV charging free \n"
      f"V2G system at {profit_counts.get('positive', 0):.2f}% of the nodes made more than what it takes to charge their EVs")
Total Profit accounts for the electricity used to charge EVs; on a single night simulation- 
V2G system at 83.90% of the nodes did not make enough to make up for EV charging 
V2G system at 13.41% of the nodes made enough to make EV charging free 
V2G system at 2.69% of the nodes made more than what it takes to charge their EVs
In [6]:
node_profit_df.head(5)
Out[6]:
NODE Total Profit ($)
0 POD_ADLIN_1_UNITS-APND 4.982919
1 SLAP_PGNC-APND 4.934240
2 PGNC_1_PDRP19-APND 4.916442
3 PGNC_1_PDRP17-APND 4.916442
4 PGNC_1_PDRP01-APND 4.916442
  • Node POD_ADLIN_1_UNITS-APND appeared to have the most profitability with the one day of simulation. Let's retrieve more data from this location
  • Below is the LMP of node POD_ADLIN_1_UNITS-APND from 2025-04-07 to 2025-05-06
In [7]:
monthly = pd.read_csv('../data/preprocessed/monthlypre.csv')
monthly['INTERVALSTARTTIME'] = pd.to_datetime(monthly['INTERVALSTARTTIME'])

chart_month = alt.Chart(monthly).mark_line(color = '#3A7DC1', interpolate='step-after').encode(
    x='INTERVALSTARTTIME:T',
    y='MW:Q',
    tooltip=['Hour_Label', 'MW']
).properties(
    title='Day-Ahead LMP ($/MWh) for Node- POD_ADLIN_1_UNITS-APND',
    width=800,
    height=400
).interactive()

chart_month
Out[7]:
In [8]:
with contextlib.redirect_stdout(open(os.devnull, 'w')):
    monthly_result = run_weekly_optimization_with_daily_usage(
        monthly,
        initial_soc=66.5,
        daily_miles=30.1,
        miles_per_kwh=3.83 
    )

print("By participating with V2G, the utility can profit", round(monthly_result["Profit ($)"].sum(), 2), "dollars with the EV owner benifit from charging for free during the window of April 7th to May 6th. ")
By participating with V2G, the utility can profit 28.21 dollars with the EV owner benifit from charging for free during the window of April 7th to May 6th. 
In [9]:
df_all = prepare_visualization(monthly_result, monthly)
chart_monthsim = plot_altair_separate(df_all)
chart_monthsim
Out[9]:

Discussion¶

By increasing battery storage and reducing peak demand, utilities can avoid significant grid construction costs. Further opportunities could arise from incorporating EV charging during the day (8:00 AM – 6:00 PM), which would help shift demand and maximize the grid’s efficiency. The power market benefits when all participants make decisions that maximize their self-interest, contributing to a more efficient and stable system, a process that could be further enhanced if utilities integrate V2G technology.

Findings¶

This simulation estimates the arbitrage benefits utilities can gain. For instance, at node POD_ADLIN_1_UNITS-APND, a V2G system with a Tesla Wall Connector and Model S/Model X battery can generate an additional $28.21 in 30 days. It also provides a budget reference for utilities considering similar programs.

Limitations¶

  • The simulation doesn't include the Real-Time Market
  • The simulation doesn't account for the implementation costs of the technology