This page was generated from docs/examples/writing_drivers/A-ParameterWithSetpoints-Example-with-Dual-Setpoints.ipynb. Interactive online version: Binder badge.

A ParameterWithSetpoints Example with Dual Setpoints

This notebook explains how you can account for dual setpoints using ParameterWithSetpoints. The basics of writing drivers using ParameterWithSetpoints is covered in the notebook named Simple Example of ParameterWithSetpoints.

In this example we consider a dummy instrument that can return a time trace or the discreet Fourier transform (magnitude square) of that trace. The setpoints are accounted for in an easy way.

[1]:
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from typing_extensions import Unpack
import os

import numpy as np

import qcodes.validators as vals
from qcodes.dataset import (
    Measurement,
    initialise_or_create_database_at,
    load_or_create_experiment,
    plot_dataset,
)
from qcodes.instrument import Instrument, InstrumentBaseKWArgs
from qcodes.parameters import Parameter, ParameterWithSetpoints
Logging hadn't been started.
Activating auto-logging. Current session state plus future input saved.
Filename       : /home/runner/.qcodes/logs/command_history.log
Mode           : append
Output logging : True
Raw input log  : False
Timestamping   : True
State          : active
Qcodes Logfile : /home/runner/.qcodes/logs/241118-6640-qcodes.log
[2]:
def timetrace(npts: int, dt: float) -> np.ndarray:
    """
    A very realistic-looking signal
    """
    # freq = 10/(dt*npts)
    # decay = 1/(dt*npts)
    freq = 10
    decay = 1
    time = np.linspace(0, npts * dt, npts, endpoint=False)
    signal = np.exp(-decay * time) * np.sin(2 * np.pi * freq * time)
    noise = 0.1 * np.random.randn(npts)
    return signal + noise
[3]:
class TimeTrace(ParameterWithSetpoints):
    def get_raw(self):
        npts = self.root_instrument.npts()
        dt = self.root_instrument.dt()

        return timetrace(npts, dt)


class Periodogram(ParameterWithSetpoints):
    def get_raw(self):
        tt = self.root_instrument.trace()

        return np.abs(np.fft.fft(tt)) ** 2


class TimeAxis(Parameter):
    def get_raw(self):
        npts = self.root_instrument.npts()
        dt = self.root_instrument.dt()
        return np.linspace(0, dt * npts, npts, endpoint=False)


class FrequencyAxis(Parameter):
    def get_raw(self):
        npts = self.root_instrument.npts()
        dt = self.root_instrument.dt()

        return np.linspace(0, 1 / dt, npts)


class OzzyLowScope(Instrument):
    def __init__(self, name: str, **kwargs: "Unpack[InstrumentBaseKWArgs]"):
        super().__init__(name, **kwargs)

        self.npts = self.add_parameter(
            name="npts",
            initial_value=500,
            label="Number of points",
            get_cmd=None,
            set_cmd=None,
        )

        self.dt = self.add_parameter(
            name="dt",
            initial_value=1e-3,
            label="Time resolution",
            unit="s",
            get_cmd=None,
            set_cmd=None,
        )

        self.time_axis = self.add_parameter(
            name="time_axis",
            label="Time",
            unit="s",
            vals=vals.Arrays(shape=(self.npts,)),
            parameter_class=TimeAxis,
        )

        self.freq_axis = self.add_parameter(
            name="freq_axis",
            label="Frequency",
            unit="Hz",
            vals=vals.Arrays(shape=(self.npts,)),
            parameter_class=FrequencyAxis,
        )

        self.trace = self.add_parameter(
            name="trace",
            label="Signal",
            unit="V",
            vals=vals.Arrays(shape=(self.npts,)),
            setpoints=(self.time_axis,),
            parameter_class=TimeTrace,
        )

        self.periodogram = self.add_parameter(
            name="periodogram",
            label="Periodogram",
            unit="V^2/Hz",
            vals=vals.Arrays(shape=(self.npts,)),
            setpoints=(self.freq_axis,),
            parameter_class=Periodogram,
        )
[4]:
osc = OzzyLowScope("osc")
[5]:
tutorial_db_path = os.path.join(os.getcwd(), "tutorial_doND.db")
initialise_or_create_database_at(tutorial_db_path)
load_or_create_experiment(experiment_name="tutorial_exp", sample_name="no sample")
[5]:
tutorial_exp#no sample#1@/home/runner/work/Qcodes/Qcodes/docs/examples/writing_drivers/tutorial_doND.db
-------------------------------------------------------------------------------------------------------

Measurement 1: Time Trace

[6]:
timemeas = Measurement()
timemeas.register_parameter(osc.trace)

osc.dt(0.001)

with timemeas.run() as datasaver:
    datasaver.add_result((osc.trace, osc.trace.get()))

dataset = datasaver.dataset
Starting experimental run with id: 1.
[7]:
_ = plot_dataset(dataset)
../../_images/examples_writing_drivers_A-ParameterWithSetpoints-Example-with-Dual-Setpoints_8_0.png
[8]:
osc.dt(0.01)  # make the trace 10 times longer

with timemeas.run() as datasaver:
    datasaver.add_result((osc.trace, osc.trace.get()))

dataset = datasaver.dataset
Starting experimental run with id: 2.
[9]:
_ = plot_dataset(dataset)
../../_images/examples_writing_drivers_A-ParameterWithSetpoints-Example-with-Dual-Setpoints_10_0.png

Measurement 2: Periodogram

[10]:
freqmeas = Measurement()
freqmeas.register_parameter(osc.periodogram)

osc.dt(0.01)

with freqmeas.run() as datasaver:
    datasaver.add_result((osc.periodogram, osc.periodogram.get()))

dataid = datasaver.dataset
Starting experimental run with id: 3.
[11]:
axs, cbax = plot_dataset(dataset)
aa = axs[0]
aa.set_yscale("log")
../../_images/examples_writing_drivers_A-ParameterWithSetpoints-Example-with-Dual-Setpoints_13_0.png

Just for the fun of it, let’s make a measurement with the averaged periodogram.

[12]:
no_of_avgs = 100

with freqmeas.run() as datasaver:
    temp_per = osc.periodogram()

    for _ in range(no_of_avgs - 1):
        temp_per += osc.periodogram()

    datasaver.add_result(
        (osc.periodogram, temp_per / no_of_avgs), (osc.freq_axis, osc.freq_axis.get())
    )

dataset = datasaver.dataset
Starting experimental run with id: 4.
[13]:
axs, cbax = plot_dataset(dataset)
aa = axs[0]
aa.set_yscale("log")
../../_images/examples_writing_drivers_A-ParameterWithSetpoints-Example-with-Dual-Setpoints_16_0.png

Measurement 3: 2D Sweeping

[14]:
meas = Measurement()
meas.register_parameter(osc.npts)
meas.register_parameter(osc.trace, setpoints=[osc.npts], paramtype="numeric")

with meas.run() as datasaver:
    osc.dt(0.001)

    for npts in [200, 400, 600, 800, 1000, 1200]:
        osc.npts(npts)
        datasaver.add_result((osc.trace, osc.trace.get()), (osc.npts, osc.npts()))

dataset = datasaver.dataset
Starting experimental run with id: 5.
[15]:
_ = plot_dataset(dataset)
../../_images/examples_writing_drivers_A-ParameterWithSetpoints-Example-with-Dual-Setpoints_19_0.png
[ ]:

[ ]: