如何从python中的带通滤波器频率扫描数据中找到中断频率/ 3dB点?

时间:2014-10-09 14:19:28

标签: python math signal-processing

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

  1. 找到最大点然后通带中的点的平均值然后找到大约3dB的点
  2. 使用sympy库进行数值区分并确定关键点/拐点
  3. 使用直方图/ bin函数来查找通带的幅度。
  4. 缺点

    1. 对尖峰敏感,不太确定如何做到这一点
    2. 我没有理解所涉及的数学,而且数据很嘈杂,可能导致很多误报
    3. 将幅度值与列表索引值相关联可能很棘手
    4. 你能想到更好的想法和/或实现我所描述的方法吗?

3 个答案:

答案 0 :(得分:0)

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

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

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

答案 1 :(得分:0)

好吧,这似乎必须通过数据分析来解决。我会建议这些步骤:

如果您怀疑它太嘈杂,请预处理您的数据。我建议使用移动平均滤波器(sp.convolve(data, sp.ones(n)/n, "same"))或更好的savitzky-golay滤波器(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信号。可以通过使用混合模型将其扩展为处理多个信号。

答案 2 :(得分:0)

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

  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)