-
Notifications
You must be signed in to change notification settings - Fork 9
Using SMUs
The standard functionality of SMUs in JISA
is defined by the SMU
interface.
That is, every make/model of SMU in JISA
(like K2450
, K2612B
etc) is
considered to be an SMU
with a standard set of functions that you can use on
it.
This page serves to give a guide on what these are and how best to use them.
- Connecting
- Basics
- Multiple Channels
- Range Configuration
- Compliance/Limit Configuration
- Integration Time
- Four-Probe/Four-Wire Measurements
- Front/Rear Terminal Selection
- Averaging/Filtering
- Use as Voltmeter or Ammeter
- Example
As with any other instrument in JISA
, you first need to connect to it before
you can control it. As described on the "instrument basics" page, this is done
by creating the relevant driver and supplying any address information it needs.
For example, let's take a Keithley 2450 connected over GPIB on address 20:
Java
K2450 smu = new K2450(new GPIBAddress(0, 20));
Kotlin
val smu = K2450(GPIBAddress(0, 20))
Python
smu = K2450(GPIBAddress(0, 20))
From this point onwards, we will assume we have connected to an SMU
and have
assigned it to the variable smu
.
SMU channels typically have an on/off switch. That is you can configure them to
output a value but they won't actually output it until the channel has been
turned on. You can control this in JISA
by use of:
smu.turnOn(); // Enable output
smu.turnOff(); // Disable output
SMUs typically have two modes:
- Source voltage (and measure current)
- Source current (and measure voltage)
To configure an SMU to source some amount of voltage, simply call
setVoltage()
:
smu.setVoltage(5.0); // Source 5 V
This will both change it to voltage-sourcing mode and set the source value to 5 Volts. Likewise for current (500 mA):
smu.setCurrent(500e-3); // Source 500 mA
If the channel is on this will change immediately. If it is off, then this value will only be output when turned on.
You can then request a measurement of either voltage or current by use of the
getVoltage()
and getCurrent()
methods respectively:
Java
double voltage = smu.getVoltage();
double current = smu.getCurrent();
Kotlin
val voltage = smu.getVoltage()
val current = smu.getCurrent()
Python
voltage = smu.getVoltage()
current = smu.getCurrent()
If the SMU you are using has multiple channels, you can extract each channel out
as its own SMU
object by use of getSMU(...)
like so:
Java
SMU channelA = smu.getSMU(0);
SMU channelB = smu.getSMU(1);
Kotlin
val channelA = smu.getSMU(0)
val channelB = smu.getSMU(1)
Python
channelA = smu.getSMU(0)
channelB = smu.getSMU(1)
You can now use all the standard SMU methods on these individual SMU objects to control their respective channel as if they were separate SMUs.
channelA.setVoltage(5.0);
channelB.setCurrent(15e-3);
channelA.turnOn();
channelB.turnOn();
double voltage = channelB.getVoltage();
double current = channelA.getCurrent();
Alternatively, you can use the generic MultiInstrument
interface that MCSMU
implements to extract individual channels, like so:
Java
// Check that this indeed does contain SMU channel sub-instruments
if (smu.contains(SMU.class)) {
SMU channelA = smu.get(SMU.class, 0); // First sub-instrument that counts as an SMU
SMU channelB = smu.get(SMU.class, 1); // Second sub-instrument that counts as an SMU
}
Kotlin
// Check that this indeed does contain SMU channel sub-instruments
if (SMU::class in smu) {
val channelA = smu[SMU::class, 0] // First sub-instrument that counts as an SMU
val channelB = smu[SMU::class, 1] // Second sub-instrument that counts as an SMU
}
Python
# Check that this indeed does contain SMU channel sub-instruments
if smu.contains(SMU):
channelA = smu.get(SMU, 0) # First sub-instrument that counts as an SMU
channelB = smu.get(SMU, 1) # Second sub-instrument that counts as an SMU
You can configure the range that an SMU uses for both voltage and current by use
of the setVoltageRange(...)
and setCurrentRange(...)
methods like so:
smu.setVoltageRange(20.0); // 20 V range
smu.setCurrentRange(200e-3); // 200 mA range
This will pick the smallest range that contains the value you specify when only discrete options are available. You can configure both in one go by use of:
smu.setRanges(20.0, 200e-3);
To check what ranges are currently being used:
double voltageRange = smu.getVoltageRange();
double currentRange = smu.getCurrentRange();
If you want the SMU to decide automatically which range to use, then enable auto-ranging like so:
smu.useAutoVoltageRange();
smu.useAutoCurrentRange();
or again, both at once:
smu.useAutoRanges();
To check whether auto-ranging is enabled:
boolean voltageAuto = smu.isVoltageRangeAuto(); // true or false
boolean currentAuto = smu.isCurrentRangeAuto(); // true or false
SMUs provide a means of protection when sourcing voltage or current in the form of a "compliance limit". This is a limit placed on the uncontrolled quantity. For example, if sourcing voltage then the uncontrolled quantity is current. This is essntially designed to stop you frying your device under test.
To set a compliance limit, use the following methods:
smu.setVoltageLimit(5.0); // 5 V voltage limit
smu.setCurrentLimit(100e-3); // 100 mA current limit
or both together:
smu.setLimits(5.0, 100e-3);
You can also check the compliance limit by use of:
double voltageLimit = smu.getVoltageLimit();
double currentLimit = smu.getCurrentLimit();
Another parameter that you may want to tune on your SMU is the integration time. This is essentially the amount of time over which the SMU performs a measurement. Longer integration times lead to more precise measurements since they effectively average over any random noise but, obviously, take longer.
To set the integration time, in seconds, use:
smu.setIntegrationTime(20e-3); // 20 ms
If only discrete options are available, the closest option is chosen.
You can also check the currently used integration time by use of:
double integrationTime = smu.getIntegrationTime();
An SMU provides you with two sets of terminals: "force" and "sense". This allows you to source with one whilst measuring with the other, allowing you to perform four-probe measurements. To enable or disable this functionality use:
smu.setFourProbeEnabled(true); // Use four-wire measurements
smu.setFourProbeEnabled(false); // Use two-wire measurements
To check which it is using:
boolean fourProbe = smu.isFourProbeEnabled();
Some SMUs have terminals both on the front and on the back. To select which set to use, call the following:
smu.setTerminals(Terminals.FRONT) // Front
smu.setTerminals(Terminals.REAR) // Rear
To check which terminals the SMU is using:
Terminals used = smu.getTerminals();
You can check what type of terminals are on the front and back (if any) by use of:
TType typeFront = smu.getTerminalType(Terminals.FRONT);
TType typeRear = smu.getTerminalType(Terminals.REAR);
The possible types are:
TType.TRIAX // Triaxial connectors
TType.PHOENIX // Phoenix connectors
TType.BNC // BNC/Coaxial connectors
TType.BANANA // Banana plug connectors
TType.NONE // Terminals do not exist
Most SMUs offer some means of averaging over a certain sample number per measurement. In Keithley units this is often referred to as filtering. When averaging there are two parameters to consider: the average type and the average count.
For type all SMU drivers will allow you to specify either a regular mean or median or a moving mean or median, or no averaging. This can be chosen by use of:
smu.setAverageMode(AMode.NONE);
smu.setAverageMode(AMode.MEAN_REPEAT);
smu.setAverageMode(AMode.MEDIAN_REPEAT);
smu.setAverageMode(AMode.MEAN_MOVING);
smu.setAverageMode(AMode.MEDIAN_MOVING);
You can also check which mode is being used by use of:
AMode mode = smu.getAverageMode();
The averaging count is how many samples are used per measurement using the
averaging mode (if the mode is set to AMode.NONE
then no averaging will occur
and only 1 sample will be used regardless). This can be set by use of:
smu.setAverageCount(15); // Average over 15 measurements
smu.setAverageCount(3); // Average over 3 measurements
This value can be checked by use of:
int count = smu.getAverageCount();
To set both at once use:
smu.setAveraging(AMode.MEAN_REPEAT, 15);
You can use an SMU as simply a voltmeter or ammeter by setting it to source 0 of the opposite quantity. For example, to measure voltage, set the SMU to source 0 Amps:
smu.setCurrent(0.0);
smu.turnOn();
double voltage = smu.getVoltage(); // Voltage reading as voltmeter
You can also transform an SMU into a VMeter
or IMeter
object like so:
VMeter meter = smu.asVMeter();
IMeter meter = smu.asIMeter();
This will configure the SMU accordingly and return itself as a VMeter
or
IMeter
object, so your code now only considers it to be a voltmeter or ammeter
respectively (ie the returned meter
object will only be able to measure
voltage or current respectively).
In this example, we want to sweep voltage on channel A of a Keithley K2612B SMU (which has two channels). At each step we want to record the current being supplied by channel A and the voltage picked up by channel B.
public class Main {
public static void main(String[] args) throws Exception {
// Connect to the SMU
K2612B keithley = new K2612B(new TCPIPAddress("192.168.0.2"));
// Get both channels from it
SMU channelA = keithley.get(SMU.class, 0);
SMU channelB = keithley.get(SMU.class, 1);
// Set them both to source 0 volts and amps respectively
channelA.setVoltage(0.0);
channelB.setCurrent(0.0);
// Use auto ranging on both channels
channelA.useAutoRanges();
channelB.useAutoRanges();
// Enable both channels
channelA.turnOn();
channelB.turnOn();
// Loop through generated list of voltages
for (double voltage : Range.linear(0, 60)) {
// Source voltage on channel A
channelA.setVoltage(voltage);
// Wait 0.5 seconds (delay time)
Util.sleep(500);
// Measure current on channel A and voltage on channel B
double current = channelA.getCurrent();
double voltage = channelB.getVoltage();
// Output values to the terminal
System.out.printf("I = %e A, V = %e V%n", current, voltage);
}
// Turn off both channels
channelA.turnOff();
channelB.turnOff();
}
}
fun main() {
// Connect to the SMU
val keithley = K2612B(TCPIPAddress("192.168.0.2"))
// Get both channels from it
val channelA = keithley.getSMU(0)
val channelB = keithley.getSMU(1)
// Set them both to source 0 volts and amps respectively
channelA.voltage = 0.0
channelB.current = 0.0
// Use auto ranging on both channels
channelA.useAutoRanges()
channelB.useAutoRanges()
// Enable both channels
channelA.turnOn()
channelB.turnOn()
// Loop through generated list of voltages
for (voltage in Range.linear(0, 60)) {
// Source voltage on channel A
channelA.voltage = voltage
// Wait 0.5 seconds (delay time)
Util.sleep(500)
// Measure current on channel A and voltage on channel B
val current = channelA.current
val voltage = channelB.voltage
// Output values to the terminal
println("I = %e A, V = %e V".format(current, voltage))
}
// Turn off both channels
channelA.turnOff()
channelB.turnOff()
}
def main():
# Connect to the SMU
keithley = K2612B(TCPIPAddress("192.168.0.2"))
# Get both channels from it
channelA = keithley.getSMU(0)
channelB = keithley.getSMU(1)
# Set them both to source 0 volts and amps respectively
channelA.setVoltage(0.0)
channelB.setCurrent(0.0)
# Use auto ranging on both channels
channelA.useAutoRanges()
channelB.useAutoRanges()
# Enable both channels
channelA.turnOn()
channelB.turnOn()
# Loop through generated list of voltages
for voltage in Range.linear(0, 60):
# Source voltage on channel A
channelA.setVoltage(voltage)
# Wait 0.5 seconds (delay time)
Util.sleep(500)
# Measure current on channel A and voltage on channel B
current = channelA.getCurrent()
voltage = channelB.getVoltage()
# Output values to the terminal
print("I = %e A, V = %e V" % (current, voltage))
# Turn off both channels
channelA.turnOff()
channelB.turnOff()
main()
- Getting Started
- Object Orientation
- Choosing a Language
- Using JISA in Java
- Using JISA in Python
- Using JISA in Kotlin
- Exceptions
- Functions as Objects
- Instrument Basics
- SMUs
- Thermometers (and old TCs)
- PID and Temperature Controllers
- Lock-Ins
- Power Supplies
- Pre-Amplifiers
- Writing New Drivers