Title: | Electric Vehicle Charging Sessions Simulation |
---|---|
Description: | Simulation of Electric Vehicles charging sessions using Gaussian models, together with time-series power demand calculations. The simulation methodology is published in Cañigueral et al. (2023, ISBN:0957-4174) <doi:10.1016/j.eswa.2023.120318>. |
Authors: | Marc Cañigueral [aut, cre] |
Maintainer: | Marc Cañigueral <[email protected]> |
License: | GPL-3 |
Version: | 1.6.1 |
Built: | 2025-01-26 05:41:45 UTC |
Source: | https://github.com/mcanigueral/evsim |
Calculate connection and charging times according to energy, power and time resolution
adapt_charging_features( sessions, time_resolution = 15, power_resolution = 0.01 )
adapt_charging_features( sessions, time_resolution = 15, power_resolution = 0.01 )
sessions |
tibble, sessions data set in standard format marked by |
time_resolution |
integer, time resolution (in minutes) of the sessions' datetime variables |
power_resolution |
numeric, power resolution (in kW) of the sessions' power |
All sessions' Power
must be higher than 0
, to avoid NaN
values from dividing
by zero.
The ConnectionStartDateTime
is first aligned to the desired time resolution,
and the ConnectionEndDateTime
is calculated according to the ConnectionHours
.
The ChargingHours
is recalculated with the values of Energy
and Power
,
limited by ConnectionHours
. Finally, the charging times are also calculated.
tibble
suppressMessages(library(dplyr)) sessions <- head(evsim::california_ev_sessions, 10) sessions %>% select(ConnectionStartDateTime, ConnectionEndDateTime, Power) adapt_charging_features( sessions, time_resolution = 60, power_resolution = 0.01 ) %>% select(ConnectionStartDateTime, ConnectionEndDateTime, Power) adapt_charging_features( sessions, time_resolution = 15, power_resolution = 1 ) %>% select(ConnectionStartDateTime, ConnectionEndDateTime, Power)
suppressMessages(library(dplyr)) sessions <- head(evsim::california_ev_sessions, 10) sessions %>% select(ConnectionStartDateTime, ConnectionEndDateTime, Power) adapt_charging_features( sessions, time_resolution = 60, power_resolution = 0.01 ) %>% select(ConnectionStartDateTime, ConnectionEndDateTime, Power) adapt_charging_features( sessions, time_resolution = 15, power_resolution = 1 ) %>% select(ConnectionStartDateTime, ConnectionEndDateTime, Power)
Variable ChargingStation
and Socket
will be assigned to the sessions
tibble with a name pattern being: names_prefix
+ "CHS" + number
add_charging_infrastructure( sessions, resolution = 15, min_stations = 0, n_sockets = 2, names_prefix = NULL, duration_th = 0 )
add_charging_infrastructure( sessions, resolution = 15, min_stations = 0, n_sockets = 2, names_prefix = NULL, duration_th = 0 )
sessions |
tibble, sessions data set in standard format marked by |
resolution |
integer, time resolution in minutes |
min_stations |
integer, minimum number of charging stations to consider |
n_sockets |
integer, number of sockets per charging station |
names_prefix |
character, prefix of the charging station names (optional) |
duration_th |
integer between 0 and 100, minimum share of time (in percentage)
of the "occupancy duration curve" (see function |
tibble
# Assign a `ChargingStation` to every session according to the occupancy sessions_infrastructure <- add_charging_infrastructure( sessions = head(evsim::california_ev_sessions, 50), resolution = 60 ) print(unique(sessions_infrastructure$ChargingStation)) # Now without considering the occupancy values that only represent # a 10% of the time sessions_infrastructure <- add_charging_infrastructure( sessions = head(evsim::california_ev_sessions, 50), resolution = 60, duration_th = 10 ) print(unique(sessions_infrastructure$ChargingStation))
# Assign a `ChargingStation` to every session according to the occupancy sessions_infrastructure <- add_charging_infrastructure( sessions = head(evsim::california_ev_sessions, 50), resolution = 60 ) print(unique(sessions_infrastructure$ChargingStation)) # Now without considering the occupancy values that only represent # a 10% of the time sessions_infrastructure <- add_charging_infrastructure( sessions = head(evsim::california_ev_sessions, 50), resolution = 60, duration_th = 10 ) print(unique(sessions_infrastructure$ChargingStation))
Every session in sessions
is divided in multiple time slots
with the corresponding Power
consumption, among other variables.
expand_sessions(sessions, resolution)
expand_sessions(sessions, resolution)
sessions |
tibble, sessions data set in standard format marked by |
resolution |
integer, time resolution (in minutes) of the time slots |
The Power
value is calculated for every time slot according to the original
required energy. The columns PowerNominal
, EnergyRequired
and
FlexibilityHours
correspond to the values of the original session, and not
to the expanded session in every time slot. The column ID
shows the number
of the time slot corresponding to the original session.
tibble
library(dplyr) sessions <- head(evsim::california_ev_sessions, 10) expand_sessions( sessions, resolution = 60 )
library(dplyr) sessions <- head(evsim::california_ev_sessions, 10) expand_sessions( sessions, resolution = 60 )
Get charging rates distribution in percentages from a charging sessions data set
get_charging_rates_distribution(sessions, unit = "year", power_interval = NULL)
get_charging_rates_distribution(sessions, unit = "year", power_interval = NULL)
sessions |
tibble, sessions data set in standard format marked by |
unit |
character. Valid base units are |
power_interval |
numeric, interval of kW between power rates.
It is used to round the |
tibble
get_charging_rates_distribution(evsim::california_ev_sessions, unit = "year")
get_charging_rates_distribution(evsim::california_ev_sessions, unit = "year")
Get the EV model object of class evmodel
get_custom_ev_model( names, months_lst = list(1:12, 1:12), wdays_lst = list(1:5, 6:7), parameters_lst, connection_log, energy_log, data_tz )
get_custom_ev_model( names, months_lst = list(1:12, 1:12), wdays_lst = list(1:5, 6:7), parameters_lst, connection_log, energy_log, data_tz )
names |
character vector with the given names of each time-cycle model |
months_lst |
list of integer vectors with the corresponding months of the year for each time-cycle model |
wdays_lst |
list of integer vectors with the corresponding days of the week for each time-cycle model (week start = 1) |
parameters_lst |
list of tibbles corresponding to the GMM parameters of every time-cycle model |
connection_log |
logical, true if connection models have logarithmic transformations |
energy_log |
logical, true if energy models have logarithmic transformations |
data_tz |
character, time zone of the original data (necessary to properly simulate new sessions) |
object of class evmodel
# For workdays time cycle workdays_parameters <- dplyr::tibble( profile = c("Worktime", "Visit"), ratio = c(80, 20), start_mean = c(9, 11), start_sd = c(1, 4), duration_mean = c(8, 4), duration_sd = c(0.5, 2), energy_mean = c(15, 6), energy_sd = c(4, 3) ) # For weekends time cycle weekends_parameters <- dplyr::tibble( profile = "Visit", ratio = 100, start_mean = 12, start_sd = 4, duration_mean = 3, duration_sd = 2, energy_mean = 4, energy_sd = 4 ) parameters_lst <- list(workdays_parameters, weekends_parameters) # Get the whole model ev_model <- get_custom_ev_model( names = c("Workdays", "Weekends"), months_lst = list(1:12, 1:12), wdays_lst = list(1:5, 6:7), parameters_lst = parameters_lst, connection_log = FALSE, energy_log = FALSE, data_tz = "Europe/Amsterdam" )
# For workdays time cycle workdays_parameters <- dplyr::tibble( profile = c("Worktime", "Visit"), ratio = c(80, 20), start_mean = c(9, 11), start_sd = c(1, 4), duration_mean = c(8, 4), duration_sd = c(0.5, 2), energy_mean = c(15, 6), energy_sd = c(4, 3) ) # For weekends time cycle weekends_parameters <- dplyr::tibble( profile = "Visit", ratio = 100, start_mean = 12, start_sd = 4, duration_mean = 3, duration_sd = 2, energy_mean = 4, energy_sd = 4 ) parameters_lst <- list(workdays_parameters, weekends_parameters) # Get the whole model ev_model <- get_custom_ev_model( names = c("Workdays", "Weekends"), months_lst = list(1:12, 1:12), wdays_lst = list(1:5, 6:7), parameters_lst = parameters_lst, connection_log = FALSE, energy_log = FALSE, data_tz = "Europe/Amsterdam" )
Obtain time-series of EV demand from sessions data set
get_demand( sessions, dttm_seq = NULL, by = "Profile", resolution = 15, mc.cores = 1 )
get_demand( sessions, dttm_seq = NULL, by = "Profile", resolution = 15, mc.cores = 1 )
sessions |
tibble, sessions data set in standard format marked by |
dttm_seq |
sequence of datetime values that will be the |
by |
character, being 'Profile' or 'Session'. When |
resolution |
integer, time resolution (in minutes) of the sessions datetime variables.
If |
mc.cores |
integer, number of cores to use. Must be at least one, and parallelization requires at least two cores. |
Note that the time resolution of variables ConnectionStartDateTime
and
ChargingStartDateTime
must coincide with
resolution
parameter. For example, if a charging session in sessions
starts charging
at 15:32 and resolution = 15
, the load of this session won't be computed. To solve this,
the function automatically aligns charging sessions' start time according to
resolution
, so following the previous example the session would start at 15:30.
time-series tibble with first column of type datetime
suppressMessages(library(lubridate)) suppressMessages(library(dplyr)) # Get demand with the complete datetime sequence from the sessions sessions <- head(evsim::california_ev_sessions, 100) demand <- get_demand( sessions, by = "Session", resolution = 60 ) demand %>% plot_ts(ylab = "EV demand (kW)") # Get demand with a custom datetime sequence and resolution of 15 minutes sessions <- head(evsim::california_ev_sessions_profiles, 100) dttm_seq <- seq.POSIXt( as_datetime(dmy(08102018)) %>% force_tz(tz(sessions$ConnectionStartDateTime)), as_datetime(dmy(11102018)) %>% force_tz(tz(sessions$ConnectionStartDateTime)), by = "15 mins" ) demand <- get_demand( sessions, dttm_seq = dttm_seq, by = "Profile", resolution = 15 ) demand %>% plot_ts(ylab = "EV demand (kW)")
suppressMessages(library(lubridate)) suppressMessages(library(dplyr)) # Get demand with the complete datetime sequence from the sessions sessions <- head(evsim::california_ev_sessions, 100) demand <- get_demand( sessions, by = "Session", resolution = 60 ) demand %>% plot_ts(ylab = "EV demand (kW)") # Get demand with a custom datetime sequence and resolution of 15 minutes sessions <- head(evsim::california_ev_sessions_profiles, 100) dttm_seq <- seq.POSIXt( as_datetime(dmy(08102018)) %>% force_tz(tz(sessions$ConnectionStartDateTime)), as_datetime(dmy(11102018)) %>% force_tz(tz(sessions$ConnectionStartDateTime)), by = "15 mins" ) demand <- get_demand( sessions, dttm_seq = dttm_seq, by = "Profile", resolution = 15 ) demand %>% plot_ts(ylab = "EV demand (kW)")
evmodel
parameters in a listEvery time cycle is an element of the returned list, containing a list with the user profile as elements, each one containing the ratio and the corresponding tables with the statistic parameters of connection and energy GMM.
get_evmodel_parameters(evmodel)
get_evmodel_parameters(evmodel)
evmodel |
object of class |
list
get_evmodel_parameters(evsim::california_ev_model)
get_evmodel_parameters(evsim::california_ev_model)
evmodel
parameters in a list of summary tablesEvery time cycle is an element of the returned list, containing a table with
a user profile in every row and the mean and standard deviation values of the
GMM variables (connection duration, connection start time and energy).
If the energy models were built by charging rate, the average mean
and sd
are provided without taking into account different charging rates (this
information is lost in this summary).
get_evmodel_summary(evmodel)
get_evmodel_summary(evmodel)
evmodel |
object of class |
list
get_evmodel_summary(evsim::california_ev_model)
get_evmodel_summary(evsim::california_ev_model)
Obtain time-series of simultaneously connected EVs from sessions data set
get_occupancy( sessions, dttm_seq = NULL, by = "Profile", resolution = 15, mc.cores = 1 )
get_occupancy( sessions, dttm_seq = NULL, by = "Profile", resolution = 15, mc.cores = 1 )
sessions |
tibble, sessions data set in standard format marked by |
dttm_seq |
sequence of datetime values that will be the |
by |
character, being 'Profile' or 'Session'. When |
resolution |
integer, time resolution (in minutes) of the sessions datetime variables.
If |
mc.cores |
integer, number of cores to use. Must be at least one, and parallelization requires at least two cores. |
Note that the time resolution of variable ConnectionStartDateTime
must coincide with
resolution
parameter. For example, if a charging session in sessions
starts charging
at 15:32 and resolution = 15
, the load of this session won't be computed. To solve this,
the function automatically aligns charging sessions' start time according to
resolution
, so following the previous example the session would start at 15:30.
time-series tibble with first column of type datetime
library(lubridate) library(dplyr) # Get occupancy with the complete datetime sequence from the sessions sessions <- head(evsim::california_ev_sessions, 100) connections <- get_occupancy( sessions, by = "ChargingStation", resolution = 60 ) connections %>% plot_ts(ylab = "Vehicles connected", legend_show = "onmouseover") # Get occupancy with a custom datetime sequence and resolution of 15 minutes sessions <- head(evsim::california_ev_sessions_profiles, 100) dttm_seq <- seq.POSIXt( as_datetime(dmy(08102018)) %>% force_tz(tz(sessions$ConnectionStartDateTime)), as_datetime(dmy(11102018)) %>% force_tz(tz(sessions$ConnectionStartDateTime)), by = "15 mins" ) connections <- get_occupancy( sessions, dttm_seq = dttm_seq, by = "Profile" ) connections %>% plot_ts(ylab = "Vehicles connected", legend_show = "onmouseover")
library(lubridate) library(dplyr) # Get occupancy with the complete datetime sequence from the sessions sessions <- head(evsim::california_ev_sessions, 100) connections <- get_occupancy( sessions, by = "ChargingStation", resolution = 60 ) connections %>% plot_ts(ylab = "Vehicles connected", legend_show = "onmouseover") # Get occupancy with a custom datetime sequence and resolution of 15 minutes sessions <- head(evsim::california_ev_sessions_profiles, 100) dttm_seq <- seq.POSIXt( as_datetime(dmy(08102018)) %>% force_tz(tz(sessions$ConnectionStartDateTime)), as_datetime(dmy(11102018)) %>% force_tz(tz(sessions$ConnectionStartDateTime)), by = "15 mins" ) connections <- get_occupancy( sessions, dttm_seq = dttm_seq, by = "Profile" ) connections %>% plot_ts(ylab = "Vehicles connected", legend_show = "onmouseover")
Get the user profiles distribution from the original data set used to build the model
get_user_profiles_distribution(evmodel)
get_user_profiles_distribution(evmodel)
evmodel |
object of class |
tibble
get_user_profiles_distribution(evsim::california_ev_model)
get_user_profiles_distribution(evsim::california_ev_model)
This term is based on the "load duration curve" and is useful to see the behavior of occupancy over the time in your charging installation. The steeper the curve, the shorter the duration that higher number of connections are sustained. Conversely, the flatter the curve, the longer the duration that higher number of connections are sustained. This information is crucial for various purposes, such as infrastructure planning, capacity sizing, and resource allocation.
plot_occupancy_duration_curve( sessions, dttm_seq = NULL, by = "Profile", resolution = 15, mc.cores = 1 )
plot_occupancy_duration_curve( sessions, dttm_seq = NULL, by = "Profile", resolution = 15, mc.cores = 1 )
sessions |
tibble, sessions data set in standard format marked by |
dttm_seq |
sequence of datetime values that will be the |
by |
character, being 'Profile' or 'Session'. When |
resolution |
integer, time resolution (in minutes) of the sessions datetime variables.
If |
mc.cores |
integer, number of cores to use. Must be at least one, and parallelization requires at least two cores. |
ggplot
library(dplyr) sessions <- head(evsim::california_ev_sessions_profiles, 100) plot_occupancy_duration_curve( sessions, by = "Profile", resolution = 15 )
library(dplyr) sessions <- head(evsim::california_ev_sessions_profiles, 100) plot_occupancy_duration_curve( sessions, by = "Profile", resolution = 15 )
First column of the df
tibble must be a datetime
or date variable.
The rest of columns must be numeric of the same units. This functions makes
use of dygraphs
package to generate an HTML Dygraphs plot.
plot_ts( df, title = NULL, xlab = NULL, ylab = NULL, legend_show = "auto", legend_width = 250, group = NULL, width = NULL, height = NULL, ... )
plot_ts( df, title = NULL, xlab = NULL, ylab = NULL, legend_show = "auto", legend_width = 250, group = NULL, width = NULL, height = NULL, ... )
df |
data.frame or tibble, first column of name |
title |
character, title of the plot (accepts HTML code) |
xlab |
character, X axis label (accepts HTML code) |
ylab |
character, Y axis label (accepts HTML code) |
legend_show |
character, when to display the legend. Specify "always" to always show the legend. Specify "onmouseover" to only display it when a user mouses over the chart. Specify "follow" to have the legend show as overlay to the chart which follows the mouse. The default behavior is "auto", which results in "always" when more than one series is plotted and "onmouseover" when only a single series is plotted. |
legend_width |
integer, width (in pixels) of the div which shows the legend. |
group |
character, dygraphs group to associate this plot with. The x-axis zoom level of dygraphs plots within a group is automatically synchronized. |
width |
Width in pixels (optional, defaults to automatic sizing) |
height |
Height in pixels (optional, defaults to automatic sizing) |
... |
extra arguments to pass to |
dygraph
suppressMessages(library(lubridate)) suppressMessages(library(dplyr)) # Get demand with the complete datetime sequence from the sessions sessions <- head(evsim::california_ev_sessions, 100) demand <- get_demand( sessions, by = "Session", resolution = 60 ) demand %>% plot_ts()
suppressMessages(library(lubridate)) suppressMessages(library(dplyr)) # Get demand with the complete datetime sequence from the sessions sessions <- head(evsim::california_ev_sessions, 100) demand <- get_demand( sessions, by = "Session", resolution = 60 ) demand %>% plot_ts()
Read an EV model JSON file and convert it to object of class evmodel
read_ev_model(file)
read_ev_model(file)
file |
path to the JSON file |
object of class evmodel
ev_model <- california_ev_model # Model of example save_ev_model(ev_model, file = file.path(tempdir(), "evmodel.json")) read_ev_model(file = file.path(tempdir(), "evmodel.json"))
ev_model <- california_ev_model # Model of example save_ev_model(ev_model, file = file.path(tempdir(), "evmodel.json")) read_ev_model(file = file.path(tempdir(), "evmodel.json"))
Save the EV model object of class evmodel
to a JSON file
save_ev_model(evmodel, file)
save_ev_model(evmodel, file)
evmodel |
object of class |
file |
character string with the path or name of the file |
nothing but saves the evmodel
object in a JSON file
ev_model <- california_ev_model # Model of example save_ev_model(ev_model, file = file.path(tempdir(), "evmodel.json"))
ev_model <- california_ev_model # Model of example save_ev_model(ev_model, file = file.path(tempdir(), "evmodel.json"))
Simulate EV charging sessions given the evmodel
object and other contextual parameters.
simulate_sessions( evmodel, sessions_day, user_profiles, charging_powers, dates, resolution )
simulate_sessions( evmodel, sessions_day, user_profiles, charging_powers, dates, resolution )
evmodel |
object of class |
sessions_day |
tibble with variables |
user_profiles |
tibble with variables |
charging_powers |
tibble with variables |
dates |
date sequence that will set the time frame of the simulated sessions |
resolution |
integer, time resolution (in minutes) of the sessions datetime variables |
Some adaptations have been done to the output of the Gaussian models: the minimum simulated energy is considered to be 1 kWh, while the minimum connection duration is 30 minutes.
tibble
library(dplyr) library(lubridate) # Get the example `evmodel` ev_model <- evsim::california_ev_model # Simulate EV charging sessions, considering that the Worktime sessions # during Workdays have 11 kW, while all Visit sessions charge at 3.7kW or # 11kW, with a distribution of 30% and 70% respectively. simulate_sessions( ev_model, sessions_day = tibble( time_cycle = c("Workday", "Weekend"), n_sessions = c(15, 10) ), user_profiles = tibble( time_cycle = c("Workday", "Workday", "Weekend"), profile = c("Visit", "Worktime", "Visit"), ratio = c(0.5, 0.5, 1), power = c(NA, 11, NA) ), charging_powers = tibble( power = c(3.7, 11), ratio = c(0.3, 0.7) ), dates = seq.Date(today(), today()+days(4), length.out = 4), resolution = 15 )
library(dplyr) library(lubridate) # Get the example `evmodel` ev_model <- evsim::california_ev_model # Simulate EV charging sessions, considering that the Worktime sessions # during Workdays have 11 kW, while all Visit sessions charge at 3.7kW or # 11kW, with a distribution of 30% and 70% respectively. simulate_sessions( ev_model, sessions_day = tibble( time_cycle = c("Workday", "Weekend"), n_sessions = c(15, 10) ), user_profiles = tibble( time_cycle = c("Workday", "Workday", "Weekend"), profile = c("Visit", "Worktime", "Visit"), ratio = c(0.5, 0.5, 1), power = c(NA, 11, NA) ), charging_powers = tibble( power = c(3.7, 11), ratio = c(0.3, 0.7) ), dates = seq.Date(today(), today()+days(4), length.out = 4), resolution = 15 )