如何在python中实现连续时间高通/低通滤波器?
我有一个应用程序,接收固定频率的输入信号。我一直在尝试为这个传入信号实现一个过滤器,而不必节省N个时间步并对其执行过滤功能。我想做的是类似于一维卡尔曼滤波器,我用新的观测值更新我的当前状态。我不是数学家,因此维基百科关于这是否可能的页面对我来说是完全无法理解的。此外,这个域中的StackOverflow答案(我已经发现)只考虑是否有N个时间步的信号可用,以及如何对其执行过滤,我可以毫无问题地进行过滤 我在下面提供了一些虚拟代码,说明了我一直试图编写的函数类型如何在python中实现连续时间高通/低通滤波器?,python,numpy,scipy,filtering,Python,Numpy,Scipy,Filtering,我有一个应用程序,接收固定频率的输入信号。我一直在尝试为这个传入信号实现一个过滤器,而不必节省N个时间步并对其执行过滤功能。我想做的是类似于一维卡尔曼滤波器,我用新的观测值更新我的当前状态。我不是数学家,因此维基百科关于这是否可能的页面对我来说是完全无法理解的。此外,这个域中的StackOverflow答案(我已经发现)只考虑是否有N个时间步的信号可用,以及如何对其执行过滤,我可以毫无问题地进行过滤 我在下面提供了一些虚拟代码,说明了我一直试图编写的函数类型 import numpy as np
import numpy as np
import matplotlib.pyplot as plt
def high_pass(new, previous, cutoff=20):
# Howto?
return 0
def low_pass(new, previous, cutofff=20):
# Howto?
return 0
def continuous_filter(vs):
prev_highpass, prev_lowpass = 0, 0
for v in vs:
prev_highpass = high_pass(v, prev_highpass)
prev_lowpass = low_pass(v, prev_lowpass)
yield prev_highpass, prev_lowpass
np.random.seed(21)
sec_duration = 10.0
time_resolution = 1e3
dt = 1/time_resolution
steps = int(sec_duration * time_resolution)
signal = np.sum([np.sin(np.linspace(0, np.random.randint(10, 100), steps)) * np.random.random() for _ in range(3)], axis=0)
filt_signals = np.array([[high, low] for high, low in continuous_filter(signal)])
plt.plot(signal, label="Input signal")
plt.plot(filt_signals[:, 0], label="High-pass")
plt.plot(filt_signals[:, 1], label="Low pass")
plt.legend()
plt.show()
有人能告诉我这是否可能吗?我一直在看SciPy,但我不理解它。首先,你需要一个截止时间的过滤器时间常数:
alpha=dt/(RC+dt)
和截止时间=1/(2*pi*RC)
您需要此因子来计算下一个过滤值:
def low_pass(x_new, y_old, cutoff=20):
alpha = dt / (dt + 1 / (2 * np.pi * cutoff))
y_new = x_new * alpha + (1 - alpha) * y_old
return y_new
来自维基百科:
来自维基百科:
首先,您需要从截止点为过滤器设置一个时间常数:
alpha=dt/(RC+dt)
和cutoff=1/(2*pi*RC)
您需要此因子来计算下一个过滤值:
def low_pass(x_new, y_old, cutoff=20):
alpha = dt / (dt + 1 / (2 * np.pi * cutoff))
y_new = x_new * alpha + (1 - alpha) * y_old
return y_new
来自维基百科:
来自维基百科:
这是一个很好的回答,多利安,谢谢你。经过多年的阴影堆栈溢出,这将是我的第一个贡献。它是次要的,希望它有助于扩展用例。尽可能多地保留原始符号,以便于跟踪 只需要两次进口
'''python
import numpy as np
import matplotlib.pyplot as plt
对rc_高通量α值的轻微修正
def rc_low_pass(x_new, y_old, sample_rate_hz, lowpass_cutoff_hz):
dt = 1/sample_rate_hz
rc = 1/(2*np.pi*lowpass_cutoff_hz)
alpha = dt/(rc + dt)
y_new = x_new * alpha + (1 - alpha) * y_old
return y_new
def rc_high_pass(x_new, x_old, y_old, sample_rate_hz, highpass_cutoff_hz):
dt = 1/sample_rate_hz
rc = 1/(2*np.pi*highpass_cutoff_hz)
alpha = rc/(rc + dt)
y_new = alpha * (y_old + x_new - x_old)
return y_new
def rc_filters(xs, sample_rate_hz,
highpass_cutoff_hz,
lowpass_cutoff_hz):
# Initialize. This can be improved to match wikipedia.
x_prev = 0
y_prev_high = 0
y_prev_low = 0
for x in xs:
y_prev_high = rc_high_pass(x, x_prev, y_prev_high, sample_rate_hz,
highpass_cutoff_hz)
y_prev_low = rc_low_pass(x, y_prev_low, sample_rate_hz,
lowpass_cutoff_hz)
x_prev = x
yield y_prev_high, y_prev_low
现在转到主屏幕,我使用赫兹和秒的物理单位。请原谅基数为2的数字表示法,它有助于为FFT设置舞台
if __name__ == "__main__":
"""
# RC filters for continuous signals
"""
sample_rate = 2**13 # Close to 8 kHz
duration_points = 2**10
sec_duration = duration_points/sample_rate
frequency_low = sample_rate/2**9
frequency_high = sample_rate/2**3
# Design the cutoff
number_octaves = 3
highpass_cutoff = frequency_high/2**number_octaves
lowpass_cutoff = frequency_low*2**number_octaves
print('Two-tone test')
print('Sample rate, Hz:', sample_rate)
print('Record duration, s:', sec_duration)
print('Low, high tone frequency:', frequency_low, frequency_high)
time_s = np.arange(duration_points)/sample_rate
sig = np.sin(2*np.pi*frequency_low*time_s) + \
np.sin(2*np.pi*frequency_high*time_s)
filt_signals = np.array([[high, low]
for high, low in
rc_filters(sig, sample_rate,
highpass_cutoff, lowpass_cutoff)])
输入信号不同,更接近我的典型用例,结果图显示通常的RC滤波器不是很快。这是一个经典的解决方案,在这里使用它很好
plt.plot(sig, label="Input signal")
plt.plot(filt_signals[:, 0], label="High-pass")
plt.plot(filt_signals[:, 1], label="Low-pass")
plt.title("RC Low-pass and High-pass Filter Response")
plt.legend()
plt.show()
这是一个很好的回答,多利安,谢谢你。经过多年的阴影堆栈溢出,这将是我的第一个贡献。它是次要的,希望它有助于扩展用例。尽可能多地保留原始符号,以便于跟踪 只需要两次进口
'''python
import numpy as np
import matplotlib.pyplot as plt
对rc_高通量α值的轻微修正
def rc_low_pass(x_new, y_old, sample_rate_hz, lowpass_cutoff_hz):
dt = 1/sample_rate_hz
rc = 1/(2*np.pi*lowpass_cutoff_hz)
alpha = dt/(rc + dt)
y_new = x_new * alpha + (1 - alpha) * y_old
return y_new
def rc_high_pass(x_new, x_old, y_old, sample_rate_hz, highpass_cutoff_hz):
dt = 1/sample_rate_hz
rc = 1/(2*np.pi*highpass_cutoff_hz)
alpha = rc/(rc + dt)
y_new = alpha * (y_old + x_new - x_old)
return y_new
def rc_filters(xs, sample_rate_hz,
highpass_cutoff_hz,
lowpass_cutoff_hz):
# Initialize. This can be improved to match wikipedia.
x_prev = 0
y_prev_high = 0
y_prev_low = 0
for x in xs:
y_prev_high = rc_high_pass(x, x_prev, y_prev_high, sample_rate_hz,
highpass_cutoff_hz)
y_prev_low = rc_low_pass(x, y_prev_low, sample_rate_hz,
lowpass_cutoff_hz)
x_prev = x
yield y_prev_high, y_prev_low
现在转到主屏幕,我使用赫兹和秒的物理单位。请原谅基数为2的数字表示法,它有助于为FFT设置舞台
if __name__ == "__main__":
"""
# RC filters for continuous signals
"""
sample_rate = 2**13 # Close to 8 kHz
duration_points = 2**10
sec_duration = duration_points/sample_rate
frequency_low = sample_rate/2**9
frequency_high = sample_rate/2**3
# Design the cutoff
number_octaves = 3
highpass_cutoff = frequency_high/2**number_octaves
lowpass_cutoff = frequency_low*2**number_octaves
print('Two-tone test')
print('Sample rate, Hz:', sample_rate)
print('Record duration, s:', sec_duration)
print('Low, high tone frequency:', frequency_low, frequency_high)
time_s = np.arange(duration_points)/sample_rate
sig = np.sin(2*np.pi*frequency_low*time_s) + \
np.sin(2*np.pi*frequency_high*time_s)
filt_signals = np.array([[high, low]
for high, low in
rc_filters(sig, sample_rate,
highpass_cutoff, lowpass_cutoff)])
输入信号不同,更接近我的典型用例,结果图显示通常的RC滤波器不是很快。这是一个经典的解决方案,在这里使用它很好
plt.plot(sig, label="Input signal")
plt.plot(filt_signals[:, 0], label="High-pass")
plt.plot(filt_signals[:, 1], label="Low-pass")
plt.title("RC Low-pass and High-pass Filter Response")
plt.legend()
plt.show()
太好了!但是,代码中有一个小错误。高通函数中的截止参数需要松开一个“f”。我不能做那个编辑,因为它是太小,根据其他评论:没有连续时间这样的事情,你总是在看离散的步骤。这只是对你的问题的补充。太好了!但是,代码中有一个小错误。高通函数中的截止参数需要松开一个“f”。我不能做那个编辑,因为它是太小,根据其他评论:没有连续时间这样的事情,你总是在看离散的步骤。这是一个很好的答案,谢谢。您是指谁?对于主要解决方案贡献者,感谢您指出这一点。这是一个很好的答案,谢谢。您是指谁?对于主要解决方案贡献者,感谢您指出这一点。在这方面我是新手。