Skip to content

Commit

Permalink
Add reactive power for inverters, meters and EV chargers
Browse files Browse the repository at this point in the history
Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
  • Loading branch information
llucax committed Mar 27, 2024
1 parent c1f6059 commit bb708b6
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/frequenz/client/microgrid/_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,16 @@ class ComponentMetricId(Enum):
ACTIVE_POWER_PHASE_3 = "active_power_phase_3"
"""Active power in phase 3."""

REACTIVE_POWER = "reactive_power"
"""Reactive power."""

REACTIVE_POWER_PHASE_1 = "reactive_power_phase_1"
"""Reactive power in phase 1."""
REACTIVE_POWER_PHASE_2 = "reactive_power_phase_2"
"""Reactive power in phase 2."""
REACTIVE_POWER_PHASE_3 = "reactive_power_phase_3"
"""Reactive power in phase 3."""

CURRENT_PHASE_1 = "current_phase_1"
"""Current in phase 1."""
CURRENT_PHASE_2 = "current_phase_2"
Expand Down
66 changes: 66 additions & 0 deletions src/frequenz/client/microgrid/_component_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,22 @@ class MeterData(ComponentData):
* Negative means supply into the grid.
"""

reactive_power: float
"""The total reactive 3-phase AC power, in Volt-Ampere Reactive (VAr).
* Positive power means capacitive (current leading w.r.t. voltage).
* Negative power means inductive (current lagging w.r.t. voltage).
"""

reactive_power_per_phase: tuple[float, float, float]
"""The per-phase AC reactive power, in Volt-Ampere Reactive (VAr).
The provided values are for phase 1, 2, and 3 respectively.
* Positive power means capacitive (current leading w.r.t. voltage).
* Negative power means inductive (current lagging w.r.t. voltage).
"""

current_per_phase: tuple[float, float, float]
"""AC current in Amperes (A) for phase/line 1,2 and 3 respectively.
Expand Down Expand Up @@ -123,6 +139,12 @@ def from_proto(cls, raw: PbComponentData) -> Self:
raw.meter.data.ac.phase_2.power_active.value,
raw.meter.data.ac.phase_3.power_active.value,
),
reactive_power=raw.meter.data.ac.power_reactive.value,
reactive_power_per_phase=(
raw.meter.data.ac.phase_1.power_reactive.value,
raw.meter.data.ac.phase_2.power_reactive.value,
raw.meter.data.ac.phase_3.power_reactive.value,
),
current_per_phase=(
raw.meter.data.ac.phase_1.current.value,
raw.meter.data.ac.phase_2.current.value,
Expand Down Expand Up @@ -270,6 +292,22 @@ class InverterData(ComponentData): # pylint: disable=too-many-instance-attribut
* Negative means supply into the grid.
"""

reactive_power: float
"""The total reactive 3-phase AC power, in Volt-Ampere Reactive (VAr).
* Positive power means capacitive (current leading w.r.t. voltage).
* Negative power means inductive (current lagging w.r.t. voltage).
"""

reactive_power_per_phase: tuple[float, float, float]
"""The per-phase AC reactive power, in Volt-Ampere Reactive (VAr).
The provided values are for phase 1, 2, and 3 respectively.
* Positive power means capacitive (current leading w.r.t. voltage).
* Negative power means inductive (current lagging w.r.t. voltage).
"""

current_per_phase: tuple[float, float, float]
"""AC current in Amperes (A) for phase/line 1, 2 and 3 respectively.
Expand Down Expand Up @@ -359,6 +397,12 @@ def from_proto(cls, raw: PbComponentData) -> Self:
raw.inverter.data.ac.phase_2.power_active.value,
raw.inverter.data.ac.phase_3.power_active.value,
),
reactive_power=raw.inverter.data.ac.power_reactive.value,
reactive_power_per_phase=(
raw.inverter.data.ac.phase_1.power_reactive.value,
raw.inverter.data.ac.phase_2.power_reactive.value,
raw.inverter.data.ac.phase_3.power_reactive.value,
),
current_per_phase=(
raw.inverter.data.ac.phase_1.current.value,
raw.inverter.data.ac.phase_2.current.value,
Expand Down Expand Up @@ -413,6 +457,22 @@ class EVChargerData(ComponentData): # pylint: disable=too-many-instance-attribu
* Negative means supply into the grid.
"""

reactive_power: float
"""The total reactive 3-phase AC power, in Volt-Ampere Reactive (VAr).
* Positive power means capacitive (current leading w.r.t. voltage).
* Negative power means inductive (current lagging w.r.t. voltage).
"""

reactive_power_per_phase: tuple[float, float, float]
"""The per-phase AC reactive power, in Volt-Ampere Reactive (VAr).
The provided values are for phase 1, 2, and 3 respectively.
* Positive power means capacitive (current leading w.r.t. voltage).
* Negative power means inductive (current lagging w.r.t. voltage).
"""

voltage_per_phase: tuple[float, float, float]
"""The AC voltage in Volts (V) between the line and the neutral
wire for phase/line 1,2 and 3 respectively.
Expand Down Expand Up @@ -491,6 +551,12 @@ def from_proto(cls, raw: PbComponentData) -> Self:
raw.ev_charger.data.ac.phase_2.power_active.value,
raw.ev_charger.data.ac.phase_3.power_active.value,
),
reactive_power=raw.ev_charger.data.ac.power_reactive.value,
reactive_power_per_phase=(
raw.ev_charger.data.ac.phase_1.power_reactive.value,
raw.ev_charger.data.ac.phase_2.power_reactive.value,
raw.ev_charger.data.ac.phase_3.power_reactive.value,
),
current_per_phase=(
raw.ev_charger.data.ac.phase_1.current.value,
raw.ev_charger.data.ac.phase_2.current.value,
Expand Down
10 changes: 10 additions & 0 deletions tests/test_component_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,28 @@ def test_inverter_data() -> None:
system_exclusion_bounds=Bounds(lower=-501.0, upper=501.0),
system_inclusion_bounds=Bounds(lower=-51_000.0, upper=51_000.0),
),
power_reactive=Metric(
value=200.3,
system_exclusion_bounds=Bounds(lower=-502.0, upper=502.0),
system_inclusion_bounds=Bounds(lower=-52_000.0, upper=52_000.0),
),
phase_1=AC.ACPhase(
current=Metric(value=12.3),
voltage=Metric(value=229.8),
power_active=Metric(value=33.1),
power_reactive=Metric(value=10.1),
),
phase_2=AC.ACPhase(
current=Metric(value=23.4),
voltage=Metric(value=230.0),
power_active=Metric(value=33.3),
power_reactive=Metric(value=10.2),
),
phase_3=AC.ACPhase(
current=Metric(value=34.5),
voltage=Metric(value=230.2),
power_active=Metric(value=33.8),
power_reactive=Metric(value=10.3),
),
),
),
Expand All @@ -84,6 +92,8 @@ def test_inverter_data() -> None:
assert inv_data.frequency == pytest.approx(50.1)
assert inv_data.active_power == pytest.approx(100.2)
assert inv_data.active_power_per_phase == pytest.approx((33.1, 33.3, 33.8))
assert inv_data.reactive_power == pytest.approx(200.3)
assert inv_data.reactive_power_per_phase == pytest.approx((10.1, 10.2, 10.3))
assert inv_data.current_per_phase == pytest.approx((12.3, 23.4, 34.5))
assert inv_data.voltage_per_phase == pytest.approx((229.8, 230.0, 230.2))
assert inv_data.active_power_inclusion_lower_bound == pytest.approx(-51_000.0)
Expand Down

0 comments on commit bb708b6

Please sign in to comment.