Skip to main content

A simple Python 3 interface for controlling electronic measurement instruments and scripting measurement sweeps.

Project description

pyneMeas documentation (v0.0.4)

A package for simple electrical measurements using the National Instruments (NI) VISA standard. Developed by Jakob Seidl and coworkers at the Nanoelectronics group at the University of New South Wales, Sydney. It was originally written in Python 2.7 and later adapted for modern Python 3.

The package is divided into two sub-units: Instruments and utility functions that help carry out a electronic measurement. It allows you to connect to various electronic measurement equipment in few lines of code.

Currently implemented instruments include:

  1. Keithley 2400 series source measure units (SMUs)
  2. Keithley 2000 series digital multimeters
  3. Keithley 6517 'Electrometer'
  4. Stanford Instruments SRS830 Lock-in amplifier
  5. National Instruments USB6216 data acquisition card (NiDAQ)
  6. Yokogawa GS200 source measure unit

It is easy to write you own instrument classes by using existing intrument classes and replacing the required GPIB SCPI commands commonly supplied in the intrument's handbook.

In addition, this code was also used to control Oxford Instruments superconducting magnet power supplies and read out the status of Oxford instruments Heliox cryostats. This code is available from the author upon request.

A: Quickstart guide

A.1 Installing pyneMeas:

Case A: from the online repository PyPi:

$ pip install pyneMeas

Case B: from a local pyneMeas folder on your PC:

$ pip install -e local/Path/pyneMeas/. the -e flag allows to make changes to the original files in the folder, useful if you want to tweak the code while working. Enclose you path like this if it contains whitespace: "local Path/with whitespace/SourceDirectory".
You can download the sourcecode (.zip) from github under https://github.com/JakobSeidl/pyneMeas

Install the package in a virtual environment (see e.g. this guide) or in your global Python 3 installation, whatever works best for your use-case.

Check if the installation was successful:
$ pip list returns a list of packages that should contain

pyneMeas           0.0.4    

if you installed it from the internet (Case A) or

pyneMeas           /Path/To/Local/SourceDirectory    

if you installed pyneMeas from a local folder, e.g., after downloading the source code from gitHub (Case B).
You can then try loading the package as described in the following section.

A.2 Non-python drivers and hardware you'll need

IMPORTANT: In order to use commercial GPIB-controlled instruments such as Keithely source-measure units, you need to install the proprietary National Instruments VISA/USB-H bundle driver here. Possibly, this could be replaced by a fully open-source library such as pyvisa-py that supplies the back-end. For using the National Instruments Data Acquisition cards (NIDaQ), you need the corresponding NIDaQ driver.

For both we recommend not chossing the latest version but simpler, earlier versions.

A.3 Loading and testing pyneMeas:

In your python console type:

>>> import pyneMeas.Instruments as I
>>> import pyneMeas.utility as U

If this works, you can run a test measurement using 'virtual' instruments to check weather plotting and data storage works fine:

>>> U.runTest()

should open a plot window with simulated linear and sinusoidal noise signals measured over time. A progress bar should indicated the status of the measurement. In the console, you should see a notification that a folder has been created where the data will be stored.

Out: Created data storage directory: TempDat/
/>>>>>> Finished measurement A1 | Duration: 9.4 seconds = 0.2 min  <<<<<<<

Setting up any basic measurement requires three steps:

  1. Setting up all required instruments and configuring them (see A.4)
  2. Defining the sweep-array and designating which instrument should sweep a variable and which instrument(s) should just read/measure (see A.5).
  3. Call the sweep function 'sweep()' from pyneMeas.utility using the Instrument parameters defined in 2, see A.5.

A.4 Initializing instruments:

We reccommend using an IDE such as PyCharm that supports code completion. E.g., type 'I.' (or any other alias you imported pyneMeas.Instruments as) and all implemented Instruments will appear in a drop-down list. Use TAB-completion when typing in the console. Let's use a Keithley 2401 source-measure unit:

>>> myKeithley = I.Keithley2401(10)  #  Initializes a Keithely2401 instrument at GPIB port 10
KEITHLEY INSTRUMENTS INC., MODEL nnnn, xxxxxxx, yyyyy/zzzzz /a/d  #  Parameters on the right depend on exact model/firmware

The 'KEITHLEY INSTRUMENTS INC.' message is the instrument's response to the typical '*IDN?' query and indicates that the instrument has been successfully initiated. Most instruments have internal options that can be set before the measurement. E.g., the Keithley source-measure unit can be set to source voltage (and measure its output current) or to source a current instead. Every instrument has a set() and setOptions() method: E.g.

>>> myKeithley.set('name','myKeithleyInstrumentName) # Every instrument can have a unique 'name'
>>> myKeithley.setOptions({'sourceMode':'voltage, # sourcing voltage
                      'sourceRange':20})      # Using high source range of up to 20 Volts

For a list of all instrument options and possible values, see [XX].

A.5 Using the sweep() function

In this example we define a simple current vs. voltage sweep with a single Keithley instrument. We define a empty dictionary that holds all relevant data. After defining 'basePath' and 'fileName' under which the data will be stored, we define the 'setter' and 'getters' fields. They determine, which instrument actively set (outputs) a value, e.g. a gate voltage, and which instruments measure the resulting variables, e.g., input voltages, currents. Here we use the same Keithley instrument to do both. The values we want to sweep over, in this case source-drain voltages, are defined in the 'sweepArray field. Here we use the targetArray() function, but standard lists or numpy.arrays can be used as well. In the last step, we call the sweep() function with the required Dct parameter and two optional parameters, delay and plotVars. Note that the name Dct of the dictionary may be changed but the keywords such as 'setter' and 'sweepArray' need to be exactly used as displayed here.

myScript.py
-----------
Dct = {} # Define empty dictionary as container
Dct['basePath'] = "Data/" # Relative to your current working directory
Dct['fileName'] = 'SampleA' # Sets the file name under which data will be saved and logged.

Dct['setters'] = {myKeithley:    'V_SD'} # Set the variable called 'V_SD' with our 'myKeithley' object
Dct['readers'] = {myKeithley:    'I_SD'} # Measure the variable called 'I_SD' with our 'myKeithley' object

Dct['sweepArray'] = U.targetArray([0,1,0],stepsize=0.1) # Define values from 0V -> 1V -> 0V in 0.1V steps
                                                        # targetArray is a utility function provided

df = U.sweep(Dct,                          # call sweep function and provide the Dct dictionary defined
             delay=0.2,                    # seconds wait time in between points
             plotVars = [('V_SD','I_SD')]) # plot 'I_SD' (y-axis) over 'V_SD (x-axis)'      

This should open a live-plot that shows 'I_SD' vs. 'V_SD'. The data is saved under "Data/" (folder is created if it doesn't exist, see console output). Per measurement, four files are saved: The data is saved in .tsv format (blank text), in .mat matlab data format. In addition, a log.tsv file is created that logs important information of the measurement run, such as instruments used etc. When plotting is enabled, the plot is also saved as .png. Note that each measurement has unique measurement ID consisting of a letter prefix and a running number. This is e.g., displayed in the plot title and each saved data file is preceded by it. This also prevents data from being overwritten even when the user uses the same fileName repeatedly. The sweep() function returns a pandas.DataFrame, here assigned to df, that holds the acquired data with column labels corresponding to the variable names provided. This can be useful if the user wants to use the acquired data immediately during the measurement routine.

>>> df
Out:
      V_SD      I_SD     
0        .         .    
1        .         .  
2        .         .   
..     ...       ... 

>>> df.plot(x = 'V_SD', y ='I_SD') # A simple way of plotting the data                                                        

A.5 finding help

1 Remember that in Python, you can call the help() function on any method or object. E.g., if you want to find out about the sweep() function, try calling

>>> help(U.sweep) # No brackets here as we don't want to call the function

Note: Doc-strings are currently being implemented, so help() might not yet work for all methods/classes.

2 If you can't remember, which attributes you can set with the myInstrument.set(), just call those methods with a clearly wrong argument:

>>> noiseGenerator = I.LinearNoiseGenerator()

>>> noiseGenerator.set('wrong',1)
ValueError: 
"wrong is not a valid option. dict_keys(['sourceLevel', 'name'])
 are available"

,which means only the keys 'sourceLevel and 'name can be set for this instrument.

3 If you remember the key attribute but not the possible numerical ranges, you can call set() with a clearly wrong numerical argument

>>> keithley = I.Keithley2401(10)

>>> keithley.set('sourceRange',3000)
ValueError: 
"3000 is not a valid voltage source range for the Keithley2401.
Valid voltage ranges are: 20, 10, 1, 0.1, 0.01 and 0.001 Volts and
equivalent exponential representations."

B Example scripts/ Tutorials

B.1 Two variables: A gate-sweep measurement

gateSweepScript.py
------------------

Vgate_Keithley = I.Keithley2401(10)
VBias_Keithley = I.Keithley2401(11)

[Set options either manually or with .setOptions({'key':argument}) method]

Dct = {} # Define empty dictionary as container
Dct['basePath'] = "Data/" 


Dct['setters'] = {Vgate_Keithley:    'V_G'} 

Dct['readers'] = {  VBias_Keithley:    'I_SD',
                    Vgate_Keithley:    'I_LeakGate'} 


gateLow = -1; gateHigh = 1.5
Dct['sweepArray'] = U.targetArray([0, gateLow, gateHigh, 0], stepsize = 0.05) 

sourceDrainBiases = [0.05, 0.1, 0.5] #  volt

for bias in sourceDrainBiases:

    Dct['fileName'] = f'SampleA_{bias}_volt' # data for each bias will have the bias in the filename for convenience, e.g. SampleA_0.5_volt'

    VBias_Keithley.goTo(bias,0.01,0.2) # Go to the desired bias, then execute gate sweep.  
    U.sweep(Dct, delay=0.2, plotVars = [('V_G','I_SD'), ('V_G','I_LeakGate')])


B.2 Measure instruments over time

timeMeasScript.py
-----------------

myKeith = I.Keithley2401(11)
myTimeInst = I.TimeMeas()  # virtual instrument

[Set myKeith options if desired ...]

Dct['basePath'] = "Data/" 
Dct['fileName'] = 'SampleB_currOverTime'

Dct['setters'] = {myTimeInst:    'dummyPoints'} 

Dct['readers'] = {  myKeith:    'I_d',
                    myTimeInst:    'time'}    

Dct['sweepArray'] = range(100) # measure over 100 datapoints

df = U.sweep(Dct, delay=0.2, # The delay here determines roughly how often we measure per unit time.
        plotVars = [('time','I_d')],
        breakCondition = ('time','>',50)) # optionally we can terminate the measurement after a certain time period if desired.


B.3 Simple I-V measurements with the NIDaq

simpleNiDaQ.py
--------------

DaqIn = USB6216In(2,usbPort = 'Dev1') # Using Analog Input AI2. usbPort depends on the usb port windows assigns to the nidaq
DaqOut = USB6216Out(1,usbPort = 'Dev1') # Using Analog Output AO1

DaqOut.setOptions({
    "feedBack":"Int",
    "extPort":6, # Can be any number 0-7 if in 'Int'
    "scaleFactor":1
})

DaqIn.set("scaleFactor",1) # If we don't use an amplifier, gain =1)

myTime = TimeMeas()

Dct = {} # Define empty dictionary as container
Dct['basePath'] = "Data/" 
Dct['fileName'] = 'SampleC_IV'


Dct['setters'] = {DaqOut:    'V_SD'} 

Dct['readers'] = {  DaqIn:    'I_SD',
                    myTime:    'time'} 

targetLow = 0; targetHigh = 1.5
Dct['sweepArray'] = U.targetArray([targetLow, targetHigh, targetLow], stepsize = 0.01) 

df = U.sweep(Dct, # No plotting and 'delay' here to speed up the nidaq aquisition.
saveCounter = 100) # Only save data every 100th read to increase speed.

B.4 Example using lock-in amplifiers

lockIn_HallScript.py
--------------------
lockIn_ISD = I.SRS830(8)
lockIn_VSD = I.SRS830(10)
lockIn_VHall = I.SRS830(11)  
keith_Vg = I.Keithley2401(13)


# You could set all these manually on the instrument,
# except 'scaleFactor' and 'autoSensitivity'

lockIn_ISD.setOptions({
      'frequency':77, 
      'amplitude':0.004,
      'input':'I1',
      'scaleFactor':1,
      'phase':180,
      'autoSensitivity':False })


[.. set other options as desired...]


Dct = {} # Define empty dictionary as container
Dct['basePath'] = "Data/" 
Dct['fileName'] = 'SampleC_IV'

myComments = """
        Hall bar measurement at B = +2 T @ 4K
        We measure the current through device with lockIn_ISD
        and the voltage across the device with lockIn_VSD. The third lock in,
        lockIn_VHall, measures the Hall voltage. We sweep the gate-voltage with 
        a Keithley2400 (keith_Vg). """

Dct['setters'] = {keith_Vg:    'V_g'} 

Dct['readers'] = {  lockIn_ISD:    ['Isd_X','Isd_Y'],  # The lock-in puts out TWO read-values
                    lockIn_VSD:    ['Vsd_X','Vsd_Y'],  # We put them together in brackets 
                    lockIn_VH:    ['VHall_X','VHall_Y'],
                    keith_Vg:    'I_gateLeak'          # Instruments that only yield single values
            }                                          # don't need brackets.


targetLow = 0; targetHigh = 1.5
Dct['sweepArray'] = U.targetArray([targetLow, targetHigh, targetLow], stepsize = 0.01) 

lockIn_ISD.goTo(2,0.2,0.2) # got to a excitation amplitude of 2 V (usually into a voltage divider)                                                             

data = U.sweep(Dct,
               plotVars = [('V_g','I_sd_X),
                            ('V_g','V_Hall_X),
                            ('V_g','VHall_Y)]),
               plotParams = [('b-','linear-log'), # Sets the plot appearance and lin-log x-y scale
                              ('go','linear-linear')  #linear-linear scale (default)
                              ('ro--','linear-linear')],
               comments = myComments
               )

B.5 Abruptly changing signals - sourcing step functions with SMU's

square_transients.py
--------------------
Vgate_Keithley = I.Keithley2401(10)
VBias_Keithley = I.Keithley2401(11)
myTime = TimeMeas()

Dct = {} # Define empty dictionary as container
Dct['basePath'] = "Data/" 
Dct['fileName'] = 'SampleD_GateTransient'

VgHigh = 0.5  # volt
VgLow = -0.1 
# Creates a Low-HIgh-Low-High square wave gate potential:  
Dct['sweepArray'] = [VgLow]*50 + [VgHigh]*150 + [VgLow]*50 + [VgHigh]*150


Dct['setters'] = {Vgate_Keithley:      'V_G'} 

Dct['readers'] = {  VBias_Keithley:    'I_SD',
                    Vgate_Keithley:    'I_LeakGate'
                    myTime:            'time'} 

df = U.sweep(Dct,
        plotVars = [('time','I_SD'),
                    ('time','V_G')]
            )                                                      

B.6 Reading current instrument setter status to dynamically define next sweeps

breakGateSweep.py
------------------
import pandas as pd # Required later for dataframe operations

Vgate_Keithley = I.Keithley2401(10)
VBias_Keithley = I.Keithley2401(11)

[Set options either manually or with .setOptions({'key':argument}) method]

Dct = {} # Define empty dictionary as container
Dct['basePath'] = "Data/" 

Dct['setters'] = {Vgate_Keithley:    'V_G'} 

Dct['readers'] = {  VBias_Keithley:    'I_SD',
                    Vgate_Keithley:    'I_LeakGate'} 

gateLow = -1; gateHigh = 1.5
Dct['sweepArray'] = U.targetArray([0, gateLow, gateHigh, 0], stepsize = 0.05) 

sourceDrainBiase = 0.1 #  volt

Dct['fileName'] = 'gateSweep_01V'

VBias_Keithley.goTo(bias,0.01,0.2) # Go to the desired bias, then execute gate sweep.  

# This gatesweep breaks if the gate leakge current ever surpasses 10 nA.
df = U.sweep(Dct, delay=0.2,
        plotVars = [('V_G','I_SD'), ('V_G','I_LeakGate')],
        breakCondition=('I_LeakGate','>',10E-9))


#Check if the measurement was broken by the breakCondition:
# If measurement was stopped, measure from the current gate voltage back to 0.

if len(df) < len(Dct['sweepArray']):
    currentVg = Vgate_Keithley.get('sourceLevel') # At what VG did the gate leakage exceed out limit?
    Dct['sweepArray'] = U.targetArray([currentVg,0], stepsize = 0.05) # overwrite previous array

    # Finally carry out measurement
    dfBack = U.sweep(Dct, delay=0.2,
                     plotVars = [('V_G','I_SD'), ('V_G','I_LeakGate')]) 

# It can be useful to concatenate the data from both measurements into one dataframe .
This can be more convenient than the separate saved data files, which were created for each measurement.


dataFull = pd.concat([df,dfBack],ignore_index=True)
dataFull.plot(x='V_G',y='I_SD')


C Documentation of instrument parameters

Upon creation, these Instruments need to be prefixed by the pyneMeas.Instrument alias (I. in the example scripts.)

Most if the following properties can be set, as well as queried with the get/set methods.

C.1 Keithley 2400 series

Source/measure unit supplying either voltage or current.

'outputEnable': Boolean, Turns instrument output on (True or 1) or off (False or 0). outputEnable = True is required for instrument operation. Example: >>> myKeithley.set('outputEnable',False)

'sourceMode', String, can be 'voltage' or 'current' for sourcing a voltage or current respectively. The instrument will also measure the flowing current (when sourcing 'voltage') or the resulting voltage (when sourcing a 'current'). When a Keithley2400 instrument is created, it will internally check the current source mode of the instrument, so 'sourceMode' can be set in hardware or software.

'sourceRange': Float, sets overall source range of instrument. Highest value you want to put out need to be below this limit. When sourcing 'voltage', possible limits are: (20,10,1,0.1,0.01,0.001) (in volts). When sourcing 'current', possible limits are: (1,0.1,0.01,0.001,1E-4,1E-5,1E-6)(in amperes).

'name'' String, Optional unique name of the instrument to distinguish between various instruments of the same type.

'sourceLevel', Float, set or get method. Directly sets the output (voltage or current) to the set value. We do not recommend using this directly, especially not for sensitive nanoscale samples. Use myInstrument.goTo(target,stepSize,delay) instead to slowly approach the desired setpoint.

'senseLevel' Returns float, get method only. Returns the current voltage/current reading.

'senseRange', when sourcing 'voltage': (1.05E-4,1.05E-5,1.05E-6) amperes. OR when sourcing 'current': (21.0,2.1,0.21) volts

compliance, Float, Hard limit of highest current the instrument supplies when sourcing 'voltage' or highest voltage when sourcing 'current'. Must lie below the highest value the instrument can measure, see 'senseRange'.

'scaleFactor' Float, scales the measured values form the instrument. Defaults to 1 and does not usually have to be set.


C.2 Keithley 2000 series

Versatile amp/voltmeter.

'senseMode', String, determines whether the instrument reads current or voltage as input. Can be 'voltage' or 'current'.

'senseRange' Float, sets the input range. Allowed voltage ranges are: (100E-3,1,10,100,1000) # volts. Allowed current ranges are: (10E-3,100E-3,1,3) # amps.

'senseLevel', Returns float, get method only. Returns reading of input voltage/current.

'scaleFactor' Float, scales the measured values form the instrument. Useful when current or voltage preamps are used and the output is read by the Keithley 2000.


C.3 Keithley 6517A Electrometer

Very sensitive amp/voltmeter.

'zeroCheck' Boolean, True enables zerocheck mode, which protects the instrument when not in use. Needs to be disabled (False) before a measurement.

senseMode', String, determines whether the instrument reads current or voltage as input. Can be 'voltage' or 'current'.

'senseLevel', Returns float, get method only. Returns reading of input voltage/current.

'senseRange' Float, when measuring current: [20E-12,200E-12,2E-9,20E-9,200E-9,2E-6,20E-6,200E-6,2E-3,20E-3] # amperes. When measuring voltage: [2,20,200] # volts.

'autoRange', Boolean. When True, the instrument will try to adjust its 'senseLevel' according to its input readings.

'NPLC', Float between 0.1 & 10. Sets the integration time during a measurement in 'power line cycles'. Default is 1. Reduce this if your overall sweep velocity is too fast for the instrument to catch up, increase 'NPLC' if you need slow, high precision readings of low currents.


C.4 SRS830 lock-in amplifier

For a detailed look at the lock-in specific parameters, please refer to the excellent manual of the SRS830.

'frequency': Float between 0.1 Hz & 100 kHz. Sets the operation frequency.

'amplitude': Float between 0.004 V & 5 V. Sets the root-mean-square amplitude of the sinusoidal output voltage of the amplifier.

'input' String, can be "A","A-B","I1" or "I2" corresponding to a simple voltage measurement "A", a differential voltage measurement "A-B" or a current measurement with two different gains "I1"/"I2""

'timeConst' : Float or int. Sets the time constant of the lock-in amplifier. Allowed inputs are: [10E-6,30E-6,100E-6,300E-6,1E-3,3E-3,10E-3,30E-3,100E-3,300E-3,1,3,10,30,100,300] # seconds

'phase' Float, sets the phase-parameter of the lock-in amplifier in degrees. Can range from 0 to 360 degrees.

'sweepParameter' String, can be "frequency" or "amplitude". When the lock-in is used as a setter in the sweep() function, you can choose whether you want to sweep the RMS amplitude (default) or output frequency. Sweeping the frequency can e.g. be used to determine which drive frequency generates low noise background

'sourceLevel', Float, set method only. Directly sets the output amplitude (or frequency) to the set value. We do not recommend using this directly. Use myInstrument.goTo(target,stepSize,delay) instead to slowly approach the desired setpoint.

'senseLevel' Tuple of floats (Xreading, Yreading), get method only. Returns the X- and Y-component of the voltage/current reading.

'senseRange' Float, [1E-9,2E-9,5E-9,10E-9,20E-9,50E-9,100E-9,200E-9,500E-9,1E-6,2E-6,5E-6,10E-6,20E-6,50E-6,100E-6,200E-6,500E-6,1E-3,2E-3,5E-3,10E-3,20E-3,50E-3,100E-3,200E-3,500E-3,1] # volts These voltage ranges directly correspond to current ranges, as written on the amplifier front panel.

'autoSensitivity' Boolean. When True, the instrument will try to adjust its 'senseLevel' according to its input readings. Note that this is not fully mature at the moment and should be properly tested prior to use in a real experiment. Defaults to False.

'name' String, Optional unique name of the instrument to distinguish between various instruments of the same type.

C.5 YokogawaGS200

Voltage/current source unit.

outputEnable, Boolean, True is required for instrument operation.

'sourceMode', String, can be 'voltage' or 'current' for sourcing a voltage or current, respectively.

'sourceRange': Float, sets overall source range of instrument. Highest value you want to put out needs to be below this limit. When sourcing 'voltage', possible limits are: (30,10,1,0.1,0.01) (in volts). When sourcing 'current', possible limits are: (0.2,0.1,0.01,0.001)(in amperes).

'sourceLevel', Float, set or get method. Directly sets the output amplitude to the set value. We do not recommend using this directly. Use myInstrument.goTo(target,stepSize,delay) instead to slowly approach the desired setpoint.

'name' String, optional. Unique name of the instrument to distinguish between various instruments of the same type.

compliance, Float, Hard limit of highest current the instrument supplies when sourcing 'voltage' or highest voltage when sourcing 'current'.

C.6 National Instruments NiDaQ (USB6216)

Data acquisition device that can carry out fast (up to 200kHz) transient measurements. Consists of a arbitrary function generator part (Out) and various Analog-to-digital converter inputs (IN). These are realized by the USB6216Out() and USB6216In() classes, respectively.

  1. USB6216Out(outputPort,usbPort)

outputPort int, required upon initialization. Can be 0: (port AO0) or 1: (port AO1)

usbPort int, required upon initialization. Internal device port of the NiDaQ. Is usually 1 (Dev1) or 2 (Dev). Will throw an error when outputting a voltage. Device number can be found e.g. using NI MAX.

feedback int, optional. Default: 'Int' (internal). External feedback ('Ext') not tested yet.

extPort int, optional. If feedback is set to 'Int', it can be any number from 0-7, without any effect. Testing required when feedback is set to 'Ext'.

  1. USB6216In(inputPort,usbPort)

inputPort int, required upon initialization. Can range from 0: (port AI0) to 7: (port AI7)

usbPort int, required upon initialization. Internal device port of the NiDaQ. Is usually 1 (Dev1) or 2 (Dev). Will throw an error when outputting a voltage. Device number can be found e.g. using NI MAX.

scaleFactor float, optional. Scales the measured voltages by this factor. Used when the measured voltages are amplified by an amplifier of known gain.

D Documentation of utility functions

To access these functions, use the pyneMeas.utility alias (U. in the example scripts.)

D.1 The sweep() function

Common usage: See example script above.

Parameters:

delay Float, wait time in seconds after a value has been set and before instruments are read out. Default=0.0

comments String, Comments on experiment, sample etc. Is stored in the .log file together with the saved data. Useful for data not measured by instruments. Example: "SampleA, I-V, T= 77K"

plotVars list of ('xVar','yVar') tuples to be plotted. Example: [ ('V_SD', 'I_SD') ] from above.

plotParams list of ('plotString','XAxisScale-YAxisScale') tuples. 'plotString' contains color, line and marker info. See the Matplotlib documentation under Notes. 'XAxisScale-YAxisScale' can be e.g. 'linear-linear' or 'linear-log' or any combination. Example: [ ('go-', 'linear-linear') ]

plotAlpha Float, Transparency of markers: 1= no transparency, 0 = fully transparent. Default = 0.8

plotCounter Integer, After how many datapoints do you want to update the plot. plotCounter > 1 helps speed up plotting. Default = 1

plotSize Tuple of two floats (xSize,ySize), size of plot window in cm. Default = (10,10)

saveCounter Integer, After how many datapoints do you want to save data to disc. Can help speed up the measurement slightly. Default = 10

breakCondition Tuple, ('Variable','comparisonOperator',Value). Allows to stop a measurement when a certain condition is met. 'Variable' is compared against Value using 'comparisonOperator'. 'comparisonOperator' can be '<' or '>' at the moment. Example: breakCondition = ('I_SD','>',1E-6) will end the measurement when 'I_SD' reaches a value above 1 microampere.

extraInstruments List of instrument objects, used to keep track of instruments that are not directly used as setter or reader but you still want to see logged in the .log file.

saveEnable Boolean, Defines whether saving the data is desired. Default = True. In the current version, saveEnable = False also disables plotting.

D.2 The targetArray([targetList],stepSize) function

Convenient way of creating a linearly-spaced array of floats of type np.arange(). Easier than concatenating np.arange() or np.linspace().

E.g. targetArray([0.0,1.0,-1.3,0.0],0.2) creates an array from 0.0 -> 1.0 -> -1.3 -> 0.0 in 0.2 steps.

targetList list of floats. E.g. [0.0,1.0,-1.3,0.0]

stepSize float. E.g. 0.2. IMPORTANT: If the targets can't be reached with the specified stepsize, e.g., a target of 0.3 with a stepsize of 0.2, the last datapoint will overshoot the setpoint. >>> targetArray([0,0.3],0.2) returns array([0.,0.2,0.4]) NOT containing 0.3! If possible, choose stepsizes that match the desired setpoints to avoid this.

D.3 Managing the unique measurement identifiers

Every measurement performed with the sweep() identifier displayed as the plot title that is also part of all saved file names. It consist of a unique prefix + running ID number (int). This assures that no measurement will eve rbe overwritten and that you have a unique reference to each measurement, useful for logging data in a database.

How do I access and manipulate this identifier?

You can list all currently defined identifiers using (assuming you imported pyneMeas.utility as U)

>>> U.listIDs()
Currently used Prefix/Setup: A  --> ID = 1
-------------------------------------------- 
Other available Setups/Prefixes are: #none at the moment

Currently only one prefix ('A') is defined. It's running ID is 1, which would increment when running a measurement.

'A' is the standard prefix out of the box. You can create more meaningful prefixes like so:

>>> U.addPrefix('test')

Checking the identifier with listIDs() now shows the new prefix with a ID of 0. However 'A' is still the active prefix. This means, when carrying out a measurement, only the ID of 'A' is increased. This can be useful, if more than one scientist works on the same setup but wants to get their data indexed separately, e.g., prefixed by initials.

>>> U.listIDs()
Currently used Prefix/Setup: A  --> ID = 1
-------------------------------------------- 
Other available Setups/Prefixes are: 
Prefix/Setup: test  --> ID = 0

We can make 'test' the active setup by typing:

>>> setCurrentSetup('test')
Succesfully changed preFix/Setup from: A ---> test

>>> U.listIDs()
Currently used Prefix/Setup: test  --> ID = 0
--------------------------------------------- 
Other available Setups/Prefixes are: 
Prefix/Setup: A  --> ID = 1

We can directly access the current prefix (string) and ID by with:

>>> U.readCurrentSetup()
'test'
>>> U.readCurrentID()
0

This is useful if you want to log the measurement ID together with the dataframe output of the sweep function, i.e., if you're not using the data files saved by sweep().

Lastly, you can clear all current identifiers and start with the default values

U.initID()

however, be aware that this removes all user information and should only be used as a last resort.

Beyond the sweep() function: Using instruments in a custom for-loop

The sweep() function is a convenient way of carrying out many standard electronic measurements, while facilitating live plotting. However, in its current form, it cannot cater for more complex measurements, such as multi-parameter sweeps. By accessing instruments directly, you can create custom procedures that are more versatile. The fundamental methods to set an instrument's output (e.g. output voltage) or access its current reading (e.g. input current) are myInstr.set('sourceLevel',outputLevel) and myInstrument.read() methods, respectively.

In the following example, we will replicate a simple (virtual) noise over time measurement, but this should work accordingly for any instrument.

import time
import pyneMeas.Instruments as I
import pyneMeas.utility as U
import matplotlib.pyplot as plt

T = I.TimeMeas()
Noi = I.LinearNoiseGenerator()

points = range(50)

data= {}
data['noise'] = []
data['time'] = []

delay = 0.2 # in seconds

for point in points:

    Noi.set('sourceLevel', point) # This does not do anything with this virtual instrument.
    # Using this on a real instrument would output e.g. a voltage.

    time.sleep(delay) # wait between measurements

    data['time'].append(T.read()) # Read the current time and write to list
    data['noise'].append(Noi.read()) # Reads current (virtual) noise level and write to list

plt.plot(data['time'],data['noise'],'-o')
plt.xlabel('time');
plt.ylabel('Noise')
plt.show()

In principle, this for-loop can be a lot more complex and behave differently, depending on readings from various instruments or user input.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyneMeas-0.0.4.tar.gz (59.7 kB view details)

Uploaded Source

Built Distribution

pyneMeas-0.0.4-py3-none-any.whl (46.6 kB view details)

Uploaded Python 3

File details

Details for the file pyneMeas-0.0.4.tar.gz.

File metadata

  • Download URL: pyneMeas-0.0.4.tar.gz
  • Upload date:
  • Size: 59.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.4.0 requests-toolbelt/0.9.1 tqdm/4.36.1 CPython/3.7.4

File hashes

Hashes for pyneMeas-0.0.4.tar.gz
Algorithm Hash digest
SHA256 2539122e8f6bfad854f6459b6d27f42c37d2811f8dd1bc04460400c896394b62
MD5 446e570f077f00274342781922e92871
BLAKE2b-256 255fe3b3d8b03606262f0b392d2d5c2559b16c1c2db01b34f3988ca89d1b04ea

See more details on using hashes here.

File details

Details for the file pyneMeas-0.0.4-py3-none-any.whl.

File metadata

  • Download URL: pyneMeas-0.0.4-py3-none-any.whl
  • Upload date:
  • Size: 46.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.4.0 requests-toolbelt/0.9.1 tqdm/4.36.1 CPython/3.7.4

File hashes

Hashes for pyneMeas-0.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 97decf268654e1ff9592af2967f402d54cf6673942174dd41811680240a0dc8e
MD5 41c11e3295fbc104f63746c72586fa0f
BLAKE2b-256 b5ceee3f3b9d93a2a734d4145536b4f16a5dbc0ac5dbd844ff2d178017b86162

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page