Per-Unit System
In power system modeling and analysis, variables and parameters are often normalized using the per-unit system. The per-unit system is particularly advantageous for analyzing networks with multiple voltage levels connected by transformers with different turns ratios.
In static scenarios, there are four key quantities of interest: voltage, current, power, and impedance or admittance. Defining a per-unit system requires selecting base values for each of these quantities. However, since these quantities are interconnected by various laws, the choice of base values cannot be arbitrary. Typically, the base quantities are chosen as voltage and power, with the base current and impedance (or admittance) then calculated accordingly. Usually, base quantities are selected as follows:
- three-phase apparent power $S_{3\phi(\text{b})}$,
- line-to-line voltage $V_{LL(\text{b})}$.
While the value of three-phase apparent power is unique across the entire system, multiple line-to-line base voltages are used to account for the different voltage zones created by transformers.
Since balanced three-phase power systems are treated as a single line with a neutral return, confusion may arise regarding the relationship between the per-unit values of line voltages and phase voltages, as well as between the per-unit values of single-phase and three-phase powers [7]. To clarify these relationships, we will systematically explore the conversions between the per-unit and SI systems below.
Powers
Let us consider the three-phase apparent power expressed in SI units, denoted as $S_{3\phi(\text{si})}$. To convert this into the per-unit system, we divide it by the base power:
\[S_{3\phi(\text{pu})} = \cfrac{S_{3\phi(\text{si})}}{S_{3\phi(\text{b})}}.\]
Now, let us examine the power of a single phase and convert it to the per-unit system:
\[S_{1\phi(\text{pu})} = \cfrac{S_{1\phi(\text{si})}}{S_{1\phi(\text{b})}} = \cfrac{S_{3\phi(\text{si})}}{3} \cfrac{3}{S_{3\phi(\text{b})}} = \cfrac{S_{3\phi(\text{si})}}{S_{3\phi(\text{b})}} = S_{3\phi(\text{pu})}.\]
This indicates that in the per-unit system, there is no distinction between three-phase and single-phase powers. The type of power only becomes relevant when converting back from per-unit to SI units, and vice versa.
As is standard practice, even if all simulations utilize a single-phase equivalent, input powers provided in SI units are assumed to represent three-phase powers. Similarly, if simulation results are displayed in SI units, they are considered to be three-phase powers, as we have selected three-phase power as the base value.
Voltages
Format for input data that JuliaGrid uses required value for base voltage per each bus, and those values represent the line-to-line voltages. On the other hand, in all analyses we are working with line-to-neutral voltages. To convert a line-to-neutral voltage given in SI units $V_{LN(\text{si})}$ to per-unit form $V_{LN(\text{pu})}$, or vice versa, we use the formula:
\[V_{LN(\text{pu})} = \cfrac{\sqrt{3}V_{LN(\text{si})}}{V_{LL(\text{b})}}.\]
Similarly to power, JuliaGrid simulations use a single-phase equivalent. Voltage values specified in volts correspond to line-to-neutral values, while base voltages are expected to be provided as line-to-line values.
Impedances
Let us first consider the line itself, excluding transformers. The base impedance of the line is given by:
\[Z_{L(\text{b})} = \cfrac{V_{LL(\text{b})}^2}{S_{3\phi(\text{b})}}.\]
If the impedance is provided in ohms, its value in the per-unit system is:
\[Z_{L(\text{pu})} = \cfrac{Z_{L(\text{si})}}{Z_{L(\text{b})}} = \cfrac{Z_{L(\text{si})} S_{3\phi(\text{b})}}{V_{LL(\text{b})}^2}.\]
A common question that arises is which base voltage should be used for the line, considering the two ends of the line (from-bus and to-bus). The key assumption here is that the base voltages correspond to the nominal voltages of the transformers. Therefore, when the user defines base voltages, JuliaGrid assumes these voltages represent the nominal voltages of the transformers, implying that the base voltages on both the from-bus and to-bus ends of the line will be the same.
Now, let us consider the transformer. The base voltages at the from-bus end (primary side) $V_{LLF(\text{b})}$, and the to-bus end (secondary side) $V_{LLT(\text{b})}$, will generally be different. This requires us to define a conversion method for impedance. Typically, when impedance is given in ohms, it refers to the primary side of the transformer, denoted as $Z_{F(\text{si})}$, while the impedance in our unified branch model refers to the secondary side, denoted as $Z_{T(\text{si})}$. To convert the impedance from the from-bus end to the to-bus end, we use:
\[Z_{T(\text{si})} = \cfrac{Z_{F(\text{si})}}{m^2},\]
where $m$ is the effective turns ratio, calculated as:
\[m = \tau \cfrac{V_{LLF(\text{b})}}{V_{LLT(\text{b})}},\]
with $\tau$ is off-nominal turns ratio. This equation provides the impedance on the to-bus end of the branch or the secondary side of the transformer in ohms.
To convert this impedance to the per-unit system, we use the base impedance for the secondary side:
\[Z_{T(\text{pu})} = \cfrac{Z_{T(\text{si})}}{Z_{T(\text{b})}},\]
where:
\[Z_{T(\text{b})} = \cfrac{V_{LLT(\text{b})}^2}{S_{3\phi(\text{b})}}.\]
Substituting the previous expressions, we obtain the following formula for the impedance on the secondary side in per-unit system:
\[Z_{T(\text{pu})} = \cfrac{Z_{F(\text{si})} S_{3\phi(\text{b})}}{\tau^2 V_{LLF(\text{b})}^2}.\]
This formula applies to both lines and transformers. For a line, where $\tau = 1$, the formula simplifies and becomes the same as the impedance equation for a line.
In the case of a transformer, if impedances or admittances are provided in SI units, they must be specified for the primary side (from-bus end).
Currents
Once the base power and base voltage values are set, we can calculate the base current flowing through a line or branch as follows:
\[I_{L(\text{b})} = \cfrac{S_{3\phi(\text{b})}}{\sqrt{3}V_{LL(\text{b})}}.\]
When we transform currents that are given in SI unit to per-unit, or vice versa, we use the following formula:
\[I_{L(\text{pu})} = \cfrac{I_{L(\text{si})}}{I_{L(\text{b})}} = \cfrac{\sqrt{3}I_{L(\text{si})}V_{LL(\text{b})}}{S_{3\phi(\text{b})}}.\]
Per-Units to SI Units
To create a comprehensive tutorial, let us start with an example where input data is defined in per-units, while the simulation results are outputted in SI units.
system = powerSystem()
@base(system, MVA, kV)
First, we initialize the power system container, setting the base value for three-phase apparent power $S_{3\phi(\text{b})}$. We use a macro to specify that power is given in megavolt-amperes (MVA):
julia> system.base.power.value
100.0
We also specify that base line-to-line voltages will be stored in kilovolts (kV).
Buses
Next, we add buses to the system:
addBus!(system; label = "Bus 1", type = 3, magnitude = 1.0, base = 115e3)
addBus!(system; label = "Bus 2", type = 1, magnitude = 1.1, base = 230e3)
addBus!(system; label = "Bus 3", type = 1, active = 1.2, reactive = 0.1, base = 230e3)
The base
keyword allows us to specify base line-to-line voltages $V_{LL(\text{b})}$ for each bus in volts (V). However, these voltages are stored in kV, as specified by the @base
macro:
julia> print(system.bus.label, system.base.voltage.value)
Bus 1: 115.0 Bus 2: 230.0 Bus 3: 230.0
The magnitude
keyword sets the initial line-to-neutral bus voltages in per-units:
julia> print(system.bus.label, system.bus.voltage.magnitude)
Bus 1: 1.0 Bus 2: 1.1 Bus 3: 1.0
Using the active
and reactive
keywords, we define the three-phase power demands for the load at Bus 3
in per-units:
julia> print(system.bus.label, system.bus.demand.active, system.bus.demand.reactive)
Bus 1: 0.0, 0.0 Bus 2: 0.0, 0.0 Bus 3: 1.2, 0.1
Branches
Now, let us define the branches:
@branch(label = "Branch ?")
addBranch!(system; from = "Bus 1", to = "Bus 2", turnsRatio = 0.98, reactance = 0.03)
addBranch!(system; from = "Bus 2", to = "Bus 3", reactance = 0.1, susceptance = 0.03)
The first branch represents a transformer, with its reactance given in per-units on the secondary side (to-bus end), and an off-nominal turns ratio of $\tau = 0.98$. The second branch represents a transmission line, with parameters also specified in per-units:
julia> prmt = system.branch.parameter;
julia> print(system.branch.label, prmt.reactance, prmt.susceptance, prmt.turnsRatio)
Branch 1: 0.03, 0.0, 0.98 Branch 2: 0.1, 0.03, 1.0
Generators
Finally, we add a generator to our example:
@generator(label = "Generator ?")
addGenerator!(system; bus = "Bus 1", active = 2.3, reactive = 0.2)
We set up the generator at Bus 1
, using the active
and reactive
keywords to define the three-phase power output of the generator in per-units:
julia> output = system.generator.output;
julia> print(system.generator.label, output.active, output.reactive)
Generator 1: 2.3, 0.2
AC Power Flow
For example, we can perform AC power flow analysis on our defined power system:
analysis = newtonRaphson(system)
for i = 1:10
stopping = mismatch!(system, analysis)
if all(stopping .< 1e-8)
break
end
solve!(system, analysis)
end
power!(system, analysis)
Results
Now, we can examine some results in SI units:
@voltage(kV, deg, V)
@power(MW, MVAr, MVA)
show = Dict("Power Generation" => false, "Shunt Power" => false)
printBusData(system, analysis; show)
|--------------------------------------------------------------------------|
| Bus Data |
|--------------------------------------------------------------------------|
| Label | Voltage | Power Demand | Power Injection |
| | | | |
| Bus | Magnitude | Angle | Active | Reactive | Active | Reactive |
| | [kV] | [deg] | [MW] | [MVAr] | [MW] | [MVAr] |
|-------|-----------|---------|----------|----------|-----------|----------|
| Bus 1 | 66.3953 | 0.0000 | 0.0000 | 0.0000 | 120.0000 | 25.8458 |
| Bus 2 | 134.5731 | -1.9950 | 0.0000 | 0.0000 | -0.0000 | 0.0000 |
| Bus 3 | 132.4899 | -8.8109 | 120.0000 | 10.0000 | -120.0000 | -10.0000 |
|--------------------------------------------------------------------------|
Here, the voltage magnitudes in kV represent line-to-neutral voltages for each bus, while the powers in MW and MVAr represent three-phase powers.
SI Units to Per-Units
In this section, we will create the same power system as before, but using SI units:
@voltage(kV, deg, kV)
@power(MW, MVAr, MVA)
@parameter(Ω, S)
system = powerSystem()
@base(system, MVA, kV)
Note that even though we define parameters in SI units, JuliaGrid will automatically convert these parameters to per-units and store them in that format.
Buses
Next, we add the same three buses, this time using SI units:
addBus!(system; label = "Bus 1", type = 3, magnitude = 115 / sqrt(3) , base = 115.0)
addBus!(system; label = "Bus 2", type = 1, magnitude = 253 / sqrt(3), base = 230.0)
addBus!(system; label = "Bus 3", type = 1, active = 120, reactive = 100, base = 230.0)
The base
keyword specifies the base line-to-line voltages $V_{LL(\text{b})}$ for each bus in kV, and these values are also stored in kV:
julia> print(system.bus.label, system.base.voltage.value)
Bus 1: 115.0 Bus 2: 230.0 Bus 3: 230.0
The magnitude
keyword sets the initial line-to-neutral bus voltages in kV, but they are stored in per-units:
julia> print(system.bus.label, system.bus.voltage.magnitude)
Bus 1: 1.0 Bus 2: 1.0999999999999999 Bus 3: 1.0
Using the active
and reactive
keywords, we define the three-phase power demands for the load at Bus 3
in SI units, which are then stored in per-units:
julia> print(system.bus.label, system.bus.demand.active, system.bus.demand.reactive)
Bus 1: 0.0, 0.0 Bus 2: 0.0, 0.0 Bus 3: 1.2, 1.0
Branches
Now, let us define the branches:
@branch(label = "Branch ?")
addBranch!(system; from = "Bus 1", to = "Bus 2", turnsRatio = 0.98, reactance = 3.81)
addBranch!(system; from = "Bus 2", to = "Bus 3", reactance = 52.9, susceptance = 5.67e-5)
The first branch represents a transformer, with its reactance specified in ohms on the primary side (from-bus end) and an off-nominal turns ratio of $\tau = 0.98$. This reactance is then converted to the secondary side and transformed into per-units. The second branch represents a transmission line, with its parameters in SI units, which are also stored in per-units:
julia> prmt = system.branch.parameter;
julia> print(system.branch.label, prmt.reactance, prmt.susceptance, prmt.turnsRatio)
Branch 1: 0.029996953065397295, 0.0, 0.98 Branch 2: 0.1, 0.0299943, 1.0
Generators
Finally, we add the same generator as before:
@generator(label = "Generator ?")
addGenerator!(system; bus = "Bus 1", active = 230.0, reactive = 20.0)
Using the active
and reactive
keywords, we define the three-phase power output of the generator in SI units, and these values are stored in per-units:
julia> output = system.generator.output;
julia> print(system.generator.label, output.active, output.reactive)
Generator 1: 2.3000000000000003, 0.2
AC Power Flow
As before, we can perform AC power flow analysis on our defined power system:
analysis = newtonRaphson(system)
for i = 1:10
stopping = mismatch!(system, analysis)
if all(stopping .< 1e-8)
break
end
solve!(system, analysis)
end
power!(system, analysis)
Results
Now, we will examine the results in per-units:
@voltage(pu, rad, V)
@power(pu, pu, pu)
show = Dict("Power Generation" => false, "Shunt Power" => false)
printBusData(system, analysis; show)
|----------------------------------------------------------------------|
| Bus Data |
|----------------------------------------------------------------------|
| Label | Voltage | Power Demand | Power Injection |
| | | | |
| Bus | Magnitude | Angle | Active | Reactive | Active | Reactive |
| | [pu] | [rad] | [pu] | [pu] | [pu] | [pu] |
|-------|-----------|---------|--------|----------|---------|----------|
| Bus 1 | 1.0000 | 0.0000 | 0.0000 | 0.0000 | 1.2000 | 1.4048 |
| Bus 2 | 0.9797 | -0.0360 | 0.0000 | 0.0000 | -0.0000 | 0.0000 |
| Bus 3 | 0.8538 | -0.1800 | 1.2000 | 1.0000 | -1.2000 | -1.0000 |
|----------------------------------------------------------------------|
Here, the voltage magnitudes in per-units represent line-to-neutral voltages for each bus, while the powers are independent of whether they are three-phase or single-phase, since they are expressed in per-units.