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 块定义
接口调用(总入口)
python
from gnuradio import filter, 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 普通 FIR
tb.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):纯算法,可被多块复用。
44:49:e:\Code\suanfa\gnuradio-main\gnuradio-main\gr-filter\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 块。
77:81:e:\Code\suanfa\gnuradio-main\gnuradio-main\gr-filter\lib\fir_filter_blk_impl.cc
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 → kernel iir_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对齐内存
接口调用
python
import gnuradio.fft as fft
from gnuradio import filter
# 设计 + 使用
taps = filter.firdes.low_pass(1.0, 48000, 5000, 1000, fft.window.WIN_HAMMING)
fir = filter.fir_filter_fff(1, taps) # 普通 FIR
fir_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)
cpp
#include <gnuradio/filter/fir_filter_blk.h>
auto fir = 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)
72:77:e:\Code\suanfa\gnuradio-main\gnuradio-main\gr-filter\lib\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
- 输入
124:147:e:\Code\suanfa\gnuradio-main\gnuradio-main\gr-filter\lib\fft_filter.cc
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 数信道化中的性能优化路径。
接口调用
python
# 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:
247:256:e:\Code\suanfa\gnuradio-main\gnuradio-main\gr-filter\lib\rational_resampler_impl.cc
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] → 多路窄带信道
接口调用
python
# 插值
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按小数步进更新,溢出时推进输入
192:196:e:\Code\suanfa\gnuradio-main\gnuradio-main\gr-filter\lib\pfb_arb_resampler.cc
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)
- 符号时钟恢复后的分数重采样
- 软件无线电中非标比率变换
接口调用
python
# 浮点 → 浮点,重采样到 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] → 频率调制
接口调用
python
# 直接设计 taps
rrc_taps = filter.firdes.root_raised_cosine(
gain=1.0,
sampling_freq=8e6, # 8 样点/符号
symbol_rate=1e6, # 1 Msps
alpha=0.35, # 滚降
ntaps=11*8) # 通常 8~16 倍 spb
gauss_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)
from gnuradio.filter import optfir
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\]))
长形式:四级滑动平均 + 延迟线,阻带更深。
93:98:e:\Code\suanfa\gnuradio-main\gnuradio-main\gr-filter\lib\dc_blocker_ff_impl.cc
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{(或等效频域变换)}
接口调用
python
# DC 消除
dc = filter.dc_blocker_ff(D=32, long_form=True) # float
dc_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)
总览:典型信号处理流程
发射链
比特
root_raised_cosine FIR
interp_fir_filter 上采样
上变频
接收链
USRP IQ
dc_blocker_cc
freq_xlating_fir_filter 或 mix+FIR
rational_resampler 或 pfb_arb
fir_filter 信道 LPF
解调器 gr-analog
语法知识汇总
| 语法/模式 | 示例位置 | 用途 |
|---|---|---|
三层模板 <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)。