
简介面向MATLAB信号处理初学者与工程开发者的滤波器设计学习包系统讲解低通、高通、带通、带阻四类滤波器的设计原理、参数定义与实现步骤。压缩包共3个文件整体约53MB包含MATLAB脚本.m提供滤波器设计核心代码WMV格式实操录屏演示利用fdatool完成滤波器的设计、导出与应用全流程另附RAR资料包用于集中管理示例工程与参考文档。已有468人学习浏览适合希望快速上手滤波器设计、打通理论到代码落地的读者。通过脚本可了解窗口法、切比雪夫型、椭圆函数型等常见设计方法的实现差异结合录屏可掌握截止频率、过渡带、阻带衰减等关键参数的设定技巧以及filter、freqz等函数在信号去噪和频段提取中的实际用法辅助读者在自身信号处理项目中灵活选用合适的滤波器。1. 基于MATLAB做滤波器设计先定指标后谈算法很多人在MATLAB里做滤波器设计卡住的不是不会用函数而是把起点放错了。接到需求后第一件事不应该是问“用FIR还是IIR”而应该是问采样率多少、通带边界多少Hz、阻带边界多少Hz、通带纹波和阻带衰减要求多少。这四个数值一出来滤波器阶数、设计工具、甚至Simulink里的仿真步长都会被逼着确定下来。这篇文章围绕基于MATLAB的滤波器设计完整链路展开从归一化频率计算、fir1和butter等核心函数的参数含义到freqz验证、Simulink测试台搭建以及最后系数定点化和零相位滤波这些容易忽略的工程点按一条可直接复制的路径走通。适合通信、语音、测控、电源控制以及靠MATLAB交仿真作业的读者新手能照步骤跑通熟手可以跳过基础命令直接看参数陷阱。2. 基于MATLAB的FIR滤波器设计最小可复现路径与参数陷阱2.1 FIR低通滤波器的最小命令fir1与归一化频率计算把需求转换成代码的第一步是把所有频率先换算成以奈奎斯特频率fs/2为基准的归一化频率。MATLAB里fir1、butter、cheby1这些设计函数接收的都不是Hz而是0到1之间的归一化数值。以采样率12000 Hz、通带边界1500 Hz、阻带起始2000 Hz的低通设计为例最干净的命令行写法是这样的fs 12000; % 采样率 12 kHz fp 1500; % 通带边界 1500 Hz fa 2000; % 阻带起始 2000 Hz fc (fp fa) / 2; % 6dB 截止位置fir1 实际使用的频点 Wn fc / (fs / 2); % 归一化频率除以奈奎斯特频率 N 64; % 滤波器阶数系数个数是 N1 b fir1(N, Wn, low); % 设计低通 FIR结果存在 b 中这个例子里最容易被忽略的是fc的取法。fir1的Wn参数定义为幅度下降6 dB的位置不是通带边缘。直接填fp/(fs/2)会让1500 Hz处已经掉到-3 dB以下看上去过渡带起点比预期偏早。工程上一般取(fpfa)/2作为过渡带中心让通带边缘保住平坦区阻带从2000 Hz开始进入衰减。N的值也不是越大越好。N太大系数长度变长卷积计算量线性上升在实时系统里会直接吃掉CPU。先用一个经验公式估起点N ≈ (-20*log10(sqrt(δp*δs)) - 13) / (14.6 * (fa-fp)/fs)其中δp和δs分别是通带和阻带的纹波线性值。对本例来说过渡带500 Hz、阻带衰减60 dB估算结果落在60到90之间从64开始试是合理的。若freqz看下来衰减裕量不够再向上加10阶左右即可。提示fir1返回的系数总和接近1但不是严格等于1。做低通时还好做高通或带通时受窗函数影响会有小幅增益偏差作为控制输出或信号发生器增益标定时建议先看sum(b)再决定是否补增益校正。2.2 用freqz验证FIR设计结果看幅度、看相位、看群延迟设计完不能只看一条幅频曲线。freqz是验证滤波器设计最直接的函数一次画出幅度和相位两张图还可以通过grpdelay单独看群延迟是否恒定。freqz(b, 1, 1024, fs); % b 是分子系数1 表示无分母1024 是频响点数freqz的第二个参数填1表示这个数字滤波器没有反馈项即全零点FIR结构。第三个参数1024是频响计算点数点数越多频率轴越光滑但拐点附近的采样间隔也越细。最后一个参数fs可填可不填不填时横轴是归一化频率0到1填了则显示为实际Hz更适合对着指标核对。从这个例子的频响图上应该看到两种结果1500 Hz之前幅度接近0 dB2000 Hz之后衰减超过40 dB过渡带从1500到2000 Hz这一段没有明显过冲。如果衰减不够优先加阶数如果过渡带太宽但阶数已经很大要考虑改用firls或filterDesigner里的等波纹设计而不是继续堆N。FIR的线性相位特性也要在这个环节确认。fir1默认使用汉明窗设计结果满足线性相位群延迟恒定为N/2个采样点。但如果后面手动修改了系数、做了圆整或者截断了某个抽头这一特性会被破坏。验证时跑一下grpdelay(b, 1, 512, fs)如果群延迟变成一条上下波动的曲线而不是平坦直线就要回去检查系数对称性。2.3 从firls到filterDesignerFIR设计函数选型与任意幅频响应实际项目里FIR设计很少是一个fir1走到底。fir2可以设计任意形状的幅频响应firls可以做带误差权重的频段拟合filterDesigner则适合在界面上反复试参数。四个工具的分工关系如下函数/工具适用场景需要提供的参数常见坑fir1标准低通/高通/带通/带阻N、Wn、窗类型过渡带宽度不可控fir2任意形状频响、多段折线幅频N、f点数组、m幅度数组f必须严格递增且末端为1firls频段加权最小二乘拟合N、f数组、a数组、w权重频率点数必须是偶数filterDesigner交互式试参、导出Simulink模块界面表单改完参数忘记重新生成举一个firls的典型场景信号里存在一个约1800 Hz的窄带干扰但希望保留1500 Hz以下和2100 Hz以上的内容。如果用fir1设计带阻过渡带宽度不受控会把有用频段边缘也削掉。改用firls直接指定几个关键频点和目标幅度N 100; f [0 0.24 0.26 0.34 0.36 1]; % 归一化频点对应约 0/1440/1560/2040/2160 Hz a [1 1 0 0 1 1]; % 目标幅度1440 Hz 前保留1560~2040 Hz 抑制 b firls(N, f, a);f数组必须是从0开始、以1结束的严格递增序列a数组长度与f相同给出每个频点上的目标幅度。两个相邻频点之间就是实际上的过渡带。firls设计出来的滤波器在通带和阻带都有等波纹特性阻带衰减不一定特别深但对指定频段的幅频拟合更精准。设计完同样用freqz验证不要因为函数名字里带least-squares就默认结果一定收敛。2.4 阶数估算与批量扫描先给N一个合理起点阶数估算公式只能给出一个粗略起点碰到特殊指标时还是要扫一遍。把设计过程包成一个for循环从低阶到高阶逐个算阻带衰减找到第一个满足指标的值Rs_target 60; % 目标阻带衰减 60 dB for N_test 20: 2: 120 b_test fir1(N_test, Wn, low); [h, w] freqz(b_test, 1, 8192, fs); idx find(w fa, 1); % 取阻带起始点之后的最小值 Rs_now -20*log10(max(abs(h(idx:end)))); if Rs_now Rs_target N N_test; break; end end这段代码从20阶开始以2为步长向上扫描每次看阻带范围内的最大旁瓣是否已经压到目标以下。freqz返回的h是复数频率响应abs取幅度-20*log10转成dB。扫到第一个满足条件的N后break后续再用这个N重新设计一次即可。这种批处理方式比单次试凑更可控也方便把指标写成可配置参数换一个采样率就能复用。3. 基于MATLAB的IIR滤波器设计阶数、SOS结构与落地写法3.1 四种原型怎么选butter、cheby1、cheby2、ellip的适用边界IIR滤波器的设计思路是先选定模拟原型滤波器再通过双线性变换映射到数字域。MATLAB把原型创建、频率变换、离散化全部封装进一个函数调用所以butter一行就能返回数字滤波器系数但设计者必须知道自己选的是哪种原型。四种原型的差异集中在通带平坦度、过渡带宽度、阻带衰减和阶数四个维度上取舍关系很明确函数通带特性阻带特性同指标下阶数典型场景butter最大平坦单调衰减最高测量通道、对纹波敏感的系统cheby1通带等波纹单调衰减中等对通带纹波容忍度较高的场景cheby2通带平坦阻带等波纹中等通带要求平坦、阻带允许纹波ellip通带等波纹阻带等波纹最低嵌入式、存储和算力受限工程选型通常先看这个指标能不能接受通带内允许最大纹波多少dB。如果要求通带绝对平坦只能选butter代价是过渡带最宽如果只是不想让相位问题更严重而幅频纹波能容忍ellip可以用最低阶数达到最窄过渡带。ellip的代价是相位非线性更剧烈在需要保留波形形态的应用里要掂量。3.2 用buttord先求阶数再用butter设计参数对应关系很多教材直接写butter(10, Wn)这在工程里不够稳。10阶是否满足60 dB衰减取决于过渡带相对于采样率的宽度。稳妥的做法是先让MATLAB用buttord估算最小阶数再根据返回值设计。fs 40000; % 采样率 40 kHz fp 8000; % 通带边缘 8 kHz fa 10000; % 阻带起始 10 kHz Rp 0.5; % 通带纹波 0.5 dB Rs 60; % 阻带衰减 60 dB Wp fp / (fs / 2); % 通带归一化频率0.4 Ws fa / (fs / 2); % 阻带归一化频率0.5 [n, Wn] buttord(Wp, Ws, Rp, Rs); % n 是最小阶数Wn 是实际截止频点 [b, a] butter(n, Wn); % 得到直接型 IIR 系数buttord的第一个输出n是满足纹波和衰减指标所需的最小阶数第二个输出Wn是实际投入设计用的截止频率。Wn通常比Wp略大一点这是给过渡带留的余量。如果直接把butter(n, Wp)拿来用通带边缘会更早下跌指标看起来满足实际有效带宽却变窄了。这个例子里fp8000、fa10000、fs40000归一化过渡带宽度只有0.1对IIR来说算相当紧凑。如果buttord返回的阶数超过20说明指标给得太紧应该回头检查阻带起始频率是否真的需要设在10 kHz或者换成ellip降低阶数。设计完成后用freqz(b, a, 4096, fs)核查频响。与FIR不同IIR的相位曲线必然非线性验证重点是通带纹波是否低于0.5 dB、阻带是否压到-60 dB以下。若Rs刚好卡在60 dB建议把Rs多留3到5 dB余量后面做系数量化或者转C代码时还会再劣化几个dB。3.3 直接型系数不能直接上机tf转SOS与极零点分析[b,a]这种分子分母多项式形式在MATLAB浮点仿真里能用但放到定点仿真、C代码或者Verilog实现里很容易出问题。高阶IIR的极点聚集在单位圆附近直接型结构对系数量化误差极其敏感轻微的舍入就可能把极点推到单位圆外导致滤波器自激振荡。[sos, g] tf2sos(b, a); % 拆成二阶分段级联结构 zplane(b, a); % 查看零极点位置tf2sos返回的sos是一个L行6列的矩阵每行是[b0 b1 b2 1 a1 a2]表示一个二阶节g是整条链的增益。把高阶IIR拆成多个二阶节级联后每一级的极点都更容易控制在单位圆内数值稳定性好得多。ellip设计的滤波器尤其要转SOS因为它极点更靠近单位圆。zplane可以直观看到零极点分布。IIR滤波器的极点必须全部落在单位圆内这是系统稳定的充要条件。如果设计出的系数出现极点在单位圆上几乎可以断定是数值问题或者是把归一化频率算错了。用zplane看完后还要顺手确认滤波器的阶数是否合理IIR阶数超过30的场合极少见一旦遇到就要怀疑设计指标本身有矛盾。4. 基于Simulink的滤波器仿真从系数到模块的完整链路4.1 从filterDesigner导出滤波器到Simulink两种路径滤波器在MATLAB里设计完成后仿真验证经常要放到Simulink里因为它要带着电机模型、通信接收链路或者控制系统一起跑。filterDesigner旧版本叫fdatool提供两种导出路径。第一种是界面上的File - Export... - Export to Simulink ModelMATLAB会自动生成一个Simulink模型并把滤波器模块放进去。这条路径适合快速看波形缺点是模型里的模块是黑盒参数修改要回到GUI重来一遍。第二种是把系数先导出到MATLAB工作空间再手动配置Simulink里的Discrete Filter模块。这种方式更透明换参数时只需要重新跑一遍设计脚本Simulink模型不用改。实际工程里我更倾向于第二种配合脚本批量试参数时不需要反复打开GUI。filterDesigner; % 打开交互式设计界面在GUI里完成设计后选择File - Export将系数导出为变量。FIR滤波器导出的是分子系数bIIR滤波器导出的是SOS矩阵和增益g也可以选择导出成直接型的Numerator和Denominator。导出的变量会出现在工作空间里作为下一步Simulink模块填参数的数据源。4.2 在Simulink里搭最小测试台信号源、离散滤波器和显示器继续沿用第2章的低通例子fs12000 Hz、fp1500 Hz、fa2000 Hz用来滤除4 kHz的带外干扰。Simulink模型里只需要四个模块Sine Wave、Discrete Filter、Scope和To Workspace。模块参数位置配置值说明Sine WaveSample time1/(fs*10)源信号步长设细避免混叠Sine WaveFrequency2pi1000有用信号 1 kHzDiscrete FilterNumeratormat2str(b)手工粘贴时用空格分隔Discrete FilterSample time1/fs必须与滤波器采样率一致To WorkspaceSave formatTimeseries便于导出后做FFT分析Sine Wave模块的采样时间不要直接设成1/fs。在Simulink里连续信号经过离散滤波器时默认会按后者的采样时间采样但如果源信号步长比滤波器采样率还粗4 kHz干扰会混叠到低频段滤波结果会莫名出现低频包络。先把源信号步长设成1/(fs*10)再用Rate Transition块转到1/fs能避免这类假性失真。Discrete Filter模块的Numerator和Denominator字段接受字符串形式的系数。从工作空间填数时可以直接写mat2str(b)如果是IIR的SOS形式需要先把每个二阶节的系数依次展开再拼接或者用一个预处理脚本把SOS矩阵转换成直接型系数后再填入。注意Discrete Filter模块的系数不支持矩阵形式。FIR滤波器分子填行向量、分母填1IIR滤波器如果填入SOS矩阵模块会报错需要先展开或者选择Discrete Transfer Fcn模块分段级联。4.3 配置仿真参数与导出结果避免步长和类型错误模型搭好后打开Configuration Parameters把Solver改成离散求解器最大步长设到Ts/4以下。对包含连续源和离散滤波器的混合模型来说这一步能避免求解器在离散采样点之间插入不必要的连续求解步骤防止仿真变慢以及波形尖刺。仿真结束后To Workspace导出的数据是一个timeseries对象。用下面这段代码在MATLAB里对滤波器输出做频谱验证确认阻带成分确实被压下去了y out.y.Data; % 取出离散输出序列 L length(y); Y fft(y); f (0: L-1) * (fs / L); % 构造频率轴 plot(f(1: L/2), 20*log10(abs(Y(1: L/2)))); xlabel(Frequency (Hz)); ylabel(Magnitude (dB));fft结果的频率分辨率是fs/L如果y太短频率轴上4000 Hz附近可能只有一个点干扰的残余幅度会被低估。验证阻带衰减时建议把仿真时间拉长到1秒以上或者用nextpow2扩展FFT点数再做幅频图。两种情况对应两种结论短时长的曲线只适合看启动瞬态长时长的曲线才适合看稳态频谱。5. 滤波器设计结果的高级处理系数定点化与零相位滤波5.1 系数量化对频响的影响滤波器从MATLAB走向DSP或FPGA时浮点系数必须量化成定点数。调试时最典型的现象是频响在预期之外出现缓慢的起伏MATLAB里设计结果很理想上板之后阻带多了几个dB的鼓包或者带通边缘出现额外的波纹。原因往往是某个高阶节或者Q值较高的二阶节对系数量化过于敏感。filterDesigner界面顶部的量化按钮可以直接把系数量化成16位或24位量化后频响曲线会重新绘制与浮点结果并排对比。IIR比FIR敏感得多特别是ellip设计的高Q值节位宽不足时极点偏移明显。观察量化后频响时至少要保证阻带衰减比指标低3 dB以上否则就要提升位宽或者改用SOS结构重新设计。5.2 用filtfilt消除相位失真对于离线数据处理比如传感器标定、语音标注、测试仪器后端滤波器设计完成后可以用filtfilt代替filter执行滤波用非实时性换取零相位失真。y filtfilt(b, a, x); % 正向滤波后再反向滤波群延迟为零filtfilt会把数据先正向通过滤波器再把结果反向通过一次两个方向的相位失真相互抵消。代价是信号不能实时处理且数据首尾各有一小段因为延拓引起的过渡失真。数据足够长、关心稳态幅频特征的场景下这一句命令带来的收益非常明显。调试时我会把filter和filtfilt的输出对比如果两者幅度谱一致而时域波形只是相位不同说明滤波器数值上没有异常只是应用方式选择问题。5.3 用批量脚本和优化思路找最优指标滤波器设计常常不是一次到位的。把设计过程封装成函数让采样率和边界频率成为输入参数然后批量扫描阶数、通带纹波和阻带衰减的组合能省掉大量手工试参时间。这个思路其实是把前面各章的命令行参数集中到一个脚本里每次只改需求边界不做重复劳动。以FIR为例可以按阻带衰减从低到高扫描记录每个设计结果的实际过渡带宽度直到找到满足系统约束的最短阶数。扫描范围更大时还能在MATLAB优化工具箱里用fminsearch或fmincon包一层让优化器在通带纹波、阶数、阻带衰减三个变量之间找一个均衡解。但大多数滤波器指标只有三个频率点和一个衰减量线性扫描已经足够不值得为了自动化而把简单问题复杂化。做成函数后不同项目复用只改采样率和边界频率即可。本文还有配套的精品资源点击获取