logo

DC-DC Buck Converter as a Dynamical System 📂Dynamics

DC-DC Buck Converter as a Dynamical System

Model

The voltage $V$ and current $I$ of a circuit diagram like the one above 1 can be represented as a non-smooth, non-autonomous system. This is referred to as a DC-DC Buck Converter.

$$ \begin{align*} \dot{V} =& - {{ 1 } \over { RC }} V + {{ 1 } \over { C }} I \\ \dot{I} =& - {{ V } \over { L }} + \begin{cases} 0 & , \text{if } V \ge V_{r} (t) \\ E / L & , \text{if } V < V_{r} (t) \end{cases} \\ V_{r} (t) =& \gamma + \eta \left( t \bmod T \right) \end{align*} $$

Variables

  • $V(t)$: Represents the voltage at time $t$.
  • $I(t)$: Represents the current at time $t$.
  • $V_{r}(t)$: Control signal at time $t$ following the $T$-cycle. If the voltage is lower than this signal, the switch opens to charge the battery, and if higher, the switch closes to supply the current.

Parameters

  • $\gamma , \eta , T > 0$: Constants related to the configuration of control. A smaller $\gamma = 11.75238 V$ allows for current supply at lower voltages and a larger $\eta = 1309.524Vs^{-1}$ charges the battery at higher voltages. A smaller $T = 400 \mu s$ results in more frequent switching to maintain a more uniform voltage.
  • $C = 47 \mu F$: Capacitance.
  • $E = 53.500001$: Battery Voltage.
  • $L = 20 mH$: Inductance.
  • $R = 22 \Omega$: Resistance.

The default values of parameters used in all simulations reproduced in this post are $m = 10^{-3}$, $\mu = 10^{-6}$. Note that in the main reference (Bernardo), $C$ was $4.7 \mu F$, but in another reference (Deane), when $C = 47 \mu F$ was used, the simulation did not work properly, so $C$ was set differently.

Description

The DC-DC buck converter, simply known as Buck Converter, is a converter for lowering the voltage below the input voltage2. In fact, the author is not very familiar with this ‘item’, and as the title suggests, only intends to explain the system.

Non-Smooth System

As can be seen from the equations, the buck converter system is a non-smooth system because the derivatives are not continuous. The red line is the control signal $V_{r} (t)$, and depending on whether the voltage $V(t)$ exceeds this signal or not, the system jumps and transitions non-smoothly. Accordingly, the system voltage is maintained between approximately 11.5~14.0V.

Chaotic System

If we look at the subsystem when the switch opens and closes, each seems to be a linear system, so it does not appear difficult. However, the problem is that the timing $t$, in other words, the switching on and off, is entirely inconsistent.

The above figure shows when switching occurs in the trajectory. As can be seen, there are bands where the dots form a group, i.e., the region $V \approx V_{r}$, but it is certainly hard to guarantee under what conditions it occurs just by looking at $V,I$. Due to this non-smoothness, this seemingly simple system is actually chaotic and has been studied for a long time3.

Bifurcation

buck_bifurcation.png

If we change the parameter $E$ and plot the value of $V$ according to the signal’s cycle, we can see the bifurcation as shown in the diagram above4. It is normal for two branches to emerge at $E \approx 25$, cross, and periodic orbits to appear around the branches at $E \approx 30$.

Code

Trajectory

The following is Julia code that can reproduce the figure showing the location of jumping points in the system.

using CSV, DataFrames, Clustering

function RK4(f::Function,v::AbstractVector, h=10^(-2))
    V1 = f(v)
    V2 = f(v + (h/2)*V1)
    V3 = f(v + (h/2)*V2)
    V4 = f(v + h*V3)
    return v + (h/6)*(V1 + 2V2 + 2V3 + V4)
end


if !isfile("./buck.csv")
    m = 10^(-3)
    μ = 10^(-6)
    R = 22
    C = 47μ
    L = 20m
    T = 400μ
    γ = 11.75238
    η = 1309.524
    E = 53.500001

    Vr(t) = γ + η * (mod(t, T))
    function buck(v)
        V, I, t = v

        V̇ = - V/(R*C) + I/C
        İ = - (V/L) + ifelse(V < Vr(t), E/L, 0)
        return [V̇, İ, 1]
    end

    u0 = [12.3, 0.55, 0.0]
    u_ = [u0]
    ∇_ = []
    dt = 0.00001; tend = 0.25
    for t in dt:dt:tend
        push!(∇_, buck(u_[end]))
        push!(u_, RK4(buck, u_[end], dt))
    end
    push!(∇_, buck(u_[end]))
    U = stack(u_)[Not(end), :]
    ∇ = stack(∇_)[Not(end), :]
    CSV.write("buck.csv", DataFrame(
        [collect(0:dt:tend)'; U; ∇; Vr.(0:dt:tend)']'
      , ["t", "V", "I", "dV", "dI", "Vr"]))
end

DATA = CSV.read("data/buck.csv", DataFrame)

Y = select(DATA, [:dV, :dI]) |> Matrix .|> Float32
X = select(DATA, [ :V,  :I]) |> Matrix .|> Float32
XY = [X Y]

dbs = dbscan(col_normalize(Y)', 0.01); nsubsys = length(dbs.clusters); println(nsubsys, " clusters found!")

a1 = plot(DATA.V, DATA.I, alpha = 0.1, legend = :best, label = "Trajectory", xlabel = L"V", ylabel = L"I")
scatter!(a1, 
    DATA.V[Not(1)][.!iszero.(diff(dbs.assignments))]
  , DATA.I[Not(1)][.!iszero.(diff(dbs.assignments))]
  , color = 1, shape = :+, label = "Jumping points")

Bifurcation Diagram

Below is the code for the bifurcation diagram. Note that there is a slight technical issue; to accurately simulate the buck converter, the time interval must be around $h = 10^{-7}$. Despite using the Euler method, it takes about 10 hours on an Intel i7-12700F.

const m = 10^(-3)
const μ = 10^(-6)
const R = 22 # 22
const L = 20m # 20m
const C = 47μ # 22μ
const T = 400μ
const γ = 11.7 # 11.75238
const η = 1309.5 # 1309.524
const RC = R*C

using ProgressBars
packages = [:DataFrames, :CSV, :Plots, :LaTeXStrings]
for package in ProgressBar(packages)
    @eval using $(package)
end
println(join(packages, ", "), " loaded!")

function Euler(f::Function,v::AbstractVector, h=10^(-2))
    V1 = f(v)
    return v + h*V1, V1
end

Vr(t) = γ + η * (mod(t, T))

function factory_buck(idx::Int64, E::Number; flag_filesave = false)
    EdL = E/L
    
    controlterm = 0.0
    function buck(v::AbstractVector)
        V, I = v

        V̇ = - V/(RC) + I/C
        İ = - (V/L) + controlterm
        return [V̇, İ]
    end
    dt = 10^(-7); tend = 0.5
    t_ = 0:dt:tend
    Vr_ = Vr.(t_)

    ndatapoints = round(Int64, tend/(100dt))

    len_t_ = length(t_)
    traj = zeros(4, len_t_+1)
    u = [12.0, 0.55]
    du = buck(u)
    traj[1:2, 1] = u

    
    for t in 1:length(t_)
        controlterm = ifelse(u[1] < Vr_[t], EdL, 0)
        u, du = Euler(buck, u, dt)
        if t ≥ ndatapoints
            traj[3:4,   t] = du
            traj[1:2, t+1] = u
        end
    end
    traj = traj[:, 1:(end-1)]'

    if flag_filesave
        data = DataFrame(
            [t_ traj Vr_],
            ["t", "V", "I", "dV", "dI", "Vr"])
            @warn "file saving mode!"
            CSV.write("G:/buck/buck_$(lpad(idx, 6, '0')).csv", data)
        return nothing
    else
        data = DataFrame(
            [t_ traj Vr_][(end-ndatapoints):end, :],
            ["t", "V", "I", "dV", "dI", "Vr"])
    end

    return data
end

# E_range = 15:40
E_range = 15:0.001:40
schedule = DataFrame(idx = eachindex(E_range), E = E_range)

xdots = Float64[]; ydots = Float64[]
for dr in ProgressBar(eachrow(schedule))
    data = factory_buck(dr.idx, dr.E)
    
    idx_sampled = diff(data.Vr) .< 0
    sampledV = data[Not(1), :V][idx_sampled]
    append!(xdots, fill(dr.E, length(sampledV)))
    append!(ydots, sampledV)
end
@time a1 = scatter(xdots, ydots,
xlabel = L"E", ylabel = L"V",
label = :none, msw = 0, color = :black, ms = 0.5, alpha = 0.5, size = (700, 480));

png(a1, "buck_bifurcation")

  1. https://upload.wikimedia.org/wikipedia/commons/c/ca/Commutation_cell_in_converters.svg ↩︎

  2. https://gdnn.tistory.com/85 ↩︎

  3. J. H. B. Deane and D. C. Hamill, “Analysis, simulation and experimental study of chaos in the buck converter,” 21st Annual IEEE Conference on Power Electronics Specialists, San Antonio, TX, USA, 1990, pp. 491-498, doi: https://doi.org/10.1109/PESC.1990.131228↩︎

  4. M. di Bernardo, F. Garefalo, L. Glielmo and F. Vasca, “Switchings, bifurcations, and chaos in DC/DC converters,” in IEEE Transactions on Circuits and Systems I: Fundamental Theory and Applications, vol. 45, no. 2, pp. 133-141, Feb. 1998, doi: https://doi.org/10.1109/81.661675 ↩︎