knitr::opts_chunk$set(echo = TRUE, message = F, warning = F, error = F, fig.width = 9)
library(evsim)
library(dplyr)
library(lubridate)

Functions simulate_sessions(), get_demand() or get_occupancy() requires a parameter called resolution, which defines the minutes between a time-slot and the following one.

For example, if resolution = 15, the charging sessions simulated during 4 PM of a specific day will start at 16:00, 16:15, 16:30 or 16:45, but not during any time between these time-slots. However, the connection duration of every session can have any value, so the session can finish at 16:22 for instance. The same concept is applied to the charging times.

Therefore, the function get_demand gives the average charging power during a certain time-slot. If we use a resolution = 15, a demand of 55kW for time-slot 16:30 means that between 16:30 and 16:45 it has been consumed the energy corresponding to an average power of 55 kW (so 55ยท15/60=13.75 kWh). This can modify the power profile of sessions that stop charging at a time between time-slots. For example, considering a resolution = 15 and a session charging at 10kW from 16:30 to 16:55, the demand of time-slot 16:30 will be 10kW but the demand of time-slot 16:45 will decrease to 6.67 kW (charging only 3/4 parts of the time-slot). The "real" power profile of the session is a constant power step of 10kW, but the demand profile obtained with a resolution = 15 does not. To obtain a more accurate power profile of the session, the resolution parameter should be set to higher resolutions (until a maximum of 1 minute).

Finally, note that the resolution parameter of time-series functions (i.e. get_demand() and get_n_connections()) does not have to correspond necessarily to the resolution of simulated sessions, even though it would not have much sense to obtain the time-series demand in a lower resolution (longer time intervals) than sessions since we loose accuracy on the power profile.

Let's see and example simulating 10 charging sessions with a resolution of 30 minutes:

# Required parameters first
ev_model <- evsim::california_ev_model

sessions_day <- tibble(
  time_cycle = ev_model$models$time_cycle,
  n_sessions = c(10, 10)
)

user_profiles <- get_user_profiles_distribution(ev_model)

charging_powers <- tibble(
  power = c(3.7, 7.3, 11),
  ratio = c(0.2, 0.4, 0.4)
)

# Sessions simulation
set.seed(123)
sessions <- simulate_sessions(
  ev_model,
  sessions_day,
  user_profiles,
  charging_powers,
  dmy("31/01/2023"),
  resolution = 30
) %>% 
  mutate(Profile = 'Users')
sessions %>% 
  select_if(is.timepoint) %>% 
  mutate_all(format, "%d/%m/%Y %H:%M") %>% 
  knitr::kable()

If we calculate the aggregated demand of the above simulated sessions with a resolution of 5, 15 and 30, the resulting power profile loses accuracy when we decrease the time resolution (so higher time intervals):

demand_5 <- sessions %>%
  get_demand(resolution = 5)

demand_15 <- sessions %>%
  get_demand(resolution = 15)

demand_30 <- sessions %>%
  get_demand(resolution = 30)

Then we can create a common object to compare the three vectors of EV demand, making use of dplyr::left_join to join by datetime and tidyr::fill to fill the gaps with the previous exisiting power:

demand_comparison <- demand_5 %>% 
  rename(`5-minute resolution` = Users) %>% 
  left_join(
    rename(demand_15, `15-minute resolution` = Users)
  ) %>% 
  left_join(
    rename(demand_30, `30-minute resolution` = Users)
  ) %>% 
  tidyr::fill(-datetime, .direction = 'down')

demand_comparison %>% 
  plot_ts(stepPlot = T, strokeWidth = 2, ylab = "EV demand (kW)")

The power profile with a resolution of 5 minutes represents in a higher accuracy when sessions start and finish. If we zoom-in, we can see clearly that the average power profile really depends on the time resolution:

demand_comparison %>% 
  filter(
    datetime >= dmy_h("31/01/2023 16", tz = ev_model$metadata$tzone),
    datetime < dmy_h("31/01/2023 19", tz = ev_model$metadata$tzone)
  ) %>% 
  plot_ts(stepPlot = T, strokeWidth = 2, ylab = "EV demand (kW)")

However, the total area of the three lines (energy consumed) corresponds to the same value since the power values are the average power of every time-slot whatever the resolution is:

sum(demand_5$Users*5/60) # in kWh
sum(demand_15$Users*15/60) # in kWh
sum(demand_30$Users*30/60) # in kWh


mcanigueral/evsim documentation built on April 5, 2025, 3:05 a.m.