|
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 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 | 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 | 188 |
|
189 | | -### Shifting the target power by an Operating Point power |
| 189 | +#### Adding the power proposals of individual actors |
190 | 190 |
|
191 | | -There are cases where the target power needs to be shifted by an operating point. This |
192 | | -can be done by designating some actors to be able to set only the operating point power. |
| 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: |
193 | 194 |
|
194 | | -When creating a `*Pool` instance using the above-mentioned constructors, an optional |
195 | | -`set_operating_point` parameter can be passed to specify that this actor is special, and |
196 | | -the target power of the regular actors will be shifted by the target power of all actors |
197 | | -with `set_operating_point` together. |
| 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. |
198 | 199 |
|
199 | | -In a location with 2 regular actors and 1 `set_operating_point` actor, here's how things |
200 | | -would play out: |
| 200 | +This has the effect of adding the powers set by actors A and B. |
201 | 201 |
|
202 | | -1. When only regular actors have made proposals, the power bounds available from the |
203 | | - batteries are available to them exactly. |
| 202 | +*Example 1*: Battery bounds available for use: -100kW to 100kW |
204 | 203 |
|
205 | | - | actor priority | in op group? | proposed power/bounds | available bounds | |
206 | | - |----------------|--------------|-----------------------|------------------| |
207 | | - | 3 | No | 1000, -4000..2500 | -3000..3000 | |
208 | | - | 2 | No | 2500 | -3000..2500 | |
209 | | - | 1 | Yes | None | -3000..3000 | |
| 204 | +| Actor | Priority | System Bounds | Requested Bounds | Requested | Adjusted | Aggregate | |
| 205 | +| | | | | Power | Power | Power | |
| 206 | +|-------|----------|-----------------|------------------|-----------|--------------|-----------| |
| 207 | +| A | 3 | -100kW .. 100kW | None | 20kW | 20kW | 20kW | |
| 208 | +| B | 2 | -120kW .. 80kW | None | 50kW | 50kW | 70kW | |
| 209 | +| C | 1 | -170kW .. 30kW | None | 50kW | 30kW | 100kW | |
| 210 | +| | | | | | target power | 100kW | |
210 | 211 |
|
211 | | - Power actually distributed to the batteries: 2500W |
| 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`. |
212 | 216 |
|
213 | | -2. When the `set_operating_point` actor has made proposals, the bounds available to the |
214 | | - regular actors gets shifted, and the final power that actually gets distributed to |
215 | | - the batteries is also shifted. |
| 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`. |
216 | 221 |
|
217 | | - | actor priority | in op group? | proposed power/bounds | available bounds | |
218 | | - |----------------|--------------|-----------------------|------------------| |
219 | | - | 3 | No | 1000, -4000..2500 | -2000..4000 | |
220 | | - | 2 | No | 2500 | -2000..2500 | |
221 | | - | 1 | Yes | -1000 | -3000..3000 | |
| 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 | Adjusted | Aggregate | |
| 228 | +| | | | | Power | Power | Power | |
| 229 | +|-------|----------|-----------------|------------------|-----------|--------------|-----------| |
| 230 | +| A | 3 | -100kW .. 100kW | None | 20kW | 20kW | 20kW | |
| 231 | +| B | 2 | -120kW .. 80kW | None | -20kW | -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 | Adjusted | Aggregate | |
| 245 | +| | | | | Power | Power | Power | |
| 246 | +|-------|----------|-----------------|------------------|-----------|--------------|-----------| |
| 247 | +| A | 3 | -100kW .. 100kW | -20kW .. 100kW | 50kW | 40kW | 50kW | |
| 248 | +| B | 2 | -70kW .. 50kW | -90kW .. 0kW | -10kW | -10kW | 40kW | |
| 249 | +| C | 1 | -60kW .. 10kW | None | -20kW | -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 | Adjusted | Aggregate | |
| 272 | +| | | | | Power | Power | Power | |
| 273 | +|-------|----------|-----------------|------------------|-----------|--------------|-----------| |
| 274 | +| A | 3 | -100kW .. 100kW | -20kW .. 100kW | 50kW | 50kW | 50kW | |
| 275 | +| B | 2 | -70kW .. 50kW | -90kW .. 0kW | -90kW | -70kW | -20kW | |
| 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 | |
222 | 298 |
|
223 | | - Power actually distributed to the batteries: 1500W |
224 | 299 | """ # noqa: D205, D400 |
225 | 300 |
|
226 | 301 | from datetime import timedelta |
|
0 commit comments