Source code for KEITHLEY2612

# -*- coding: utf-8 -*-
"""
Created on Fri Dec 10 08:39:48 2021

@author: Martin.Mihaylov
"""


import numpy as np
import pyvisa as visa


    
[docs] class KEITHLEY2612: ''' This function is using pyvisa. Please install PyVisa before you use it. ''' def __init__(self, resource_str): ''' Connect to Device and print the Identification Number. ''' self._resource = visa.ResourceManager().open_resource(resource_str) print(self._resource.query('*IDN?').strip()) # Internal Variables self._chList = ['a', 'b']
[docs] def query(self, message): return self._resource.query(message)
[docs] def write(self, message): return self._resource.write(message)
[docs] def Close(self): self._resource.close() print('Instrument Keithley Instruments Inc., Model 2612, 1152698, 1.4.2 is closed!')
# ============================================================================= # Reset to Default # =============================================================================
[docs] def Reset(self,chan): ''' Parameters ---------- chan : str Select Channel A or B and restore to default channel settings. Raises ------ ValueError Error message Returns ------- None. ''' chan = chan.lower() if chan in self._chList: self.write('smu'+str(chan)+'.reset()') else: raise ValueError('Unknown input! See function description for more info.')
# ============================================================================= # ASK # =============================================================================
[docs] def getIdn(self): ''' Returns ------- TYPE str Instrument identification ''' return str(self.query('*IDN?')).strip()
[docs] def ask_LimitReached(self,chan: str) -> bool: '''This attribute contains the state of source compliance. Parameters ---------- chan : str This output indicates that a configured limit has been reached. (voltage, current, or power limit) Returns ------- TYPE DESCRIPTION. ''' chan = chan.lower() if chan in self._chList: v = self.query('print(smu'+str(chan)+'.source.compliance)').strip().lower() return True if v == 'true' else False
[docs] def ask_Current(self,chan: str) -> float: '''This function performs one current measurements and returns the value. Parameters ---------- chan : str Select channel A or B Raises ------ ValueError Error message Returns ------- TYPE float Return float with the measured current value on the channel. ''' chan = chan.lower() if chan in self._chList: return float(self.query('print(smu'+str(chan)+'.measure.i())')) else: raise ValueError('Unknown input! See function description for more info.')
[docs] def ask_Voltage(self,chan: str) -> float: '''This function performs one voltage measurements and returns the value. Parameters ---------- chan : str Select channel A or B Raises ------ ValueError Error message Returns ------- TYPE : float Return float with the measured voltage value on the channel. ''' chan = chan.lower() if chan in self._chList: return float(self.query('print(smu'+str(chan)+'.measure.v())')) else: raise ValueError('Unknown input! See function description for more info.')
[docs] def ask_Power(self,chan: str) -> float: '''This function performs one power measurements and returns the value. Parameters ---------- chan : str Select channel A or B Raises ------ ValueError Error message Returns ------- TYPE : float Return float with the measured power value on the channel. ''' chan = chan.lower() if chan in self._chList: return float(self.query('print(smu'+str(chan)+'.measure.p())')) else: raise ValueError('Unknown input! See function description for more info.')
[docs] def ask_Resistance(self,chan: str) -> float: '''This function performs one resistance measurements and returns the value. Parameters ---------- chan : str Select channel A or B Raises ------ ValueError Error message Returns ------- TYPE : float Return float with the measured resistance value on the channel. ''' chan = chan.lower() if chan in self._chList: return print(self.query('print(smu'+str(chan)+'.measure.r())')) else: raise ValueError('Unknown input! See function description for more info.')
[docs] def ask_readBuffer(self,chan,start,stop): '''TODO: This function should be checked. Also is doesn't return anything at the moment. Parameters ---------- chan : str Select channel A or B start : int select start value stop : int select stop value Raises ------ ValueError Error message Returns ------- Print the source function used for 'start' - 'stop' readings stored in source-measure unit (SMU) channel A, buffer 1. ''' chan = chan.lower() if chan in self._chList: self.query('printbuffer('+str(start)+','+str(stop)+',smu'+str(chan)+')') else: raise ValueError('Unknown input! See function description for more info.')
# ============================================================================= #SET # =============================================================================
[docs] def set_SourceOutput(self, chan: str, state: int|str) -> None: '''This attribute sets source output state (on or off) Parameters ---------- chan : str Select channel A or B state : str Set source output (CHAN A/B) ON or OFF Raises ------ ValueError Error message Returns ------- None. ''' # Normalize channel and state inputs chan = chan.lower() state_mapping = { 'on': 'ON', 'off': 'OFF', 1: 'ON', 0: 'OFF', 2: 'HIGH_Z', '1': 'ON', '0': 'OFF' } state_normalized = state_mapping.get(state if isinstance(state, int) else state.lower()) # Validate inputs if chan in self._chList and state_normalized is not None: self.write('smu'+str(chan)+'.source.output = smu'+str(chan)+'.OUTPUT_'+str(state_normalized)) else: raise ValueError('Unknown input! See function description for more info.')
[docs] def set_MeasOutput(self, chan: str, state: int|str) -> None: '''This attribute sets source output state (on or off) Parameters ---------- chan : str Select channel A or B state : str Set source output (CHAN A/B) ON or OFF Raises ------ ValueError Error message Returns ------- None. ''' # Normalize channel and state inputs chan = chan.lower() state_mapping = { 'on': 'ON', 'off': 'OFF', 1: 'ON', 0: 'OFF', 2: 'HIGH_Z', '1': 'ON', '0': 'OFF' } state_normalized = state_mapping.get(state if isinstance(state, int) else state.lower()) # Validate inputs if chan in self._chList and state_normalized is not None: self.write('smu'+str(chan)+'.source.output = smu'+str(chan)+'.OUTPUT_'+str(state_normalized)) else: raise ValueError('Invalid channel or state! Channel must be "A" or "B". \ State must be "ON", "OFF", 1, or 0.')
[docs] def set_AutoVoltageRange(self, chan: str, state: int|str) -> None: '''This attribute contains the state of the source autorange control (on/off). Parameters ---------- chan : str Select channel A or B state : str ON/OFF voltage source automatic range Raises ------ ValueError Error message Returns ------- None. ''' # Normalize channel and state inputs chan = chan.lower() state_mapping = { 'on': 'ON', 'off': 'OFF', 1: 'ON', 0: 'OFF', '1': 'ON', '0': 'OFF' } state_normalized = state_mapping.get(state if isinstance(state, int) else state.lower()) # Validate inputs if chan in self._chList and state_normalized is not None: self.write('smu'+str(chan)+'.source.autorangev = smu'+str(chan)+'.AUTORANGE_' + str(state_normalized)) else: raise ValueError('Unknown input! See function description for more info.')
[docs] def set_AutoCurrentRange(self, chan: str, state: int|str) -> None: '''This attribute contains the state of the source autorange control (on/off). Parameters ---------- chan : str Select channel A or B state : str ON/OFF current source automatic range Raises ------ ValueError Error message Returns ------- None. ''' # Normalize channel and state inputs chan = chan.lower() state_mapping = { 'on': 'ON', 'off': 'OFF', 1: 'ON', 0: 'OFF', '1': 'ON', '0': 'OFF' } state_normalized = state_mapping.get(state if isinstance(state, int) else state.lower()) # Validate inputs if chan in self._chList and state_normalized is not None: self.write('smu'+str(chan)+'.source.autorangei = smu'+str(chan)+'.AUTORANGE_' + str(state_normalized)) else: raise ValueError('Unknown input! See function description for more info.')
[docs] def set_VoltageRange(self, chan: str, value: int|float) -> None: '''This attribute contains the positive full-scale value of the measure range for voltage Parameters ---------- chan : str Select Channel A or B value : int/float Set voltage source voltage limit Raises ------ ValueError Error message Returns ------- None. ''' chan = chan.lower() if chan in self._chList: value = '{:.0e}'.format(value) self.write('smu'+str(chan) + '.measure.rangev = ' + value) else: raise ValueError('Unknown input! See function description for more info.')
[docs] def set_CurrentRange(self, chan: str, value: int|float) -> None: '''This attribute contains the positive full-scale value of the measure range for current Parameters ---------- chan : str Select Channel A or B value : int/float Set current source voltage limit Raises ------ ValueError Error message Returns ------- None. ''' chan = chan.lower() if chan in self._chList: value = '{:.0e}'.format(value) self.write('smu'+str(chan)+'.measure.rangei = ' + str(value)) else: raise ValueError('Unknown input! See function description for more info.')
[docs] def set_VoltageLimit(self, chan: str, value: int|float) -> None: '''Sets voltage source compliance. Use to limit the voltage output when in the current source mode. This attribute should be set in the test sequence before turning the source on. Parameters ---------- chan : str Select Channel A or B value : int/float Sets the voltage limit of channel X to V. Using a limit value of 0 will result in a "Parameter Too Small" error message (error 1102) Raises ------ ValueError Error message Returns ------- None. ''' chan = chan.lower() if chan in self._chList and 20e-3 < value < 200: value = '{:.0e}'.format(value) self.write('smu'+str(chan)+'.source.limitv = ' + str(value)) else: raise ValueError('Unknown input! See function description for more info.')
[docs] def set_CurrentLimit(self, chan: str, value: int|float) -> None: '''Sets current source compliance. Use to limit the current output when in the voltage source mode. This attribute should be set in the test sequence before turning the source on. Parameters ---------- chan : str Select Channel A or B value : int/float Sets the current limit of channel X to A. Using a limit value of 0 will result in a "Parameter Too Small" error message (error 1102) Raises ------ ValueError Error message Returns ------- None. ''' chan = chan.lower() if chan in self._chList and 10e-9 < value < 3: value = '{:.0e}'.format(value) self.write('smu'+str(chan)+'.source.limiti = ' + str(value)) else: raise ValueError('Unknown input! See function description for more info.')
[docs] def set_Voltage(self, chan: str, value: int|float) -> None: '''This attribute sets the source level voltage. Parameters ---------- chan : str Select Channel A or B value : int/float Set voltage on channels A and B Raises ------ ValueError Error message Returns ------- None. ''' chan = chan.lower() if chan in self._chList: value = '{:.4e}'.format(value) self.write('smu'+str(chan)+'.source.levelv = '+str(value)) else: raise ValueError('Unknown input! See function description for more info.')
[docs] def set_Current(self, chan: str, value: int|float) -> None: '''This attribute sets the source level current. Parameters ---------- chan : str Select Channel A or B value : int/float Set Current on channels A and B Raises ------ ValueError Error message Returns ------- None. ''' chan = chan.lower() if chan in self._chList: value = '{:.4e}'.format(value) self.write('smu'+str(chan)+'.source.leveli = '+str(value)) else: raise ValueError('Unknown input! See function description for more info.')
[docs] def set_ChannelDisplay(self,chan: str, double: bool = True) -> None: ''' Parameters ---------- chan : str Select channel A or B double : boolean, optional Displays source-measure for SMU A and SMU B. double = True per default. if double = True: Display Chan A and B else: Display only Chan selected Raises ------ ValueError Error message Returns ------- None. ''' chan = chan.lower() if chan in self._chList: if double == False: self.write('display.screen = display.SMU'+str(chan.upper())) else: self.write('display.screen = display.SMUA_SMUB') else: raise ValueError('Unknown input! See function description for more info.')
[docs] def set_OutputSourceFunction(self, chan: str, type: str) -> None: '''This attribute sets the source function (V source or I source). Parameters ---------- chan : str Select channel A or B type : str The source function. Set to one of the following values: type = 'volt' Selects voltage source function type = 'amp' Selects current source function Raises ------ ValueError Error message Returns ------- None. ''' chan = chan.lower() type = type.lower() tList = ['volt','amp'] if chan in self._chList and type in tList: if type == 'volt': self.write('smu'+str(chan)+'.source.func = smu'+str(chan)+'.OUTPUT_DCVOLTS') elif type == 'amp': self.write('smu'+str(chan)+'.source.func = smu'+str(chan)+'.OUTPUT_DCAMPS') else: raise ValueError('Unknown input! See function description for more info.')
[docs] def set_DisplayMeasurementFunction(self, chan: str, type: str) -> None: '''This attribute specifies the type of measurement being displayed. Parameters ---------- chan : str Select channel A or B type : str Selects the displayed measurement function: volt, amp, ohm, or watt. SMU A and SMU B can be set for different measurement functions! Raises ------ ValueError Error message Returns ------- None. ''' chan = chan.lower() type = type.lower() tList = ['volt','amp','ohm','watt'] if chan in self._chList and type in tList: if type == 'volt': self.write('display.smu'+str(chan)+'.measure.func = display.MEASURE_DCVOLTS') elif type == 'amp': self.write('display.smu'+str(chan)+'.measure.func = display.MEASURE_DCAMPS') elif type == 'ohm': self.write('display.smu'+str(chan)+'.measure.func = display.MEASURE_OHMS') elif type == 'watt': self.write('display.smu'+str(chan)+'.measure.func = display.MEASURE_WATTS') else: raise ValueError('Unknown input! See function description for more info.')
[docs] def set_MeasurementVoltageRange(self, chan: str, type: str, value: int|float) -> None: '''This attribute contains the positive full-scale value of the measure range for voltage or current. Parameters ---------- chan : str Select channel A or B type : str Selects the measurement function: 'volt' or 'amp'. SMU A and SMU B can be set for different measurement functions! value : int/float Set to the maximum expected voltage or current to be measured. Raises ------ ValueError Error message Returns ------- None. ''' chan = chan.lower() type = type.lower() value = '{:.0e}'.format(value) tList = ['volt','amp'] if chan in self._chList and type in tList: if type == 'volt': self.write('smu'+str(chan)+'.measure.rangev = ' + str(float(value))) elif type == 'amp': self.write('smu'+str(chan)+'.measure.rangei = ' + str(float(value))) else: raise ValueError('Unknown input! See function description for more info.') else: raise ValueError('Unknown input! See function description for more info.')
[docs] def set_PulseMeasured(self,chan:str,value:int|float,ton:int|float,toff:int|float) -> None: ''' Parameters ---------- chan : str Select channel A or B value : int/float or list with curly braces for example {1,2,3....}. ton : int/float X ms pulse on toff : int/float X ms pulse off Raises ------ ValueError Error message Returns ------- None. ''' chan = chan.lower() if chan in self._chList: self.write('ConfigPulseIMeasureV(smu'+str(chan)+','+str(value)+','+str(ton)+','+str(toff)+')') else: raise ValueError('Unknown input! See function description for more info.')
[docs] def set_offmode(self, chan: str, type: int | str) -> None: """This attribute sets the source output-off mode Parameters ---------- chan : str Channel A or B type : int | str 0 or NORMAL: Configures the source function according to smuX.source.offfunc attribute 1 or ZERO: Configures source to output 0 V 2 or HIGH_Z: Opens the output relay when the output is turned off Raises ------ ValueError Channel not in Channel list or Type not in Type list """ # Normalize channel and state inputs chan = chan.lower() type_mapping = { 0: 'NORMAL', 1: 'ZERO', 2: 'HIGH_Z', 'normal': 'NORMAL', 'zero': 'ZERO' } type_normalized = type_mapping.get(type if isinstance(type, int) else type.lower()) # Validate inputs if chan in self._chList and type_normalized is not None: self.write('smu'+str(chan)+'.source.offmode = smu'+str(chan)+'.OUTPUT_'+str(type_normalized)) else: raise ValueError('Unknown input! See function description for more info.')
# ============================================================================= # Get/Save Data # =============================================================================
[docs] def get_Data(self,chan): ''' Parameters ---------- chan : str Select channel A or B Returns ------- OutPut : dict Return a dictionary with the measured voltage and current. ''' chan = chan.lower() OutPut = {} if chan in self._chList: Current = self.ask_Current(chan) Voltage = self.ask_Voltage(chan) OutPut['Voltage/V'] = Voltage OutPut['Current/A'] = Current return OutPut