diff --git a/packages/modules/common/utils/peak_filter.py b/packages/modules/common/utils/peak_filter.py index 0ef0cc1af3..bfb26cfbad 100644 --- a/packages/modules/common/utils/peak_filter.py +++ b/packages/modules/common/utils/peak_filter.py @@ -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 @@ -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( @@ -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. " @@ -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 diff --git a/packages/modules/common/utils/test_peak_filter.py b/packages/modules/common/utils/test_peak_filter.py index b50d9eedd8..9af278ece9 100644 --- a/packages/modules/common/utils/test_peak_filter.py +++ b/packages/modules/common/utils/test_peak_filter.py @@ -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