示例#1
0
def convert(values, unit1, unit2):
    """Converts values from unit1 to unit2
    Parameters
    ----------
    values: ndarray
        Values of the field to convert
    unit1: str
        start unit
    unit2: str
        final unit
    Returns
    -------
    ndarray of the converted field
    """
    unit1_save = unit1
    unit2_save = unit2
    # Format the strings
    unit1 = unit1.replace("*", "").replace(" ", "").replace("^", "")
    unit2 = unit2.replace("*", "").replace(" ", "").replace("^", "")
    # Unit1 parsing
    if "/" in unit1:
        dim1_denom, prefix1_denom = get_dim_prefix(unit1.split("/")[1])
        unit1 = unit1.split("/")[0]
    else:
        dim1_denom = [0, 0, 0, 0, 0, 0]
        prefix1_denom = 1.0
    dim1_num, prefix1_num = get_dim_prefix(unit1)
    # Unit2 parsing
    if "/" in unit2:
        dim2_denom, prefix2_denom = get_dim_prefix(unit2.split("/")[1])
        unit2 = unit2.split("/")[0]
    else:
        dim2_denom = [0, 0, 0, 0, 0, 0]
        prefix2_denom = 1.0
    dim2_num, prefix2_num = get_dim_prefix(unit2)
    # Check compatibility
    dim1 = [i - j for i, j in zip(dim1_num, dim1_denom)]
    dim2 = [i - j for i, j in zip(dim2_num, dim2_denom)]
    if dim1 != dim2:
        raise UnitError("ERROR: Units " + unit1_save + " and " + unit2_save +
                        " do not match")
    else:
        return values * (prefix1_num / prefix1_denom) / (prefix2_num /
                                                         prefix2_denom)
示例#2
0
def dB_to_dBA(values, freqs):
    """Converts values from dB into dBA (requires frequency vector)
    
    Parameters
    ----------
    values: array
        Values of the field to convert (must be 1D)
    freqs: array
        Frequency vector
    Returns
    -------
    ndarray of the converted field
    """
    freq2 = square(freqs)
    RA = (12200.0**2 * freq2**2 / ((freq2 + 20.6**2) * sqrt(
        (freq2 + 107.7**2) * (freq2 + 737.0**2)) * (freq2 + 12200.0**2)))
    Aweight = 2.0 + 20.0 * log10(RA)
    try:
        values += Aweight
        return values
    except:
        raise UnitError("ERROR: dBA conversion only available for 1D fft")
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
示例#4
0
def dB_to_dBA(values, freqs, noct=None):
    """Converts values from dB into dBA (requires frequency vector)

    Parameters
    ----------
    values: array
        Values of the field to convert (must be 1D)
    freqs: array
        Frequency vector
    Returns
    -------
    ndarray of the converted field
    """
    if noct is not None:
        freqs_ref = [
            12.5,
            16,
            20,
            25,
            31.5,
            40,
            50,
            63,
            80,
            100,
            125,
            160,
            200,
            250,
            315,
            400,
            500,
            630,
            800,
            1000,
            1250,
            1600,
            2000,
            2500,
            3150,
            4000,
            5000,
            6300,
            8000,
            10000,
            12500,
            16000,
            20000,
        ]
        Aweight = [
            -63.4,
            -56.7,
            -50.5,
            -44.7,
            -39.4,
            -34.6,
            -30.2,
            -26.2,
            -22.5,
            -19.1,
            -16.1,
            -13.4,
            -10.9,
            -8.6,
            -6.6,
            -4.8,
            -3.2,
            -1.9,
            -0.8,
            0,
            0.6,
            1,
            1.2,
            1.3,
            1.2,
            1,
            0.5,
            -0.1,
            -1.1,
            -2.5,
            -4.3,
            -6.6,
            -9.3,
        ]
        mask = argwhere(freqs in freqs_ref)
        Aweight = take(Aweight, mask)
    else:
        freq2 = square(freqs)
        freq2[freq2 == 0] = nan
        RA = (
            12200.0 ** 2
            * freq2 ** 2
            / (
                (freq2 + 20.6 ** 2)
                * sqrt((freq2 + 107.7 ** 2) * (freq2 + 737.0 ** 2))
                * (freq2 + 12200.0 ** 2)
            )
        )
        Aweight = 2.0 + 20.0 * log10(RA)
        Aweight[isnan(Aweight)] = -100  # replacing NaN by -100 dB
        Aweight[
            values <= 0
        ] = 0  # avoiding to increase dB in dBA at frequencies where noise is already null
    try:
        values += Aweight
        return values
    except:
        raise UnitError("ERROR: dBA conversion only available for 1D fft")
示例#5
0
def convert(self, values, unit, is_norm, is_squeeze, is_magnitude, axes_list):
    """Returns the values of the field transformed or converted.
    Parameters
    ----------
    self: Data
        a Data object
    values: ndarray
        array of the field
    unit: str
        Unit requested by the user ("SI" by default)
    is_norm: bool
        Boolean indicating if the field must be normalized (False by default)
    Returns
    -------
    values: ndarray
        values of the field
    """

    # Take magnitude before summing
    if is_magnitude:
        values = np_abs(values)

    # Apply sums, means, etc
    for axis_requested in axes_list:
        # sum over sum axes
        if axis_requested.extension == "sum":
            values = np_sum(values, axis=axis_requested.index, keepdims=True)
        # root sum square over rss axes
        elif axis_requested.extension == "rss":
            values = sqrt(
                np_sum(values**2, axis=axis_requested.index, keepdims=True))
        # mean value over mean axes
        elif axis_requested.extension == "mean":
            values = np_mean(values, axis=axis_requested.index, keepdims=True)
        # RMS over rms axes
        elif axis_requested.extension == "rms":
            values = sqrt(
                np_mean(values**2, axis=axis_requested.index, keepdims=True))
        # integration over integration axes
        elif axis_requested.extension == "integrate":
            values = trapz(
                values, x=axis_requested.values,
                axis=axis_requested.index) / (np_max(axis_requested.values) -
                                              np_min(axis_requested.values))

    if is_squeeze:
        values = squeeze(values)

    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(np_abs(values), self.unit, ref_value)
    elif unit == "dBA":
        ref_value = 1.0
        if "ref" in self.normalizations.keys():
            ref_value *= self.normalizations.get("ref")
        for axis in axes_list:
            is_match = False
            if axis.name == "freqs" or axis.corr_name == "freqs":
                index = axis.index
                values = apply_along_axis(to_dBA, index, values, axis.values,
                                          self.unit, ref_value)
                is_match = True
            elif axis.name == "frequency":
                index = axis.index
                values = apply_along_axis(to_dBA, index, values, axis.values,
                                          self.unit, ref_value)
                is_match = True
        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_unit(values, self.unit, unit)

    return values
示例#6
0
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]