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_xxxiir_filter_xxxfft_filter_xxx 抗混叠、信道选择、音频 LPF
多速率 interp_fir_filterrational_resamplerpfb_arb_resampler 改变采样率
PFB 架构 pfb_channelizerpfb_decimator/interpolatorpfb_synthesizer 高效多信道、多相抽取/插值
频移+滤波 freq_xlating_fir_filterfreq_xlating_fft_filter 下变频+滤波一体
系数设计 firdesoptfirpm_remez 离线/在线生成 taps
通信成形 root_raised_cosine_filter、RRC/Gaussian taps 脉冲成形、匹配滤波
简单滤波 dc_blockersingle_pole_iirlow_pass_filter DC 消除、一阶平滑
其他 hilbert_fcfilterbankmmse_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:普通 FIR
  • decimation>1:FIR + 抽取(每 D 点输出 1 点)
  • set_history(ntaps):保留历史样本供卷积

实现优化

  • taps 反转 存储(std::reverse)适配卷积方向
  • 多份对齐 tapsd_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 处理流程

  1. 预计算 :对 taps 做 FFT → d_xformed_taps(乘 (1/N) 缩放)
  2. 每块处理
    • 输入 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=True
  • freq_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
Kernelpfb_arb_resampler.cc

5.1 目标

实现任意比率重采样 (f_{out} = r \cdot f_{in}),(r) 为任意浮点数(如 1.037)。

5.2 原理:多相滤波器 + 线性插值

  1. 设滤波器组数 (N =) filter_size(即 d_int_rate
  2. 整数部分:(D = \lfloor N/r \rfloor)
  3. 小数部分:(f = N/r - D)(d_flt_rate
  4. 每输出 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_filterhigh_pass_filterband_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)。

相关推荐
黎阳之光12 小时前
黎阳之光:以原创硬核通信,定义无人系统与应急指挥新边界|7030‑46无线图数自组网电台技术解析
大数据·人工智能·物联网·算法·数字孪生
不知名的老吴13 小时前
经典算法实战:重新排列日志文件(二)
数据结构·算法
CS创新实验室13 小时前
数据结构和算法:斐波那契堆
数据结构·算法·斐波那契堆
炽烈小老头13 小时前
【每天学习一点算法 2026/05/22】课程表 II
学习·算法
Old Uncle Tom13 小时前
推荐算法应用举例
算法·机器学习·推荐算法
2601_9583529014 小时前
免提通话中的非线性回声与神经降噪:A-29P 模块背后的算法与系统架构
算法·系统架构·语音处理·回音消除·降噪模块
小O的算法实验室14 小时前
2026年IEEE TEVC,具有子结构保持双学习进化算法+带容量约束车辆路径问题
算法
用户9385156350714 小时前
数组去重,从双重循环到一行 Set,我经历了什么?
javascript·算法
小许同学记录成长14 小时前
gr-analog 模拟信号模块完整源码分析
python·算法·信号处理