DC Optimal Power Flow
Definition
Optimal Power Flow determines the optimal generator dispatch that meets system demand at minimum cost, while satisfying network constraints such as line limits and power flow equations.
DC Optimal Power Flow (DC OPF) is a linearized approximation of AC OPF that simplifies the power flow equations by assuming flat voltage magnitudes, small angle differences, no reactive power and no transmission losses. It is widely used in electricity markets to determine efficient dispatch and compute locational marginal prices (LMPs) under transmission constraints.
Mathematical formulation 🧮
Equation explanation
(1a): Objective function
This function minimizes the total generation cost over all generators in set
(1b): Volatge Angle Difference Limit Constraint
This constraint limits the volatge angle difference across each line to ensure system stability.
It ensures that the difference in voltage angles across each transmission line stays within acceptable bounds.
(1c): Generation Limit Constraint
This constraint restricts generator output within its physical minimum and maximum limits.
(1d) & (1e): Power Flow Equations (Linearized DC)
These expressions define line flows using the DC power flow approximation, where power flow is proportional to the angle difference of the two nodes divided by the line’s reactance.
(1f) & (1g): Line Flow Limit Constraints
These constraints enforces thermal or operational limits on line power flows in both directions.
(1h): Generation-load Balance Contraint
This constraint ensures nodal active power balance at each bus.
Julia code 🔢
# Data for the problembusset = 1:3genset = 1:2lineset = 1:3slack_bus = 1
Pd = [0.0, 0.0, 150.0]
# Generator data: (bus, Pmin, Pmax, cost)gen_data = [ (1, 0.0, 100.0, 10.0), (2, 0.0, 100.0, 20.0)]
# Line data: (from, to, reactance, flow_limit)line_data = [ (1, 2, 0.1, 100.0), (2, 3, 0.1, 100.0), (3, 1, 0.1, 100.0)]
# Optimization modelusing JuMP, IpoptOPF = Model(Ipopt.Optimizer)
@variable(OPF, pg[g in genset])@variable(OPF, θ[b in busset])@variable(OPF, p_ft[l in lineset])
@constraint(OPF, θ[slack_bus] == 0)
@constraint(OPF, [g in genset], gen_data[g][2] <= pg[g] <= gen_data[g][3])
@constraint(OPF, [l in lineset], p_ft[l] == (1 / line_data[l][3]) * (θ[line_data[l][1]] - θ[line_data[l][2]]))
@constraint(OPF, [l in lineset], -line_data[l][4] <= p_ft[l] <= line_data[l][4])
@constraint(OPF, [b in busset], sum(pg[g] for g in genset if gen_data[g][1] == b) + sum(p_ft[l] for l in lineset if line_data[l][2] == b) - sum(p_ft[l] for l in lineset if line_data[l][1] == b) == Pd[b])
@objective(OPF, Min, sum(gen_data[g][4] * pg[g] for g in genset))
optimize!(OPF)Visualization 📊
Below is a visualization that shows how generation is dispatched by network and cost as demand at bus 3 changes.
3-Bus DC-OPF Chart
Demand at Bus 3: 150 MW