Skip to content
Merged
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
47 changes: 35 additions & 12 deletions packages/modules/common/utils/peak_filter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
from control import data
from typing import Optional
from typing import Optional, Tuple

from modules.common.fault_state import FaultState
from modules.common.component_type import ComponentType
Expand Down Expand Up @@ -64,12 +64,12 @@ def check_imported_exported(
control_interval = data.data.general_data.data.control_interval
allowed_deviation = 2 * (control_interval / 3600) * max_power

imp = self.check_total_energy(imported, self.imported, allowed_deviation, max_energy)
self.imported = imported
checked_imp, prev_imp = self.check_total_energy(imported, self.imported, allowed_deviation, max_energy)
self.imported = prev_imp

exp = self.check_total_energy(exported, self.exported, allowed_deviation, max_energy)
self.exported = exported
return imp, exp
checked_exp, prev_exp = self.check_total_energy(exported, self.exported, allowed_deviation, max_energy)
self.exported = prev_exp
return checked_imp, checked_exp
return imported, exported

def check_total_energy(
Expand All @@ -78,7 +78,7 @@ def check_total_energy(
previous_total_energy: Optional[float],
allowed_deviation: float,
max_energy: float
) -> Optional[float]:
) -> Tuple[Optional[float], Optional[float]]:
if total_energy is not None:
if total_energy > max_energy:
log.debug(f"PeakFilter: Unplausibler Zählerwert: {total_energy / 1000}kWh. "
Expand All @@ -88,14 +88,37 @@ def check_total_energy(
self.fault_state.warning("PeakFilter: Vorheriger Wert None (Startup), "
f"aktueller Zählerwert: {total_energy / 1000 }kWh. "
"Warte einen Regelintervall.")
elif (allowed_deviation > 0 and
((total_energy - previous_total_energy) > allowed_deviation or
(total_energy - previous_total_energy) < 0)):
elif allowed_deviation > 0 and (total_energy - previous_total_energy) > allowed_deviation:
log.debug(f"PeakFilter: Unplausibler Zählerwert: {total_energy / 1000}kWh. "
f"Differenz zum vorherigen Wert: {total_energy - previous_total_energy}Wh. "
f"erlaubte Differenz: {round(allowed_deviation, 2)}Wh.")
elif (total_energy - previous_total_energy) < 0:
if previous_total_energy > max_energy:
log.debug("PeakFilter: Erholung nach unplausibel hohem Zählerwert erkannt. "
f"Vorheriger Wert: {previous_total_energy / 1000}kWh über dem 50-Jahres-Limit "
f"({max_energy / 1000}kWh). Aktueller Wert {total_energy / 1000}kWh wird "
"verworfen und als neue Vergleichsbasis verwendet.")
checked_energy = None
prev_energy = total_energy
return checked_energy, prev_energy
log.debug(f"PeakFilter: Unplausibler Rückwärtssprung: {total_energy / 1000}kWh. "
f"Vorherigen Wert: {previous_total_energy / 1000}kWh. "
"Höchststand beibehalten.")
checked_energy = previous_total_energy
prev_energy = previous_total_energy
return checked_energy, prev_energy
else:
log.debug(f"PeakFilter: Zählerwert: {total_energy}Wh innerhalb der zulässigen Grenzen. "
f"Differenz zum vorherigen Wert: {total_energy - previous_total_energy}Wh.")
return total_energy
return None
checked_energy = total_energy
prev_energy = total_energy
return checked_energy, prev_energy
# wenn der Peak-Filter greift, Zählerstand nicht aktualisieren (None).
# Zählerstand merken, damit immer nur die zwei letzten verglichen werden, um Vorwärtssprünge abzubilden.
checked_energy = None
prev_energy = total_energy
return checked_energy, prev_energy
else:
checked_energy = None
prev_energy = None
return checked_energy, prev_energy
54 changes: 54 additions & 0 deletions packages/modules/common/utils/test_peak_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,57 @@ def test_check_values_valid(params):
imp, exp = pf.check_values(params.power, params.imported, params.exported)
assert imp == params.expected_imported
assert exp == params.expected_exported


def test_check_total_energy_forward_jump_then_accept_second_high_and_wait_after_backward_jump():
fs = DummyFaultState()
pf = PeakFilter(ComponentType.COUNTER, 1, fs)

allowed_deviation = 10
max_energy = 1_000_000_000

# Vorwaertssprung: erster Wert wird verworfen, aber als Vergleichsbasis gespeichert.
checked, previous = pf.check_total_energy(2000, 1000, allowed_deviation, max_energy)
assert checked is None
assert previous == 2000

# Zweiter hoher Wert mit kleiner Differenz wird uebernommen.
checked, previous = pf.check_total_energy(2005, previous, allowed_deviation, max_energy)
assert checked == 2005
assert previous == 2005

# Rueckwaertssprung: letzter gueltiger Hoechststand bleibt erhalten.
checked, previous = pf.check_total_energy(1900, previous, allowed_deviation, max_energy)
assert checked == 2005
assert previous == 2005

# Unterhalb des Hoechststands wird weiterhin gewartet.
checked, previous = pf.check_total_energy(1990, previous, allowed_deviation, max_energy)
assert checked == 2005
assert previous == 2005

# Naechster gleicher oder hoeherer Wert wird wieder zugelassen.
checked, previous = pf.check_total_energy(2005, previous, allowed_deviation, max_energy)
assert checked == 2005
assert previous == 2005

checked, previous = pf.check_total_energy(2010, previous, allowed_deviation, max_energy)
assert checked == 2010
assert previous == 2010

# Der niedrigere Folgewert wird einmal verworfen und als neue Vergleichsbasis gesetzt.
allowed_deviation = 10
max_energy = 3000

checked, previous = pf.check_total_energy(4000, 2900, allowed_deviation, max_energy)
assert checked is None
assert previous == 4000

checked, previous = pf.check_total_energy(2800, previous, allowed_deviation, max_energy)
assert checked is None
assert previous == 2800

# Danach wird ein plausibler Folgewert wieder zugelassen.
checked, previous = pf.check_total_energy(2805, previous, allowed_deviation, max_energy)
assert checked == 2805
assert previous == 2805
Loading