gpt4 book ai didi

python - 在Python中应用时变过滤器

转载 作者:太空狗 更新时间:2023-10-30 02:04:42 28 4
gpt4 key购买 nike

我正在尝试使用一个带时变截止频率的带通滤波器来使用Python。我目前使用的例程将我的信号分割成等长度的时间段,然后在每次将信号合并之前,对每个段应用一个具有特定于时间的参数的滤波器。参数是基于预先存在的估计。
我所遇到的问题是,在应用了过滤器之后出现的每个时间段的边缘都有“涟漪”。这会导致我的信号不连续,干扰我的滤波后数据分析。
我希望有人能告诉我,在Python中是否存在用于实现具有时变参数的过滤器的现有例程?另外,关于我如何解决这个问题的建议将非常感谢。
编辑——下面添加了我想做的事情的示例。
假设我有一个信号x(t)。我想用参数(100200)Hz的带通滤波器对上半部分进行滤波。下半部分我想用参数(140, 240)Hz滤波。我迭代X(t),将我的过滤器应用到每一半,然后重新组合结果。一些示例代码可能如下所示:

outputArray = np.empty(len(x))
segmentSize = len(x) / 2
filtParams = [(100, 200), (140, 240)]

for i in range(2):
tempData = x[i*segmentSize:(i+1)*segmentSize]
tempFiltered = bandPassFilter(tempData, parameters=filtParams[i])
outputArray[i*segmentSize:(i+1)*segmentSize] = tempFiltered

(为了节省空间,假设我有一个执行带通滤波的函数)。
如您所见,数据段不重叠,只是简单地“粘贴”在新数组中。
编辑2——我的问题@ HD的一些示例代码。
首先,感谢你迄今为止的重要投入。AudioLasy软件包看起来是个很棒的工具。
我想如果我能更详细地描述我的目标会更有用一些。正如我已经发表的 elsewhere,我试图用希尔伯特变换提取一个信号的AA>(if)。我的数据包含了很大的噪声,但是我对我的IF信号的带宽有很好的估计。不过,我遇到的一个问题是
IF常常是非平稳的。因此,使用“静态”滤波器的方法经常需要使用宽的带通区域,以确保捕获所有频率。
下面的代码演示了增加滤波器带宽对中频信号的影响。它包括信号生成功能、使用SIPY.Stand信号包的带通滤波器的实现以及提取所得到的滤波信号的IF的方法。
from audiolazy import *
import scipy.signal as sig
import numpy as np
from pylab import *

def sineGenerator( ts, f, rate, noiseLevel=None ):
"""generate a sine tone with time, frequency, sample rate and noise specified"""

fs = np.ones(len(ts)) * f
y = np.sin(2*np.pi*fs*ts)

if noiseLevel: y = y + np.random.randn(len(y))/float(noiseLevel)
return y

def bandPassFilter( y, passFreqs, rate, order ):
"""STATIC bandpass filter using scipy.signal Butterworth filter"""

nyquist = rate / 2.0
Wn = np.array([passFreqs[0]/nyquist, passFreqs[1]/nyquist])
z, p, k = sig.butter(order, Wn, btype='bandpass', output='zpk')
b, a = sig.zpk2tf(z, p, k)

return sig.lfilter(b, a, y)

if __name__ == '__main__':
rate = 1e4
ts = np.arange(0, 10, 1/rate)

# CHANGING THE FILTER AFFECTS THE LEVEL OF NOISE
ys = sineGenerator(ts, 600.0, 1e4, noiseLevel=1.0) # a 600Hz signal with noise
filts = [[500, 700], [550, 650], [580, 620]]

for f in filts:
tempFilt = bandPassFilter( ys, f, rate, order=2 )
tempFreq = instantaneousFrequency( tempFilt, rate )

plot( ts[1:], tempFreq, alpha=.7, label=str(f).strip('[]') )

ylim( 500, 750 )
xlabel( 'time' )
ylabel( 'instantaneous frequency (Hz)' )

legend(frameon=False)
title('changing filter passband and instantaneous frequency')
savefig('changingPassBand.png')

信号中只有一个频率分量(600Hz)。图例显示了在每种情况下使用的滤波器参数。使用一个更窄的“静态”过滤器给出一个“干净”的输出。但是我的滤波器能有多窄受到频率的限制。例如,考虑以下两个频率分量的信号(一个在600Hz,另一个在650Hz)。
在这个例子中,我被迫使用一个更宽的带通滤波器,这导致额外的噪声悄悄进入中频数据。
我的想法是,通过使用时变滤波器,我可以在某些时间增量上“优化”我的信号的滤波器。所以对于上面的信号,我可能希望在前5秒过滤580-620Hz,然后在后5秒过滤630-670Hz。基本上我想在最终的中频信号中最小化噪声。
基于您发送的示例代码,我编写了一个函数,该函数使用AdoLoZy在信号上实现静态巴特沃思滤波器。
def audioLazyFilter( y, rate, Wp, Ws ):
"""implement a Butterworth filter using audiolazy"""

s, Hz = sHz(rate)
Wp = Wp * Hz # Bandpass range in rad/sample
Ws = Ws * Hz # Bandstop range in rad/sample

order, new_wp_divpi = sig.buttord(Wp/np.pi, Ws/np.pi, gpass=dB10(.6), gstop=dB10(.1))
ssfilt = sig.butter(order, new_wp_divpi, btype='bandpass')
filt_butter = ZFilter(ssfilt[0].tolist(), ssfilt[1].tolist())

return list(filt_butter(y))

使用该滤波器结合希尔伯特变换例程获得的IF数据与使用SiPi.Stand获得的那些信号进行了比较:
AL_filtered = audioLazyFilter( ys, rate, np.array([580, 620]), np.array([570, 630]) )
SP_filtered = bandPassFilter( ys, [580, 620], rate, order=2 )
plot(ts[1:], instantaneousFrequency( SP_filtered, 1e4 ), alpha=.75, label='scipy.signal Butterworth filter')
plot(ts[1:], instantaneousFrequency( AL_filtered, 1e4 ), 'r', alpha=.75, label='audiolazy Butterworth filter')

我的问题是现在我可以将AdioLasZy ButtValm例程与您在原始文章中描述的时变特性结合起来吗?

最佳答案

使用时变滤波器的本地工作原理

from audiolazy import sHz, white_noise, line, resonator, AudioIO

rate = 44100
s, Hz = sHz(rate)

sig = white_noise() # Endless white noise Stream

dur = 8 * s # Some few seconds of audio
freq = line(dur, 200, 800) # A lazy iterable range
bw = line(dur, 100, 240)

filt = resonator(freq * Hz, bw * Hz) # A simple bandpass filter

with AudioIO(True) as player:
player.play(filt(sig), rate=rate)

您也可以使用它来绘制(或一般的)分析,通过使用 list(filt(sig))或< > >。还有很多其他的资源可能是有用的,例如在z变换滤波器方程中直接应用时变系数。
编辑:有关AudioLazy组件的详细信息
下面的例子是使用ipython完成的。
谐振器是一个cc实例,它将许多实现绑定在一个地方。
In [1]: from audiolazy import *

In [2]: resonator
Out[2]:
{('freq_poles_exp',): <function audiolazy.lazy_filters.freq_poles_exp>,
('freq_z_exp',): <function audiolazy.lazy_filters.freq_z_exp>,
('poles_exp',): <function audiolazy.lazy_filters.poles_exp>,
('z_exp',): <function audiolazy.lazy_filters.z_exp>}

In [3]: resonator.default
Out[3]: <function audiolazy.lazy_filters.poles_exp>

因此 filt(sig).take(inf)在内部调用 StrategyDict函数,从中可以获得一些帮助
In [4]: resonator.poles_exp?
Type: function
String Form:<function poles_exp at 0x2a55b18>
File: /usr/lib/python2.7/site-packages/audiolazy/lazy_filters.py
Definition: resonator.poles_exp(freq, bandwidth)
Docstring:
Resonator filter with 2-poles (conjugated pair) and no zeros (constant
numerator), with exponential approximation for bandwidth calculation.

Parameters
----------
freq :
Resonant frequency in rad/sample (max gain).
bandwidth :
Bandwidth frequency range in rad/sample following the equation:

``R = exp(-bandwidth / 2)``

where R is the pole amplitude (radius).

Returns
-------
A ZFilter object.
Gain is normalized to have peak with 0 dB (1.0 amplitude).

所以一个详细的过滤器分配将是
filt = resonator.poles_exp(freq=freq * Hz, bandwidth=bw * Hz)

其中 resonator只是一个数字,将单元从HZ转换到RAAD/SAMPLE,就像大多数音频文件中使用的一样。
让我们使用 resonator.poles_expHzfreq = pi/4已经在 bw = pi/8命名空间中):
In [5]: filt = resonator(freq=pi/4, bandwidth=pi/8)

In [6]: filt
Out[6]:
0.233921
------------------------------------
1 - 1.14005 * z^-1 + 0.675232 * z^-2


In [7]: type(filt)
Out[7]: audiolazy.lazy_filters.ZFilter

您可以尝试使用此筛选器,而不是第一个示例中给定的筛选器。
另一种方法是使用包中的 pi对象。
首先让我们找出全极点谐振器的常数:
In [8]: freq, bw = pi/4, pi/8

In [9]: R = e ** (-bw / 2)

In [10]: c = cos(freq) * 2 * R / (1 + R ** 2) # AudioLazy included the cosine

In [11]: gain = (1 - R ** 2) * sqrt(1 - c ** 2)

分母可以直接使用公式中的 audiolazy来完成:
In [12]: denominator = 1 - 2 * R * c * z ** -1 + R ** 2 * z ** -2

In [13]: gain / denominator
Out[14]:
0.233921
------------------------------------
1 - 1.14005 * z^-1 + 0.675232 * z^-2

In [15]: type(_) # The "_" is the last returned value in IPython
Out[15]: audiolazy.lazy_filters.ZFilter

编辑2:关于时变系数
滤波器系数也可以是流实例(可以从任何iterable转换)。
In [16]: coeff = Stream([1, -1, 1, -1, 1, -1, 1, -1, 1, -1]) # Cast from a list

In [17]: (1 - coeff * z ** -2)(impulse()).take(inf)
Out[17]: [1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

同样,给出一个列表输入而不是 z流:
In [18]: coeff = Stream((1, -1, 1, -1, 1, -1, 1, -1, 1, -1)) # Cast from a tuple 

In [19]: (1 - coeff * z ** -2)([1, 0, 0, 0, 0, 0, 0]).take(inf)
Out[19]: [1.0, 0.0, -1, 0, 0, 0, 0]

numpy 1d数组也是一个iterable:
In [20]: from numpy import array

In [21]: array_data = array([1, -1, 1, -1, 1, -1, 1, -1, 1, -1])

In [22]: coeff = Stream(array_data) # Cast from an array

In [23]: (1 - coeff * z ** -2)([0, 1, 0, 0, 0, 0, 0]).take(inf)
Out[23]: [0.0, 1.0, 0, 1, 0, 0, 0]

最后一个例子展示了时变行为。
编辑3:分块重复序列行为
line函数的行为类似于 z,它获取范围“length”而不是“step”。
In [24]: import numpy

In [25]: numpy.linspace(10, 20, 5) # Start, stop (included), length
Out[25]: array([ 10. , 12.5, 15. , 17.5, 20. ])

In [26]: numpy.linspace(10, 20, 5, endpoint=False) # Makes stop not included
Out[26]: array([ 10., 12., 14., 16., 18.])

In [27]: line(5, 10, 20).take(inf) # Length, start, stop (range-like)
Out[27]: [10.0, 12.0, 14.0, 16.0, 18.0]

In [28]: line(5, 10, 20, finish=True).take(inf) # Include the "stop"
Out[28]: [10.0, 12.5, 15.0, 17.5, 20.0]

这样,过滤器方程每个样本具有不同的行为样本(1样本“块”)。不管怎样,对于较大的块大小,可以使用中继器:
In [29]: five_items = _ # List from the last Out[] value

In [30]: @tostream
....: def repeater(sig, n):
....: for el in sig:
....: for _ in xrange(n):
....: yield el
....:

In [31]: repeater(five_items, 2).take(inf)
Out[31]: [10.0, 10.0, 12.5, 12.5, 15.0, 15.0, 17.5, 17.5, 20.0, 20.0]

并在第一个示例的行中使用它,使 impulse()numpy.linspace变成:
chunk_size = 100
freq = repeater(line(dur / chunk_size, 200, 800), chunk_size)
bw = repeater(line(dur / chunk_size, 100, 240), chunk_size)

编辑4:利用时变增益/包络仿真LTI滤波器的时变滤波器/系数
另一种方法是使用不同的“权重”来对两个不同的滤波版本进行信号处理,并用信号进行一些“交叉渐变”的数学运算,比如:
signal = thub(sig, 2) # T-Hub is a T (tee) auto-copy
filt1(signal) * line(dur, 0, 1) + filt2(signal) * line(dur, 1, 0)

这将从同一信号的不同滤波版本应用线性包络(从0到1和从1到0)。如果< > >看起来很混乱,尝试使用“cc”和“cc”,而这些应该做同样的事情。
编辑5:时变Butterworth滤波器
我花了最后几个小时试图让北海个人化为你的例子,强加 freq并给予半功率带宽(~3dB)直接。我已经做了四个例子,代码是AA>,并且我已经更新了AdioLoZy以包含一个 bw高斯分布的噪声流。请注意,GIST中的代码没有优化,它是在这个特定的情况下工作的,并且Chirp示例使得它由于“每个样本”系数查找行为而变得非常慢。瞬时频率可以从/采样中的[过滤]数据得到:
diff(unwrap(phase(hilbert(filtered_data))))

thub或另一种在离散时间内找到导数的方法中, sig1, sig2 = tee(sig, 2)是从“cc>函数中给出的解析信号(离散希尔伯特变换是它的结果的虚部),另外两个是来自AdioLoZy的辅助函数。
这是当巴特沃思突然改变其系数,同时保持其记忆,没有噪声:
在这种转变中,一种明显的振荡行为是显而易见的。你可以使用一个移动中值来“平滑”在低频侧,同时保持突然的转变,但是这不会用更高的频率来工作。这是我们期望的完美正弦曲线,但是有噪声(很多噪声,高斯的标准偏差等于正弦振幅),它变成:
我试着用同样的声音来做,正是这样:
这显示了一个奇怪的行为时,低带宽滤波,在最高频率。加性噪声:
gist中的代码也 filt(sig1)这最后一个噪声啁啾。
编辑6:时变谐振器滤波器
我在 AudioLazy中添加了一个使用谐振器而不是巴特沃斯的例子。它们在纯Python中并没有被优化,但是在啁啾中对每个样本的调用速度比调用 filt(sig2)要快,并且更容易实现,因为所有 order = 2策略都接受流实例作为有效输入。以下是两个谐振器级联(即二阶滤波器)的曲线图:
对于三个谐振器的级联(即,第三阶滤波器)是相同的:
这些谐振器在中心频率处的增益等于1(0db),并且即使没有任何滤波,从过渡过程中的“突变纯正弦波”图中的振荡模式也会发生。

关于python - 在Python中应用时变过滤器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18128057/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com