使用scipy.signal.decimate(ftype='fir')出现振荡,如何匹配Matlab结果?
Matlab与Scipy decimate(FIR模式)结果差异的原因及解决方案
问题重现
Matlab代码(v2019b)
artest = 1:109; artestd = decimate(artest, 2, 'fir'); artestd(40:end)
输出末尾为连续奇数:79.0000 至 109.0000
Python代码(3.9.12,scipy 1.7.3)
import numpy as np from scipy import signal as sg artest = np.arange(1,110) artestd = sg.decimate(artest, 2, ftype='fir') artestd[39:]
输出末尾出现振荡:[79.0, 81.0,...114.35633594, 81.63376904]
差异原因分析
两者结果差异的核心在于滤波器设计参数、边缘处理逻辑的不同:
- 滤波器规格不匹配:
- Matlab的
decimate(A,2,'fir')默认使用30阶凯泽窗FIR滤波器(β=5),截止频率为归一化的0.25(对应下采样因子2的奈奎斯特频率的一半)。 - Scipy的
sg.decimate默认使用20阶凯泽窗FIR滤波器,且滤波采用单向的lfilter,未做延迟补偿。
- Matlab的
- 边缘处理方式差异:
- Matlab在处理FIR滤波时,会自动处理边界延迟,且滤波器阶数更高,通带内信号失真极小,下采样后能完整保留原信号的奇数点序列。
- Scipy默认用
lfilter做单向滤波,信号末尾采用零填充,当滤波器窗口无法覆盖足够样本时,会触发吉布斯振荡(边缘效应),导致末尾结果失真。
解决方案
要让Python输出与Matlab完全一致,需手动匹配Matlab的滤波器参数与处理流程:
import numpy as np from scipy import signal as sg # 1. 匹配Matlab的FIR滤波器参数:30阶凯泽窗(β=5),截止频率0.25 order = 30 cutoff = 1 / (2 * 2) # 下采样因子为2,截止频率=1/(2*subsample) window = sg.kaiser(order + 1, 5) b = sg.fir1(order, cutoff, window=window) artest = np.arange(1, 110) # 2. 使用filtfilt双向滤波,消除延迟与边缘振荡 filtered_signal = sg.filtfilt(b, [1], artest) # 3. 下采样取偶数索引(对应Matlab的1-based奇数位置) artestd = filtered_signal[::2] print(artestd[39:])
运行后输出末尾将与Matlab一致:[79.0, 81.0, ..., 109.0]
内容的提问来源于stack exchange,提问作者Warren Lewis
相关产品推荐
相关产品推荐

