158 lines
5.2 KiB
Python
158 lines
5.2 KiB
Python
#!/usr/bin/env python3
|
|
import numpy as np
|
|
import csv
|
|
import itertools
|
|
import math
|
|
|
|
distancemeasure="max" #mse, max
|
|
|
|
|
|
column_label=0
|
|
column_capacity=3
|
|
column_resistance=4
|
|
|
|
|
|
config_parallel=2
|
|
config_cells=12
|
|
|
|
#config_parallel*config_cells*config_packs needed
|
|
batteriesneeded=config_parallel*config_cells
|
|
|
|
|
|
batteries=[]
|
|
batterylabels=[]
|
|
|
|
with open('12S_LiIon_Akkupack_selected.csv', 'r') as csvfile:
|
|
csvreader = csv.reader(csvfile, delimiter=';')
|
|
firstrow=True
|
|
for row in csvreader:
|
|
label=row[column_label]
|
|
capacity=row[column_capacity]
|
|
resistance=row[column_resistance]
|
|
if not firstrow:
|
|
capacity=float(capacity)
|
|
resistance=float(resistance)
|
|
|
|
batteries.append([label,capacity,resistance])
|
|
#batterylabels.append(label)
|
|
firstrow=False
|
|
|
|
print(str(len(batteries))+" Batteries found")
|
|
if len(batteries)==batteriesneeded:
|
|
print("You have enough batteries for "+str(config_cells)+"S"+str(config_parallel)+"P")
|
|
elif len(batteries)>batteriesneeded:
|
|
print("You have "+str(len(batteries)-batteriesneeded)+" batteries in spare")
|
|
elif len(batteries)<batteriesneeded:
|
|
print("You need "+str(batteriesneeded-len(batteries))+" more batteries!")
|
|
exit()
|
|
|
|
|
|
#calculate mean capacity of all cells
|
|
meancapacity=0
|
|
for i in batteries:
|
|
meancapacity+=i[1] #add capacities
|
|
meancapacity/=len(batteries)
|
|
print("Mean Capacity= "+str(meancapacity))
|
|
|
|
comb_parallel_all=[]
|
|
for comb_parallel in itertools.combinations(batteries,config_parallel):
|
|
comb_parallel_all.append(comb_parallel)
|
|
|
|
comb_parallel_all_meancapacities=[]
|
|
for current_parallel in comb_parallel_all:
|
|
#print(current_parallel)
|
|
meancapacity_parallel=0
|
|
for current_cell_from_parallel in current_parallel:
|
|
meancapacity_parallel+=current_cell_from_parallel[1] #add capacities
|
|
|
|
meancapacity_parallel/=len(current_parallel)
|
|
#print("Mean Capacity Parallel set="+str(meancapacity_parallel))
|
|
comb_parallel_all_meancapacities.append( meancapacity_parallel )
|
|
|
|
deviationFromMean = [abs(x - meancapacity) for x in comb_parallel_all_meancapacities]
|
|
assert len(comb_parallel_all)==len(deviationFromMean), "Menacapacity array lenght not matching"
|
|
|
|
sortedIndices=np.argsort(deviationFromMean)
|
|
|
|
|
|
bestSelection=[]
|
|
bestSelectionDistance=10000000000
|
|
|
|
def getDistanceFromSelection(selection):
|
|
if distancemeasure=="mse":
|
|
return getDistanceFromSelectionMSE(selection)
|
|
elif distancemeasure=="max":
|
|
return getDistanceFromSelectionMAX(selection)
|
|
|
|
def getDistanceFromSelectionMSE(selection): #Mean Squared Error
|
|
global deviationFromMean
|
|
distance=0
|
|
for i in selection:
|
|
distance+= math.pow(deviationFromMean[i],2)
|
|
distance/=len(selection)
|
|
return distance
|
|
|
|
def getDistanceFromSelectionMAX(selection): #Mean Squared Error
|
|
global deviationFromMean
|
|
_deviations=[deviationFromMean[x] for x in selection]
|
|
distance=max(_deviations)
|
|
return distance
|
|
|
|
def greedy(parallelCombinations,remainingSortedIndices,currentSelection):
|
|
global config_cells
|
|
global bestSelection
|
|
global bestSelectionDistance
|
|
global deviationFromMean
|
|
#print("greedy("+str(len(parallelCombinations))+","+str(len(remainingSortedIndices))+","+str(currentSelection)+")")
|
|
|
|
if len(remainingSortedIndices)<1 or len(currentSelection)>=config_cells : #nothing left
|
|
|
|
currentSelectionDistance=getDistanceFromSelection(currentSelection)
|
|
if currentSelectionDistance < bestSelectionDistance: #new best found
|
|
bestSelectionDistance=currentSelectionDistance
|
|
bestSelection=currentSelection
|
|
print("")
|
|
print("New best found "+str(currentSelection))
|
|
_print_deviationFromMean=[round(deviationFromMean[a],1) for a in currentSelection]
|
|
print("Dev. from mean "+str(_print_deviationFromMean))
|
|
print("Distance="+str(currentSelectionDistance))
|
|
for i in bestSelection:
|
|
print(str(comb_parallel_all[i])+" mc="+str(comb_parallel_all_meancapacities[i]))
|
|
|
|
|
|
return #backtrack
|
|
|
|
if len(currentSelection)>0 and getDistanceFromSelection(currentSelection)>bestSelectionDistance: #distance is already too high
|
|
return #backtrack early
|
|
|
|
for i in remainingSortedIndices: #try all in sorted order
|
|
newremainingSortedIndices=[x for x in remainingSortedIndices] #copy list, should be the same for every i
|
|
|
|
_selectedIndex=i #greedy take element i
|
|
|
|
|
|
#remove elements with one of the used batteries
|
|
for used in parallelCombinations[_selectedIndex]:
|
|
#print(used)
|
|
for rsi in newremainingSortedIndices: #check all remaining indices
|
|
containesBattery=False
|
|
for pcb in parallelCombinations[rsi]:
|
|
if pcb==used:
|
|
containesBattery=True
|
|
|
|
if containesBattery:
|
|
newremainingSortedIndices=[x for x in newremainingSortedIndices if x is not rsi] #remove current index rsi from remainingSortedIndices
|
|
|
|
#repeat until empty
|
|
greedy(parallelCombinations,newremainingSortedIndices,currentSelection+[_selectedIndex])
|
|
|
|
|
|
|
|
|
|
greedy(comb_parallel_all,sortedIndices, [])
|
|
print(bestSelection)
|
|
|
|
print("###")
|
|
for i in bestSelection:
|
|
print(str(comb_parallel_all[i])+" mc="+str(comb_parallel_all_meancapacities[i]))
|