scipy.signal.minimumphase偏离了预期的幅度

时间:2018-01-18 08:23:50

标签: python-3.x scipy filtering signal-processing digital-filter

我遇到的问题scipy.signal.minimumphase没有提供与我输入相同的幅度响应,它偏离了很多。

长话短说。我有一种材料,其中所述材料的吸收是在倍频带(6个离散值)中测量的。我需要一个适合这些值的脉冲响应。我想通过使用最小相位FIR滤波器来近似该脉冲响应,因为我没有任何相位信息。

我的程序如下

  1. 使用样条插值方案从离散值创建所需的幅度响应。
  2. 镜像插值幅度响应
  3. IFFT幅度响应。
  4. 将脉冲响应移动一半长度,创建线性相位并使其成为因果关系
  5. 使用scipy.signal.minimuphase创建最小相位冲动
  6. 样条插值在这里不是问题,问题是最小相位的大小偏离了线性相位,我似乎无法找到错误或原因?运行下面的代码会产生以下响应:

    enter image description here

    这是代码的最小工作部分,它绘制了插值幅度响应,线性相位幅度和最小相位幅度。

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy import signal
    
    plt.close('all')
    
    ## Determining Gradient between points
    def slope(x1, y1, x2, y2):
        m = (y2-y1)/(x2-x1)
        return m
    
    
    ## Parameters for designing the frequency response
    fs = 48000
    N = 4096
    alpha = np.array([1,0.07,0.17,0.40,0.55,0.65,0.65,1])
    beta = np.sqrt(1-alpha)
    f = np.array([0,125,250,500,1000,2000,4000,(fs/2)])
    
    ### Spline interpolation
    faxis = np.linspace(0,fs/2,np.int64(N))
    gradient = np.zeros((np.size(f),1))
    x = np.zeros([4,np.size(f)-1])   
    
    for n in range(0,np.size(f)-1,1):
        gradient[n] = slope(f[n],beta[n],f[n+1],beta[n+1])
    
    for n in range(0,(np.size(f))-1,1):
        a = np.array([[f[n]**3,f[n]**2,f[n]**1,1], 
                      [f[n+1]**3,f[n+1]**2,f[n+1]**1,1],
                      [3*(f[n]**2),f[n]*2,1,0],
                      [3*(f[n+1]**2),f[n+1]*2,1,0]])
        b = np.array([beta[n],beta[n+1],gradient[n],gradient[n+1]])    
        x[:,n] = np.linalg.solve(a, b)
    
    ## Using a,b,c,d coef. to make the polynomials and then crop them to fit
    poly = np.zeros([(np.size(faxis)),np.size(beta)])
    combined = np.array([])
    for n in range(0,np.size(poly,1)-1,1):
        poly[:,n] = x[0,n]*faxis**3+x[1,n]*faxis**2+x[2,n]*faxis+x[3,n]        
        combined = np.append(combined,poly[(faxis >= f[n]) & (faxis <= f[n+1]),n])        
    
    ## Mirror the single sided frequency response
    Full = np.concatenate((combined,np.flipud(combined)))
    
    ## ifft the mirrored resposne - No Phase info
    impulse = np.real(np.fft.ifft(Full))
    
    ## Add linear phase to the impulse - i.e. shift the response and make it causal 
    impulseshift = np.roll(impulse,np.int(len(impulse)/2)-1)
    
    ## Change to minimumphase
    minphase = signal.minimum_phase(impulseshift[:-1],method='hilbert',n_fft=fs)   
    
    
    ## Plot the results
    wLinear, hLinear = signal.freqz(impulseshift,worN=4096)  
    w, h = signal.freqz(minphase,worN=4096)  
    
    plt.figure
    plt.semilogx(faxis,combined,label="No Phase")
    plt.semilogx((fs * 0.5 / np.pi) * w, abs(h),label="Minimum Phase")
    plt.semilogx((fs * 0.5 / np.pi) * wLinear, abs(hLinear),label="Linear Phase")
    plt.grid()
    plt.legend()
    plt.xlabel("Frequency [Hz]")
    plt.ylabel("Amplitude [.]")
    

1 个答案:

答案 0 :(得分:0)

除了使用scipy.signal.firwin2直接基于某些倍频程带增益设计线性相位滤波器(您的第1步至第4步),然后使其成为最小相位外,我在做相同的事情。

如果您查看documentation中的参数详细信息,则会看到:

  产生的最小相位滤波器的幅度响应为   近似于原始过滤器幅度的 平方根   响应。

您的情节反映了这种平方根关系。简单的解决方法是在将您的“所需幅度响应”输入scipy.signal.minimuphase之前对其进行平方。