简体   繁体   English

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

[英]How can I find the break frequencies/3dB points from a bandpass filter frequency sweep data in python?

The data that i have is stored in a 2D list where one column represents a frequency and the other column is its corresponding dB.我拥有的数据存储在二维列表中,其中一列代表频率,另一列是其对应的 dB。 I would like to programmatically identify the frequency of the 3db points on either end of the passband.我想以编程方式识别通带两端的 3db 点的频率。 I have two ideas on how to do this but they both have drawbacks.我有两个关于如何做到这一点的想法,但它们都有缺点。

  1. Find maximum point then the average of points in the passband then find points about 3dB lower找到最大点然后通带中点的平均值然后找到大约低 3dB 的点
  2. Use the sympy library to perform numerical differentiation and identify the critical points/inflection points使用 sympy 库执行数值微分并识别关键点/拐点
  3. use a histogram/bin function to find the amplitude of the passband.使用直方图/bin 函数找到通带的幅度。

drawbacks缺点

  1. sensitive to spikes, not quite sure how to do this对尖峰敏感,不太确定如何做到这一点
  2. i don't under stand the math involved and the data is noisy which could lead to a lot of false positives我不明白所涉及的数学和数据是嘈杂的,这可能会导致很多误报
  3. correlating the amplitude values with list index values could be tricky将幅度值与列表索引值相关联可能很棘手

Can you think of better ideas and/or ways to implement what I have described?你能想到更好的想法和/或方法来实现我所描述的内容吗?

Assuming that you've loaded multiple readings of the PSD from the signal analyzer, try averaging them before attempting to find the bandedges.假设您已经从信号分析仪加载了多个 PSD 读数,请在尝试找到带边之前尝试对它们求平均值。 If the signal isn't changing too dramatically, the averaging process might smooth away any peaks and valleys and noise within the passband, making it easier to find the edges.如果信号变化不大,平均过程可能会消除通带内的任何波峰和波谷以及噪声,从而更容易找到边缘。 This is what many spectrum analyzers can do to make for a smoother PSD.这是许多频谱分析仪可以实现的更平滑的 PSD。

In case that wasn't clear, assume that each reading gives you 128 tuples of the frequency and power and that you capture 100 of these buffers of data.如果不清楚,假设每个读数为您提供 128 个频率和功率元组,并且您捕获了 100 个这些数据缓冲区。 Now average the 100 samples from bin 0, then samples from 1, 2, ..., 128. Now try and locate the bandpass on this data.现在平均来自 bin 0 的 100 个样本,然后来自 1, 2, ..., 128 的样本。现在尝试定位这些数据的带通。 It should be easier than on any single buffer.它应该比在任何单个缓冲区上更容易。 Note I used 100 as an example.注意我以 100 为例。 If your data is very noisy, it may require more.如果您的数据非常嘈杂,则可能需要更多。 If there isn't much noise, fewer.如果没有太多噪音,就更少。

Be careful when doing the averaging.求平均值时要小心。 Your data is in dB.您的数据以 dB 为单位。 To add the samples together in order to find an average, you must first convert the dB data back to decimal, do the adds, do the divide to find the average, and then convert the averaged power back into dB.要将样本加在一起以找到平均值,您必须首先将 dB 数据转换回十进制,然后进行加法、除法以找到平均值,然后将平均功率转换回 dB。

Ok it seems this has to be solved by data analysis.好吧,看来这必须通过数据分析来解决。 I would propose these steps:我会提出以下步骤:

Preprocess you data if you suspect it to bee too noisy.如果您怀疑数据过于嘈杂,请对数据进行预处理。 I'd suggest either moving-average filter ( sp.convolve(data, sp.ones(n)/n, "same") ) or better a savitzky-golay-filter ( sp.signal.savgol_filter(data, n, polyorder=3) ) because you will be interested in extrema of the data, which will be unnecessarily distorted by the ma filter.我建议使用移动平均滤波器( sp.convolve(data, sp.ones(n)/n, "same") )或更好的 savitzky-golay-filter( sp.signal.savgol_filter(data, n, polyorder=3) ) 因为您将对数据的极值感兴趣,这将被 ma 过滤器不必要地扭曲。 You might also want to get rid of artifacts like 60Hz noise at this stage.在此阶段,您可能还想消除 60Hz 噪声等伪像。

If the signal you are interested in lives in a narrow band, the spectrum will be a single pronounced peak.如果您感兴趣的信号位于窄带中,则频谱将是一个明显的峰值。 In that case you could just fit a curve to your data, a gaussian would be appropriate in that case.在这种情况下,您可以只为您的数据拟合一条曲线,在这种情况下高斯将是合适的。

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]]

This is more an example than a solution, and relies heavily on the assumption the you are searching and finding a high SNR signal with a narrow band.这与其说是解决方案,不如说是一个示例,并且在很大程度上依赖于您正在搜索并找到窄带高 SNR 信号的假设。 It could be extended to handle more than one signal by use of a mixture model.通过使用混合模型,它可以扩展到处理多个信号。

You can use scipy's UnivariateSpline and leastsq methods:您可以使用 scipy 的 UnivariateSpline 和 leastsq 方法:

  1. Create a spline of y-(np.max(y)-3)创建y-(np.max(y)-3)的样条
  2. Find the roots of it.找出它的根源。
  3. Calculate the difference between the two roots.计算两个根之间的差值。
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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM