//  [python]
def rate_update():
	"""Add a new data point to the rate testing measurement (should be called regularly)."""
	global state, crate_index, rate_halfcycle_countdown
	elapsed_time = timeit.default_timer()-rate_starttime
	read_potential_current()
	rate_time_data.add_sample(elapsed_time)
	rate_potential_data.add_sample(potential)
	rate_current_data.add_sample(1e-3*current) # Convert mA to A
	if len(rate_time_data.samples) == 0 and len(rate_time_data.averagebuffer) > 0: # A new average was just calculated
		rate_outputfile_raw.write("%e\t%e\t%e\n"%(rate_time_data.averagebuffer[-1],rate_potential_data.averagebuffer[-1],rate_current_data.averagebuffer[-1])) # Write it out
	if (rate_halfcycle_countdown%2 == 0 and potential > rate_parameters['ubound']) or (rate_halfcycle_countdown%2 != 0 and potential < rate_parameters['lbound']): # A potential cut-off has been reached
		rate_halfcycle_countdown -= 1
		if rate_halfcycle_countdown == 1: # Last charge cycle for this C-rate, so calculate and plot the charge capacity
			charge = numpy.abs(scipy.integrate.trapz(rate_current_data.averagebuffer,rate_time_data.averagebuffer)/3600.) # Charge in Ah
			rate_chg_charges.append(charge)
			rate_plot_scatter_chg.setData(rate_parameters['crates'][0:crate_index+1], rate_chg_charges)
		elif rate_halfcycle_countdown == 0: # Last discharge cycle for this C-rate, so calculate and plot the discharge capacity, and go to the next C-rate
			charge = numpy.abs(scipy.integrate.trapz(rate_current_data.averagebuffer,rate_time_data.averagebuffer)/3600.) # Charge in Ah
			rate_dis_charges.append(charge)
			rate_plot_scatter_dis.setData(rate_parameters['crates'][0:crate_index+1], rate_dis_charges)
			rate_outputfile_capacities.write("%e\t%e\t%e\n"%(rate_parameters['crates'][crate_index],rate_chg_charges[-1],rate_dis_charges[-1]))
			if crate_index == len(rate_parameters['crates'])-1: # Last C-rate was measured
				rate_stop(interrupted=False)
				return
			else: # New C-rate
				crate_index += 1
				rate_halfcycle_countdown = 2*rate_parameters['numcycles'] # Set the amount of remaining half cycles for the new C-rate
				set_output(1, 0.) # Set zero current while range switching
				hardware_manual_control_range_dropdown.setCurrentIndex(current_range_from_current(rate_parameters['currents'][crate_index])) # Determine the proper current range for the new setpoint
				set_current_range() # Set new current range
				numsamples = max(1,int(36./rate_parameters['crates'][crate_index])) # Set an appropriate amount of samples to average for the new C-rate; results in approx. 1000 points per curve
				for data in [rate_time_data, rate_potential_data, rate_current_data]:
					data.number_of_samples_to_average = numsamples
		rate_current = rate_parameters['currents'][crate_index] if rate_halfcycle_countdown%2 == 0 else -rate_parameters['currents'][crate_index] # Apply positive current for odd half cycles (charge phase) and negative current for even half cycles (discharge phase)
		set_output(1, rate_current) # Set current to setpoint
		for data in [rate_time_data, rate_potential_data, rate_current_data]: # Clear average buffers to prepare them for the next cycle
			data.clear()
		rate_current_crate_entry.setText("%d"%rate_parameters['crates'][crate_index])