概要
FIR 即有限脉冲响应(finite impulse response),它对应着无限脉冲响应。一般在现实生活中,由于数字方法处理信号时,不可能对无限长的信号进行测量和运算,而是取其有限的时间片段进行分析。能够做到的是用窗函数截断出近似的信号进行处理,或者对信号时间片段进行周期延拓等等方法。
FIR滤波器的特点:FIR 滤波器可以得到严格的线性相位,但它的传递函数的极点固定在原点,只能通过改变零点位置来改变性能
FIR 滤波器的设计方法主要有三种:窗函数法、频率抽样法和切比雪夫逼近方法。窗函数法较为简单易行,本次作业就窗函数设计的角度展开。
窗函数的“窗”指的是频谱上窗型的频率响应,在频域上有限宽度的窗,经过离散傅里叶反变换后,在时域上就是无限长的序列。不同形状的窗函数的滤波性能也不同,不仅取决于级数,还与因果与非因果等因素有关。
作业中的代码和演示在 Jupyter Notebook 中完成。
In this project, with some previous Python programming experiences, I basically learned:
How to complete basic tasks of data processing with fundamental python packages. (numpy, scipy, etc.)
How to design digital FIR filters with different module of FIRs.
The difference between 2 methods of signal filtering encapsuled within scipy.signal package.
How to read, extract and process data from wfdb-python package, which is an open source ECG dataset.
本编
首先调用所需的 Python 库:
import numpy as np
import scipy.signal as signal
import matplotlib.pyplot as plt
import wfdb
from matplotlib.font_manager import FontProperties
myfont = FontProperties(fname=r'C:/Windows/Fonts/msyh.ttf')
# set default size of plots
plt.rcParams['figure.figsize'] = (15, 4)
理想窗函数滤波器
理想窗函数的频响如图,频谱在通带和阻带之间直接截断,没有过渡带,如果是一个非因果的双边滤波器,则他的时域响应是一个离散的升余弦函数:
$$h_{ideal}[n] = \frac{\sin(2 \pi f_c)}{\pi n} = 2f_c sinc(2f_c n)$$
而一个因果的单边理想窗函数 LPF 的频响示意图如下:
接下来用理论的时域响应函数通过FFT得到因果和非因果窗函数各自的频响:
#one side signal (karma)
def sinc_n(M, fc):
return 2 * fc * np.sinc(2 * fc * np.arange(0, M, 1.0))
#two side signal (non-karma)
def sincdouble_n(M, fc):
return 2 * fc * np.sinc(2 * fc * np.arange(-M, M, 1.0))
def sinc_freqz(b, title, semilogx = False, showpart = False):
'''
calculate Z transform.
Cut-out in time domain signal cause side lobes in Frequency Responce'''
w, h = signal.freqz(b)
h_dB = 20 * np.log10(abs(h))
f = w / (np.pi) #regularize frequncy to be between 0 and 1
plt.rcParams['figure.figsize'] = (15, 4)
if showpart == False: plt.subplot(122)
# select plot mode: log space or linear space
if semilogx == True:
plt.semilogx(f, h_dB)
else:
plt.plot(f, h_dB)
plt.plot([0, 1], [-21, -21], 'k--', LineWidth = 1.0)
plt.text(0.26, -21, 'MSB of sinc double = -21 dB', fontdict={'size': 16})
plt.xlabel('$\omega$')
plt.ylabel('$H (dB)$')
# if compare between different sample number
if showpart == False: