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¶
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
allNodesin this notebook
- Retrieved throught CAISO's OASIS Website
- 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
monthlyin this notebook
- Retrieved throught CAISO's OASIS Website
- 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.
allNodes = pd.read_csv('../data/preprocessed/0506pre.csv')
allNodes['INTERVALSTARTTIME'] = pd.to_datetime(allNodes['INTERVALSTARTTIME'])
allNodes.head()
| 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 |
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