Working with Units in Power System Components¶
This tutorial guides you through creating power system components with proper unit handling in R2X Core. You’ll learn how to define components with per-unit calculations, work with different unit systems, and leverage multiple base values for complex equipment models.
What You’ll Learn¶
By the end of this tutorial, you’ll be able to:
Create components with unit-aware fields
Use device-base and system-base per-unit systems
Display values in different unit modes
Handle natural unit inputs automatically
Work with components that have multiple base values
Prerequisites¶
Make sure you have R2X Core installed:
pip install r2x-core
Understanding Per-Unit Systems in Power Systems¶
Power system analysis relies heavily on per-unit normalization to simplify calculations and comparisons across equipment with different ratings. In R2X Core, components can express electrical quantities in three different ways depending on the analysis context.
Important
All per-unit quantities in R2X Core are stored internally in device-base per-unit. Display modes only affect how values are shown to users, not how they’re stored or used in calculations.
Step 1: Creating a Basic Component with Units¶
Let’s start by creating a simple generator component that tracks its power output using per-unit values.
from typing import Annotated
from infrasys import Component
from r2x_core.units import HasPerUnit, Unit
class Generator(HasPerUnit, Component):
"""A simple generator with per-unit power tracking."""
base_power: Annotated[float, Unit("MVA")]
rated_voltage: Annotated[float, Unit("kV")]
output: Annotated[float, Unit("pu", base="base_power")]
The base_power
field uses Unit("MVA")
to indicate it stores power in megavolt-amperes. The output
field uses Unit("pu", base="base_power")
which tells R2X Core that this value is in per-unit with base_power
as its base quantity.
Create a generator instance:
gen = Generator(
name="Coal Plant 1",
base_power=500.0, # 500 MVA rated capacity
rated_voltage=22.0, # 22 kV terminal voltage
output=0.85 # Operating at 85% of rated capacity
)
print(f"Generator: {gen.name}")
print(f"Base Power: {gen.base_power} MVA")
print(f"Output: {gen.output} pu")
# Output shows: Output: 0.85 pu
The component stores output
internally as 0.85 in per-unit based on the device’s own rating.
Tip
Use Unit()
as a shorthand for UnitSpec()
. Both work identically: Unit("MVA")
is equivalent to UnitSpec("MVA")
.
Step 2: Using Natural Unit Inputs¶
R2X Core automatically converts natural units to per-unit for storage. Instead of manually calculating per-unit values, you can provide actual megawatt values:
gen = Generator(
name="Wind Farm 1",
base_power=200.0,
rated_voltage=34.5,
output={"value": 150.0, "unit": "MVA"} # Natural unit input
)
print(f"Output: {gen.output} pu")
# Automatically converted: 150 MVA / 200 MVA base = 0.75 pu
When you provide a dictionary with value
and unit
keys, R2X Core performs the conversion automatically. This feature simplifies data import from external sources that provide measurements in physical units rather than per-unit.
Note
Natural unit inputs are automatically converted during component construction. The internal storage is always per-unit, ensuring consistent calculations regardless of input format.
Step 3: Displaying Values in Different Unit Systems¶
R2X Core supports three display modes for per-unit quantities, allowing you to view the same data in different ways depending on your analysis needs.
Device-Base Per-Unit (Default)¶
The default mode shows values normalized to each device’s own rating:
from r2x_core.units import UnitSystem, set_unit_system
# Ensure device-base mode
set_unit_system(UnitSystem.DEVICE_BASE)
gen = Generator(
name="Gas Turbine 1",
base_power=300.0,
rated_voltage=13.8,
output=0.90
)
print(gen)
# Shows: output='0.9 pu'
This mode is intuitive because each device expresses its loading relative to its own nameplate rating.
Natural Units Mode¶
Natural units mode displays the actual physical quantities:
set_unit_system(UnitSystem.NATURAL_UNITS)
print(gen)
# Shows: output='270 MVA' (calculated as 0.90 * 300 MVA)
This mode is helpful when you need to see absolute values for reporting or validation against measured data.
System-Base Per-Unit¶
System-base mode normalizes all quantities to a common system base, essential for power flow analysis and system-wide comparisons:
from r2x_core.system import System
# Create a system with 100 MVA system base
system = System(100.0, name="TransmissionGrid")
system.add_component(gen)
set_unit_system(UnitSystem.SYSTEM_BASE)
print(gen)
# Shows: output='2.7 pu (system)' (calculated as 270 MVA / 100 MVA system base)
When components are added to a system, they automatically track the system base power for this conversion. System-base per-unit is crucial for network analysis where all impedances and powers must reference the same base.
Warning
Components can only be added to one system at a time. Attempting to add a component to multiple systems with different base values will raise an error.
Step 4: Working with Multiple Base Values¶
Real power system equipment often has multiple ratings. A transformer, for example, has separate voltage bases for its high and low sides:
class Transformer(HasPerUnit, Component):
"""Transformer with high and low voltage sides."""
base_power: Annotated[float, Unit("MVA")]
high_voltage: Annotated[float, Unit("kV")]
low_voltage: Annotated[float, Unit("kV")]
# Impedance referenced to base_power
impedance: Annotated[float, Unit("pu", base="base_power")]
# Tap position referenced to high_voltage
tap_position: Annotated[float, Unit("pu", base="high_voltage")]
# Load current referenced to low_voltage
load_current: Annotated[float, Unit("pu", base="low_voltage")]
Create a transformer with multiple references:
tx = Transformer(
name="Main Transformer",
base_power=100.0,
high_voltage=138.0,
low_voltage=13.8,
impedance=0.10,
tap_position=1.05, # 5% above nominal
load_current={"value": 4.2, "unit": "kA"} # Natural units
)
Each per-unit field correctly references its designated base. The impedance
uses base_power
, tap_position
uses high_voltage
, and load_current
uses low_voltage
. R2X Core tracks these relationships and performs conversions accordingly:
set_unit_system(UnitSystem.NATURAL_UNITS)
print(f"Impedance: {tx.impedance}") # Shows as percentage of base power
print(f"Tap: {tx.tap_position}") # Shows as kV on high side
print(f"Current: {tx.load_current}") # Shows as amperes on low side
Step 5: Building a Complete System¶
Let’s combine everything into a small power system:
from r2x_core.system import System
from r2x_core.units import set_unit_system, UnitSystem
# Create system with 100 MVA base
system = System(100.0, name="DistributionFeeder")
# Add generators
coal_gen = Generator(
name="Coal Unit",
base_power=500.0,
rated_voltage=22.0,
output={"value": 425.0, "unit": "MVA"}
)
wind_gen = Generator(
name="Wind Farm",
base_power=150.0,
rated_voltage=34.5,
output={"value": 120.0, "unit": "MVA"}
)
# Add transformer
step_up = Transformer(
name="Step-Up TX",
base_power=600.0,
high_voltage=230.0,
low_voltage=22.0,
impedance=0.08,
tap_position=1.0,
load_current=0.85
)
system.add_components(coal_gen, wind_gen, step_up)
# View in different modes
print("=== Device Base ===")
set_unit_system(UnitSystem.DEVICE_BASE)
for comp in system.get_components(Generator):
print(f"{comp.name}: output={comp.output}")
print("\n=== Natural Units ===")
set_unit_system(UnitSystem.NATURAL_UNITS)
for comp in system.get_components(Generator):
print(f"{comp.name}: output={comp.output}")
print("\n=== System Base ===")
set_unit_system(UnitSystem.SYSTEM_BASE)
for comp in system.get_components(Generator):
print(f"{comp.name}: output={comp.output}")
The output demonstrates how the same data appears in each mode:
=== Device Base ===
Coal Unit: output=0.85 pu
Wind Farm: output=0.8 pu
=== Natural Units ===
Coal Unit: output=425 MVA
Wind Farm: output=120 MVA
=== System Base ===
Coal Unit: output=4.25 pu (system)
Wind Farm: output=1.2 pu (system)
Next Steps¶
Now that you understand unit handling in R2X Core, you can:
Create complex component models with multiple electrical quantities
Import data from measurement systems using natural units
Perform system-wide analysis using common system-base per-unit
Build parsers that automatically handle unit conversions
See also
Unit Operations - Additional unit manipulation techniques
Unit System Design and Architecture - Deep dive into the unit system design
Units Module - Complete API reference for units module