问题
scipy.signal
(或其他python包)是否内置了可逆低通滤波器?如果是这样,它是什么?如果没有,为什么不呢(反转低通滤波器是否特别困难)?
细化
我需要一个可逆(数字,一阶,具体而言)低通滤波器,例如巴特沃斯滤波器。我需要应用它的倒数来用预补偿模拟信号。信号经过滤波后由数字转换为模拟。
迄今为止完成的工作
天真地,(据我所知)我可以做到以下几点:
import numpy as np
import scipy
# define signal here
num_order = 1
cutoff_frequency = 1e4 # Hz
time_constant = 1/(2*np.pi*cutoff_frequency)
lpf_b, lpf_a = scipy.signal.butter(num_order, btype='low', Wn=1/time_constant/(2*np.pi*sample_rate/2))
precompensated_signal = scipy.signal.lfilter(lpf_a, lpf_b, signal)
其中一个示例信号被定义为(例如)
sample_rate = 1e6
t_period = 2*1e-3
num_samples = int(round(t_period*sample_rate))
amplitude = 0.23
signal = amplitude*np.ones(num_samples)
这种方法在反转高通滤波器时有效。
在正向应用过滤器 ( filtered_signal
)
filtered_signal = scipy.signal.lfilter(lpf_b, lpf_a, signal)
但是将其向后 ( precompensated_signal
) 应用到预补偿会产生一个振荡信号:
查看系数,我发现
lpf_a = [ 1.0, -0.93906251]
lpf_b = [0.03046875, 0.03046875]
似乎在 b 中具有两个相同的系数作为第一个也是唯一的系数是使滤波器不可逆的原因。
2016年有一个相关的问题和答案。根据答案,取给定的滤波器系数scipy.signal.butter
并修改如下
lpf_b, lpf_a = scipy.signal.butter(num_order, btype='low', Wn=1/time_constant/(2*np.pi*sample_rate/2))
lpf_b_2 = [1 + lpf_a[1]] # note that lpf_b_2[0] = lpf_b[0] + lpf_b[1]
filtered_signal_2 = scipy.signal.lfilter(lpf_b_2, lpf_a, signal)
precompensated_signal_2 = scipy.signal.lfilter(lpf_a, lpf_b_2, signal)
产生一个过滤器,它在正向 ( filtered_signal_2
) 上的行为与原始过滤器相同:
并且在向后方向上表现得更好(precompensated_signal_2
):
尽管产生的信号仍然值得怀疑。唯一与幅度不同的系数是第一个(即使改变截止频率,这似乎也是如此),令人担忧的是,第一个数据点的电压变得非常大。对于上述链接答案中的过滤器,此功能似乎是正确的。
编辑
ZR Han建议(谢谢!)移动过滤器的极点。据我了解,可以这样做:
z, p, k = scipy.signal.tf2zpk(lpf_b, lpf_a)
# the zero z = [-1.0] as he suggested
z = [-0.95]
lpf_b, lpf_a = scipy.signal.zpk2tf(z, p, k)
这导致
lpf_b = [0.03046875, 0.02894531]
lpf_a = [ 1.0, -0.93906251]
但不幸的是,这并没有消除所有的振荡,通过绘制预补偿信号 ( ) 可以看出scipy.signal.lfilter(lpf_a, lpf_b, signal) with the modified coeffs
:
也许这是由于 z/my 对什么是“小转变”缺乏正式的选择而造成的。由于预补偿信号被转换为模拟信号,不幸的是,该解决方案不能容忍不良行为。
从这里出发的路线
- 解释修改后的过滤器对应的内容
- 从 scipy 的答案中找到过滤器
- 寻找另一个更适合用于转换为模拟信号的滤波器(平滑和有限)
背景:我在数字信号处理方面没有正式的背景,但我可以学习我需要的东西(如果我指向来源,会更快)。