Qcodes example with Swabian Instruments Time Tagger¶
[1]:
from qcodes_contrib_drivers.drivers.SwabianInstruments.Swabian_Instruments_Time_Tagger import TimeTagger
The driver wraps the TimeTagger
python API provided by Swabian Instruments (download here). As the API is very object-oriented, the QCoDeS driver is fairly dynamic in that, for each new measurement type, a new InstrumentChannel
of the corresponding type is added to the main instrument. These channels have parameters which correspond to the instantiation arguments of the API objects, as well as gettable parameters which
correspond to the measured data.
For more information on the driver design, see the SwabianInstruments/Swabian_Instruments_Time_Tagger.py
module docstring.
[2]:
tagger = TimeTagger('tagger')
Connected to: Swabian Instruments Time Tagger 20 (serial:1234567AB8, firmware:TT-20, FW4, OK 3.1) in 1.40s
Measurements¶
The tagger
instrument has submodules (channel lists) for each type of measurement or virtual channel that is implemented and which are at first empty:
[3]:
tagger.submodules
[3]:
{'synchronized_measurements': <TimeTaggerSynchronizedMeasurements: tagger_synchronized_measurements of TimeTagger: tagger>,
'correlation_measurements': ChannelList(<TimeTagger: tagger>, CorrelationMeasurement, []),
'combiner_virtual_channels': ChannelList(<TimeTagger: tagger>, CombinerVirtualChannel, []),
'count_rate_measurements': ChannelList(<TimeTagger: tagger>, CountRateMeasurement, []),
'histogram_log_bins_measurements': ChannelList(<TimeTagger: tagger>, HistogramLogBinsMeasurement, []),
'counter_measurements': ChannelList(<TimeTagger: tagger>, CounterMeasurement, []),
'coincidence_virtual_channels': ChannelList(<TimeTagger: tagger>, CoincidenceVirtualChannel, [])}
To add for example a new Correlation
measurement, use the automatically generated helper method add_correlation_measurement
, which adds a CorrelationMeasurement
channel to the correlation_measurements
channel list.
[4]:
correlation = tagger.add_correlation_measurement()
correlation
[4]:
<CorrelationMeasurement: tagger_correlation_1 of TimeTagger: tagger>
At first, the API object is not yet instantiated because arguments are missing:
[5]:
try:
correlation.api
except RuntimeError as err:
print(err)
The following parameters need to be initialized first: channels
Instead, we must provide the arguments by setting the parameters (note that units are the same as the API driver, so usually picoseconds):
[6]:
correlation.channels([1, 2])
correlation.binwidth(1)
correlation.n_bins(4_000_000)
correlation.api
[6]:
<TimeTagger.Correlation; proxy of <Swig Object of type 'Correlation *' at 0x00000260E600A630> >
We can now start measuring (we switch on the test signal to have a meaningful output):
[7]:
tagger.set_test_signal([1, 2], state=True)
correlation.start_for(5 * 10 ** 12, clear=True)
correlation.wait_until_finished()
# The capture_duration parameter is inherited by all Measurement classes
print(correlation.capture_duration()) # ps
correlation.data_normalized()
5000000000000
[7]:
array([0., 0., 0., ..., 0., 0., 0.])
Once a measurement is not needed anymore, it may also be removed from the tagger object:
[8]:
tagger.correlation_measurements.remove(correlation)
Virtual Channels¶
The second type of API object that is implemented are virtual channels. These are objects that behave like a physical channel (i.e., they return time stamps of clicks), but can process events from multiple physical channels (such as aggregation or coincidence counting).
To reproduce the API documentation’s example, do the following:
[9]:
tagger.set_test_signal([1, 2], True)
vc = tagger.add_combiner_virtual_channel()
vc.channels([1, 2])
rate = tagger.add_count_rate_measurement()
rate.channels([1, 2, vc.get_channel()])
rate.start_for(int(1e12), clear=True)
rate.wait_until_finished()
print(rate.data())
[ 815477. 815477. 1630954.]
Synchronized measurements¶
The TimeTagger
driver also implements the SynchronizedMeasurements
functionality of the API. This is an object that helps to synchronize multiple different measurements using the same physical tagger. It can either be used by passing the virtual tagger return by its get_tagger()
method to the measurement, or by calling the register_measurement()
and unregister_measurement()
methods:
[10]:
tagger.synchronized_measurements
[10]:
<TimeTaggerSynchronizedMeasurements: tagger_synchronized_measurements of TimeTagger: tagger>
[11]:
sync_tagger = tagger.synchronized_measurements.api_tagger
sync_correlation = tagger.add_correlation_measurement(api_tagger=sync_tagger)
sync_correlation.channels([1, 2])
sync_count_rate = tagger.add_count_rate_measurement(api_tagger=sync_tagger)
sync_count_rate.channels([1, 2])
Measurements are then controlled by the SynchronizedMeasurements
object.
Note: Currently, the api property of the measurements and virtual channels needs to be accessed once before using the measurement control methods of the SynchronizedMeasurements object. This is because the Time Tagger API object is only instantiated once the api cached property is accessed (as parameters need to be initialized for this).
[12]:
sync_correlation.api
sync_count_rate.api
[12]:
<TimeTagger.Countrate; proxy of <Swig Object of type 'Countrate *' at 0x00000260FDF97180> >
[13]:
tagger.synchronized_measurements.start_for(int(1e12), clear=True)
tagger.synchronized_measurements.wait_until_finished()
print(sync_count_rate.data())
[815269. 815269.]
Or, equivalently (note that parameters need to be initialized):
[14]:
correlation = tagger.add_correlation_measurement()
correlation.channels([-1, -2]) # falling flank
count_rate = tagger.add_count_rate_measurement()
count_rate.channels([-1, -2])
tagger.synchronized_measurements.register_measurement(correlation)
tagger.synchronized_measurements.register_measurement(count_rate)
# Perform measurement as usual
tagger.synchronized_measurements.unregister_measurement(correlation)
tagger.synchronized_measurements.unregister_measurement(count_rate)
Using this syntax, the api
property is automatically accessed by the register_measurement
method and the above note does not apply.
[15]:
# Convenience methods to clear all channel lists
tagger.remove_all_measurements()
tagger.remove_all_virtual_channels()
tagger.close()