From c144c905f88a88ff742bfe5035a0822b9f33e4e8 Mon Sep 17 00:00:00 2001 From: G Adam Cox Date: Fri, 10 Feb 2023 10:20:37 -0800 Subject: [PATCH 1/2] Updates conversion of data lists to numpy arrays. After data acquisition is complete, data is stored in a list where each element of the list is a list of length two. The first element is a float and the second element is a numpy array. New versions of numpy prohibit automatic conversion of this kind of list to a numpy array without explicitly stating the data type of the array as an 'object'. This change is necessary to use versions of numpy > 1.23. --- pyproject.toml | 2 +- src/qt3utils/experiments/cwodmr.py | 2 +- src/qt3utils/experiments/podmr.py | 2 +- src/qt3utils/experiments/rabi.py | 3 +-- src/qt3utils/experiments/ramsey.py | 3 +-- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f3f19788..d054a5a5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "qt3utils" -version = "1.0.2.dev0" +version = "1.0.2.dev1" description = "A package for performing experiments in the QT3 lab at UW." readme = "README.md" diff --git a/src/qt3utils/experiments/cwodmr.py b/src/qt3utils/experiments/cwodmr.py index 2d2e6379..106ab6e8 100644 --- a/src/qt3utils/experiments/cwodmr.py +++ b/src/qt3utils/experiments/cwodmr.py @@ -203,7 +203,7 @@ def run(self, N_cycles = 500000, logger.error(f'in finally.close. {type(e)}: {e}') self.rfsynth.rf_off(self.rfsynth_channel) - data = np.array(data) + data = np.array(data, dtype=object) data = data[data[:,0].argsort()] #sorts the data by values in zeroth column... this is necessary if random_order = True return data diff --git a/src/qt3utils/experiments/podmr.py b/src/qt3utils/experiments/podmr.py index f520516d..480d9192 100644 --- a/src/qt3utils/experiments/podmr.py +++ b/src/qt3utils/experiments/podmr.py @@ -210,7 +210,7 @@ def run(self, N_cycles = 500000, except Exception as e: logger.error(f'in finally.close. {type(e)}: {e}') #rfsynth.rf_off(self.rfsynth_channel) - data = np.array(data) + data = np.array(data, dtype=object) data = data[data[:,0].argsort()] #sorts the data by values in zeroth column... this is necessary if random_order = True return data diff --git a/src/qt3utils/experiments/rabi.py b/src/qt3utils/experiments/rabi.py index 3e853c62..58831411 100644 --- a/src/qt3utils/experiments/rabi.py +++ b/src/qt3utils/experiments/rabi.py @@ -267,8 +267,7 @@ def run(self, N_cycles = 50000, except Exception as e: pass #rfsynth.rf_off(self.rfsynth_channel) - data = np.array(data) + data = np.array(data, dtype=object) return data - return data diff --git a/src/qt3utils/experiments/ramsey.py b/src/qt3utils/experiments/ramsey.py index 346c2ce3..9bcfeecd 100644 --- a/src/qt3utils/experiments/ramsey.py +++ b/src/qt3utils/experiments/ramsey.py @@ -228,8 +228,7 @@ def run(self, N_cycles = 50000, except Exception as e: logger.error(f'in finally.close. {type(e)}: {e}') #rfsynth.rf_off(self.rfsynth_channel) - data = np.array(data) + data = np.array(data, dtype=object) return data - return data From c8a53c947c662bed781efbcc93b001e3ef01463b Mon Sep 17 00:00:00 2001 From: G Adam Cox Date: Fri, 10 Feb 2023 10:56:59 -0800 Subject: [PATCH 2/2] Adds verbose documentation on return type --- src/qt3utils/experiments/cwodmr.py | 19 +++++++++++-------- src/qt3utils/experiments/podmr.py | 15 +++++++++------ src/qt3utils/experiments/rabi.py | 13 ++++++++----- src/qt3utils/experiments/ramsey.py | 28 ++++++++++++++-------------- 4 files changed, 42 insertions(+), 33 deletions(-) diff --git a/src/qt3utils/experiments/cwodmr.py b/src/qt3utils/experiments/cwodmr.py index 106ab6e8..acf80dbf 100644 --- a/src/qt3utils/experiments/cwodmr.py +++ b/src/qt3utils/experiments/cwodmr.py @@ -88,10 +88,10 @@ def experimental_conditions(self): def run(self, N_cycles = 500000, post_process_function = simple_measure_contrast, random_order = False): - ''' - Performs the CWODMR scan over the specificed range of frequencies. + """ + Performs the CWODMR scan over the specified range of frequencies. - For each frequency, some number of cycles of data are acquired. A cycle + For each frequency, the specified number of cycles of data are acquired. A cycle is one full sequence of the pulse train used in the experiment. For CWODMR, a cycle is {RF on for pulser.rf_pulse_duration time, RF off for pulser.rf_pulse_duration time}. @@ -109,7 +109,7 @@ def run(self, N_cycles = 500000, which is useful to reduce the required memory to hold the raw data. After data acquisition for each frequency in the scan, - the post_process_function function is called and takes two arguments: + the post_process_function is called and takes two arguments: 1) data_buffer: the full trace of data acquired 2) self: a reference to an instance of this object @@ -118,15 +118,18 @@ def run(self, N_cycles = 500000, If post_process_function = None, the full raw data trace will be kept. - The return from this function is a list. Each element of the list + The return from this function is a numpy array. Each element of the array is a list of the following values - RF Frequency, - data_post_processing_output (or raw data trace) + RF Frequency (float), + data_post_processing_output, or raw data trace (typically of type numpy array(dtype = float)) + + Because of the mixed types in this array, the numpy array data type returned + here is an 'object'. The remaining (fixed) values for analysis can be obtained from the self.experimental_conditions function. - ''' + """ self.N_cycles = int(N_cycles) diff --git a/src/qt3utils/experiments/podmr.py b/src/qt3utils/experiments/podmr.py index 480d9192..741f261d 100644 --- a/src/qt3utils/experiments/podmr.py +++ b/src/qt3utils/experiments/podmr.py @@ -96,7 +96,7 @@ def _stop_and_close_daq_tasks(self): def run(self, N_cycles = 500000, post_process_function = simple_measure_contrast, random_order = False): - ''' + """ Performs the PulsedODMR scan over the specificed range of frequencies. For each frequency, some number of cycles of data are acquired. A cycle @@ -117,7 +117,7 @@ def run(self, N_cycles = 500000, which is useful to reduce the required memory to hold the raw data. After data acquisition for each frequency in the scan, - the post_process_function function is called and takes two arguments: + the post_process_function is called and takes two arguments: 1) data_buffer: the full trace of data acquired 2) self: a reference to an instance of this object @@ -126,16 +126,19 @@ def run(self, N_cycles = 500000, If post_process_function = None, the full raw data trace will be kept. - The return from this function is a list. Each element of the list + The return from this function is a numpy array. Each element of the array is a list of the following values - RF Frequency, - data_post_processing_output (or raw data trace) + RF Frequency (float), + data_post_processing_output, or raw data trace (typically of type numpy array(dtype = float)) + + Because of the mixed types in this array, the numpy array data type returned + here is an 'object'. The remaining (fixed) values for analysis can be obtained from the self.experimental_conditions function. - ''' + """ self.N_cycles = int(N_cycles) diff --git a/src/qt3utils/experiments/rabi.py b/src/qt3utils/experiments/rabi.py index 58831411..c6061639 100644 --- a/src/qt3utils/experiments/rabi.py +++ b/src/qt3utils/experiments/rabi.py @@ -188,7 +188,7 @@ def _acquire_data_at_parameter(self, rf_pulse_duration, N_cycles = 10000, def run(self, N_cycles = 50000, post_process_function = qt3utils.experiments.podmr.simple_measure_contrast): - ''' + """ Performs the scan over the specificed range of RF widths. For each RF width, some number of cycles of data are acquired. A cycle @@ -221,14 +221,17 @@ def run(self, N_cycles = 50000, If post_process_function = None, the full raw data trace will be kept. - The return from this function is a list. Each element of the list + The return from this function is a numpy array. Each element of the array is a list of the following values - RF width, - data_post_processing_output (or raw data trace) + RF width (float), + data_post_processing_output, or raw data trace (typically of type numpy array(dtype = float)) + + Because of the mixed types in this array, the numpy array data type returned + here is an 'object'. The remaining (fixed) values for analysis can be obtained from the self.experimental_conditions function. - ''' + """ #first check that the pulser width is large enough try: diff --git a/src/qt3utils/experiments/ramsey.py b/src/qt3utils/experiments/ramsey.py index 9bcfeecd..3553df80 100644 --- a/src/qt3utils/experiments/ramsey.py +++ b/src/qt3utils/experiments/ramsey.py @@ -26,7 +26,7 @@ def __init__(self, ramsey_pulser, rfsynth, edge_counter_config, of an experiment and the hardware system setup. Hardware Settings - ramsey_pulser - a qt3utils.experiments.pulsers.pulseblaster.PulseBlasterRamHahnDD object + ramsey_pulser - a qt3utils.pulsers.pulseblaster.PulseBlasterRamHahnDD object rfsynth - a qt3rfsynthcontrol.Pulser object edge_counter_config - a qt3utils.nidaq.config.EdgeCounter object @@ -101,27 +101,24 @@ def experimental_conditions(self): def run(self, N_cycles = 50000, post_process_function = qt3utils.experiments.podmr.simple_measure_contrast): - ''' + """ Performs the scan over the specificed range of free precession times. - For each RF width, some number of cycles of data are acquired. A cycle - is one full sequence of the pulse train used in the experiment. - For Rabi, a cycle is {AOM on, AOM off/RF on, AOM on, AOM off/RF off}. + For each RF pulse delay, tau, some number of cycles of data are acquired. A cycle + is one full sequence of the pulse train used in the experiment as specified + by the supplied ramsey_pulser object. The N_cycles specifies the total number of these cycles to acquire. Your choice depends on your desired resolution or signal-to-noise ratio, your post-data acquisition processing choices, and the amount of memory available on your computer. - For each width, the number of data read from the NI DAQ will be + For each free precession time, tau, the number of data read from the NI DAQ will be N_clock_ticks_per_cycle * N_cycles, where N_clock_ticks_per_cycle is the value returned by self.set_pulser_state(tau). - Given the way our pulser is configured, N_clock_ticks_per_cycle will - grow linearly by tau. - The acquired data are stored in a data_buffer within this method. They - may be analyzed with a function passed to post_process_function, + may be processed with a function passed to post_process_function, which is useful to reduce the required memory to hold the raw data. After data acquisition for each width in the scan, @@ -134,14 +131,17 @@ def run(self, N_cycles = 50000, If post_process_function = None, the full raw data trace will be kept. - The return from this function is a list. Each element of the list + The return from this function is a numpy array. Each element of the array is a list of the following values - RF width, - data_post_processing_output (or raw data trace) + RF Frequency (float), + data_post_processing_output, or raw data trace (typically of type numpy array(dtype = float)) + + Because of the mixed types in this array, the numpy array data type returned + here is an 'object'. The remaining (fixed) values for analysis can be obtained from the self.experimental_conditions function. - ''' + """ #first check that the pulser width is large enough try: