Accessing unit test data

Striptease implements a few functions to download and access the data acquired during the unit tests of the Strip polarimeters. These tests were done at the cryogenic laboratory of the University of Milan Bicocca, and they are used as reference in some of the system-level tests. The tests are currently available at https://striptest.fisica.unimi.it/unittests/; the library provides a simple interface to download the data from there and load them into Python objects.

Here is an example that shows how to use these functionalities:

import striptease.unittests as u

# Download the test with ID #354 from the web server. This might
# take a few seconds…
test = u.get_unit_test(354)

# …but if you ask for it again, it will use a local cache and will
# return the value instantly
_ = u.get_unit_test(354)

# The result of the call to "u.get_unit_test" is a UnitTest object
print(type(test))
# Output:
# <class 'striptease.unittests.UnitTest'>

print(f"{test.url}, {test.polarimeter_name}")
# Output:
# https://striptest.fisica.unimi.it/unittests/tests/354, STRIP02

# The "test" variable only contains metadata about the test.
# To actually load the datasets, use "u.load_unit_test_data".
# It returns the actual data from the HDF5 file itself.
data = u.load_unit_test_data(test)

# The type of "data" depends on the test; it can either be a
# "UnitTestDC" class or a "UnitTestTimestream" class.
print(type(data))
# Output:
# <class 'striptease.unittests.UnitTestDC'>

As you see in the example, there are two functions to access the test data: the first one, get_unit_test(), downloads the metadata for a test, while the second one, load_unit_test_data(), download the full data. As the second one can take some time, if you are just interested in the general characteristics of the test (e.g., when the test was done, or on which polarimeter) you should call just get_unit_test().

striptease.get_unit_test(test_num: int, server='https://striptest.fisica.unimi.it', local_cache=PosixPath('/home/docs/.strip/unittests/unittests.db')) → Optional[striptease.unittests.UnitTest][source]

Return a UnitTest object referring to a unit test.

This function is used to access the data files acquired during the Strip Unit Tests done in Milano Bicocca. Each test is referenced by an unique number, which is passed in the parameter test_num. The parameter server must be a string containing the name of the web server hosting the test database. The parameter local_cache points to a file that will contain a local copy of each test downloaded from the webserver.

The following code prints some information about test #354:

from striptease.unittests import get_unit_test

test = get_unit_test(354)
print(f"The test was acquired on {test.acquisition_date}")

Once you retrieve the information for a test, you can use load_unit_test_data() to load the actual data acquired during the test.

Parameters:
  • test_num (int) – the unique ID of the unit test to download
  • server (str) – the protocol+name/IP address of the web server that hosts the unit tests. The default is the variable DEFAULT_UNIT_TEST_SERVER, and it should probably be ok for any situation.
  • local_cache (Path) – the path to a file that will contain a local copy of each test downloaded using this function. This speeds up subsequent queries to the same test.
Returns:

An instance of UnitTest.

striptease.load_unit_test_data(input_file: Union[str, pathlib.Path, striptease.unittests.UnitTest]) → Union[striptease.unittests.UnitTestTimestream, striptease.unittests.UnitTestDC][source]

Load an HDF5 file into a Timestream object

Return either an instance of the class UnitTestTimestream or UnitTestDC. The choice between the two types depends on the type of the test (i.e., the value of the key test_type in the metadata of the test):

  1. DC tests return a UnitTestDc; these tests were acquired by directly sampling the biases at the components of the polarimeters, and no proper time streams were recorded.
  2. All other types of tests return a UnitTestTimestream.

The typical usage for this function is to call it on the result of a call to get_unit_test(), as in the following example:

import striptease.unittests as u

test = u.get_unit_test(354)
data = load_unit_test_data(test)
Parameters:input_file – Either a string containing the path to a HDF5 file, a pathlib.Path object, or a UnitTest object.
Returns:(1) a dictionary containing a set of attributes read from the root object of the HDF5 file, and (2) either an instance of the class UnitTestTimestream or UnitTestDC, depending on the type of the test.
Return type:A pair containing two elements

The type of the return value of the function load_unit_test_data() depends on the kind of test. During the unit tests in the cryogenic laboratory of the University of Milano Bicocca, tests were grouped in two categories:

  • DC tests exercised every single component of each polarimetric unit. They were done using an apparatus that provided biases and measured currents and voltages. Data acquired during this kind of test is stored in a UnitTestDC object.
  • The tests that exercised the polarimeter as a whole used a different acquisition system, which was able to record the timing of each measurement. Data acquired during this kind of test is stored in a UnitTestTimestream object.

In the next chapters we detail the structure of the two classes UnitTestDC and UnitTestTimestream.

class striptease.UnitTestType[source]

An enumeration.

class striptease.UnitTest(url: str = '', metadata: Dict[str, Any] = <factory>, hdf5_file_path: pathlib.Path = PosixPath('.'))[source]

Information about a polarimetric unit test

This class hold some information about the data of a polarimetric unit test ran in Bologna, and it is returned by the function get_unit_test(). It contains the following fields:

  • url: a string containing the base URL of the test
  • metadata: a dictionary containing the JSON record downloaded from the web server. This dictionary contains many details about the test itself: the name of the operators that actually executed the test, the date when the data was acquired, etc.
  • hdf5_file_path: a pathlib.Path object pointing to the HDF5 file saved in the local cache. Instead of accessing this file directly, you should instead call load_unit_test_data().
class striptease.UnitTestDC(acquisition_date: datetime.date, band: str, is_cryogenic: bool, polarimeter_name: str, url: str, components: Dict[str, striptease.unittests.UnitTestDCCurves] = <factory>)[source]

Detailed information about a unit-level DC test of a polarimeter.

This class is created by the function load_unit_test_data() whenever a DC test is requested. It contains the following fields:

  • acquisition_date: a datetime.date object containing the date when the test was acquired.
  • band: a string containing either Q or W;
  • is_cryogenic: a Boolean value indicating whether the test was done in cryogenic or warm conditions;
  • polarimeter_name: the name of the polarimeter being tested (e.g., STRIP02);
  • url: a string containing the URL of the test page
  • components: a dictionary associating the name of each component of the polarimeter (e.g., HA1 for the first amplifier of the first leg) with a UnitTestDCCurves object, which contains the data of the various curves characterizing the polarimetric component.
class striptease.UnitTestTimestream(acquisition_date: datetime.date, band: str, is_cryogenic: bool, polarimeter_name: str, url: str, time_s: Any = None, pctime: Any = None, phb: Any = None, record: Any = None, demodulated: Any = None, power: Any = None, rfpower_db: Any = None, freq_hz: Any = None)[source]

A time stream acquired from one polarimeter during the Unit Level tests in Bicocca.

This class is created by the function load_unit_test_data() whenever the caller asks to load a unit-level test where a timestream is acquired (e.g., bandpass measurement, noise temperature characterization, etc.). It contains the following fields:

  • acquisition_date: a datetime.date object containing the date when the test was acquired.
  • band: a string containing either Q or W;
  • is_cryogenic: a Boolean value indicating whether the test was done in cryogenic or warm conditions;
  • polarimeter_name: the name of the polarimeter being tested (e.g., STRIP02);
  • url: a string containing the URL of the test page
  • time_s: A NumPy array containing the time in seconds
  • pctime: A NumPy array containing the On-board time, in clock ticks
  • phb: A NumPy array containing the phase of the slow phase switch
  • record: A NumPy array containing an undocumented field
  • demodulated: A 4×N NumPy matrix containing the output of
    DEM0, DEM1, DEM2, DEM3 channels
  • power: A 4×N NumPy matrix containing the output of PWR0,
    PWR1, PWR2, PWR3 channels
  • rfpower_db: A NumPy array containing the power of the
    -radiofrequency generator, in dB, or 1 if turned off
  • freq_hz: A NumPy array containing the frequency of the
    signal injected by the radiofrequency generator, in Hertz. If the generator is turned off, this is -1.

Single-component tests

Single-component tests, also known as «DC tests», are represented by an instance of the class UnitTestDC. The class provides the data measured while exercising each of the components in the components field, which is an instance of the class UnitTestDCCurves. You can think of both classes as wrappers to dict types.

Here is an example, using test #354 as a testbed:

import striptease.unittests as u
import matplotlib.pylab as plt

data = u.load_unit_test_data(u.get_unit_test(354))
ha1_ivdv_data = data.components['HA1'].curves['IDVD']

_, axes = plt.subplots(nrows=3, figsize=(6, 14))
axes[0].plot(
    ha1_ivdv_data['DrainV'],
    ha1_ivdv_data['DrainI'],
)
axes[0].set_title(r'$V_d \times I_d$ curves for HA1')
axes[0].set_xlabel('Drain voltage')
axes[0].set_ylabel('Drain current')

axes[1].plot(ha1_ivdv_data['GateI'], '.')
axes[1].set_ylabel('Gate current')

axes[2].plot(ha1_ivdv_data['GateV'], '.')
axes[2].set_ylabel('Gate voltage')

The result is the following plot:

Plot of a DC test

Plot generated by the example script

Note that in this test the drain current and voltage were measured every time the gate biases were changed. The actual behavior of the data depends of course on the component and the test being done.

Polarimetric tests (timelines)

Timeline data acquired during a Strip unit test is stored in objects of type UnitTestTimestream. The following example shows how to plot the demodulated data acquired during test #355 (STRIP02):

import striptease.unittests as u
import matplotlib.pylab as plt

data = u.load_unit_test_data(u.get_unit_test(355))
_, axes = plt.subplots(nrows=4, figsize=(6, 17))

# Plot the output of DEM0, DEM1, DEM2, and DEM3
for i in range(4):
    axes[i].plot(data.time_s, data.demodulated[:, i])
    axes[i].set_xlabel("Time [s]")
    axes[i].set_ylabel("Signal [ADU]")

And here is the result:

Plot of a polarimetric test

Plot generated by the example script

Other information

There are a few other functions implemented by the framework that you might find useful, e.g., when you are producing a report and want to put links to a unit test you used in your calculations.

striptease.unit_test_url(test_num: int, server='https://striptest.fisica.unimi.it') → str[source]

Return a string containing the URL of a unit-level test

striptease.unit_test_json_url(test_num: int, server='https://striptest.fisica.unimi.it') → str[source]

Return a string containing the URL of the JSON record for a unit-level test

striptease.unit_test_download_url(test_num: int, server='https://striptest.fisica.unimi.it') → str[source]

Return a string containing the URL used to download the HDF5 file of a test

How caching works

Every time the function get_unit_test() is called, it saves a copy of the HDF5 file and the metadata downloaded from the unit test webserver into a hidden directory within the home folder of the current user. The metadata are saved in a SQLite3 database, and the HDF5 file is saved within the same folder.

The path to the SQLite3 database can be accessed using the constant DEFAULT_UNIT_TEST_CACHE_PATH. However, you will probably never need to mess with this directory, as it is handled internally by the library.