Skip to content

Commit 5f3cd29

Browse files
authored
Improve BatteryPool's SoC accuracy at the edges (#843)
When SoC is close to 0.0 or 100.0, it will be exactly 0.0 or 100.0.
2 parents f52f791 + 3c17ac3 commit 5f3cd29

File tree

1 file changed

+16
-11
lines changed

1 file changed

+16
-11
lines changed

src/frequenz/sdk/timeseries/battery_pool/_metric_calculator.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55

66

77
import logging
8+
import math
89
from abc import ABC, abstractmethod
910
from collections.abc import Mapping, Set
1011
from datetime import datetime, timezone
1112
from typing import Generic, TypeVar
1213

1314
from ... import timeseries
15+
from ..._internal import _math
1416
from ...actor.power_distributing._component_managers._battery_manager import (
1517
_get_battery_inverter_mappings,
1618
)
@@ -361,9 +363,9 @@ def calculate(
361363
Return None if there are no component metrics.
362364
"""
363365
timestamp = _MIN_TIMESTAMP
364-
usable_capacity_x100: float = 0
365-
used_capacity_x100: float = 0
366-
total_capacity_x100: float = 0
366+
usable_capacity_x100: float = 0.0
367+
used_capacity_x100: float = 0.0
368+
total_capacity_x100: float = 0.0
367369

368370
for battery_id in working_batteries:
369371
if battery_id not in metrics_data:
@@ -395,26 +397,29 @@ def calculate(
395397
# Therefore, the variables are named with a `_x100` suffix.
396398
usable_capacity_x100 = capacity * (soc_upper_bound - soc_lower_bound)
397399
soc_scaled = (
398-
(soc - soc_lower_bound) / (soc_upper_bound - soc_lower_bound) * 100
400+
(soc - soc_lower_bound) / (soc_upper_bound - soc_lower_bound) * 100.0
399401
)
400402
# we are clamping here because the SoC might be out of bounds
401-
soc_scaled = min(max(soc_scaled, 0), 100)
403+
soc_scaled = min(max(soc_scaled, 0.0), 100.0)
402404
timestamp = max(timestamp, metrics.timestamp)
403405
used_capacity_x100 += usable_capacity_x100 * soc_scaled
404406
total_capacity_x100 += usable_capacity_x100
405407

406408
if timestamp == _MIN_TIMESTAMP:
407409
return Sample(datetime.now(tz=timezone.utc), None)
408410

411+
# When the calculated is close to 0.0 or 100.0, they are set to exactly 0.0 or
412+
# 100.0, to make full/empty checks using the == operator less error prone.
413+
pct = 0.0
409414
# To avoid zero division error
410-
if total_capacity_x100 == 0:
411-
return Sample(
412-
timestamp=timestamp,
413-
value=Percentage.from_percent(0.0),
414-
)
415+
if not _math.is_close_to_zero(total_capacity_x100):
416+
pct = used_capacity_x100 / total_capacity_x100
417+
if math.isclose(pct, 100.0):
418+
pct = 100.0
419+
415420
return Sample(
416421
timestamp=timestamp,
417-
value=Percentage.from_percent(used_capacity_x100 / total_capacity_x100),
422+
value=Percentage.from_percent(pct),
418423
)
419424

420425

0 commit comments

Comments
 (0)