From c4a0653ca85d5314b9bdff9886e9be0d36fad894 Mon Sep 17 00:00:00 2001 From: Felix Remmel Date: Tue, 7 Jan 2025 17:15:35 +0100 Subject: [PATCH] fix(core): Avoid flickering between charge/discharge due to PID filter Before this change the PID filter implementation eventually caused the behavior to switch from charging to discharing, eventhough the system wanted to (a) charge with a lower value than before (b) set active power to 0. This was due to the fact, that the PID filter overshoots its target. By detecting if the system wants charge/discharge/no current flow the battery, it now dynamically adjusts the limits of the battery so it does not overshoot in the unwanted area. This reduces stress on the battery. It also improves the controller that are using this filter (e.g. self consumption optimization, peak load shaving). Sometimes they showed behavior where they wildly flicker between charging/discharging. --- .../ess/api/ActivePowerConstraintWithPid.java | 40 +++ .../edge/ess/api/ManagedSymmetricEss.java | 23 +- .../api/ActivePowerConstraintWithPidTest.java | 292 ++++++++++++++++++ 3 files changed, 333 insertions(+), 22 deletions(-) create mode 100644 io.openems.edge.ess.api/src/io/openems/edge/ess/api/ActivePowerConstraintWithPid.java create mode 100644 io.openems.edge.ess.api/test/io/openems/edge/ess/api/ActivePowerConstraintWithPidTest.java diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ActivePowerConstraintWithPid.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ActivePowerConstraintWithPid.java new file mode 100644 index 00000000000..5b14d2c58dc --- /dev/null +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ActivePowerConstraintWithPid.java @@ -0,0 +1,40 @@ +package io.openems.edge.ess.api; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingBiConsumer; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Pwr; + +public final class ActivePowerConstraintWithPid implements ThrowingBiConsumer { + + @Override + public void accept(ManagedSymmetricEss ess, Integer value) throws OpenemsNamedException { + if (value != null) { + var power = ess.getPower(); + var pidFilter = power.getPidFilter(); + + // configure PID filter + var minPower = power.getMinPower(ess, Phase.ALL, Pwr.ACTIVE); + var maxPower = power.getMaxPower(ess, Phase.ALL, Pwr.ACTIVE); + if (maxPower < minPower) { + maxPower = minPower; // avoid rounding error + } + + int currentActivePower = ess.getActivePower().orElse(0); + + if (value <= 0 && currentActivePower <= 0 && minPower < 0 && maxPower > 0) { + // Prevent PID filter to overshoot and flicker from charging to discharging + pidFilter.setLimits(minPower, 0); + } else if (value >= 0 && currentActivePower >= 0 && minPower < 0 && maxPower > 0) { + pidFilter.setLimits(0, maxPower); + } else { + // changing between charging/discharging is intended behavior, so we allow it. + pidFilter.setLimits(minPower, maxPower); + } + + var pidOutput = pidFilter.applyPidFilter(currentActivePower, value); + + ess.setActivePowerEquals(pidOutput); + } + } +} \ No newline at end of file diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java index 36565ec140f..8b309fb0147 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java @@ -85,28 +85,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { .unit(Unit.WATT) // .accessMode(AccessMode.WRITE_ONLY) // .onChannelSetNextWrite( - new PowerConstraint("SetActivePowerEqualsWithPid", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS) { - @Override - public void accept(ManagedSymmetricEss ess, Integer value) throws OpenemsNamedException { - if (value != null) { - var power = ess.getPower(); - var pidFilter = power.getPidFilter(); - - // configure PID filter - var minPower = power.getMinPower(ess, Phase.ALL, Pwr.ACTIVE); - var maxPower = power.getMaxPower(ess, Phase.ALL, Pwr.ACTIVE); - if (maxPower < minPower) { - maxPower = minPower; // avoid rounding error - } - pidFilter.setLimits(minPower, maxPower); - - int currentActivePower = ess.getActivePower().orElse(0); - var pidOutput = pidFilter.applyPidFilter(currentActivePower, value); - - ess.setActivePowerEquals(pidOutput); - } - } - })), + new ActivePowerConstraintWithPid())), /** * Sets a fixed Reactive Power. * diff --git a/io.openems.edge.ess.api/test/io/openems/edge/ess/api/ActivePowerConstraintWithPidTest.java b/io.openems.edge.ess.api/test/io/openems/edge/ess/api/ActivePowerConstraintWithPidTest.java new file mode 100644 index 00000000000..dc6d8dfa599 --- /dev/null +++ b/io.openems.edge.ess.api/test/io/openems/edge/ess/api/ActivePowerConstraintWithPidTest.java @@ -0,0 +1,292 @@ +package io.openems.edge.ess.api; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.common.channel.IntegerWriteChannel; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Pwr; +import io.openems.edge.ess.test.DummyManagedSymmetricEss; +import io.openems.edge.ess.test.DummyPower; + +public class ActivePowerConstraintWithPidTest { + + @Test + public void testSwitchBetweenChargeDischarge() throws OpenemsNamedException { + var constraint = new ActivePowerConstraintWithPid(); + var ess = new DummyManagedSymmetricEss("bla"); + ess.setPower(new DummyPower(0.3, 0.3, 0.1)); + var actualPower = this.setAndVerifyPower(constraint, ess, 0, 10_000, 3_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 4_800); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 6_480); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 7_548); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 8_345); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 8_868); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_235); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_481); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_648); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_762); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_839); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_891); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_926); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_950); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_966); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_977); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_984); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_989); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_993); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_995); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_997); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_998); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_998); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_999); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9_999); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, 4000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, 400); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -2960); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -5096); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -6690); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -7737); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -8471); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -8961); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9297); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9523); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9677); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9781); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9852); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9900); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9932); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9954); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9969); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9979); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9986); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9990); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9993); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9996); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9997); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9998); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9999); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9999); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -9999); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -10_000, -10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, -3_999); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, -400); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 2960); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 5096); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 6690); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 7737); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 8471); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 8961); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9297); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9523); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9677); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9781); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9852); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9900); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9932); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9954); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9969); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9979); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9985); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9990); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9993); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9996); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9997); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9998); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9999); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9999); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 9999); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 10_000, 10_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 7_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 5_200); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 3_520); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 2_452); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 1655); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 1131); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 765); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 519); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 352); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 238); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 161); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 109); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 74); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 50); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 34); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 23); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 16); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 11); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 7); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 5); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 3); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 2); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 2); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 1); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 1); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + } + + @Test + public void testBetweenChargeNoCharge() throws OpenemsNamedException { + var constraint = new ActivePowerConstraintWithPid(); + var ess = new DummyManagedSymmetricEss("bla"); + ess.setPower(new DummyPower(0.3, 0.3, 0.1)); + var actualPower = this.setAndVerifyPower(constraint, ess, 100_000, 100_000, 100_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + } + + @Test + public void testBetweenDischargeNoCharge() throws OpenemsNamedException { + var constraint = new ActivePowerConstraintWithPid(); + var ess = new DummyManagedSymmetricEss("bla"); + ess.setPower(new DummyPower(0.3, 0.3, 0.1)); + var actualPower = this.setAndVerifyPower(constraint, ess, -100_000, -100_000, -100_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, 0); + } + + @Test + public void testMaxLowerThanMin() throws OpenemsNamedException { + var constraint = new ActivePowerConstraintWithPid(); + var ess = new DummyManagedSymmetricEss("bla"); + int minPower = 5; + ess.setPower(new DummyPower(0.3, 0.3, 0.1) { + @Override + public int getMinPower(ManagedSymmetricEss ess, Phase phase, Pwr pwr) { + return minPower; + } + + @Override + public int getMaxPower(ManagedSymmetricEss ess, Phase phase, Pwr pwr) { + return minPower - 1; + } + }); + var actualPower = this.setAndVerifyPower(constraint, ess, 0, -100_000, minPower); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, minPower); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, minPower, minPower); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, minPower); + } + + @Test + public void testOnlyDischargeAllowed() throws OpenemsNamedException { + var constraint = new ActivePowerConstraintWithPid(); + var ess = new DummyManagedSymmetricEss("bla"); + ess.setPower(new DummyPower(0.3, 0.3, 0.1) { + @Override + public int getMinPower(ManagedSymmetricEss ess, Phase phase, Pwr pwr) { + return -1_000; + } + + @Override + public int getMaxPower(ManagedSymmetricEss ess, Phase phase, Pwr pwr) { + return -500; + } + }); + var actualPower = this.setAndVerifyPower(constraint, ess, 0, -2_000, -500); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -500); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -600); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -710); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -796); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -860); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -904); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -935); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -955); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -970); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -979); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -986); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -991); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -994); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -996); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -997); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -998); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -999); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -999); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -999); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, -100_000, -1_000); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -849); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -760); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -676); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -622); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -583); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -556); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -538); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -526); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -518); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -512); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -508); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -506); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -504); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -502); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -502); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -501); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -501); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -500); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -500); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -500); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 0, -500); + actualPower = this.setAndVerifyPower(constraint, ess, actualPower, 100_000, -500); + } + + private int setAndVerifyPower(ActivePowerConstraintWithPid constraint, DummyManagedSymmetricEss ess, + int currentActivePower, int targetActivePower, int expectedActivePower) throws OpenemsNamedException { + ess._setActivePower(currentActivePower); + ess.getActivePowerChannel().nextProcessImage(); + IntegerWriteChannel activePowerChannel = (IntegerWriteChannel) ess.getSetActivePowerEqualsChannel(); + constraint.accept(ess, targetActivePower); + int actualPower = activePowerChannel.getNextWriteValue().get().intValue(); + assertEquals(expectedActivePower, actualPower); + return actualPower; + } + +}