【问题标题】:How can I find the break frequencies/3dB points from a bandpass filter frequency sweep data in python?如何从 python 中的带通滤波器频率扫描数据中找到中断频率/3dB 点?
【发布时间】:2014-12-04 12:38:02
【问题描述】:

我拥有的数据存储在一个二维列表中,其中一列代表频率,另一列是其对应的 dB。我想以编程方式识别通带两端 3db 点的频率。我有两个关于如何做到这一点的想法,但它们都有缺点。

  1. 找到最大点,然后找到通带中点的平均值,然后找到大约低 3dB 的点
  2. 使用 sympy 库执行数值微分并识别临界点/拐点
  3. 使用直方图/bin 函数来查找通带的幅度。

缺点

  1. 对尖峰敏感,不太确定如何操作
  2. 我不理解所涉及的数学运算,而且数据嘈杂,可能导致大量误报
  3. 将幅度值与列表索引值关联起来可能很棘手

你能想出更好的想法和/或方法来实现我所描述的吗?

【问题讨论】:

  • 您知道用于获取数据的过滤器类型吗?这可能会导致理论上的结果。
  • 使用信号分析仪收集数据。一个信号发生器,对滤波器进行步进频率扫描。至于滤波器本身是如何构造的,我不确定它的带通范围之外。最终,无论带通滤波器的类型如何,我都希望能够处理来自信号分析仪的数据。

标签: python math signal-processing


【解决方案1】:

假设您已经从信号分析仪加载了多个 PSD 读数,请在尝试找到带边之前尝试对它们进行平均。如果信号变化不大,平均过程可能会消除通带内的任何峰谷和噪声,从而更容易找到边缘。这是许多频谱分析仪可以做的,以使 PSD 更平滑。

如果不清楚,假设每个读数都为您提供 128 个频率和功率元组,并且您捕获了 100 个这些数据缓冲区。现在平均来自 bin 0 的 100 个样本,然后来自 1、2、...、128 的样本。现在尝试在此数据上定位带通。它应该比任何单个缓冲区更容易。注意我以 100 为例。如果您的数据非常嘈杂,则可能需要更多。如果噪音不大,那就少一点。

进行平均时要小心。您的数据以 dB 为单位。要将样本相加以获得平均值,您必须首先将 dB 数据转换回十进制,然后进行加法、除法以找到平均值,然后将平均功率转换回 dB。

【讨论】:

    【解决方案2】:

    好的,看来这必须通过数据分析来解决。我会提出以下步骤:

    如果您怀疑数据过于嘈杂,请对数据进行预处理。我建议使用移动平均滤波器 (sp.convolve(data, sp.ones(n)/n, "same")) 或更好的 savitzky-golay-filter (sp.signal.savgol_filter(data, n, polyorder=3)),因为您会对数据的极值感兴趣,这将被 ma 滤波器不必要地扭曲。在此阶段,您可能还想消除 60Hz 噪声等伪影。

    如果您感兴趣的信号处于窄带中,则频谱将是一个明显的峰值。在这种情况下,您可以只为您的数据拟合一条曲线,在这种情况下,高斯将是合适的。

    import scipy as sp
    import matplotlib.pyplot as plt
    from scipy.optimize import curve_fit
    
    freq, pow = read_in_your_data_here()
    freq, pow = sp.asarray(freq), sp.asarray(pow)
    
    def gauss(x, a, mu, sig):
        return a**sp.exp(-(x-mu)**2/(2.*sig**2))
    
    (a, mu, sig), _ = curve_fit(gauss, freq, pow)
    fitted_curve = gauss(freq, a, mu, sig)
    
    plt.plot(freq, pow)
    plt.plot(freq, fitted_curve)
    plt.vlines(mu, min(pow)-2, max(pow)+2)
    plt.show()
    
    center_idx = sp.absolute(freq-mu).argmin()
    pow_center = pow[center_idx]
    pow_3db = pow_center - 3.
    
    def interv_from_binvec(data):
        indicator = sp.convolve(data, [-1,1], "same")
        return indicator.argmin(), indicator.argmax()
    
    passband_idx = interv_from_binvec(pow > pow_3db)
    passband = freq[passband_idx[0]], freq[passband_idx[1]]
    

    这与其说是一个解决方案,不如说是一个示例,并且很大程度上依赖于您正在搜索并找到具有窄带的高 SNR 信号的假设。通过使用混合模型,它可以扩展到处理多个信号。

    【讨论】:

      【解决方案3】:

      您可以使用 scipy 的 UnivariateSpline 和 leastsq 方法:

      1. 创建y-(np.max(y)-3)的样条线
      2. 找到它的根源。
      3. 计算两个根之间的差。
      from scipy.interpolate import UnivariateSpline
      from scipy.optimize import leastsq
      
      x = df["Wavelength / nm"]
      y = df["Power / dBm"]
      
      #create spline
      spline = UnivariateSpline(x, y-(np.max(y)-3), s=0)
      
      # find the roots
      r1, r2 = spline.roots()
      
      # calculate the difference
      threedB_bandwidth = abs(r2-r1)
      

      【讨论】:

        猜你喜欢
        • 2016-02-08
        • 1970-01-01
        • 2014-03-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-19
        • 2013-06-22
        • 2015-11-27
        相关资源
        最近更新 更多