Step 1: Get yourself an HP 6632B power supply. These are 100W two-quadrant (charge + discharge) units.
Step 2: Connect to its GPIB or RS232 (untested) port.
Step 3: Download, configure, and run the attached software.
Use gnuplot if you want to see pretty plots of the logged battery behavior.
BatteryAnalyzer.py
import visa
import time
charge_voltage = 14.5
charge_current = 2.0
charge_current_stop = 0.1
discharge_voltage = 11.0
discharge_current = 2.0
discharge_current_stop = -0.5
poll_seconds = 10
rest_seconds = 300
iterations = 3
resurrect = 0
class HP6632B:
"""A class for controlling an HP 6632B power supply"""
def __init__(self, GPIB_address = 21):
resource_manager = visa.ResourceManager()
self.__instrument = resource_manager.open_resource('GPIB::{0}::INSTR'.format(GPIB_address))
self.set_output(False)
def set_output(self, on = False):
self.__instrument.write('OUTP {0}'.format('1' if on else '0'))
def set_current(self, amps = 0):
self.__instrument.write('CURR {0} MA'.format(amps * 1000))
def set_voltage(self, volts = 0):
self.__instrument.write('VOLT {0} MV'.format(volts * 1000))
def measure_current(self):
return float(self.__instrument.query('MEAS:CURR?'))
def measure_voltage(self):
return float(self.__instrument.query('MEAS:VOLT?'))
psu = HP6632B(21)
for iteration in range(0, iterations):
if resurrect:
log = open('charge-resurrection.csv', 'w', 0)
psu.set_current(charge_current)
psu.set_voltage(charge_voltage)
psu.set_output(True)
resurrected = 0
while True:
now = time.time()
current = psu.measure_current()
voltage = psu.measure_voltage()
print('Charge resurrection {0}: {1}V @ {2}A'.format(now, voltage, current))
log.write("{0},{1},{2}\n".format(now, voltage, current))
if current > charge_current_stop:
resurrected += 1
if current <= charge_current_stop and resurrected >= 10:
break
time.sleep(poll_seconds)
psu.set_output(False)
print('Charge complete. Resting for {0} seconds.'.format(rest_seconds))
log.close()
time.sleep(rest_seconds)
log = open('discharge-{0}.csv'.format(iteration), 'w', 0)
psu.set_current(discharge_current)
psu.set_voltage(discharge_voltage)
psu.set_output(True)
while True:
now = time.time()
current = psu.measure_current()
voltage = psu.measure_voltage()
print('Discharge #{0} {1}: {2}V @ {3}A'.format(iteration, now, voltage, current))
log.write("{0},{1},{2}\n".format(now, voltage, current))
if current >= discharge_current_stop:
break
time.sleep(poll_seconds)
psu.set_output(False)
print('Discharge complete. Resting for {0} seconds.'.format(rest_seconds))
log.close()
time.sleep(rest_seconds)
log = open('charge-{0}.csv'.format(iteration), 'w', 0)
psu.set_current(charge_current)
psu.set_voltage(charge_voltage)
psu.set_output(True)
while True:
now = time.time()
current = psu.measure_current()
voltage = psu.measure_voltage()
print('Charge #{0} {1}: {2}V @ {3}A'.format(iteration, now, voltage, current))
log.write("{0},{1},{2}\n".format(now, voltage, current))
if current <= charge_current_stop:
break
time.sleep(poll_seconds)
psu.set_output(False)
print('Charge complete. Resting for {0} seconds.'.format(rest_seconds))
log.close()
time.sleep(rest_seconds)
print('{0} iterations complete.'.format(iterations))