From 07d0c2cf0bafbced704784b5950315acfa646928 Mon Sep 17 00:00:00 2001 From: Dival Banerjee Date: Thu, 13 Aug 2020 16:17:44 -0400 Subject: [PATCH 01/10] Created new files Created new files for each class --- main.py | 654 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/cell.py | 1 + src/main.py | 656 +-------------------------------------------------- src/motor.py | 1 + src/pack.py | 3 + 5 files changed, 663 insertions(+), 652 deletions(-) create mode 100644 main.py create mode 100644 src/cell.py create mode 100644 src/motor.py create mode 100644 src/pack.py diff --git a/main.py b/main.py new file mode 100644 index 0000000..adb27a7 --- /dev/null +++ b/main.py @@ -0,0 +1,654 @@ + +import math + +FLAGS_ENABLED = 1 #1 for warning messages, 0 to disable warnings +DISPLAY_OPTIMAL_ONLY = 0 # 1 for displaying optimal cell only + +#Vehicle inputs: +motorCount = 4 +#Replit test +#example +#Motor input: +motorName = 'U7 V2.0 - KV 420' +motorVoltage = 25 +motorMaxCurrent = 47.5 + +#Energy input: +#Format [power(Watts), duration(hours)],[power2(Watts), duration2(hours)] + +energyList = [[8650,.00833],[5970,.5], [7040, .5], [3830,.00833]] + +class cell(object): + + #new cell + cellName = 'empty' + intitialPotential = -1 + finalPotential = -1 + ratedPotential = -1 + capacity = -1 + maxDischarge = -1 + internalResistance = -1 + remainingCapacity = -1 + weight = -1 + usableCapacity = -1 + + def __init__(self,cellName,ratedVoltage,capacity,peakCurrent,startingVoltage,endingVoltage,resistance,weight): + self.cellName = cellName + self.ratedPotential = ratedVoltage + self.capacity = capacity + self.maxDischarge = peakCurrent + self.intitialPotential = startingVoltage + self.finalPotential = endingVoltage + self.internalResistance = resistance + self.weight = weight + self.remainingCapacity = capacity + + @classmethod + def basicCell(self, ratedVoltage, maxAmperage): + self.cellName = 'empty' + self.intitialPotential = -1 + self.finalPotential = -1 + self.ratedPotential = -1 + self.capacity = -1 + self.maxDischarge = -1 + self.internalResistance = -1 + self.remainingCapacity = -1 + self.weight = -1 + + @classmethod + def emptyCell(self): + self.cellName = 'empty' + self.intitialPotential = -1 + self.finalPotential = -1 + self.ratedPotential = -1 + self.capacity = -1 + self.maxDischarge = -1 + self.internalResistance = -1 + self.remainingCapacity = -1 + self.weight = -1 + return self + + def setCellName(self, name): + self.cellName = name + + def setInitialPotential(self, volts): + self.intitialPotential = volts + + def setFinalPotential(self, volts): + self.finalPotential = volts + + def setRatedPotential(self, volts): + self.ratedPotential = volts + + def setCapacity(self, ampHours): + self.capacity = ampHours + + def setMaxDischarge(self, amps): + self.maxDischarge = amps + + def setInternalResistance(self,ohms): + self.internalResistance = ohms + + def setWeight(self, grams): + self.weight = grams + + def getCellName(self): + return self.cellName + + def getWeight(self): + return self.weight + + def getInitialPotential(self): + return self.intitialPotential + + def getFinalPotential(self): + return self.finalPotential + + def getVoltage(self): + return self.ratedPotential + + def getMaxDischarge(self): + return self.maxDischarge + + def getCapacity(self): + return self.capacity + + def getInternalResistance(self): + return self.internalResistance + + def findEnergyDensity(self): + if(FLAGS_ENABLED == 1): + if(self.capacity <= 0): + print ('Warning -- Function findEnergyDensity() -- member of class cell -- Capacity must be greater than 0') + + energyDensity = self.capacity/self.weight + return energyDensity + + def findPowerThermalLoss(self,I): + power = (I^2)*self.internalResistance + return power + + def findPowerDensity(self): + #TODO: This will have to be done later, the discharge curve needs to be found with polynomial approximation + return 0 + + def findUsableCapacity(self): + self.usableCapacity = self.capacity - self.remainingCapacity + + def findUsableEnergyDensity(self): + #TODO: This will have to be done later, the discharge curve needs to be found with polynomial approximation + return 0 + + def toString(self): + return (self.cellName + ', ' + self.ratedPotential + ', ' + self.capacity) + + +class motor(object): + def __init__(self, name, motorType, current, voltage, torque, weight, RPM, iResistance): + #max continuous currenet, voltage, torque, weight, rpm, internal resistance, operating temp, % throttle + self.motorName = name + self.motorType = motorType + self.maxContinuousCurrent = current + self.voltage = voltage + self.torque = torque + self.motorWeight = weight + self.rpm = RPM + self.internalResistance = iResistance + self.operatingTemperature = 0 + self.percentThrottle = 0 + + @classmethod + def emptyMotor(self): + #Sets all values to negative 1 + self.motorName = 'empty' + self.motorType = -1 + self.maxContinuousCurrent = -1 + self.voltage = -1 + self.torque = -1 + self.motorWeight = -1 + self.rpm = -1 + self.internalResistance = -1 + self.operatingTemperature = -1 + self.percentThrottle = -1 + + + #set functions + def setMotorName(self, name): + self.motorName = name + + def setMotorType(self, motorType): + self.motorType = motorType + + def setMaxContinuousCurrent(self, current): + self.maxContinuousCurrent = current + + def setVoltage(self, voltage): + self.voltage = voltage + + def setTorque(self, torque): + self.torque = torque + + def setMotorWeight(self, weight): + self.motorWeight = weight + + def setRPM(self, RPM): + self.rpm = RPM + + def setInternalResistance(self, iResistance): + self.internalResistance = iResistance + + def setOperatingTemperature(self, temperature): + self.operatingTemperature = temperature + + def setPercentThrottle(self, percThrottle): + self.percentThrottle = percThrottle + + #corresponding get functions + def getMotorName(self): + return self.motorName + + def getMotorType(self): + return self.motorType + + def getMaxContinuousCurrent(self): + if(FLAGS_ENABLED ==1): + if(self.maxContinuousCurrent <= 0): + print('Error -- Function: getMaxContinuousCurrent() -- member of class cell -- maxContinuousCurrent must be greater than 0') + return self.maxContinuousCurrent + + def getVoltage(self): + return self.voltage + + def getTorque(self): + return self.torque + + def getMotorWeight(self): + return self.motorWeight + + def getRPM(self): + return self.rpm + + def getInternalResistance(self): + return self.internalResistance + + def getOperatingTemperature(self): + return self.operatingTemperature + + def getPercentThrottle(self): + return self.percentThrottle + + #TODO: write member functions to connect attributes + +class pack(object): + + cellsInParallel = 0 + cellsInSeries = 0 + energyRequired = 0 + packEnergyList = energyList + voltageRequired = 0 + powerRequired = 0 + additionalCapacity = 30 + totalCells = 0 + weightInKilograms = 0 + currentCell = cell('empty',-1,-1,-1,-1,-1,-1,200000) + #cell(name,ratedvoltage,capacity, peakContinousCurrent,startingVoltage,endingVoltage,resistance,weight) + cellList = [cell('Polymer Li-Ion 1055275',3.7,18000,42,3.7,2.7,.015,406.9), + cell('Polymer Lithium-ion 9759156-10C cell',3.7,10000,100,3.7,2.75,.005,210), + cell('LMP063767',3.8,3400,6.8,3.8,3,.018,29), + cell('SLPB065070180',3.7,12000,24,3.7,2.7,.00204,1750), + #cell('Licerion[experemental]',5,20000,60,5,4,.0018, 154), + cell('UHP341440 NCA', 3.6,7500,150,3.6,2.7,.00065,320), + #cell('553562-10C',3.7,1050,10,3.7,2.7,.04,18) + cell('Venom Industrial LCO 22Ah',3.7,22000,330,3.7,3,.0002,415), + cell('Venom Industrial LCO 16Ah',3.7,16000,240,3.7,3,.0002,300), + cell('Venom Industrial LC0 13 Ah',3.7,13000,195,3.7,3,.0002,248), + cell('Venom Industrial LCO 8 Ah', 3.7, 8000, 120, 3.7, 3, .0002, 167), + cell('Venom Industrial LCO 37 Ah', 3.65, 37000, 120, 3.7, 3, .0003, 863), + cell('SLPB98188216P', 3.7, 30000, 600, 3.7, 3, .0007, 780), + cell('SLPB60216216', 3.7, 25000, 200, 3.7, 3, .0012, 555), + cell('SLPB065070180', 3.7, 11600, 23.2, 3.7, 3, .0028, 175), + cell('SLC-202', 3.7, 1750, 3.5, 3.7, 3, .001, 29)] + #cell('553562-10C', 3.7, 1050, 10.5 ,3.7, 3, .001, 18), + #cell('703562-10C', 3.7, 1150, 14, 3.7, 3, .001, 28)] #Cell options Licerion cell is experemental + + #Default Constructor + def __init__(self): + self.cellsInParallel = 0 + self.cellsInSeries = 0 + self.energyRequired = 0 + self.voltageRequired = 0 + self.currentRequired = 0 + self.peakCurrentRequired= 0 + self.additionalCapacity = 30 + self.currentCell = cell.emptyCell() + + #Set energy spec + def setEnergyRequired(self, energy): + self.energyRequired = energy + + #Sets voltage spec + def setVoltageRequired(self, myVoltage): + self.voltageRequired = myVoltage + + #Sets power spec + def setPowerRequired(self,powerInKW): + self.powerRequired = powerInKW + + #Sets capacity margin + def setAdditionalCapacity(self, percentage): + self.additionalCapacity = percentage + + #Sets total cell count + def setTotalCells(self, cellCount): + self.totalCells = cellCount + + #Sets weight battery pack weight + def setWeightInKilograms(self, weight): + self.weightInKilograms = weight + + #Sets cell + def setCell(self, newCell): + self.currentCell = newCell + + def addCellToList(self, newCell): + self.cellList.append(newCell) + + def getEnergyRequired(self): + if(FLAGS_ENABLED == 1): + if(self.energyRequired <= 0): + print('Warning: Function getEnergyRequired() -- member of class pack -- enerrgyRequried should be greater than 0') + return self.energyRequired + + def getVoltageRequired(self): + if(FLAGS_ENABLED == 1): + if(self.voltageRequired <= 0): + print('Warning: Function getVoltageRequired() -- member of class pack -- voltageRequired should be greater than 0') + return self.voltageRequired + + def getPowerRequired(self): + if(FLAGS_ENABLED == 1): + if(self.getPowerRequired <= 0): + print('Warning: Function getPowerRequired() -- member of class pack -- power requried should be greater than 0') + return self.powerRequired + + def getAdditionalCapacity(self): + return self.additionalCapacity + + def getTotalCells (self): + if(FLAGS_ENABLED ==1): + if(self.totalCells <= 0): + print('Function: getTotalCells in pack - Warning: cell count is incorrect') + return self.totalCells + + def getWeight(self): + if(FLAGS_ENABLED == 1): + if(self.weightInKilograms <= 0): + print('Warning: -- Function getWeight() -- member of class pack -- weightInKilograms is less than or equal to 0') + + return self.weightInKilograms + + def getCell(self): + return self.currentCell + + def getCellsInSeries(self): + return self.cellsInSeries + + def getCellsInParallel(self): + + return self.cellsInParallel + + #Gets capacity in Ah + def getCapacity(self): + if(FLAGS_ENABLED == 1): + if(self.cellsInParallel <= 0): + print('Error -- Function: getCapacity() -- member of class pack -- cells in parallel should be greater than 0') + if(self.currentCell.getCapacity() <= 0): + print('Error -- Function: getCapacity() -- member of class pack -- cell capacity should be greagter than 0') + return ((self.cellsInParallel * self.currentCell.getCapacity())/1000) + + def powerRequiredFromCSV(self,path): + ''' + with open(path) as csvFile: + #csvReader = csv.reader(csvFile,delimiter = ';') + lineCount = 0 + #for row in csvReader: + #if lineCount == 0: + # lineCount += 1 + #else: + #in this file, power is stored in the first column, and duration in second column + # linecount += 1 + # self.powerRequired.append((row[0],row[1])) + # self.energyRequired = self.energyRequired + ((row[0]*row[1])/(self.voltageRequired*1000)) + + ''' + + def energyRequiredFromList(self, myList): + if(FLAGS_ENABLED == 1): + if(len(myList) == 0): + print('Error -- Function: energyRequiredFromList() -- member of class pack -- No elements in list') + + totalEnergy = 0 + for power in myList: + totalEnergy += (power[0]*power[1]) + self.energyRequired = totalEnergy + + #Rough estimate, shouldn't use + def findBasicPackConfig(self,cell): + if(FLAGS_ENABLED == 1): + if(self.voltageRequired <= 0 ): + print('Error -- Function: findBasicPackConfig() -- member of class pack -- Voltage required has to be greater than 0') + if(self.energyRequired <= 0): + print('Error -- Function: findBasicPackConfig() -- member of class pack -- Energy Required has to be greater than 0') + if(self.currentCell.getCapacity() <= 0): + print('Error -- Function: findBasicPackConfig() -- member of class pack -- Cell capacity must be greater than 0') + if(self.powerRequired <= 0): + print('Error: -- Function: findBasicPackConfig() -- member of class pack -- power Required must be greater than 0') + if(self.currentCell.getVoltage() <= 0): + print('Error: -- Function findBasicPackConfig() -- member of class pack -- current cell voltage should be greater than 0') + if(self.currentCell.getCapacity() <= 0): + print('Error -- Function findBasicPackConfig() -- member of class pack -- current cell capacity should be greater than 0') + if(self.currentCell.getMaxDischarge() <= 0): + print('Error -- Function findBasicPackConfig() -- member of class pack -- current cell max current dischange should be greater than 0') + + self.cellsInSeries = self.voltageRequired/self.currentCell.getVoltage() + self.cellsForCapacity = (self.energyRequired/((self.currentCell.getCapacity()-.7)))*1.3 + self.cellsForPower = self.powerRequired/self.currentCell.getMaxDischarge() + + #Gets cell info froma csv file + def loadCellInfo(self,path): + ''' + with open('cellList.txt') as csvFile: + #csvReader = csv.reader(csvFile, delimiter=';') + lineCount = 0 + for row in csvReader: + if lineCount == 0: + #First line + print ('Cell Portfolio') + lineCount += 1 + else: + #line 2 and after + #newCell = cell(row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],row[8]) + #self.cellList.append(newCell) + #print (newCell.toString()) + lineCount += 1 + ''' + + #Gets a count of cells needed in parallel for power + def findCellsForPower(self, myCell): + if(FLAGS_ENABLED == 1): + if(self.powerRequired <= 0): + print('Error -- Function findCellsForPower() -- member of class pack -- pack power required should be greater than 0') + if(myCell.getMaxDischarge() <= 0): + print('Error -- Function findCellsForPower() -- member of cell pack -- cell max current dischange should be greater than 0') + + maxFlightCurrent = 0 + bustCurrent = self.powerRequired + + for element in self.packEnergyList: + temp = element[0]/(self.cellsInSeries*self.currentCell.getVoltage()) + if(temp > maxFlightCurrent): + maxFlightCurrent = temp #safety factor + + return math.ceil((maxFlightCurrent/myCell.getMaxDischarge())) + #Gets the count of cells required for voltage + def findCellsForVoltage(self, myCell): + if(FLAGS_ENABLED == 1): + if(self.voltageRequired <= 0): + print('Error -- Function findCellsForVoltage() -- member of class pack -- pack voltage required must be greater than 0') + if(myCell.getVoltage() <= 0): + print('Error -- Function findCellsForVoltage() -- member of class pack -- cell voltage must be greater than 0') + + return math.ceil((self.voltageRequired/myCell.getVoltage())) + + def findCellsForCapacity(self,cell): + if(FLAGS_ENABLED == 1): + if(self.energyRequired <= 0): + print('Error -- Function findCellsForCapacity() -- member of class pack -- pack energy required must be greater than 0') + if(cell.getCapacity() <= 0): + print('Error -- Funciton findCellsForCapacity() -- member of class pack -- cell capacity must be greater than 0') + + return math.ceil((self.energyRequired/cell.getCapacity())) + + def findAdditionalCellsForCapacity(self, cell, capacity): + return math.ceil((capacity/cell.getCapacity())) + +#TODO: Consistancy issue, no return while findCellsInSeries() returns int + def findCellsInParallel(self, myCell): + if self.findCellsForPower(myCell) > self.findCellsForCapacity(myCell): + self.cellsInParallel = self.findCellsForPower(myCell) + else: + self.cellsInParallel = self.findCellsForCapacity(myCell) + + #finds total number of cells in a pack + def findTotalCells(self): + if(FLAGS_ENABLED == 1): + if(self.cellsInParallel <= 0): + print('Error -- Function findTotalCells() -- member of class pack -- cells in parallel must be greater than 0') + if(self.cellsInSeries <= 0): + print('pack -- cells in series must be greater than 0') + self.totalCells = self.cellsInParallel * self.cellsInSeries + + def findWeight(self): + if(FLAGS_ENABLED == 1): + if(self.totalCells <= 0): + print('Error -- Function findWeight() -- member of class pack -- total cells must be greater than 0') + if(self.currentCell.getWeight() <= 0): + print('Error -- Function findWeight() -- member of class pack -- cell must have weight greater than 0') + self.weightInKilograms = ((self.totalCells * self.currentCell.getWeight())/1000) + + def findThermalLosses(self): + cellResistance = 0 + parallelResistance = 0 + overallResistance = 0 + + if(FLAGS_ENABLED == 1): + if(self.currentCell.getInternalResistance() < 0): + print('Error -- Function findThermalLosses() -- member of class pack -- cell internal resistance unassigned') + else: + cellResistance = self.currentCell.getInternalResistance() + if(self.cellsInParallel <= 0): + print('Error -- Function findThermalLosses() -- member of class pack -- cells in parallel must be greater than 0') + else: + parallelResistance = 1/(self.cellsInParallel*(1/cellResistance)) + if(self.cellsInSeries <= 0): + print('Error -- Function findThermalLosses() -- member of class pack -- cells in series must be greater than 0') + + overallResistance = self.cellsInSeries * parallelResistance + + energyLost = 0 + for element in self.packEnergyList: + amps = element[0]/(self.cellsInSeries*self.currentCell.getVoltage()) + energyLost += ((amps**2)*overallResistance*element[1]) + return energyLost + + def findDimensions(self,myCell): + #this is where all calculations are done for each pack + self.cellsInSeries = self.findCellsForVoltage(myCell) + self.findCellsInParallel(myCell) + self.findTotalCells() + additionalCapacity = self.findThermalLosses() #TODO: Technically additional energy + additionalAmpHours = additionalCapacity/(self.currentCell.getVoltage()*self.cellsInSeries) + additionalCellsInParallel = self.findAdditionalCellsForCapacity(self.currentCell,additionalAmpHours) + self.cellsInParallel = self.cellsInParallel + additionalCellsInParallel + self.findTotalCells() + self.findWeight() + + def convertToBTU(self, wattHours): + return (wattHours*3.412) + + def printPack(self): + #print (f'Pack energy(KWh):') + print('') + print(f'Pack voltage(V): {(self.getCellsInSeries()*self.currentCell.getVoltage())}') + print (f'Pack max continuous current(A): {(self.getCellsInParallel()*self.currentCell.getMaxDischarge())}') + print (f'Cell name: {self.currentCell.getCellName()}') + print(f'Cells in series: {self.cellsInSeries}') + print(f'Cells in parallel: {self.cellsInParallel}') + print(f'Total cells: {self.getTotalCells()}') + print(f'Total capacity(Ah): {self.getCapacity()}') + print(f'Weight(Kg): {self.getWeight()}') + thermalLoss = self.findThermalLosses() + print(f'Thermal loss(Wh): {thermalLoss}') + print(f'Thermal loss(BTU): {self.convertToBTU(thermalLoss)}') + print ('_______________________________________________________________') + + def optimizePack(self): + #Optimize pack for weight + optimalCell = cell('empty',-1,-1,-1,-1,-1,-1,200000) + previousWeight = 200000 + self.setWeightInKilograms(0) + + for potentialCell in self.cellList: + self.currentCell = potentialCell + self.findDimensions(self.currentCell) + if self.getWeight() < previousWeight: + optimalCell = self.currentCell + previousWeight = self.getWeight() + if(DISPLAY_OPTIMAL_ONLY == 0): + print('New optimal pack!') + if(DISPLAY_OPTIMAL_ONLY == 0): + self.printPack() + self.currentCell = optimalCell + self.findDimensions(self.currentCell) + print('Optimal pack:') + self.printPack() + + def findFeasiblePacks(self): + #Needs to find cost + print('Function is incomplete') + + def sortCellsByCost(self): + print('Function is incomplete') + +class vehicle(object): + motorCount = -1 + #currentMotor = motor() + batteryPack = pack() + motorList = [] + structuralMass = 0 + payloadMass = 0 + totalWeight = 0 + totalThrust = 0 + + def __init__(self,motorCount,structuralMass, payloadMass): + self.motorCount = motorCount + self.structuralMass = structuralMass + self.payloadMass = payloadMass + + def setMotorCount(self, numberOfMotors): + self.motorCount = numberOfMotors + def setMotor(self,motor): + self.currentMotor = motor + + def setStructuralMass(self, mass): + self.structuralMass = mass + + def setPayloadMass(self, mass): + self.payloadMass = mass + + def setTotalWeight(self, mass): + self.totalWeight = mass + + def getMotorCount(self): + return self.motorCount + + def getMotor(self): + return self.currentMotor + + def getStructualMass(self): + return self.structuralMass + + def getPayloadMass(self): + return self.payloadMass + + def getTotalWeight(self): + return self.totalWeight + + def findTotalWeight(self): + + if(FLAGS_ENABLED == 1): + if(self.structuralMass <= 0): + print ('Warning: Invalid structural mass for vehicle') + if(self.payloadMass <= 0): + print ('Warning: Invalid payload mass for vehicle') + if(self.batteryPack.getWeight() <= 0): + print ('Warning: Battery pack weight is invalid') + + self.totalWeight = self.structuralMass + self.payloadMass + self.batteryPack.getWeight() + ''' + def openMotorList(self,path, motorList): + with open(path) as csvFile: + csvReader = csv.reader(csvFile, delimiter=';') + lineCount = 0 + for row in csvReader: + motorList.append(motor(row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],row[8],row[9])) + ''' + +#Main: +myPack = pack() +myPack.setVoltageRequired(motorVoltage) +myPack.setPowerRequired((motorCount*motorMaxCurrent)) +myPack.energyRequiredFromList(energyList) +print ('_______________________________________________________________') +myPack.optimizePack() + diff --git a/src/cell.py b/src/cell.py new file mode 100644 index 0000000..45edcdc --- /dev/null +++ b/src/cell.py @@ -0,0 +1 @@ +#file --cell.py-- diff --git a/src/main.py b/src/main.py index adb27a7..d17d127 100644 --- a/src/main.py +++ b/src/main.py @@ -1,654 +1,6 @@ +#file --main.py-- -import math - -FLAGS_ENABLED = 1 #1 for warning messages, 0 to disable warnings -DISPLAY_OPTIMAL_ONLY = 0 # 1 for displaying optimal cell only - -#Vehicle inputs: -motorCount = 4 -#Replit test -#example -#Motor input: -motorName = 'U7 V2.0 - KV 420' -motorVoltage = 25 -motorMaxCurrent = 47.5 - -#Energy input: -#Format [power(Watts), duration(hours)],[power2(Watts), duration2(hours)] - -energyList = [[8650,.00833],[5970,.5], [7040, .5], [3830,.00833]] - -class cell(object): - - #new cell - cellName = 'empty' - intitialPotential = -1 - finalPotential = -1 - ratedPotential = -1 - capacity = -1 - maxDischarge = -1 - internalResistance = -1 - remainingCapacity = -1 - weight = -1 - usableCapacity = -1 - - def __init__(self,cellName,ratedVoltage,capacity,peakCurrent,startingVoltage,endingVoltage,resistance,weight): - self.cellName = cellName - self.ratedPotential = ratedVoltage - self.capacity = capacity - self.maxDischarge = peakCurrent - self.intitialPotential = startingVoltage - self.finalPotential = endingVoltage - self.internalResistance = resistance - self.weight = weight - self.remainingCapacity = capacity - - @classmethod - def basicCell(self, ratedVoltage, maxAmperage): - self.cellName = 'empty' - self.intitialPotential = -1 - self.finalPotential = -1 - self.ratedPotential = -1 - self.capacity = -1 - self.maxDischarge = -1 - self.internalResistance = -1 - self.remainingCapacity = -1 - self.weight = -1 - - @classmethod - def emptyCell(self): - self.cellName = 'empty' - self.intitialPotential = -1 - self.finalPotential = -1 - self.ratedPotential = -1 - self.capacity = -1 - self.maxDischarge = -1 - self.internalResistance = -1 - self.remainingCapacity = -1 - self.weight = -1 - return self - - def setCellName(self, name): - self.cellName = name - - def setInitialPotential(self, volts): - self.intitialPotential = volts - - def setFinalPotential(self, volts): - self.finalPotential = volts - - def setRatedPotential(self, volts): - self.ratedPotential = volts - - def setCapacity(self, ampHours): - self.capacity = ampHours - - def setMaxDischarge(self, amps): - self.maxDischarge = amps - - def setInternalResistance(self,ohms): - self.internalResistance = ohms - - def setWeight(self, grams): - self.weight = grams - - def getCellName(self): - return self.cellName - - def getWeight(self): - return self.weight - - def getInitialPotential(self): - return self.intitialPotential - - def getFinalPotential(self): - return self.finalPotential - - def getVoltage(self): - return self.ratedPotential - - def getMaxDischarge(self): - return self.maxDischarge - - def getCapacity(self): - return self.capacity - - def getInternalResistance(self): - return self.internalResistance - - def findEnergyDensity(self): - if(FLAGS_ENABLED == 1): - if(self.capacity <= 0): - print ('Warning -- Function findEnergyDensity() -- member of class cell -- Capacity must be greater than 0') - - energyDensity = self.capacity/self.weight - return energyDensity - - def findPowerThermalLoss(self,I): - power = (I^2)*self.internalResistance - return power - - def findPowerDensity(self): - #TODO: This will have to be done later, the discharge curve needs to be found with polynomial approximation - return 0 - - def findUsableCapacity(self): - self.usableCapacity = self.capacity - self.remainingCapacity - - def findUsableEnergyDensity(self): - #TODO: This will have to be done later, the discharge curve needs to be found with polynomial approximation - return 0 - - def toString(self): - return (self.cellName + ', ' + self.ratedPotential + ', ' + self.capacity) - - -class motor(object): - def __init__(self, name, motorType, current, voltage, torque, weight, RPM, iResistance): - #max continuous currenet, voltage, torque, weight, rpm, internal resistance, operating temp, % throttle - self.motorName = name - self.motorType = motorType - self.maxContinuousCurrent = current - self.voltage = voltage - self.torque = torque - self.motorWeight = weight - self.rpm = RPM - self.internalResistance = iResistance - self.operatingTemperature = 0 - self.percentThrottle = 0 - - @classmethod - def emptyMotor(self): - #Sets all values to negative 1 - self.motorName = 'empty' - self.motorType = -1 - self.maxContinuousCurrent = -1 - self.voltage = -1 - self.torque = -1 - self.motorWeight = -1 - self.rpm = -1 - self.internalResistance = -1 - self.operatingTemperature = -1 - self.percentThrottle = -1 - - - #set functions - def setMotorName(self, name): - self.motorName = name - - def setMotorType(self, motorType): - self.motorType = motorType - - def setMaxContinuousCurrent(self, current): - self.maxContinuousCurrent = current - - def setVoltage(self, voltage): - self.voltage = voltage - - def setTorque(self, torque): - self.torque = torque - - def setMotorWeight(self, weight): - self.motorWeight = weight - - def setRPM(self, RPM): - self.rpm = RPM - - def setInternalResistance(self, iResistance): - self.internalResistance = iResistance - - def setOperatingTemperature(self, temperature): - self.operatingTemperature = temperature - - def setPercentThrottle(self, percThrottle): - self.percentThrottle = percThrottle - - #corresponding get functions - def getMotorName(self): - return self.motorName - - def getMotorType(self): - return self.motorType - - def getMaxContinuousCurrent(self): - if(FLAGS_ENABLED ==1): - if(self.maxContinuousCurrent <= 0): - print('Error -- Function: getMaxContinuousCurrent() -- member of class cell -- maxContinuousCurrent must be greater than 0') - return self.maxContinuousCurrent - - def getVoltage(self): - return self.voltage - - def getTorque(self): - return self.torque - - def getMotorWeight(self): - return self.motorWeight - - def getRPM(self): - return self.rpm - - def getInternalResistance(self): - return self.internalResistance - - def getOperatingTemperature(self): - return self.operatingTemperature - - def getPercentThrottle(self): - return self.percentThrottle - - #TODO: write member functions to connect attributes - -class pack(object): - - cellsInParallel = 0 - cellsInSeries = 0 - energyRequired = 0 - packEnergyList = energyList - voltageRequired = 0 - powerRequired = 0 - additionalCapacity = 30 - totalCells = 0 - weightInKilograms = 0 - currentCell = cell('empty',-1,-1,-1,-1,-1,-1,200000) - #cell(name,ratedvoltage,capacity, peakContinousCurrent,startingVoltage,endingVoltage,resistance,weight) - cellList = [cell('Polymer Li-Ion 1055275',3.7,18000,42,3.7,2.7,.015,406.9), - cell('Polymer Lithium-ion 9759156-10C cell',3.7,10000,100,3.7,2.75,.005,210), - cell('LMP063767',3.8,3400,6.8,3.8,3,.018,29), - cell('SLPB065070180',3.7,12000,24,3.7,2.7,.00204,1750), - #cell('Licerion[experemental]',5,20000,60,5,4,.0018, 154), - cell('UHP341440 NCA', 3.6,7500,150,3.6,2.7,.00065,320), - #cell('553562-10C',3.7,1050,10,3.7,2.7,.04,18) - cell('Venom Industrial LCO 22Ah',3.7,22000,330,3.7,3,.0002,415), - cell('Venom Industrial LCO 16Ah',3.7,16000,240,3.7,3,.0002,300), - cell('Venom Industrial LC0 13 Ah',3.7,13000,195,3.7,3,.0002,248), - cell('Venom Industrial LCO 8 Ah', 3.7, 8000, 120, 3.7, 3, .0002, 167), - cell('Venom Industrial LCO 37 Ah', 3.65, 37000, 120, 3.7, 3, .0003, 863), - cell('SLPB98188216P', 3.7, 30000, 600, 3.7, 3, .0007, 780), - cell('SLPB60216216', 3.7, 25000, 200, 3.7, 3, .0012, 555), - cell('SLPB065070180', 3.7, 11600, 23.2, 3.7, 3, .0028, 175), - cell('SLC-202', 3.7, 1750, 3.5, 3.7, 3, .001, 29)] - #cell('553562-10C', 3.7, 1050, 10.5 ,3.7, 3, .001, 18), - #cell('703562-10C', 3.7, 1150, 14, 3.7, 3, .001, 28)] #Cell options Licerion cell is experemental - - #Default Constructor - def __init__(self): - self.cellsInParallel = 0 - self.cellsInSeries = 0 - self.energyRequired = 0 - self.voltageRequired = 0 - self.currentRequired = 0 - self.peakCurrentRequired= 0 - self.additionalCapacity = 30 - self.currentCell = cell.emptyCell() - - #Set energy spec - def setEnergyRequired(self, energy): - self.energyRequired = energy - - #Sets voltage spec - def setVoltageRequired(self, myVoltage): - self.voltageRequired = myVoltage - - #Sets power spec - def setPowerRequired(self,powerInKW): - self.powerRequired = powerInKW - - #Sets capacity margin - def setAdditionalCapacity(self, percentage): - self.additionalCapacity = percentage - - #Sets total cell count - def setTotalCells(self, cellCount): - self.totalCells = cellCount - - #Sets weight battery pack weight - def setWeightInKilograms(self, weight): - self.weightInKilograms = weight - - #Sets cell - def setCell(self, newCell): - self.currentCell = newCell - - def addCellToList(self, newCell): - self.cellList.append(newCell) - - def getEnergyRequired(self): - if(FLAGS_ENABLED == 1): - if(self.energyRequired <= 0): - print('Warning: Function getEnergyRequired() -- member of class pack -- enerrgyRequried should be greater than 0') - return self.energyRequired - - def getVoltageRequired(self): - if(FLAGS_ENABLED == 1): - if(self.voltageRequired <= 0): - print('Warning: Function getVoltageRequired() -- member of class pack -- voltageRequired should be greater than 0') - return self.voltageRequired - - def getPowerRequired(self): - if(FLAGS_ENABLED == 1): - if(self.getPowerRequired <= 0): - print('Warning: Function getPowerRequired() -- member of class pack -- power requried should be greater than 0') - return self.powerRequired - - def getAdditionalCapacity(self): - return self.additionalCapacity - - def getTotalCells (self): - if(FLAGS_ENABLED ==1): - if(self.totalCells <= 0): - print('Function: getTotalCells in pack - Warning: cell count is incorrect') - return self.totalCells - - def getWeight(self): - if(FLAGS_ENABLED == 1): - if(self.weightInKilograms <= 0): - print('Warning: -- Function getWeight() -- member of class pack -- weightInKilograms is less than or equal to 0') - - return self.weightInKilograms - - def getCell(self): - return self.currentCell - - def getCellsInSeries(self): - return self.cellsInSeries - - def getCellsInParallel(self): - - return self.cellsInParallel - - #Gets capacity in Ah - def getCapacity(self): - if(FLAGS_ENABLED == 1): - if(self.cellsInParallel <= 0): - print('Error -- Function: getCapacity() -- member of class pack -- cells in parallel should be greater than 0') - if(self.currentCell.getCapacity() <= 0): - print('Error -- Function: getCapacity() -- member of class pack -- cell capacity should be greagter than 0') - return ((self.cellsInParallel * self.currentCell.getCapacity())/1000) - - def powerRequiredFromCSV(self,path): - ''' - with open(path) as csvFile: - #csvReader = csv.reader(csvFile,delimiter = ';') - lineCount = 0 - #for row in csvReader: - #if lineCount == 0: - # lineCount += 1 - #else: - #in this file, power is stored in the first column, and duration in second column - # linecount += 1 - # self.powerRequired.append((row[0],row[1])) - # self.energyRequired = self.energyRequired + ((row[0]*row[1])/(self.voltageRequired*1000)) - - ''' - - def energyRequiredFromList(self, myList): - if(FLAGS_ENABLED == 1): - if(len(myList) == 0): - print('Error -- Function: energyRequiredFromList() -- member of class pack -- No elements in list') - - totalEnergy = 0 - for power in myList: - totalEnergy += (power[0]*power[1]) - self.energyRequired = totalEnergy - - #Rough estimate, shouldn't use - def findBasicPackConfig(self,cell): - if(FLAGS_ENABLED == 1): - if(self.voltageRequired <= 0 ): - print('Error -- Function: findBasicPackConfig() -- member of class pack -- Voltage required has to be greater than 0') - if(self.energyRequired <= 0): - print('Error -- Function: findBasicPackConfig() -- member of class pack -- Energy Required has to be greater than 0') - if(self.currentCell.getCapacity() <= 0): - print('Error -- Function: findBasicPackConfig() -- member of class pack -- Cell capacity must be greater than 0') - if(self.powerRequired <= 0): - print('Error: -- Function: findBasicPackConfig() -- member of class pack -- power Required must be greater than 0') - if(self.currentCell.getVoltage() <= 0): - print('Error: -- Function findBasicPackConfig() -- member of class pack -- current cell voltage should be greater than 0') - if(self.currentCell.getCapacity() <= 0): - print('Error -- Function findBasicPackConfig() -- member of class pack -- current cell capacity should be greater than 0') - if(self.currentCell.getMaxDischarge() <= 0): - print('Error -- Function findBasicPackConfig() -- member of class pack -- current cell max current dischange should be greater than 0') - - self.cellsInSeries = self.voltageRequired/self.currentCell.getVoltage() - self.cellsForCapacity = (self.energyRequired/((self.currentCell.getCapacity()-.7)))*1.3 - self.cellsForPower = self.powerRequired/self.currentCell.getMaxDischarge() - - #Gets cell info froma csv file - def loadCellInfo(self,path): - ''' - with open('cellList.txt') as csvFile: - #csvReader = csv.reader(csvFile, delimiter=';') - lineCount = 0 - for row in csvReader: - if lineCount == 0: - #First line - print ('Cell Portfolio') - lineCount += 1 - else: - #line 2 and after - #newCell = cell(row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],row[8]) - #self.cellList.append(newCell) - #print (newCell.toString()) - lineCount += 1 - ''' - - #Gets a count of cells needed in parallel for power - def findCellsForPower(self, myCell): - if(FLAGS_ENABLED == 1): - if(self.powerRequired <= 0): - print('Error -- Function findCellsForPower() -- member of class pack -- pack power required should be greater than 0') - if(myCell.getMaxDischarge() <= 0): - print('Error -- Function findCellsForPower() -- member of cell pack -- cell max current dischange should be greater than 0') - - maxFlightCurrent = 0 - bustCurrent = self.powerRequired - - for element in self.packEnergyList: - temp = element[0]/(self.cellsInSeries*self.currentCell.getVoltage()) - if(temp > maxFlightCurrent): - maxFlightCurrent = temp #safety factor - - return math.ceil((maxFlightCurrent/myCell.getMaxDischarge())) - #Gets the count of cells required for voltage - def findCellsForVoltage(self, myCell): - if(FLAGS_ENABLED == 1): - if(self.voltageRequired <= 0): - print('Error -- Function findCellsForVoltage() -- member of class pack -- pack voltage required must be greater than 0') - if(myCell.getVoltage() <= 0): - print('Error -- Function findCellsForVoltage() -- member of class pack -- cell voltage must be greater than 0') - - return math.ceil((self.voltageRequired/myCell.getVoltage())) - - def findCellsForCapacity(self,cell): - if(FLAGS_ENABLED == 1): - if(self.energyRequired <= 0): - print('Error -- Function findCellsForCapacity() -- member of class pack -- pack energy required must be greater than 0') - if(cell.getCapacity() <= 0): - print('Error -- Funciton findCellsForCapacity() -- member of class pack -- cell capacity must be greater than 0') - - return math.ceil((self.energyRequired/cell.getCapacity())) - - def findAdditionalCellsForCapacity(self, cell, capacity): - return math.ceil((capacity/cell.getCapacity())) - -#TODO: Consistancy issue, no return while findCellsInSeries() returns int - def findCellsInParallel(self, myCell): - if self.findCellsForPower(myCell) > self.findCellsForCapacity(myCell): - self.cellsInParallel = self.findCellsForPower(myCell) - else: - self.cellsInParallel = self.findCellsForCapacity(myCell) - - #finds total number of cells in a pack - def findTotalCells(self): - if(FLAGS_ENABLED == 1): - if(self.cellsInParallel <= 0): - print('Error -- Function findTotalCells() -- member of class pack -- cells in parallel must be greater than 0') - if(self.cellsInSeries <= 0): - print('pack -- cells in series must be greater than 0') - self.totalCells = self.cellsInParallel * self.cellsInSeries - - def findWeight(self): - if(FLAGS_ENABLED == 1): - if(self.totalCells <= 0): - print('Error -- Function findWeight() -- member of class pack -- total cells must be greater than 0') - if(self.currentCell.getWeight() <= 0): - print('Error -- Function findWeight() -- member of class pack -- cell must have weight greater than 0') - self.weightInKilograms = ((self.totalCells * self.currentCell.getWeight())/1000) - - def findThermalLosses(self): - cellResistance = 0 - parallelResistance = 0 - overallResistance = 0 - - if(FLAGS_ENABLED == 1): - if(self.currentCell.getInternalResistance() < 0): - print('Error -- Function findThermalLosses() -- member of class pack -- cell internal resistance unassigned') - else: - cellResistance = self.currentCell.getInternalResistance() - if(self.cellsInParallel <= 0): - print('Error -- Function findThermalLosses() -- member of class pack -- cells in parallel must be greater than 0') - else: - parallelResistance = 1/(self.cellsInParallel*(1/cellResistance)) - if(self.cellsInSeries <= 0): - print('Error -- Function findThermalLosses() -- member of class pack -- cells in series must be greater than 0') - - overallResistance = self.cellsInSeries * parallelResistance - - energyLost = 0 - for element in self.packEnergyList: - amps = element[0]/(self.cellsInSeries*self.currentCell.getVoltage()) - energyLost += ((amps**2)*overallResistance*element[1]) - return energyLost - - def findDimensions(self,myCell): - #this is where all calculations are done for each pack - self.cellsInSeries = self.findCellsForVoltage(myCell) - self.findCellsInParallel(myCell) - self.findTotalCells() - additionalCapacity = self.findThermalLosses() #TODO: Technically additional energy - additionalAmpHours = additionalCapacity/(self.currentCell.getVoltage()*self.cellsInSeries) - additionalCellsInParallel = self.findAdditionalCellsForCapacity(self.currentCell,additionalAmpHours) - self.cellsInParallel = self.cellsInParallel + additionalCellsInParallel - self.findTotalCells() - self.findWeight() - - def convertToBTU(self, wattHours): - return (wattHours*3.412) - - def printPack(self): - #print (f'Pack energy(KWh):') - print('') - print(f'Pack voltage(V): {(self.getCellsInSeries()*self.currentCell.getVoltage())}') - print (f'Pack max continuous current(A): {(self.getCellsInParallel()*self.currentCell.getMaxDischarge())}') - print (f'Cell name: {self.currentCell.getCellName()}') - print(f'Cells in series: {self.cellsInSeries}') - print(f'Cells in parallel: {self.cellsInParallel}') - print(f'Total cells: {self.getTotalCells()}') - print(f'Total capacity(Ah): {self.getCapacity()}') - print(f'Weight(Kg): {self.getWeight()}') - thermalLoss = self.findThermalLosses() - print(f'Thermal loss(Wh): {thermalLoss}') - print(f'Thermal loss(BTU): {self.convertToBTU(thermalLoss)}') - print ('_______________________________________________________________') - - def optimizePack(self): - #Optimize pack for weight - optimalCell = cell('empty',-1,-1,-1,-1,-1,-1,200000) - previousWeight = 200000 - self.setWeightInKilograms(0) - - for potentialCell in self.cellList: - self.currentCell = potentialCell - self.findDimensions(self.currentCell) - if self.getWeight() < previousWeight: - optimalCell = self.currentCell - previousWeight = self.getWeight() - if(DISPLAY_OPTIMAL_ONLY == 0): - print('New optimal pack!') - if(DISPLAY_OPTIMAL_ONLY == 0): - self.printPack() - self.currentCell = optimalCell - self.findDimensions(self.currentCell) - print('Optimal pack:') - self.printPack() - - def findFeasiblePacks(self): - #Needs to find cost - print('Function is incomplete') - - def sortCellsByCost(self): - print('Function is incomplete') - -class vehicle(object): - motorCount = -1 - #currentMotor = motor() - batteryPack = pack() - motorList = [] - structuralMass = 0 - payloadMass = 0 - totalWeight = 0 - totalThrust = 0 - - def __init__(self,motorCount,structuralMass, payloadMass): - self.motorCount = motorCount - self.structuralMass = structuralMass - self.payloadMass = payloadMass - - def setMotorCount(self, numberOfMotors): - self.motorCount = numberOfMotors - def setMotor(self,motor): - self.currentMotor = motor - - def setStructuralMass(self, mass): - self.structuralMass = mass - - def setPayloadMass(self, mass): - self.payloadMass = mass - - def setTotalWeight(self, mass): - self.totalWeight = mass - - def getMotorCount(self): - return self.motorCount - - def getMotor(self): - return self.currentMotor - - def getStructualMass(self): - return self.structuralMass - - def getPayloadMass(self): - return self.payloadMass - - def getTotalWeight(self): - return self.totalWeight - - def findTotalWeight(self): - - if(FLAGS_ENABLED == 1): - if(self.structuralMass <= 0): - print ('Warning: Invalid structural mass for vehicle') - if(self.payloadMass <= 0): - print ('Warning: Invalid payload mass for vehicle') - if(self.batteryPack.getWeight() <= 0): - print ('Warning: Battery pack weight is invalid') - - self.totalWeight = self.structuralMass + self.payloadMass + self.batteryPack.getWeight() - ''' - def openMotorList(self,path, motorList): - with open(path) as csvFile: - csvReader = csv.reader(csvFile, delimiter=';') - lineCount = 0 - for row in csvReader: - motorList.append(motor(row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],row[8],row[9])) - ''' - -#Main: -myPack = pack() -myPack.setVoltageRequired(motorVoltage) -myPack.setPowerRequired((motorCount*motorMaxCurrent)) -myPack.energyRequiredFromList(energyList) -print ('_______________________________________________________________') -myPack.optimizePack() +import src.cell +import src.motor +import src.pack diff --git a/src/motor.py b/src/motor.py new file mode 100644 index 0000000..a6c5576 --- /dev/null +++ b/src/motor.py @@ -0,0 +1 @@ +#file --motor.py-- \ No newline at end of file diff --git a/src/pack.py b/src/pack.py new file mode 100644 index 0000000..aa2346b --- /dev/null +++ b/src/pack.py @@ -0,0 +1,3 @@ +#file --pack.py-- + +import src.cell From ac4f28df9e1892232ac864c473a2151594d8b74e Mon Sep 17 00:00:00 2001 From: Dival Banerjee Date: Thu, 13 Aug 2020 17:41:22 -0400 Subject: [PATCH 02/10] Created variables for cell class created variables for cell class --- src/cell.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/cell.py b/src/cell.py index 45edcdc..2f01e71 100644 --- a/src/cell.py +++ b/src/cell.py @@ -1 +1,12 @@ #file --cell.py-- + +class cell(object): + name = "empty" + initialVoltage = -1 + finalVoltage = -1 + ratedVoltage = -1 + capacity = -1 + maxContinousDischarge = -1 + internalResistance = -1 + remainingCapacity = -1 #TODO: Rename this + usableCapacity = -1 \ No newline at end of file From 179975b46cbbed6589d294de7d03cd3306374bdc Mon Sep 17 00:00:00 2001 From: Dival Banerjee Date: Thu, 13 Aug 2020 17:41:40 -0400 Subject: [PATCH 03/10] Added parameters for main added parameters for main --- src/main.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main.py b/src/main.py index d17d127..9a5c89e 100644 --- a/src/main.py +++ b/src/main.py @@ -4,3 +4,14 @@ import src.motor import src.pack +#Vehicle inputs: +motorCount = 4 +#example +#Motor input: +motorName = 'U7 V2.0 - KV 420' +motorVoltage = 25 +motorMaxCurrent = 47.5 + +#Energy input: +#Format [power(Watts), duration(hours)],[power2(Watts), duration2(hours)] +powerInterval = [[8650,.00833],[5970,.5], [7040, .5], [3830,.00833]] \ No newline at end of file From 4977fbffb395a862bc18d5ca8e905d5f9206a72a Mon Sep 17 00:00:00 2001 From: Dival Banerjee Date: Thu, 13 Aug 2020 17:42:18 -0400 Subject: [PATCH 04/10] Created vehicle.py --- src/vehicle.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/vehicle.py diff --git a/src/vehicle.py b/src/vehicle.py new file mode 100644 index 0000000..fcd19fc --- /dev/null +++ b/src/vehicle.py @@ -0,0 +1 @@ +#file --vehicle.py-- \ No newline at end of file From 011f5f321097e3001ae741f6a2c5a1c5e11bf707 Mon Sep 17 00:00:00 2001 From: Dival Banerjee Date: Thu, 13 Aug 2020 18:52:51 -0400 Subject: [PATCH 05/10] Added variables for vehicle.py --- src/main.py | 1 + src/vehicle.py | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main.py b/src/main.py index 9a5c89e..2814805 100644 --- a/src/main.py +++ b/src/main.py @@ -3,6 +3,7 @@ import src.cell import src.motor import src.pack +import src.vehicle #Vehicle inputs: motorCount = 4 diff --git a/src/vehicle.py b/src/vehicle.py index fcd19fc..a8d2d7a 100644 --- a/src/vehicle.py +++ b/src/vehicle.py @@ -1 +1,14 @@ -#file --vehicle.py-- \ No newline at end of file +#file --vehicle.py-- + +import src.cell +import src.motor +import src.pack + +class vehicle(object): + motorCount = -1 + batteryPack = pack() + motorList = [] + structuralMass = 0 + payloadMass = 0 + totalWeight = 0 + totalThurst = 0 From 6ba064674a16e3a199bbd4480d4d3c024c823857 Mon Sep 17 00:00:00 2001 From: Dival Banerjee Date: Thu, 3 Sep 2020 04:20:21 -0400 Subject: [PATCH 06/10] Wrote cell.py --- src/cell.py | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/src/cell.py b/src/cell.py index 2f01e71..0409086 100644 --- a/src/cell.py +++ b/src/cell.py @@ -9,4 +9,114 @@ class cell(object): maxContinousDischarge = -1 internalResistance = -1 remainingCapacity = -1 #TODO: Rename this - usableCapacity = -1 \ No newline at end of file + usableCapacity = -1 + + def __init__(self,cellName,ratedVoltage,capacity,peakCurrent,startingVoltage,endingVoltage,resistance,weight): + self.cellName = cellName + self.ratedPotential = ratedVoltage + self.capacity = capacity + self.maxDischarge = peakCurrent + self.intitialPotential = startingVoltage + self.finalPotential = endingVoltage + self.internalResistance = resistance + self.weight = weight + self.remainingCapacity = capacity + + @classmethod + def basicCell(self, ratedVoltage, maxAmperage): + self.cellName = 'empty' + self.intitialPotential = -1 + self.finalPotential = -1 + self.ratedPotential = -1 + self.capacity = -1 + self.maxDischarge = -1 + self.internalResistance = -1 + self.remainingCapacity = -1 + self.weight = -1 + + @classmethod + def emptyCell(self): + self.cellName = 'empty' + self.intitialPotential = -1 + self.finalPotential = -1 + self.ratedPotential = -1 + self.capacity = -1 + self.maxDischarge = -1 + self.internalResistance = -1 + self.remainingCapacity = -1 + self.weight = -1 + return self + + def setCellName(self, name): + self.cellName = name + + def setInitialPotential(self, volts): + self.intitialPotential = volts + + def setFinalPotential(self, volts): + self.finalPotential = volts + + def setRatedPotential(self, volts): + self.ratedPotential = volts + + def setCapacity(self, ampHours): + self.capacity = ampHours + + def setMaxDischarge(self, amps): + self.maxDischarge = amps + + def setInternalResistance(self,ohms): + self.internalResistance = ohms + + def setWeight(self, grams): + self.weight = grams + + def getCellName(self): + return self.cellName + + def getWeight(self): + return self.weight + + def getInitialPotential(self): + return self.intitialPotential + + def getFinalPotential(self): + return self.finalPotential + + def getVoltage(self): + return self.ratedPotential + + def getMaxDischarge(self): + return self.maxDischarge + + def getCapacity(self): + return self.capacity + + def getInternalResistance(self): + return self.internalResistance + + def findEnergyDensity(self): + if(FLAGS_ENABLED == 1): + if(self.capacity <= 0): + print ('Warning -- Function findEnergyDensity() -- member of class cell -- Capacity must be greater than 0') + + energyDensity = self.capacity/self.weight + return energyDensity + + def findPowerThermalLoss(self,I): + power = (I^2)*self.internalResistance + return power + + def findPowerDensity(self): + #TODO: This will have to be done later, the discharge curve needs to be found with polynomial approximation + return 0 + + def findUsableCapacity(self): + self.usableCapacity = self.capacity - self.remainingCapacity + + def findUsableEnergyDensity(self): + #TODO: This will have to be done later, the discharge curve needs to be found with polynomial approximation + return 0 + + def toString(self): + return (self.cellName + ', ' + self.ratedPotential + ', ' + self.capacity) \ No newline at end of file From 22dd0bb6612bad05e5bc0707dd03247fd5d6352b Mon Sep 17 00:00:00 2001 From: Dival Banerjee Date: Thu, 3 Sep 2020 04:34:40 -0400 Subject: [PATCH 07/10] Moved motor.py to seperate file --- src/motor.py | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/src/motor.py b/src/motor.py index a6c5576..2444865 100644 --- a/src/motor.py +++ b/src/motor.py @@ -1 +1,97 @@ -#file --motor.py-- \ No newline at end of file +#file --motor.py-- + +class motor(object): + def __init__(self, name, motorType, current, voltage, torque, weight, RPM, iResistance): + #max continuous currenet, voltage, torque, weight, rpm, internal resistance, operating temp, % throttle + self.motorName = name + self.motorType = motorType + self.maxContinuousCurrent = current + self.voltage = voltage + self.torque = torque + self.motorWeight = weight + self.rpm = RPM + self.internalResistance = iResistance + self.operatingTemperature = 0 + self.percentThrottle = 0 + + @classmethod + def emptyMotor(self): + #Sets all values to negative 1 + self.motorName = 'empty' + self.motorType = -1 + self.maxContinuousCurrent = -1 + self.voltage = -1 + self.torque = -1 + self.motorWeight = -1 + self.rpm = -1 + self.internalResistance = -1 + self.operatingTemperature = -1 + self.percentThrottle = -1 + + + #set functions + def setMotorName(self, name): + self.motorName = name + + def setMotorType(self, motorType): + self.motorType = motorType + + def setMaxContinuousCurrent(self, current): + self.maxContinuousCurrent = current + + def setVoltage(self, voltage): + self.voltage = voltage + + def setTorque(self, torque): + self.torque = torque + + def setMotorWeight(self, weight): + self.motorWeight = weight + + def setRPM(self, RPM): + self.rpm = RPM + + def setInternalResistance(self, iResistance): + self.internalResistance = iResistance + + def setOperatingTemperature(self, temperature): + self.operatingTemperature = temperature + + def setPercentThrottle(self, percThrottle): + self.percentThrottle = percThrottle + + #corresponding get functions + def getMotorName(self): + return self.motorName + + def getMotorType(self): + return self.motorType + + def getMaxContinuousCurrent(self): + if(FLAGS_ENABLED ==1): + if(self.maxContinuousCurrent <= 0): + print('Error -- Function: getMaxContinuousCurrent() -- member of class cell -- maxContinuousCurrent must be greater than 0') + return self.maxContinuousCurrent + + def getVoltage(self): + return self.voltage + + def getTorque(self): + return self.torque + + def getMotorWeight(self): + return self.motorWeight + + def getRPM(self): + return self.rpm + + def getInternalResistance(self): + return self.internalResistance + + def getOperatingTemperature(self): + return self.operatingTemperature + + def getPercentThrottle(self): + return self.percentThrottle + + #TODO: write member functions to connect attribute \ No newline at end of file From b937586a8600ee7cb50fcf0b3378ba5f80e78a5f Mon Sep 17 00:00:00 2001 From: Dival Banerjee Date: Thu, 3 Sep 2020 04:35:06 -0400 Subject: [PATCH 08/10] Moved pack.py to seperate file --- src/pack.py | 341 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 341 insertions(+) diff --git a/src/pack.py b/src/pack.py index aa2346b..3fe00cc 100644 --- a/src/pack.py +++ b/src/pack.py @@ -1,3 +1,344 @@ #file --pack.py-- import src.cell + +class pack(object): + + cellsInParallel = 0 + cellsInSeries = 0 + energyRequired = 0 + packEnergyList = energyList + voltageRequired = 0 + powerRequired = 0 + additionalCapacity = 30 + totalCells = 0 + weightInKilograms = 0 + currentCell = cell('empty',-1,-1,-1,-1,-1,-1,200000) + #cell(name,ratedvoltage,capacity, peakContinousCurrent,startingVoltage,endingVoltage,resistance,weight) + cellList = [cell('Polymer Li-Ion 1055275',3.7,18000,42,3.7,2.7,.015,406.9), + cell('Polymer Lithium-ion 9759156-10C cell',3.7,10000,100,3.7,2.75,.005,210), + cell('LMP063767',3.8,3400,6.8,3.8,3,.018,29), + cell('SLPB065070180',3.7,12000,24,3.7,2.7,.00204,1750), + #cell('Licerion[experemental]',5,20000,60,5,4,.0018, 154), + cell('UHP341440 NCA', 3.6,7500,150,3.6,2.7,.00065,320), + #cell('553562-10C',3.7,1050,10,3.7,2.7,.04,18) + cell('Venom Industrial LCO 22Ah',3.7,22000,330,3.7,3,.0002,415), + cell('Venom Industrial LCO 16Ah',3.7,16000,240,3.7,3,.0002,300), + cell('Venom Industrial LC0 13 Ah',3.7,13000,195,3.7,3,.0002,248), + cell('Venom Industrial LCO 8 Ah', 3.7, 8000, 120, 3.7, 3, .0002, 167), + cell('Venom Industrial LCO 37 Ah', 3.65, 37000, 120, 3.7, 3, .0003, 863), + cell('SLPB98188216P', 3.7, 30000, 600, 3.7, 3, .0007, 780), + cell('SLPB60216216', 3.7, 25000, 200, 3.7, 3, .0012, 555), + cell('SLPB065070180', 3.7, 11600, 23.2, 3.7, 3, .0028, 175), + cell('SLC-202', 3.7, 1750, 3.5, 3.7, 3, .001, 29)] + #cell('553562-10C', 3.7, 1050, 10.5 ,3.7, 3, .001, 18), + #cell('703562-10C', 3.7, 1150, 14, 3.7, 3, .001, 28)] #Cell options Licerion cell is experemental + + #Default Constructor + def __init__(self): + self.cellsInParallel = 0 + self.cellsInSeries = 0 + self.energyRequired = 0 + self.voltageRequired = 0 + self.currentRequired = 0 + self.peakCurrentRequired= 0 + self.additionalCapacity = 30 + self.currentCell = cell.emptyCell() + + #Set energy spec + def setEnergyRequired(self, energy): + self.energyRequired = energy + + #Sets voltage spec + def setVoltageRequired(self, myVoltage): + self.voltageRequired = myVoltage + + #Sets power spec + def setPowerRequired(self,powerInKW): + self.powerRequired = powerInKW + + #Sets capacity margin + def setAdditionalCapacity(self, percentage): + self.additionalCapacity = percentage + + #Sets total cell count + def setTotalCells(self, cellCount): + self.totalCells = cellCount + + #Sets weight battery pack weight + def setWeightInKilograms(self, weight): + self.weightInKilograms = weight + + #Sets cell + def setCell(self, newCell): + self.currentCell = newCell + + def addCellToList(self, newCell): + self.cellList.append(newCell) + + def getEnergyRequired(self): + if(FLAGS_ENABLED == 1): + if(self.energyRequired <= 0): + print('Warning: Function getEnergyRequired() -- member of class pack -- enerrgyRequried should be greater than 0') + return self.energyRequired + + def getVoltageRequired(self): + if(FLAGS_ENABLED == 1): + if(self.voltageRequired <= 0): + print('Warning: Function getVoltageRequired() -- member of class pack -- voltageRequired should be greater than 0') + return self.voltageRequired + + def getPowerRequired(self): + if(FLAGS_ENABLED == 1): + if(self.getPowerRequired <= 0): + print('Warning: Function getPowerRequired() -- member of class pack -- power requried should be greater than 0') + return self.powerRequired + + def getAdditionalCapacity(self): + return self.additionalCapacity + + def getTotalCells (self): + if(FLAGS_ENABLED ==1): + if(self.totalCells <= 0): + print('Function: getTotalCells in pack - Warning: cell count is incorrect') + return self.totalCells + + def getWeight(self): + if(FLAGS_ENABLED == 1): + if(self.weightInKilograms <= 0): + print('Warning: -- Function getWeight() -- member of class pack -- weightInKilograms is less than or equal to 0') + + return self.weightInKilograms + + def getCell(self): + return self.currentCell + + def getCellsInSeries(self): + return self.cellsInSeries + + def getCellsInParallel(self): + + return self.cellsInParallel + + #Gets capacity in Ah + def getCapacity(self): + if(FLAGS_ENABLED == 1): + if(self.cellsInParallel <= 0): + print('Error -- Function: getCapacity() -- member of class pack -- cells in parallel should be greater than 0') + if(self.currentCell.getCapacity() <= 0): + print('Error -- Function: getCapacity() -- member of class pack -- cell capacity should be greagter than 0') + return ((self.cellsInParallel * self.currentCell.getCapacity())/1000) + + def powerRequiredFromCSV(self,path): + ''' + with open(path) as csvFile: + #csvReader = csv.reader(csvFile,delimiter = ';') + lineCount = 0 + #for row in csvReader: + #if lineCount == 0: + # lineCount += 1 + #else: + #in this file, power is stored in the first column, and duration in second column + # linecount += 1 + # self.powerRequired.append((row[0],row[1])) + # self.energyRequired = self.energyRequired + ((row[0]*row[1])/(self.voltageRequired*1000)) + + ''' + + def energyRequiredFromList(self, myList): + if(FLAGS_ENABLED == 1): + if(len(myList) == 0): + print('Error -- Function: energyRequiredFromList() -- member of class pack -- No elements in list') + + totalEnergy = 0 + for power in myList: + totalEnergy += (power[0]*power[1]) + self.energyRequired = totalEnergy + + #Rough estimate, shouldn't use + def findBasicPackConfig(self,cell): + if(FLAGS_ENABLED == 1): + if(self.voltageRequired <= 0 ): + print('Error -- Function: findBasicPackConfig() -- member of class pack -- Voltage required has to be greater than 0') + if(self.energyRequired <= 0): + print('Error -- Function: findBasicPackConfig() -- member of class pack -- Energy Required has to be greater than 0') + if(self.currentCell.getCapacity() <= 0): + print('Error -- Function: findBasicPackConfig() -- member of class pack -- Cell capacity must be greater than 0') + if(self.powerRequired <= 0): + print('Error: -- Function: findBasicPackConfig() -- member of class pack -- power Required must be greater than 0') + if(self.currentCell.getVoltage() <= 0): + print('Error: -- Function findBasicPackConfig() -- member of class pack -- current cell voltage should be greater than 0') + if(self.currentCell.getCapacity() <= 0): + print('Error -- Function findBasicPackConfig() -- member of class pack -- current cell capacity should be greater than 0') + if(self.currentCell.getMaxDischarge() <= 0): + print('Error -- Function findBasicPackConfig() -- member of class pack -- current cell max current dischange should be greater than 0') + + self.cellsInSeries = self.voltageRequired/self.currentCell.getVoltage() + self.cellsForCapacity = (self.energyRequired/((self.currentCell.getCapacity()-.7)))*1.3 + self.cellsForPower = self.powerRequired/self.currentCell.getMaxDischarge() + + #Gets cell info froma csv file + def loadCellInfo(self,path): + ''' + with open('cellList.txt') as csvFile: + #csvReader = csv.reader(csvFile, delimiter=';') + lineCount = 0 + for row in csvReader: + if lineCount == 0: + #First line + print ('Cell Portfolio') + lineCount += 1 + else: + #line 2 and after + #newCell = cell(row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],row[8]) + #self.cellList.append(newCell) + #print (newCell.toString()) + lineCount += 1 + ''' + + #Gets a count of cells needed in parallel for power + def findCellsForPower(self, myCell): + if(FLAGS_ENABLED == 1): + if(self.powerRequired <= 0): + print('Error -- Function findCellsForPower() -- member of class pack -- pack power required should be greater than 0') + if(myCell.getMaxDischarge() <= 0): + print('Error -- Function findCellsForPower() -- member of cell pack -- cell max current dischange should be greater than 0') + + maxFlightCurrent = 0 + bustCurrent = self.powerRequired + + for element in self.packEnergyList: + temp = element[0]/(self.cellsInSeries*self.currentCell.getVoltage()) + if(temp > maxFlightCurrent): + maxFlightCurrent = temp #safety factor + + return math.ceil((maxFlightCurrent/myCell.getMaxDischarge())) + #Gets the count of cells required for voltage + def findCellsForVoltage(self, myCell): + if(FLAGS_ENABLED == 1): + if(self.voltageRequired <= 0): + print('Error -- Function findCellsForVoltage() -- member of class pack -- pack voltage required must be greater than 0') + if(myCell.getVoltage() <= 0): + print('Error -- Function findCellsForVoltage() -- member of class pack -- cell voltage must be greater than 0') + + return math.ceil((self.voltageRequired/myCell.getVoltage())) + + def findCellsForCapacity(self,cell): + if(FLAGS_ENABLED == 1): + if(self.energyRequired <= 0): + print('Error -- Function findCellsForCapacity() -- member of class pack -- pack energy required must be greater than 0') + if(cell.getCapacity() <= 0): + print('Error -- Funciton findCellsForCapacity() -- member of class pack -- cell capacity must be greater than 0') + + return math.ceil((self.energyRequired/cell.getCapacity())) + + def findAdditionalCellsForCapacity(self, cell, capacity): + return math.ceil((capacity/cell.getCapacity())) + +#TODO: Consistancy issue, no return while findCellsInSeries() returns int + def findCellsInParallel(self, myCell): + if self.findCellsForPower(myCell) > self.findCellsForCapacity(myCell): + self.cellsInParallel = self.findCellsForPower(myCell) + else: + self.cellsInParallel = self.findCellsForCapacity(myCell) + + #finds total number of cells in a pack + def findTotalCells(self): + if(FLAGS_ENABLED == 1): + if(self.cellsInParallel <= 0): + print('Error -- Function findTotalCells() -- member of class pack -- cells in parallel must be greater than 0') + if(self.cellsInSeries <= 0): + print('pack -- cells in series must be greater than 0') + self.totalCells = self.cellsInParallel * self.cellsInSeries + + def findWeight(self): + if(FLAGS_ENABLED == 1): + if(self.totalCells <= 0): + print('Error -- Function findWeight() -- member of class pack -- total cells must be greater than 0') + if(self.currentCell.getWeight() <= 0): + print('Error -- Function findWeight() -- member of class pack -- cell must have weight greater than 0') + self.weightInKilograms = ((self.totalCells * self.currentCell.getWeight())/1000) + + def findThermalLosses(self): + cellResistance = 0 + parallelResistance = 0 + overallResistance = 0 + + if(FLAGS_ENABLED == 1): + if(self.currentCell.getInternalResistance() < 0): + print('Error -- Function findThermalLosses() -- member of class pack -- cell internal resistance unassigned') + else: + cellResistance = self.currentCell.getInternalResistance() + if(self.cellsInParallel <= 0): + print('Error -- Function findThermalLosses() -- member of class pack -- cells in parallel must be greater than 0') + else: + parallelResistance = 1/(self.cellsInParallel*(1/cellResistance)) + if(self.cellsInSeries <= 0): + print('Error -- Function findThermalLosses() -- member of class pack -- cells in series must be greater than 0') + + overallResistance = self.cellsInSeries * parallelResistance + + energyLost = 0 + for element in self.packEnergyList: + amps = element[0]/(self.cellsInSeries*self.currentCell.getVoltage()) + energyLost += ((amps**2)*overallResistance*element[1]) + return energyLost + + def findDimensions(self,myCell): + #this is where all calculations are done for each pack + self.cellsInSeries = self.findCellsForVoltage(myCell) + self.findCellsInParallel(myCell) + self.findTotalCells() + additionalCapacity = self.findThermalLosses() #TODO: Technically additional energy + additionalAmpHours = additionalCapacity/(self.currentCell.getVoltage()*self.cellsInSeries) + additionalCellsInParallel = self.findAdditionalCellsForCapacity(self.currentCell,additionalAmpHours) + self.cellsInParallel = self.cellsInParallel + additionalCellsInParallel + self.findTotalCells() + self.findWeight() + + def convertToBTU(self, wattHours): + return (wattHours*3.412) + + def printPack(self): + #print (f'Pack energy(KWh):') + print('') + print(f'Pack voltage(V): {(self.getCellsInSeries()*self.currentCell.getVoltage())}') + print (f'Pack max continuous current(A): {(self.getCellsInParallel()*self.currentCell.getMaxDischarge())}') + print (f'Cell name: {self.currentCell.getCellName()}') + print(f'Cells in series: {self.cellsInSeries}') + print(f'Cells in parallel: {self.cellsInParallel}') + print(f'Total cells: {self.getTotalCells()}') + print(f'Total capacity(Ah): {self.getCapacity()}') + print(f'Weight(Kg): {self.getWeight()}') + thermalLoss = self.findThermalLosses() + print(f'Thermal loss(Wh): {thermalLoss}') + print(f'Thermal loss(BTU): {self.convertToBTU(thermalLoss)}') + print ('_______________________________________________________________') + + def optimizePack(self): + #Optimize pack for weight + optimalCell = cell('empty',-1,-1,-1,-1,-1,-1,200000) + previousWeight = 200000 + self.setWeightInKilograms(0) + + for potentialCell in self.cellList: + self.currentCell = potentialCell + self.findDimensions(self.currentCell) + if self.getWeight() < previousWeight: + optimalCell = self.currentCell + previousWeight = self.getWeight() + if(DISPLAY_OPTIMAL_ONLY == 0): + print('New optimal pack!') + if(DISPLAY_OPTIMAL_ONLY == 0): + self.printPack() + self.currentCell = optimalCell + self.findDimensions(self.currentCell) + print('Optimal pack:') + self.printPack() + + def findFeasiblePacks(self): + #Needs to find cost + print('Function is incomplete') + + def sortCellsByCost(self): + print('Function is incomplete') \ No newline at end of file From 07bf6e94715d906c375a14581ff4b4aa0c2b6556 Mon Sep 17 00:00:00 2001 From: Dival Banerjee Date: Thu, 3 Sep 2020 05:50:36 -0400 Subject: [PATCH 09/10] Created CellTable.Py --- src/CellTable.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/CellTable.py diff --git a/src/CellTable.py b/src/CellTable.py new file mode 100644 index 0000000..609711c --- /dev/null +++ b/src/CellTable.py @@ -0,0 +1 @@ +#file: --CellTable.py-- From c5cd29f5caf6b134ca79a31235a03aef7841a1ac Mon Sep 17 00:00:00 2001 From: Dival Banerjee Date: Thu, 8 Oct 2020 18:14:29 -0400 Subject: [PATCH 10/10] Added to init.py, doesn't need python path variable set --- src/__init__.py | 6 ++++++ src/main.py | 17 ++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/__init__.py b/src/__init__.py index e69de29..66805d8 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -0,0 +1,6 @@ +from .cell import * +from .CellTable import * +from .motor import * +from .pack import * +from .vehicle import * +from .main import * \ No newline at end of file diff --git a/src/main.py b/src/main.py index 2814805..875d06c 100644 --- a/src/main.py +++ b/src/main.py @@ -1,9 +1,9 @@ #file --main.py-- -import src.cell -import src.motor -import src.pack -import src.vehicle +from src.cell import cell +from src.motor import motor +from src.pack import pack +from src.vehicle import vehicle #Vehicle inputs: motorCount = 4 @@ -15,4 +15,11 @@ #Energy input: #Format [power(Watts), duration(hours)],[power2(Watts), duration2(hours)] -powerInterval = [[8650,.00833],[5970,.5], [7040, .5], [3830,.00833]] \ No newline at end of file +powerInterval = [[8650,.00833],[5970,.5], [7040, .5], [3830,.00833]] + +myPack = pack() +myPack.setVoltageRequired(motorVoltage) +myPack.setPowerRequried(motorCount*motorMaxCurrent) +myPack.energyRequiredFromList(powerInterval) +print('_______________________________________________________________') +myPack.optimizePack() \ No newline at end of file