基于Python实现滤波器
- SciPy数值计算
- 11天前
- 52热度
- 0评论
滤波器是一种对信号进行选择性过滤的器件或电路。它由电容、电感和电阻等元件组成,可以滤除信号中特定频率的频点或该频点以外的频率,从而得到一个特定频率的信号,或消除一个特定频率后信号。
滤波器的主要作用是抑制噪声功率、滤除噪声和杂波,使信号变得干净漂亮。它就像是一个美颜相机,能够去除信号中的“瑕疵”,让我们只看到想要的信号成分。
滤波器在通信、音频处理、图像处理等领域都有广泛应用,是信号处理中不可或缺的重要部分。通过选择性地传递或阻止信号中的不同频率成分,滤波器能够帮助我们提取出所需的信号,同时抑制不需要的干扰和噪声
本文将深入探讨几种常见的频率滤波器:低通滤波器、高通滤波器和带通滤波器,并通过软件来实现滤波器功能。
低通滤波器
低通滤波器允许低频信号通过,并抑制高频信号。其核心思想是在频率域上通过移除高频成分来平滑信号。这在去噪、平滑和提取基本频率成分时非常有用。
想象一个筛子,小孔只允许小石子(低频信号)通过,大石子(高频信号)则被挡住。低通滤波器就是这样工作的,它根据信号的频率来决定是否让信号通过。
上图是含有噪声的原始信号,原始信号的频率为5HZ,现在需要编写一个Python滤波程序,过滤掉原始信号的噪声。在设计滤波器时,了解噪声的频率成分对于确定滤波器类型和参数至关重要。当噪声频率未知时,可以通过信号分析来获取这些信息,从而指导滤波器的设计。
首先,我们需要对原始信号进行频域分析,这通常通过计算信号的傅里叶变换来实现
下图是原始信号的频谱图,横轴表示频率,纵轴表示幅度或功率。在频谱图中,任何明显的峰值都可能代表信号中的主要频率成分,包括噪声。在频谱图中,除了信号的主频率成分之外,任何额外的明显峰值都可能是噪声的来源。这些峰值对应的频率即为噪声频率。如果噪声分布在一个较宽的频带上,则表现为连续的背景噪声。
一旦确定了噪声频率,就可以选择适当的滤波器类型来消除这些噪声。分析原始信号的频谱图,信号的主频率成分约为5HZ,噪声频率约为50HZ。因此应设计低通滤波器,允许低频信号通过,高频信号截止。
设计低通滤波器时,要注意截止频率的设置,高于截止频率的信号被阻止,低于截止频率的信号允许通过。
下面给出Python代码实现。
生成原始信号
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import butter, filtfilt
from scipy.fft import fft, fftfreq, ifft
# 生成一个示例信号(包含低频和高频成分)
fs = 500 # 采样频率
# 时间向量
t = np.linspace(0, 1, fs, endpoint=False)
# 5Hz 和 50Hz 的正弦波
signal = np.sin(2 * np.pi * 5 * t) + 0.5 * np.sin(2 * np.pi * 50 * t)
傅里叶变换
# 计算信号的频域表示(傅里叶变换)
frequencies = np.fft.fftfreq(len(t), 1/fs)
fft_signal = np.fft.fft(signal)
fft_signal_magnitude = np.abs(fft_signal) / len(t) # 归一化
# 只取前半部分并乘以2(因为FFT是对称的)
fft_signal_magnitude = fft_signal_magnitude[0:len(t)//2] * 2
绘制时域和频域信号
# 绘制时域信号
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(t, signal)
plt.title('Original Signal')
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
# 绘制频域信号
plt.subplot(2, 1, 2)
plt.plot(frequencies[:len(t)//2], fft_signal_magnitude)
plt.title('Filtered Signal (Low-Pass)')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Amplitude')
plt.xlim(0, fs/2) # 限制频率范围为0到fs/2
plt.tight_layout()
plt.show()
设计低通滤波器
# 设置滤波器的参数
cutoff = 15.0 # 截止频率(Hz)
order = 4 # 滤波器的阶数
# 设计Butterworth低通滤波器
def butter_lowpass(cutoff, fs, order=5):
nyquist = 0.5 * fs
normal_cutoff = cutoff / nyquist
b, a = butter(order, normal_cutoff, btype='low', analog=False)
return b, a
# 滤波函数
def lowpass_filter(data, cutoff, fs, order=5):
b, a = butter_lowpass(cutoff, fs, order=order)
y = filtfilt(b, a, data)
return y
应用低通滤波器
# 应用滤波器
filtered_signal = lowpass_filter(signal, cutoff, fs, order)
绘制原始信号和滤波后的信号
# 绘制原始信号和滤波后的信号
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(t, signal)
plt.title('Original Signal')
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
plt.subplot(2, 1, 2)
plt.plot(t, filtered_signal)
plt.title('Filtered Signal (Low-Pass)')
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
plt.tight_layout()
plt.show()
高通滤波器
高通滤波器就是一个能让高频信号通过,而阻止或减弱低频信号的电子设备或算法。高通滤波器有一个截止频率。在这个频率之下的信号会被减弱或阻止,而在这个频率之上的信号则可以通过。这个截止频率就像是高通滤波器的门槛,只有高于这个门槛的信号才能被允许通过。
基于Python实现的高通滤波器。
import numpy as np
import scipy.signal as signal
import matplotlib.pyplot as plt
# 采样频率和信号时长
fs = 500.0 # 采样频率为500Hz
T = 1.0 # 信号时长为1秒
L = int(T * fs) # 信号长度,即采样点数
t = np.linspace(0, T, L, endpoint=False) # 时间向量
# 生成一个包含低频和高频成分的信号
# 例如:5Hz的正弦波(低频成分)和50Hz的正弦波(高频成分)
osignal = np.sin(2 * np.pi * 5 * t) + 0.5 * np.sin(2 * np.pi * 50 * t)
# 设计高通滤波器
# 设定截止频率为15Hz(这个值可以根据需要调整)
cutoff = 15.0
nyquist = 0.5 * fs # 奈奎斯特频率(采样频率的一半)
normal_cutoff = cutoff / nyquist # 归一化截止频率
order = 4 # 滤波器阶数(可以根据需要调整)
# 使用butter函数设计高通IIR滤波器
# b, a是滤波器的分子(numerator)和分母(denominator)系数
b, a = signal.butter(order, normal_cutoff, btype='high', analog=False)
# 应用滤波器到信号上
# 使用lfilter进行滤波会产生相位失真,因为它只进行前向滤波
# 使用filtfilt进行零相位滤波,它会先正向滤波再反向滤波,从而消除相位失真
filtered_signal = signal.filtfilt(b, a, osignal)
# 绘制原始信号和滤波后的信号
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(t, osignal)
plt.title('Original Signal')
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
plt.subplot(2, 1, 2)
plt.plot(t, filtered_signal)
plt.title('Filtered Signal')
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
plt.tight_layout()
plt.show()
从运行结果可以看出,低于截止频率(15Hz)的成分应该被显著减弱或去除,而高于截止频率的成分(如50Hz)则相对保留。
带通滤波器
带通滤波器是指能通过某一频率范围内的频率分量,但将其他范围的频率分量衰减到极低水平的滤波器。
下面使用 SciPy 的 butter, filtfilt 等函数来实现一个巴特沃斯滤波器带通滤波器。并生成一个包含噪声的信号,然后应用滤波器来去除噪声。
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import butter, filtfilt
# 生成一个包含噪声的信号
def generate_signal(freq, sample_rate, duration, noise_level=0.5):
t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
signal = np.sin(2 * np.pi * freq * t) # 正弦波信号
noise = noise_level * np.random.normal(size=t.shape) # 高斯噪声
noisy_signal = signal + noise
return t, signal, noisy_signal
# 设计 Butterworth 带通滤波器
def butter_bandpass(lowcut, highcut, fs, order=5):
nyquist = 0.5 * fs
low = lowcut / nyquist
high = highcut / nyquist
b, a = butter(order, [low, high], btype='band')
return b, a
# 应用滤波器
def bandpass_filter(data, lowcut, highcut, fs, order=5):
b, a = butter_bandpass(lowcut, highcut, fs, order=order)
y = filtfilt(b, a, data)
return y
# 参数设置
sample_rate = 500 # 采样率
duration = 1.0 # 信号持续时间(秒)
freq = 50 # 信号频率(Hz)
lowcut = 45 # 带通滤波器低截止频率(Hz)
highcut = 55 # 带通滤波器高截止频率(Hz)
# 生成信号
t, signal, noisy_signal = generate_signal(freq, sample_rate, duration)
# 应用滤波器
filtered_signal = bandpass_filter(noisy_signal, lowcut, highcut, sample_rate)
# 绘制结果
plt.figure(figsize=(10, 6))
plt.subplot(3, 1, 1)
plt.plot(t, signal, label='Original Signal')
plt.title('Original Signal')
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
plt.legend()
plt.subplot(3, 1, 2)
plt.plot(t, noisy_signal, label='Noisy Signal', color='orange')
plt.title('Noisy Signal')
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
plt.legend()
plt.subplot(3, 1, 3)
plt.plot(t, filtered_signal, label='Filtered Signal', color='green')
plt.title('Filtered Signal')
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
plt.legend()
plt.tight_layout()
plt.show()
代码解释
(1)生成信号:
generate_signal 函数生成一个包含噪声的正弦波信号。
freq 是信号的频率,sample_rate 是采样率,duration 是信号的持续时间,noise_level 是噪声的幅度。
(2)设计滤波器:
butter_bandpass 函数设计了一个 Butterworth 带通滤波器。
lowcut 和 highcut 是滤波器的低截止频率和高截止频率,fs 是采样率,order 是滤波器的阶数。
(3)应用滤波器:
bandpass_filter 函数使用 filtfilt 函数对信号进行双向滤波,以消除相位失真。
(4)输出结果:
使用 Matplotlib 绘制原始信号、带噪声的信号和滤波后的信号。
运行这段代码后,你将看到三个子图,分别显示原始信号、带噪声的信号和滤波后的信号。滤波后的信号应该比带噪声的信号更加平滑,并且更接近原始信号。