This page was generated from docs/examples/DataSet/Paramtypes explained.ipynb. Interactive online version: Binder badge.

Paramtypes explained

Internally in the SQLite database on disk, data are registered as being of one of (currently) four allowed types:

  • numeric

  • array

  • text

  • complex

This notebook seeks to exemplify when each type should be used, and how differently the Measurement object treats data of each type.

We start with necessary imports, and then initialising our database and creating an experiment.

[1]:
import os
import time

import numpy as np

from qcodes.dataset import (
    Measurement,
    initialise_or_create_database_at,
    load_or_create_experiment,
)
from qcodes.instrument_drivers.mock_instruments import DummyInstrument
from qcodes.parameters import ArrayParameter
Logging hadn't been started.
Activating auto-logging. Current session state plus future input saved.
Filename       : /home/runner/.qcodes/logs/command_history.log
Mode           : append
Output logging : True
Raw input log  : False
Timestamping   : True
State          : active
Qcodes Logfile : /home/runner/.qcodes/logs/240508-15379-qcodes.log
[2]:
initialise_or_create_database_at(os.path.join(os.getcwd(), 'paramtypes_explained.db'))
exp = load_or_create_experiment('paramtypes', sample_name='not_available')

Let us, now, create two dummy instruments to be used in our experiment.

[3]:
dac = DummyInstrument('dac', gates=['ch1', 'ch2'])
SA = DummyInstrument('SA')
[4]:
# some array-like data types


class Spectrum(ArrayParameter):

    def __init__(self, name, instrument):

        self.N = 7
        setpoints = (np.linspace(0, 1, self.N),)

        super().__init__(name=name,
                         instrument=instrument,
                         setpoints=setpoints,
                         shape=(20,),
                         label='Noisy spectrum',
                         unit='V/sqrt(Hz)',
                         setpoint_names=('Frequency',),
                         setpoint_units=('Hz',))

    def get_raw(self):
        return np.random.randn(self.N)


class MultiDimSpectrum(ArrayParameter):

    def __init__(self, name, instrument):
        self.start = 0
        self.stop = 1
        self.npts = (2, 5, 3)
        sp1 = np.linspace(self.start, self.stop,
                          self.npts[0])
        sp2 = np.linspace(self.start, self.stop,
                          self.npts[1])
        sp3 = np.linspace(self.start, self.stop,
                          self.npts[2])
        setpoints = (sp1,
                     np.tile(sp2, (len(sp1), 1)),
                     np.tile(sp3, (len(sp1), len(sp2), 1)))
        super().__init__(name=name,
                         instrument=instrument,
                         setpoints=setpoints,
                         shape=(100, 50, 20),
                         label='Flower Power Spectrum in 3D',
                         unit='V/sqrt(Hz)',
                         setpoint_names=('Frequency0', 'Frequency1',
                                         'Frequency2'),
                             setpoint_units=('Hz', 'Other Hz', "Third Hz"))

    def get_raw(self):
        a = self.npts[0]
        b = self.npts[1]
        c = self.npts[2]
        return np.reshape(np.arange(a*b*c), (a, b, c))

# a string-valued parameter


def dac1_too_high():
    return 'Too high' if dac.ch1() > 5 else 'OK'

Finally, we add our parameters to the dummy instruments:

[5]:
dac.add_parameter('control', get_cmd=dac1_too_high)
SA.add_parameter('spectrum', parameter_class=Spectrum)
SA.add_parameter('spectrum3D', parameter_class=MultiDimSpectrum)

Numeric

The numeric datatype is simply a number. Data registered with this type are saved as individual numbers. This is the default datatype when registering parameters.

Numeric example 1

In this example, all parameters get registered as numeric type. This entails that the array in unraveled and inserted point-by-point.

[6]:
meas = Measurement(exp=exp)
meas.register_parameter(dac.ch1)
meas.register_parameter(SA.spectrum, setpoints=(dac.ch1,))

t0 = time.perf_counter()

with meas.run() as datasaver:
    for dac_v in np.linspace(0, 2, 5):
        dac.ch1(dac_v)
        datasaver.add_result((dac.ch1, dac_v), (SA.spectrum, SA.spectrum()))

t1 = time.perf_counter()

print(f'Finished run in {(t1-t0):.3f} s')

dataset1 = datasaver.dataset
Starting experimental run with id: 1.
Finished run in 0.021 s

The data may be retrieved using the get_parameter_data method. This function will bring back the data in a way that reflects the datastructure as it is stored.

[7]:
dataset1.get_parameter_data()
[7]:
{'SA_spectrum': {'SA_spectrum': array([[-0.64338438,  0.10255998, -0.24770061, -0.1338508 , -0.31338664,
          -0.37219301, -0.11297632],
         [ 1.6251966 , -0.1923248 , -0.09041389,  0.45631154, -0.26691936,
           0.63012185,  0.41554131],
         [-1.92461719, -0.3189955 , -1.07730978,  0.33155346,  0.01791025,
           0.13429531, -1.27223058],
         [-0.1892373 , -1.43649941, -0.8201869 , -0.5458621 ,  0.40043134,
           1.24858852,  0.31813436],
         [-0.19898771,  0.26043093, -1.31079252, -1.12846602,  0.17262878,
           1.19688513, -0.69039067]]),
  'dac_ch1': array([[0. , 0. , 0. , 0. , 0. , 0. , 0. ],
         [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
         [1. , 1. , 1. , 1. , 1. , 1. , 1. ],
         [1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5],
         [2. , 2. , 2. , 2. , 2. , 2. , 2. ]]),
  'SA_Frequency': array([[0.        , 0.16666667, 0.33333333, 0.5       , 0.66666667,
          0.83333333, 1.        ],
         [0.        , 0.16666667, 0.33333333, 0.5       , 0.66666667,
          0.83333333, 1.        ],
         [0.        , 0.16666667, 0.33333333, 0.5       , 0.66666667,
          0.83333333, 1.        ],
         [0.        , 0.16666667, 0.33333333, 0.5       , 0.66666667,
          0.83333333, 1.        ],
         [0.        , 0.16666667, 0.33333333, 0.5       , 0.66666667,
          0.83333333, 1.        ]])}}

Array

The array paramtype stores data as binary blobs in the database. Insertion is faster (asymptotically much faster) this way, but the data are “dead” to SQL queries inside the database. Be informed that a BLOB in sqlite has a default max length limit set at 1 billion (1,000,000,000) bytes (for more information, refer to Sqlite docs).

Array example 1

Let us repeat the above measurement, but this time using array paramtypes.

[8]:
meas = Measurement(exp=exp)
meas.register_parameter(dac.ch1)
meas.register_parameter(SA.spectrum, setpoints=(dac.ch1,), paramtype='array')

t0 = time.perf_counter()

with meas.run() as datasaver:
    for dac_v in np.linspace(0, 2, 5):
        dac.ch1(dac_v)
        datasaver.add_result((dac.ch1, dac_v), (SA.spectrum, SA.spectrum()))

t1 = time.perf_counter()

print(f'Finished run in {(t1-t0):.3f} s')

dataset2 = datasaver.dataset
Starting experimental run with id: 2.
Finished run in 0.012 s
[9]:
dataset2.get_parameter_data()
[9]:
{'SA_spectrum': {'SA_spectrum': array([[ 0.08793072, -0.13400467,  0.57117557, -1.23291948, -1.12015827,
           1.466851  ,  1.46304373],
         [ 0.54909911, -1.88877258,  2.55989884, -0.72670758, -0.58865027,
           1.21933933,  0.01905281],
         [-0.03873303,  0.51650937, -0.65405771, -0.77641302,  0.13629895,
           0.11411464,  0.23845281],
         [ 0.39650286, -2.25712826,  0.182786  , -1.87259143, -2.05947184,
          -0.08414006, -0.66069054],
         [-0.86723109,  0.07792755,  0.23513656, -1.4840619 ,  0.52638165,
          -0.1250588 ,  0.71303083]]),
  'dac_ch1': array([[0. , 0. , 0. , 0. , 0. , 0. , 0. ],
         [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
         [1. , 1. , 1. , 1. , 1. , 1. , 1. ],
         [1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5],
         [2. , 2. , 2. , 2. , 2. , 2. , 2. ]]),
  'SA_Frequency': array([[0.        , 0.16666667, 0.33333333, 0.5       , 0.66666667,
          0.83333333, 1.        ],
         [0.        , 0.16666667, 0.33333333, 0.5       , 0.66666667,
          0.83333333, 1.        ],
         [0.        , 0.16666667, 0.33333333, 0.5       , 0.66666667,
          0.83333333, 1.        ],
         [0.        , 0.16666667, 0.33333333, 0.5       , 0.66666667,
          0.83333333, 1.        ],
         [0.        , 0.16666667, 0.33333333, 0.5       , 0.66666667,
          0.83333333, 1.        ]])}}

Array example 2

When storing multidimensional array data (think: Alazar cards), both numeric and array types can be used.

[10]:
meas = Measurement(exp=exp)
meas.register_parameter(SA.spectrum3D, paramtype='array')

with meas.run() as datasaver:
    datasaver.add_result((SA.spectrum3D, SA.spectrum3D()))
dataset3 = datasaver.dataset
Starting experimental run with id: 3.

The data come out the way we expect them to.

[11]:
dataset3.get_parameter_data()
[11]:
{'SA_spectrum3D': {'SA_spectrum3D': array([[[[ 0,  1,  2],
           [ 3,  4,  5],
           [ 6,  7,  8],
           [ 9, 10, 11],
           [12, 13, 14]],

          [[15, 16, 17],
           [18, 19, 20],
           [21, 22, 23],
           [24, 25, 26],
           [27, 28, 29]]]]),
  'SA_Frequency0': array([[[[0., 0., 0.],
           [0., 0., 0.],
           [0., 0., 0.],
           [0., 0., 0.],
           [0., 0., 0.]],

          [[1., 1., 1.],
           [1., 1., 1.],
           [1., 1., 1.],
           [1., 1., 1.],
           [1., 1., 1.]]]]),
  'SA_Frequency1': array([[[[0.  , 0.  , 0.  ],
           [0.25, 0.25, 0.25],
           [0.5 , 0.5 , 0.5 ],
           [0.75, 0.75, 0.75],
           [1.  , 1.  , 1.  ]],

          [[0.  , 0.  , 0.  ],
           [0.25, 0.25, 0.25],
           [0.5 , 0.5 , 0.5 ],
           [0.75, 0.75, 0.75],
           [1.  , 1.  , 1.  ]]]]),
  'SA_Frequency2': array([[[[0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ]],

          [[0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ]]]])}}

Array example 3

For completeness, here, we provide an example where the multidimensional array has an auxiliary setpoint.

[12]:
meas = Measurement(exp=exp)
meas.register_parameter(dac.ch1)
meas.register_parameter(SA.spectrum3D, paramtype='array', setpoints=(dac.ch1,))

with meas.run() as datasaver:
    for dac_v in [3, 4, 5]:
        dac.ch1(dac_v)
        datasaver.add_result((dac.ch1, dac_v),
                             (SA.spectrum3D, SA.spectrum3D()))
dataset4 = datasaver.dataset
Starting experimental run with id: 4.
[13]:
dataset4.get_parameter_data()
[13]:
{'SA_spectrum3D': {'SA_spectrum3D': array([[[[ 0,  1,  2],
           [ 3,  4,  5],
           [ 6,  7,  8],
           [ 9, 10, 11],
           [12, 13, 14]],

          [[15, 16, 17],
           [18, 19, 20],
           [21, 22, 23],
           [24, 25, 26],
           [27, 28, 29]]],


         [[[ 0,  1,  2],
           [ 3,  4,  5],
           [ 6,  7,  8],
           [ 9, 10, 11],
           [12, 13, 14]],

          [[15, 16, 17],
           [18, 19, 20],
           [21, 22, 23],
           [24, 25, 26],
           [27, 28, 29]]],


         [[[ 0,  1,  2],
           [ 3,  4,  5],
           [ 6,  7,  8],
           [ 9, 10, 11],
           [12, 13, 14]],

          [[15, 16, 17],
           [18, 19, 20],
           [21, 22, 23],
           [24, 25, 26],
           [27, 28, 29]]]]),
  'dac_ch1': array([[[[3., 3., 3.],
           [3., 3., 3.],
           [3., 3., 3.],
           [3., 3., 3.],
           [3., 3., 3.]],

          [[3., 3., 3.],
           [3., 3., 3.],
           [3., 3., 3.],
           [3., 3., 3.],
           [3., 3., 3.]]],


         [[[4., 4., 4.],
           [4., 4., 4.],
           [4., 4., 4.],
           [4., 4., 4.],
           [4., 4., 4.]],

          [[4., 4., 4.],
           [4., 4., 4.],
           [4., 4., 4.],
           [4., 4., 4.],
           [4., 4., 4.]]],


         [[[5., 5., 5.],
           [5., 5., 5.],
           [5., 5., 5.],
           [5., 5., 5.],
           [5., 5., 5.]],

          [[5., 5., 5.],
           [5., 5., 5.],
           [5., 5., 5.],
           [5., 5., 5.],
           [5., 5., 5.]]]]),
  'SA_Frequency0': array([[[[0., 0., 0.],
           [0., 0., 0.],
           [0., 0., 0.],
           [0., 0., 0.],
           [0., 0., 0.]],

          [[1., 1., 1.],
           [1., 1., 1.],
           [1., 1., 1.],
           [1., 1., 1.],
           [1., 1., 1.]]],


         [[[0., 0., 0.],
           [0., 0., 0.],
           [0., 0., 0.],
           [0., 0., 0.],
           [0., 0., 0.]],

          [[1., 1., 1.],
           [1., 1., 1.],
           [1., 1., 1.],
           [1., 1., 1.],
           [1., 1., 1.]]],


         [[[0., 0., 0.],
           [0., 0., 0.],
           [0., 0., 0.],
           [0., 0., 0.],
           [0., 0., 0.]],

          [[1., 1., 1.],
           [1., 1., 1.],
           [1., 1., 1.],
           [1., 1., 1.],
           [1., 1., 1.]]]]),
  'SA_Frequency1': array([[[[0.  , 0.  , 0.  ],
           [0.25, 0.25, 0.25],
           [0.5 , 0.5 , 0.5 ],
           [0.75, 0.75, 0.75],
           [1.  , 1.  , 1.  ]],

          [[0.  , 0.  , 0.  ],
           [0.25, 0.25, 0.25],
           [0.5 , 0.5 , 0.5 ],
           [0.75, 0.75, 0.75],
           [1.  , 1.  , 1.  ]]],


         [[[0.  , 0.  , 0.  ],
           [0.25, 0.25, 0.25],
           [0.5 , 0.5 , 0.5 ],
           [0.75, 0.75, 0.75],
           [1.  , 1.  , 1.  ]],

          [[0.  , 0.  , 0.  ],
           [0.25, 0.25, 0.25],
           [0.5 , 0.5 , 0.5 ],
           [0.75, 0.75, 0.75],
           [1.  , 1.  , 1.  ]]],


         [[[0.  , 0.  , 0.  ],
           [0.25, 0.25, 0.25],
           [0.5 , 0.5 , 0.5 ],
           [0.75, 0.75, 0.75],
           [1.  , 1.  , 1.  ]],

          [[0.  , 0.  , 0.  ],
           [0.25, 0.25, 0.25],
           [0.5 , 0.5 , 0.5 ],
           [0.75, 0.75, 0.75],
           [1.  , 1.  , 1.  ]]]]),
  'SA_Frequency2': array([[[[0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ]],

          [[0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ]]],


         [[[0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ]],

          [[0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ]]],


         [[[0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ]],

          [[0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ],
           [0. , 0.5, 1. ]]]])}}

Text

Text is strings. Sometimes it may be useful to capture categorial data that is represented as string values, or a log message, or else.

Note that the paramtype setting is important. The datasaver will not allow to save numeric data for a parameter that was registered as text. The opposite it also true: the datasaver will not allow to save strings for a parameter what was registered as non-text (numeric or array).

[14]:
meas = Measurement(exp=exp)
meas.register_parameter(dac.ch1)
meas.register_parameter(dac.control, setpoints=(dac.ch1,), paramtype='text')

with meas.run() as datasaver:
    for dac_v in np.linspace(4, 6, 10):
        dac.ch1(dac_v)
        datasaver.add_result((dac.ch1, dac_v),
                             (dac.control, dac.control()))
dataset5 = datasaver.dataset
Starting experimental run with id: 5.
[15]:
dataset5.get_parameter_data()
[15]:
{'dac_control': {'dac_control': array(['OK', 'OK', 'OK', 'OK', 'OK', 'Too high', 'Too high', 'Too high',
         'Too high', 'Too high'], dtype='<U8'),
  'dac_ch1': array([4.        , 4.22222222, 4.44444444, 4.66666667, 4.88888889,
         5.11111111, 5.33333333, 5.55555556, 5.77777778, 6.        ])}}
[ ]: