@@ -277,8 +277,11 @@ def _total_capacity(self, components: List[InvBatPair]) -> float:
277
277
return total_capacity
278
278
279
279
def _compute_battery_availability_ratio (
280
- self , components : List [InvBatPair ], available_soc : Dict [int , float ]
281
- ) -> Tuple [List [Tuple [InvBatPair , float ]], float ]:
280
+ self ,
281
+ components : List [InvBatPair ],
282
+ available_soc : Dict [int , float ],
283
+ excl_bounds : Dict [int , float ],
284
+ ) -> Tuple [List [Tuple [InvBatPair , float , float ]], float ]:
282
285
r"""Compute battery ratio and the total sum of all of them.
283
286
284
287
battery_availability_ratio = capacity_ratio[i] * available_soc[i]
@@ -291,6 +294,7 @@ def _compute_battery_availability_ratio(
291
294
available_soc: How much SoC remained to reach
292
295
* SoC upper bound - if need to distribute consumption power
293
296
* SoC lower bound - if need to distribute supply power
297
+ excl_bounds: Exclusion bounds for each inverter
294
298
295
299
Returns:
296
300
Tuple where first argument is battery availability ratio for each
@@ -299,30 +303,35 @@ def _compute_battery_availability_ratio(
299
303
of all battery ratios in the list.
300
304
"""
301
305
total_capacity = self ._total_capacity (components )
302
- battery_availability_ratio : List [Tuple [InvBatPair , float ]] = []
306
+ battery_availability_ratio : List [Tuple [InvBatPair , float , float ]] = []
303
307
total_battery_availability_ratio : float = 0.0
304
308
305
309
for pair in components :
306
- battery = pair [ 0 ]
310
+ battery , inverter = pair
307
311
capacity_ratio = battery .capacity / total_capacity
308
312
soc_factor = pow (
309
313
available_soc [battery .component_id ], self ._distributor_exponent
310
314
)
311
315
312
316
ratio = capacity_ratio * soc_factor
313
- battery_availability_ratio .append ((pair , ratio ))
317
+ battery_availability_ratio .append (
318
+ (pair , excl_bounds [inverter .component_id ], ratio )
319
+ )
314
320
total_battery_availability_ratio += ratio
315
321
316
- battery_availability_ratio .sort (key = lambda item : item [1 ], reverse = True )
322
+ battery_availability_ratio .sort (
323
+ key = lambda item : (item [1 ], item [2 ]), reverse = True
324
+ )
317
325
318
326
return battery_availability_ratio , total_battery_availability_ratio
319
327
320
- def _distribute_power (
328
+ def _distribute_power ( # pylint: disable=too-many-arguments
321
329
self ,
322
330
components : List [InvBatPair ],
323
331
power_w : float ,
324
332
available_soc : Dict [int , float ],
325
- upper_bounds : Dict [int , float ],
333
+ incl_bounds : Dict [int , float ],
334
+ excl_bounds : Dict [int , float ],
326
335
) -> DistributionResult :
327
336
# pylint: disable=too-many-locals
328
337
"""Distribute power between given components.
@@ -336,17 +345,18 @@ def _distribute_power(
336
345
available_soc: how much SoC remained to reach:
337
346
* SoC upper bound - if need to distribute consumption power
338
347
* SoC lower bound - if need to distribute supply power
339
- upper_bounds: Min between upper bound of each pair in the components list:
340
- * supply upper bound - if need to distribute consumption power
341
- * consumption lower bound - if need to distribute supply power
348
+ incl_bounds: Inclusion bounds for each inverter
349
+ excl_bounds: Exclusion bounds for each inverter
342
350
343
351
Returns:
344
352
Distribution result.
345
353
"""
346
354
(
347
355
battery_availability_ratio ,
348
356
sum_ratio ,
349
- ) = self ._compute_battery_availability_ratio (components , available_soc )
357
+ ) = self ._compute_battery_availability_ratio (
358
+ components , available_soc , excl_bounds
359
+ )
350
360
351
361
distribution : Dict [int , float ] = {}
352
362
@@ -359,7 +369,7 @@ def _distribute_power(
359
369
power_to_distribute : float = power_w
360
370
used_ratio : float = 0.0
361
371
ratio = sum_ratio
362
- for pair , battery_ratio in battery_availability_ratio :
372
+ for pair , excl_bound , battery_ratio in battery_availability_ratio :
363
373
inverter = pair [1 ]
364
374
# ratio = 0, means all remaining batteries reach max SoC lvl or have no
365
375
# capacity
@@ -375,10 +385,17 @@ def _distribute_power(
375
385
376
386
# If the power allocated for that inverter is out of bound,
377
387
# then we need to distribute more power over all remaining batteries.
378
- upper_bound = upper_bounds [inverter .component_id ]
379
- if distribution [inverter .component_id ] > upper_bound :
380
- distribution [inverter .component_id ] = upper_bound
381
- distributed_power += upper_bound
388
+ incl_bound = incl_bounds [inverter .component_id ]
389
+ if distribution [inverter .component_id ] > incl_bound :
390
+ distribution [inverter .component_id ] = incl_bound
391
+ distributed_power += incl_bound
392
+ # Distribute only the remaining power.
393
+ power_to_distribute = power_w - distributed_power
394
+ # Distribute between remaining batteries
395
+ ratio = sum_ratio - used_ratio
396
+ elif distribution [inverter .component_id ] < excl_bound :
397
+ distribution [inverter .component_id ] = excl_bound
398
+ distributed_power += excl_bound
382
399
# Distribute only the remaining power.
383
400
power_to_distribute = power_w - distributed_power
384
401
# Distribute between remaining batteries
@@ -487,19 +504,25 @@ def _distribute_consume_power(
487
504
0.0 , battery .soc_upper_bound - battery .soc
488
505
)
489
506
490
- bounds : Dict [int , float ] = {}
507
+ incl_bounds : Dict [int , float ] = {}
508
+ excl_bounds : Dict [int , float ] = {}
491
509
for battery , inverter in components :
492
510
# We can supply/consume with int only
493
- inverter_bound = inverter .active_power_inclusion_upper_bound
494
- battery_bound = battery .power_inclusion_upper_bound
495
- bounds [inverter .component_id ] = min (inverter_bound , battery_bound )
511
+ incl_bounds [inverter .component_id ] = min (
512
+ inverter .active_power_inclusion_upper_bound ,
513
+ battery .power_inclusion_upper_bound ,
514
+ )
515
+ excl_bounds [inverter .component_id ] = max (
516
+ inverter .active_power_exclusion_upper_bound ,
517
+ battery .power_exclusion_upper_bound ,
518
+ )
496
519
497
520
result : DistributionResult = self ._distribute_power (
498
- components , power_w , available_soc , bounds
521
+ components , power_w , available_soc , incl_bounds , excl_bounds
499
522
)
500
523
501
524
return self ._greedy_distribute_remaining_power (
502
- result .distribution , bounds , result .remaining_power
525
+ result .distribution , incl_bounds , result .remaining_power
503
526
)
504
527
505
528
def _distribute_supply_power (
@@ -525,19 +548,24 @@ def _distribute_supply_power(
525
548
0.0 , battery .soc - battery .soc_lower_bound
526
549
)
527
550
528
- bounds : Dict [int , float ] = {}
551
+ incl_bounds : Dict [int , float ] = {}
552
+ excl_bounds : Dict [int , float ] = {}
529
553
for battery , inverter in components :
530
- # We can consume with int only
531
- inverter_bound = inverter .active_power_inclusion_lower_bound
532
- battery_bound = battery .power_inclusion_lower_bound
533
- bounds [inverter .component_id ] = - 1 * max (inverter_bound , battery_bound )
554
+ incl_bounds [inverter .component_id ] = - 1 * max (
555
+ inverter .active_power_inclusion_lower_bound ,
556
+ battery .power_inclusion_lower_bound ,
557
+ )
558
+ excl_bounds [inverter .component_id ] = - 1 * min (
559
+ inverter .active_power_exclusion_lower_bound ,
560
+ battery .power_exclusion_lower_bound ,
561
+ )
534
562
535
563
result : DistributionResult = self ._distribute_power (
536
- components , - 1 * power_w , available_soc , bounds
564
+ components , - 1 * power_w , available_soc , incl_bounds , excl_bounds
537
565
)
538
566
539
567
result = self ._greedy_distribute_remaining_power (
540
- result .distribution , bounds , result .remaining_power
568
+ result .distribution , incl_bounds , result .remaining_power
541
569
)
542
570
543
571
for inverter_id in result .distribution .keys ():
0 commit comments