def calculate_tunneling_rate(runids, station=None, exp=None, plot=False):
    meas = Measurement(exp=exp, station=station)
    meas.register_parameter(station.n6705b.VTUN, )
    meas.register_custom_parameter("Tunneling_Gradient",
                                   setpoints=(station.n6705b.VTUN, ),
                                   unit="V/S")
    meas.register_custom_parameter("runid")

    grads = []
    tun_vs = []
    for id in runids:
        data = load_by_id(id)
        sweep_data = data.get_parameter_data()
        x = sweep_data['dmm_VOUT']['time']
        y = sweep_data['dmm_VOUT']['dmm_VOUT']
        tun_v = sweep_data['n6705b_VTUN']['n6705b_VTUN'][0]
        # y = mx + b
        m, b = polyfit(x, y, 1)
        grads.append(m)
        tun_vs.append(tun_v)
        if plot:
            plt.figure()
            plt.plot(x, y)
            y2 = x * m + b
            plt.plot(x, y2)
            plt.ylabel("vout [V]")
            plt.xlabel("time [s]")
            plt.show()

    with meas.run() as datasaver:
        for m, tv, run in zip(grads, tun_vs, runids):
            datasaver.add_result((station.n6705b.VTUN, tv),
                                 ("Tunneling_Gradient", m), ("runid", run))
Example #2
0
def setup_measurement(dataset: OldDataSet,
                      exp: Optional['Experiment'] = None) -> Measurement:
    """
    Register parameters for all :class:.`DataArrays` in a given QCoDeS legacy dataset

    This tries to infer the `name`, `label` and `unit` along with any `setpoints`
    for the given array.

    Args:
        dataset: Legacy dataset to register parameters from.
        exp: experiment that the legacy dataset should be bound to. If
            None the default experiment is used. See the
            docs of :class:`.Measurement` for more details.
    """
    meas = Measurement(exp=exp)
    for arrayname, array in dataset.arrays.items():
        if array.is_setpoint:
            setarrays = None
        else:
            setarrays = [setarray.array_id for setarray in array.set_arrays]
        meas.register_custom_parameter(name=array.array_id,
                                       label=array.label,
                                       unit=array.unit,
                                       setpoints=setarrays
                                       )
    return meas
Example #3
0
def IV_up_ithaco(station, voltages, stanford_gain_V, ithaco_gain_I):

    now = datetime.now()
    # dd/mm/YY H:M:S
    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
    print(dt_string)   


    R_I = 1e4 #The value of the resistor used to measure the current

    print(f'Stanford Gain V ={stanford_gain_V}')
    print(f'Ithaco Gain I ={ithaco_gain_I}')
    print(f'Voltage Max V_max = {voltages[-1]}')

    int_time = 1 #Integration time of the dmm's

    station.dmm1.volt()
    station.dmm1.NPLC(int_time)

    station.dmm2.volt() 
    station.dmm2.NPLC(int_time)

    print(f'Integration time = {int_time*0.02} s')

    station.yoko.output('off')
    station.yoko.source_mode("VOLT")
    station.yoko.output('on')

    station.yoko.voltage.step = 0.1e-6
    station.yoko.voltage.inter_delay = 5e-4

    meas = Measurement()
    
    meas.register_parameter(station.yoko.voltage)
    meas.register_parameter(station.dmm2.volt)
    meas.register_custom_parameter("Current", unit="A")
    meas.register_parameter(station.dmm1.volt, setpoints=("Current",))

    with meas.run() as datasaver:

        for v in voltages:

            station.yoko.voltage(v)

            voltage_meas = station.dmm1.volt()/stanford_gain_V
            current_meas = -1*station.dmm2.volt()/ithaco_gain_I

            datasaver.add_result((station.yoko.voltage,v),
                                (station.dmm2.volt,station.dmm2.volt()),
                                ("Current",current_meas),
                                (station.dmm1.volt,voltage_meas))
        ID_exp = datasaver.run_id

    station.yoko.voltage(0)
    plot_by_id(ID_exp)
def inject_to_target(exp, station, fn_switch, events, target):
    """
    open loop sweep of vref
    """
    # Set the switch state to 'open'
    if not callable(fn_switch):
        raise ValueError("Expecting Switch Function")
    fn_switch("open")
    voltages = {
        "vdd": 0,
        "vfeedback": 0,
        "vdrain": 0,
        "vbias": 0,
        "vref": 0,
        "vtun": 2,
        "vbus": 2
    }
    deps = [
        station.b2962.IDRAIN, station.dmm.VOUT, station.n6705b.VBUS,
        station.n6705b.VFEEDBACK, station.n6705b.VREF, station.n6705b.VTUN,
        station.b2962.VDD, station.b2962.VDRAIN, station.yoko.VBIAS
    ]

    meas = Measurement(exp=exp, station=station)
    meas.register_custom_parameter("time", label="Time", unit="S")
    meas.register_custom_parameter("injection_target",
                                   label="Injection Target",
                                   unit="A")

    meas.add_before_run(lambda: setup(station, voltages), ())
    meas.add_after_run(lambda: all_disable(station), ())

    for p in deps:
        meas.register_parameter(p, setpoints=("time", ))

    with meas.run() as datasaver:
        time.sleep(1)
        start = time.time()
        events.fn_before()
        while (station.b2962.IDRAIN() > target):
            save_list = []
            save_list.append(["time", time.time() - start])
            save_list.append(["injection_target", target])
            for p in deps:
                save_list.append([p, p.get()])

            datasaver.add_result(*save_list)

            time.sleep(events.step)
        runid = datasaver.run_id
    return runid
Example #5
0
def test_datasaver_foul_input(experiment):

    meas = Measurement()

    meas.register_custom_parameter('foul',
                                   label='something unnatural',
                                   unit='Fahrenheit')

    foul_stuff = [qc.Parameter('foul'), set((1, 2, 3))]

    with meas.run() as datasaver:
        for ft in foul_stuff:
            with pytest.raises(ValueError):
                datasaver.add_result(('foul', ft))
Example #6
0
def test_run_loaded_experiment():
    """
    Test that we can resume a measurement after loading by name
    """
    new_experiment("test", "test1")
    exp_loaded = load_experiment_by_name("test", "test1")

    meas = Measurement(exp=exp_loaded)
    meas.register_custom_parameter(name='dummy', paramtype='text')
    with meas.run():
        pass

    with meas.run():
        pass
Example #7
0
def test_nested_measurement(bg_writing):
    meas1 = Measurement()
    meas1.register_custom_parameter('foo1')
    meas1.register_custom_parameter('bar1', setpoints=('foo1', ))

    meas2 = Measurement()
    meas2.register_custom_parameter('foo2')
    meas2.register_custom_parameter('bar2', setpoints=('foo2', ))


    with meas1.run(write_in_background=bg_writing) as ds1, \
            meas2.run(write_in_background=bg_writing) as ds2:
        for i in range(10):
            ds1.add_result(("foo1", i), ("bar1", i**2))
            ds2.add_result(("foo2", 2 * i), ("bar2", (2 * i)**2))

    data1 = ds1.dataset.get_parameter_data()["bar1"]
    assert len(data1.keys()) == 2
    assert "foo1" in data1.keys()
    assert "bar1" in data1.keys()

    assert_allclose(data1["foo1"], np.arange(10))
    assert_allclose(data1["bar1"], np.arange(10)**2)

    data2 = ds2.dataset.get_parameter_data()["bar2"]
    assert len(data2.keys()) == 2
    assert "foo2" in data2.keys()
    assert "bar2" in data2.keys()
    assert_allclose(data2["foo2"], np.arange(0, 20, 2))
    assert_allclose(data2["bar2"], np.arange(0, 20, 2)**2)
Example #8
0
def setup_measurement(dataset: OldDataSet) -> Measurement:
    """
    Register parameters for all DataArrays in a given QCoDeS legacy dataset

    This tries to infer the name, label and unit along with any setpoints
    for the given array.
    """
    meas = Measurement()
    for arrayname, array in dataset.arrays.items():
        if array.is_setpoint:
            setarrays = None
        else:
            setarrays = [setarray.array_id for setarray in array.set_arrays]
        meas.register_custom_parameter(name=array.array_id,
                                       label=array.label,
                                       unit=array.unit,
                                       setpoints=setarrays)
    return meas
def tunnel_to_target(exp, station, fn_switch, voltages, vtun, target):
    """
    open loop sweep of vref
    """
    # Set the switch state to 'open'
    if not callable(fn_switch):
        raise ValueError("Expecting Switch Function")
    fn_switch("close")

    deps = [
        station.dmm.VOUT, station.n6705b.VBUS, station.n6705b.VFEEDBACK,
        station.n6705b.VREF, station.n6705b.VTUN, station.b2962.VDD,
        station.b2962.VDRAIN, station.yoko.VBIAS
    ]

    meas = Measurement(exp=exp, station=station)
    meas.register_custom_parameter("time", label="Time", unit="S")
    meas.register_custom_parameter("tunnel_target",
                                   label="Tunnel Target",
                                   unit="V")

    meas.add_before_run(lambda: setup(station, voltages), ())
    meas.add_after_run(lambda: all_disable(station), ())

    for p in deps:
        meas.register_parameter(p, setpoints=("time", ))

    voltages['vtun'] = vtun
    with meas.run() as datasaver:
        time.sleep(1)
        start = time.time()
        print(station.dmm.VOUT())
        while (station.dmm.VOUT() > target):
            save_list = []
            save_list.append(["time", time.time() - start])
            save_list.append(["tunnel_target", target])
            for p in deps:
                save_list.append([p, p.get()])

            datasaver.add_result(*save_list)

            time.sleep(0.1)
        runid = datasaver.run_id
    return runid
Example #10
0
 def _create_measurement(self, *set_params):
     meas = Measurement()
     for p in set_params:
         meas.register_parameter(p)
     meas.register_custom_parameter('time', label='Time', unit='s')
     for p in self._params:
         meas.register_parameter(p, setpoints=(
             *set_params,
             'time',
         ))
     for l, _, _ in self._sr830s:
         meas.register_parameter(l.X, setpoints=(
             *set_params,
             'time',
         ))
         meas.register_parameter(l.Y, setpoints=(
             *set_params,
             'time',
         ))
     return meas
def time_sweep(dependents,
               event_list,
               fn_before=None,
               fn_after=None,
               exp=None,
               station=None):
    """
    Takes a list of Events which can run some event and then measure
    for a period of time. Eg
    Set vtun to 3v for 5 secs, then bump to 10v for 2 secs, then
    back to 3v for another 5 secs.
    """
    meas = Measurement(exp=exp, station=station)
    meas.register_custom_parameter("time", label="Time", unit="S")

    if callable(fn_before):
        meas.add_before_run(fn_before, ())
    if callable(fn_after):
        meas.add_after_run(fn_after, ())

    for p in dependents:
        meas.register_parameter(p, setpoints=("time", ))

    with meas.run() as datasaver:
        start = time.time()
        for event in event_list:
            begin = time.time()
            if callable(event.fn_before):
                event.fn_before()
            time.sleep(0.5)
            while (time.time() - begin < event.time):
                save_list = []
                save_list.append(["time", time.time() - start])
                for p in dependents:
                    save_list.append([p, p.get()])

                datasaver.add_result(*save_list)

                time.sleep(event.step)
        runid = datasaver.run_id
    return runid
Example #12
0
def test_snapshot_creation_for_types_not_supported_by_builtin_json(experiment):
    """
    Test that `Measurement`/`Runner`/`DataSaver` infrastructure
    successfully dumps station snapshots in JSON format in cases when the
    snapshot contains data of types that are not supported by python builtin
    `json` module, for example, numpy scalars.
    """
    p1 = ManualParameter('p_np_int32', initial_value=numpy.int32(5))
    p2 = ManualParameter('p_np_float16', initial_value=numpy.float16(5.0))
    p3 = ManualParameter('p_np_array',
                         initial_value=numpy.meshgrid((1, 2), (3, 4)))
    p4 = ManualParameter('p_np_bool', initial_value=numpy.bool_(False))

    station = Station(p1, p2, p3, p4)

    measurement = Measurement(experiment, station)

    # we need at least 1 parameter to be able to run the measurement
    measurement.register_custom_parameter('dummy')

    with measurement.run() as data_saver:
        # we do this in order to create a snapshot of the station and add it
        # to the database
        pass

    snapshot = data_saver.dataset.snapshot

    assert 5 == snapshot['station']['parameters']['p_np_int32']['value']
    assert 5 == snapshot['station']['parameters']['p_np_int32']['raw_value']

    assert 5.0 == snapshot['station']['parameters']['p_np_float16']['value']
    assert 5.0 == snapshot['station']['parameters']['p_np_float16'][
        'raw_value']

    lst = [[[1, 2], [1, 2]], [[3, 3], [4, 4]]]
    assert lst == snapshot['station']['parameters']['p_np_array']['value']
    assert lst == snapshot['station']['parameters']['p_np_array']['raw_value']

    assert False is snapshot['station']['parameters']['p_np_bool']['value']
    assert False is snapshot['station']['parameters']['p_np_bool']['raw_value']
Example #13
0
def array_dataset_with_nulls(experiment, request):
    """
    A dataset where two arrays are measured, one as a function
    of two other (setpoint) arrays, the other as a function of just one
    of them
    """
    meas = Measurement()
    meas.register_custom_parameter('sp1', paramtype=request.param)
    meas.register_custom_parameter('sp2', paramtype=request.param)
    meas.register_custom_parameter('val1',
                                   paramtype=request.param,
                                   setpoints=('sp1', 'sp2'))
    meas.register_custom_parameter('val2',
                                   paramtype=request.param,
                                   setpoints=('sp1', ))

    with meas.run() as datasaver:
        sp1_vals = np.arange(0, 5)
        sp2_vals = np.arange(5, 10)
        val1_vals = np.ones(5)
        val2_vals = np.zeros(5)
        datasaver.add_result(('sp1', sp1_vals), ('sp2', sp2_vals),
                             ('val1', val1_vals))
        datasaver.add_result(('sp1', sp1_vals), ('val2', val2_vals))
    try:
        yield datasaver.dataset
    finally:
        datasaver.dataset.conn.close()
Example #14
0
def save_1Ddata_with_qcodes(data_generator_method, metadata_generator_method):
    meas = Measurement()
    meas.register_custom_parameter("voltage",
                                   paramtype="numeric",
                                   label="voltage x",
                                   unit="V")
    meas.register_custom_parameter(
        "current",
        paramtype="numeric",
        label="dc current",
        unit="A",
        setpoints=("voltage", ),
    )

    meas.register_custom_parameter(
        "sensor",
        paramtype="numeric",
        label="dc sensor",
        unit="A",
        setpoints=("voltage", ),
    )
    voltage, current, sensor = data_generator_method()
    with meas.run() as datasaver:
        datasaver.add_result(("voltage", voltage), ("current", current))
        datasaver.add_result(("voltage", voltage), ("sensor", sensor))

        nt_metadata, current_label = metadata_generator_method()
        datasaver.dataset.add_metadata(nt.meta_tag, json.dumps(nt_metadata))
        datasaver.dataset.add_metadata("snapshot", json.dumps({}))
        for label, value in current_label.items():
            datasaver.dataset.add_metadata(label, value)

    return datasaver
Example #15
0
def test_datasaver_unsized_arrays(empty_temp_db, N):
    new_experiment('firstexp', sample_name='no sample')

    meas = Measurement()

    meas.register_custom_parameter(name='freqax',
                                   label='Frequency axis',
                                   unit='Hz')
    meas.register_custom_parameter(name='signal',
                                   label='qubit signal',
                                   unit='Majorana number',
                                   setpoints=('freqax', ))
    # note that np.array(some_number) is not the same as the number
    # its also not an array with a shape. Check here that we handle it
    # correctly
    with meas.run() as datasaver:
        freqax = np.linspace(1e6, 2e6, N)
        signal = np.random.randn(N)
        for i in range(N):
            myfreq = np.array(freqax[i])
            mysignal = np.array(signal[i])
            datasaver.add_result(('freqax', myfreq), ('signal', mysignal))

    assert datasaver.points_written == N
Example #16
0
def test_datasaver_arrays(empty_temp_db, N):
    new_experiment('firstexp', sample_name='no sample')

    meas = Measurement()

    meas.register_custom_parameter(name='freqax',
                                   label='Frequency axis',
                                   unit='Hz')
    meas.register_custom_parameter(name='signal',
                                   label='qubit signal',
                                   unit='Majorana number',
                                   setpoints=('freqax',))

    with meas.run() as datasaver:
        freqax = np.linspace(1e6, 2e6, N)
        signal = np.random.randn(N)

        datasaver.add_result(('freqax', freqax), ('signal', signal))

    assert datasaver.points_written == N

    with meas.run() as datasaver:
        freqax = np.linspace(1e6, 2e6, N)
        signal = np.random.randn(N-1)

        with pytest.raises(ValueError):
            datasaver.add_result(('freqax', freqax), ('signal', signal))

    meas.register_custom_parameter(name='gate_voltage',
                                   label='Gate tuning potential',
                                   unit='V')
    meas.register_custom_parameter(name='signal',
                                   label='qubit signal',
                                   unit='Majorana flux',
                                   setpoints=('freqax', 'gate_voltage'))

    with meas.run() as datasaver:
        freqax = np.linspace(1e6, 2e6, N)
        signal = np.random.randn(N)

        datasaver.add_result(('freqax', freqax),
                             ('signal', signal),
                             ('gate_voltage', 0))

    assert datasaver.points_written == N
Example #17
0
def test_register_custom_parameter(DAC):
    """
    Test the registration of custom parameters
    """
    meas = Measurement()

    name = 'V_modified'
    unit = 'V^2'
    label = 'square of the voltage'

    meas.register_custom_parameter(name, label, unit)

    assert len(meas.parameters) == 1
    assert isinstance(meas.parameters[name], ParamSpec)
    assert meas.parameters[name].unit == unit
    assert meas.parameters[name].label == label
    assert meas.parameters[name].type == 'numeric'

    newunit = 'V^3'
    newlabel = 'cube of the voltage'

    meas.register_custom_parameter(name, newlabel, newunit)

    assert len(meas.parameters) == 1
    assert isinstance(meas.parameters[name], ParamSpec)
    assert meas.parameters[name].unit == newunit
    assert meas.parameters[name].label == newlabel

    with pytest.raises(ValueError):
        meas.register_custom_parameter(name,
                                       label,
                                       unit,
                                       setpoints=(DAC.ch1, ))
    with pytest.raises(ValueError):
        meas.register_custom_parameter(name, label, unit, basis=(DAC.ch2, ))

    meas.register_parameter(DAC.ch1)
    meas.register_parameter(DAC.ch2)
    meas.register_custom_parameter('strange_dac')

    meas.register_custom_parameter(name,
                                   label,
                                   unit,
                                   setpoints=(DAC.ch1, str(DAC.ch2)),
                                   basis=('strange_dac', ))

    assert len(meas.parameters) == 4
    parspec = meas.parameters[name]
    assert parspec.inferred_from == 'strange_dac'
    assert parspec.depends_on == ', '.join([str(DAC.ch1), str(DAC.ch2)])

    with pytest.raises(ValueError):
        meas.register_custom_parameter('double dependence',
                                       'label',
                                       'unit',
                                       setpoints=(name, ))
Example #18
0
def test_nested_measurement_array(bg_writing, outer_len, inner_len1,
                                  inner_len2):
    meas1 = Measurement()
    meas1.register_custom_parameter('foo1', paramtype='numeric')
    meas1.register_custom_parameter('bar1spt', paramtype='array')
    meas1.register_custom_parameter('bar1',
                                    setpoints=('foo1', "bar1spt"),
                                    paramtype='array')

    meas2 = Measurement()
    meas2.register_custom_parameter('foo2', paramtype='numeric')
    meas2.register_custom_parameter('bar2spt', paramtype='array')
    meas2.register_custom_parameter('bar2',
                                    setpoints=(
                                        'foo2',
                                        'bar2spt',
                                    ),
                                    paramtype='array')

    with meas1.run(write_in_background=bg_writing) as ds1, \
            meas2.run(write_in_background=bg_writing) as ds2:
        for i in range(outer_len):
            bar1sptdata = np.arange(inner_len1)
            bar2sptdata = np.arange(inner_len2)
            ds1.add_result(("foo1", i), ("bar1spt", bar1sptdata),
                           ("bar1", np.ones(inner_len1) * i * bar1sptdata))
            ds2.add_result(("foo2", i), ("bar2spt", bar2sptdata),
                           ("bar2", np.ones(inner_len2) * i * bar2sptdata))

    data1 = ds1.dataset.get_parameter_data()["bar1"]
    assert len(data1.keys()) == 3
    assert "foo1" in data1.keys()
    assert "bar1spt" in data1.keys()
    assert "bar1" in data1.keys()

    expected_foo1_data = np.repeat(np.arange(outer_len),
                                   inner_len1).reshape(outer_len, inner_len1)
    expected_bar1spt_data = np.tile(np.arange(inner_len1), (outer_len, 1))

    assert_allclose(data1["foo1"], expected_foo1_data)
    assert_allclose(data1["bar1spt"], expected_bar1spt_data)
    assert_allclose(data1["bar1"], expected_foo1_data * expected_bar1spt_data)

    data2 = ds2.dataset.get_parameter_data()["bar2"]
    assert len(data2.keys()) == 3
    assert "foo2" in data2.keys()
    assert "bar2spt" in data2.keys()
    assert "bar2" in data2.keys()

    expected_foo2_data = np.repeat(np.arange(outer_len),
                                   inner_len2).reshape(outer_len, inner_len2)
    expected_bar2spt_data = np.tile(np.arange(inner_len2), (outer_len, 1))

    assert_allclose(data2["foo2"], expected_foo2_data)
    assert_allclose(data2["bar2spt"], expected_bar2spt_data)
    assert_allclose(data2["bar2"], expected_foo2_data * expected_bar2spt_data)
Example #19
0
def G_up(station, v_gates, v_polar, amplitude, stanford_gain_V_ac):
    #Before using this code change these values according to your own setup :

    R_polar = 1e6  #value of the polarization resistor

    now = datetime.now()
    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")  # dd/mm/YY H:M:S
    print(dt_string)  #print date and time of the measurement

    #Start the measurement

    meas = Measurement()

    meas.register_parameter(station.lockin_2.amplitude)
    meas.register_parameter(station.lockin_2.sine_outdc)
    meas.register_parameter(station.mdac_8.ch01.voltage)

    meas.register_parameter(station.lockin_1.Y,
                            setpoints=(station.mdac_8.ch01.voltage, ))
    meas.register_parameter(station.lockin_2.Y,
                            setpoints=(station.mdac_8.ch01.voltage, ))
    meas.register_parameter(station.lockin_1.X,
                            setpoints=(station.mdac_8.ch01.voltage, ))
    meas.register_parameter(station.lockin_2.X,
                            setpoints=(station.mdac_8.ch01.voltage, ))
    meas.register_custom_parameter("R_ac",
                                   unit="Ohm",
                                   setpoints=(station.mdac_8.ch01.voltage, ))

    #Prepare the live plot
    win = qcm.pyplot.PlotWindow(title="Gate Sweep 1D")
    win.resize(600, 400)

    plot = win.addPlot(title="R_ac(V_g)")
    plot.update_axes(station.mdac_8.ch01.voltage, station.lockin_1.X)

    R_ac_all = np.full(len(v_gates), np.nan)

    #Print the main lockin settings
    print(f'Stanford Gain V_AC ={stanford_gain_V_ac}')

    time_constant = station.lockin_2.time_constant()
    print(f'Integration time lockins {time_constant} s')

    print(f'Frequency Lockin : {station.lockin_2.frequency()} Hz')

    print(f'Filter lockin 1 : {station.lockin_1.filter_slope()} dB roll off')
    print(f'Sensitivity lockin 1 : {station.lockin_1.sensitivity()} V')

    print(f'Filter lockin 2 : {station.lockin_2.filter_slope()} dB roll off')
    print(f'Sensitivity lockin 2 : {station.lockin_2.sensitivity()} A')

    #Initialisation of the lockin

    station.lockin_2.amplitude(amplitude)
    print(f'V_ac polarization : {amplitude/1e-3} mV')

    station.lockin_2.sine_outdc(v_polar)
    print(f'V_dc polarization : {v_polar/1e-3} mV')

    with meas.run() as datasaver:

        for i, v_g in enumerate(v_gates):

            station.mdac_8.ch01.ramp(v_g, 0.01)
            station.mdac_8.ch02.ramp(v_g, 0.01)
            station.mdac_8.ch03.ramp(v_g, 0.01)
            station.mdac_8.ch01.block()
            station.mdac_8.ch02.block()
            station.mdac_8.ch03.block()

            print(v_g)

            time.sleep(5 * time_constant)

            voltage_X_AC = station.lockin_1.X() / stanford_gain_V_ac
            current_X_AC = station.lockin_2.X()

            voltage_Y_AC = station.lockin_1.Y() / stanford_gain_V_ac
            current_Y_AC = station.lockin_2.Y()

            R_ac = voltage_X_AC / current_X_AC

            R_ac_all[i] = R_ac

            trace = plot.plot(setpoint_x=v_gates, pen=(0, 0, 255), name="R_ac")
            trace.update(R_ac_all)

            datasaver.add_result(("R_ac", R_ac),
                                 (station.lockin_2.amplitude, amplitude),
                                 (station.lockin_2.sine_outdc, v_polar),
                                 (station.mdac_8.ch01.voltage, v_g),
                                 (station.lockin_2.Y, current_Y_AC),
                                 (station.lockin_1.Y, voltage_Y_AC),
                                 (station.lockin_2.X, current_X_AC),
                                 (station.lockin_1.X, voltage_X_AC))

        ID_exp = datasaver.run_id

    station.lockin_2.sine_outdc(0)
    station.lockin_2.amplitude(0)

    win.export('figures/Rac_Gate_sweep_1D_ID_exp_' + str(ID_exp) + '.png')

    plot_by_id(ID_exp)
Example #20
0
def Hall_gate(station, v_gates, V_polar, field_range_Y, stanford_gain_1, stanford_gain_2, stanford_gain_3):

    R_polar = 1e6

    print(f'I_polar = {V_polar/R_polar}')

    R_I = 1e4

    # dmm1 is voltage
    station.dmm1.NPLC(100)

    # dmm2 is current
    station.dmm2.NPLC(10)

    station.dmm3.NPLC(100)
    
    station.yoko.voltage.step = 1e-4
    station.yoko.voltage.inter_delay = 0.0001

    meas = Measurement()

    meas.register_parameter(station.yoko.voltage)
    meas.register_parameter(station.mag.y_target)
    meas.register_parameter(station.mag.y_measured)
    meas.register_parameter(station.mdac_8.ch01.voltage)
    meas.register_parameter(station.dmm1.volt, setpoints = (station.mag.y_target,station.mdac_8.ch01.voltage))
    meas.register_parameter(station.dmm2.volt, setpoints = (station.mag.y_target,station.mdac_8.ch01.voltage))
    meas.register_parameter(station.dmm3.volt, setpoints = (station.mag.y_target,station.mdac_8.ch01.voltage))
    meas.register_custom_parameter("R_h", unit = "Ohms", setpoints = (station.mag.y_target,station.mdac_8.ch01.voltage))
    meas.register_custom_parameter("R_xx", unit = "Ohms", setpoints = (station.mag.y_target,station.mdac_8.ch01.voltage))

    with meas.run() as datasaver:

        for b in field_range_Y:

            station.mag.y_target(b)
            station.mag.ramp('simul')

            while abs(station.mag.y_measured()-b)>0.001:
                time.sleep(2)
            time.sleep(5)

            l_y = station.mag.y_measured()

            print(l_y)

            for v_g in v_gates:

                station.mdac_8.ch01.ramp(v_g, 0.01)
                while abs(station.mdac_8.ch01.voltage()-v_g)>0.001:
                    time.sleep(2)
                time.sleep(2)
                print(f'V_g = {v_g} V')

           
                station.yoko.voltage(-V_polar)

                time.sleep(1)

                volt_h_m = station.dmm1.volt()/stanford_gain_1
                curr_m = station.dmm2.volt()/(R_I*stanford_gain_2)
                volt_m = station.dmm3.volt()/stanford_gain_3
                
                time.sleep(1)
                
                station.yoko.voltage(V_polar)
                
                time.sleep(1)
                
                volt_h_p = station.dmm1.volt()/stanford_gain_1
                curr_p = station.dmm2.volt()/(R_I*stanford_gain_2)
                volt_p = station.dmm3.volt()/stanford_gain_3
                
                time.sleep(1)
                
                V_av = (volt_p - volt_m)/2
                I_av = (curr_p - curr_m)/2
                V_h_av = (volt_h_p - volt_h_m)/2
                
                R_av = V_av/I_av
                R_h_av = V_h_av/I_av

                print(R_av)
                
                datasaver.add_result((station.mdac_8.ch01.voltage, v_g),
                                     (station.yoko.voltage, V_polar),
                                     (station.dmm2.volt, curr_p),
                                     (station.dmm1.volt, V_h_av),
                                     (station.dmm3.volt, V_av),
                                     (station.mag.y_measured, l_y),
                                     (station.mag.y_target, b),
                                     ("R_h", R_h_av),
                                     ("R_xx",R_av))
                station.yoko.voltage(0)
                ID_exp = datasaver.run_id
                
        plot_by_id(ID_exp)
Example #21
0
class BaseSweep(QObject):
    """
    This is the base class for the 0D (tracking) sweep class and the 1D sweep class. Each of these functions
    is used by both classes.
    """

    start_sweep = pyqtSignal()

    def __init__(self,
                 set_param=None,
                 inter_delay=0.01,
                 save_data=True,
                 plot_data=True,
                 x_axis=1,
                 datasaver=None):
        """
        Initializer for both classes, called by super().__init__() in Sweep0D and Sweep1D classes.
        Simply initializes the variables and flags.
        
        Arguments:
            set_param - QCoDeS Parameter to be swept
            inter_delay - Time (in seconds) to wait between data points
            save_data - Flag used to determine if the data should be saved or not
            plot_data - Flag to determine if we should live-plot data
        """
        self._params = []
        self._srs = []
        self.set_param = set_param
        self.inter_delay = inter_delay
        self.save_data = save_data
        self.plot_data = plot_data
        self.x_axis = x_axis

        self.is_running = False
        self.t0 = time.monotonic()

        self.runnerThread = QThread()
        self.plotterThread = QThread()

        self.datasaver = datasaver

        QObject.__init__(self)

    def follow_param(self, *p):
        """
        This function saves parameters to be tracked, for both saving and plotting data.
        The parameters must be followed before '_create_measurement()' is called.
        
        Arguments:
            *p - Variable number of arguments, each of which must be a QCoDeS Parameter
                 that you want the sweep to follow
        """
        for param in p:
            if isinstance(param, list):
                for l in param:
                    self._params.append(l)
            else:
                self._params.append(param)

    def follow_srs(self, l, name, gain=1.0):
        """
        Adds an SRS lock-in to ensure that the range is kept correctly.
        
        Arguments:
            l - lockin instrument
            name - name of instrument
            gain - current gain value
        """
        self._srs.append((l, name, gain))

    def _create_measurement(self):
        """
        Creates a QCoDeS Measurement object. This controls the saving of data by registering
        QCoDeS Parameter objects, which this function does. Registers all 'tracked' parameters, 
        Returns the measurement object.
        This function will register only parameters that are followed BEFORE this function is
        called.
        """

        # First, create time parameter
        self.meas = Measurement()
        self.meas.register_custom_parameter('time', label='Time', unit='s')

        # Check if we are 'setting' a parameter, and register it
        if self.set_param is not None:
            self.meas.register_parameter(self.set_param)
        # Register all parameters we are following
        for p in self._params:
            self.meas.register_parameter(p)

        return self.meas

    def stop(self):
        """
        Stops/pauses the program from running by setting the 'is_running' flag to false. This is
        the flag that the children threads check in their loop to determine if they should
        continue running.
        """
        self.is_running = False

    def check_running(self):
        """
        Returns the status of the sweep.
        """
        return self.is_running

    def start(self, persist_data=None):
        """
        Starts the sweep by creating and running the worker threads. Used to both start the 
        program and unpause after calling 'stop()'
        """

        # Flag that we are now running.
        self.is_running = True

        first = False
        if self.plotter is None and self.runner is None:
            first = True

        # Save persistent data from 2D sweep
        self.persist_data = persist_data

        # If we don't have a plotter yet want to plot, create it and the figures
        if self.plotter is None and self.plot_data is True:
            self.plotter = Plotter(self)
            self.plotter.create_figs()

        # If we don't have a runner, create it and tell it of the plotter,
        # which is where it will send data to be plotted
        if self.runner is None:
            self.runner = Runner(self)
            self.datasaver = self.runner.datasaver
            self.runner.add_plotter(self.plotter)

        if first is True:
            # Tells the threads to begin
            self.runner.moveToThread(self.runnerThread)
            self.plotter.moveToThread(self.plotterThread)

            self.runnerThread.start()
            self.plotterThread.start()

            self.start_sweep.connect(self.runner.run)

        self.start_sweep.emit()

    def update_values(self):
        """
        Iterates our data points, changing our setpoint if we are sweeping, and refreshing
        the values of all our followed parameters. If we are saving data, it happens here,
        and the data is returned.
        
        Returns:
            data - A list of tuples with the new data. Each tuple is of the format 
                   (<QCoDeS Parameter>, measurement value). The tuples are passed in order of
                   time, then set_param (if applicable), then all the followed params.
        """
        t = time.monotonic() - self.t0

        data = []
        data.append(('time', t))

        if self.set_param is not None:
            data.append(self.step_param())

        persist_param = None
        if self.persist_data is not None:
            data.append(self.persist_data)
            persist_param = self.persist_data[0]

        for i, (l, _, gain) in enumerate(self._srs):
            _autorange_srs(l, 3)

        for i, p in enumerate(self._params):
            if p is not persist_param:
                v = p.get()
                data.append((p, v))

        if self.save_data and self.is_running:
            self.runner.datasaver.add_result(*data)

        return data

    def clear_plot(self):
        """
        Clears the currently showing plots.
        """
        self.plotter.reset()

    def no_change(self, *args):
        """
        This function is passed when we don't need to connect a function when the 
        sweep is completed.
        """
        pass

    def __del__(self):
        if self.datasaver is not None:
            self.datasaver.__exit__()
Example #22
0
 def _create_measurement(self, *set_params):
     meas = Measurement()
     self._etp = ElapsedTimeParameter('time')
     meas.register_parameter(self._etp)
     for param in set_params:
         meas.register_parameter(param)
     for param in self._params:
         meas.register_parameter(param.param,
                                 setpoints=(*set_params, self._etp))
     for sr830 in self._sr830s:
         meas.register_parameter(sr830.sr830.X,
                                 setpoints=(*set_params, self._etp))
         meas.register_parameter(sr830.sr830.Y,
                                 setpoints=(*set_params, self._etp))
     if self._fbl is not None:
         for c in self._fbl.channels:
             meas.register_custom_parameter(f'fbl_c{c}_x',
                                            setpoints=(*set_params,
                                                       self._etp))
             meas.register_custom_parameter(f'fbl_c{c}_p',
                                            setpoints=(*set_params,
                                                       self._etp))
             if self._fbl.outputs:
                 meas.register_custom_parameter(f'fbl_c{c}_o',
                                                setpoints=(*set_params,
                                                           self._etp))
             if self._fbl.setpoints:
                 meas.register_custom_parameter(f'fbl_c{c}_s',
                                                setpoints=(*set_params,
                                                           self._etp))
             if self._fbl.dc:
                 meas.register_custom_parameter(f'fbl_c{c}_dc',
                                                setpoints=(*set_params,
                                                           self._etp))
     for fn in self._fns:
         meas.register_custom_parameter(fn.name,
                                        setpoints=(*set_params, self._etp))
     return meas
Example #23
0
def sweep_time(*param_meas, delay=10, until=None,
               win=None, append=False, plot_params=None, annotation=None,
               atstart=(), ateach=(), atend=()):
    """
    Run a time sweep, with a delay between each point. This sweep will run for `until` seconds,
    or indefinitely if until is None

    Args:
        *param_meas (Iterable[Parameter]): A list of the parameters to be measured at each of the
        set points. For now, these MUST be simple parameters. Arrays cannot be measured.

        win (Optional[PlotWindow]): The plot window to add plots to. If this value is None, the sweep
        will not be live plotted.

        append (bool): If this parameter is true, the trace will be appended to an existing window.

        plot_params (Optional[Iterable[Parameter]]): A list of parameters to plot. If not passed or None,
        all measured parameters will be automatically plotted.

        atstart (Optional[Union[Callable,Iterable[Callable]]]): A function or list of functions
        to be run before the measurement is started. The functions will be run BEFORE the parameters
        are inserted into the measurement, hence if some parameters require setup before they are run,
        they can be inserted here.

        ateach (Optional[Union[Callable,Iterable[Callable]]]): A function or list of functions
        to be run after each time the sweep parameter is set. These functions will be run AFTER
        the delay, and so is suitable if an instrument requires a call to capture a trace before
        the parameter can be read.

        atend (Optional[Union[Callable,Iterable[Callable]]]): A function or list of functions
        to be run at the end of a trace. This is run AFTER the data is saved into the database,
        and after parameters are set back to their starting points (if setback is True), and
        can therefore be used to read the data that was taken and potentially do some post analysis.

    Returns:
        (iw, win): ID is the trace id of the saved wave, win is a handle to the plot window that was created
        for the purposes of liveplotting.
    """
    _flush_buffers(*param_meas)

    # Register setpoints
    m = Measurement()
    m.register_custom_parameter("time", label="Time", unit="s")

    _run_functions(atstart)

    # Keep track of data and plots
    plt_data = {}
    time_data = np.full((1,), np.nan)
    array_size = 1
    curr_point = 0

    # If plot_params is not given, plot all measured parameters
    if plot_params is None:
        plot_params = param_meas

    # Set up parameters
    for param in param_meas:
        m.register_parameter(param, setpoints=("time", ))

        # Create plot window
        if win is not None and param in plot_params:
            plot = win.addPlot(name=param.full_name,
                            title=f"{param.full_name} ({param.label})")
            plot.left_axis.label = param.label
            plot.left_axis.unit = param.unit
            plot.bot_axis.label = "Time"
            plot.bot_axis.unit = "s"
            plotdata = plot.plot(setpoint_x=time_data, name=param.name, pen=(255,0,0))
            plt_data[param] = (plot, plotdata, np.full((1,), np.nan))

    if win is not None and annotation is not None:
        win.items[0].textbox(annotation)

    try:
        with m.run() as datasaver:
            start_time = time.monotonic()
            win.win_title += f"{datasaver.run_id}"
            for pd in plt_data.values():
                pd[0].plot_title += f" (id: {datasaver.run_id})"
            while True:
                # Update each parameter
                data = [("time", time.monotonic()-start_time)]
                time_data[curr_point] = data[-1][1]

                _run_functions(ateach, param_vals=(Setpoint("time", curr_point, data[-1][1])))

                if until is not None and time_data[curr_point] > until:
                    break

                for param in param_meas:
                    val = param()
                    if val is None:
                        val = np.nan
                    data.append((param, val))
                    if param in plot_params:
                        plt_data[param][2][curr_point] = data[-1][1]
                        plt_data[param][1].xData = time_data
                        plt_data[param][1].update(plt_data[param][2])

                curr_point += 1

                # Resize plot arrays if necessary
                if array_size == curr_point:
                    array_size *= 2
                    logger.debug("New plot array size: %d", array_size)
                    time_data.resize(array_size)
                    time_data[array_size//2:] = np.nan
                    for pld in plt_data.values():
                        pld[2].resize(array_size)
                        pld[2][array_size//2:] = np.nan

                datasaver.add_result(*data)

                # Wait until the next point time. Try to keep track of how long it
                # took for equipment to respond
                next_time = start_time + delay*curr_point
                while time.monotonic() < next_time:
                    sleep_time = max(0, min(0.01, time.monotonic() - next_time))
                    time.sleep(sleep_time)
    except KeyboardInterrupt:
        print(f"Trace cancelled with Ctrl-C")
        print(f"Ending plot at time {time.monotonic() - start_time}.")
    finally:
        _run_functions(atend)

    return datasaver.run_id
Example #24
0
class Sweep1D(object):
    """
    Class to control sweeping along 1 parameter, while tracking multiple other parameters.
    It has functionality to live plot, or not, and one can create their own figures (e.g. in a GUI)
    or have the class create its own matplotlib figues. Follows QCoDeS data-taking methods.
    Adapted from Joe Finney's code.
    
    SR830s are not currently implemented.
    """
    def __init__(self,
                 set_param,
                 start,
                 stop,
                 step,
                 freq,
                 bidirectional=False,
                 meas=None,
                 plot=False,
                 auto_figs=False):
        """
        Initializes the Sweep object. Takes in the parameter to be swept (set_param), the 
        value to start and stop sweeping at (start/stop, respectively), the step spacing (step),
        and the frequency of measurements. Can turn plotting off through 'plot', also tells 
        system whether to create it's own plots or use given ones through 'auto_figs'.
        """
        # Save our input variables
        self.set_param = set_param
        self.start = start
        self.stop = stop
        self.step = step

        if (self.stop - self.start) > 0:
            self.step = abs(self.step)
        else:
            self.step = (-1) * abs(self.step)

        self.inter_delay = 1 / freq
        self.t0 = time.monotonic()
        self.setpoint = self.start - self.step
        self.bidirectional = bidirectional
        self.direction = 0  #Forward

        d = (stop - start) / step * self.inter_delay
        h, m, s = int(d / 3600), int(d / 60) % 60, int(d) % 60
        print(f'Minimum duration: {h}h {m}m {s}s')

        # Either mark or save the measurement object
        if meas is not None:
            self.meas = meas

        # Saves our plotting flags
        self.plot = plot
        self.auto_figs = auto_figs
        # Sets a flag to ensure that the figures have been created before trying to plot
        self.figs_set = False
        self.pause = False
        self._sr830s = []
        self._params = []

    def follow_param(self, p):
        """
        This function takes in a QCoDeS Parameter p, and tracks it through each sweep.
        """
        self._params.append(p)

    def follow_sr830(self, l, name, gain=1.0):
        """
        This function adds an SR830, but (as of now) does not do anything with it.
        """
        self._sr830s.append((l, name, gain))

    def _create_measurement(self, *set_params):
        """
        Creates a QCoDeS Measurement object. This controls the saving of data by registering
        QCoDeS Parameter objects, which this function does. Registers all 'sweeping' parameters
        (set_params), and all 'tracked' parameters, 'self._params'. Returns the measurement
        object.
        """
        self.meas = Measurement()
        for p in set_params:
            self.meas.register_parameter(p)
        self.meas.register_custom_parameter('time', label='Time', unit='s')
        for p in self._params:
            self.meas.register_parameter(p, setpoints=(
                *set_params,
                'time',
            ))
        for l, _, _ in self._sr830s:
            self.meas.register_parameter(l.X,
                                         setpoints=(
                                             *set_params,
                                             'time',
                                         ))
            self.meas.register_parameter(l.Y,
                                         setpoints=(
                                             *set_params,
                                             'time',
                                         ))

        return self.meas

    def create_figs(self):
        """
        Creates default figures for each of the parameters. Plots them in a new, separate window.
        """
        self.fig = plt.figure(
            figsize=(4 * (2 + len(self._params) + len(self._sr830s)), 4))
        self.grid = plt.GridSpec(4,
                                 1 + len(self._params) + len(self._sr830s),
                                 hspace=0)
        self.setax = self.fig.add_subplot(self.grid[:, 0])
        # First, create a plot of the sweeping parameters value against time
        self.setax.set_xlabel('Time (s)')
        self.setax.set_ylabel(
            f'{self.set_param.label} ({self.set_param.unit})')
        self.setaxline = self.setax.plot([], [])[0]

        self.plines = []
        self.axes = []
        # Now create a plot for every tracked parameter as a function of sweeping parameter
        for i, p in enumerate(self._params):
            self.axes.append(self.fig.add_subplot(self.grid[:, 1 + i]))
            self.axes[i].set_xlabel(
                f'{self.set_param.label} ({self.set_param.unit})')
            self.axes[i].set_ylabel(f'{p.label} ({p.unit})')

            forward_line = matplotlib.lines.Line2D([], [])
            forward_line.set_color('b')
            backward_line = matplotlib.lines.Line2D([], [])
            backward_line.set_color('r')
            self.axes[i].add_line(forward_line)
            self.axes[i].add_line(backward_line)
            self.plines.append((forward_line, backward_line))

        self.figs_set = True

    def set_figs(self, fig, setax, axes):
        """
        Give a figure and plots for both the sweeping parameter and the tracked parameters
        for the program to update. fig is of type matplotlib Figure, setax is a (sub)plot, 
        and axes is an array of subplots.
        """
        self.figs_set = True
        self.fig = fig
        self.setax = setax
        self.axes = axes

        # Initializes sweeping plot
        self.setax.set_xlabel('Time (s)')
        self.setax.set_ylabel(
            f'{self.set_param.label} ({self.set_param.unit})')
        self.setaxline = setax.plot([], [])[0]

        self.plines = []
        # Initializes tracking plots
        for i, p in enumerate(self._params):
            self.axes[i].set_xlabel(
                f'{self.set_param.label} ({self.set_param.unit})')
            self.axes[i].set_ylabel(f'{p.label} ({p.unit})')

            forward_line = matplotlib.lines.Line2D([], [])
            forward_line.set_color('b')
            backward_line = matplotlib.lines.Line2D([], [])
            backward_line.set_color('r')
            self.axes[i].add_line(forward_line)
            self.axes[i].add_line(backward_line)
            self.plines.append((forward_line, backward_line))

    def autorun(self, datasaver=None, persist_data=None):
        """
        Run a sweep through this class. Makes call to create_figs if needed.
        Calls self.iterate to move through each data point.
        """
        # Checks to see if it needs to generate its own figures
        if self.plot and self.auto_figs and not self.figs_set:
            self.create_figs()

        # If plots should have been set but are not, return 0
        if self.plot is True and self.figs_set is False:
            return 0

        # Run the loop
        if datasaver is None:
            with self.meas.run() as datasaver:
                # Check if we are within the stopping condition
                while abs(self.setpoint - self.stop) > abs(self.step / 2):
                    self.iterate(datasaver)

                # If we want to go both ways, we flip the start and stop, and run again
                if self.bidirectional:
                    self.flip_direction()
                    while abs(self.setpoint - self.stop) > abs(self.step / 2):
                        self.iterate(datasaver)
                    self.flip_direction()
        else:
            # Check if we are within the stopping condition
            while abs(self.setpoint - self.stop) > abs(self.step / 2):
                self.iterate(datasaver, persist_data)

            # If we want to go both ways, we flip the start and stop, and run again
            if self.bidirectional:
                self.flip_direction()
                while abs(self.setpoint - self.stop) > abs(self.step / 2):
                    self.iterate(datasaver, persist_data)
                self.flip_direction()

        return 1

    def iterate(self, datasaver=None, persist_data=None):
        """
        Runs one 'step' in the sweep. Takes in only the datasaver object, which is always
        a Measurement object's run() function (see autorun()). Iterate will update the 
        sweeping parameter, read each of the tracking parameters, and update the plots
        if plotting is enabled. Returns all values as a list of tuples, in the form of
        (parameter_name, parameter_value).
        """
        t = time.monotonic() - self.t0
        # Step the setpoint, and update the value
        self.setpoint = self.step + self.setpoint
        self.set_param.set(self.setpoint)

        # Update the sweeping parameter plot
        if self.plot is True:
            self.setaxline.set_xdata(np.append(self.setaxline.get_xdata(), t))
            self.setaxline.set_ydata(
                np.append(self.setaxline.get_ydata(), self.setpoint))
            self.setax.relim()
            self.setax.autoscale_view()

        # Pause if desired
        if self.inter_delay is not None:
            time.sleep(self.inter_delay)

        # Create our data storage object, which is a list of tuples of the parameter
        # and its value
        data = []
        if persist_data is not None:
            data.append(persist_data)
        data.append((self.set_param, self.setpoint))
        data.append(('time', t))

        # Loop through each of the tracking parameters
        for i, p in enumerate(self._params):
            # Update their values, and add them to the data object
            v = p.get()
            data.append((p, v))
            # Update each of the plots for the tracking parameters
            if self.plot is True:
                self.plines[i][self.direction].set_xdata(
                    np.append(self.plines[i][self.direction].get_xdata(),
                              self.setpoint))
                self.plines[i][self.direction].set_ydata(
                    np.append(self.plines[i][self.direction].get_ydata(), v))
                self.axes[i].relim()
                self.axes[i].autoscale_view()

        # Add this point to the dataset
        if datasaver is not None:
            datasaver.add_result(*data)

        # Set the plots
        if self.plot is True:
            self.fig.tight_layout()
            self.fig.canvas.draw()
            plt.pause(0.001)

        # Finally return all data
        return data

    def pause_run(self):
        self.pause = not self.pause

    def is_paused(self):
        return self.pause

    def ramp_to_zero(self):
        self.stop = 0
        if self.setpoint - self.step > 0:
            self.step = (-1) * abs(self.step)
        else:
            self.step = abs(self.step)

        print(f'Ramping {self.set_param.label} to 0 . . . ')
        while abs(self.setpoint - self.stop) > abs(self.step / 2):
            self.iterate()

        self.set_param.set(0)
        print(f'Done ramping {self.set_param.label} to 0!')

    def flip_direction(self):
        """
        Flips the direction of the sweep, to do bidirectional sweeping.
        """
        temp = self.start
        self.start = self.stop
        self.stop = temp
        self.step = -1 * self.step
        self.setpoint -= self.step

        # If backwards, go forwards, and vice versa
        if self.direction:
            self.direction = 0
        else:
            self.direction = 1

    def reset(self, new_params=None):
        """
        Resets the Sweep1D to reuse the same object with the same plots.
        
        Arguments:
            new_params - list of 4 values to determine how we sweep. In order, 
                         must be [ start value, stop value, step, frequency ]
        """
        # Set our new values if desired
        if new_params is not None:
            self.start = new_params[0]
            self.stop = new_params[1]
            self.step = new_params[2]
            self.inter_delay = 1 / new_params[3]

        # Reset our setpoint
        self.setpoint = self.start - self.step

        # Reset our plots
        if self.plot is True:
            self.setaxline.set_xdata(np.array([]))
            self.setaxline.set_ydata(np.array([]))
            self.setax.relim()
            self.setax.autoscale_view()

            for i, p in enumerate(self._params):
                self.plines[i][0].set_xdata(np.array([]))
                self.plines[i][0].set_ydata(np.array([]))
                self.plines[i][1].set_xdata(np.array([]))
                self.plines[i][1].set_ydata(np.array([]))
                self.axes[i].relim()
                self.axes[i].autoscale_view()

    def get_measurement(self):
        """
        Returns the measurement object.
        """
        return self.meas

    def save(self):
        """
        Saves the plots as a png
        (may not work? untested)
        """
        b = io.BytesIO()
        self.fig.savefig(b, format='png')
Example #25
0
    def save_segmented_data_return_info(
        self,
        segment_db_name: str,
        segment_db_folder: Optional[str] = None,
    ) -> Dict[int, Dict[str, Dict[str, Tuple[float, float]]]]:
        """
        Save each mesh in a new dataset in given databases

        returns:
        segment_info = {
            data_id: {
                readout_method: {'range_x': (),
                                 'range_y': ()
                        }
                    }
        }
        """
        if segment_db_folder is None:
            segment_db_folder = nt.config["db_folder"]

        if not self.segmented_data:
            self.prepare_segmented_data(use_raw_data=True)
        if not os.path.isfile(os.path.join(segment_db_folder, segment_db_name)):
            ds = load_by_id(self.qc_run_id)
            nt.new_database(segment_db_name, db_folder=segment_db_folder)
            qc.new_experiment(f'segmented_{ds.exp_name}',
                              sample_name=ds.sample_name)


        original_params = self.qc_parameters
        segment_info: Dict[int, Dict[str, Dict[str, Tuple[float, float]]]] = {}

        with nt.switch_database(segment_db_name, segment_db_folder):
            for segment in self.segmented_data:
                meas = Measurement()
                meas.register_custom_parameter(
                    original_params[0].name,
                    label=original_params[0].label,
                    unit=original_params[0].unit,
                    paramtype="array",
                )

                meas.register_custom_parameter(
                    original_params[1].name,
                    label=original_params[1].label,
                    unit=original_params[1].unit,
                    paramtype="array",
                )
                result: List[List[Tuple[str, np.ndarray]]] = []
                ranges: Dict[str, Dict[str, Tuple[float, float]]] = {}
                m_params = [str(it) for it in list(segment.data_vars)]
                for ip, param_name in enumerate(m_params):
                    coord_names = list(segment.coords)
                    x_crd_name = coord_names[0]
                    y_crd_name = coord_names[1]

                    voltage_x = segment[param_name][x_crd_name].values
                    voltage_y = segment[param_name][y_crd_name].values
                    signal = segment[param_name].values

                    range_x = (np.min(voltage_x), np.max(voltage_x))
                    range_y = (np.min(voltage_y), np.max(voltage_y))
                    ranges[param_name] = {}
                    ranges[param_name]["range_x"] = range_x
                    ranges[param_name]["range_y"] = range_y

                    setpoints = self.raw_data[param_name].depends_on
                    meas.register_custom_parameter(
                        original_params[ip+2].name,
                        label=original_params[ip+2].label,
                        unit=original_params[1].unit,
                        paramtype="array",
                        setpoints=setpoints,
                    )
                    v_x_grid, v_y_grid = np.meshgrid(voltage_x, voltage_y)

                    result.append([(setpoints[0], v_x_grid),
                                    (setpoints[1], v_y_grid),
                                    (param_name, signal.T)])

                with meas.run() as datasaver:
                    for r_i in range(len(self.readout_methods)):
                        datasaver.add_result(*result[r_i])

                    datasaver.dataset.add_metadata(
                        "snapshot", json.dumps(self.snapshot)
                        )
                    datasaver.dataset.add_metadata(
                        nt.meta_tag, json.dumps(self.nt_metadata)
                    )
                    datasaver.dataset.add_metadata(
                        "original_guid", json.dumps(self.guid)
                        )
                    logger.debug(
                        "New dataset created and populated.\n"
                        + "database: "
                        + str(segment_db_name)
                        + "ID: "
                        + str(datasaver.run_id)
                    )
                    segment_info[datasaver.run_id] = ranges

        return segment_info
Example #26
0
class BaseSweep(QObject):
    """
    The parent class for the 0D, 1D and 2D sweep classes. 
    
    The default independent variable for BaseSweep and Sweep0D Measurements is time.
    Creating an object in a sweep class results in data acquisition and plotting of 
    all followed parameters individually measured against the independent variable. 
    The measured data is transferred in real-time (through QObject slot and signal 
    connections) from the Sweep classes to the Runner and Plotter Threads to organize, 
    save, and live-plot the tracked parameters.
    
    Attributes:
    -----------
    _params: 
        Defaults as blank list. Desired QCoDeS parameters should be added using 
        follow_param method.
    _srs: 
        Defaults as blank list. Used to incorporate lock-in amplifier with 
        measurement.
    set_param: 
        QCoDeS Parameter to be swept, defaults to None for 0D sweep.
    inter_delay: 
        Time (in seconds) to wait between data points.
    save_data: 
        Flag used to determine if the data should be saved or not.
    plot_data: 
        Flag to determine whether or not to live-plot data
    x_axis: 
        Defaults to 1 to set as time for 0D; defaults to 0 in 1D.
    meas: 
        Measurement class from QCoDeS, used to register and follow desired 
        parameters. Default is None until a measurement is created using 
        the create_measurement method.
    dataset: 
        Stores the data obtained during the measurement.
    continuous: 
        No effect on Sweep0D. Defaults to False for Sweep1D.
    plot_bin: 
        Defaults to 1. Used to plot data that has been sent to the 
        data_queue list in the Plotter Thread.
    is_running: 
        Flag to determine whether or not sweep is currently running.
    t0: 
         Set to monotonic time when creating Runner Thread.
    persist_data: 
        Always none except in Sweep2D, takes one set_param, allows sweeping of 2 parameters.
    datasaver: 
        Initiated by Runner Thread to enable saving and export of data.
    
    Methods
    ---------
    follow_param(*p)
        Adds QCoDes parameters from imported drivers to be tracked.            
    remove_param(*p)
        Removes parameters that have been assigned to be tracked.
    follow_srs(l, name, gain)
        Adds SRS lock-in amplifier to keep range consistent.
    create_measurement()
        Creates a QCoDeS Measurement Object
    stop()
        Stops/pauses the sweep.
    kill()
        Ends all threads and closes any active plots.
    check_running()
        Returns the status of the sweep.
    start(persist_data=None, ramp_to_start = False)
        Creates QCoDeS Measurement, Runner and Plotter Threads, and begins sweep.            
    resume()
        Restarts the sweep using the start method.            
    get_dataset()
        Retrieves collected data.
    receive_dataset(ds_dict)
        Slot to receive data in dictionary form, reemits received data.            
    update_values()
        Returns dictionary of updated [parameter:value] pairs, default parameter is time.       
    send_updates()
        Emits signal containing dictionary of parameter, setpoint, direction, and status.
        If running Sweep0D, will default to time at one second intervals.   
    clear_plot()
        Clears any displayed plots.            
    set_plot_bin(pb)
        Sets value for the Plotter Thread plot bin.   
    set_complete_func(func)
        Sets function to call when sweep is completed.            
    no_change(*args, **kwargs)
        Does nothing when sweep is completed.            
    check_params_are_correct()
        Compares the followed parameters to the previously created measurement parameters.            
    export_json(fn=None)
        Saves all sweep information, attributes, and parameters of QCoDeS Station as
        JSON dictionary.     
    import_json(json_dict, station=Station())
        Loads previously saved experimental setup.
    """
    
    update_signal = pyqtSignal(dict)
    dataset_signal = pyqtSignal(dict)
    reset_plot = pyqtSignal()
    add_break = pyqtSignal(int)
    completed = pyqtSignal()

    def __init__(self, set_param=None, inter_delay=0.1, save_data=True, plot_data=True, x_axis_time=1,
                 datasaver=None, complete_func=None, plot_bin=1, back_multiplier=1):
        """
        Initializer for both classes, called by BaseSweep.__init__() in Sweep0D and Sweep1D classes.
        
        Parameters:
        ---------
        _params: 
            Defaults as blank list. Desired QCoDeS parameters should be added using 
            follow_param method.
        _srs: 
            Defaults as blank list. Used to incorporate lock-in amplifier with 
            measurement.
        set_param: 
            QCoDeS Parameter to be swept, defaults to None for 0D sweep.
        inter_delay: 
            Time (in seconds) to wait between data points.
        save_data: 
            Flag used to determine if the data should be saved or not.
        plot_data: 
            Flag to determine whether or not to live-plot data
        x_axis: 
            Defaults to 1 to set as time for 0D; defaults to 0 in 1D.
        meas: 
            Measurement class from QCoDeS, used to register and follow desired 
            parameters. Default is None until a measurement is created using 
            the create_measurement method.
        dataset: 
            Stores the data obtained during the measurement.
        continuous: 
            No effect on Sweep0D. Defaults to False for Sweep1D.
        plot_bin: 
            Defaults to 1. Used to plot data that has been sent to the 
            data_queue list in the Plotter Thread.
        is_running: 
            Flag to determine whether or not sweep is currently running.
        t0: 
             Set to monotonic time when creating Runner Thread.
        persist_data: 
            Always none except in Sweep2D, takes one set_param, allows sweeping of 2 parameters.
        datasaver: 
            Initiated by Runner Thread to enable saving and export of data.
            
        """
        QObject.__init__(self)

        self._params = []
        self._srs = []
        self.set_param = set_param
        if inter_delay is None or inter_delay < 0:
            inter_delay = 0
        self.inter_delay = inter_delay
        self.save_data = save_data
        self.plot_data = plot_data
        self.x_axis = x_axis_time
        self.back_multiplier = back_multiplier
        self.direction = 0
        self.meas = None
        self.dataset = None

        self.continuous = False
        self.plot_bin = plot_bin

        self.is_running = False
        self.t0 = 0

        self.persist_data = None
        self.datasaver = datasaver

        # Set the function to call when we are finished
        self.complete_func = complete_func
        if complete_func is None:
            complete_func = self.no_change
        self.completed.connect(complete_func)

        self.plotter = None
        self.plotter_thread = None
        self.runner = None

    @classmethod
    def init_from_json(cls, fn, station):
        """ Initializes QCoDeS station from previously saved setup. """
        with open(fn) as json_file:
            data = json.load(json_file)
            return BaseSweep.import_json(data, station)

    def follow_param(self, *p):
        """
        Saves parameters to be tracked, for both saving and plotting data.
        
        The parameters must be followed before '_create_measurement()' is called.
        
        Parameters:
            *p: 
                Variable number of arguments, each of which must be a QCoDeS Parameter
                that is desired to be followed.
        """
        
        if self.is_running:
            print("Cannot update the parameter list while the sweep is running.")

        for param in p:
            if isinstance(param, list):
                for l in param:
                    if l not in self._params:
                        self._params.append(l)
            else:
                if param not in self._params:
                    self._params.append(param)

    def remove_param(self, *p):
        """
        Removes parameters that were previously followed.
        
        Parameters:
            *p - Variable number of arguments, each of which must be a QCoDeS Parameter
                 that is currently being tracked.
        """
        
        if self.is_running:
            print("Cannot update the parameter list while the sweep is running.")

        for param in p:
            if isinstance(param, list):
                for l in param:
                    self._params.remove(l)
            else:
                self._params.remove(param)

    def follow_srs(self, l, name, gain=1.0):
        """
        Adds an SRS lock-in to ensure that the range is kept correctly.
        
        Parameters:
            l:
                The lock-in instrument. 
            name:
                The name of the instrument to be followed.
            gain:
                The current gain value.
        """
        
        if self.is_running:
            print("Cannot update the srs list while the sweep is running.")

        if (l, name, gain) not in self._srs:
            self._srs.append((l, name, gain))

    def _create_measurement(self):
        """
        Creates a QCoDeS Measurement object. 
        
        Controls the saving of data by registering QCoDeS Parameter objects.
        Registers all desired parameters to be followed. This function will 
        register only parameters that are followed BEFORE this function is
        called.
        
        Returns
        ---------
        The measurement object with the parameters to be followed.
        
        """

        # First, create time parameter
        self.meas = Measurement()

        # Check if we are 'setting' a parameter, and register it
        if self.set_param is not None:
            self.meas.register_parameter(self.set_param)
            self.meas.register_custom_parameter('time', label='time', unit='s', setpoints=(self.set_param,))
        else:
            self.meas.register_custom_parameter('time', label='time', unit='s')

            # Register all parameters we are following
        for p in self._params:
            if self.set_param is None:
                self.meas.register_parameter(p, setpoints=('time',))
            else:
                self.meas.register_parameter(p, setpoints=(self.set_param,))

        return self.meas

    def stop(self):
        """
        Stops/pauses the program from running by setting the is_running flag to false. 
        
        The is_running flag is checked in every thread's loop to determine whether or 
        not to continue running. When sweep is stopped, all data is updated a final time
        to ensure all completed measurements are stored.
        """
        
        if self.save_data and self.runner is not None:
            self.runner.flush_flag = True

        if not self.is_running:
            print("Sweep not currently running. Nothing to stop.")
        self.is_running = False
        self.send_updates()

    def kill(self):
        """ Ends the threads spawned by the sweep and closes any active plots. """
        
        # Stop any data-taking
        self.is_running = False

        # Gently shut down the runner
        if self.runner is not None:
            self.runner.flush_flag = True
            self.runner.kill_flag = True
            self.runner.quit()
            if not self.runner.wait(1000):
                self.runner.terminate()
                print('forced runner to terminate')
            self.runner = None
            self.send_updates()
        # Gently shut down the plotter
        if self.plotter is not None:
            self.plotter_thread.quit()
            if not self.plotter_thread.wait(1000):
                self.plotter_thread.terminate()
                print('forced plotter to terminate')
            self.close_plots()
            self.plotter = None

    def check_running(self):
        """ Returns the status of the sweep. """
        
        return self.is_running

    def start(self, persist_data=None, ramp_to_start=False):
        """
        Starts the sweep by creating and running the worker threads.
        
        Can be used to both start the program and unpause after calling 'stop()'.
        
        Parameters
        ---------
        persist_data:
            Optional argument which allows Sweep2D to sweep two paramters.
        ramp_to_start:
            Optional argument which gradually ramps each parameter to the starting
            point of its sweep. Default is true for Sweep1D and Sweep2D.
        """

        if self.is_running:
            print("We are already running, can't start while running.")
            return

        # Check if we have a measurement object
        if self.meas is None:
            self._create_measurement()
        # Check if our list of parameters is out of date- meaning we started, stopped, updated params, and restarted
        elif not self.check_params_are_correct():
            self._create_measurement()
            if self.plotter is not None and self.plotter.figs_set is True:
                self.plotter.clear()
                # print("reset figs")
                self.plotter.create_figs()

        # If we don't have a plotter yet want to plot, create it and the figures
        if self.plotter is None and self.plot_data is True:
            self.plotter = Plotter(self, self.plot_bin)
            self.plotter_thread = QThread()
            self.plotter.moveToThread(self.plotter_thread)
            self.plotter.create_figs()

            self.add_break.connect(self.plotter.add_break)
            self.reset_plot.connect(self.plotter.reset)

        # If we don't have a runner, create it and tell it of the plotter,
        # which is where it will send data to be plotted
        if self.runner is None:
            self.runner = RunnerThread(self)
            self.runner.get_dataset.connect(self.receive_dataset)
            self.t0 = time.monotonic()

            if self.plot_data is True:
                self.runner.add_plotter(self.plotter)

        # Flag that we are now running.
        self.is_running = True

        # Save persistent data from 2D sweep
        self.persist_data = persist_data

        # Tells the threads to begin
        if self.plot_data is True and self.plotter_thread.isRunning() is False:
            self.plotter_thread.start()
        elif self.plot_data is True and self.plotter.figs_set is False:
            # print("somehow here")
            self.plotter.create_figs()
        if not self.runner.isRunning():
            self.runner.kill_flag = False
            self.runner.start()

    def resume(self):
        """ Restarts the sweep after it has been paused. """
        
        if self.is_running is False:
            self.start(ramp_to_start=False)
        self.send_updates(no_sp=True)

    def get_dataset(self):
        """ Returns the dataset object which contains the collected data. """

        return self.dataset

    @pyqtSlot(dict)
    def receive_dataset(self, ds_dict):
        """
        Connects the dataset of Runner Thread to the dataset object of the sweep.
        
        Parameters
        ---------
        ds_dict:
            Dataset dictionary passed between Runner Thread and sweep.
        """
        
        self.dataset = ds_dict
        self.dataset_signal.emit(ds_dict)

    def update_values(self):
        """
        Called as Runner Thread loops to update parameter values.
        
        Verifies the data to be updated depending on type of sweep.
        Iterates through data point intervals, assigning collected values to 
        their respective parameters. If data is to be saved, it happens here,
        and the updated data is emitted to all connected slots.
        
        Returns
        ---------
        data: 
            A dictionary of tuples with the updated data. Each tuple is of the format 
            (<QCoDeS Parameter>, measurement value). The tuples are passed in order of
            time, then set_param (if applicable), then all the followed params.
        """
        
        t = time.monotonic() - self.t0

        data = [('time', t)]

        if self.set_param is not None:
            sp_data = self.step_param()
            if sp_data is not None:
                data += sp_data
            else:
                return None

        persist_param = None
        if self.persist_data is not None:
            data.append(self.persist_data)
            persist_param = self.persist_data[0]

        for i, (l, _, gain) in enumerate(self._srs):
            _autorange_srs(l, 3)

        for i, p in enumerate(self._params):
            if p is not persist_param:
                v = safe_get(p)
                data.append((p, v))

        if self.save_data and self.is_running:
            self.runner.datasaver.add_result(*data)

        self.send_updates()

        return data

    def send_updates(self, no_sp=False):
        """
        Emits the signal after dictionary values are updated by 'update_values'.
        
        Parameters
        ---------
        no_sp:
            Represents a 'no setpoints' boolean. Default is False, when true it
            sets the setpoint key to None in the updated dictionary.
        """
        
        update_dict = {}
        if self.set_param is None:
            update_dict['set_param'] = 'time'
            update_dict['setpoint'] = time.monotonic() - self.t0
            update_dict['direction'] = 0
        else:
            update_dict['set_param'] = self.set_param
            if not no_sp:
                update_dict['setpoint'] = self.setpoint
            else:
                update_dict['setpoint'] = None
            update_dict['direction'] = self.direction
        update_dict['status'] = self.is_running

        self.update_signal.emit(update_dict)

    def reset_plots(self):
        """ Clears the currently displayed plots. """
        
        if self.plotter is not None:
            self.reset_plot.emit()

    def close_plots(self):
        """ Resets the plotter and closes all displayed plots. """

        if self.plotter is not None:
            self.plotter.clear()

    def set_plot_bin(self, pb):
        """
        Sets value for the Plotter Thread plot bin.
        
        Parameters
        ---------
        pb:
            Integer value which determines the amount of data to remain in 
            Plotter's data_queue while sweeping. The data queue is only 
            emptied completely when force is set to True in 'update_plots'.
        """
        
        self.plot_bin = pb
        if self.plotter is not None:
            self.plotter.plot_bin = pb

    def set_complete_func(self, func, *args, **kwargs):
        """
        Sets a function to be called whenever the sweep is finished.
        
        Connects to completed signal for Sweep0D, Sweep1D, and Sweep2D.
        
        Parameters
        ---------
        func:
            The function to be called upon completion of the sweep.
        *args:
            Arbitrary arguments to be passed to the callback function
        **kwargs:
            Arbitrary keyword arguments to be passed to the callback function
        """

        self.complete_func = partial(func, *args, **kwargs)
        self.completed.connect(self.complete_func)

    @pyqtSlot()
    def no_change(self, *args, **kwargs):
        """
        Passed when there is no function to be called on completion.
        
        Simply allows the sweep to end when 'complete_func' is set to None.
        """
        pass

    def check_params_are_correct(self):
        """
        Compares the followed parameters to the measurement parameters.
        
        Pulls paramaters from object _params, compares list to parameters
        found in QCoDeS measurement dictionary.
        
        Returns
        ---------
        Boolean value for whether or not each followed parameter is a QCoDeS
        parameter associated with the measurement instrument.
        """
        
        p_list = []
        meas_list = []
        # print("our params list")
        for p in self._params:
            # print(str(p))
            p_list.append(str(p))
        p_list.append("time")
        if self.set_param is not None:
            p_list.append(str(self.set_param))
        # print("measurement param list")
        for key, val in self.meas.parameters.items():
            # print(str(key))
            meas_list.append(key)

        return set(p_list) == set(meas_list)

    def export_json(self, fn=None):
        """
        Saves sweep attributes and parameters of QCoDeS Station as JSON dictionary.
        
        Called to save experimental setup to avoid repetitive setup of commonly
        used measurement instruments.
        
        Parameters
        ---------
        fn:
            Represents optional filename to be opened. A copy of the station
            information will be saved in this file.
            
        Returns
        ---------
        Dictionary containing all current instruments, parameters, and sweep 
        attributes.
        """
        
        json_dict = {}
        json_dict['class'] = str(self.__class__.__name__)
        json_dict['module'] = str(self.__class__.__module__)

        json_dict['attributes'] = {}
        json_dict['attributes']['inter_delay'] = self.inter_delay
        json_dict['attributes']['save_data'] = self.save_data
        json_dict['attributes']['plot_data'] = self.plot_data
        json_dict['attributes']['plot_bin'] = self.plot_bin

        if 'Sweep0D' in json_dict['class']:
            json_dict['set_param'] = None
            json_dict['attributes']['max_time'] = self.max_time
        elif 'Sweep1D' in json_dict['class']:
            json_dict['set_param'] = {}
            json_dict['set_param']['param'] = self.set_param.name
            json_dict['set_param']['instr_module'] = self.set_param.instrument.__class__.__module__
            json_dict['set_param']['instr_class'] = self.set_param.instrument.__class__.__name__
            json_dict['set_param']['instr_name'] = self.set_param.instrument.name
            json_dict['set_param']['start'] = self.begin
            json_dict['set_param']['stop'] = self.end
            json_dict['set_param']['step'] = self.step
            json_dict['attributes']['bidirectional'] = self.bidirectional
            json_dict['attributes']['continual'] = self.continuous
            json_dict['attributes']['x_axis_time'] = self.x_axis
        elif 'Sweep2D' in json_dict['class']:
            json_dict['attributes']['outer_delay'] = self.outer_delay
            json_dict['inner_sweep'] = {}
            json_dict['inner_sweep']['param'] = self.in_param.name
            json_dict['inner_sweep']['instr_module'] = self.in_param.instrument.__class__.__module__
            json_dict['inner_sweep']['instr_class'] = self.in_param.instrument.__class__.__name__
            json_dict['inner_sweep']['instr_name'] = self.in_param.instrument.name
            json_dict['inner_sweep']['start'] = self.in_start
            json_dict['inner_sweep']['stop'] = self.in_stop
            json_dict['inner_sweep']['step'] = self.in_step
            json_dict['outer_sweep'] = {}
            json_dict['outer_sweep']['param'] = self.set_param.name
            json_dict['outer_sweep']['instr_module'] = self.set_param.instrument.__class__.__module__
            json_dict['outer_sweep']['instr_class'] = self.set_param.instrument.__class__.__name__
            json_dict['outer_sweep']['instr_name'] = self.set_param.instrument.name
            json_dict['outer_sweep']['start'] = self.out_start
            json_dict['outer_sweep']['stop'] = self.out_stop
            json_dict['outer_sweep']['step'] = self.out_step
        elif 'SimulSweep' in json_dict['class']:
            json_dict['attributes']['bidirectional'] = self.bidirectional
            json_dict['attributes']['continual'] = self.continuous

            json_dict['set_params'] = {}
            for p, items in self.set_params_dict.items():
                json_dict['set_params'][p.name] = items
                json_dict['set_params'][p.name]['instr_module'] = p.instrument.__class__.__module__
                json_dict['set_params'][p.name]['instr_class'] = p.instrument.__class__.__name__
                json_dict['set_params'][p.name]['instr_name'] = p.instrument.name

        json_dict['follow_params'] = {}

        for p in self._params:
            json_dict['follow_params'][p.name] = (p.instrument.name, p.instrument.__class__.__module__,
                                                  p.instrument.__class__.__name__)

        if fn is not None:
            with open(fn, 'w') as outfile:
                json.dump(json_dict, outfile)

        return json_dict

    @classmethod
    def import_json(cls, json_dict, station=Station()):
        """
        Loads previously exported Station setup.
        
        Reassigns all dictionary values exported as JSON to their appropriate
        objects.
        """
        
        def load_parameter(name, instr_name, instr_type, station):
            if instr_name in station.components.keys():
                if isinstance(station.components[instr_name], instr_type):
                    return station.components[instr_name].parameters[name]

            for i_name, instr in station.components.items():
                if isinstance(instr, instr_type):
                    return instr.parameters[name]

        sweep_class = json_dict['class']
        sweep_module = json_dict['module']

        if 'Sweep1D' in sweep_class:
            sp = json_dict['set_param']

            module = importlib.import_module(sweep_module)
            sc = getattr(module, sweep_class)
            instr_module = importlib.import_module(sp['instr_module'])
            instrument = getattr(instr_module, sp['instr_class'])

            set_param = load_parameter(sp['param'], sp['instr_name'], instrument, station)
            sweep = sc(set_param, sp['start'], sp['stop'], sp['step'], **json_dict['attributes'])
        elif 'Sweep0D' in sweep_class:
            module = importlib.import_module(sweep_module)
            sc = getattr(module, sweep_class)
            sweep = sc(**json_dict['attributes'])
        elif 'Sweep2D' in sweep_class:
            module = importlib.import_module(sweep_module)
            sc = getattr(module, sweep_class)

            in_param = json_dict['inner_sweep']
            in_instr_module = importlib.import_module(in_param['instr_module'])
            in_instrument = getattr(in_instr_module, in_param['instr_class'])
            inner_param = load_parameter(in_param['param'], in_param['instr_name'], in_instrument, station)

            out_param = json_dict['outer_sweep']
            out_instr_module = importlib.import_module(out_param['instr_module'])
            out_instrument = getattr(out_instr_module, out_param['instr_class'])
            outer_param = load_parameter(out_param['param'], out_param['instr_name'], out_instrument, station)

            inner_list = [inner_param, in_param['start'], in_param['stop'], in_param['step']]
            outer_list = [outer_param, out_param['start'], out_param['stop'], out_param['step']]

            sweep = sc(inner_list, outer_list, **json_dict['attributes'])
        elif 'SimulSweep' in sweep_class:
            module = importlib.import_module(sweep_module)
            sc = getattr(module, sweep_class)

            set_params_dict = {}
            for p, items in json_dict['set_params'].items():
                instr_module = importlib.import_module(items['instr_module'])
                instrument = getattr(instr_module, items['instr_class'])

                param = load_parameter(p, items['instr_name'], instrument, station)
                set_params_dict[param] = {}
                set_params_dict[param]['start'] = items['start']
                set_params_dict[param]['stop'] = items['stop']
                set_params_dict[param]['step'] = items['step']

            sweep = sc(set_params_dict, **json_dict['attributes'])
        else:
            return

        for p, instr in json_dict['follow_params'].items():
            instr_module = importlib.import_module(instr[1])
            instrument = getattr(instr_module, instr[2])

            param = load_parameter(p, instr[0], instrument, station)
            sweep.follow_param(param)

        return sweep

    def estimate_time(self, verbose=True):
        return 0

    def __del__(self):
        """ Deletes all child threads and closes all figures. """
        
        self.kill()
Example #27
0
class Sweep2D(object):
    def __init__(self, inner_sweep_parameters, outer_sweep_parameters, freq,
                 follow_param):
        """
        We initialize our 2D sweep by taking in the parameters for each sweep, and the frequency.
        The inner_sweep_parameters and outer_sweep_parameters MUST be a list, conforming to the 
        following standard:
        
            [ <QCoDeS Parameter>, <start value>, <stop value>, <step size> ]
            
        Arguments: 
            inner_sweep_parameters - list conforming to above standard for the inner sweep
            outer_sweep_parameters - list conforming to above standard for the inner sweep
            freq - the frequency of measurement
            follow_param - the parameter to be tracked while other two are swept
        """

        # Ensure that the inputs were passed (at least somewhat) correctly
        if len(inner_sweep_parameters) != 4 or len(
                outer_sweep_parameters) != 4:
            raise TypeError(
                'For 2D Sweep, must pass list of 4 object for each sweep parameter, \
                             in order: [ <QCoDeS Parameter>, <start value>, <stop value>, <step size> ]'
            )

        # Save our input variables
        self.in_param = inner_sweep_parameters[0]
        self.in_start = inner_sweep_parameters[1]
        self.in_stop = inner_sweep_parameters[2]
        self.in_step = inner_sweep_parameters[3]

        if (self.in_stop - self.in_start) > 0:
            self.in_step = abs(self.in_step)
        else:
            self.in_step = (-1) * abs(self.in_step)

        self.out_param = outer_sweep_parameters[0]
        self.out_start = outer_sweep_parameters[1]
        self.out_stop = outer_sweep_parameters[2]
        self.out_step = outer_sweep_parameters[3]

        if (self.out_stop - self.out_start) > 0:
            self.out_step = abs(self.out_step)
        else:
            self.out_step = (-1) * abs(self.out_step)

        self.out_setpoint = self.out_start - self.out_step

        self.inter_delay = 1 / freq

        # Sets a flag to ensure that the figures have been created before trying to plot
        self.figs_set = False
        self._params = []
        self._sr830s = []

        # Add the tracking parameter, and create the measurement
        self.follow_param(follow_param)
        self.meas = self._create_measurement(self.out_param, self.in_param)

        # Create the inner sweep
        self.inner_sweep = Sweep1D(self.in_param,
                                   self.in_start,
                                   self.in_stop,
                                   self.in_step,
                                   freq,
                                   meas=self.meas,
                                   bidirectional=True,
                                   plot=True,
                                   auto_figs=False)
        # Make sure the inner sweep knows what parameter it should be reading
        self.inner_sweep._params.append(follow_param)

        # Deal with creating the figures
        self.create_figs()
        self.inner_sweep.set_figs(self.fig, self.setax, self.axes)

        self.t0 = time.monotonic()
        # The origin of the plot is top left, we want it to be bottom left,
        # so we keep count of what number sweep we are at to put it into the
        # matrix backwards
        self.count = 0

        # We want to track the max and min values seen to autorange the heatmap
        self.max_datapt = float("-inf")
        self.min_datapt = float("inf")

        self.pause = False

    def autorun(self, update_rule=None):
        """
        Run the 2D Sweep. Creates the datasaver and passes it to the iterate function.
        Updates the plots, and then updates the inner sweep if desired.
        
        Arguments:
            update_rule - function to call, accepting the Sweep1D object as an argument,
                          to determine how the next inner sweep should behave
        """
        # If there is not an update_rule passed, then call our own no_change function
        # to run the same sweep again
        if update_rule is None:
            update_rule = self.no_change

        with self.meas.run() as datasaver:
            # Loop until we are done
            while abs(self.out_setpoint - self.out_stop) > abs(
                    self.out_step / 2) and self.pause is False:
                self.iterate(datasaver)

                self.update_heatmap(self.count)

                update_rule(self.inner_sweep)
                self.count += 1

            datasaver.flush_data_to_database()
            # Make the plots persist after finishing plotting
            plt.show()

    def iterate(self, datasaver):
        """
        This function is one iteration of the outer sweep, which steps the outer parameter,
        and then runs the inner sweep.
        
        Arguments:
            datasaver - the Runner object created from calling Measurement.run()
        """
        # Step the setpoint, and update the value
        self.out_setpoint = self.out_step + self.out_setpoint
        self.out_param.set(self.out_setpoint)

        # Pause if desired
        if self.inter_delay is not None:
            time.sleep(self.inter_delay)

        # Create our data storage object, which is a list of tuples of the parameter
        # and its value
        data = (self.out_param, self.out_setpoint)

        # We pass to the inner sweep the datasaver, and pass it the information about
        # the outer sweep parameter
        self.inner_sweep.autorun(datasaver, data)

    def ramp_to_zero(self):
        """
        Ramps the parameter down to 0.
        """
        self.out_stop = 0
        if self.out_setpoint - self.out_stop > 0:
            self.out_step = (-1) * abs(self.out_step)
        else:
            self.out_step = abs(self.out_step)

        self.inner_sweep.ramp_to_zero()

        print(f'Ramping {self.out_param.label} to 0 . . . ')

        while abs(self.out_setpoint - self.out_stop) > abs(self.out_step / 2):
            # Step the setpoint, and update the value
            self.out_setpoint = self.out_step + self.out_setpoint
            self.out_param.set(self.out_setpoint)

            # Pause if desired
            if self.inter_delay is not None:
                time.sleep(self.inter_delay)

        print(f'Done ramping {self.out_param.label} to 0!')

    def pause_run(self):
        if self.pause is False:
            self.pause = True
        else:
            self.pause = False

    def create_figs(self):
        """
        Creates default figures for each of the parameters. Plots them in a new, separate window.
        Also creates a 2D heatmap of the data.
        """
        self.fig = plt.figure(
            figsize=(4 * (2 + len(self._params) + len(self._sr830s)), 4))
        self.grid = plt.GridSpec(4,
                                 1 + len(self._params) + len(self._sr830s),
                                 hspace=0)
        self.setax = self.fig.add_subplot(self.grid[:, 0])
        # First, create a plot of the sweeping parameters value against time
        self.setax.set_xlabel('Time (s)')
        self.setax.set_ylabel(f'{self.in_param.label} ({self.in_param.unit})')
        self.setaxline = self.setax.plot([], [])[0]

        self.axes = []
        # Now create a plot for every tracked parameter as a function of sweeping parameter
        for i, p in enumerate(self._params):
            self.axes.append(self.fig.add_subplot(self.grid[:, 1 + i]))
            self.axes[i].set_xlabel(
                f'{self.in_param.label} ({self.in_param.unit})')
            self.axes[i].set_ylabel(f'{p.label} ({p.unit})')

        # Create the heatmap
        # First, determine the resolution on each axis
        self.res_in = math.ceil(
            abs((self.in_stop - self.in_start) / self.in_step)) + 1
        self.res_out = math.ceil(
            abs((self.out_stop - self.out_start) / self.out_step)) + 1

        self.heatmap_data = np.zeros((self.res_out, self.res_in))
        self.heat_fig = plt.figure(2)
        self.heatmap = plt.imshow(self.heatmap_data)
        ax = plt.gca()
        self.heat_ax = ax

        plt.ylabel(f'{self.out_param.label} ({self.out_param.unit})')
        plt.xlabel(f'{self.in_param.label} ({self.in_param.unit})')
        inner_tick_lbls = np.linspace(self.in_start, self.in_stop, 5)
        outer_tick_lbls = np.linspace(self.out_stop, self.out_start, 5)

        ax.set_xticks(np.linspace(0, self.res_in - 1, 5))
        ax.set_yticks(np.linspace(0, self.res_out - 1, 5))
        ax.set_xticklabels(inner_tick_lbls)
        ax.set_yticklabels(outer_tick_lbls)

        divider = make_axes_locatable(ax)
        cax = divider.append_axes("right", size="5%", pad=0.05)

        cbar = plt.colorbar(self.heatmap, cax=cax)
        cbar.set_label(f'{self._params[0].label} ({self._params[0].unit})')

        self.figs_set = True

    def update_heatmap(self, count):
        # GRAB THE X AND Y DATA HERE
        forward_line = self.axes[0].get_lines()[0]
        backward_line = self.axes[0].get_lines()[1]

        x_data_forward = forward_line.get_xdata()
        y_data_forward = forward_line.get_ydata()

        x_data_backward = backward_line.get_xdata()
        y_data_backward = backward_line.get_ydata()

        # ADD THE DATA TO THE HEATMAP
        for i, x in enumerate(x_data_forward):
            self.heatmap_data[self.res_out - count - 1, i] = y_data_forward[i]
            if y_data_forward[i] > self.max_datapt:
                self.max_datapt = y_data_forward[i]
            if y_data_forward[i] < self.min_datapt:
                self.min_datapt = y_data_forward[i]

        self.heatmap.set_data(self.heatmap_data)
        self.heatmap.set_clim(self.min_datapt, self.max_datapt)
        self.heat_fig.canvas.draw()
        self.heat_fig.canvas.flush_events()

    def no_change(self, sweep):
        """
        This function is the default update_rule function. It simply runs the same sweep over again.
        """
        sweep.reset()

    def follow_param(self, p):
        """
        This function takes in a QCoDeS Parameter p, and tracks it through each sweep.
        """
        self._params.append(p)

    def follow_sr830(self, l, name, gain=1.0):
        """
        This function adds an SR830, but (as of now) does not do anything with it.
        """
        self._sr830s.append((l, name, gain))

    def _create_measurement(self, *set_params):
        """
        Creates a QCoDeS Measurement object. This controls the saving of data by registering
        QCoDeS Parameter objects, which this function does. Registers all 'sweeping' parameters
        (set_params), and all 'tracked' parameters, 'self._params'. Returns the measurement
        object.
        """
        self.meas = Measurement()
        for p in set_params:
            self.meas.register_parameter(p)
        self.meas.register_custom_parameter('time', label='Time', unit='s')
        for p in self._params:
            self.meas.register_parameter(p, setpoints=(
                *set_params,
                'time',
            ))
        for l, _, _ in self._sr830s:
            self.meas.register_parameter(l.X,
                                         setpoints=(
                                             *set_params,
                                             'time',
                                         ))
            self.meas.register_parameter(l.Y,
                                         setpoints=(
                                             *set_params,
                                             'time',
                                         ))

        return self.meas
Example #28
0
class FollowPlotParams(object):
    def __init__(self, params, inter_delay=0.01, save_data=False):
        self._params = []
        self.save_data = save_data
        self.inter_delay = inter_delay
        self.pause = False

        for p in params:
            self._params.append(p)

        if self.save_data:
            self._create_measurement()

        self.create_figs()
        self.t0 = time.monotonic()

    def _create_measurement(self):
        """
        Creates a QCoDeS Measurement object. This controls the saving of data by registering
        QCoDeS Parameter objects, which this function does. Registers all 'tracked' parameters, 
        Returns the measurement object.
        """

        self.meas = Measurement()
        self.meas.register_custom_parameter('time', label='Time', unit='s')
        for p in self._params:
            self.meas.register_parameter(p)

        return self.meas

    def create_figs(self):
        """
        Creates default figures for each of the parameters. Plots them in a new, separate window.
        """

        self.fig = plt.figure(figsize=(4 * (2 + len(self._params)), 4))
        self.grid = plt.GridSpec(4, 1 + len(self._params), hspace=0)
        self.setax = []
        self.setaxline = []

        for i, p in enumerate(self._params):
            self.setax.append(self.fig.add_subplot(self.grid[:, i]))
            # First, create a plot of the sweeping parameters value against time
            self.setax[i].set_xlabel('Time (s)')
            self.setax[i].set_ylabel(f'{p.label} ({p.unit})')
            self.setaxline.append(self.setax[i].plot([], [])[0])

    def pause_run(self):
        self.pause = not self.pause

    def is_paused(self):
        return self.pause

    def autorun(self):
        if self.save_data:
            with self.meas.run() as datasaver:

                while self.pause is False:
                    t = time.monotonic() - self.t0

                    data = []
                    data.append(('time', t))

                    for i, p in enumerate(self._params):
                        v = p.get()
                        data.append((p, v))

                        self.setaxline[i].set_xdata(
                            np.append(self.setaxline[i].get_xdata(), t))
                        self.setaxline[i].set_ydata(
                            np.append(self.setaxline[i].get_ydata(), v))
                        self.setax[i].relim()
                        self.setax[i].autoscale_view()

                    if self.save_data:
                        datasaver.add_result(*data)

                    plt.pause(self.inter_delay)

    def iterate(self):
        t = time.monotonic() - self.t0

        data = []
        data.append(('time', t))

        for i, p in enumerate(self._params):
            v = p.get()
            data.append((p, v))

            self.setaxline[i].set_xdata(
                np.append(self.setaxline[i].get_xdata(), t))
            self.setaxline[i].set_ydata(
                np.append(self.setaxline[i].get_ydata(), v))
            self.setax[i].relim()
            self.setax[i].autoscale_view()

        if self.save_data:
            datasaver.add_result(*data)

        plt.pause(self.inter_delay)
def G_up_B(station, field_max, v_polar, amplitude, stanford_gain_V_ac):

    #Before using this code change these values according to your own setup :
    
    R_polar = 1e6 #value of the polarization resistor

    now = datetime.now()
    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")    # dd/mm/YY H:M:S
    print(dt_string)    #print date and time of the measurement

    #Start the measurement

    meas = Measurement()

    meas.register_parameter(station.lockin_2.amplitude)
    meas.register_parameter(station.lockin_2.sine_outdc)
    meas.register_parameter(station.mag.y_measured)

    meas.register_parameter(station.lockin_1.Y, setpoints=(station.mag.y_measured,))
    meas.register_parameter(station.lockin_2.Y, setpoints=(station.mag.y_measured,))
    meas.register_parameter(station.lockin_1.X, setpoints=(station.mag.y_measured,))
    meas.register_parameter(station.lockin_2.X, setpoints=(station.mag.y_measured,))
    meas.register_custom_parameter("R_ac", unit="Ohm",setpoints=(station.mag.y_measured,))

    #Prepare the live plot
    win = qcm.pyplot.PlotWindow(title="Field Sweep 1D")
    win.resize(600,400)

    num_points = 0
    array_size = 1
    B_array = np.full((1,), np.nan)
    r_array = np.full((1,), np.nan)

    plot1 = win.addPlot(title ="R_ac(B)")
    plotdata = plot1.plot(setpoint_x = B_array)

    plot1.left_axis.label = "Resistance"
    plot1.left_axis.units = "Ohms"
    plot1.bot_axis.label = "B"
    plot1.bot_axis.units = "T"

    #Print the main lockin settings
    print(f'Stanford Gain V_AC ={stanford_gain_V_ac}')
   
    time_constant = station.lockin_2.time_constant()
    print(f'Integration time lockins {time_constant} s')

    print(f'Frequency Lockin : {station.lockin_2.frequency()} Hz')

    print(f'Filter lockin 1 : {station.lockin_1.filter_slope()} dB roll off')
    print(f'Sensitivity lockin 1 : {station.lockin_1.sensitivity()} V')

    print(f'Filter lockin 2 : {station.lockin_2.filter_slope()} dB roll off')
    print(f'Sensitivity lockin 2 : {station.lockin_2.sensitivity()} A')

    #Initialisation of the lockin

    station.lockin_2.amplitude(amplitude)
    print(f'V_ac polarization : {amplitude/1e-3} mV')

    station.lockin_2.sine_outdc(v_polar)
    print(f'V_dc polarization : {v_polar/1e-3} mV')



    with meas.run() as datasaver:

        station.mag.y_target(field_max)
        station.mag.ramp('simul')

        while abs(station.mag.y_measured()-field_max)>0.001:
        
            time.sleep(5*time_constant)

            b_y = station.mag.y_measured()

            voltage_X_AC = station.lockin_1.X()/stanford_gain_V_ac
            current_X_AC = station.lockin_2.X()

            voltage_Y_AC = station.lockin_1.Y()/stanford_gain_V_ac
            current_Y_AC = station.lockin_2.Y()

            R_ac = voltage_X_AC/current_X_AC

            datasaver.add_result(("R_ac", R_ac),
                                (station.lockin_2.amplitude, amplitude),
                                (station.lockin_2.sine_outdc, v_polar),
                                (station.mag.y_measured, b_y),
                                (station.lockin_2.Y,current_Y_AC),
                                (station.lockin_1.Y,voltage_Y_AC),
                                (station.lockin_2.X,current_X_AC),
                                (station.lockin_1.X,voltage_X_AC))

            B_array[num_points] = b_y
            r_array[num_points] = R_ac
            plotdata.xData = B_array
            plotdata.update(r_array)
            num_points += 1

            if num_points == array_size:
                array_size *= 2
                B_array.resize(array_size)
                B_array[array_size//2:] = np.nan
                r_array.resize(array_size)
                r_array[array_size//2:] = np.nan


        ID_exp = datasaver.run_id

    station.lockin_2.sine_outdc(0)

    win.export('figures/Rac_Field_sweep_1D_ID_exp_'+str(ID_exp)+'.png')

    plot_by_id(ID_exp)
Example #30
0
def RT_LT_ithaco(station, voltage, stanford_gain_V, gain_ithaco):

    station.dmm1.NPLC(10)
    station.dmm2.NPLC(10)

    station.yoko.output('off')
    station.yoko.source_mode("VOLT")
    station.yoko.output('on')

    station.yoko.voltage.step = 1e-3
    station.yoko.voltage.inter_delay = 0.0001

    meas = Measurement()

    meas.register_parameter(station.yoko.voltage)
    meas.register_parameter(station.BlueFors_LD.MC_temp)
    meas.register_custom_parameter("Counter")
    meas.register_custom_parameter("Current", unit = "A")
    meas.register_parameter(station.dmm1.volt)
    meas.register_parameter(station.dmm2.volt)
    meas.register_custom_parameter("Resistance", unit = "Ohms", setpoints=(station.BlueFors_LD.MC_temp,))
    
    win = qcm.pyplot.PlotWindow(title="R(T)")
    win.resize(750,500)

    num_points = 0
    array_size = 1
    temp_array = np.full((1,), np.nan)
    r_array = np.full((1,), np.nan)


    plot1 = win.addPlot(title="RT  4K - 8mK")
    plotdata = plot1.plot(setpoint_x=temp_array, color=(0, 0, 255))

    plot1.left_axis.label = "Resistance"
    plot1.left_axis.units = "Ohms"
    plot1.bot_axis.label = "Temperature"
    plot1.bot_axis.units = "K"

    j=0

    T = station.BlueFors_LD.MC_temp()

    with meas.run() as datasaver:
        
        while T  >0.008:
            T = station.BlueFors_LD.MC_temp() 

            station.yoko.voltage(voltage)
            
            time.sleep(1)

            volt_p = station.dmm1.volt()/stanford_gain_V
            curr_p = -station.dmm2.volt()/gain_ithaco
            
            
            station.yoko.voltage(-voltage)
            
            time.sleep(1)
            
            volt_m = station.dmm1.volt()/stanford_gain_V
            curr_m = -station.dmm2.volt()/gain_ithaco
            
            V_av = (volt_p - volt_m)/2
            I_av = (curr_p - curr_m)/2
            R_av = V_av/I_av

            datasaver.add_result((station.yoko.voltage, voltage),
                                (station.BlueFors_LD.MC_temp, T),
                                ("Counter", j),
                                 ("Resistance", R_av),
                                (station.dmm1.volt,V_av),
                                ("Current", I_av))

            temp_array[num_points] = T
            r_array[num_points] = R_av
            plotdata.xData = temp_array
            plotdata.update(r_array)
            num_points += 1

            if num_points == array_size:
                array_size *= 2
                temp_array.resize(array_size)
                temp_array[array_size//2:] = np.nan
                r_array.resize(array_size)
                r_array[array_size//2:] = np.nan
            
            #print((T,R_av))
            time.sleep(2)
            j = j+1
            
    station.yoko.voltage(0)