我有一些信号每1 ns(1e-9 sec)采样一次,并且有1e4点。我需要从该信号中滤除高频。假设我需要过滤高于10 MHz的频率。我希望对于低于截止频率的频率,信号将保持不变。这意味着对于低于截止频率的频率,滤波器的增益将为1。我希望能够指定过滤器顺序。我的意思是,一阶滤波器在截止频率后具有20 db / dec的斜率(功率下降),二阶滤波器在截止频率后具有40 db / dec的斜率,依此类推。代码的高性能很重要。

#1 楼

使用黄油功能设计的滤波器的频率响应为:



,但是没有理由将滤波器限制为恒定的单调性
过滤器设计。如果您希望阻带
具有更高的衰减并且过渡带更加陡峭,则可以使用其他选项。有关使用iirdesing指定过滤器的更多信息,请参见此。如黄油的频率响应图所示,截止频率(-3dB点)离目标还很远。可以通过在过滤之前进行下采样来缓解此问题(使用这样的窄滤波器(带宽的2%),设计功能将很难解决)。让我们看一下使用指定的截止值过滤原始样本的速度。

import numpy as np
from scipy import signal
from matplotlib import pyplot as plt

from scipy.signal import fir_filter_design as ffd
from scipy.signal import filter_design as ifd

# setup some of the required parameters
Fs = 1e9           # sample-rate defined in the question, down-sampled

# remez (fir) design arguements
Fpass = 10e6       # passband edge
Fstop = 11.1e6     # stopband edge, transition band 100kHz
Wp = Fpass/(Fs)    # pass normalized frequency
Ws = Fstop/(Fs)    # stop normalized frequency

# iirdesign agruements
Wip = (Fpass)/(Fs/2)
Wis = (Fstop+1e6)/(Fs/2)
Rp = 1             # passband ripple
As = 42            # stopband attenuation

# Create a FIR filter, the remez function takes a list of 
# "bands" and the amplitude for each band.
taps = 4096
br = ffd.remez(taps, [0, Wp, Ws, .5], [1,0], maxiter=10000) 

# The iirdesign takes passband, stopband, passband ripple, 
# and stop attenuation.
bc, ac = ifd.iirdesign(Wip, Wis, Rp, As, ftype='ellip')  
bb, ab = ifd.iirdesign(Wip, Wis, Rp, As, ftype='cheby2') 




如上所述,因为我们正在尝试要过滤这么小的带宽
,过滤器将不会有明显的截止。在这种情况下,低通滤波器可以减小带宽以获得更好的外观。可以使用python / scipy.signal重采样功能来减少带宽。

请注意,重采样功能将执行过滤以防止
混叠。也可以进行预过滤(以减少混叠)
,在这种情况下,我们可以简单地按100重新采样并完成,但是
有关创建过滤器的问题问了。对于此示例,我们将降低25采样率并创建一个新的滤波器

R = 25;            # how much to down sample by
Fsr = Fs/25.       # down-sampled sample rate
xs = signal.resample(x, len(x)/25.)


如果我们更新FIR滤波器的设计参数,则


# Down sampled version, create new filter and plot spectrum
R = 25.             # how much to down sample by
Fsr = Fs/R          # down-sampled sample rate
Fstop = 11.1e6      # modified stopband
Wp = Fpass/(Fsr)    # pass normalized frequency
Ws = Fstop/(Fsr)    # stop normalized frequency
taps = 256
br = ffd.remez(taps, [0, Wp, Ws, .5], [1,0], maxiter=10000) 




对下采样数据进行操作的过滤器具有更好的响应。使用FIR滤波器的另一个好处是您
将具有线性相位响应。

评论


$ \ begingroup $
谢谢。如何创建信号频谱图?
$ \ endgroup $
– Alex
12年7月12日在11:39

$ \ begingroup $
非常感谢您的出色回答!我想知道您是否可以解释如何根据使用Remez计算的系数来应用FIR滤波器?我在理解filtfilt想要a参数时遇到麻烦。
$ \ endgroup $
–ali_m
13年5月19日在22:40

$ \ begingroup $
一旦获得了滤波器设计的系数(b代表FIR,b代表IIR),则可以使用几个不同的函数来执行滤波:lfilter,convolve,filtfilt。通常,所有这些函数的工作方式相似:y = filtfilt(b,a,x)如果您具有FIR滤波器,只需将a = 1设置为x,则x为输入信号,b为FIR系数。这篇文章可能也有帮助。
$ \ endgroup $
–克里斯托弗·费尔顿(Christopher Felton)
13年5月24日在12:58

#2 楼

这行得通吗?

from __future__ import division
from scipy.signal import butter, lfilter

fs = 1E9 # 1 ns -> 1 GHz
cutoff = 10E6 # 10 MHz
B, A = butter(1, cutoff / (fs / 2), btype='low') # 1st order Butterworth low-pass
filtered_signal = lfilter(B, A, signal, axis=0)


没错,但是文档不是很完整。看起来butteriirfilter的包装,更好地记录在案:


N:int
过滤器的顺序。
Wn:array_like
给出临界频率的标量或长度为2的序列。


大多数东西都是从matlab克隆的,因此您也可以查看它们的文档:


归一化截止频率Wn必须为0到1之间的数字,其中1对应于奈奎斯特频率,每个样本π弧度。


更新:

我添加了这些功能的文档。 :) Github变得很容易。

#3 楼

不确定您的应用程序是什么,但是您可能要查看Gnuradio:http://gnuradio.org/doc/doxygen/classgr__firdes.html

信号处理模块是用C ++编写的(尽管Gnuradio流程图在Python中),但您确实说过高性能很重要。

#4 楼

这个FIR滤波器的效果很好。请注意,它两次应用了滤波器,分别进行“正向”和“反向”,以补偿信号偏移(filtfilt功能无效,不知道为什么):

def firfilt(interval, freq, sampling_rate):
    nfreq = freq/(0.5*sampling_rate)
    taps =  sampling_rate + 1
    a = 1
    b = scipy.signal.firwin(taps, cutoff=nfreq)
    firstpass = scipy.signal.lfilter(b, a, interval)
    secondpass = scipy.signal.lfilter(b, a, firstpass[::-1])[::-1]
    return secondpass


这是我设计此代码的源泉,以及可以通过带通和高通滤波器示例的滤波器设计和使用的绝佳资源。

评论


$ \ begingroup $
我认为对FIR滤波器进行正向和反向滤波没有太大好处。 IIR滤波器可以从正向/反向(filtfilt)中受益,因为您可以通过反向滤波从非线性相位滤波器中获得线性相位。
$ \ endgroup $
–克里斯托弗·费尔顿(Christopher Felton)
2012年7月12日下午5:14

$ \ begingroup $
@ChristopherFelton为了使RAW肌电信号与平滑后的信号同步,我只是反转了一下。我知道我可以移动信号,但是两次滤波可以减少麻烦。值得注意的是,第二遍几乎不会更改已过滤的第一遍...谢谢!
$ \ endgroup $
– heltonbiker
2012年7月12日13:21

$ \ begingroup $
啊,是的。要消除延迟(群延迟),要点。
$ \ endgroup $
–克里斯托弗·费尔顿(Christopher Felton)
2012年7月12日在17:32

#5 楼

我没有评论权...

@endolith:除了使用scipy.signal.filtfilt(B,A,x)(其中x是要过滤的输入向量)之外,我使用的其他用法与您相同-例如numpy.random.normal(size =(N))。 filtfilt对信号进行正向和反向传递。为了完整起见(大多数与@endolith相同):@heltonbiker也建议使用filtfilt,我相信它需要系数数组。如果需要在复杂的基带上执行带通滤波,则需要更复杂的配置,但这在这里似乎不是问题。