-
Notifications
You must be signed in to change notification settings - Fork 9
PID
A common type of laboratory instrumentation is a PID controller — which tries to stably control some "input" quantity by adjusting an "output" quantity. The most common for of this is a temperature controller, where the input quantity is temperature, and the output is often something like heater power.
In JISA
PID controllers are represented by the PID
interface. Extending from
this interface is the TC
interface, specifically for temperature controlling
PID instruments.
- Basics of Inputs, Outputs and Loops
- Loop Set-Points and Quantities
- Loop PID Values and Manual Output
- PID Zoning
- Ramping
- Temperature Controllers
Each PID
instrument will have a number of three different "parts" in the form
of PID.Input
, PID.Ouput
, and PID.Loop
objects. A PID.Input
represents an
input quantity (i.e. the value we want to control), whereas a PID.Output
represents an output quantity (i.e. what we want the PID
controller to change
to control the PID.Input
value).
To extract these, you can use the relevant get...(...)
methods like so:
PID pid = new Driver(new Address(...));
List<PID.Input> inputs = pid.getInputs();
List<PID.Output> outputs = pid.getOutputs();
List<PID.Loop> loops = pid.getLoops();
Each PID.Loop
can therefore have a single PID.Input
object and a single
PID.Output
object to configure the PID controller. To see which are currently
configured as such, you can call getInput()
and getOutput()
like so:
PID pid = new Driver(new Address(...));
PID.Loop loop = pid.getLoops().get(0); // Get the first loop
PID.Input input = loop.getInput(); // Get the input used for this loop
PID.Output output = loop.getOutput(); // Get the output used for this loop
The PID controller can also be configured to use a different input and/or output
by use of the set...(...)
methods like so
loop.setInput(input);
loop.setOutput(output);
However, care must be taken here, as different PID controllers have different
restrictions regarding which inputs and outputs can be used for which loops.
Therefore, each PID.Loop
object provides getAvailable...()
methods like so:
List<PID.Input> inputs = loop.getAvailableInputs();
List<PID.OUtput> outputs = loop.getAvailableOutputs();
which will return lists of the various inputs and outputs that can be used for that loop. For instance, to configure the first loop to use its first available input and output:
PID pid = new Driver(new Address(...)); // Connect to instrument
// Get first loop, and first available input and output
PID.Loop loop = pid.getLoops().get(0);
PID.Input input = loop.getAvailableInputs().get(0);
PID.Output output = loop.getAvailableOutputs().get(0);
// Configure loop to use the extracted input and output
loop.setInput(input);
loop.setOutput(output);
Controlling a PID control loop is therefore achieved by using its corresponding
PID.Loop
object. For instance, its set-point can be controlled and checked like so:
loop.setSetPoint(100.0);
double setPoint = loop.getSetPoint();
You can query its input and output values like so:
double inputValue = loop.getInput().getValue();
double outputValue = loop.getOutput().getValue();
You can configure/query the PID values of a loop by use of:
// All at once
loop.setPIDValues(p, i, d);
// Separately
loop.setPValue(p);
loop.setIValue(i);
loop.setDValue(d);
// Query
double p = loop.getPValue();
double i = loop.getIValue();
double d = loop.getDValue();
Whether the loop should use its PID values to control its output, or whether it just output some manually defined quantity can be chosen by using
// Sets its manual value to 10.0
loop.setManualOutputValue(10.0);
// true: use PID control, false: use manual value
loop.setPIDEnabled(true/false);
You can further configure a PID loop to use a table of PID values corresponding to different regions of the set-point value. For instance, if the input was temperature then you may want something like
Min [K] | Max [K] | P | I | D | Limit [%] |
---|---|---|---|---|---|
0.0 | 100.0 | 10 | 5 | 0 | 50 |
100.0 | 200.0 | 20 | 8 | 1 | 100 |
200.0 | 300.0 | 30 | 9 | 2 | 100 |
where "Limit [%]" is the percentage limit to impose upon the PID output for a
given range. To configure this, we will need to create a PID.Zone
object for
each line and pass them all to setPIDZones(...)
like so:
loop.setPIDZones(
new PID.Zone(0 , 100, 10, 5, 0, 50),
new PID.Zone(100, 200, 20, 8, 1, 100),
new PID.Zone(200, 300, 30, 9, 2, 100)
);
Then to enable the use of the table, use:
loop.setPIDZoningEnabled(true);
To disable it, and return to the single set of PID values, use:
loop.setPIDZoningEnabled(false);
Most (if not all) PID controllers offer a means of ramping their controlled quantity at a specified maximum rate (i.e. "go to this value at a constant rate of x" as opposed to "go to this value as quickly as possible"). To access this feature through the PID.Loop
interface you can use the following methods:
// Methods to set
loop.setRampRate(value);
loop.setRampEnabled(true/false);
// Methods to query
double rate = loop.getRampRate();
boolean ramping = loop.isRampEnabled();
For instance, to enable ramping for a temperature controller at 1.0 K/min:
loop.setRampRate(1.0);
loop.setRampEnabled(true);
The ramp can then later be disabled by using:
loop.setRampEnabled(false);
For PID controllers that are specifically temperature controllers, they are
represented using the TC
interface. This extends from the PID
interface, so
the types are interchangeable.
The purpose of the TC
interface is simply to add more TC-specific method names
to the controllers, its inputs and outputs. For instance, thermometer inputs
implement the TMeter
interface, so they can be treated as individual
thermometers. They also include the extra getThermometers()
and getHeaters()
methods to specifically return only the inputs/outputs of that given type.
Here's some example code:
Java
// Accessing individual input/output components
TC tc = new Driver(new Address(...));
TC.Heater heater1 = tc.getHeaters().get(0);
TMeter sensor1 = tc.getThermometers().get(0);
double temperature = sensor1.getTemperature();
double power = heater1.getPower();
// Accessing first loop and first useable thermometer and heater
TC.Loop loop1 = tc.getLoops().get(0);
TC.Input thermometer = loop1.getAvailableThermometers().get(0);
TC.Output heater = loop1.getAvailableHeaters().get(0)
// Configure first loop
loop1.setInput(thermometer);
loop1.setOutput(heater);
loop1.setPIDValues(70, 30, 0);
// Go to 150 K
loop1.setTemperature(150);
loop1.setPIDEnabled(true);
Kotlin
// Accessing individual input/output components
val tc = Driver(Address(...))
val heater1 = tc.heaters[0]
val sensor1 = tc.thermometers[0]
val temperature = sensor1.temperature
val power = heater1.power
// Accessing first loop and first useable thermometer and heater
val loop1 = tc.loops.first() // can use first() instead of [0]
val thermometer = loop1.availableThermometers.first()
val heater = loop1.availableHeaters.first()
// Configuring loop
loop1.input = thermometer
loop1.output = heater
loop1.P = 70.0
loop1.I = 30.0
loop1.D = 0.0
// Go to 150.0 K
loop1.temperature = 150.0
loop1.isPIDEnabled = true
Python
# Accessing individual input/output components
tc = Driver(Address(...))
heater1 = tc.getHeaters()[0]
sensor1 = tc.getThermometers()[0]
temperature = sensor1.getTemperature()
power = heater1.getPower()
# Accessing first loop and first useable thermometer and heater
loop1 = tc.getLoops()[0]
thermometer = loop1.getAvailableThermometers()[0]
heater = loop1.getAvailableHeaters()[0]
# Configuring loop
loop1.setInput(thermometer)
loop1.setOutput(heater)
loop1.setPIDValues(70.0, 30.0, 0.0)
# Go to 150.0 K
loop1.setTemperature(150.0)
loop1.setPIDEnabled(True)
- 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