I want to optimize a charging schedule for Battery Electric Vehicles (BEV) along a grid line, taking into account customer wishes (when to be done with charging with what State of Charge (SOC)) and other loads like households. So the goal is to load the BEV -- if possible meet the customer's wishes -- and assure that the grid is not overloaded.

I will first try to explain some background. The actual question is at the end.

I use python and pyomo as an optimization framework, as a solver I use glpk.

That's what a generic grid line with 4 nodes looks like:

enter image description here

Here is, what my formulation looks like:



Symbol Meaning
$n$ node
$t$ timestep
$l$ line


Symbol Meaning
$\mathcal{N}$ set of all nodes
$\mathcal{N}_\mathrm{BEV}$ set of nodes with attached charger
$\mathcal{T}$ set of all timesteps
$\mathcal{L}$ set of all lines

Decision Variables

Symbol Meaning
$I^\mathrm{BEV}_{t,n}$ BEV charging current
$SOC_{t,n}$ BEV SOC


Symbol Meaning
$I^\mathrm{HH}_{t,n}$ household current
$Z_l$ line impedance
$u_0$ voltage at transformer low voltage side
$u_n$ voltage at node $n$
$u_\mathrm{min}$ minimum permitted voltage
$i_\mathrm{max}$ maximum permitted current
$P_\mathrm{trafo}$ transformer power
$E_n$ BEV battery capacity
$\Delta t$ lenght of timestep
$\Delta SOC_\mathrm{max}$ maximum tolerable SOC difference

Target Function:

Maximize the charging current for each node at each timestep $$ \mathrm{max.}\quad\sum_{t\in\mathcal{T}}\bigg(\sum_{n\in\mathcal{% N_\mathrm{BEV}}}\!\!\!\Big( I^\mathrm{BEV}_{t,n} \Big) \bigg) $$


Don't fall below permitted voltage $$u_0-\sum_{l\in\mathcal{L}}\bigg( Z_l\cdot\sum_{\substack{% n\in\mathcal{N} \\ n>l}}\Big( I^\mathrm{BEV}_{t,n}+% I^\mathrm{HH}_{t,n} \Big) \bigg)\geq u_\mathrm{min}\quad \forall t \in\mathcal{T}$$

Don't exceed permitted current $i_\mathrm{max}=P_\mathrm{trafo}/u_0$ $$\sum_{n\in\mathcal{N}}\Big( I^\mathrm{BEV}_{t,n}+% I^\mathrm{HH}_{t,n} \Big)\leq i_\mathrm{max}\quad \forall t\in\mathcal{T}$$

Ensure energy conservation while charging $$SOC_{t,n}+\frac{I^\mathrm{BEV}_{t,n}\cdot u_n\cdot\Delta t}{% E_{n}}\cdot 100\%=SOC_{t+1,n}\quad\forall t\in\mathcal{T}\quad\forall n\in\mathcal{% N_\mathrm{BEV}}$$

Ensure equal SOCs after charging $$\frac{SOC_{t_\mathrm{end},n}-SOC^\mathrm{start}_n}{SOC^\mathrm{target}_n-% SOC^\mathrm{start}_n}-\frac{SOC_{t_\mathrm{end},n-1}-SOC^\mathrm{start}% _{n-1}}{SOC^\mathrm{target}_{n-1}-SOC^\mathrm{start}_{n-1}}\leq\Delta SOC_\mathrm{max}\quad\forall n\in\mathcal{N}_\mathrm{BEV}$$


Let's consider the following scenario: a gridline with 6 nodes, 2 charging stations (11kW each, one at the first and one at the last node). The household currents are just taken from some standard load profile. Both BEVs arrive at 15pm with 20% SOC and wish to finish charging at 20pm with 100% SOC. The transformer is only 15kVA, thus not enough to allow both BEVs to concurrently charge at nominal power.

Now when I start the optimizer without the equal-SOCs-constraint activated, I get the following result:

enter image description here

The optimizer clearly favors the BEV at node 6, which is not fair.

Now when I activate the equal-SOCs-constraint ($\Delta SOC_\mathrm{max}=0$) and rerun, I get the following result:

enter image description here

Okay, both end up with the same SOC, that's nice. But the optimizer switches the chargers on and off all the time -- that's annoying and also not good for the batteries I guess.

Finally, my Question

Is there any other way to formulate the equal-SOCs-constraint, to achieve a smooth loading? E.g. something like (sorry for my bad drawing):

enter image description here

  • 1
    $\begingroup$ In your equal SOC constraint, $n\in \mathcal{N}_\mathrm{BEV}$, but it is not necessarily case that $n-1 \in \mathcal{N}_\mathrm{BEV}.$ Should $n-1$ actually mean the predecessor of $n$ in $\mathcal{N}_\mathrm{BEV}?$ $\endgroup$
    – prubin
    Apr 15, 2022 at 15:17
  • $\begingroup$ yes, that is what it is supposed to be, thank you for the hint! $\endgroup$
    – Andre
    Apr 18, 2022 at 8:43

3 Answers 3


Regarding the equal-SOC constraint, you might want to consider changing $n-1$ to $n'$ and enforcing it for all pairs $n,\ n' \in \mathcal{N}_\mathrm{BEV}$ such that $n' < n.$ This would add some constraints but perhaps make for a more "egalitarian" final state. As it stands, when there are more than two charging stations the solver can leave you with an ascending sequence of SOCs, with the first charging node at a considerably lower level than the last one.

As far as the variability in current, one possibility would be to add a constraint saying that $I^\mathrm{BEV}_{t,n} - I^\mathrm{BEV}_{t-1,n}\ge \lambda$ for some parameter value $\lambda > 0.$ This limits the amount the current can drop over consecutive periods, and keeps your model as a linear program. An alternative approach would be to assert a minimum number of periods that current could be supplied. For instance, you could say that once charging is turned on it must continue for at least 3 periods. This approach would require binary variables for each combination of charging node and time period, plus additional constraints. It would turn your linear program into an mixed integer linear program.

  • $\begingroup$ ahh, thank you! I want to implement your solution for the equal-socs, but I am fighting with the formulation in pyomo -- I will ask a separate question for this. $\endgroup$
    – Andre
    Apr 18, 2022 at 8:46
  • $\begingroup$ yes, I have also thought about a similar constraint with the currents. But I think this cannot be my solution :(. One important thing is the possibility of the optimizer to shift the charging of the BEVs when it realizes high loads from the households. This approach might make the optimizer "too slow" to react fast enough on changes in the household loads. But still thanks for the tip! $\endgroup$
    – Andre
    Apr 18, 2022 at 8:52
  • 1
    $\begingroup$ Since household load is a parameter, you could try a constraint along the following lines: $$I_{t,n}^{\mathrm{BEV}}\ge \lambda I_{t-1,n}^{\mathrm{BEV}}-\max(0,I_{t,n}^{\mathrm{HH}}-I_{t-1,n}^{\mathrm{HH}}).$$If household load at the node decreases or stays the same, charging current can go down by at most a factor of $1-\lambda.$ If household load increases, charging current can go down to match the household increase plus a fraction $1-\lambda$ of the previous charging current. $\endgroup$
    – prubin
    Apr 18, 2022 at 14:51

The switching on-and-off reminds me of a similar phenomenon, called "ringing", in this paper: Case Studies in Trajectory Optimization: Trains, Planes, and Other Pastimes Robert J. Vanderbei Optimization and Engineering volume 2, pages 215–243 (2001) https://vanderbei.princeton.edu/tex/trajopt/trajopt.pdf See Figure 3 and the discussion near it. Their optimization problem is already nonlinear, so they don't mind adding a nonlinear term to the objective function: the squared difference between successive decision variables. If at some point your LP becomes an NLP, then perhaps this idea will be useful.

  • $\begingroup$ thank you for your pointer at the paper, I will have a look at it! $\endgroup$
    – Andre
    Apr 18, 2022 at 8:54

I see three options which do not involve extra binary variables. Although i agree that the binary variables would work.

Smooth your plan after the fact with post processing while keeping the objective the same. This could either happen by an algorithm you write (which preserves optimality of solutions) or MILP solving with objective that punishes the excitement while adding the constraint that the term which was previously the objective must assume the optimal value of the previous problem.

Add a penalty term which punishes the L1 norm or sign changes (discrete norm) of $I$ slightly. Also MILP possible with MILP

A better modeling of ramp up or down constraints which are the reason why plugging in and out is bad could help. This would possible with MILP.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.