Skip to content

Commit a4abcec

Browse files
committed
Update microgrid documentation with new power manager behaviour
Signed-off-by: Sahas Subramanian <[email protected]>
1 parent 963b6c8 commit a4abcec

File tree

1 file changed

+120
-9
lines changed

1 file changed

+120
-9
lines changed

src/frequenz/sdk/microgrid/__init__.py

Lines changed: 120 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -174,17 +174,128 @@
174174
controlling batteries, power could be distributed based on the `SoC` of the
175175
individual batteries, to keep the batteries in balance.
176176
177-
### Resolving conflicting power proposals
177+
### How to work with other actors
178178
179-
When there are multiple actors trying to control the same set of batteries, a
180-
target power is calculated based on the priorities of the actors making the
181-
requests. Actors need to specify their priorities as parameters when creating
182-
the `*Pool` instances using the constructors mentioned above.
179+
If multiple actors are trying to control (by proposing power values) the same
180+
set of components, the power manager will aggregate their desired power values,
181+
while considering the priority of the actors and the bounds they set, to
182+
calculate the target power for the components.
183+
184+
The final target power can be accessed using the receiver returned from the
185+
[`power_status`][frequenz.sdk.timeseries.battery_pool.BatteryPool.power_status]
186+
method available for all pools, which also streams the bounds that an actor
187+
should comply with, based on its priority.
188+
189+
#### Adding the power proposals of individual actors
190+
191+
When an actor A calls the `propose_power` method with a power, the proposed
192+
power of the lower priority actor will get added to actor A's power. This works
193+
as follows:
194+
195+
- the lower priority actor would see bounds shifted by the power proposed by
196+
actor A.
197+
- After lower priority actor B sets a power in its shifted bounds, it will get
198+
shifted back by the power set by actor A.
199+
200+
This has the effect of adding the powers set by actors A and B.
201+
202+
*Example 1*: Battery bounds available for use: -100kW to 100kW
203+
204+
| Actor | Priority | System Bounds | Requested Bounds | Requested | Aggregate |
205+
| | | | | Power | Power |
206+
|-------|----------|-----------------|------------------|--------------|-----------|
207+
| A | 3 | -100kW .. 100kW | None | 20kW | 20kW |
208+
| B | 2 | -120kW .. 80kW | None | 50kW | 70kW |
209+
| C | 1 | -170kW .. 30kW | None | 50kW | 100kW |
210+
| | | | | target power | 100kW |
211+
212+
Actor A proposes a power of `20kW`, but no bounds. In this case, actor B sees
213+
bounds shifted by A's proposal. Actor B proposes a power of `50kW` on this
214+
shifted range, and if this is applied on to the original bounds (aka shift the
215+
bounds back to the original range), it would be `20kW + 50kW = 70kW`.
216+
217+
So Actor C sees bounds shifted by `70kW` from the original bounds, and sets
218+
`50kW` on this shifted range, but it can't exceed `30kW`, so its request gets
219+
limited to 30kW. Shifting this back by `70kW`, the target power is calculated
220+
to be `100kW`.
221+
222+
Irrespective of what any actor sets, the final power won't exceed the available
223+
battery bounds.
224+
225+
*Example 2*:
226+
227+
| Actor | Priority | System Bounds | Requested Bounds | Requested | Aggregate |
228+
| | | | | Power | Power |
229+
|-------|----------|-----------------|------------------|--------------|-----------|
230+
| A | 3 | -100kW .. 100kW | None | 20kW | 20kW |
231+
| B | 2 | -120kW .. 80kW | None | -20kW | 0kW |
232+
| | | | | target power | 0kW |
233+
234+
Actors with exactly opposite requests cancel each other out.
235+
236+
#### Limiting bounds for lower priority actors
237+
238+
When an actor A calls the `propose_power` method with bounds (either both lower
239+
and upper bounds or at least one of them), lower priority actors will see their
240+
(shifted) bounds restricted and can only propose power values within that range.
241+
242+
*Example 1*: Battery bounds available for use: -100kW to 100kW
243+
244+
| Actor | Priority | System Bounds | Requested Bounds | Requested | Aggregate |
245+
| | | | | Power | Power |
246+
|-------|----------|-----------------|------------------|--------------|-----------|
247+
| A | 3 | -100kW .. 100kW | -20kW .. 100kW | 50kW | 50kW |
248+
| B | 2 | -70kW .. 50kW | -90kW .. 0kW | -10kW | 40kW |
249+
| C | 1 | -60kW .. 10kW | None | -20kW | 20kW |
250+
| | | | | target power | 20kW |
251+
252+
Actor A with the highest priority has the entire battery bounds available to it.
253+
It sets limited bounds of -20kW .. 100kW, and proposes a power of 50kW.
254+
255+
Actor B sees Actor A's limit of -20kW..100kW shifted by 50kW as -70kW..50kW, and
256+
can only propose powers within this range, which will get added (shifted back)
257+
to Actor A's proposed power.
258+
259+
Actor B tries to limit the bounds of actor C to -90kW .. 0kW, but it can only
260+
operate in the -70kW .. 50kW range because of bounds set by actor A, so its
261+
requested bounds get restricted to -70kW .. 0kW.
262+
263+
Actor C sees this as -60kW .. 10kW, because it gets shifted by Actor B's
264+
proposed power of -10kW.
265+
266+
Actor C proposes a power within its bounds and the proposals of all the actors
267+
are added to get the target power.
268+
269+
*Example 2*:
270+
271+
| Actor | Priority | System Bounds | Requested Bounds | Requested | Aggregate |
272+
| | | | | Power | Power |
273+
|-------|----------|-----------------|------------------|--------------|-----------|
274+
| A | 3 | -100kW .. 100kW | -20kW .. 100kW | 50kW | 50kW |
275+
| B | 2 | -70kW .. 50kW | -90kW .. 0kW | -90kW | -70kW |
276+
| | | | | target power | -20kW |
277+
278+
When an actor requests a power that's outside its available bounds, the closest
279+
available power is used.
280+
281+
#### Comprehensive example
282+
283+
Battery bounds available for use: -100kW to 100kW
284+
285+
| Priority | System Bounds | Requested Bounds | Requested | Adjusted | Aggregate |
286+
| | | | Power | Power | Power |
287+
|----------|-------------------|------------------|-----------|--------------|-----------|
288+
| 7 | -100 kW .. 100 kW | None | 10 kW | 10 kW | 10 kW |
289+
| 6 | -110 kW .. 90 kW | -110 kW .. 80 kW | 10 kW | 10 kW | 20 kW |
290+
| 5 | -120 kW .. 70 kW | -100 kW .. 80 kW | 80 kW | 70 kW | 90 kW |
291+
| 4 | -170 kW .. 0 kW | None | -120 kW | -120 kW | -30 kW |
292+
| 3 | -50 kW .. 120 kW | None | 60 kW | 60 kW | 30 kW |
293+
| 2 | -110 kW .. 60 kW | -40 kW .. 30 kW | 20 kW | 20 kW | 50 kW |
294+
| 1 | -60 kW .. 10 kW | -50 kW .. 40 kW | 25 kW | 10 kW | 60 kW |
295+
| 0 | -60 kW .. 0 kW | None | 12 kW | 0 kW | 60 kW |
296+
| -1 | -60 kW .. 0 kW | -40 kW .. -10 kW | -10 kW | -10 kW | 50 kW |
297+
| | | | | Target Power | 50 kW |
183298
184-
The algorithm used for resolving power conflicts based on actor priority can be
185-
found in the documentation for any of the
186-
[`propose_power`][frequenz.sdk.timeseries.battery_pool.BatteryPool.propose_power]
187-
methods.
188299
""" # noqa: D205, D400
189300

190301
from datetime import timedelta

0 commit comments

Comments
 (0)