Download

Download this file as Jupyter notebook: hdf5_file_interface.ipynb.

Interfacing with HDF5 files

After executing a program, its results can be exported from the database to a portable HDF5 file with the to_hdf5() method, as shown in Running a program on hardware. In this tutorial, we go over of the structure of these files.

[2]:
import h5py
import keysight.qcs as qcs
import numpy as np

file = h5py.File("swept_program.hdf5")

Attributes on the file

The attributes of the HDF5 are accessed with the attrs property.

[3]:
list(file.attrs.keys())
[3]:
['Program', 'ChannelMapper', 'FPGAPostprocessing', 'Shape', 'Version']

The FPGAPostprocessing attribute specifies whether these results are obtained with (True) or without (False) hardware demodulation. The file contains either IQ or trace data, respectively. This file contains trace data.

[4]:
file.attrs["FPGAPostprocessing"]
[4]:
False

The Shape attribute describes how the program was repeated during execution and is similar to the shape of a program’s repetitions. As we flatten the data, this value describes how the data should be reshaped. For trace data the innermost value is set to \(-1\) to account for different numbers of samples, following the the convention of, e.g., numpy.reshape().

[5]:
file.attrs["Shape"]
[5]:
array([11, 10, -1], dtype=int32)

The above value indicates that the trace data should be interpreted as an array of shape \((11, 10, n / (11 * 10))\), where \(n\) is the total number of data points.

Finally, the Program and the ChannelMapper used during its execution are serialized and stored in the file.

Datasets on the file

The file structure is different dependent on whether the program contains IQ or trace data.

Trace data

An HDF5 file containing trace data will store each repeated acquisition in its own dataset. The datasets are stored in groups named DutChannel_{channel_number}_Acquisition_{acquisition_number} that are keys of the file, each of which corresponds to a physical channel.

[6]:
list(file.keys())
[6]:
['DutChannel_1_Acquisition_0']

This file contains a single group for the acquisitions on DutChannel_1. The group has a dataset with no additional attributes named trace.

[7]:
acquisition = file["DutChannel_1_Acquisition_0"]["trace"]
acquisition.shape
[7]:
(42240,)

We then reshape to and display the innermost value, the number of samples per repetition.

[8]:
np.reshape(acquisition, file.attrs["Shape"]).shape[-1]
[8]:
384

IQ data

We now load a file that contains results from the same program run with hardware demodulation.

[9]:
file_demod = h5py.File("swept_program_demod.hdf5")
file_demod.attrs["FPGAPostprocessing"]
[9]:
True

Instead of using physical channels as keys, the IQ data uses virtual channels to label the groups as Channel_{channel_name}_{channel_label}_Acquisition_{acquisition_number}.

[10]:
list(file_demod.keys())
[10]:
['Channel_digs_0_Acquisition_0',
 'Channel_digs_1_Acquisition_0',
 'Channel_digs_2_Acquisition_0',
 'Channel_digs_3_Acquisition_0']

The IQ data is separated into real and imaginary parts.

[11]:
acquisition_demod = file_demod["Channel_digs_0_Acquisition_0"]
print(acquisition_demod["iq_real"])
print(acquisition_demod["iq_imaginary"])
<HDF5 dataset "iq_real": shape (110,), type "<f8">
<HDF5 dataset "iq_imaginary": shape (110,), type "<f8">

The shape of the IQ data is exactly the program’s repetitions’ shape.

[12]:
np.reshape(acquisition_demod["iq_real"], file_demod.attrs["Shape"]).shape
[12]:
(11, 10)

Accessing metadata from the program

The program that was executed can be loaded from the file by calling load().

[13]:
program = qcs.load("swept_program.hdf5")

We can access metadata including, e.g., the program’s repetitions.

[14]:
program.repetitions
[14]:
NestedRepetition(Sweep(rf=Array(name=freq_vals, shape=(11, 4), dtype=float, unit=none)), Repeat(10))

From this, we see that the program’s rf variable was swept with freq_vals and each sweep point was repeated \(10\) times.


Download

Download this file as Jupyter notebook: hdf5_file_interface.ipynb.

On this page