gr-filter 滤波与多速率模块完整源码分析
1. gr-filter 整体定位与功能分类
定位
gr-filter是 GNU Radio 的滤波与采样率变换核心包,负责:
- FIR/IIR 滤波
- 抽取/插值/有理数/任意比率重采样
- 多相滤波器组(PFB)信道化
- 滤波器系数设计(
firdes) - 通信专用成形滤波(RRC、高斯)
依赖
gnuradio-runtime → 块基类、调度 gr-fft → FFT 加速滤波、窗函数 gr-blocks → 部分辅助块 Volk → SIMD 卷积功能分类(GRC 树)
| 类别 | 代表块 | 流程作用 |
|---|---|---|
| FIR/IIR 滤波 | fir_filter_xxx、iir_filter_xxx、fft_filter_xxx | 抗混叠、信道选择、音频 LPF |
| 多速率 | interp_fir_filter、rational_resampler、pfb_arb_resampler | 改变采样率 |
| PFB 架构 | pfb_channelizer、pfb_decimator/interpolator、pfb_synthesizer | 高效多信道、多相抽取/插值 |
| 频移+滤波 | freq_xlating_fir_filter、freq_xlating_fft_filter | 下变频+滤波一体 |
| 系数设计 | firdes、optfir、pm_remez | 离线/在线生成 taps |
| 通信成形 | root_raised_cosine_filter、RRC/Gaussian taps | 脉冲成形、匹配滤波 |
| 简单滤波 | dc_blocker、single_pole_iir、low_pass_filter | DC 消除、一阶平滑 |
| 其他 | hilbert_fc、filterbank、mmse_resampler | 希尔伯特变换、滤波器组、分数插值 |
源码结构
gr-filter/ ├── include/gnuradio/filter/ # API + kernel 类(fir_filter, fft_filter, pfb_*) ├── lib/ # *_impl.cc + firdes.cc + pm_remez.cc ├── python/filter/ # PyBind11 + optfir.py + pfb.py └── grc/ # GRC 块定义接口调用(总入口)
fromgnuradioimportfilter,gr,fft# 设计系数taps=filter.firdes.low_pass(gain=1.0,sampling_freq=fs,cutoff_freq=fc,transition_width=tw,window=fft.window.WIN_HAMMING)# 使用滤波器lpf=filter.fir_filter_fff(1,taps)# decim=1 普通 FIRtb.connect(src,lpf,dst)2. FIR/IIR 滤波器底层源码实现
2.1 FIR 核心公式
离散卷积(FIR):
[
y[n] = \sum_{k=0}^{N-1} h[k] \cdot x[n-k]
]
传递函数:(H(z) = \sum_{k=0}^{N-1} h[k] z^{-k})
2.2 FIR 架构:Kernel + Block 两层
Kernel 类(include/gnuradio/filter/fir_filter.h):纯算法,可被多块复用。
OUT_T filter(const IN_T input[]) const; void filterN(OUT_T output[], const IN_T input[], unsigned long n); void filterNdec(OUT_T output[], ..., unsigned int decimate);Block 类(fir_filter_blk_impl.cc):包装为 GNU Radio 块。
if (this->decimation() == 1) { d_fir.filterN(out, in, noutput_items); } else { d_fir.filterNdec(out, in, noutput_items, this->decimation()); }decimation=1:普通 FIRdecimation>1:FIR + 抽取(每 D 点输出 1 点)set_history(ntaps):保留历史样本供卷积
实现优化:
- taps反转存储(
std::reverse)适配卷积方向 - 多份对齐 taps(
d_aligned_taps)处理非对齐输入 - float/complex 走VOLK点积内核
2.3 IIR 核心公式
Direct Form I 差分方程(newstyle=false,与 scipy/MATLAB 一致):
[
y[n] + \sum_{k=1}^{M} a_k y[n-k] = \sum_{k=0}^{N} b_k x[n-k]
]
[
H(z) = \frac{\sum_{k=0}^{N} b_k z^{-k}}{1 + \sum_{k=1}^{M} a_k z^{-k}}
]
fftaps= 前馈系数 (b_k)fbtaps= 反馈系数 (a_k)((a_0) 被忽略)
文件:iir_filter_ffd_impl.cc→ kerneliir_filter<i,o,tap,acc>
2.4 firdes:FIR 系数设计
低通(窗函数法,firdes.cc):
理想低通冲激响应(sinc):
[
h[n] = \frac{\sin(2\pi f_c n / f_s)}{\pi n} \cdot w[n], \quad n \neq 0
]
[
h[0] = \frac{2 f_c}{f_s} \cdot w[0]
]
再归一化使 DC 增益 =gain。
流程作用
| 场景 | 用法 |
|---|---|
| 接收音频 LPF | fir_filter_fff(decim, taps) |
| FM 去加重后音频滤波 | wfm_rcv中 FIR decim |
| 抗混叠 | 抽取前 LPF |
| IIR 去加重 | iir_filter_ffd(btaps, ataps)(gr-analog fm_emph 使用) |
涉及语法
- 三层模板
fir_filter<IN_T, OUT_T, TAP_T> sync_decimator(FIR+抽取)- Kernel/Block 分离
volk::vector对齐内存
接口调用
importgnuradio.fftasfftfromgnuradioimportfilter# 设计 + 使用taps=filter.firdes.low_pass(1.0,48000,5000,1000,fft.window.WIN_HAMMING)fir=filter.fir_filter_fff(1,taps)# 普通 FIRfir_decim=filter.fir_filter_fff(4,taps)# 4 倍抽取 FIR# IIR(来自 scipy 设计时 oldstyle=False)iir=filter.iir_filter_ffd(fftaps,fbtaps,oldstyle=False)# GRC 层次块(设计+滤波一体)lpf=filter.low_pass_filter(1,samp_rate,cutoff,transition,window)#include<gnuradio/filter/fir_filter_blk.h>autofir=gr::filter::fir_filter_blk<float,float,float>::make(1,taps);3. FFT 加速滤波原理与源码优化逻辑
3.1 原理:Overlap-Add / 频域卷积
时域卷积等价于频域相乘:
[
y[n] = x[n] * h[n] \Leftrightarrow Y[k] = X[k] \cdot H[k]
]
当 tap 数 (N) 较大时,FFT 法复杂度约 (O(N\log N)),优于直接卷积 (O(N \cdot L))。
3.2 关键参数(fft_filter.cc)
d_ntaps = ntaps; d_fftsize = (int)(2 * pow(2.0, ceil(log(double(ntaps)) / log(2.0)))); d_nsamples = d_fftsize - d_ntaps + 1;| 符号 | 含义 |
|---|---|
d_ntaps | 滤波器阶数 |
d_fftsize | FFT 长度(≥ 2×ntaps,2 的幂) |
d_nsamples | 每块有效输出样本数 |
d_tail | 块间重叠相加的“尾巴” |
3.3 处理流程
- 预计算:对 taps 做 FFT →
d_xformed_taps(乘 (1/N) 缩放) - 每块处理:
- 输入
d_nsamples点 + 零填充 → 长度d_fftsize - 正向 FFT → 与
d_xformed_taps相乘(VOLK) - 逆向 IFFT
- 加上上一块
d_tail(overlap-add) - 输出前
d_nsamples点,保存新 tail
- 输入
volk_32fc_x2_multiply_32fc_a(c, a, d_xformed_taps.data(), ...); d_invfft->execute(); for (j = 0; j < tailsize(); j++) d_invfft->get_outbuf()[j] += d_tail[j]; ... memcpy(&d_tail[0], d_invfft->get_outbuf() + d_nsamples, ...);3.4 何时用 FFT 滤波
- tap 很长(数百~数千)时比 FIR 直接卷积更快
pfb_decimator可选use_fft_filters=Truefreq_xlating_fft_filter结合频移
流程作用
广播/宽信道、高阶 LPF、大 tap 数信道化中的性能优化路径。
接口调用
# FFT 滤波块(支持 decimation)fft_fir=filter.fft_filter_fff(decimation=4,taps=taps,nthreads=1)fft_fir_ccf=filter.fft_filter_ccf(decimation=1,taps=taps)4. 抽取/插值滤波、多相滤波架构
4.1 插值 FIR(interp_fir_filter)
公式:先插零再滤波,等价于多相实现。
插值 (L) 倍:输出采样率 (f_s’ = L \cdot f_s)
多相分解:原 taps (h[n]) 拆成 (L) 个子滤波器:
[
h_r[k] = h[r + kL], \quad r = 0,1,\ldots,L-1
]
每个输入样本依次通过 (L) 个子滤波器,产生 (L) 个输出。
继承:sync_interpolator(1 输入 : L 输出)
4.2 有理数重采样(rational_resampler)
采样率变换:
[
f_{out} = f_{in} \cdot \frac{L}{M}
]
(L)=interpolation,(M)=decimation。
多相 FIR 银行+ 计数器d_ctr:
while ((i < noutput_items) && (count < ninput_items[0])) { out[i++] = d_firs[ctr].filter(in); ctr += this->decimation(); while (ctr >= this->interpolation()) { ctr -= this->interpolation(); in++; count++; } }- 每输入 1 点,按相位
ctr选子滤波器输出 - 无用户 taps 时自动用 Kaiser 窗设计 LPF(
design_resampler_filter) - 用
std::gcd(L,M)约简降低复杂度
4.3 多相滤波器组(PFB)通用架构
核心思想:把原型滤波器 (H(z)) 分解为 (N) 个多相分支:
[
H(z) = \sum_{k=0}^{N-1} z^{-k} H_k(z^N)
]
| 块 | 作用 |
|---|---|
pfb_decimator_ccf | (N) 路输入 → 选 1 路信道输出(抽取+选频) |
pfb_interpolator_ccf | 1 路 → (N) 路(插值+合成) |
pfb_channelizer_ccf | 宽输入 → 多窄带信道(FFT 信道化) |
pfb_synthesizer_ccf | 多信道 → 宽输出(合成) |
pfb_decimator还含复数旋转器 (e^{j2\pi k \cdot \text{chan}/N}) 选信道。
流程作用
ADC 高采样率 → [抽取 FIR] → 低采样率基带 音频 48k → [插值 FIR] → 240k 供 FM 调制 任意 L/M → [rational_resampler] → 统一采样率 宽频谱 → [pfb_channelizer] → 多路窄带信道接口调用
# 插值interp=filter.interp_fir_filter_fff(interpolation=4,taps=taps)# 有理数重采样 48k → 44.1k 类场景rr=filter.rational_resampler_fff(interpolation=441,decimation=480,taps=[],fractional_bw=0.4)# PFB 抽取(8 选 1 信道)pfb_dec=filter.pfb_decimator_ccf(decim=8,taps=taps,channel=0)# PFB 插值pfb_int=filter.pfb_interpolator_ccf(interp=8,taps=taps)# PFB 信道化chan=filter.pfb_channelizer_ccf(numchans=8,taps=taps)5. 任意重采样模块底层原理
块名:pfb_arb_resampler_xxx
Kernel:pfb_arb_resampler.cc
5.1 目标
实现任意比率重采样 (f_{out} = r \cdot f_{in}),(r) 为任意浮点数(如 1.037)。
5.2 原理:多相滤波器 + 线性插值
- 设滤波器组数 (N =)
filter_size(即d_int_rate) - 整数部分:(D = \lfloor N/r \rfloor)
- 小数部分:(f = N/r - D)(
d_flt_rate) - 每输出 1 点:
- 用第 (j) 个子滤波器 FIR 得 (o_0)
- 用差分滤波器得 (o_1)((H’(z)) 近似)
- 线性插值:(y = o_0 + o_1 \cdot \text{acc})
- 累加器
d_acc按小数步进更新,溢出时推进输入
o0 = d_filters[j].filter(&input[i_in]); o1 = d_diff_filters[j].filter(&input[i_in]); output[i_out] = o0 + o1 * d_acc;差分 taps 由[-1, 1]差分器作用于原型 taps 得到,用于子样本级插值。
5.3 与 rational_resampler 对比
| rational_resampler | pfb_arb_resampler | |
|---|---|---|
| 比率 | 有理数 L/M | 任意浮点 r |
| 精度 | 精确 | 近似(插值) |
| 复杂度 | 较低 | 较高(双滤波器组) |
流程作用
- 音频设备采样率不匹配(48000 ↔ 44100)
- 符号时钟恢复后的分数重采样
- 软件无线电中非标比率变换
接口调用
# 浮点 → 浮点,重采样到 1.2 倍arb=filter.pfb_arb_resampler_fff(rate=1.2,taps=taps,filter_size=32)# 复数arb_ccf=filter.pfb_arb_resampler_ccf(rate=0.8,taps=taps,filter_size=32)6. 通信专用 RRC/升余弦、高斯滤波源码
设计入口:firdes.cc+ GRC 变量块variable_rrc_filter_taps
6.1 根升余弦(RRC)
用途:发送端脉冲成形;接收端匹配滤波。发送+接收 RRC 级联 ≈ 升余弦,消除 ISI。
频域:滚降系数 (\alpha \in [0,1])
时域(firdes::root_raised_cosine,(T_s = 1/\text{symbol_rate}),(spb = f_s \cdot T_s)):
[
h(t) = \frac{4\alpha}{\pi\sqrt{T_s}} \cdot
\frac{\cos((1+\alpha)\pi t/T_s) + \frac{\sin((1-\alpha)\pi t/T_s)}{4\alpha t/T_s}}
{1 - (4\alpha t/T_s)^2}
]
((t=0) 及分母为 0 处用极限值处理,见源码if (fabs(x3) >= 0.000001)分支。)
6.2 高斯滤波
用途:GFSK/MSK(如蓝牙、GSM)频谱成形,限制带外辐射。
公式(firdes::gaussian):
[
h[n] = \exp\left(-\frac{1}{2}\left(\frac{s \cdot n \cdot T_s}{T_{sym}}\right)^2\right)
]
其中 (s = \frac{1}{\sqrt{\ln 2 / (2\pi^2 B T^2)}}),(BT) 为带宽-符号时间积(bt参数)。
6.3 升余弦(RC)
firdes也提供raised_cosine(非 root),用于理论分析或特殊链路;实际通信多用RRC 对。
流程作用
比特流 → [RRC 成形 FIR] → 上变频 → 信道 ↓ 限制带宽、控制 ISI GFSK: 比特 → [高斯 FIR] → 频率调制接口调用
# 直接设计 tapsrrc_taps=filter.firdes.root_raised_cosine(gain=1.0,sampling_freq=8e6,# 8 样点/符号symbol_rate=1e6,# 1 Mspsalpha=0.35,# 滚降ntaps=11*8)# 通常 8~16 倍 spbgauss_taps=filter.firdes.gaussian(gain=1.0,spb=8,bt=0.35,ntaps=4*8)# 使用rrc_fir=filter.fir_filter_fff(1,rrc_taps)# GRC 层次块rrc_blk=filter.root_raised_cosine_filter(gain=1.0,sample_rate=fs,symbol_rate=Rs,alpha=0.35,ntaps=101)# 优化设计(需 scipy)fromgnuradio.filterimportoptfir taps=optfir.low_pass(1,fs,passband,stopband,ripple,atten)7. DC 消除、简单高低通滤波
7.1 DC Blocker(dc_blocker_ff_impl.cc)
问题:IQ 接收机常有 DC 偏置,影响解调/频谱。
原理:(H(z) = \frac{1 - z^{-D}}{1 - z^{-D}/D}) 的滑动平均实现(近似高通,截止 (\approx f_s/(2\pi D)))。
短形式(long_form=False):
[
y[n] = x[n-D+1] - \text{MA}_2(\text{MA}_1(x[n]))
]
长形式:四级滑动平均 + 延迟线,阻带更深。
y1 = d_ma_0.filter(in[i]); y2 = d_ma_1.filter(y1); out[i] = d_ma_0.delayed_sig() - y2;流程作用:USRP/IQ 接收最前端,解调之前。
7.2 单极点 IIR(single_pole_iir_filter_ff)
一阶 IIR 低通:
[
y[n] = \alpha x[n] + (1-\alpha) y[n-1]
]
(\alpha) 越小,截止频率越低。
流程作用:极简平滑、慢变 DC 跟踪(比 dc_blocker 更简单)。
7.3 简单高低通(GRC 层次块 + firdes)
low_pass_filter、high_pass_filter、band_pass_filter等:
内部 =firdes.low_pass(...)+fir_filter_fff(1, taps)
低通 firdes 公式(见第 2 节 sinc × 窗)。
高通:频谱反转低通:
[
h_{HP}[n] = h_{LP}[n] \cdot (-1)^n \quad \text{(或等效频域变换)}
]
接口调用
# DC 消除dc=filter.dc_blocker_ff(D=32,long_form=True)# floatdc_c=filter.dc_blocker_cc(D=32,long_form=False)# complex# 单极点 IIR 低通iir1=filter.single_pole_iir_filter_ff(alpha=0.01)# 简单低通(设计+滤波一体)lpf=filter.low_pass_filter(gain=1.0,samp_rate=48000,cutoff_freq=5000,transition_width=1000,window=fft.window.WIN_HAMMING)hpf=filter.high_pass_filter(1.0,48000,200,500,fft.window.WIN_HAMMING)bpf=filter.band_pass_filter(1.0,48000,200,4000,500,fft.window.WIN_HAMMING)总览:典型信号处理流程
语法知识汇总
| 语法/模式 | 示例位置 | 用途 |
|---|---|---|
三层模板<IN,OUT,TAP> | fir_filter_blk,rational_resampler | 多类型支持 |
| Kernel + Block 分离 | kernel::fir_filter+fir_filter_blk_impl | 算法复用 |
sync_decimator/interpolator | FIR decim, interp_fir | 固定比率多速率 |
block+general_work | rational_resampler | 任意 consume/produce |
| 多相 taps 分解 | rational_resampler, pfb_* | 高效多速率 |
| VOLK SIMD | fir_filter, fft_filter | 卷积加速 |
| FFT overlap-add | fft_filter.cc | 长 FIR 加速 |
set_history/set_relative_rate | 多速率块 | 调度器配合 |
firdes静态设计类 | firdes.cc | 系数生成 |
pm_remez | 等波纹最优 FIR | 精确通带设计 |
std::gcd约简 | rational_resampler | 降低多相数 |
std::deque延迟线 | dc_blocker | 滑动平均 |
Python 快速参考
| 功能 | 调用 |
|---|---|
| 设计 LPF taps | filter.firdes.low_pass(gain, fs, fc, tw, window) |
| 设计 RRC | filter.firdes.root_raised_cosine(gain, fs, sym_rate, alpha, ntaps) |
| 设计高斯 | filter.firdes.gaussian(gain, spb, bt, ntaps) |
| FIR 滤波 | filter.fir_filter_fff(decim, taps) |
| IIR 滤波 | filter.iir_filter_ffd(b, a, oldstyle=False) |
| FFT FIR | filter.fft_filter_fff(decim, taps) |
| 插值 | filter.interp_fir_filter_fff(L, taps) |
| 有理重采样 | filter.rational_resampler_fff(L, M, taps, fractional_bw=0.4) |
| 任意重采样 | filter.pfb_arb_resampler_ccf(rate, taps, filter_size=32) |
| PFB 信道化 | filter.pfb_channelizer_ccf(numchans, taps) |
| DC 消除 | filter.dc_blocker_cc(D, long_form) |
| 频移+滤波 | filter.freq_xlating_fir_filter_ccc(center_freq, samp_rate, taps) |
与 gr-analog / gr-blocks 的分工
| 模块 | 职责 |
|---|---|
| gr-filter | 滤波、多速率、系数设计、RRC/高斯 |
| gr-analog | FM/AM 调制解调,调用 gr-filter 做音频 LPF |
| gr-fft | FFT 引擎、窗函数 |
| gr-blocks | 基础数学、类型转换 |
例如wfm_rcv中:quadrature_demod_cf(analog)+fir_filter_fff(filter)+fm_deemph(analog 的 IIR)。
