Loading...
 

Battery Analyzer

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))