-
Notifications
You must be signed in to change notification settings - Fork 9
Logging
Often you will want to create some sort of logging feature for your experiment. For example, if you have a cryostat you may wish to keep a running log of temperature, heater power, flow rate etc. To do this, JISA
provides multiple tools.
The first problem you might imagine when taking a large number of data-points is that we could run out of memory. When using a ResultList
object, each "row" is stored in memory. To counter this, we use instead a ResultStream
object which directly writes the data to a file instead of holding it in memory.
Using a ResultStream
is easy as it is almost identical to a ResultList
, the only difference is you need to specify where to save the file when you create it:
Java
Column<Double> TIME = Column.ofDoubles("Time", "s");
Column<Double> TEMP = Column.ofDoubles("Temperature", "K");
Column<Double> HEAT = Column.ofDoubles("Heater", "%");
ResultTable stream = new ResultStream("file.csv", TIME, TEMP, HEAT);
Python
TIME = Column.ofDoubles("Time", "s")
TEMP = Column.ofDoubles("Temperature", "K")
HEAT = Column.ofDoubles("Heater", "%")
stream = ResultStream("file.csv", TIME, TEMP, HEAT)
Now you will only be limited by how much space you have on your hard-drive, which is likely to be vastly more than you have available in RAM.
When you are finished making additions and changes to the ResultStream
you can release any resources it's holding open (ie the file) by using:
stream.close();
Calling close()
on a ResultStream
object causes it to become read-only and cannot be undone.
To take a measurement periodically, what we essentially want is a piece of code to be run periodically independently of the rest of the code. To achieve this, JISA
provides the RTask
class. RTask
works very similarly to Thread
in that you provide it code to run and then start it, but differs in the fact that you also need to specify how often you want it to run.
To create an RTask
you do the following:
Java
RTask task = new RTask(interval, t -> {
// Code to run periodically goes here
});
Kotlin
val task = RTask(interval) { t ->
// Code to run periodically goes here
}
Python
def onTask(t: RTask):
# Code to run periodically goes here
...
task = RTask(interval, onTask)
where interval
is the interval in milliseconds.
After creating the RTask
you can set it going by use of:
task.start();
and stop it with:
task.stop();
You can check whether it is currently running or not:
boolean running = task.isRunning();
and get how much time has passed since it was started in milliseconds or seconds:
int count = task.getCount();
long milliSeconds = task.getMSecFromStart();
double seconds = task.getSecFromStart();
These are all also available from inside the repeating task lambda itself via
the t
argument provided (i.e., in our above examples, t
is of type RTask
).
Now let's look at a complete example:
Java
public class Main {
private final static Column<Double> TIME = Column.ofDoubles("Time", "s");
private final static Column<Double> TEMP = Column.ofDoubles("Temperature", "K");
private final static Column<Double> HEAT = Column.ofDoubles("Heater", "%");
private static RTask logger;
public static void main(String[] args) throws Exception {
// Connect to temperature controller
TC tc = new ITC503(new GPIBAddress(0, 20));
TC.TMeter sensor = tc.getThermometers().get(0);
TC.Heater heater = tc.getHeaters().get(0);
// Create results storage
stream = new ResultStream("file.csv", TIME, TEMP, HEAT);
// Create the repeat-task, but don't start it yet
logger = new RTask(5000, t -> {
stream.addRow(row -> {
row.set(TIME, t.getSecFromStart());
row.set(TEMP, sensor.getTemperature());
row.set(HEAT, heater.getPower());
});
});
}
public static void startLog() {
logger.start();
}
public static void stopLog() {
logger.stop();
}
}
Kotlin
val TIME = Column.ofDoubles("Time", "s");
val TEMP = Column.ofDoubles("Temperature", "K");
val HEAT = Column.ofDoubles("Heater", "%");
val stream = ResultStream("file.csv", TIME, TEMP, HEAT);
val tc = ITC503(new GPIBAddress(0, 20))
val sensor = loop.thermometers[0]
val heater = loop.heaters[0]
val logger = RTask(5000) { t ->
stream.addRow {
row[TIME] = t.secFromStart
row[TEMP] = sensor.temperature
row[HEAT] = heater.power
}
}
fun startLog() {
logger.start();
}
fun stopLog() {
logger.stop();
}
fun main() {
...
}
Python
TIME = Column.ofDoubles("Time", "s");
TEMP = Column.ofDoubles("Temperature", "K");
HEAT = Column.ofDoubles("Heater", "%");
stream = ResultStream("file.csv", TIME, TEMP, HEAT);
tc = ITC503(new GPIBAddress(0, 20))
sensor = loop.getThermometers()[0]
heater = loop.getHeaters()[0]
def log(t: RTask):
stream.mapRow({
TIME: t.getSecFromStart(),
TEMP: sensor.getTemperature(),
HEAT: heater.getPower()
})
logger = RTask(5000, log)
def startLog():
logger.start()
def stopLog():
logger.stop()
In the above example, when Main.startLog()
is called, the code inside the RTask
will be run every 5 seconds (5000 milliseconds). Each time this happens we log the temperature (tc.getTemperature()
) and heater power (tc.getHeaterPower()
) being reported by the temperature controller tc
along with the number of seconds since the log was started by use of logger.getSecFromStart()
.
- 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