python三倍频程频谱

python三倍频程频谱,python,signal-processing,fft,bandpass-filter,Python,Signal Processing,Fft,Bandpass Filter,我试图得到时间信号的三倍频程频谱 时间信号是转子旋转噪声的声压,是谐波。它的基频是ff=n*n_b,因此,所有频率都应该是ff的倍数 使用fft,我得到了预期的结果: 基频的倍数是频谱中的相关频率 为了获得第三个倍频程频谱,我想使用python声学,但函数带通\u第三个倍频程的结果与我预期的不一样 我预计fft频谱的峰值将简单地移动到第三倍频程中心频率,并调整振幅。至少这是我想要的 我想我对带通三倍频程的输出解释不正确。它的输出是一个包含第三倍频程频率的元组和一个数组列表,据我所知,数组应该包含

我试图得到时间信号的三倍频程频谱

时间信号是转子旋转噪声的声压,是谐波。它的基频是ff=n*n_b,因此,所有频率都应该是ff的倍数

使用fft,我得到了预期的结果: 基频的倍数是频谱中的相关频率

为了获得第三个倍频程频谱,我想使用python声学,但函数
带通\u第三个倍频程
的结果与我预期的不一样

我预计fft频谱的峰值将简单地移动到第三倍频程中心频率,并调整振幅。至少这是我想要的

我想我对带通三倍频程的输出解释不正确。它的输出是一个包含第三倍频程频率的元组和一个数组列表,据我所知,数组应该包含振幅值

我目前使用阵列的最大值作为结果振幅,因为它比使用其总和效果更好。这种解释可能是我的错误

我将感谢任何帮助。我不需要使用
python声学
。任何获得第三倍频程频谱的解决方案都将是了不起的

编辑:使用平均值而不是最大值会产生更好的结果,但我仍然不完全满意

import matplotlib.pyplot as plt
import numpy as np
from scipy.sparse import spdiags
from scipy.signal import butter, lfilter, freqz, filtfilt, sosfilt

import acoustics.octave
#from acoustics.octave import REFERENCE

import acoustics.bands
from scipy.signal import hilbert
from acoustics.standards.iso_tr_25417_2007 import REFERENCE_PRESSURE
from acoustics.standards.iec_61672_1_2013 import (NOMINAL_OCTAVE_CENTER_FREQUENCIES,
                                                  NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES)

try:
    from pyfftw.interfaces.numpy_fft import rfft
except ImportError:
    from numpy.fft import rfft


def bandpass_filter(lowcut, highcut, fs, order=8, output='sos'):
    """Band-pass filter.
    :param lowcut: Lower cut-off frequency
    :param highcut: Upper cut-off frequency
    :param fs: Sample frequency
    :param order: Filter order
    :param output: Output type. {'ba', 'zpk', 'sos'}. Default is 'sos'. See also :func:`scipy.signal.butter`.
    :returns: Returned value depends on `output`.
    A Butterworth filter is used.
    .. seealso:: :func:`scipy.signal.butter`.
    """
    nyq = 0.5 * fs
    low = lowcut / nyq
    high = highcut / nyq
    output = butter(order / 2, [low, high], btype='band', output=output)
    return output



def bandpass(signal, lowcut, highcut, fs, order=8, zero_phase=False):
    """Filter signal with band-pass filter.
    :param signal: Signal
    :param lowcut: Lower cut-off frequency
    :param highcut: Upper cut-off frequency
    :param fs: Sample frequency
    :param order: Filter order
    :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
    A Butterworth filter is used. Filtering is done with second-order sections.
    .. seealso:: :func:`bandpass_filter` for the filter that is used.
    """
    sos = bandpass_filter(lowcut, highcut, fs, order, output='sos')
    if zero_phase:
        return _sosfiltfilt(sos, signal)
    else:
        return sosfilt(sos, signal)


class Frequencies:
    """
    Object describing frequency bands.
    """

    def __init__(self, center, lower, upper, bandwidth=None):

        self.center = np.asarray(center)
        """
        Center frequencies.
        """

        self.lower = np.asarray(lower)
        """
        Lower frequencies.
        """

        self.upper = np.asarray(upper)
        """
        Upper frequencies.
        """

        self.bandwidth = np.asarray(bandwidth) if bandwidth is not None else np.asarray(self.upper) - np.asarray(
            self.lower)
        """
        Bandwidth.
        """

    def __iter__(self):
        for i in range(len(self.center)):
            yield self[i]

    def __len__(self):
        return len(self.center)

    def __str__(self):
        return str(self.center)

    def __repr__(self):
        return "Frequencies({})".format(str(self.center))

    def angular(self):
        """Angular center frequency in radians per second.
        """
        return 2.0 * np.pi * self.center



class OctaveBand(Frequencies):
    """Fractional-octave band spectrum.
    """

    def __init__(self, center=None, fstart=None, fstop=None, nbands=None, fraction=1,
                 reference=acoustics.octave.REFERENCE):

        if center is not None:
            try:
                nbands = len(center)
            except TypeError:
                center = [center]
            center = np.asarray(center)
            indices = acoustics.octave.index_of_frequency(center, fraction=fraction, ref=reference)
        elif fstart is not None and fstop is not None:
            nstart = acoustics.octave.index_of_frequency(fstart, fraction=fraction, ref=reference)
            nstop = acoustics.octave.index_of_frequency(fstop, fraction=fraction, ref=reference)
            indices = np.arange(nstart, nstop + 1)
        elif fstart is not None and nbands is not None:
            nstart = acoustics.octave.index_of_frequency(fstart, fraction=fraction, ref=reference)
            indices = np.arange(nstart, nstart + nbands)
        elif fstop is not None and nbands is not None:
            nstop = acoustics.octave.index_of_frequency(fstop, fraction=fraction, ref=reference)
            indices = np.arange(nstop - nbands, nstop)
        else:
            raise ValueError("Insufficient parameters. Cannot determine fstart and/or fstop.")

        center = acoustics.octave.exact_center_frequency(None, fraction=fraction, n=indices, ref=reference)
        lower = acoustics.octave.lower_frequency(center, fraction=fraction)
        upper = acoustics.octave.upper_frequency(center, fraction=fraction)
        bandwidth = upper - lower
        nominal = acoustics.octave.nominal_center_frequency(None, fraction, indices)

        super(OctaveBand, self).__init__(center, lower, upper, bandwidth)

        self.fraction = fraction
        """Fraction of fractional-octave filter.
        """

        self.reference = reference
        """Reference center frequency.
        """

        self.nominal = nominal
        """Nominal center frequencies.
        """

    def __getitem__(self, key):
        return type(self)(center=self.center[key], fraction=self.fraction, reference=self.reference)

    def __repr__(self):
        return "OctaveBand({})".format(str(self.center))




def bandpass_frequencies(x, fs, frequencies, order=8, purge=False, zero_phase=False):
    """"Apply bandpass filters for frequencies
    :param x: Instantaneous signal :math:`x(t)`.
    :param fs: Sample frequency.
    :param frequencies: Frequencies. Instance of :class:`Frequencies`.
    :param order: Filter order.
    :param purge: Discard bands of which the upper corner frequency is above the Nyquist frequency.
    :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
    :returns: Tuple. First element is an instance of :class:`OctaveBand`. The second element an array.
    """
    if purge:
        frequencies = frequencies[frequencies.upper < fs / 2.0]
    return frequencies, np.array(
        [bandpass(x, band.lower, band.upper, fs, order, zero_phase=zero_phase) for band in frequencies])




def bandpass_third_octaves(x, fs, frequencies=NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES, order=8, purge=False,
                           zero_phase=False):
    """Apply 1/3-octave bandpass filters.
    :param x: Instantaneous signal :math:`x(t)`.
    :param fs: Sample frequency.
    :param frequencies: Frequencies.
    :param order: Filter order.
    :param purge: Discard bands of which the upper corner frequency is above the Nyquist frequency.
    :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
    :returns: Tuple. First element is an instance of :class:`OctaveBand`. The second element an array.
    .. seealso:: :func:`octavepass`
    """
    return bandpass_fractional_octaves(x, fs, frequencies, fraction=3, order=order, purge=purge, zero_phase=zero_phase)



def bandpass_fractional_octaves(x, fs, frequencies, fraction=None, order=8, purge=False, zero_phase=False):
    """Apply 1/N-octave bandpass filters.
    :param x: Instantaneous signal :math:`x(t)`.
    :param fs: Sample frequency.
    :param frequencies: Frequencies. Either instance of :class:`OctaveBand`, or array along with fs.
    :param order: Filter order.
    :param purge: Discard bands of which the upper corner frequency is above the Nyquist frequency.
    :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
    :returns: Tuple. First element is an instance of :class:`OctaveBand`. The second element an array.
    .. seealso:: :func:`octavepass`
    """
    if not isinstance(frequencies, Frequencies):
        frequencies = OctaveBand(center=frequencies, fraction=fraction)
    return bandpass_frequencies(x, fs, frequencies, order=order, purge=purge, zero_phase=zero_phase)



def _sosfiltfilt(sos, x, axis=-1, padtype='odd', padlen=None, method='pad', irlen=None):
    """Filtfilt version using Second Order sections. Code is taken from scipy.signal.filtfilt and adapted to make it work with SOS.
    Note that broadcasting does not work.
    """
    from scipy.signal import sosfilt_zi
    from scipy.signal._arraytools import odd_ext, axis_slice, axis_reverse
    x = np.asarray(x)

    if padlen is None:
        edge = 0
    else:
        edge = padlen

    # x's 'axis' dimension must be bigger than edge.
    if x.shape[axis] <= edge:
        raise ValueError("The length of the input vector x must be at least " "padlen, which is %d." % edge)

    if padtype is not None and edge > 0:
        # Make an extension of length `edge` at each
        # end of the input array.
        if padtype == 'even':
            ext = even_ext(x, edge, axis=axis)
        elif padtype == 'odd':
            ext = odd_ext(x, edge, axis=axis)
        else:
            ext = const_ext(x, edge, axis=axis)
    else:
        ext = x

    # Get the steady state of the filter's step response.
    zi = sosfilt_zi(sos)

    # Reshape zi and create x0 so that zi*x0 broadcasts
    # to the correct value for the 'zi' keyword argument
    # to lfilter.
    #zi_shape = [1] * x.ndim
    #zi_shape[axis] = zi.size
    #zi = np.reshape(zi, zi_shape)
    x0 = axis_slice(ext, stop=1, axis=axis)
    # Forward filter.
    (y, zf) = sosfilt(sos, ext, axis=axis, zi=zi * x0)

    # Backward filter.
    # Create y0 so zi*y0 broadcasts appropriately.
    y0 = axis_slice(y, start=-1, axis=axis)
    (y, zf) = sosfilt(sos, axis_reverse(y, axis=axis), axis=axis, zi=zi * y0)

    # Reverse y.
    y = axis_reverse(y, axis=axis)

    if edge > 0:
        # Slice the actual signal from the extended signal.
        y = axis_slice(y, start=edge, stop=-edge, axis=axis)

    return y


rho = 1.2
a = 340
N_b = 1
R = 1
r_H = 10
A = np.pi*R**2
TA = 287  
M_H = 0.3
w = M_H*a/R
n = w/(2*np.pi)

t = np.linspace(0,0.8,num=40000)
az = t*2*np.pi*n*N_b

sin = np.sin(az)
cos = np.cos(az)


#Thickness Noise

F_H = R/r_H
F_E = 0.00012875807653441588  #Bestimmt für den Propeller aus Paper
T1 = ((3-M_H*sin)*sin)/((1-M_H*sin)**3)
T2 = (M_H*(cos**2))/(10*(1-M_H*sin)**4)
T3 = 50 + 39*(M_H**2) - 45*M_H*sin - 11*(M_H**2)*(sin**2) + 12* (M_H**3) *sin - 18*(M_H**3)*(sin**3)
T_M = ((M_H**3)/12)*(-T1 + T2 * T3)

p_T = 0.5 * rho * a**2 * F_H * F_E * T_M 


#Loading Noise

F_T = (TA/ (rho * a**2))**(3/2) * (1 / (60 * np.sqrt(2) * N_b))
L = 60 + 30 * M_H**2 * cos**2 - 120 * M_H * sin - 30 * M_H**3 * sin * cos**2 + 80 * M_H**2 * sin**2 + 9 * M_H**4 * sin**2 * cos**2 - 20 * M_H**3 * sin**3
L_M = cos * (1 - M_H * sin)**(-3) * L

p_L = 0.5 * rho * a**2 * F_H * F_T * L_M

#Total

p_total = p_T + p_L
plt.figure(1)
plt.plot(t, p_total)
plt.title('Signal in time domain')
plt.xlabel('time [s]')
plt.ylabel('acoustic pressure [Pa]')

#fundamental frequency
ff = n*N_b
print('ff',ff)

#Sampling frequency
T = t[1] - t[0]
f_s = 1/T
print('fs',f_s)

#Trying to get the one third octave frequency spectrum

test = bandpass_third_octaves(p_total, f_s,frequencies=NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES,order=8,purge=False,zero_phase = True)
a_l = list()
i = 0
while i < 34:
    a = max(test[1][i])
    a_l.append(a)
    i+=1

f = NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES
plt.figure(2)
plt.bar(f, np.abs(a_l))
plt.title('Supposed one third octave spectrum of the time signal')
plt.xlabel('frequency [Hz]')
plt.ylabel('acoustic pressure [Pa]')
plt.xlim(0,100)

#FFT of the time signal p_total

N = p_total.size
f = np.linspace(0, 1/T, N)
f_scaled = f[:N // 2]
p_total -= np.mean(p_total)
fft = np.fft.fft(p_total)
fft_scaled = np.abs(fft)[:N // 2] * 2 / N
plt.figure(3)
plt.bar(f_scaled, fft_scaled)
plt.title('Signal in frequency domain')
plt.xlabel('frequency [Hz]')
plt.ylabel('acoustic pressure [Pa]')
plt.xlim(0,100)
plt.show()

导入matplotlib.pyplot作为plt
将numpy作为np导入
从scipy.spdiags导入spdiags
来自scipy.signal进口黄油、lfilter、FREKZ、filtfilt、sosfilt
八度音阶
#来自声学。倍频程输入参考
进口音响.乐队
从scipy.signal导入hilbert
从austics.standards.iso_tr_25417_2007导入参考压力
来自声学标准iec 61672 1 2013导入(标称倍频程中心频率,
标称(三倍频程(中心频率)
尝试:
从pyfftw.interfaces.numpy\u fft导入rfft
除恐怖外:
从numpy.fft导入rfft
def带通滤波器(低切、高切、fs,顺序=8,输出='sos'):
带通滤波器。
:param lowcut:较低截止频率
:param highcut:上限截止频率
:param fs:采样频率
:参数顺序:过滤器顺序
:param output:output type.{'ba','zpk','sos'}。默认值为'sos'。另请参见:func:'scipy.signal.butter`。
:返回:返回值取决于“输出”。
使用巴特沃斯过滤器。
…另请参见:::func:`scipy.signal.butter`。
"""
nyq=0.5*fs
低=低切/nyq
高=高切/nyq
输出=黄油(订单/2,[低,高],b类型='band',输出=输出)
返回输出
def带通(信号、低切、高切、fs、顺序=8、零相位=假):
“”“使用带通滤波器对信号进行滤波。
:参数信号:信号
:param lowcut:较低截止频率
:param highcut:上限截止频率
:param fs:采样频率
:参数顺序:过滤器顺序
:param zero_phase:通过在两个方向上进行过滤来防止相位错误(filt)
使用Butterworth过滤器。使用二阶段进行过滤。
..另请参见:::func:`bandpass_filter`了解所使用的滤波器。
"""
sos=带通滤波器(低切、高切、fs、顺序、输出='sos')
如果零相位:
返回sosfiltfilt(sos,信号)
其他:
返回sosfilt(sos、信号)
班次:
"""
描述频带的对象。
"""
def _初始__(自身、中心、下部、上部、带宽=无):
self.center=np.asarray(中心)
"""
中心频率。
"""
self.lower=np.asarray(下)
"""
低频率。
"""
self.upper=np.asarray(上)
"""
高频。
"""
self.bandwidth=np.asarray(带宽),如果带宽不是其他np.asarray(self.upper)-np.asarray(
自我保护(较低)
"""
带宽。
"""
定义(自我):
对于范围内的i(len(自中心)):
屈服自我[i]
定义(自我):
返回透镜(自中心)
定义(自我):
返回str(自我中心)
定义报告(自我):
返回“Frequencies({})”格式(str(self.center))
def角度(自身):
“”“角中心频率,以弧度/秒为单位。
"""
返回2.0*np.pi*self.center
八级波段(频率):
分数倍频程谱。
"""
定义初始化(self,center=None,fstart=None,fstop=None,nbands=None,分数=1,
参考=声学。倍频程。参考):
如果“中心”不是“无”:
尝试:
nbands=透镜(中心)
除类型错误外:
中心=[中心]
中心=np.asarray(中心)
指数=声学。倍频程。频率指数(中心,分数=分数,参考=参考)
elif fstart不是None,fstop不是None:
nstart=声学。倍频程。频率指数(fstart,分数=分数,ref=参考)
nstop=声学。倍频程。频率指数(fstop,分数=分数,ref=参考)
指数=np.arange(nstart,nstop+1)
elif fstart不是None,nbands不是None:
nstart=声学。倍频程。频率指数(fstart,分数=分数,ref=参考)
指数=np.arange(nstart,nstart+nbands)
elif fstop不是None,nbands不是None:
nstop=声学。倍频程。频率指数(fstop,分数=分数,ref=参考)
指数=np.arange(nstop-nbands,nstop)
其他:
raise VALUERROR(“参数不足。无法确定fstart和/或fstop。”)
中心=声学。倍频程。准确的中心频率(无,分数=分数,n=指数,r