def get_values( self, unit="SI", is_oneperiod=False, is_antiperiod=False, is_smallestperiod=False ): """Returns the vector 'axis' by rebuilding the linspace, symmetries and unit included. Parameters ---------- self: DataLinspace a DataLinspace object unit: str requested unit is_oneperiod: bool return values on a single period is_antiperiod: bool return values on a semi period (only for antiperiodic signals) Returns ------- Vector of axis values """ initial = self.initial if self.number == None: final = self.final number = (final - initial + self.step) / self.step elif self.final == None: number = self.number final = self.initial + (number - 1) * self.step else: number = self.number final = self.final values = linspace(initial, final, int(number), endpoint=self.include_endpoint) # Unit conversion if unit != "SI" and unit != self.unit: values = convert(values, self.unit, unit) # Ignore symmetries if fft axis if self.name == "freqs" or self.name == "wavenumber": is_smallestperiod = True # Rebuild symmetries if is_smallestperiod: return values elif is_antiperiod: if "antiperiod" in self.symmetries: return values else: raise AxisError("ERROR: axis has no antiperiodicity") elif is_oneperiod: if "antiperiod" in self.symmetries: nper = self.symmetries["antiperiod"] self.symmetries["antiperiod"] = 2 values = rebuild_symmetries_axis(values, self.symmetries) self.symmetries["antiperiod"] = nper return values elif "period" in self.symmetries: return values else: return values else: values = rebuild_symmetries_axis(values, self.symmetries) return values
def get_phase_along(self, *args, unit="SI", is_norm=False, axis_data=[]): """Returns the ndarray of the magnitude of the FT, using conversions and symmetries if needed. Parameters ---------- self: Data a Data object *args: list of strings List of axes requested by the user, their units and values (optional) unit: str Unit requested by the user ("SI" by default) is_norm: bool Boolean indicating if the field must be normalized (False by default) axis_data: list list of ndarray corresponding to user-input data Returns ------- list of 1Darray of axes values, ndarray of magnitude values """ if len(args) == 1 and type(args[0]) == tuple: args = args[0] # if called from another script with *args return_dict = self.get_along(args, axis_data=axis_data) values = return_dict[self.symbol] # Compute magnitude values = np_angle(values) # Convert into right unit (apart because of degree conversion) if unit == self.unit or unit == "SI": if is_norm: try: values = values / self.normalizations.get("ref") except: raise NormError( "ERROR: Reference value not specified for normalization" ) elif unit == "°": values = convert(values, "rad", "°") elif unit in self.normalizations: values = values / self.normalizations.get(unit) else: values = convert(values, self.unit, unit) return_dict[self.symbol] = values return return_dict
def get_values(self, unit="SI", is_oneperiod=False, is_antiperiod=False, is_smallestperiod=False): """Returns the vector 'axis' taking symmetries into account. Parameters ---------- self: Data1D a Data1D object unit: str requested unit is_oneperiod: bool return values on a single period is_antiperiod: bool return values on a semi period (only for antiperiodic signals) Returns ------- Vector of axis values """ values = self.values # Unit conversion if unit != "SI" and unit != self.unit: values = convert(values, self.unit, unit) # Ignore symmetries if fft axis if self.name == "freqs" or self.name == "wavenumber": is_smallestperiod = True # Rebuild symmetries if is_smallestperiod: return values elif is_antiperiod: if "antiperiod" in self.symmetries: return values else: raise AxisError("ERROR: axis has no antiperiodicity") elif is_oneperiod: if "antiperiod" in self.symmetries: nper = self.symmetries["antiperiod"] self.symmetries["antiperiod"] = 2 values = rebuild_symmetries_axis(values, self.symmetries) self.symmetries["antiperiod"] = nper return values elif "period" in self.symmetries: return values else: return values else: values = rebuild_symmetries_axis(values, self.symmetries) return values
def get_magnitude_along(self, *args, unit="SI", is_norm=False, axis_data=[]): """Returns the ndarray of the magnitude of the FT, using conversions and symmetries if needed. Parameters ---------- self: Data a Data object *args: list of strings List of axes requested by the user, their units and values (optional) unit: str Unit requested by the user ("SI" by default) is_norm: bool Boolean indicating if the field must be normalized (False by default) axis_data: list list of ndarray corresponding to user-input data Returns ------- list of 1Darray of axes values, ndarray of magnitude values """ return_dict = self.get_along(args, axis_data=axis_data) values = return_dict[self.symbol] # Compute magnitude values = np_abs(values) # Convert into right unit (apart because of dBA conversion) if unit == self.unit or unit == "SI": if is_norm: try: values = values / self.normalizations.get("ref") except: raise NormError( "ERROR: Reference value not specified for normalization") elif unit == "dB": ref_value = 1.0 if "ref" in self.normalizations.keys(): ref_value *= self.normalizations.get("ref") values = to_dB(values, self.unit, ref_value) elif unit == "dBA": ref_value = 1.0 if "ref" in self.normalizations.keys(): ref_value *= self.normalizations.get("ref") if "freqs" in return_dict.keys(): values = to_dBA(values, return_dict["freqs"], self.unit, ref_value) else: raise UnitError( "ERROR: dBA conversion only available for fft with frequencies" ) elif unit in self.normalizations: values = values / self.normalizations.get(unit) else: values = convert(values, self.unit, unit) return_dict[self.symbol] = values return return_dict
def get_values( self, unit="SI", is_pattern=False, is_oneperiod=False, is_antiperiod=False, is_smallestperiod=False, ): """Returns the vector 'axis' taking symmetries into account. Parameters ---------- self: DataPattern a DataPattern object unit: str requested unit is_oneperiod: bool return values on a single period is_antiperiod: bool return values on a semi period (only for antiperiodic signals) Returns ------- Vector of axis values """ values = self.values # Unit conversion if unit != "SI" and unit != self.unit: values = convert(values, self.unit, unit) # Rebuild pattern if is_smallestperiod or is_pattern: return values else: if self.values_whole is not None: return self.values_whole else: return values[self.rebuild_indices]
def get_axis(self, axis, normalizations): """Computes the vector 'axis' in the unit required, using conversions and symmetries if needed. Parameters ---------- self: RequestedAxis a RequestedAxis object axis: Axis an Axis object normalizations: dict dictionary of the normalizations """ # Get original values of the axis if self.operation is not None: module = import_module("SciDataTool.Functions.conversions") func = getattr(module, self.operation) # Conversion function values = array(func(axis.get_values())) else: values = array(axis.get_values()) # Unit conversions and normalizations unit = self.unit if unit == axis.unit or unit == "SI": pass elif unit in normalizations: values = array([v / normalizations.get(unit) for v in values]) else: values = convert(values, axis.unit, unit) # Interpolate axis with input data if self.extension == "whole": self.values = values elif self.input_data is not None: self.input_data = get_common_base(self.input_data, values) self.values = values elif self.indices is not None: self.values = values[self.indices]
def get_axis(self, axis, is_real): """Computes the vector 'axis' in the unit required, using conversions and symmetries if needed. Parameters ---------- self: RequestedAxis a RequestedAxis object axis: Axis an Axis object """ if self.operation is not None: module = import_module("SciDataTool.Functions.conversions") func = getattr(module, self.operation) # Conversion function if isinstance(axis, DataPattern): self.is_pattern = True self.rebuild_indices = axis.rebuild_indices self.is_step = axis.is_step is_components = getattr(axis, "is_components", False) if is_components: values = axis.get_values() if not self.extension in ["sum", "rss", "mean", "rms", "integrate"]: self.extension = "list" if self.indices is not None: self.values = values[self.indices] else: self.values = values else: if self.extension == "pattern": if not self.is_pattern: raise AxisError( "ERROR: [pattern] cannot be called with non DataPattern axis" ) else: is_smallestperiod = True is_oneperiod = False is_antiperiod = False self.extension = "smallestperiod" elif self.extension == "smallestperiod": if isinstance(axis, DataPattern): raise AxisError( "ERROR: [smallestperiod] cannot be called with DataPattern axis" ) else: is_smallestperiod = True is_oneperiod = False is_antiperiod = False elif self.extension == "antiperiod": if isinstance(axis, DataPattern): raise AxisError( "ERROR: [antiperiod] cannot be called with DataPattern axis" ) else: is_smallestperiod = False is_oneperiod = False is_antiperiod = True elif self.extension == "oneperiod" or self.transform == "fft": if isinstance(axis, DataPattern): raise AxisError( "ERROR: [oneperiod] cannot be called with DataPattern axis" ) else: is_smallestperiod = False is_oneperiod = True is_antiperiod = False elif self.extension in ["sum", "rss", "mean", "rms", "integrate"]: is_smallestperiod = False is_oneperiod = False is_antiperiod = False # Ignore symmetries if fft axis elif self.name == "freqs" or self.name == "wavenumber": is_smallestperiod = True is_oneperiod = False is_antiperiod = False else: if self.input_data is not None and not self.is_step: # Check if symmetries need to be reconstructed to match input_data if self.operation is not None: axis_values = func( axis.get_values(is_smallestperiod=True, ), is_real=is_real, ) else: axis_values = axis.get_values(is_smallestperiod=True, ) if min(self.input_data) >= min(axis_values) and max( self.input_data) <= max(axis_values): is_smallestperiod = True is_oneperiod = False is_antiperiod = False else: if self.operation is not None: axis_values = func( axis.get_values(is_oneperiod=True, ), is_real=is_real, ) else: axis_values = axis.get_values(is_oneperiod=True, ) if min(self.input_data) >= min(axis_values) and max( self.input_data) <= max(axis_values): is_smallestperiod = False is_oneperiod = True is_antiperiod = False self.extension = "oneperiod" else: is_smallestperiod = False is_oneperiod = False is_antiperiod = False if not self.is_pattern: self.extension = "interval" elif self.transform == "ifft": # Ignore symmetries in ifft case is_smallestperiod = True is_oneperiod = False is_antiperiod = False else: is_smallestperiod = False is_oneperiod = False is_antiperiod = False # Get original values of the axis if self.operation is not None: values = array( func( axis.get_values( is_oneperiod=is_oneperiod, is_antiperiod=is_antiperiod, is_smallestperiod=is_smallestperiod, ), is_real=is_real, )) # Store original values self.corr_values = array( axis.get_values( is_oneperiod=is_oneperiod, is_antiperiod=is_antiperiod, is_smallestperiod=is_smallestperiod, )) else: values = array( axis.get_values( is_oneperiod=is_oneperiod, is_antiperiod=is_antiperiod, is_smallestperiod=is_smallestperiod, )) # Unit conversions and normalizations unit = self.unit if unit == self.corr_unit or unit == "SI": pass elif unit in axis.normalizations: if axis.normalizations.get(unit) == "indices": values = array([i for i in range(len(values))]) elif isinstance(axis.normalizations.get(unit), ndarray): values = axis.normalizations.get(unit) else: values = values / axis.normalizations.get(unit) else: values = convert(values, self.corr_unit, unit) # Rebuild symmetries in fft case if self.transform == "fft": if "period" in axis.symmetries: if axis.name != "time": values = values * axis.symmetries["period"] elif "antiperiod" in axis.symmetries: if axis.name != "time": values = values * axis.symmetries["antiperiod"] / 2 # Rebuild symmetries in ifft case if self.transform == "ifft": # if "antiperiod" in axis.symmetries: # axis.symmetries["antiperiod"] = int(axis.symmetries["antiperiod"]/2) if (self.extension != "smallestperiod" and self.extension != "oneperiod" and self.extension != "antiperiod"): values = rebuild_symmetries_axis(values, axis.symmetries) # if "period" in axis.symmetries: # if axis.name != "freqs": # values = values * axis.symmetries["period"] # elif "antiperiod" in axis.symmetries: # if axis.name != "freqs": # values = values * axis.symmetries["antiperiod"] / 2 # Interpolate axis with input data if self.input_data is None: self.values = values else: # if self.is_step: # values = values[axis.rebuild_indices] if len(self.input_data) == 2 and self.extension != "axis_data": indices = [ i for i, x in enumerate(values) if x >= self.input_data[0] and x <= self.input_data[-1] ] if self.indices is None: self.indices = indices else: indices_new = [] for i in self.indices: if i in indices: indices_new.append(i) self.indices = indices_new self.input_data = None else: self.values = values if self.indices is not None: self.values = values[self.indices] if self.extension in ["sum", "rss", "mean", "rms", "integrate"]: self.indices = None
def get_axis(self, axis): """Computes the vector 'axis' in the unit required, using conversions and symmetries if needed. Parameters ---------- self: RequestedAxis a RequestedAxis object axis: Axis an Axis object """ is_components = getattr(axis, "is_components", False) if is_components: values = axis.get_values() self.extension = "list" if self.indices is not None: self.values = values[self.indices] else: self.values = values else: if self.extension == "smallestperiod": is_smallestperiod = True is_oneperiod = False is_antiperiod = False elif self.extension == "antiperiod": is_smallestperiod = False is_oneperiod = False is_antiperiod = True elif self.extension == "oneperiod" or self.transform == "fft": is_smallestperiod = False is_oneperiod = True is_antiperiod = False elif self.extension == "axis_data": is_smallestperiod = True is_oneperiod = False is_antiperiod = False else: is_smallestperiod = False is_oneperiod = False is_antiperiod = False # Get original values of the axis if self.operation is not None: module = import_module("SciDataTool.Functions.conversions") func = getattr(module, self.operation) # Conversion function values = array( func( axis.get_values( is_oneperiod=is_oneperiod, is_antiperiod=is_antiperiod, is_smallestperiod=is_smallestperiod, ) ) ) else: values = array( axis.get_values( is_oneperiod=is_oneperiod, is_antiperiod=is_antiperiod, is_smallestperiod=is_smallestperiod, ) ) # Unit conversions and normalizations unit = self.unit if unit == self.corr_unit or unit == "SI": pass elif unit in axis.normalizations: values = array([v / axis.normalizations.get(unit) for v in values]) else: values = convert(values, self.corr_unit, unit) # Rebuild symmetries in fft case if self.transform == "fft": if "period" in axis.symmetries: if axis.name != "time": values = values * axis.symmetries["period"] elif "antiperiod" in axis.symmetries: if axis.name != "time": values = ( values * axis.symmetries["antiperiod"] / 2 ) # Interpolate axis with input data if self.extension in ["whole", "oneperiod", "antiperiod", "smallestperiod"]: self.values = values elif self.input_data is not None: if len(self.input_data) == 2 and self.extension != "axis_data": self.indices = [ i for i, x in enumerate(values) if x >= self.input_data[0] and x <= self.input_data[-1] ] self.input_data = None else: if self.extension == "axis_data": self.input_data = get_common_base(self.input_data, values, is_downsample=True) else: self.input_data = get_common_base(self.input_data, values) self.values = values if self.indices is not None: self.values = values[self.indices]
def get_magnitude_along( self, *args, unit="SI", is_norm=False, axis_data=[], is_squeeze=True ): """Returns the ndarray of the magnitude of the FT, using conversions and symmetries if needed. Parameters ---------- self: Data a Data object *args: list of strings List of axes requested by the user, their units and values (optional) unit: str Unit requested by the user ("SI" by default) is_norm: bool Boolean indicating if the field must be normalized (False by default) axis_data: list list of ndarray corresponding to user-input data Returns ------- list of 1Darray of axes values, ndarray of magnitude values """ if len(args) == 1 and type(args[0]) == tuple: args = args[0] # if called from another script with *args return_dict = self.get_along( args, axis_data=axis_data, is_squeeze=is_squeeze, is_magnitude=True ) values = return_dict[self.symbol] # 1/nth octave band for axis in return_dict["axes_list"]: if axis.name == "freqs" or axis.corr_name == "freqs": index = axis.index if axis.noct is not None: (values, foct) = apply_along_axis( to_noct, index, values, return_dict["freqs"], noct=axis.noct ) return_dict[axis.name] = foct # Convert into right unit (apart because of dBA conversion) if unit == self.unit or unit == "SI": if is_norm: try: values = values / self.normalizations.get("ref") except: raise NormError( "ERROR: Reference value not specified for normalization" ) elif unit == "dB": ref_value = 1.0 if "ref" in self.normalizations.keys(): ref_value *= self.normalizations.get("ref") values = to_dB(values, self.unit, ref_value) elif unit == "dBA": ref_value = 1.0 if "ref" in self.normalizations.keys(): ref_value *= self.normalizations.get("ref") if "freqs" in return_dict.keys(): for axis in return_dict["axes_list"]: if axis.name == "freqs" or axis.corr_name == "freqs": index = axis.index values = apply_along_axis( to_dBA, index, values, return_dict["freqs"], self.unit, ref_value ) else: raise UnitError( "ERROR: dBA conversion only available for fft with frequencies" ) elif unit in self.normalizations: values = values / self.normalizations.get(unit) else: values = convert(values, self.unit, unit) return_dict[self.symbol] = values return return_dict
def get_harmonics(self, N_harm, *args, unit="SI", is_norm=False, is_flat=False): """Returns the complex Fourier Transform of the field, using conversions and symmetries if needed. Parameters ---------- self: Data a Data object N_harm: int Number of largest harmonics to be extracted args: list Axes names, ranges and units unit: str Unit demanded by the user ("SI" by default) is_norm: bool Boolean indicating if the field must be normalized (False by default) is_flat: bool Boolean if the output data remains flattened (for 2D cases) Returns ------- list of 1Darray of axes values, ndarray of magnitude of FT """ # Read the axes input in args if len(args) == 1 and type(args[0]) == tuple: args = args[0] # if called from another script with *args axes_list = read_input_strings(args, []) # Extract the requested axes (symmetries + unit) for axis_requested in axes_list: if axis_requested[3] == "values": # Get original values of the axis axis_requested.append( self.get_FT_axis(axis_requested[0] + axis_requested[1])) # Interpolate axis with input data if str(axis_requested[4]) == "whole": axis_requested[4] = axis_requested[5] axis_requested[5] = "whole" else: axis_requested[4] = get_common_base(axis_requested[5], axis_requested[4]) # Change fft name for the slices of the field if axis_requested[0] == "freqs": axis_requested[0] = "time" elif axis_requested[0] == "wavenumber": axis_requested[0] = "angle" # Check if the requested axis is defined in the Data object for axis_requested in axes_list: axis_name = axis_requested[0] is_match = False for index, axis in enumerate(self.axes): if axis.name == axis_name: is_match = True if not is_match: axes_list.remove(axis_requested) # Rebuild symmetries of field if axis is extracted values = self.values for index, axis in enumerate(self.axes): for axis_requested in axes_list: if axis.name in self.symmetries.keys( ) and axis.name == axis_requested[0]: values = rebuild_symmetries(values, index, self.symmetries.get(axis.name)) # Extract the slices of the field (single values) for index, axis in enumerate(self.axes): is_match = False for axis_requested in axes_list: if axis.name == axis_requested[0]: is_match = True if axis_requested[3] == "indices" and axis_requested[ 2] == "single": values = take(values, axis_requested[4], axis=index) if not is_match: # Axis was not specified -> take slice at the first value values = take(values, [0], axis=index) # Interpolate over axis values (single values) for index, axis in enumerate(self.axes): for axis_requested in axes_list: if (axis.name == axis_requested[0] and axis_requested[3] == "values" and axis_requested[2] == "single"): values = apply_along_axis( get_interpolation, index, values, axis_requested[5], axis_requested[4], ) # Perform Fourier Transform values = np_abs(comp_fft(values)) # Extract slices again (intervals) for index, axis in enumerate(self.axes): for axis_requested in axes_list: if axis.name == axis_requested[0]: if axis_requested[2] == "indices" and axis_requested[ 2] == "interval": values = take(values, axis_requested[4], axis=index) # Interpolate over axis values again (intervals) for index, axis in enumerate(self.axes): for axis_requested in axes_list: if axis.name == axis_requested[0]: if axis_requested[3] == "values" and axis_requested[ 2] == "interval": values = apply_along_axis( get_interpolation, index, values, axis_requested[5], axis_requested[4], ) # Eliminate dimensions=1 values = squeeze(values) # Test if data is 1D or 2D if len(values.shape) > 2: raise AxisError("ERROR: only 1D or 2D implemented") else: # Convert into right unit if unit == self.unit or unit == "SI": if is_norm: try: values = values / self.normalizations.get("ref") except: raise NormError( "ERROR: Reference value not specified for normalization" ) elif unit == "dB": ref_value = 1.0 if "ref" in self.normalizations.keys(): ref_value *= self.normalizations.get("ref") values = to_dB(values, self.unit, ref_value) elif unit == "dBA": ref_value = 1.0 is_match = False if "ref" in self.normalizations.keys(): ref_value *= self.normalizations.get("ref") for axis_requested in axes_list: if axis_requested[0] == "time": is_match = True values = to_dBA(values, axis_requested[4], self.unit, ref_value) if not is_match: raise UnitError( "ERROR: dBA conversion only available for fft with frequencies" ) elif unit in self.normalizations: values = values / self.normalizations.get(unit) else: values = convert(values, self.unit, unit) # 1D case if len(values.shape) == 1: for axis_requested in axes_list: if axis_requested[2] == "interval": axis_values = axis_requested[4] indices = argsort(negative(values)) indices = indices[:N_harm] axis_values = axis_values[indices] values = values[indices] return [axis_values, values] # 2D case else: for axis_requested in axes_list: if axis_requested[0] == "angle": r = axis_requested[4] elif axis_requested[0] == "time": f = axis_requested[4] # Flatten the data values_flat = values.flatten() R, F = meshgrid(r, f) f = F.flatten() r = R.flatten() # Get the N_harm largest peaks indices = argsort(negative(values_flat)) indices = indices[:N_harm] values = values_flat[indices] f = f[indices] r = r[indices] if len(values.shape) == 2 and not is_flat: f.reshape((N_harm, N_harm)) r.reshape((N_harm, N_harm)) values.reshape((N_harm, N_harm)) return [f, r, values]