Tutorial 2: Charging scheduling

See tutorial/tutorial_2_Charging_scheduling.mlx. This tutorial includes various methods to perform scheduling for a given scenario (a Scenario object) or a distribution of scenario (an AbstractScenarioGenerator object). While we focus on the load flattening problem here, but everything is the same for the user-friendly problem.

Recall: Using any method, create a Scenario object as in Tutorial 1. For example,

gen = PoissonScenarioGenerator(T=36);
my_sc = generate(gen);

Charging scheduling with oracle information: schedule()

First, we assume that we have all information provided in the Scenario object my_sc. Then, we find the optimal charging schedule by executing function schedule(). (“cent” indicates that a centralized optimization algorithm is applied. Another option is “dist”, which will be discussed at the end of this tutorial.)

out = schedule(my_sc,"cent");

The following script compares the resulting total load profile with the base load profile.

tt = (1:out.scenario.T)*out.scenario.Delta/60;

figure;
base_load = out.scenario.D;
u_aggregate = sum(out.u,2);
total_load = base_load + u_aggregate;
plot(tt,base_load,'k--','LineWidth',2,'DisplayName','Base load');
hold on;
plot(tt,total_load,'b','LineWidth',2,'DisplayName','Total load (oracle)');
legend('Location','southeast');
xlabel("time(h)");
ylabel("load(kW)");

Charging scheduling with real-time information: schedule_rh()

Now, we consider the real-time scheduling using receding horizon scheme. Function schedule_rh() returns a charging schedule obtained with receding

out_rh_6 = schedule_rh(my_sc,"cent",H=6);
out_rh_12 = schedule_rh(my_sc,"cent",H=12);

The following script compares the results with the oracle solution obtained before.

Note

The results obtained by schedule_rh() will have length 31 and 25 for H=6 and H=12, respectively, whereas the oracle solution has length 36.

figure;
% plot oracle
base_load = out.scenario.D;
u_aggregate = sum(out.u,2);
total_load = base_load + u_aggregate;
plot(tt,base_load,'k--','LineWidth',2,'DisplayName','Base load');
hold on;
plot(tt,total_load,'b','LineWidth',2,'DisplayName','Total load (oracle)');

% plot receding horizon with H=6
tt_rh_6 = (1:out_rh_6.scenario.T)*out_rh_6.scenario.Delta/60;
base_load_rh_6 = out_rh_6.scenario.D;
u_aggregate_rh_6 = sum(out_rh_6.u,2);
total_load_rh_6 = base_load_rh_6 + u_aggregate_rh_6;
plot(tt_rh_6,total_load_rh_6,'r:','LineWidth',2,'DisplayName',"Total load (receding horizon, H=6)");

% plot receding horizon with H=12
tt_rh_12 = (1:out_rh_12.scenario.T)*out_rh_12.scenario.Delta/60;
base_load_rh_12 = out_rh_12.scenario.D;
u_aggregate_rh_12 = sum(out_rh_12.u,2);
total_load_rh_12 = base_load_rh_12 + u_aggregate_rh_12;
plot(tt_rh_12,total_load_rh_12,'g:','LineWidth',2,'DisplayName',"Total load (receding horizon, H=12)");


legend('Location','southeast');
xlabel("time(h)");
ylabel("load(kW)");

One-line simulation and display: simulate() and analyze()

Function simulate() performs both oracle and receding horizon scheduling. In particular, for oracle scheduling, it calls schedule() for T-H+1 time slots, for receding horizon schedulinbg, it calls schedule_rh() for T time slots so that the results has the same length as that of the oracle scheduling. The results can be compared and visualized by function analyze(). analyze() automatically recognize parameters such as Delta for visualization.

gen = PoissonScenarioGenerator(T=36,Delta=30);
my_sc = generate(gen);
sim_out = simulate(my_sc,H=6,oracle=true,cent=true);
analyze(data=sim_out);

Monte-Carlo simulation for statistical analysis: simulate_mc()

For statistical analysis, SH-V2G-Simulator provides function simulate_mc(), which repeat simulate() for scenarios that is drawn from a scenaro generator. analyze() also supports the visualization of the results of simulate_mc().

gen = PoissonScenarioGenerator(T=36,Delta=30);
mc_out = simulate_mc(gen,2,H=6,oracle=true,cent=true);
analyze(data=mc_out);

Scheduling using a distributed algorithm

All the scheduling algorithm provided in SH-V2G-Simulator support a distributed version, which can be executed by using argument “dist”.

Note

As this simulator perform all the computation in a single CPU, the distributed algorithm takes more time then the centralized algorithm.

L = 51*eye(51) - ones(51);
my_sc = set(my_sc,L=L);

out_cent = schedule(my_sc,"cent");
out_dist = schedule(my_sc,"dist");

The result of the centralized and distributed scheduling algorithm can be compared by the following script.

tt = (1:out_cent.scenario.T)*out.scenario.Delta/60;
base_load = out_cent.scenario.D;
u_aggregate_cent = sum(out_cent.u,2);
u_aggregate_dist = sum(out_dist.u,2);
total_load_cent = base_load + u_aggregate_cent;
total_load_dist = base_load + u_aggregate_dist;

figure;
u_aggregate = sum(out.u,2);
plot(tt,base_load,'k--','LineWidth',2,'DisplayName','Base load');
hold on;
plot(tt,total_load_cent,'b','LineWidth',2,'DisplayName','Total load (cent)');
plot(tt,total_load_dist,'g-.','LineWidth',2,'DisplayName','Total load (dist)');
legend('Location','southeast');
xlabel("time(h)");
ylabel("load(kW)");