This page was generated from docs/examples/driver_examples/Qcodes example with Rohde Schwarz RTO 1000 series Oscilloscope.ipynb. Interactive online version: .
QCoDeS Example with Rohde Schwarz RTO 1000 Series Oscilloscope¶
[1]:
%matplotlib notebook
from qcodes.instrument_drivers.rohde_schwarz import RohdeSchwarzRTO1000
from qcodes.measure import Measure
from qcodes.plots.qcmatplotlib import MatPlot
[2]:
# Select your scope based on its ip address
# rto = RTO1000('rto', 'TCPIP0::172.20.3.86::inst0::INSTR')
rto = RohdeSchwarzRTO1000("rto", "TCPIP0::192.168.0.3::inst0::INSTR", model="RTO1024")
Connected to: Rohde&Schwarz RTO (serial:1316.1000k24/400376, firmware:3.70.1.0) in 0.06s
[3]:
# Before we do anything, let's make sure that the instrument is in a clean state
#
# WARNING: This resets the instrument. Only execute this cell if you are sure about it!
rto.reset()
[4]:
# The display should be set to 'remote' for better performance regarding data acquisition
# Most of the time, however, we'd like to look at the oscilloscope to see data
# and therefore set it to 'view'
rto.display("view")
[ ]:
# To get an overview of all instrument settings, print_readable_sanpshot is great
rto.print_readable_snapshot(update=True)
A signal to record¶
For this tutorial, we record a 100 kHz sine wave with a peak-to-peak amplitude of 100 mV and an offset of 10 mV.
Input settings¶
Our waveform generator outputs 50 Ohm, so we better set the input coupling to DC 50 Ohm as well. And turn on channel 1.
[5]:
rto.ch1.coupling(
"DC"
) # 'DC' means DC 50 Ohm, 'DCLimit' means DC 1 MOhm, 'AC' means AC 1 MOhm.
rto.ch1.state("ON")
Triggering¶
Let us set up an edge trigger on channel 1 with a trigger level of 25 mV.
[6]:
rto.trigger_source("CH1")
rto.trigger_type("EDGE")
rto.trigger_edge_slope("NEG")
rto.trigger_level(0.025)
Acquisition pt. 1 (running continuously)¶
The oscilloscope can run continuously or acquire a fixed number of times (or of course not run at all).
[7]:
rto.run_cont() # run continuously
Horizontal settings¶
We want to see one period of the sine.
[8]:
rto.timebase_range(1 / 100e3)
rto.timebase_position(5e-6)
Vertical settings¶
We of course want the sine wave to fully occupy the oscilloscope screen.
[9]:
# This is EXACTLY matching the waveform...
rto.ch1.range(0.1)
rto.ch1.offset(0)
[10]:
# ... but we increase it a bit due to noise
rto.ch1.range(0.11)
Acquisition pt. 2 (averaging)¶
To average on the scope, you must activate the averaging arithmetics for the relevant channel.
The averaging takes place irrespective of run mode. Here, we perform 1000 averages and then stop the acquisition by acquiring NxSINGLE shots.
If you average in continuous acquisition mode, you get a running average of the latest num_acquisition
scope shots.
[11]:
# Let's do 1000 averages of our sine wave
rto.num_acquisitions(1000)
rto.ch1.arithmetics("AVERAGE") # other options: 'ENVELOPE' and 'OFF'
rto.run_single() # and perform a single run.
[12]:
# To avoid running average effects, we reset the aqcuisition to "normal" mode
rto.num_acquisitions(1)
rto.ch1.arithmetics("OFF")
rto.run_cont()
Reading out the trace - RUN CONT¶
[13]:
# Before making a serious recording, consider whether you want 8 bit or 16 bit resolution
# This option may not be available on all scopes
rto.high_definition_state("ON") # 'ON' -> 16 bit, 'OFF' -> 8 bit
[14]:
##########################
# A NOTE ABOUT BANDWIDTH #
##########################
# In non-high definition state, each channel has its own bandwidth, that may either be
# 'FULL', 'B800', 'B200', or 'B20', where the numbers correspond to a bandwidth limit
# in MHz. In high defition mode, a global bandwidth limit is used.
rto.high_definition_bandwidth(1e9)
[15]:
# Next, the trace must be prepared. This ensures that all settings are correct
rto.ch1.trace.prepare_trace()
[16]:
# Now make a measurement of the trace and display it
data_hd = Measure(rto.ch1.trace).run()
plot = MatPlot(data_hd.arrays["trace"])
DataSet:
location = 'data/2018-12-21/#003_{name}_16-21-28'
<Type> | <array_id> | <array.name> | <array.shape>
Measured | trace | trace | (100000,)
acquired at 2018-12-21 16:21:29
[17]:
# Compare this to the 8 bit version:
rto.high_definition_state("OFF")
rto.ch1.trace.prepare_trace()
data_ld = Measure(rto.ch1.trace).run()
plot = MatPlot(data_ld.arrays["trace"])
DataSet:
location = 'data/2018-12-21/#004_{name}_16-21-38'
<Type> | <array_id> | <array.name> | <array.shape>
Measured | trace | trace | (100000,)
acquired at 2018-12-21 16:21:39
Reading out the trace - RUN Nx SINGLE¶
Oftentimes it is desirable to read out an averaged trace. The driver makes sure that the acqusition has completed before asking for the trace.
For this example, we apply white noise with a 100 mV peak-to-peak amplitude and no offset.
[18]:
# to see averaging effects, we make the time base long
rto.timebase_range(0.1)
[19]:
rto.ch1.trace.prepare_trace()
[20]:
rto.num_acquisitions(10)
rto.ch1.arithmetics("AVERAGE") # other options: 'ENVELOPE' and 'OFF'
rto.run_single() # and perform a single run. NOTE: YOU MUST CALL THIS AS THE LAST THING BEFORE GETTING THE TRACE!!!
[21]:
data_avgd = Measure(rto.ch1.trace).run()
plot = MatPlot(data_avgd.arrays["trace"])
DataSet:
location = 'data/2018-12-21/#005_{name}_16-21-58'
<Type> | <array_id> | <array.name> | <array.shape>
Measured | trace | trace | (1000000,)
acquired at 2018-12-21 16:22:07
[ ]:
# We can see the averaging effect by increasing the number of averages
rto.num_acquisitions(500)
rto.ch1.arithmetics("AVERAGE") # other options: 'ENVELOPE' and 'OFF'
rto.run_single() # and perform a single run. NOTE: YOU MUST CALL THIS AS THE LAST THING BEFORE GETTING THE TRACE!!!
data_avgd = Measure(rto.ch1.trace).run()
plot = MatPlot(data_avgd.arrays["trace"])
Measurements¶
Start 1 of the 8 mesurements
[23]:
import time
def do_measurement(rto, nr_measurements, nr_samples):
"""
Will clean prevous measurement en start a new one
Args:
rto: scope driver object
nr_measurements: number of used/enabled measurements (up to 8)
nr_samples: minimal number of samples before the measurement will stop
"""
# Clear the prevous mesurement
for meas_ch in range(1, nr_measurements + 1):
rto.submodules[f"meas{meas_ch}"].clear()
rto.opc()
rto.run_continues()
# Check if measurement is running
if rto.is_acquiring() is False:
raise RuntimeError("Cannot start measuremet; scope is not trigged")
# Wait for the scope to be ready
while rto.submodules[f"meas{nr_measurements}"].event_count() < 10:
time.sleep(0.1)
rto.opc()
## Actual measurement
for meas_ch in range(1, nr_measurements + 1):
rto.submodules[f"meas{meas_ch}"].clear()
while rto.submodules[f"meas{nr_measurements}"].event_count() < nr_samples:
time.sleep(0.1)
rto.stop_opc()
[27]:
rto.timebase_range(1.5 * (1 / 100e3)) # Need a bit more than 1 period
rto.ch1.range(0.11) # Need a bit more the 100mV
# Configure measurement 1 to determine frequency
rto.meas1.enable("ON")
rto.meas1.source("C1W1") # See rto.meas1.sources for more options
rto.meas1.category("AMPTime") # See rto.meas1.categories for more options
rto.meas1.main("FREQuency") # See rto.meas1.meas_type for more options
rto.meas1.clear()
rto.meas1.statistics_enable("ON")
rto.run_continues()
# start measurement
print("Wait for results")
do_measurement(rto, 1, 500)
actualFq = rto.meas1.result_avg() * 1e-3
print(f"Ch: 1; frequency: {actualFq:.0f}kHz")
Wait for results
Ch: 1; frequency: 100kHz
[26]:
print(rto.meas1.sources)
<Enum: {'D13', 'Z2I4', 'C4W2', 'Z1I3', 'TRK4', 'SG2TL1', 'Z1I2', 'D12', 'SBUS3', 'Z1I1', 'Z2I3', 'R1', 'M1', 'C2W1', 'D10', 'SBUS4', 'Z2V1', 'R4', 'D0', 'D2', 'D7', 'M4', 'R2', 'R3', 'C2W3', 'D8', 'M2', 'D4', 'D6', 'TRK2', 'TRK8', 'Z1V3', 'Z2V4', 'C3W1', 'D3', 'Z2V3', 'TRK5', 'TRK1', 'SG1TL2', 'C4W3', 'SG3TL1', 'Z1I4', 'SG3TL2', 'C1W3', 'SG2TL2', 'C2W2', 'Z2I1', 'SG4TL2', 'C1W1', 'SG4TL1', 'Z2V2', 'C3W2', 'D1', 'TRK3', 'TRK6', 'C3W3', 'Z2I2', 'C1W2', 'D11', 'Z1V2', 'SBUS2', 'Z1V1', 'D9', 'TRK7', 'D5', 'SG1TL1', 'Z1V4', 'C4W1', 'D15', 'D14', 'M3', 'SBUS1'}>