def __init__(self, name, measurement_segment: segment_measurements, segment_type='render'): ''' Args: name (str): name of the segment usually the channel name segment_type (str) : type of the segment (e.g. 'render' --> to be rendered, 'virtual'--> no not render.) ''' self.type = segment_type self.name = name self._measurement_segment = measurement_segment self._measurement_index = 0 # store data in numpy looking object for easy operator access. self.data = data_container(acquisition_data()) # local copy of self that will be used to count up the virtual gates. self._pulse_data_all = None # data caching variable. Used for looping and so on (with a decorator approach) self.data_tmp = None # setpoints of the loops (with labels and units) self._setpoints = setpoint_mgr() self.render_mode = False
def __init__(self, name, data_object, HVI_variable_data=None, segment_type='render'): ''' Args: name (str): name of the segment usually the channel name data_object (object) : class that is used for saving the data type. HVI_variable_data (segment_HVI_variables) : segment used to keep variables that can be used in HVI. segment_type (str) : type of the segment (e.g. 'render' --> to be rendered, 'virtual'--> no not render.) ''' self.type = segment_type self.name = name self.render_mode = False # variable specifing the laetest change to the waveforms, self._last_edit = last_edit.ToRender # store data in numpy looking object for easy operator access. self.data = data_container(data_object) self._data_hvi_variable = HVI_variable_data # references to other channels (for virtual gates). self.reference_channels = [] # reference channels for IQ virtual channels self.IQ_ref_channels = [] self.references_markers = [] # local copy of self that will be used to count up the virtual gates. self._pulse_data_all = None # data caching variable. Used for looping and so on (with a decorator approach) self.data_tmp = None # variable specifing the lastest time the pulse_data_all is updated # setpoints of the loops (with labels and units) self._setpoints = setpoint_mgr()
def _extend_dimensions(data, shape, use_ref): ''' Extends the dimensions of a existing array object. This is useful if one would have first defined sweep axis 2 without defining axis 1. In this case axis 1 is implicitly made, only harbouring 1 element. This function can be used to change the axis 1 to a different size. Args: data (np.ndarray[dtype = object]) : numpy object that contains all the segment data of every iteration. shape (list/np.ndarray) : list of the new dimensions of the array (should have the same lenght as the dimension of the data!) use_ref (bool) : use pointer to copy, or take full copy (False is full copy) ''' new_data = data_container(shape=shape) for i in range(len(shape)): if data.shape[i] != shape[i]: if i == 0: for j in range(len(new_data)): new_data[j] = cpy_numpy_shallow(data, use_ref) else: new_data = new_data.swapaxes(i, 0) data = data.swapaxes(i, 0) for j in range(len(new_data)): new_data[j] = cpy_numpy_shallow(data, use_ref) new_data = new_data.swapaxes(i, 0) return new_data
def add_sequence(self, sequence): ''' Adds a sequence to this object. Args: sequence (array) : array of segment_container ''' # check input for entry in sequence: if isinstance( entry, pulse_lib.segments.segment_container.segment_container): self.sequence.append(entry) else: raise ValueError( 'The provided element in the sequence seems to be of the wrong data type. {} provided, segment_container expected' .format(type(entry))) # update dimensionality of all sequence objects for seg_container in self.sequence: seg_container.enter_rendering_mode() self._shape = find_common_dimension(seg_container.shape, self._shape) # Set the waveform cache equal to the the sum of the length of all axis of all channels. # The cache will than be big enough for 1D iterations along every axis. This gives best performance total_axis_length = 0 for seg_container in self.sequence: for channel_name in seg_container.channels: shape = getattr(seg_container, channel_name).data.shape total_axis_length += sum(shape) parent_data.set_waveform_cache_size(total_axis_length) self._shape = tuple(self._shape) self._sweep_index = [0] * self.ndim self._HVI_variables = data_container(marker_HVI_variable()) self._HVI_variables = update_dimension(self._HVI_variables, self.shape) # enforce master clock for the current segments (affects the IQ channels (translated into a phase shift) and and the marker channels (time shifts)) t_tot = np.zeros(self.shape) for seg_container in self.sequence: seg_container.extend_dim(self._shape, ref=True) lp_time = loop_obj(no_setpoints=True) lp_time.add_data(t_tot, axis=list(range(self.ndim - 1, -1, -1))) seg_container.add_master_clock(lp_time) self._HVI_variables += seg_container._software_markers.pulse_data_all t_tot += seg_container.total_time self.params = [] for i in range(len(self.labels)): par_name = self.labels[i] set_param = index_param(par_name, self, dim=i) self.params.append(set_param) setattr(self, par_name, set_param)
def __getitem__(self, *key): ''' get slice or single item of this segment (note no copying, just referencing) Args: *key (int/slice object) : key of the element -- just use numpy style accessing (slicing supported) ''' item = copy.copy(self) item.data = data_container(self.data[key[0]]) return item
def _add_dimensions(data, shape, use_ref): """ Function that can be used to add and extra dimension of an array object. A seperate function is needed since we want to make a copy and not a reference. Note that only one dimension can be extended! Args: data (np.ndarray[dtype = object]) : numpy object that contains all the segment data of every iteration. shape (list/np.ndarray) : list of the new dimensions of the array use_ref (bool) : use pointer to copy, or take full copy (False is full copy) """ new_data = data_container(shape=shape) for i in range(shape[0]): new_data[i] = cpy_numpy_shallow(data, use_ref) return new_data
def get_marker_data(self, pre_delay, post_delay): ''' generate markers for the PM of the IQ modulation ''' my_marker_data = update_dimension(data_container(marker_data()), self.shape) my_marker_data = my_marker_data.flatten() # make a flat reference. local_data = self.data.flatten() for i in range(len(local_data)): for MW_pulse_info in local_data[i].MW_pulse_data: my_marker_data[i].add_marker(MW_pulse_info.start - pre_delay, MW_pulse_info.stop + post_delay) my_marker_data = my_marker_data.reshape(self.shape) return my_marker_data
def __getitem__(self, *key): ''' get slice or single item of this segment (note no copying, just referencing) Args: *key (int/slice object) : key of the element -- just use numpy style accessing (slicing supported) ''' data_item = self.data[key[0]] if not isinstance(data_item, data_container): # If the slice contains only 1 element, then it's not a data_container anymore. # Put it in a data_container to maintain pulse_lib structure. data_item = data_container(data_item) # To avoid unnecessary copying of data we first slice on self, copy, and then restore data in self. # This trick makes the indexing operation orders faster. data_org = self.data self.data = data_item item = copy.copy(self) item.data = data_item # TODO [SdS]: make clean solution self.data = data_org return item