def __init__(self, modules): """ Create new menu from module tree. @param dict m: module tree """ super().__init__() self.modules = [] self.hwmenu = QtWidgets.QMenu('Hardware') self.logicmenu = QtWidgets.QMenu('Logic') self.guimenu = QtWidgets.QMenu('Gui') self.addMenu(self.hwmenu) self.addMenu(self.logicmenu) self.addMenu(self.guimenu) self.hwmenuitems = MenuItem(self.hwmenu) self.logicmenuitems = MenuItem(self.logicmenu) self.guimenuitems = MenuItem(self.guimenu) for module_path, module in natural_sort(modules['hardware'].items()): self.build_submenu(self.hwmenuitems, module_path, module) for module_path, module in natural_sort(modules['logic'].items()): self.build_submenu(self.logicmenuitems, module_path, module) for module_path, module in natural_sort(modules['gui'].items()): self.build_submenu(self.guimenuitems, module_path, module)
def load_sequence(self, sequence_name): """ Loads a sequence to the channels of the device in order to be ready for playback. For devices that have a workspace (i.e. AWG) this will load the sequence from the device workspace into the channels. @param sequence_name: str, name of the sequence to load @return (dict, str): Dictionary with keys being the channel number and values being the respective asset loaded into the channel, string describing the asset type ('waveform' or 'sequence') """ if sequence_name not in self.sequence_dict: self.log.error( 'Sequence loading failed. No sequence with name "{0}" found on device ' 'memory.'.format(sequence_name)) return self.get_loaded_assets() # Determine if the device is purely digital and get all active channels analog_channels = natural_sort(chnl for chnl in self.activation_config if chnl.startswith('a')) digital_channels = natural_sort(chnl for chnl in self.activation_config if chnl.startswith('d')) pure_digital = len(analog_channels) == 0 if pure_digital and len( digital_channels) != self.sequence_dict[sequence_name]: self.log.error( 'Sequence loading failed. Number of active digital channels ({0:d}) does' ' not match the number of tracks in the sequence ({1:d}).' ''.format(len(digital_channels), self.sequence_dict[sequence_name])) return self.get_loaded_assets() if not pure_digital and len( analog_channels) != self.sequence_dict[sequence_name]: self.log.error( 'Sequence loading failed. Number of active analog channels ({0:d}) does' ' not match the number of tracks in the sequence ({1:d}).' ''.format(len(analog_channels), self.sequence_dict[sequence_name])) return self.get_loaded_assets() new_loaded_assets = dict() if pure_digital: for track_index, chnl in enumerate(digital_channels): chnl_num = int(chnl.split('ch')[1]) new_loaded_assets[chnl_num] = '{0}_{1:d}'.format( sequence_name, track_index) else: for track_index, chnl in enumerate(analog_channels): chnl_num = int(chnl.split('ch')[1]) new_loaded_assets[chnl_num] = '{0}_{1:d}'.format( sequence_name, track_index) self.current_loaded_assets = new_loaded_assets return self.get_loaded_assets()
def __init__(self, pulsedmeasurementlogic): # Init base class super().__init__(pulsedmeasurementlogic) # Dictionaries holding references to the extraction methods self._gated_extraction_methods = dict() self._ungated_extraction_methods = dict() # dictionary containing all possible parameters that can be used by the extraction methods self._parameters = dict() # Currently selected extraction method self._current_extraction_method = None # import path for extraction modules from default directory (logic.pulse_extraction_methods) path_list = [ os.path.join(get_main_dir(), 'logic', 'pulsed', 'pulse_extraction_methods') ] # import path for extraction modules from non-default directory if a path has been given if isinstance(pulsedmeasurementlogic.extraction_import_path, str): path_list.append(pulsedmeasurementlogic.extraction_import_path) # Import extraction modules and get a list of extractor classes extractor_classes = self.__import_external_extractors(paths=path_list) # create an instance of each class and put them in a temporary list extractor_instances = [ cls(pulsedmeasurementlogic) for cls in extractor_classes ] # add references to all extraction methods in each instance to a dict self.__populate_method_dicts(instance_list=extractor_instances) # populate "_parameters" dictionary from extraction method signatures self.__populate_parameter_dict() # Set default extraction method if self.is_gated: self._current_extraction_method = natural_sort( self._gated_extraction_methods)[0] else: self._current_extraction_method = natural_sort( self._ungated_extraction_methods)[0] # Update from parameter_dict if handed over if isinstance(pulsedmeasurementlogic.extraction_parameters, dict): # Delete unused parameters params = [ p for p in pulsedmeasurementlogic.extraction_parameters if p not in self._parameters and p != 'method' ] for param in params: del pulsedmeasurementlogic.extraction_parameters[param] # Update parameter dict and current method self.extraction_settings = pulsedmeasurementlogic.extraction_parameters return
def update_poi(self, old_name, new_name, position): # Handle changed names and deleted/added POIs if old_name != new_name: self._mw.active_poi_ComboBox.blockSignals(True) # Remember current text text_active_poi = self._mw.active_poi_ComboBox.currentText() # sort POI names and repopulate ComboBoxes self._mw.active_poi_ComboBox.clear() poi_names = natural_sort(self.poimanagerlogic().poi_names) self._mw.active_poi_ComboBox.addItems(poi_names) if text_active_poi == old_name: self._mw.active_poi_ComboBox.setCurrentText(new_name) else: self._mw.active_poi_ComboBox.setCurrentText(text_active_poi) self._mw.active_poi_ComboBox.blockSignals(False) # Delete/add/update POI marker to image if not old_name: # POI has been added self._add_poi_marker(name=new_name, position=position) elif not new_name: # POI has been deleted self._remove_poi_marker(name=old_name) else: # POI has been renamed and/or changed position size = self.poimanagerlogic().optimise_xy_size * np.sqrt(2) self._markers[old_name].set_name(new_name) self._markers[new_name] = self._markers.pop(old_name) self._markers[new_name].setSize((size, size)) self._markers[new_name].set_position(position[:2]) active_poi = self._mw.active_poi_ComboBox.currentText() if active_poi: self._markers[active_poi].select() return
def load_waveform(self, load_dict): """ Loads a waveform to the specified channel of the pulsing device. @param load_dict: dict|list, a dictionary with keys being one of the available channel @return dict: Dictionary containing the actually loaded waveforms per channel. """ if isinstance(load_dict, list): new_dict = dict() for waveform in load_dict: channel = int(waveform.rsplit('_ch', 1)[1]) new_dict[channel] = waveform load_dict = new_dict # Get all active channels chnl_activation = self.get_active_channels() analog_channels = natural_sort( chnl for chnl in chnl_activation if chnl.startswith('a') and chnl_activation[chnl]) # Load waveforms into channels for chnl_num, waveform in load_dict.items(): self.loaded_waveforms[chnl_num] = waveform self.last_sequence = None return self.get_loaded_assets()
def update_roi(self, old_name, new_name, position): # Handle changed names and deleted/added POIs if old_name != new_name: self._mw.active_roi_ComboBox.blockSignals(True) # Remember current text text_active_roi = self._mw.active_roi_ComboBox.currentText() # sort ROI names and repopulate ComboBoxes self._mw.active_roi_ComboBox.clear() roi_names = natural_sort(self.roi_logic().roi_names) self._mw.active_roi_ComboBox.addItems(roi_names) if text_active_roi == old_name: self._mw.active_roi_ComboBox.setCurrentText(new_name) else: self._mw.active_roi_ComboBox.setCurrentText(text_active_roi) self._mw.active_roi_ComboBox.blockSignals(False) # Delete/add/update ROI marker to image if not old_name: # ROI has been added self._add_roi_marker(name=new_name, position=position) elif not new_name: # ROI has been deleted self._remove_roi_marker(name=old_name) else: # ROI has been renamed and/or changed position size = self.roi_logic.roi_width # check if width should be changed again self._markers[old_name].set_name(new_name) self._markers[new_name] = self._markers.pop(old_name) self._markers[new_name].setSize((size, size)) self._markers[new_name].set_position(position[:2]) active_roi = self._mw.active_roi_ComboBox.currentText() if active_roi: self._markers[active_roi].select()
def _update_pois(self, poi_dict): """ Populate the dropdown box for selecting a poi. """ self._mw.active_poi_ComboBox.blockSignals(True) self._mw.active_poi_ComboBox.clear() poi_names = natural_sort(poi_dict) self._mw.active_poi_ComboBox.addItems(poi_names) # Get two list of POI names. One of those to delete and one of those to add old_poi_names = set(self._markers) new_poi_names = set(poi_names) names_to_delete = list(old_poi_names.difference(new_poi_names)) names_to_add = list(new_poi_names.difference(old_poi_names)) # Delete markers accordingly for name in names_to_delete: self._remove_poi_marker(name) # Update positions of all remaining markers size = self.poimanagerlogic().optimise_xy_size * np.sqrt(2) for name, marker in self._markers.items(): marker.setSize((size, size)) marker.set_position(poi_dict[name]) # Add new markers for name in names_to_add: self._add_poi_marker(name=name, position=poi_dict[name]) # If there is no active POI, set the combobox to nothing (-1) active_poi = self.poimanagerlogic().active_poi if active_poi in poi_names: self._mw.active_poi_ComboBox.setCurrentText(active_poi) self._markers[active_poi].select() active_poi_pos = poi_dict[active_poi] self._mw.poi_coords_label.setText( '({0:.2r}m, {1:.2r}m, {2:.2r}m)'.format( ScaledFloat(active_poi_pos[0]), ScaledFloat(active_poi_pos[1]), ScaledFloat(active_poi_pos[2]))) else: self._mw.active_poi_ComboBox.setCurrentIndex(-1) self._mw.active_poi_ComboBox.blockSignals(False) return
def __init__(self, pulsedmeasurementlogic): # Init base class super().__init__(pulsedmeasurementlogic) # Dictionary holding references to all analysis methods self._analysis_methods = dict() # dictionary containing all possible parameters that can be used by the analysis methods self._parameters = dict() # Currently selected analysis method self._current_analysis_method = None # import path for analysis modules from default directory (logic.pulse_analysis_methods) path_list = [os.path.join(get_main_dir(), 'logic', 'pulsed', 'pulsed_analysis_methods')] # import path for analysis modules from non-default directory if a path has been given if isinstance(pulsedmeasurementlogic.analysis_import_path, str): path_list.append(pulsedmeasurementlogic.analysis_import_path) # Import analysis modules and get a list of analyzer classes analyzer_classes = self.__import_external_analyzers(paths=path_list) # create an instance of each class and put them in a temporary list analyzer_instances = [cls(pulsedmeasurementlogic) for cls in analyzer_classes] # add references to all analysis methods in each instance to a dict self.__populate_method_dict(instance_list=analyzer_instances) # populate "_parameters" dictionary from analysis method signatures self.__populate_parameter_dict() # Set default analysis method self._current_analysis_method = natural_sort(self._analysis_methods)[0] # Update from parameter_dict if handed over if isinstance(pulsedmeasurementlogic.analysis_parameters, dict): # Delete unused parameters params = [p for p in pulsedmeasurementlogic.analysis_parameters if p not in self._parameters and p != 'method'] for param in params: del pulsedmeasurementlogic.analysis_parameters[param] # Update parameter dict and current method self.analysis_settings = pulsedmeasurementlogic.analysis_parameters return
def _update_pois(self, poi_dict): """ Populate the dropdown box for selecting a poi. """ self._mw.active_poi_ComboBox.blockSignals(True) self._mw.active_poi_ComboBox.clear() poi_names = natural_sort(poi_dict) self._mw.active_poi_ComboBox.addItems(poi_names) # Get two list of POI names. One of those to delete and one of those to add old_poi_names = set(self._markers) new_poi_names = set(poi_names) names_to_delete = list(old_poi_names.difference(new_poi_names)) names_to_add = list(new_poi_names.difference(old_poi_names)) # Delete markers accordingly for name in names_to_delete: self._remove_poi_marker(name) # Update positions of all remaining markers size = self.poimanagerlogic().optimise_xy_size * np.sqrt(2) for name, marker in self._markers.items(): marker.setSize((size, size)) marker.set_position(poi_dict[name]) # Add new markers for name in names_to_add: self._add_poi_marker(name=name, position=poi_dict[name]) # If there is no active POI, set the combobox to nothing (-1) active_poi = self.poimanagerlogic().active_poi if active_poi in poi_names: self._mw.active_poi_ComboBox.setCurrentText(active_poi) self._markers[active_poi].select() active_poi_pos = poi_dict[active_poi] self._mw.poi_coords_label.setText( '({0:.2r}m, {1:.2r}m, {2:.2r}m)'.format(ScaledFloat(active_poi_pos[0]), ScaledFloat(active_poi_pos[1]), ScaledFloat(active_poi_pos[2]))) else: self._mw.active_poi_ComboBox.setCurrentIndex(-1) self._mw.active_poi_ComboBox.blockSignals(False) return
def _update_rois(self, roi_dict): """ Populate the dropdown box for selecting a roi. """ self._mw.active_roi_ComboBox.blockSignals(True) self._mw.active_roi_ComboBox.clear() roi_names = natural_sort(roi_dict) self._mw.active_roi_ComboBox.addItems(roi_names) # Get two lists of ROI names. One of those to delete and one of those to add old_roi_names = set(self._markers) new_roi_names = set(roi_names) names_to_delete = list(old_roi_names.difference(new_roi_names)) names_to_add = list(new_roi_names.difference(old_roi_names)) # Delete markers accordingly for name in names_to_delete: self._remove_roi_marker(name) # Update positions of all remaining markers size = self.roi_logic( ).roi_width # self.roi_logic().optimise_xy_size * np.sqrt(2) for name, marker in self._markers.items(): marker.setSize((size, size)) marker.set_position(roi_dict[name]) # Add new markers for name in names_to_add: self._add_roi_marker(name=name, position=roi_dict[name]) # If there is no active ROI, set the combobox to nothing (-1) active_roi = self.roi_logic().active_roi if active_roi in roi_names: self._mw.active_roi_ComboBox.setCurrentText(active_roi) self._markers[active_roi].select() active_roi_pos = roi_dict[active_roi] self._mw.roi_coords_label.setText('x={0}, y={1}, z={2}'.format( active_roi_pos[0], active_roi_pos[1], active_roi_pos[2])) else: self._mw.active_roi_ComboBox.setCurrentIndex(-1) self._mw.roi_coords_label.setText('') # no roi active self._mw.active_roi_ComboBox.blockSignals(False)
def write_waveform(self, name, analog_samples, digital_samples, is_first_chunk, is_last_chunk, total_number_of_samples): """ Write a new waveform or append samples to an already existing waveform on the device memory. @param name: str, waveform name, human readabla @param analog_samples: numpy.ndarray of type float32 containing the voltage samples @param digital_samples: numpy.ndarray of type bool containing the marker states (if analog channels are active, this must be the same length as analog_samples) @param is_first_chunk: bool, flag indicating if it is the first chunk to write. If True this method will create a new empty wavveform. If False the samples are appended to the existing waveform. @param is_last_chunk: bool, flag indicating if it is the last chunk to write. Some devices may need to know when to close the appending wfm. @param total_number_of_samples: int, The number of sample points for the entire waveform (not only the currently written chunk) @return: (int, list) number of samples written (-1 indicates failed process) and list of created waveform names """ tstart = datetime.datetime.now() self.log.debug('@{} write wfm: {} first: {} last: {} {}'.format( datetime.datetime.now() - tstart, name, is_first_chunk, is_last_chunk, total_number_of_samples)) waveforms = list() min_samples = 30 if not (is_first_chunk and is_last_chunk): self.log.error('Chunked Write not supported by this device.') return -1, waveforms # Sanity checks if len(analog_samples) == 0: self.log.error('No analog samples passed to write_waveform.') return -1, waveforms if total_number_of_samples < min_samples: self.log.error('Unable to write waveform.' '\nNumber of samples to write ({0:d}) is ' 'smaller than the allowed minimum waveform length ({1:d}).' ''.format(total_number_of_samples, min_samples)) return -1, waveforms # determine active channels activation_dict = self.get_active_channels() active_channels = {chnl for chnl in activation_dict if activation_dict[chnl]} active_analog = natural_sort(chnl for chnl in active_channels if chnl.startswith('a')) # Sanity check of channel numbers if active_channels != set(analog_samples.keys()).union(set(digital_samples.keys())): self.log.error('Mismatch of channel activation and sample array dimensions for ' 'waveform creation.\nChannel activation is: {0}\nSample arrays have: ' ''.format(active_channels, set(analog_samples.keys()).union(set(digital_samples.keys())))) return -1, waveforms for a_ch in active_analog: a_ch_num = self.__ch_map[a_ch] wfm_name = '{0}_ch{1:d}'.format(name, a_ch_num) wfm = ksd1.SD_Wave() analog_samples[a_ch] = analog_samples[a_ch].astype('float64') / 2 self.log.debug('wfmobj: {} {} {} min: {} max: {}'.format( a_ch, name, wfm_name, np.min(analog_samples[a_ch]), np.max(analog_samples[a_ch]))) self.log.debug('@{} Before new wfm {}'.format(datetime.datetime.now() - tstart, a_ch)) wfmid = self._fast_newFromArrayDouble( wfm, ksd1.SD_WaveformTypes.WAVE_ANALOG, analog_samples[a_ch]) self.log.debug('@{} After new wfm {}'.format(datetime.datetime.now() - tstart, a_ch)) if wfmid < 0: self.log.error('Device error when creating waveform {} ch: {}: {} {}' ''.format(wfm_name, a_ch, wfmid, ksd1.SD_Error.getErrorMessage(wfmid))) return -1, waveforms if len(self.written_waveforms) > 0: wfm_nr = max(set(self.written_waveforms.values())) + 1 else: wfm_nr = 1 self.log.debug('@{} Before loading wfm {} '.format(datetime.datetime.now() - tstart, a_ch)) written = self.awg.waveformLoad(wfm, wfm_nr) self.log.debug('@{} Samples written: {} {} '.format(datetime.datetime.now() - tstart, a_ch, wfm, written)) if written < 0: self.log.error('Device error when uploading waveform {} id: {}: {} {}' ''.format(wfm, wfm_nr, written, ksd1.SD_Error.getErrorMessage(written))) return -1, waveforms self.written_waveforms[wfm_name] = wfm_nr waveforms.append(wfm_name) self.log.debug('@{} Finished writing waveforms'.format(datetime.datetime.now() - tstart)) return total_number_of_samples, waveforms
def write_sequence(self, name, sequence_parameter_list): """ Write a new sequence on the device memory. @param name: str, the name of the waveform to be created/append to @param sequence_parameter_list: list, contains the parameters for each sequence step and the according waveform names. @return: int, number of sequence steps written (-1 indicates failed process) """ steps_written = 0 wfms_added = {} # Check if all waveforms are present on device memory avail_waveforms = set(self.get_waveform_names()) for waveform_tuple, param_dict in sequence_parameter_list: if not avail_waveforms.issuperset(waveform_tuple): self.log.error('Failed to create sequence "{0}" due to waveforms "{1}" not ' 'present in device memory.'.format(name, waveform_tuple)) return -1 active_analog = natural_sort(chnl for chnl in self.get_active_channels() if chnl.startswith('a')) num_tracks = len(active_analog) num_steps = len(sequence_parameter_list) for a_ch in active_analog: self.awg.AWGflush(self.__ch_map[a_ch]) self.awg.channelWaveShape(self.__ch_map[a_ch], ksd1.SD_Waveshapes.AOU_AWG) # Fill in sequence information for step, (wfm_tuple, seq_params) in enumerate(sequence_parameter_list, 1): # Set waveforms to play if num_tracks == len(wfm_tuple): for track, waveform in enumerate(wfm_tuple, 1): # Triggers !!! wfm_nr = self.written_waveforms[waveform] if seq_params['wait_for'] == 'SOFT': trig = ksd1.SD_TriggerModes.SWHVITRIG self.log.debug('Ch{} Trig SOFT'.format(track)) elif seq_params['wait_for'] == 'EXT': trig = ksd1.SD_TriggerModes.EXTTRIG self.log.debug('Ch{} Trig EXT'.format(track)) elif seq_params['wait_for'] == 'SOFT_CYCLE': trig = ksd1.SD_TriggerModes.SWHVITRIG_CYCLE self.log.debug('Ch{} Trig SOFT_CYCLE'.format(track)) elif seq_params['wait_for'] == 'EXT_CYCLE': trig = ksd1.SD_TriggerModes.EXTTRIG_CYCLE self.log.debug('Ch{} Trig EXT_CYCLE'.format(track)) else: self.log.debug('Ch{} TrigAuto'.format(track)) trig = ksd1.SD_TriggerModes.AUTOTRIG cycles = seq_params['repetitions'] + 1 prescale = 0 delay = 0 ret = self.awg.AWGqueueWaveform(track, wfm_nr, trig, delay, cycles, prescale) self.log.debug('Sequence: {} Ch{} {} No{}'.format( name, track, waveform, wfm_nr) ) self.log.debug('Sequence Step: {0} Ch{1} No{2} Trig: {3} Del: {4} Rep: {5} Pre: {6} -> {7}'.format( step, track, wfm_nr, trig, delay, cycles, prescale, ret) ) if ret < 0: self.log.error('Error queueing wfm: {} {}'.format(ret, ksd1.SD_Error.getErrorMessage(ret))) return steps_written wfms_added[track] = '{0}_{1:d}'.format(name, track) steps_written += 1 else: self.log.error( 'Unable to write sequence.\nLength of waveform tuple "{0}" does not ' 'match the number of sequence tracks.'.format(wfm_tuple) ) return -1 # more setup for a_ch in active_analog: self.log.debug('QueueConfig {}'.format( self.awg.AWGqueueConfig(self.__ch_map[a_ch], 1))) self.log.debug('channelAmpliude {}'.format( self.awg.channelAmplitude(self.__ch_map[a_ch], self.analog_amplitudes[a_ch]))) if num_steps == steps_written: self.last_sequence = name self.loaded_waveforms = wfms_added self.set_channel_triggers(active_analog, sequence_parameter_list) return steps_written
def on_activate(self): """ Starts up the NI-card and performs sanity checks. """ # Sanity check ConfigOptions if not self._digital_channels and not self._analog_channels: raise Exception( 'Not a single analog or digital channel provided in ConfigOptions.' ) self._digital_channels = natural_sort( str(chnl) for chnl in self._digital_channels) self._analog_channels = natural_sort( str(chnl) for chnl in self._analog_channels) if self._digital_channels: try: if len(self._digital_channels) != len( self._digital_event_rates): if len(self._digital_event_rates) == 1: tmp = self._digital_event_rates[0] self._digital_event_rates = [ i * tmp for i, _ in enumerate(self._digital_channels, 1) ] else: raise Exception( 'ConfigOption "digital_event_rates" must have same length ' 'as "digital_channels" or just be a single value.') except TypeError: self._digital_event_rates = [ i * self._digital_event_rates for i, _ in enumerate(self._digital_channels, 1) ] if self._analog_channels: try: if len(self._analog_channels) != len(self._analog_amplitudes): if len(self._analog_amplitudes) == 1: tmp = self._analog_amplitudes[0] self._analog_amplitudes = [ i * tmp for i, _ in enumerate(self._analog_channels, 1) ] else: raise Exception( 'ConfigOption "analog_amplitudes" must have same length ' 'as "analog_channels" or just be a single value.') except TypeError: self._analog_amplitudes = [ i * self._analog_amplitudes for i, _ in enumerate(self._analog_channels, 1) ] # Create constraints self._constraints = DataInStreamConstraints() self._constraints.digital_channels = tuple( StreamChannel( name=ch, type=StreamChannelType.DIGITAL, unit='counts') for ch in self._digital_channels) self._constraints.analog_channels = tuple( StreamChannel(name=ch, type=StreamChannelType.ANALOG, unit='V') for ch in self._analog_channels) self._constraints.analog_sample_rate.min = 1 self._constraints.analog_sample_rate.max = 2**31 - 1 self._constraints.analog_sample_rate.step = 1 self._constraints.analog_sample_rate.unit = 'Hz' self._constraints.digital_sample_rate.min = 1 self._constraints.digital_sample_rate.max = 2**31 - 1 self._constraints.digital_sample_rate.step = 1 self._constraints.digital_sample_rate.unit = 'Hz' self._constraints.combined_sample_rate = self._constraints.analog_sample_rate self._constraints.read_block_size.min = 1 self._constraints.read_block_size.max = 1000000 self._constraints.read_block_size.step = 1 # TODO: Implement FINITE streaming mode self._constraints.streaming_modes = (StreamingMode.CONTINUOUS, ) # , StreamingMode.FINITE) self._constraints.data_type = np.float64 self._constraints.allow_circular_buffer = True self.__sample_rate = self._constraints.combined_sample_rate.min self.__data_type = np.float64 self.__stream_length = 0 self.__buffer_size = 1000 self.__use_circular_buffer = False self.__streaming_mode = StreamingMode.CONTINUOUS self.__active_channels = tuple() # Reset data buffer self._data_buffer = np.empty(0, dtype=self.__data_type) self._has_overflown = False self._is_running = False self._last_read = None self._start_time = None return
def get_sequence_names(self): """ Retrieve the names of all uploaded sequence on the device. @return list: List of all uploaded sequence name strings in the device workspace. """ return list(natural_sort(self.sequence_names))
def get_waveform_names(self): """ Retrieve the names of all uploaded waveforms on the device. @return list: List of all uploaded waveform name strings in the device workspace. """ return list(natural_sort(self.waveform_names))
def write_sequence(self, name, sequence_parameter_list): """ Write a new sequence on the device memory. @param name: str, the name of the waveform to be created/append to @param sequence_parameter_list: list, contains the parameters for each sequence step and the according waveform names. @return: int, number of sequence steps written (-1 indicates failed process) """ steps_written = 0 wfms_added = {} # Check if device has sequencer option installed if not self.has_sequence_mode(): self.log.error('Direct sequence generation in AWG not possible. Sequencer option not ' 'installed.') return -1 # Check if all waveforms are present on device memory avail_waveforms = set(self.get_waveform_names()) for waveform_tuple, param_dict in sequence_parameter_list: if not avail_waveforms.issuperset(waveform_tuple): self.log.error('Failed to create sequence "{0}" due to waveforms "{1}" not ' 'present in device memory.'.format(name, waveform_tuple)) return -1 active_analog = natural_sort(chnl for chnl in self.get_active_channels() if chnl.startswith('a')) num_tracks = len(active_analog) num_steps = len(sequence_parameter_list) for a_ch in active_analog: self.awg.AWGflush(self.__ch_map[a_ch]) self.awg.channelWaveShape(self.__ch_map[a_ch], ksd1.SD_Waveshapes.AOU_AWG) # Fill in sequence information for step, (wfm_tuple, seq_params) in enumerate(sequence_parameter_list, 1): # Set waveforms to play if num_tracks == len(wfm_tuple): for track, waveform in enumerate(wfm_tuple, 1): # !!! wfm_nr = self.written_waveforms[waveform] if seq_params['wait_for'] == 'EXT': trig = ksd1.SD_TriggerModes.EXTTRIG self.log.debug('Ch{} Trig EXT'.format(track)) elif seq_params['wait_for'] == 'CYCLE': trig = ksd1.SD_TriggerModes.EXTTRIG_CYCLE self.log.debug('Ch{} Trig EXT_CYCLE'.format(track)) else: self.log.debug('Ch{} TrigAuto'.format(track)) trig = ksd1.SD_TriggerModes.AUTOTRIG cycles = seq_params['repetitions'] + 1 prescale = 0 delay = 0 ret = self.awg.AWGqueueWaveform(track, wfm_nr, trig, delay, cycles, prescale) self.log.debug('Sequence: {} Ch{} {} No{}'.format( name, track, waveform, wfm_nr) ) self.log.debug('Sequence Step: {0} Ch{1} No{2} Trig: {3} Del: {4} Rep: {5} Pre: {6} -> {7}'.format( step, track, wfm_nr, trig, delay, cycles, prescale, ret) ) if ret < 0: self.log.error('Error queueing wfm: {} {}'.format(ret, ksd1.SD_Error.getErrorMessage(ret))) return steps_written wfms_added[track] = '{0}_{1:d}'.format(name, track) steps_written += 1 else: self.log.error( 'Unable to write sequence.\nLength of waveform tuple "{0}" does not ' 'match the number of sequence tracks.'.format(wfm_tuple) ) return -1 # more setup for a_ch in active_analog: self.log.debug('QueueConfig {}'.format( self.awg.AWGqueueConfig(self.__ch_map[a_ch], 1))) self.log.debug('channelAmpliude {}'.format( self.awg.channelAmplitude(self.__ch_map[a_ch], self.analog_amplitudes[a_ch]))) if num_steps == steps_written: self.last_sequence = name self.loaded_waveforms = wfms_added self.set_channel_triggers(active_analog, sequence_parameter_list) return steps_written