Example workflow for a low frequency AC upgrade

Solving the OPF without upgrades

We begin by solving the optimal power flow for a network with a single, fixed frequency. Consider the 5 bus network shown here:

5 bus network

It is represented in a MATPOWER case file: case5.m

For this example, we put this file in a folder called base inside a parent folder case5 for all the cases we'll consider here. This will be the base network without any upgrades.

Because the functions in this package expect networks which may have variable frequency portions, we need to specify some details about frequency. This is done by creating a file in the same folder, called subnetworks.csv. This file must specify the name of the network data file, whether it is a variable frequency network, and at what frequency all the parameters in the network data file are defined. If the frequency is variable, it also must specify the upper and lower limits of the frequency.

indexfilevariable_ff_basef_minf_max
1case5.mfalse60

Now we can solve the standard AC OPF for this network, with the objective of minimizing cost:

using VariableFrequencyOPF

data_folder = "test/data/case5/base/"
objective = "mincost"

solution = VariableFrequencyOPF.multifrequency_opf(data_folder, objective)

# The first element in the solution output is a dictionary containing several important results.
results_dict = solution[1]
println(results_dict)

The output looks like this. The result values are in arrays, where each element corresponds to a subnetwork. We only have one subnetwork here.

Dict{String,Any} with 11 entries:
  "frequency (Hz)" => [60.0]
  "total loss"     => [0.0519209]
  "converter loss" => [0.0]
  "status"         => LOCALLY_SOLVED
  "CPU time (s)"   => 0.826
  "iterations"     => 28
  "total time (s)" => 0.860499
  "subnet"         => [1]
  "cost"           => [17551.9]
  "generation"     => [10.0519]
  "line loss"      => [0.051921]

Upgrading a line to low frequency AC

Now we would like to upgrade one line to low frequency AC (LFAC) and solve the OPF with frequency as a variable. An upgrade of line 2 will make this line into its own variable frequency subnetwork, like this:

5 bus network

To present this data to VariableFrequencyOPF, we need to create a new network file for the subnetwork, modify the original, add a line to subnetworks.csv and specify some details about how the subnetworks connect through another file, interfaces.csv.

The function upgrade_branches takes care of all of these steps for us.

base_network = "test/data/case5/base/case5.m"
output_location = "test/data/case5/"
base_frequency = 60.0
branches_to_upgrade = [2]
# We neglect converter losses in this example
noloss = true

VariableFrequencyOPF.upgrade_branches(
    base_network,
    output_location,
    base_frequency
    indices=branches_to_upgrade,
    noloss=noloss
)

This creates a new folder inside case5 called br2. In this folder, we have case5.m with line 2 removed and a new network file, lfac_case5.m, which has two LFAC buses and the line which was formerly line 2 between them. We also have subnetworks.csv with a new row:

indexfilevariable_ff_basef_minf_max
1case5.mfalse60
2lfac_case5.mtrue600.1100

This allows the frequency to vary between 0.1 and 100 Hz in the LFAC subnetwork.

We also have a new file, interaces.csv, specifying some details of the connections between the subnetworks. We set the converter losses to zero in this example, but we could specify any of these parameter values to model our converters and any filter or transformer branches connected to it. We can also specify the operating limits on current and voltage, respectively, of the converters with imax and vmax.

indexsubnet_indexbusimaxvmaxc1c2c3sw1sw2sw3MsmaxRXGBtransformertapshift
111401.10000000.9501.00E-050.00100.0001FALSE10
214401.10000000.9501.00E-050.00100.0001FALSE10
121401.10000000.9501.00E-050.00100.0001FALSE10
222401.10000000.9501.00E-050.00100.0001FALSE10

Now we can solve the OPF for this network:

data_folder = "test/data/case5/br2/"
objective = "mincost"

solution = VariableFrequencyOPF.multifrequency_opf(data_folder, objective)

# The first element in the solution output is a dictionary containing several important results.
results_dict = solution[1]
println(results_dict)

Solve the OPF for a network with a variable frequency (low frequency AC) portion

Consider a power system which is divided into two areas connected by AC-AC converters: one operates at a fixed frequency of 60 Hz, and the other is a multi-terminal low frequency AC network, whose frequency can be chosen. In the directory test/data/case14_twoarea is data for a modified IEEE 14 bus network which fits this paradigm, as drawn here, with the variable frequency portion in blue:

14 bus network with LFAC

In this example, we solve the OPF for this case, and we print the termination status, generation cost and optimal frequencies (The frequency of the standard part of the network is fixed at 60 Hz, and the frequency of the other part is allowed to vary between 1.0 and 100.0 Hz).

using VariableFrequencyOPF

data_folder = "test/data/case14_twoarea/two_area/"
objective = "mincost"

solution = VariableFrequencyOPF.multifrequency_opf(data_folder, objective)

results_dict = solution[1]

# Print results
println("Status:")
println(results_dict["status"])
println("\nCost:\n==============================")
println("Variable frequency subnetwork:")
println(results_dict["cost"][1])
println("Fixed frequency subnetwork:")
println(results_dict["cost"][2])
println("\nFrequency:\n==============================")
println("Variable frequency subnetwork:")
println(results_dict["frequency (Hz)"][1])
println("Fixed frequency subnetwork:")
println(results_dict["frequency (Hz)"][2])

output:

Status:
LOCALLY_SOLVED

Cost:
==============================
Variable frequency subnetwork:
7565.237470495639
Fixed frequency subnetwork:
553.6125608844086

Frequency:
==============================
Variable frequency subnetwork:
1.0
Fixed frequency subnetwork:
60.0