Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow more transformer vector groups #17

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion roseau/load_flow_single/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from roseau.load_flow import Projection, TransformerParameters
from roseau.load_flow import Projection
from roseau.load_flow_single.models.branches import AbstractBranch
from roseau.load_flow_single.models.buses import Bus
from roseau.load_flow_single.models.core import Element
Expand All @@ -8,6 +8,7 @@
from roseau.load_flow_single.models.loads import AbstractLoad, CurrentLoad, ImpedanceLoad, PowerLoad
from roseau.load_flow_single.models.sources import VoltageSource
from roseau.load_flow_single.models.switches import Switch
from roseau.load_flow_single.models.transformer_parameters import TransformerParameters
from roseau.load_flow_single.models.transformers import Transformer

__all__ = [
Expand Down
44 changes: 44 additions & 0 deletions roseau/load_flow_single/models/transformer_parameters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import cmath
from typing import Final

from roseau.load_flow import TransformerParameters as MultiTransformerParameters

_PHASE_SHIFT: Final = {clock: cmath.exp(-1j * clock * cmath.pi / 6) for clock in (0, 1, 2, 4, 5, 6, 7, 8, 10, 11)}
"""Phase shift for each clock number in the transformer vector group."""


class TransformerParameters(MultiTransformerParameters):
"""Parameters that define electrical models of three-phase transformers."""

# fmt: off
# Note (AH): No zigzag on the HV side as it is not common, could be added later if needed
allowed_vector_groups: Final = {
# Common connections (clock numbers 0, 1, 5, 6, 11)
"Dd0", "Yy0", "YNy0", "Yyn0", "YNyn0", "Dz0", "Dzn0",
"Dy1", "Dyn1", "Yz1", "YNz1", "Yzn1", "YNzn1", "Yd1", "YNd1",
"Dy5", "Dyn5", "Yz5", "YNz5", "Yzn5", "YNzn5", "Yd5", "YNd5",
"Dd6", "Yy6", "YNy6", "Yyn6", "YNyn6", "Yz6", "Yzn6", "YNz6", "YNzn6", "Dz6", "Dzn6",
"Dy11", "Dyn11", "Yz11", "YNz11", "Yzn11", "YNzn11", "Yd11", "YNd11",
# Additional connections (clock numbers 2, 4, 7, 8, 10)
"Dd2", "Dz2", "Dzn2",
"Dd4", "Dz4", "Dzn4",
"Dy7", "Dyn7", "Yz7", "YNz7", "Yzn7", "YNzn7", "Yd7", "YNd7",
"Dd8", "Dz8", "Dzn8",
"Dd10", "Dz10", "Dzn10",
}
# fmt: on

@property
def kd(self) -> complex:
"""The positive-sequence (direct-system) transformation ratio of the transformer."""
return self._ulv / self._uhv * _PHASE_SHIFT[self._phase_displacement]

@property
def z2d(self) -> complex:
"""The positive-sequence (direct-system) series impedance of the transformer."""
return self._z2 / 3.0 if self.winding2[0] == "d" else self._z2

@property
def ymd(self) -> complex:
"""The positive-sequence (direct-system) magnetizing admittance of the transformer."""
return self._ym * 3.0 if self.winding1[0] == "D" else self._ym
46 changes: 5 additions & 41 deletions roseau/load_flow_single/models/transformers.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,17 @@
import logging
from typing import Final

from shapely.geometry.base import BaseGeometry

from roseau.load_flow import ALPHA, ALPHA2, RoseauLoadFlowException, RoseauLoadFlowExceptionCode, TransformerParameters
from roseau.load_flow import RoseauLoadFlowException, RoseauLoadFlowExceptionCode
from roseau.load_flow.typing import Float, Id, JsonDict
from roseau.load_flow.units import Q_, ureg_wraps
from roseau.load_flow_engine.cy_engine import CySingleTransformer
from roseau.load_flow_single.models.branches import AbstractBranch
from roseau.load_flow_single.models.buses import Bus
from roseau.load_flow_single.models.transformer_parameters import TransformerParameters

logger = logging.getLogger(__name__)

# TODO: add more vector groups
_K_DIRECT_SYS_FACTOR: Final = {
("D", "d", 0): 1 + 0j,
("Y", "y", 0): 1 + 0j,
("D", "z", 0): 3 + 0j,
("D", "d", 6): -1 + 0j,
("Y", "y", 6): -1 + 0j,
("D", "z", 6): -3 + 0j,
("D", "y", 1): 1 - ALPHA,
("Y", "z", 1): 1 - ALPHA,
("Y", "d", 1): 1 / (1 - ALPHA2),
("D", "y", 5): ALPHA2 - 1,
("Y", "z", 5): ALPHA2 - 1,
("Y", "d", 5): 1 / (ALPHA - 1),
("D", "y", 11): 1 - ALPHA2,
("Y", "z", 11): 1 - ALPHA2,
("Y", "d", 11): 1 / (1 - ALPHA),
}


class Transformer(AbstractBranch[CySingleTransformer]):
"""A generic transformer model.
Expand Down Expand Up @@ -80,33 +61,16 @@ def __init__(
"""
super().__init__(id=id, bus1=bus1, bus2=bus2, n=2, geometry=geometry)

if parameters.type != "three-phase":
msg = f"{parameters.type.capitalize()} transformers are not allowed in a balanced three-phase load flow."
logger.error(msg)
raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_TRANSFORMER_TYPE)

self.tap = tap
self._parameters = parameters
self.max_loading = max_loading

# Equivalent direct-system (positive-sequence) parameters
z2, ym, k = self._get_direct_sys_zyk(parameters)
z2, ym, k = parameters.z2d, parameters.ymd, parameters.kd

self._cy_element = CySingleTransformer(z2=z2, ym=ym, k=k * tap)
self._cy_connect()

@staticmethod
def _get_direct_sys_zyk(tp: TransformerParameters) -> tuple[complex, complex, complex]:
"""Get the equivalent direct-system (positive-sequence) transformer parameters."""
w1, w2 = tp.winding1[0], tp.winding2[0]
z2, ym = tp._z2, tp._ym
if w1 == "D":
ym *= 3.0
if w2 == "d":
z2 /= 3.0
k = tp._k * _K_DIRECT_SYS_FACTOR[w1[0], w2[0], tp.phase_displacement]
return z2, ym, k

@property
def tap(self) -> float:
"""The tap of the transformer, for example 1.02."""
Expand All @@ -121,7 +85,7 @@ def tap(self, value: Float) -> None:
self._tap = float(value)
self._invalidate_network_results()
if self._cy_element is not None:
z2, ym, k = self._get_direct_sys_zyk(self.parameters)
z2, ym, k = self.parameters.z2d, self.parameters.ymd, self.parameters.kd
self._cy_element.update_transformer_parameters(z2, ym, k * value)

@property
Expand All @@ -139,7 +103,7 @@ def parameters(self, value: TransformerParameters) -> None:
self._parameters = value
self._invalidate_network_results()
if self._cy_element is not None:
z2, ym, k = self._get_direct_sys_zyk(value)
z2, ym, k = value.z2d, value.ymd, value.kd
self._cy_element.update_transformer_parameters(z2, ym, k * self.tap)

@property
Expand Down
9 changes: 4 additions & 5 deletions roseau/load_flow_single/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -926,12 +926,11 @@ def _propagate_voltages(self) -> None:
for e in element._connected_elements:
if e not in visited:
if isinstance(element, Transformer):
k = element.parameters._ulv / element.parameters._uhv
elements.append((e, initial_voltage * k, element)) # TODO dephasage
visited.add(e)
element_voltage = initial_voltage * element.parameters.kd * element._tap
else:
elements.append((e, initial_voltage, element))
visited.add(e)
element_voltage = initial_voltage
elements.append((e, element_voltage, element))
visited.add(e)
elif parent != e:
self._has_loop = True

Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading