class tempProcedure(Procedure): sample_name = Parameter("Sample Name", default='undefined') save_dir = Parameter("Save Directory", default=r"\junk") stop_temp = FloatParameter("Target Temperature", units="C", default=20) ramp_time = IntegerParameter("Ramp Time", units="min", default=1) hold_time = IntegerParameter("Hold Time", units="min", default=1) DATA_COLUMNS = ["global_time", "temperature", "heating_time"] def startup(self): log.info("Stop, Ramp, Hold: %.1f, %d, %d" % (self.stop_temp, self.ramp_time, self.hold_time)) log.info("Connecting temperature controller") self.tempcontrol = ThorlabsTC200USB('COM3') self.tempcontrol.set_temp(self.tempcontrol.act_temp()) if self.tempcontrol.get_stat(): self.tempcontrol.toggleenable() self.tempcontrol.set_mode('cycle') self.tempcontrol.set_cycle_num(1) self.tempcontrol.set_stop_temp(self.stop_temp) self.tempcontrol.set_ramp_time(self.ramp_time) self.tempcontrol.set_hold_time(self.hold_time) self.tempcontrol.toggleenable() self.duration = (self.ramp_time + self.hold_time) * 60. def execute(self): num_progress = np.floor(self.duration / 0.05) start_time = time() end_time = start_time + self.duration progress_iterator = 0 while time() < end_time: self.emit("progress", int(100 * progress_iterator / num_progress)) progress_iterator += 1 log.info("Recording results") self.emit( 'results', { "global_time": time(), "heating_time": time() - start_time, "temperature": self.tempcontrol.act_temp() }) if self.should_stop(): log.warning("Caught stop flag in procedure.") break sleep(0.05) def shutdown(self): log.info("Finished with scan. Shutting down instruments.") if self.tempcontrol.get_stat(): self.tempcontrol.toggleenable() self.tempcontrol.adapter.connection.close( ) #close serial port to avoid port already open error
class tempProcedure(Procedure): sample_name = Parameter("Sample Name", default='undefined') save_dir = Parameter("Save Directory", default=r"\junk") stop_temperature = FloatParameter("Set Temperature", units="C", default=20) ramp_time = IntegerParameter("Ramp Time", units="min", default=1) hold_time = IntegerParameter("Hold Time", units="min", default=1) DATA_COLUMNS = ["global_time", "temperature", "heating_time"] def startup(self): self.duration = (self.ramp_time + self.hold_time) * 60. log.info(self.duration) log.info("Connecting temperature controller") self.tempcontrol = ThorlabsTC200USB('/dev/ttyUSB0') if self.tempcontrol.get_stat(): self.tempcontrol.toggleenable() self.tempcontrol.set_mode('cycle') self.tempcontrol.set_cycle_num(1) self.tempcontrol.set_stop_temp(self.stop_temperature) self.tempcontrol.set_ramp_time(self.ramp_time) self.tempcontrol.set_hold_time(self.hold_time) self.tempcontrol.toggleenable() #log.info('Heater enabled, heating to:%.1f in %d minutes and holding for %d minutes' % (self.stop_temperature, self.ramp_time, self.hold_time)) def execute(self): num_progress = np.floor(self.duration / 0.05) start_time = time.time() end_time = start_time + self.duration progress_iterator = 0 while time.time() < end_time: #self._update_parameters() self.emit("progress", int(100 * progress_iterator / num_progress)) progress_iterator += 1 log.info("Recording results") self.emit( 'results', { "global_time": time.time(), "temperature": self.tempcontrol.act_temp(), "heating_time": time.time() - start_time }) if self.should_stop(): log.warning("Caught stop flag in procedure.") break sleep(0.05) def shutdown(self): log.info("Finished with scan. Shutting down instruments.") if self.tempcontrol.get_stat(): self.tempcontrol.toggleenable()
class TestProcedure(Procedure): iterations = IntegerParameter('Loop Iterations', default=100) delay = FloatParameter('Delay Time', units='s', default=0.2) seed = Parameter('Random Seed', default='12345') DATA_COLUMNS = ['Iteration', 'Random Number'] def startup(self): log.info("Setting up random number generator") random.seed(self.seed) def execute(self): log.info("Starting to generate numbers") for i in range(self.iterations): data = {'Iteration': i, 'Random Number': random.random()} log.debug("Produced numbers: %s" % data) self.emit('results', data) self.emit('progress', 100 * i / self.iterations) sleep(self.delay) if self.should_stop(): log.warning("Catch stop command in procedure") break def shutdown(self): log.info("Finished")
class TestProcedure(Procedure): iterations = IntegerParameter('Loop Iterations', default=100) delay = FloatParameter('Delay Time', units='s', default=0.2) seed = Parameter('Random Seed', default='12345') iteration = Measurable('Iteration', default=0) random_number = Measurable('Random Number', random.random) offset = Measurable('Random Number + 1', default=0) def startup(self): log.info("Setting up random number generator") random.seed(self.seed) def measure(self): data = self.get_datapoint() data['Random Number + 1'] = data['Random Number'] + 1 log.debug("Produced numbers: %s" % data) self.emit('results', data) self.emit('progress', 100. * self.iteration.value / self.iterations) def execute(self): log.info("Starting to generate numbers") for self.iteration.value in range(self.iterations): self.measure() sleep(self.delay) if self.should_stop(): log.warning("Catch stop command in procedure") break def shutdown(self): log.info("Finished")
class RandomProcedure(Procedure): iterations = IntegerParameter('Loop Iterations') delay = FloatParameter('Delay Time', units='s', default=0.2) seed = Parameter('Random Seed', default='12345') DATA_COLUMNS = ['Iteration', 'Random Number'] def startup(self): log.info("Setting the seed of the random number generator") random.seed(self.seed) def execute(self): log.info("Starting the loop of %d iterations" % self.iterations) for i in range(self.iterations): data = { 'Iteration': i, 'Random Number': random.random() } self.emit('results', data) log.debug("Emitting results: %s" % data) sleep(self.delay) if self.should_stop(): log.warning("Caught the stop flag in the procedure") break
class tempControlProcedure(Procedure): """ Procedure for calibrating the voltage to field strength relationship on Daedalus. Assumes that the center calibration has already ran. """ # control parameters calib_name = Parameter("Calibration Name", default='') temp_start = FloatParameter("Temperature start", units="C", default=-30.) temp_stop = FloatParameter("Temperature stop", units="C", default=100.) temp_step = FloatParameter("Temperature step", units="C", default=0.1) #heating_time = FloatParameter("Heating time", units="s", default=60.) #queued_time = Parameter("Queued Time") DATA_COLUMNS = ["set_temp","act_temp","elapsed_time"] def startup(self): log.info("Connecting and configuring the instruments") self.heatcontrol = ThorlabsTC200USB('/dev/ttyUSB0') self.heatcontrol.toggleenable() def execute(self): start_time = time() temp_points = np.arange(self.temp_start, self.temp_stop, self.temp_step) if self.temp_stop not in temp_points: temp_points = np.append(temp_points, self.temp_stop) temp_points = np.concatenate((temp_points, temp_points[::-1])) num_progress = temp_points.size for progress_iterator, t in enumerate(temp_points): log.info("Setting temperature %f C"%t) self.heatcontrol.set_temp = t sleep(1) self.emit('progress', int(100*progress_iterator/num_progress)) self.emit('results', { "set_temp": self.heatcontrol.get_temp(), "act_temp": self.heatcontrol.act_temp(), "elapsed_time": time()-start_time }) if self.should_stop(): log.warning("Caught stop flag in procedure.") break def shutdown(self): log.info("Done with scan. Shutting down instruments") self.heatcontrol.toggleenable()
class RandomProcedure(Procedure): iterations = IntegerParameter('Loop Iterations', default=100) delay = FloatParameter('Delay Time', units='s', default=0.001) seed = Parameter('Random Seed', default='12345') DATA_COLUMNS = ['Iteration', 'Random Number'] def startup(self): random.seed(self.seed) def execute(self): for i in range(self.iterations): data = {'Iteration': i, 'Random Number': random.random()} self.emit('results', data) self.emit('progress', 100. * i / self.iterations) sleep(self.delay) if self.should_stop(): break
class SS9Procedure(Procedure): your_name = Parameter("Your Name", default='') field_strength = FloatParameter("Field Strength", units='T', default=0) delay = FloatParameter('Delay Time', units='s', default=20) T_max = IntegerParameter('Maximum Temp.', units='K', default=350) num_averages = IntegerParameter('Number of Averages', default=5) mm1_measurement = BooleanParameter('Voltage', default=True) mm1_range = FloatParameter('Range', units='SI', default=1) mm1_address = Parameter("MM1 Address", default='') mm2_measurement = BooleanParameter('Voltage', default=True) mm2_range = FloatParameter('Range', units='SI', default=1) mm2_address = Parameter("MM2 Address", default='') mm3_measurement = BooleanParameter('Voltage', default=True) mm3_range = FloatParameter('Range', units='SI', default=1) mm3_address = Parameter("MM3 Address", default='') mm4_measurement = BooleanParameter('Voltage', default=True) mm4_range = FloatParameter('Range', units='SI', default=1) mm4_address = Parameter("MM4 Adress", default='') DATA_COLUMNS = [ 'elapsed_time', 'T', 'T_err', 'MM1_reading', 'MM1_error', 'MM2_reading', 'MM2_error', 'MM3_reading', 'MM3_error', 'MM4_reading', 'MM4_error' ] def startup(self): log.info("Setting up Multimeters") self.mm1 = Keithley2000(self.mm1_address) self.mm2 = Keithley2000(self.mm2_address) self.mm3 = Keithley2000(self.mm3_address) self.mm4 = Keithley2000(self.mm4_address) if self.mm1_measurement: self.mm1.measure_voltage(self.mm1_range) else: self.mm1.measure_current(self.mm1_range) if self.mm2_measurement: self.mm2.measure_voltage(self.mm2_range) else: self.mm2.measure_current(self.mm2_range) if self.mm3_measurement: self.mm3.measure_voltage(self.mm3_range) else: self.mm3.measure_current(self.mm3_range) if self.mm4_measurement: self.mm4.measure_voltage(self.mm4_range) else: self.mm4.measure_current(self.mm4_range) log.info("Setting up Thermocouple") self.mm2.voltage_nplc = 1 # Integration constant to Medium self.mm3.voltage_nplc = 1 # Integration constant to Medium self.mm4.voltage_nplc = 1 # Integration constant to Medium sleep(2) def execute(self): log.info("Starting Measurement") #prev_T = read_T T_min = ul.t_in(0, 0, TempScale.KELVIN) T = [T_min] start_time = time.time() while np.mean(T) < self.T_max: log.info("Temperature is at %d, waiting for it to reach %d" % \ (np.mean(T), self.T_max)) sleep(self.delay) elapsed_time = time.time() - start_time T, M1, M2, M3, M4 = [], [], [], [], [] for i in range(self.num_averages): log.info("Doing average %d of %d" % (i, self.num_averages)) if self.mm1_measurement: M1.append(self.mm1.voltage) else: M1.append(self.mm1.current) if self.mm2_measurement: M2.append(self.mm2.voltage) else: M2.append(self.mm2.current) if self.mm3_measurement: M3.append(self.mm3.voltage) else: M3.append(self.mm3.current) if self.mm4_measurement: M4.append(self.mm4.voltage) else: M4.append(self.mm4.current) T.append(ul.t_in(0, 0, TempScale.KELVIN)) sleep(self.delay / (self.num_averages + 1)) prog = int(100 * np.abs( (np.mean(T) - T_min) / (self.T_max - T_min))) self.emit("progress", prog) data = { 'elapsed_time': elapsed_time, 'T': np.mean(T), 'T_err': np.std(T), 'MM1_reading': np.mean(M1), 'MM1_error': np.std(M1), 'MM2_reading': np.mean(M2), 'MM2_error': np.std(M2), 'MM3_reading': np.mean(M3), 'MM3_error': np.std(M3), 'MM4_reading': np.mean(M4), 'MM4_error': np.std(M4) } self.emit('results', data) if self.should_stop(): log.warning("Catch stop command in procedure") break else: continue def shutdown(self): log.info("Finished") log.info("Please shut off heater, magnet and other instruments")
class MagFieldProcedure(Procedure): #Magnetic Field calibration (input field, get current) pA = -6.78951587e-06 #Constant pB = 3.27549922e-03 #First order term def IfromB(self,B): if B < 0: return 0 elif B >= self.pA: return self.pA + (B)*self.pB + (B*B)*self.pC + (B*B*B)*self.pD #Calculating the current to produce a given H else: return 0.0 fileroot = Parameter('File Root',default='.') filename = Parameter('File Prepend',default='2ndHarm') field = FloatParameter('Applied Field', units='T', default=.1) lockinamp = FloatParameter('Lockin Amplitude', units='V', default = 1.0) lockinfreq = FloatParameter('Lockin Reference', units='Hz', default = 1337.7) start_angle = FloatParameter('Start Angle', units='degrees', default=0) stop_angle = FloatParameter('Stop Angle', units='degrees', default=270) angle_step = FloatParameter('Angle Step', units='degrees', default=1) delay = FloatParameter('Delay Time', units='ms', default=100) inverse_spacing = BooleanParameter('Inverse Spacing') field_start = FloatParameter('Start Field', units='T', default=.05) field_stop = FloatParameter('Stop Field', units='T', default=.3) field_steps = IntegerParameter('Field Steps', default=10) shutdown_after = BooleanParameter('Shutdown Field After?') DATA_COLUMNS = ['Angle (deg)','Current (A)', 'Magnetic Field (T)', '1X Voltage (V)', '1Y Voltage (V)', '2X Voltage (V)', '2Y Voltage (V)'] def inmotion(self,rotator): moving = -1 success = False while not success: try: moving=int(rotator.query('LOC?')) except pyvisa.VisaIOError: pass except ValueError: moving = 0 success = True else: success = True if moving > -1: moving = 0 else: moving = -1 sleep(0.1) return moving def homeangle(self, rotator): success = False while not success: try: rotator.write('HOME') except pyvisa.VisaIOError: pass else: success = True moving = -1 while moving ==-1: moving = self.inmotion(self.rotator) sleep(1) def setangle(self, rotator,angle): success = False while not success: try: rotator.write('GOTO %f' % angle) except pyvisa.VisaIOError: pass else: success = True def getangle(self, rotator): moving = -1 while moving == -1: moving = self.inmotion(rotator) sleep(0.1) success = False while not success: try: angle = float(rotator.query('LOC?')) except pyvisa.VisaIOError: pass except ValueError: pass else: success = True sleep(0.1) return angle def startup(self): log.info("Setting up instruments") self.source = Sorensen30035E(7) self.lockin1 = DSP7265(27) self.lockin2 = DSP7265(12) self.rm = pyvisa.ResourceManager() self.rotator = self.rm.open_resource('ASRL4::INSTR') sleep(2) self.rotator.clear() sleep(1) self.homeangle(self.rotator) def execute(self): #Defining the current values angles_up = np.arange(self.start_angle, self.stop_angle+self.angle_step, self.angle_step) steps_up = len(angles_up) ###Ramping up the magnet current to minimum current log.info("Ramping to field value.") self.current = self.IfromB(self.field) if self.current > 0 : self.source.ramp_to_current(self.current, self.current/1e-1) self.source.ramp_to_current(self.current) sleep(1) log.info('Setting Lockin Parameters') self.lockin1.voltage = self.lockinamp self.lockin1.frequency = self.lockinfreq log.info("Starting to sweep through angle.") for i, angle in enumerate(angles_up): log.debug("Setting angle: %g degrees" % angle) self.setangle(self.rotator,angle) true_angle = self.getangle(self.rotator) sleep(self.delay*1e-3) magfield = self.field lockinX1 = self.lockin1.x lockinY1 = self.lockin1.y lockinX2 = self.lockin2.x lockinY2 = self.lockin2.y data = { 'Angle (deg)' : true_angle, 'Current (A)': self.current, 'Magnetic Field (T)': magfield, '1X Voltage (V)': lockinX1, '1Y Voltage (V)': lockinY1, '2X Voltage (V)': lockinX1, '2Y Voltage (V)': lockinY1,, } self.emit('results', data) self.emit('progress', 100.*i/steps_up) if self.should_stop(): log.warning("Catch stop command in procedure") return def shutdown(self): log.info("Shutting down.") #Ramping down the magnetic field if self.shutdown_after: now = self.current self.source.ramp_to_current(0.0,now/1e-1) sleep(1) sleep(1) self.rotator.close() #Turning off the RF source #self.RFsource.power = -100 log.info("Finished")
class PulseIVCycle(ProcedureWithInstruments): """ Uses a Keithley 26XX device to perform the following measurement: 1. Pulse at voltage `pulse_voltage` for `pulse_duration` in ms 2. Perform `cycles` sweeps from `min_voltage` to `max_voltage` starting with a sweep from 0 to max and ending with a sweep from max to 0 """ # define measurement paramters here max_voltage = FloatParameter('Maximum Voltage', units='V', default=1) min_voltage = FloatParameter('Minimum Voltage', units='V', default=-1) compliance = FloatParameter('Compliance', units='A', default=0.1) cycles = IntegerParameter('No. of Cycles', default=1) voltage_step = FloatParameter('Voltage Step', units='V', default=0.1) stime = FloatParameter('Settling Time', units='s', default=0.5) # Add Comments as parameters to show up in measurement file operator = Parameter('Operator', default='JD') location = Parameter('Location', default='Mun') setup = Parameter('Setup', default='Probe Station') # define DATA_COLUMNS that are written to the file DATA_COLUMNS = ['Voltage (V)', 'Current (A)', 'Current Std (A)', 'Cycle'] def startup(self): # System startup: Build instances of all necessary device objects here log.info("Connecting and configuring the instrument") log.info("Instrument Adress" + instrument_adress) self.sourcemeter = Keithley2600(instrument_adress) self.sourcemeter.reset() self.sourcemeter.clear_buffer() self.sourcemeter.triad() self.sourcemeter.set_screentext( '$R PulseIVCycle $N$B Ready to measure') def execute(self): # Make Pulse # Make Sweep log.info("Starting sweep") steps = (self.max_voltage - self.min_voltage) / self.voltage_step self.sourcemeter.autosweep(0, self.max_voltage, self.stime, steps, 'lin', 'V') for i in cycles: if self.should_stop(): log.info("User aborted the procedure") break log.info(f"Performing sweep number {i}") self.soucemeter.autosweep(self.max_voltage, self.min_voltage, self.stime, steps, 'lin', 'V') # TODO:Wait for finished measurement?! self.soucemeter.autosweep(self.min_voltage, self.max_voltage, self.stime, steps, 'lin', 'V') # TODO:Wait for finished measurement?! else: self.sourcemeter.autosweep(self.max_voltage, 0, self.stime, steps, 'lin', 'V') # TODO:Wait for finished measurement?! data_array = self.sourcemeter.get_buffer_data() # print to console to check array print(data_array) # emit data for i in range(0, len(data_array) - 1): self.emit( 'results', { 'Voltage (V)': data_array[0][i], 'Current (A)': data_array[1][i], 'Voltage Std (V)': data_array[2][i] }) def shutdown(self): self.sourcemeter.shutdown()
class FakeProcedure(Procedure): str_param = Parameter("String Parameter") bool_param = BooleanParameter("Boolean Parameter") float_param = FloatParameter("Float Parameter")
class DepProcedure(Procedure): plate_current = FloatParameter('Plating Current', units='A', minimum=-1, maximum=1, default=0.000268055577) pulse = FloatParameter('Pulse length', units='s', maximum=1e8, default=0.1) delay = FloatParameter('Delay Time', units='s', maximum=1e8, default=5.9) repeats = IntegerParameter('Cycles', units=None, minimum=1, maximum=1e8, default=500) deltat = FloatParameter('Measurement Frequency', units='Hz', default=20) voltage_range = FloatParameter('Potential Range', units='V', default=10) directory = Parameter('Working Directory', default='C:/Data/') filename = Parameter('Filename', default=unique_filename(str(directory), prefix='Plate_')) DATA_COLUMNS = ['Current (A)', 'Potential (V)', 'Time (s)'] def startup(self): log.info("Setting up instruments") """ To use the Nanovoltmeter instead of the Sourcemeter to measure potential, uncomment the following section and change the corresponding section in execute routine to measure from meter instead of source """ # self.meter = Keithley2182("GPIB::7::INSTR") # self.meter.measure_voltage() # self.meter.voltage_range = self.voltage_range # self.meter.voltage_nplc = 1 # Integration constant to Medium self.source = Keithley2400("GPIB::24::INSTR") self.source.apply_current() self.source.measure_voltage() self.source.source_current_range = self.plate_current * 1.1 # Current range is 10% over target self.source.compliance_voltage = self.voltage_range self.source.enable_source() sleep(2) def execute(self): pulses = np.repeat(self.plate_current, (self.pulse) * 1 // (1 / self.deltat)) rest = np.repeat(0, (self.delay) * 1 // (1 / self.deltat)) currents = np.concatenate((pulses, rest)) currents = np.tile(currents, np.int(self.repeats)) # currents *= 1e-3 # to mA from A steps = len(currents) log.info("Starting Pulsed electrodeposition") for i, current in enumerate(currents): log.debug("Applying current: %g A" % current) self.source.source_current = current # Or use self.source.ramp_to_current(current, delay=0.1) sleep(1 / self.deltat) voltage = self.source.voltage time = i / self.deltat data = { 'Current (A)': current, 'Potential (V)': voltage, 'Time (s)': time } self.emit('results', data) self.emit('progress', 100. * i / steps) if self.should_stop(): log.warning("Catch stop command in procedure") break def shutdown(self): self.source.shutdown() self.source.beep(783.991, 0.1) sleep(0.125) self.source.beep(1046.50, 0.1) sleep(0.125) self.source.beep(1318.51, 0.1) sleep(0.125) self.source.beep(1567.98, 0.22) sleep(0.25) self.source.beep(1318.51, 0.1) sleep(0.125) self.source.beep(1567.98, 0.25) log.info("Finished")
class IVProcedure(Procedure): max_current = FloatParameter('Maximum Current', units='mA', default=10) min_current = FloatParameter('Minimum Current', units='mA', default=-10) current_step = FloatParameter('Current Step', units='mA', default=0.1) delay = FloatParameter('Delay Time', units='ms', default=20) voltage_range = FloatParameter('Voltage Range', units='V', default=10) directory = Parameter('Working Directory', default='C:/Data/') filename = Parameter('Filename', default=unique_filename(str(directory), prefix='IV')) DATA_COLUMNS = ['Current (A)', 'Voltage (V)', 'Resistance (Ohm)'] def startup(self): log.info("Setting up instruments") # self.meter = Keithley2182("GPIB::7::INSTR") # self.meter.measure_voltage() # self.meter.voltage_range = self.voltage_range # self.meter.voltage_nplc = 1 # Integration constant to Medium self.source = Keithley2400("GPIB::24::INSTR") self.source.apply_current() self.source.source_current_range = self.max_current*1e-3 # A self.source.complinance_voltage = self.voltage_range self.source.enable_source() sleep(2) def execute(self): currents_up = np.arange(self.min_current, self.max_current, self.current_step) currents_down = np.arange(self.max_current, self.min_current, -self.current_step) currents = np.concatenate((currents_up, currents_down)) # Include the reverse currents *= 1e-3 # to mA from A steps = len(currents) log.info("Starting to sweep through current") for i, current in enumerate(currents): log.debug("Measuring current: %g mA" % current) self.source.source_current = current # Or use self.source.ramp_to_current(current, delay=0.1) sleep(self.delay*1e-3) voltage = self.meter.voltage if abs(current) <= 1e-10: resistance = np.nan else: resistance = voltage/current data = { 'Current (A)': current, 'Voltage (V)': voltage, 'Resistance (Ohm)': resistance } self.emit('results', data) self.emit('progress', 100.*i/steps) if self.should_stop(): log.warning("Catch stop command in procedure") break def shutdown(self): self.source.shutdown() self.source.beep(783.991,0.1) sleep(0.125) self.source.beep(1046.50,0.1) sleep(0.125) self.source.beep(1318.51,0.1) sleep(0.125) self.source.beep(1567.98,0.22) sleep(0.25) self.source.beep(1318.51,0.1) sleep(0.125) self.source.beep(1567.98,0.25) log.info("Finished")
class TestProcedure(Procedure): iterations = IntegerParameter('Loop Iterations', default=100) delay = FloatParameter('Delay Time', units='s', default=0.2) seed = Parameter('Random Seed', default='12345') DATA_COLUMNS = ['Iteration', 'Random Number'] def startup(self): log.info("Setting up random number generator") random.seed(self.seed) def execute(self): log.info("Starting to generate numbers") for i in range(self.iterations): data = {'Iteration': i, 'Random Number': random.random()} log.debug("Produced numbers: %s" % data) self.emit('results', data) self.emit('progress', 100 * i / self.iterations) sleep(self.delay) if self.should_stop(): log.warning("Catch stop command in procedure") break def get_estimates(self, sequence_length=None, sequence=None): """ Function that returns estimates for the EstimatorWidget. If this function is implemented (and does not return a NotImplementedError) the widget is automatically activated. The function is expected to return an int or float, or a list of tuples. If an int or float is returned, it should represent the duration in seconds.If a list of tuples is returned, each tuple containing two strings, a label and the estimate itself: estimates = [ ("label 1", "estimate 1"), ("label 2", "estimate 2"), ] The length of the number of estimates is not limited but has to remain unchanged after initialisation. Note that also the label can be altered after initialisation. The keyword arguments `sequence_length` and `sequence` are optional and return (if asked for) the length of the current sequence (of the `SequencerWidget`) or the full sequence. """ duration = self.iterations * self.delay """ A simple implementation of the get_estimates function immediately returns the duration in seconds. """ # return duration estimates = list() estimates.append(("Duration", "%d s" % int(duration))) estimates.append(("Number of lines", "%d" % int(self.iterations))) estimates.append(("Sequence length", str(sequence_length))) estimates.append( ('Measurement finished at', str(datetime.now() + timedelta(seconds=duration))[:-7])) estimates.append( ('Sequence finished at', str(datetime.now() + timedelta(seconds=duration * sequence_length))[:-7])) return estimates def shutdown(self): log.info("Finished")
class IVCycles(ProcedureWithInstruments): #define required instruments required_instruments = ['Keithley Instruments Inc., Model 2635B'] # define measurement paramters here averages = IntegerParameter('Averages', default=50) measurement_delay = FloatParameter('Measurement Delay', default=0.5) max_voltage = FloatParameter('Maximum Voltage', units='V', default=0.5) min_voltage = IntegerParameter('Minimum Voltage', units='V', default=-1.0) compliance = FloatParameter('Compliance', units='A', default=0.1) cycles = IntegerParameter('No. of Cycles', default=1) voltage_step = FloatParameter('Voltage Step', units='V', default=0.1) # Add Comments as parameters to show up in measurement file operator = Parameter('Operator', default='JD') location = Parameter('Location', default='Mun') setup = Parameter('Setup', default='Probe Station') # Calculate the number of data points from range and step data_points = IntegerParameter( 'Data points', default=np.ceil( (max_voltage.value - min_voltage.value) / voltage_step.value)) # define DATA_COLUMNS that are written to the file DATA_COLUMNS = ['Voltage (V)', 'Current (A)'] def startup(self): print('startup') for adress, name in self.instruments_dict.items(): if 'Keithley Instruments Inc., Model 2635B' in name: self.instrument_adress = adress log.info("Connecting and configuring the instrument") log.info("Instrument Adress: " + self.instrument_adress) log.info("Instrument Dict: " + str(self.instruments_dict)) self.sourcemeter = Keithley2600(self.instrument_adress) self.sourcemeter.triad() self.sourcemeter.set_screentext( '$R PulseIVCycle $N$B Ready to measure') def execute(self): print('execute') # reset instrument and its dedicated buffer self.sourcemeter.reset() self.sourcemeter.clear_buffer() self.sourcemeter.setup_buffer(precision=6) log.info( f'start: {self.min_voltage}. stop {self.max_voltage}, stime {self.measurement_delay}. points = {self.data_points}' ) self.sourcemeter.set_output(state='ON') self.sourcemeter.auto_sweep(start=0, stop=self.max_voltage, stime=self.measurement_delay, points=np.ceil(self.data_points / 2 + 1), source='V') self.sourcemeter.wait_for_srq() results = self.sourcemeter.get_buffer_data() for i in range(0, len(results['sourced']) - 1): self.emit( 'results', { 'Voltage (V)': results['sourced'][i], 'Current (A)': results['measured'][i], }) def shutdown(self): self.sourcemeter.shutdown() log.info("Finished measuring") print('shutdown')
class DepProcedure(Procedure): capacity = FloatParameter('Capacity', units='mAh', minimum=0, maximum=10, default=4.29) c_rate = FloatParameter('Charge Rate', units='C', minimum=0.01, maximum=20, default=1) repeats = IntegerParameter('Cycles', units=None, minimum=1, maximum=1e8, default=50) deltat = FloatParameter('Measurement Frequency', units='Hz', default=1) voltage_range = FloatParameter('Potential Range', units='V', default=10) directory = Parameter('Working Directory', default='C:/Data/') filename = Parameter('Filename', default=unique_filename(str(directory), prefix='charge_')) DATA_COLUMNS = ['Time (s)', 'Current (A)', 'Potential (V)'] def startup(self): log.info("Setting up instruments") """ To use the Nanovoltmeter instead of the Sourcemeter to measure potential, uncomment the following section and change the corresponding section in execute routine to measure from meter instead of source """ # self.meter = Keithley2182("GPIB::7::INSTR") # self.meter.measure_voltage() # self.meter.voltage_range = self.voltage_range # self.meter.voltage_nplc = 1 # Integration constant to Medium self.source = Keithley2400("GPIB::24::INSTR") self.source.source_current() self.source.measure_voltage() self.source.source_current_range = self.capacity * self.c_rate * 5 self.source.compliance_voltage = self.voltage_range self.source.enable_source() sleep(2) def execute(self): charge_rate = self.capacity * self.c_rate * 0.001 # Charge rate, in A discharge_rate = charge_rate * -1 # Discharge rate, in A currents = np.repeat(charge_rate, ) currents_up = np.arange(self.min_current, self.max_current, self.current_step) currents_down = np.arange(self.max_current, self.min_current, -self.current_step) currents = np.concatenate( (currents_up, currents_down)) # Include the reverse currents *= 1e-3 # to mA from A steps = len(currents) # To calculate the e_step, convert to V/s and divide by measurement frequency self.source.ramp_to_voltage(hi_e) e_step = 0.001 * self.sweep_rate / self.deltat sweep1 = np.arange(in_e, hi_e, e_step) sweep2 = np.arange(hi_e, lo_e, -e_step) sweep3 = np.arange(lo_e, hi_e, e_step) potentials = np.concatenate((sweep2, sweep3)) potentials = np.tile(potentials, np.int(self.repeats)) sweep4 = np.arange(hi_e, in_e, -e_step) potentials = np.concatenate((sweep1, potentials)) potentials = np.concatenate((potentials, sweep4)) steps = len(potentials) log.info("Starting Discharge-Charge") for i, e in enumerate(potentials): log.debug("Measuring potential: %g V" % e) self.source.source_voltage = e sleep(1 / self.deltat) current = self.source.current time = i / self.deltat data = { 'Time (s)': time, 'Potential (V)': e, 'Current (A)': current } self.emit('results', data) self.emit('progress', 100. * i / steps) if self.should_stop(): log.warning("Catch stop command in procedure") break def shutdown(self): self.source.shutdown() self.source.beep(783.991, 0.1) sleep(0.125) self.source.beep(1046.50, 0.1) sleep(0.125) self.source.beep(1318.51, 0.1) sleep(0.125) self.source.beep(1567.98, 0.22) sleep(0.25) self.source.beep(1318.51, 0.1) sleep(0.125) self.source.beep(1567.98, 0.25) log.info("Finished")
class Measure2ndHarmonic(Procedure): version = Parameter('Software Version', default="2.0.1") current = FloatParameter('Magnet Current', units='A', default=1) delay = FloatParameter('Delay Time', units='s', default=0.35) max_angle = FloatParameter('Maximum Angle', units='deg', default=180) ramp_rate = FloatParameter('Magnet Ramping Rate', units='A/s', default=0.1) fieldcal = FloatParameter('Magnetic Field Calibration', units='mT/A', default=13.69) Lockin1_use = Parameter('Lock-in 1') Lockin2_use = Parameter('Lock-in 2') # degrees per edge # it moves at degpulse at both the rise and fall of a pulse degpulse = FloatParameter('Degrees per step', units='deg/step', default=(90 / 50 / 2)) # Define motorsteps where +1 is CW step and -1 is CCW step motorstep = 0 DATA_COLUMNS = [ 'Angle (deg)', 'Magnet Current (A)', 'Magnetic Field (mT)', 'Lock-In 1 X (V)', 'Lock-In 1 Y (V)', 'Lock-In 2 X (V)', 'Lock-In 2 Y (V)' ] """ ########################################################################### ########################################################################### ############################# STARTUP PROCEDURE ######################### ########################################################################### ########################################################################### """ def startup(self): log.info("Setting up instruments") self.lockin = DSP7265("GPIB::12") self.lockin.dac3 = 0. self.lockin.dac4 = 0. self.lockin2 = DSP7265("GPIB::11") self.source = SM7045D("GPIB::8") log.info("Ramping magnet power supply to zero and enabling it.") self.source.ramp_to_zero(self.ramp_rate) self.source.enable() sleep(5) """ ########################################################################### ########################################################################### ############################# EXECUTE PROCEDURE ######################### ########################################################################### ########################################################################### """ def step_motor(self, delay=None): """ Step the rotation motor """ if self.lockin.dac3 < 2.5: self.lockin.dac3 = 5. else: self.lockin.dac3 = 0. print("Step: dac3: {:.1f}, dac4: {:.1f}, motorstep: {:d}".format( self.lockin.dac3, self.lockin.dac4, self.motorstep)) # Add or subtract one to the number of motor steps if self.lockin.dac4 < 2.5: self.motorstep += 1 else: self.motorstep -= 1 # Wait for the motor to stop moving if delay is not None: sleep(delay) else: sleep(self.delay) def home_motor(self): # SETTING DIRECTION OF ROTATION # 0 = CLOCKWISE; 5 = COUNTERCLOCKWISE if self.motorstep > 0: self.lockin.dac4 = 5. else: self.lockin.dac4 = 0. # Rotate the sample back to 0 while not self.motorstep == 0.: self.step_motor(delay=0.350) def calc_angle(self): return self.degpulse * self.motorstep def calc_magfield(self): return self.current * self.fieldcal def measure(self): log.debug("Measuring angle: %g deg." % self.calc_angle()) data = { 'Angle (deg)': self.calc_angle(), 'Magnet Current (A)': self.current, 'Magnetic Field (mT)': self.calc_magfield(), 'Lock-In 1 X (V)': self.lockin.x, 'Lock-In 1 Y (V)': self.lockin.y, 'Lock-In 2 X (V)': self.lockin2.x, 'Lock-In 2 Y (V)': self.lockin2.y, } self.emit('results', data) def measurement_procedure(self, Npulses, progress0=0, progress1=100): for i in range(Npulses): self.measure() self.emit('progress', progress0 + (progress1 - progress0) * i / Npulses) if self.should_stop(): log.warning("Catch stop command in procedure") return self.step_motor() self.measure() self.emit('progress', progress1) def execute(self): """ Prepare this specific measurement """ # Setting Magnetic Field self.source.ramp_to_current(self.current, self.ramp_rate) # Number of pulses (per degree times degree) Npulses = round((1 / self.degpulse) * self.max_angle) # Number of motor steps is initially zero. self.motorstep = 0 """ ############################# CLOCKWISE #################### """ # SETTING DIRECTION OF ROTATION # 0 = CLOCKWISE; 5 = COUNTERCLOCKWISE self.lockin.dac4 = 0. sleep(self.delay) log.info("Starting to rotate the sample clockwise.") self.measurement_procedure(Npulses, 0, 50) """ ############################# COUNTERCLOCKWISE ##################### """ # SETTING DIRECTION OF ROTATION # 0 = CLOCKWISE; 5 = COUNTERCLOCKWISE self.lockin.dac4 = 5. sleep(self.delay) log.info("Starting to rotate the sample clockwise.") self.measurement_procedure(Npulses, 50, 100) """ ############################# COUNTERCLOCKWISE ##################### """ """ ########################################################################### ########################################################################### ############################# SHUTDOWN PROCEDURE ######################## ########################################################################### ########################################################################### """ def shutdown(self): log.info("Shutting down.") # Ramp magnet current back to zero. self.source.ramp_to_zero(self.ramp_rate) sleep(1) # Disable magnet power supply. self.source.disable() # Rotate the motor back to 0 self.home_motor() # Setting DACs to zero. self.lockin.dac3 = 0. self.lockin.dac4 = 0. log.info("Finished")
class DepProcedure(Procedure): in_e = IntegerParameter('Start E', units='mV', minimum=-10000, maximum=10000, default=0) lo_e = IntegerParameter('Low E', units='mV', minimum=-10000, maximum=10000, default=-50) hi_e = IntegerParameter('High E', units='mV', minimum=-10000, maximum=10000, default=50) # sweepdirection = sweep_rate = FloatParameter('Sweep Rate', units='mV/s', minimum=0.01, maximum=500, default=10) repeats = IntegerParameter('Cycles', units=None, minimum=1, maximum=1e8, default=10) deltat = FloatParameter('Measurement Frequency', units='Hz', default=20) voltage_range = FloatParameter('Potential Range', units='V', default=10) current_range = FloatParameter('Current Range', units='A', default=0.5) directory = Parameter('Working Directory', default='C:/Data/') filename = Parameter('Filename', default=unique_filename(str(directory), prefix='CV_')) DATA_COLUMNS = ['Time (s)', 'Potential (V)', 'Current (A)'] def startup(self): log.info("Setting up instruments") """ To use the Nanovoltmeter instead of the Sourcemeter to measure potential, uncomment the following section and change the corresponding section in execute routine to measure from meter instead of source """ # self.meter = Keithley2182("GPIB::7::INSTR") # self.meter.measure_voltage() # self.meter.voltage_range = self.voltage_range # self.meter.voltage_nplc = 1 # Integration constant to Medium self.source = Keithley2400("GPIB::24::INSTR") self.source.apply_voltage() self.source.measure_current() self.source.source_current_range = self.current_range self.source.compliance_voltage = self.voltage_range self.source.enable_source() sleep(2) def execute(self): in_e = self.in_e/1000 # Convert from mV to V hi_e = self.hi_e/1000 # Convert from mV to V lo_e = self.lo_e/1000 # Convert from mV to V # To calculate the e_step, convert to V/s and divide by measurement frequency self.source.ramp_to_voltage(hi_e) e_step = 0.001*self.sweep_rate/self.deltat sweep1 = np.arange(in_e, hi_e, e_step) sweep2 = np.arange(hi_e, lo_e, -e_step) sweep3 = np.arange(lo_e, hi_e, e_step) potentials = np.concatenate((sweep2, sweep3)) potentials = np.tile(potentials, np.int(self.repeats)) sweep4 = np.arange(hi_e, in_e, -e_step) potentials = np.concatenate((sweep1, potentials)) potentials = np.concatenate((potentials, sweep4)) steps = len(potentials) log.info("Starting Cyclic Voltammetry") for i, e in enumerate(potentials): log.debug("Measuring potential: %g V" % e) self.source.source_voltage = e sleep(1/self.deltat) current = self.source.current time = i/self.deltat data = { 'Time (s)': time, 'Potential (V)': e, 'Current (A)': current } self.emit('results', data) self.emit('progress', 100.*i/steps) if self.should_stop(): log.warning("Catch stop command in procedure") break def shutdown(self): self.source.shutdown() self.source.beep(783.991,0.1) sleep(0.125) self.source.beep(1046.50,0.1) sleep(0.125) self.source.beep(1318.51,0.1) sleep(0.125) self.source.beep(1567.98,0.22) sleep(0.25) self.source.beep(1318.51,0.1) sleep(0.125) self.source.beep(1567.98,0.25) log.info("Finished")
class DepProcedure(Procedure): plate_e = FloatParameter('Plating Potential', units='V', minimum=-5, maximum=5, default=-1.5) pulse = FloatParameter('Pulse length', units='s', default=0.1) delay = FloatParameter('Delay Time', units='s', default=5.9) repeats = IntegerParameter('Cycles', units=None, default=50) deltat = FloatParameter('Measurement Frequency', units='Hz', default=20) current_range = FloatParameter('Current Range', units='A', default=0.1) directory = Parameter('Working Directory', default='C:/Data/') filename = Parameter('Filename', default=unique_filename(str(directory), prefix='Plate_')) DATA_COLUMNS = ['Current (A)', 'Potential (V)', 'Time (s)'] def startup(self): # log.info("Setting up instruments") # self.meter = Keithley2182("GPIB::7::INSTR") # self.meter.measure_voltage() # self.meter.voltage_range = self.voltage_range # self.meter.voltage_nplc = 1 # Integration constant to Medium self.source = Keithley2400("GPIB::24::INSTR") self.source.apply_voltage() self.source.measure_current() self.source.voltage_nplc = 1 # Integration constant to Medium self.source.complinance_current = self.current_range self.source.enable_source() sleep(2) def execute(self): pulses = np.repeat(self.plate_e, (self.pulse) * 1 // (1 / self.deltat)) rest = np.repeat(0, (self.delay) * 1 // (1 / self.deltat)) potentials = np.concatenate((pulses, rest)) potentials = np.tile(potentials, np.int(self.repeats)) # currents *= 1e-3 # to mA from A steps = len(potentials) log.info("Starting Pulsed electrodeposition") for i, potential in enumerate(potentials): log.debug("Applying potential: %g V" % potential) self.source.source_voltage = potential # Or use self.source.ramp_to_current(current, delay=0.1) sleep(1 / self.deltat) current = self.source.current time = i / self.deltat data = { 'Current (A)': current, 'Potential (V)': potential, 'Time (s)': time } self.emit('results', data) self.emit('progress', 100. * i / steps) if self.should_stop(): log.warning("Catch stop command in procedure") break def shutdown(self): self.source.shutdown() self.source.beep(783.991, 0.1) sleep(0.125) self.source.beep(1046.50, 0.1) sleep(0.125) self.source.beep(1318.51, 0.1) sleep(0.125) self.source.beep(1567.98, 0.22) sleep(0.25) self.source.beep(1318.51, 0.1) sleep(0.125) self.source.beep(1567.98, 0.25) log.info("Finished")
class PotentiostaticProcedure(Procedure): potential = FloatParameter('Potential', units='V', default=0.1) max_current = FloatParameter('Maximum Current', units='mA', default=10) time = FloatParameter('Experiment Length', units='s', default=5) dt = FloatParameter('Measurement frequency', units='Hz', default=5) voltage_range = FloatParameter('Voltage Range', units='V', default=10) directory = Parameter('Working Directory', default='C:/Data/') filename = Parameter('Filename', default=unique_filename(str(directory), prefix='StaticE')) DATA_COLUMNS = ['Time (s)', 'Current (A)', 'Potential (V)'] def startup(self): self.source = Keithley2400("GPIB::24::INSTR") self.source.apply_voltage(voltage_range=None, compliance_current=0.1) self.source.measure_current(nplc=1, current=self.max_current, auto_range=True) # self.source.apply_current() # self.source.source_current_range = self.max_current*1e-3 # A # self.source.complinance_voltage = self.voltage_range self.source.enable_source() sleep(2) def execute(self): potential = self.potential times = np.arange(0, self.time, 1 / self.dt) steps = len(times) log.info("Applying potential of %f V" % potential) self.source.source_voltage = potential for i, time in enumerate(times): # self.source.source_current = potential sleep(1 / self.dt) # sleep between current measurements (Hz -> s) current = self.source.current data = { # 'Time (s)': time, 'Potential (V)': potential, 'Current': current } self.emit('results', data) self.emit('progress', 100. * i / steps) if self.should_stop(): log.warning("Catch stop command in procedure") break def shutdown(self): self.source.shutdown() self.source.beep(783.991, 0.1) sleep(0.125) self.source.beep(1046.50, 0.1) sleep(0.125) self.source.beep(1318.51, 0.1) sleep(0.125) self.source.beep(1567.98, 0.22) sleep(0.25) self.source.beep(1318.51, 0.1) sleep(0.125) self.source.beep(1567.98, 0.25) log.info("Finished")