我目前正在尝试将带通滤波器实时应用于信号。有样本以恒定的采样率进入,我想计算相应的带通滤波信号。
最好的方法是什么?每次有几个新样本进入时,我是否必须过滤整个(或至少一个巨大的位)信号,或者是否有办法(如滑动 DFT)可以有效地确定过滤后的新部分信号?
我想使用一个 butterworth 过滤器(对于离线分析,我目前正在使用 scipy 的黄油和 lfilter)。我知道这个函数可以返回一个滤波器延迟,但我不知道如何使用它来获得一个恒定的信号。
我目前正在尝试将带通滤波器实时应用于信号。有样本以恒定的采样率进入,我想计算相应的带通滤波信号。
最好的方法是什么?每次有几个新样本进入时,我是否必须过滤整个(或至少一个巨大的位)信号,或者是否有办法(如滑动 DFT)可以有效地确定过滤后的新部分信号?
我想使用一个 butterworth 过滤器(对于离线分析,我目前正在使用 scipy 的黄油和 lfilter)。我知道这个函数可以返回一个滤波器延迟,但我不知道如何使用它来获得一个恒定的信号。
每次有几个新样本进入时,我是否必须过滤整个(或至少一个巨大的位)信号,或者是否有办法(如滑动 DFT)可以有效地确定过滤后的新部分信号?
数字滤波器不是这样工作的——基本上,经典的 FIR 或 IIR 可以在每个新样本上工作。您应该真正了解这些过滤器是什么,以及人们如何对它们进行建模。
我想使用巴特沃斯过滤器
好吧,那里有很多实现,
我目前正在使用 scipy 的黄油和 lfilter
其中一个你已经知道了!
现在,巴特沃斯滤波器是一个递归的东西,所以要计算采样信号的下一部分,你需要最后一个状态。这正是lfilter
返回的“过滤器延迟状态 zi”,并且可以在下一次调用中作为zi
参数。
但我不知道如何使用它来获得恒定的信号。
我认为您的意思是“实现连续过滤”。
现在,话虽如此,关键是您正在为编写自己的流式架构做好准备。我不会那样做的。使用现有框架。例如,有 GNU Radio,它可以让您在 Python 中定义信号处理流程图,并且本质上是多线程的,使用高度优化的算法实现,有很多输入和输出设施,并带有一个庞大的信号处理模块库,如果您碰巧需要这样做,可以用 Python 或 C++ 编写。
例如,从声卡中获取样本、巴特沃斯过滤它们并将它们写入文件的流程图是:
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
##################################################
# GNU Radio Python Flow Graph
# Title: Butterworth Test
# Generated: Mon Feb 8 16:17:18 2016
##################################################
from gnuradio import audio
from gnuradio import blocks
from gnuradio import eng_notation
from gnuradio import filter
from gnuradio import gr
from gnuradio.eng_option import eng_option
from gnuradio.filter import firdes
from optparse import OptionParser
class butterworth_test(gr.top_block):
def __init__(self):
gr.top_block.__init__(self, "Butterworth Test")
##################################################
# Variables
##################################################
self.samp_rate = samp_rate = 48000
##################################################
# Blocks
##################################################
# taps from scipy.butter!
self.iir_filter_xxx_0 = filter.iir_filter_ffd(([1.0952627450621233e-05, 0.00013143152940745496, 0.0007228734117410033, 0.0024095780391366808, 0.005421550588057537, 0.008674480940892064, 0.010120227764374086, 0.008674480940892081, 0.005421550588057554, 0.0024095780391366955, 0.0007228734117410089, 0.00013143152940745594, 1.0952627450621367e-05]), ([1.0, -4.4363862740719835, 10.215121830052535, -15.374408118154847, 16.57333784740102, -13.325056987818655, 8.133543488903097, -3.77641064765334, 1.3181452681671835, -0.3361758629961047, 0.05930166356243964, -0.0064815521348275, 0.00033130678123743994]), False)
self.blocks_file_sink_0 = blocks.file_sink(gr.sizeof_float*1, "", False)
self.blocks_file_sink_0.set_unbuffered(False)
self.audio_source_0 = audio.source(samp_rate, "", True)
##################################################
# Connections
##################################################
self.connect((self.audio_source_0, 0), (self.iir_filter_xxx_0, 0))
self.connect((self.iir_filter_xxx_0, 0), (self.blocks_file_sink_0, 0))
def main(top_block_cls=butterworth_test, options=None):
tb = top_block_cls()
tb.start()
try:
raw_input('Press Enter to quit: ')
except EOFError:
pass
tb.stop()
tb.wait()
if __name__ == '__main__':
main()
gnuradio-companion
请注意,此代码是从我刚刚使用该程序一起单击的图形流程图自动生成的:
如果您想了解有关如何在 Python 中实现信号处理流程图的更多信息,请 参阅 GNU Radio Guided Tutorials。
编辑:我非常喜欢@Fat32 的回答!他所描述的双缓冲架构与 GNU Radio 所做的非常接近:
上游块以任意大小的样本块生成样本,将它们写入输出环形缓冲区(在上图中用箭头表示),并通知其下游块有新数据。
下游块收到通知,检查其输出缓冲区中是否有足够的空间来处理其输入环形缓冲区(与上游块的输出缓冲区相同)中的样本,然后处理这些。完成后,它通知上游块它已用完输入环形缓冲区(然后上游块可以将其重用作为输出),并通知下游块有新样本可用。
现在,GNU Radio 是多线程的,上游块可能已经再次生成样本;在普通的 GNU Radio 应用程序中,几乎所有块都同时“活跃”,并且在多 CPU 机器上可以很好地扩展。
因此,GNU Radio 的主要工作是为您提供这个缓冲区基础设施、通知和线程管理、清晰的信号处理块 API 以及定义一切如何连接的东西,因此您不必编写 Fat32 在她/他的文件中描述的内容发布自己!请注意,正确地进行样本流编组并不是那么容易,而 GNU Radio 消除了它的困难,让您专注于您想做的事情:DSP。
PC平台下的实时数字音频处理基于双缓冲场景。[请注意,它可能不是一个完美的实时解决方案,因为通用 PC 操作系统的核心并不是为实时任务量身定制的。]
来自模拟输入源的声音首先通过声卡 ADC 转换为数字样本,并以选定的音频采样率填充到用户指定的输入缓冲区中。当这个缓冲区完全填满时,声卡控制器会通知操作系统,操作系统会通知您的应用程序,以便您的程序可以访问音频块以开始处理。
在处理当前可用块时,您的程序为声卡提供另一个(第二个)缓冲区,以填充在处理当前缓冲区期间到达的新样本。当当前可用的缓冲区被完全处理后,第二个缓冲区也应该被填满并准备好处理,您需要立即开始处理第二个缓冲区,没有任何延迟。在处理第二个缓冲区时,第一个缓冲区被并行填充以用于下一个周期。以这种双缓冲方式,您有机会创建流畅的音频播放,而不会出现故障或裂缝。
此外,无论您将执行基于 FIR 还是 IIR 的过滤,您都可以像 FIR 案例一样一次过滤整个缓冲区,或者针对 IIR 案例逐个样本递归地进行过滤。
缓冲区的大小也很重要:因为如果你把它太大,你必须等到两个缓冲区都被填满才能输出任何东西。或者如果你把它们太短,那么系统将被传入的中断淹没。大多数多任务操作系统将无法处理如此高的中断率。缓冲区大小的典型选择可能在 128 到 1024 个样本之间,具体取决于 auido 采样率。