|
174 | 174 | controlling batteries, power could be distributed based on the `SoC` of the |
175 | 175 | individual batteries, to keep the batteries in balance. |
176 | 176 |
|
177 | | -### Resolving conflicting power proposals |
| 177 | +### How to work with other actors |
178 | 178 |
|
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 consider the priority of the actors, |
| 181 | +the bounds they set, and their preferred power, when calculating the target |
| 182 | +power for the batteries. |
183 | 183 |
|
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. |
| 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 | +When designing actors to work with other actors, their interaction with other |
| 190 | +actors need to be planned. When sending proposals, actors can either: |
| 191 | +
|
| 192 | +- limit the available bounds for lower priority actors, or |
| 193 | +- shift the bounds available to lower priority actors by a specific value. |
| 194 | +
|
| 195 | +#### Limiting bounds for lower priority actors |
| 196 | +
|
| 197 | +When an actor A calls the `propose_power` method with bounds (either both lower |
| 198 | +and upper bounds or at least one of them), lower priority actors will see their |
| 199 | +bounds restricted and can only set power values within that range. If there are |
| 200 | +no lower priority actors or if none of them are proposing a power value, the |
| 201 | +target power set by actor A is used. |
| 202 | +
|
| 203 | +*Example 1*: Battery bounds available for use: -100kW to 100kW |
| 204 | +
|
| 205 | +| actor | priority | available bounds | request bounds | request power | |
| 206 | +|-------|----------|------------------|----------------|---------------| |
| 207 | +| A | 3 | -100kW .. 100kW | -20kW .. 100kW | 50kW | |
| 208 | +| B | 2 | -20kW .. 100kW | -50kW .. 0kW | -10kW | |
| 209 | +| C | 1 | -20kW .. 0kW | None | -20kW | |
| 210 | +| | | | target power | -20kW | |
| 211 | +
|
| 212 | +Actor A with the highest priority has the entire battery bounds available to it. |
| 213 | +It sets limited bounds of -20kW .. 100kW. Actor B can only set powers within |
| 214 | +this range, but actor B overrides the power set by actor A. |
| 215 | +
|
| 216 | +Actor B tries to limit the bounds of actor C to -50kW .. 0kW, but it can only |
| 217 | +operate in the -20kW .. 100kW range because of bounds set by actor A, so actor C |
| 218 | +sees -20kW .. 0kW. Actor C proposes a power, so it overrides the power proposed |
| 219 | +by actor B as well. Because there are no subsequent actors, the power set by |
| 220 | +actor C is used as the target power. |
| 221 | +
|
| 222 | +*Example 2*: |
| 223 | +
|
| 224 | +| actor | priority | available bounds | request bounds | request power | |
| 225 | +|-------|----------|------------------|----------------|---------------| |
| 226 | +| A | 3 | -100kW .. 100kW | -20kW .. 100kW | 50kW | |
| 227 | +| B | 2 | -20kW .. 100kW | -50kW .. 0kW | -10kW | |
| 228 | +| | | | target power | -10kW | |
| 229 | +
|
| 230 | +When there is no third actor, the second actor's power is the target power. |
| 231 | +
|
| 232 | +*Example 3*: |
| 233 | +
|
| 234 | +| actor | priority | available bounds | request bounds | request power | |
| 235 | +|-------|----------|------------------|----------------|---------------| |
| 236 | +| A | 3 | -100kW .. 100kW | -20kW .. 100kW | 50kW | |
| 237 | +| B | 2 | -20kW .. 100kW | -50kW .. 0kW | -50kW | |
| 238 | +| | | | target power | -20kW | |
| 239 | +
|
| 240 | +When an actor requests a power that's outside its available bounds, the closest |
| 241 | +available becomes the target power. |
| 242 | +
|
| 243 | +#### Adding the power proposals of individual actors |
| 244 | +
|
| 245 | +When an actor A calls the `propose_power` method with a power, but without any bounds (or |
| 246 | +passes None values for both lower and upper bounds), the proposed power of the lower |
| 247 | +priority actor will get added to actor A's power. This works as follows: the lower |
| 248 | +priority actor would see bounds shifted by the power proposed by actor A. After lower |
| 249 | +priority actor B sets a power, it will get shifted back by the power set by actor A. |
| 250 | +This has the effect of adding the powers set by actors A and B. |
| 251 | +
|
| 252 | +*Example 1*: Battery bounds available for use: -100kW to 100kW |
| 253 | +
|
| 254 | +| actor | priority | available bounds | request bounds | request power | cumulative power | |
| 255 | +|-------|----------|------------------|----------------|---------------|------------------| |
| 256 | +| A | 3 | -100kW .. 100kW | None | 20kW | | |
| 257 | +| B | 2 | -120kW .. 80kW | None | 50kW | 70kW | |
| 258 | +| C | 1 | -170kW .. 30kW | None | 50kW | 100kW | |
| 259 | +| | | | | target power | 100kW | |
| 260 | +
|
| 261 | +Actor A proposes a power of `20kW`, but no bounds. In this case, actor B sees |
| 262 | +bounds shifted by A's proposal. Actor B proposes a power of `50kW` on this |
| 263 | +shifted range, and if this is applied on to the original bounds (aka shift the |
| 264 | +bounds back to the original range), it would be `20kW + 50kW = 70kW`. |
| 265 | +
|
| 266 | +So Actor C sees bounds shifted by `70kW` from the original bounds, and sets |
| 267 | +`50kW` on this shifted range, but it can't exceed `30kW`, so its request gets |
| 268 | +limited to 30kW. Shifting this back by `70kW`, the target power is calculated |
| 269 | +to be `100kW`. |
| 270 | +
|
| 271 | +Irrespective of what any actor sets, the final power won't exceed the available |
| 272 | +battery bounds. |
| 273 | +
|
| 274 | +*Example 2*: |
| 275 | +
|
| 276 | +| actor | priority | available bounds | request bounds | request power | cumulative power | |
| 277 | +|-------|----------|------------------|----------------|---------------|------------------| |
| 278 | +| A | 3 | -100kW .. 100kW | None | 20kW | | |
| 279 | +| B | 2 | -120kW .. 80kW | None | -20kW | 0kW | |
| 280 | +| | | | | target power | 0kW | |
| 281 | +
|
| 282 | +Actors with exactly opposite requests cancel each other out. |
| 283 | +
|
| 284 | +
|
| 285 | +#### Comprehensive example |
| 286 | +
|
| 287 | +Battery bounds available for use: -100kW to 100kW |
| 288 | +
|
| 289 | +| pri | available bounds | req bounds | req power | s/l | power in range | cumulative power | |
| 290 | +|-----|------------------|----------------|-----------|--------|----------------|------------------| |
| 291 | +| 7 | -100kW .. 100kW | None | 10kW | shifts | 10kW | 10kW | |
| 292 | +| 6 | -110kW .. 90kW | -110kW .. 80kW | 10kW | limits | | | |
| 293 | +| 5 | -110kW .. 80kW | -100kW .. 80kW | 80kW | limits | | | |
| 294 | +| 4 | -100kW .. 80kW | None | -120kW | shifts | -100kW | -90kW | |
| 295 | +| 3 | 0kW .. 180kW | None | 60kW | shifts | 60kW | -30kW | |
| 296 | +| 2 | -60kW .. 120kW | -40kW .. 30kW | 20kW | limits | | | |
| 297 | +| 1 | -40kW .. 30kW | None | 12kW | shifts | 12kW | -18kW | |
| 298 | +| 0 | -52kW .. 18kW | -40kW .. -10kW | -10kW | limits | -10kW | -28kW | |
| 299 | +| | | | | | target power | -28kW | |
| 300 | +
|
| 301 | +In this example, there are some shifting and some limiting actors, and each of |
| 302 | +them affect the lower priority actors in the same patterns mentioned above. |
188 | 303 | """ # noqa: D205, D400 |
189 | 304 |
|
190 | 305 | from datetime import timedelta |
|
0 commit comments