The smart_charging()
function provides some parameters
that may not be required in most of simulations but configuring them in
specific cases can make a huge difference. This article raises some
cases where a more advanced knowledge and configuration of these
parameters may be required to obtain the desired results.
For the smart charging examples in this article, the same example
data sets energy_data
and ev_sessions
from the
article Smart charging will be used:
head(energy_data)
## # A tibble: 6 × 7
## datetime solar building price_imported price_exported price_turn_up
## <dttm> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2023-05-01 00:00:00 0 3.06 0.0999 0.025 0.104
## 2 2023-05-01 00:15:00 0 2.98 0.0999 0.025 0.0993
## 3 2023-05-01 00:30:00 0 2.90 0.0999 0.025 0
## 4 2023-05-01 00:45:00 0 2.82 0.0999 0.025 0
## 5 2023-05-01 01:00:00 0 2.74 0.0955 0.025 0
## 6 2023-05-01 01:15:00 0 2.64 0.0955 0.025 0
## # ℹ 1 more variable: price_turn_down <dbl>
head(ev_sessions)
## # A tibble: 6 × 11
## Session Timecycle Profile ConnectionStartDateTime ConnectionEndDateTime
## <chr> <chr> <chr> <dttm> <dttm>
## 1 S1 Workdays HomeEV 2023-05-01 13:45:00 2023-05-02 03:46:00
## 2 S2 Workdays HomeEV 2023-05-01 14:00:00 2023-05-02 04:33:00
## 3 S3 Workdays HomeEV 2023-05-01 14:15:00 2023-05-02 03:01:00
## 4 S4 Workdays HomeEV 2023-05-01 17:30:00 2023-05-02 07:09:00
## 5 S5 Workdays HomeEV 2023-05-01 21:45:00 2023-05-02 11:47:00
## 6 S6 Workdays HomeEV 2023-05-02 10:15:00 2023-05-02 23:13:00
## # ℹ 6 more variables: ChargingStartDateTime <dttm>, ChargingEndDateTime <dttm>,
## # Power <dbl>, Energy <dbl>, ConnectionHours <dbl>, ChargingHours <dbl>
For all smart charging simulations the following parameters will be considered:
- scheduling method: curtail
- optimization window days: 1
- optimization window start hour: 6:00 AM
The EV demand is pushed to the end of the optimization window
Usually applying the smart_charging()
function with
default configuration will not prevent that some EV users surpass their
setpoints, due to a lack of flexibility from the EV sessions. When this
happens, normally it results in a higher demand at the end of the
optimization window because the smart charging algorithm tries to match
the setpoint until there’s no more flexibility from the EV users and the
EV must be charged.
Below, we will see examples of these situations for the 2 types of
setpoints that smart_charging()
function can consider (grid
capacity setpoint and optimization setpoint), and how to deal with
that.
Setpoint as grid capacity
Imagine that there’s a maximum grid connection has to be reduced to 4 kW, so that we can charge only one EV at a time:
grid_capacity <- 4
We configure this grid capacity as a setpoint for the EV user profile:
opt_data <- tibble(
datetime = ev_demand$datetime, # Same date-time sequence than the demand
HomeEV = grid_capacity
)
head(opt_data)
## # A tibble: 6 × 2
## datetime HomeEV
## <dttm> <dbl>
## 1 2023-05-01 00:00:00 4
## 2 2023-05-01 00:15:00 4
## 3 2023-05-01 00:30:00 4
## 4 2023-05-01 00:45:00 4
## 5 2023-05-01 01:00:00 4
## 6 2023-05-01 01:15:00 4
sc_results <- smart_charging(
sessions = ev_sessions,
opt_data = opt_data,
opt_objective = "none",
method = "curtail",
window_days = 1,
window_start_hour = 6
)
## Warning: `production` variable not found in `opt_data`. No local energy production will be considered.
plot(sc_results, sessions = ev_sessions)
The demand is being postponed by the smart charging algorithm to match the setpoint during all possible hours, but when the end of the optimization window is reaching, the vehicle must charge to accomplish with the energy requirements by the EV user. This means that all EV users are not able to charge all their requirements under these grid conditions.
Therefore, in these scenarios where the grid stability is the
priority we have to assume that not all EV can be completely
charged, and we should be able to simulate this impact to the
EV user. This scenario can be configured with the parameter
energy_min
, as the required minimum ratio of the energy
required by the EV user. With energy_min = 0
the algorithm
considers that EVs may disconnect without charging all their energy
requirements, while with energy_min = 1
the algorithm will
make sure that all EV users charge their energy requirements, even
though the setpoint is not achieved.
Let’s try a value of energy_min = 0
to see how the
algorithm works and the corresponding impact to the vehicles:
sc_results <- smart_charging(
sessions = ev_sessions,
opt_data = opt_data,
opt_objective = "none",
method = "curtail",
window_days = 1,
window_start_hour = 6,
energy_min = 0
)
## Warning: `production` variable not found in `opt_data`. No local energy production will be considered.
plot(sc_results, sessions = ev_sessions)
Now we see that the grid capacity constraint is completely respected. But at which price?
We can calculate the impact on the EV user in terms of
percentage of energy charged with the function
summarise_energy_charged()
:
summarise_energy_charged(sc_results, sessions = ev_sessions) %>%
knitr::kable(caption = "Percentage of energy charged (%)")
Session | EnergyRequired | EnergyCharged | PctEnergyCharged |
---|---|---|---|
S1 | 17.02 | 16.16 | 95 |
S2 | 11.47 | 11.47 | 100 |
S3 | 12.80 | 12.71 | 99 |
S4 | 15.76 | NA | NA |
S5 | 14.54 | NA | NA |
S6 | 17.65 | 17.65 | 100 |
S7 | 14.28 | 14.28 | 100 |
S8 | 13.99 | NA | NA |
S9 | 17.50 | NA | NA |
S10 | 16.43 | NA | NA |
S11 | 10.80 | 10.80 | 100 |
S12 | 14.02 | NA | NA |
S13 | 15.98 | NA | NA |
S14 | 16.24 | NA | NA |
S15 | 14.25 | NA | NA |
We see that, to achieve our setpoint, some EV users can only charge a bit more than the 50% of their energy requirements.
We can also check that setting energy_min = 0.7
, for
example, results in surpassing the setpoint again, but all EV users
charge at least a 70% of their energy requirements:
sc_results <- smart_charging(
sessions = ev_sessions,
opt_data = opt_data,
opt_objective = "none",
method = "curtail",
window_days = 1,
window_start_hour = 6,
energy_min = 0.7
)
## Warning: `production` variable not found in `opt_data`. No local energy production will be considered.
plot(sc_results, sessions = ev_sessions)
summarise_energy_charged(sc_results, sessions = ev_sessions) %>%
knitr::kable(caption = "Percentage of energy charged (%) - `energy_min = 0.7`")
Session | EnergyRequired | EnergyCharged | PctEnergyCharged |
---|---|---|---|
S1 | 17.02 | 16.16 | 95 |
S2 | 11.47 | 11.47 | 100 |
S3 | 12.80 | 12.71 | 99 |
S4 | 15.76 | NA | NA |
S5 | 14.54 | NA | NA |
S6 | 17.65 | 17.65 | 100 |
S7 | 14.28 | 14.28 | 100 |
S8 | 13.99 | NA | NA |
S9 | 17.50 | NA | NA |
S10 | 16.43 | NA | NA |
S11 | 10.80 | 10.80 | 100 |
S12 | 14.02 | NA | NA |
S13 | 15.98 | NA | NA |
S14 | 16.24 | NA | NA |
S15 | 14.25 | NA | NA |
Setpoint as optimal demand
Let’s consider a grid optimization for our EV demand in the context of the following energy flows:
energy_data %>%
left_join(ev_demand, by = "datetime") %>%
select(-starts_with("price")) %>%
plot_ts(ylab = "Power (kW)", strokeWidth = 2) %>%
dySeries("solar", color = "orange") %>%
dyStackedRibbonGroup(c("HomeEV","building"), color = c("purple", "navy"))
ev_sessions %>%
smart_charging(
opt_data = energy_data %>% rename(static = building, production = solar),
opt_objective = "grid",
method = "curtail",
window_days = 1,
window_start_hour = 6
) %>%
plot()
## Warning: Unknown or uninitialised column: `sessions`.
## Warning: Unknown or uninitialised column: `demand`.
## Warning: Unknown or uninitialised column: `log`.
From the plot above we see that during most of the time the EV demand can be adapted to the setpoint but in the second optimization window, the EV demand that is not charged during the morning has to be charged during the night surpassing the setpoint.
If the setpoint is calculated for an optimization
objective (e.g. "grid"
or "cost"
), then
surpassing the setpoint may not suppose a risk but only a not optimal
solution. Even though, situations like the one above should be avoided
since we can have a rebound effect at the end of the optimization
window. A solution to these situations is the parameter
power_th
, which allows a certain threshold between the
setpoint value and the EV demand in every time slot. See the application
of power_th = 0.05
to allow a threshold of 5% of the
setpoint:
ev_sessions %>%
smart_charging(
opt_data = energy_data %>% rename(static = building, production = solar),
opt_objective = "grid",
method = "curtail",
window_days = 1,
window_start_hour = 6,
power_th = 0.05
) %>%
plot()
## Warning: Unknown or uninitialised column: `sessions`.
## Warning: Unknown or uninitialised column: `demand`.
## Warning: Unknown or uninitialised column: `log`.
The EV model has a minimum charging power
It is known that some EV models have a minimum charging power, so
below this power they can’t be charged at all. Therefore, a possible
solution is to specify a minimum charging power with the parameter
charging_power_min
. When
charging_power_min = 0
and method = "curtail"
,
the charging power can be reduced until 0 kW (interrupted), while a
value of charging_power_min = 0.5
would only allow
curtailing the EV charging power until the 50% of its nominal charging
power.
Let’s simulate that all EVs must charge at least at a 30% of their power requirements:
sc_results <- ev_sessions %>%
smart_charging(
opt_data = energy_data %>% rename(static = building, production = solar),
opt_objective = "grid",
method = "curtail",
window_days = 1,
window_start_hour = 6,
charging_power_min = 0.3
)
## Warning: Unknown or uninitialised column: `sessions`.
## Warning: Unknown or uninitialised column: `demand`.
## Warning: Unknown or uninitialised column: `log`.
Check that the minimum power of the Exploited
sessions
(i.e. the ones that provided flexibility) corresponds to the 30% of 3.7
(1.11kW):
## [1] 1.11
We can also make a histogram to show the distribution of charging power values. It is visible that the limit of 30% of the nominal power (1.11 kW) is actually limiting the flexibility, since a lot of sessions have been charged at this minimum charging rate:
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
And if we compare the final EV demand with the setpoint, in general we
see a good result even though the setpoint is not achieved during the
most restrictive periods:
plot(sc_results)