From 62338e95a4c34b13f0189b770d4779c729b0ae75 Mon Sep 17 00:00:00 2001 From: Alrik Date: Mon, 17 Aug 2020 11:01:51 +0200 Subject: [PATCH 1/8] added scripting helpers to timeseries logic --- logic/time_series_reader_logic.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/logic/time_series_reader_logic.py b/logic/time_series_reader_logic.py index 2473d666e7..f6764ebf49 100644 --- a/logic/time_series_reader_logic.py +++ b/logic/time_series_reader_logic.py @@ -812,3 +812,30 @@ def _stop_reader_wait(self): self.module_state.unlock() self.sigStatusChanged.emit(False, False) return 0 + + # Scripting zone + # + # The methods bellow are meant to be used be external script which have their own thread. + + def get_average_value(self, duration): + """ Get the average value on a given duration over all channels + + @param (float) duration: The approximate duration on which average should be computed. + + @return (np.array): An array of the average value of each active channels + + """ + if duration > self.trace_window_size: + self.log.error('Trace window duration ({} s) is smaller that required duration ({} s)'.format( + self.trace_window_size, duration)) + bins = int(duration * self.data_rate) + return self._trace_data[:, -bins:].mean(axis=1) + + def get_average_value_recorded_data(self): + """ Get the average value of each channel on the currently recorded data + + @return (np.array): An array of the average value of each active channels on the currently recorded data + + """ + return np.concatenate(self._recorded_data, axis=1).mean(axis=1) + From 30f69dbe84d4fee39666892da13f9fa6cd09a140 Mon Sep 17 00:00:00 2001 From: Alrik Date: Mon, 17 Aug 2020 11:11:21 +0200 Subject: [PATCH 2/8] added poi optimizer block method --- logic/poi_manager_logic.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/logic/poi_manager_logic.py b/logic/poi_manager_logic.py index 3895b5c51c..67a76cb760 100644 --- a/logic/poi_manager_logic.py +++ b/logic/poi_manager_logic.py @@ -1255,4 +1255,18 @@ def auto_catch_poi(self): pois[i] = [x_axis[xc2[i]], y_axis[yc2[i]], z] self.add_poi(pois[i]) if self.poi_nametag is None: - time.sleep(0.1) \ No newline at end of file + time.sleep(0.1) + + # Scripting zone + # + # The methods bellow are meant to be used be external script which have their own thread. + + def optimise_poi_position_sync(self, name=None, update_roi_position=True): + """ Start an usual optimization procedure but wait for it to finish before returning + + This method blocks the caller's thread and not this module's thread. + """ + self.optimise_poi_position(name=name, update_roi_position=update_roi_position) + while self.optimiserlogic().module_state() != 'idle': + time.sleep(0.1) + return From 7f725f0bf80afb37a3d904fecb355438e32c945d Mon Sep 17 00:00:00 2001 From: Alrik Date: Mon, 17 Aug 2020 11:39:04 +0200 Subject: [PATCH 3/8] added helper methods to POI logic --- logic/poi_manager_logic.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/logic/poi_manager_logic.py b/logic/poi_manager_logic.py index 67a76cb760..a4651595bf 100644 --- a/logic/poi_manager_logic.py +++ b/logic/poi_manager_logic.py @@ -24,6 +24,7 @@ import os import numpy as np import time +import re from collections import OrderedDict from core.connector import Connector @@ -1270,3 +1271,34 @@ def optimise_poi_position_sync(self, name=None, update_roi_position=True): while self.optimiserlogic().module_state() != 'idle': time.sleep(0.1) return + + def get_poi_list(self, regexp='*', check_in_range=False): + """ Get a list of all the POIs filtered by a given regular expression + + @param (str) regexp: A regular expression to match POI names before returning + @param (bool) check_in_range: Only returns POI in range if True + + To learn what is a regular expression, see : https://en.wikipedia.org/wiki/Regular_expression + """ + r = re.compile(regexp) + result = [name for name in self.poi_names if r.match(name)] + if check_in_range: + result = [name for name in result if self.is_poi_in_range(result)] + return result + + def is_poi_in_range(self, name, margin=0e-6, z_margin=0e-6): + """ Test if a given POI is in range of the scanner + + @param (str) name: name of the poi to query + @param (float) margin: Margin (m) on the X and Y directions necessary to consider the POI in range + @param (float) z_margin: Margin (m) on the Z direction necessary to consider the POI in range + + This method can be used when iterating over a lot of POI to check if they are currently in the scan range. + Margin can be applied to filter out POIs too close to the scanner edges. + """ + if name is None or name not in self.poi_names: + return False + x, y, z = self.get_poi_position(name) + return self.scannerlogic().x_range[0] + margin <= x <= self.scannerlogic().x_range[1] - margin and \ + self.scannerlogic().y_range[0] + margin <= y <= self.scannerlogic().y_range[1] - margin and \ + self.scannerlogic().z_range[0] + z_margin <= z <= self.scannerlogic().y_range[1] - z_margin From 3473a62e961c9613758d5cffe56de089baa48912 Mon Sep 17 00:00:00 2001 From: Alrik Date: Mon, 17 Aug 2020 11:58:48 +0200 Subject: [PATCH 4/8] added a stop sync helper method to odmr_logic --- logic/odmr_logic.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/logic/odmr_logic.py b/logic/odmr_logic.py index 4094320b28..5e2f0f6255 100644 --- a/logic/odmr_logic.py +++ b/logic/odmr_logic.py @@ -1037,3 +1037,13 @@ def perform_odmr_measurement(self, freq_start, freq_step, freq_stop, power, chan self.save_odmr_data(tag=name_tag) return self.odmr_plot_x, self.odmr_plot_y, fit_params + + def stop_odmr_scan_sync(self): + """ Stop the acquistion normally but wait for it to be over before returning + + This method blocks the caller's thread and not this module's thread. + """ + self.stop_odmr_scan() + while self.module_state() == 'locked': + time.sleep(0.1) + return From 3b24f1e1b68389d2d8eba5a64a25212d92230e4d Mon Sep 17 00:00:00 2001 From: Alrik Date: Mon, 17 Aug 2020 11:59:39 +0200 Subject: [PATCH 5/8] changed odmr setter to have default values --- logic/odmr_logic.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/logic/odmr_logic.py b/logic/odmr_logic.py index 5e2f0f6255..7438b7e6f2 100644 --- a/logic/odmr_logic.py +++ b/logic/odmr_logic.py @@ -365,7 +365,7 @@ def set_runtime(self, runtime): self.sigParameterUpdated.emit(update_dict) return self.run_time - def set_cw_parameters(self, frequency, power): + def set_cw_parameters(self, frequency=None, power=None): """ Set the desired new cw mode parameters. @param float frequency: frequency to set in Hz @@ -373,6 +373,9 @@ def set_cw_parameters(self, frequency, power): @return (float, float): actually set frequency in Hz, actually set power in dBm """ + frequency = frequency if frequency is not None else self.cw_mw_frequency + power = power if power is not None else self.cw_mw_power + if self.module_state() != 'locked' and isinstance(frequency, (int, float)) and isinstance(power, (int, float)): constraints = self.get_hw_constraints() frequency_to_set = constraints.frequency_in_range(frequency) @@ -387,7 +390,7 @@ def set_cw_parameters(self, frequency, power): self.sigParameterUpdated.emit(param_dict) return self.cw_mw_frequency, self.cw_mw_power - def set_sweep_parameters(self, start, stop, step, power): + def set_sweep_parameters(self, start=None, stop=None, step=None, power=None): """ Set the desired frequency parameters for list and sweep mode @param float start: start frequency to set in Hz @@ -398,6 +401,11 @@ def set_sweep_parameters(self, start, stop, step, power): @return float, float, float, float: current start_freq, current stop_freq, current freq_step, current power """ + start = start if start is not None else self.mw_start + stop = stop if stop is not None else self.mw_stop + step = step if step is not None else self.mw_step + power = power if power is not None else self.sweep_mw_power + limits = self.get_hw_constraints() if self.module_state() != 'locked': if isinstance(start, (int, float)): From 9927cda05fe29d9918eeab3e19e77a7c578df061 Mon Sep 17 00:00:00 2001 From: Alrik Date: Mon, 17 Aug 2020 11:59:57 +0200 Subject: [PATCH 6/8] updated perform_odmr_measurement method --- logic/odmr_logic.py | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/logic/odmr_logic.py b/logic/odmr_logic.py index 7438b7e6f2..6512735af5 100644 --- a/logic/odmr_logic.py +++ b/logic/odmr_logic.py @@ -1002,33 +1002,30 @@ def draw_figure(self, channel_number, cbar_range=None, percentile_range=None): return fig - def perform_odmr_measurement(self, freq_start, freq_step, freq_stop, power, channel, runtime, - fit_function='No Fit', save_after_meas=True, name_tag=''): - """ An independant method, which can be called by a task with the proper input values - to perform an odmr measurement. + # Scripting zone + # + # The methods bellow are meant to be used be external script which have their own thread. + + def perform_odmr_measurement(self, freq_start=None, freq_step=None, freq_stop=None, power=None, channel=0, + runtime=None, fit_function='No Fit', save_after_meas=True, name_tag=''): + """ An independent method, which can be called by a task or script to perform an odmr measurement. @return """ - timeout = 30 start_time = time.time() while self.module_state() != 'idle': time.sleep(0.5) - timeout -= (time.time() - start_time) - if timeout <= 0: + if time.time() - start_time > 30: self.log.error('perform_odmr_measurement failed. Logic module was still locked ' 'and 30 sec timeout has been reached.') return tuple() # set all relevant parameter: self.set_sweep_parameters(freq_start, freq_stop, freq_step, power) - self.set_runtime(runtime) + if runtime is not None: + self.set_runtime(runtime) - # start the scan self.start_odmr_scan() - - # wait until the scan has started - while self.module_state() != 'locked': - time.sleep(1) # wait until the scan has finished while self.module_state() == 'locked': time.sleep(1) From f6f7ad3f9fff1a0d36b039f4fbab643a05ce55a0 Mon Sep 17 00:00:00 2001 From: Alrik Date: Mon, 17 Aug 2020 12:08:36 +0200 Subject: [PATCH 7/8] updated the changelog --- documentation/changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/changelog.md b/documentation/changelog.md index e918907d5b..04c35c193c 100644 --- a/documentation/changelog.md +++ b/documentation/changelog.md @@ -77,6 +77,7 @@ please use _ni_x_series_in_streamer.py_ as hardware module. * Set proper minimum wavelength value in constraints of Tektronix AWG7k series HW module * Added a hardware file for fibered optical switch Thorlabs OSW12/22 via SwitchInterface * Fixed bug affecting interface overloading of Qudi modules +* Added scripting helper methods at the end of multiple logic modules * From 7ef18ce87703ebf8fa9bd436909ce0bf2c992298 Mon Sep 17 00:00:00 2001 From: Alrik Date: Mon, 17 Aug 2020 12:47:48 +0200 Subject: [PATCH 8/8] tested and debugged --- logic/poi_manager_logic.py | 6 +++--- logic/time_series_reader_logic.py | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/logic/poi_manager_logic.py b/logic/poi_manager_logic.py index a4651595bf..ff68036bcf 100644 --- a/logic/poi_manager_logic.py +++ b/logic/poi_manager_logic.py @@ -1272,7 +1272,7 @@ def optimise_poi_position_sync(self, name=None, update_roi_position=True): time.sleep(0.1) return - def get_poi_list(self, regexp='*', check_in_range=False): + def get_poi_list(self, regexp='', check_in_range=False): """ Get a list of all the POIs filtered by a given regular expression @param (str) regexp: A regular expression to match POI names before returning @@ -1281,9 +1281,9 @@ def get_poi_list(self, regexp='*', check_in_range=False): To learn what is a regular expression, see : https://en.wikipedia.org/wiki/Regular_expression """ r = re.compile(regexp) - result = [name for name in self.poi_names if r.match(name)] + result = [name for name in self.poi_names if r.search(name)] if check_in_range: - result = [name for name in result if self.is_poi_in_range(result)] + result = [name for name in result if self.is_poi_in_range(name)] return result def is_poi_in_range(self, name, margin=0e-6, z_margin=0e-6): diff --git a/logic/time_series_reader_logic.py b/logic/time_series_reader_logic.py index f6764ebf49..19c3ebe010 100644 --- a/logic/time_series_reader_logic.py +++ b/logic/time_series_reader_logic.py @@ -837,5 +837,7 @@ def get_average_value_recorded_data(self): @return (np.array): An array of the average value of each active channels on the currently recorded data """ + if len(self._recorded_data) == 0: + self.log.error('There is no recorded data. Can not get average value.') return np.concatenate(self._recorded_data, axis=1).mean(axis=1)