当前位置: 首页 > news >正文

多速率信号处理源码深度剖析

模块总览

块 / 类文件能力
rational_resamplerrational_resampler_impl.cc有理数倍率 (L/M)
interp_fir_filterinterp_fir_filter_impl.cc整数插值 (L)
pfb_interpolator_ccfpfb_interpolator_ccf_impl.ccPFB 插值
pfb_decimator_ccfpfb_decimator_ccf_impl.ccPFB 抽取 + 选信道
pfb_channelizer_ccfpfb_channelizer_ccf_impl.cc多信道化
pfb_arb_resampler_*pfb_arb_resampler.cc任意实数倍率
mmse_resampler_*mmse_resampler_impl.cc符号同步 / 细粒度重采样
polyphase_filterbankpolyphase_filterbank.ccPFB 公共基类
firdes::low_passfirdes.cc抗混叠原型滤波器

1. 采样率转换底层原理

1.1 数学模型

设输入采样率 (f_{s,in}),目标 (f_{s,out}),转换比:

[
r = \frac{f_{s,out}}{f_{s,in}} = \frac{L}{M}
]

经典三阶段结构:

  1. 上采样 (L) 倍:插入 (L-1) 个零 → 频谱压缩并产生 (L-1) 组镜像
  2. 抗镜像/抗混叠 FIR:截止频率 (\le \min(f_{s,in}/2,, f_{s,out}/2))
  3. 下采样 (M) 倍:每 (M) 点取 1 点

Noble 恒等式(多相实现的基础):先插零再 FIR 再抽取,等价于把原型 FIR (h[n]) 拆成 (L) 条多相支路,每条只算“有效”样本,计算量从 (O(N \cdot L)) 降到 (O(N))。

GNU Radio 中rational_resampler把插值、滤波、抽取合成一步,用多相 FIR 数组d_firs[L]实现。

1.2 源码:set_relative_rate与 GCD 化简

auto d = std::gcd(interpolation, decimation); // ... if (taps.empty()) { interpolation /= d; decimation /= d; staps = design_resampler_filter<TAP_T>(interpolation, decimation, fractional_bw); } // ... this->set_relative_rate(uint64_t{ interpolation }, uint64_t{ decimation });
  • set_relative_rate(L, M)告诉调度器:每产出 (M) 个输出样本,大约消耗 (L) 个输入样本(general_work块用forecast精确估算)。
  • GCD 约分:(48/32 \to 3/2),滤波器支路数从 48 降到 3,显著省内存与 CPU。

1.3general_work:多相指针调度

unsigned int ctr = 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++; } } d_ctr = ctr;

含义

  • ctr:当前使用的多相支路索引 (0 \ldots L-1)
  • 每输出 1 点:ctr += M;当ctr >= L时输入前进 1 样本并ctr -= L
  • 等价于:在“虚拟”的 (L) 倍插值流上,每 (M) 点取 1 点,但只对非零相位做 FIR

在信号链中的位置:ADC 采样率与算法符号率不匹配时的粗对齐(如 2 Msps → 1.28 Msps)。

1.4 涉及语法

语法用途
C++ 类模板rational_resampler<IN_T,OUT_T,TAP_T>多类型实例化(ccc/ccf/fff 等)
general_work+forecast非固定 1:1 的block
reinterpret_cast无类型 buffer → 样本指针
std::gcd有理数约分

1.5 接口调用

fromgnuradioimportfilter# L=3, M=2 → 输出率 = 输入率 × 3/2# taps 为空则自动设计 Kaiser 低通rr=filter.rational_resampler_ccc(interpolation=3,decimation=2,taps=[],# 或自定义 tapsfractional_bw=0.4# 自动设计时的通带比例)tb.connect(src,rr,sink)

C++:filter::rational_resampler_ccc::make(3, 2, taps, 0.4f)


2. 抽取、插值抗混叠滤波源码逻辑

2.1 理论:为何要滤波

操作风险滤波要求
插值 (L)镜像出现在 (\pm k f_s/L)低通,截止 (\le f_{s,out}/2)
抽取 (M)频谱折叠(混叠)先低通至 (f_{s,out}/2),再抽点

自动设计函数design_resampler_filter根据 (r = L/M) 选过渡带:

float rate = float(interpolation) / float(decimation); if (rate >= 1.0) { trans_width = halfband - fractional_bw; // 扩采样:防镜像 mid_transition_band = halfband - trans_width / 2.0; } else { trans_width = rate * (halfband - fractional_bw); // 降采样:防混叠 mid_transition_band = rate * halfband - trans_width / 2.0; } return firdes::low_pass(interpolation, interpolation, mid_transition_band, trans_width, fft::window::WIN_KAISER, beta);

设计采样率取interpolation:文档说明当 (L \ge M) 时,滤波器工作在插值后的最高速率(L \cdot f_{s,in}) 上。

2.2 原型 FIR:firdes::low_pass

int ntaps = compute_ntaps(sampling_freq, transition_width, window_type, param); double fwT0 = 2 * GR_M_PI * cutoff_freq / sampling_freq; for (int n = -M; n <= M; n++) { if (n == 0) taps[n + M] = fwT0 / GR_M_PI * w[n + M]; else taps[n + M] = sin(n * fwT0) / (n * GR_M_PI) * w[n + M]; // sinc × 窗 }

理想低通冲激响应 (h_d[n] = \frac{\sin(\omega_c n)}{\pi n}),再乘 Kaiser 窗控制旁瓣。

2.3 多相拆分:install_taps

插值 FIR 与有理重采样共用同一拆分逻辑:

for (int i = 0; i < (int)taps.size(); i++) xtaps[i % nfilters][i / nfilters] = taps[i];

原型 (h[0], h[1], \ldots, h[N-1]) → 第 (k) 相:(h[k], h[k+L], h[k+2L], \ldots)

插值interp_fir_filter的 work

for (int i = 0; i < ni; i++) { for (int nf = 0; nf < nfilters; nf++) { out[nf] = d_firs[nf].filter(&in[i]); // 1 输入 → L 输出 } out += nfilters; }

继承sync_interpolator,调度器已知输出是输入的 (L) 倍。

2.4 PFB 抽取:pfb_decimator_ccf

输入经stream_to_streams分成 (M) 路(相位 0…M-1),每路进一条多相 FIR,再旋转相加选出第 (k) 信道:

// y[i] = Σ_{j=0}^{M-1} x[j][i] · exp(2π j k / M) for (unsigned int j = 0; j < d_rate; j++) { out[i] += d_tmp[j * noutput_items + i] * d_rotator[j]; }

或用FFT代替显式复指数(work_fir_fft),计算 (O(M \log M)) 但 (M) 大时更高效。

在链路中的位置

  • 发射:符号流 →插值 + RRC(抗镜像)
  • 接收:高采样 IQ →抽取 + 低通(抗混叠)→ 符号同步

2.5 Python 便捷封装(自动 taps)

gr-filter/python/filter/pfb.pydecimator_ccf/interpolator_ccfoptfir.low_pass生成覆盖 0.4 归一化带宽的原型滤波器,并包装stream_to_streams

fromgnuradio.filterimportpfb# 8 倍抽取,选第 0 信道,自动设计 tapsdec=pfb.decimator_ccf(decim=8,channel=0,atten=100)interp=pfb.interpolator_ccf(interp=4,atten=100)

3. 多相滤波组(PFB)核心源码解析

3.1 基类polyphase_filterbank

d_taps_per_filter = ceil(ntaps / d_nfilts); for (i = 0; i < d_nfilts; i++) { for (j = 0; j < d_taps_per_filter; j++) { d_taps[i][j] = tmp_taps[i + j * d_nfilts]; // 多相分解 } d_fir_filters[i].set_taps(d_taps[i]); d_fft_filters[i].set_taps(d_taps[i]); // 可选 FFT 卷积 }

每条支路一个kernel::fir_filter_ccfd_fft_filters供长滤波器 batch 处理。

3.2 PFB 插值器

while (i < noutput_items) { for (unsigned int j = 0; j < d_rate; j++) { out[i] = d_fir_filters[j].filter(&in[count]); i++; } count++; }

1 个输入样本 → 依次通过 (L) 条多相 FIR → (L) 个输出。与interp_fir_filter数学等价,接口与 PFB 家族一致。

3.3 PFB 信道化器pfb_channelizer_ccf

将宽带信号分成 (M) 个等带宽子信道,每信道采样率 (f_s/M)。

  • 输入:(M) 路 deinterleaved 流(stream_to_streams
  • 每路多相 FIR →IFFT/FFT 旋转→ 输出 (M) 信道向量
  • oversample_rate限制为 (N/i,, i \in [1,N]),支持 fractional 信道化

作用:频谱监测、多载波并行解调、信道选择(配合set_channel_map)。

3.4 底层 FIR:kernel::fir_filter

float fir_filter<float,float,float>::filter(const float input[]) const { volk_32f_x2_dot_prod_32f_a(..., ar, d_aligned_taps[al].data(), d_ntaps + al); return d_output[0]; }
  • taps 内部反转(卷积 vs 相关)
  • VOLK对齐点积,SIMD 加速
  • filterNdec支持抽 decimate 步长的批量滤波

3.5 涉及语法

  • 继承pfb_decimator_ccf_impl : sync_block, polyphase_filterbank
  • sync_interpolator:固定 (L:1) 输出比
  • gr::thread::scoped_lock:运行时set_taps线程安全
  • set_history(nt):FIR 需要过去 (nt-1) 个样本

4. 任意分数倍重采样实现机制

GNU Radio 提供两条路径:PFB 任意重采样(宽带、带抗混叠)和MMSE 重采样(窄带、低延迟、适合符号同步)。

4.1pfb_arb_resampler:多相 + 线性插值

速率分解
void pfb_arb_resampler_ccf::set_rate(float rate) { d_dec_rate = (unsigned int)floor(d_int_rate / rate); // D = floor(N/r) d_flt_rate = (d_int_rate / rate) - d_dec_rate; // 小数部分 μ }
  • (N =)filter_size(默认 32):多相滤波器个数
  • (D = \lfloor N/r \rfloor):支路步进
  • (\mu = N/r - D):相邻两支路输出的线性插值权重
差分滤波器(导数支路)
diff_filter[0] = -1; diff_filter[1] = 1; for (i = 0; i < newtaps.size() - 1; i++) { difftaps.push_back(newtaps[i+1] - newtaps[i]); // 近似 dh/dn }

输出:

[
y \approx y_0 + \mu \cdot \frac{dy}{dn}
]

其中 (y_0 = h_j * x),(dy/dn) 来自差分 taps 的 FIR,实现相邻多相滤波器之间的亚滤波器相位插值。

核心循环
while (j < d_int_rate) { o0 = d_filters[j].filter(&input[i_in]); o1 = d_diff_filters[j].filter(&input[i_in]); output[i_out] = o0 + o1 * d_acc; d_acc += d_flt_rate; j += d_dec_rate + (int)floor(d_acc); d_acc = fmodf(d_acc, 1.0); } i_in += (int)(j / d_int_rate); j = j % d_int_rate;

状态变量d_last_filterd_accwork()调用保持连续。

Block 包装
int pfb_arb_resampler_ccf_impl::general_work(...) { int nitems = floorf((float)noutput_items / relative_rate()); int processed = d_resamp.filter(out, in, nitems, nitems_read); consume_each(nitems_read); return processed; }

set_relative_rate(rate)声明非整数比;forecastnoutput/rate估算输入需求。

自动滤波器设计(Python)
if(rate < 1): halfband = 0.5 * rate # 降采样:截止 ∝ 输出 Nyquist return filter.firdes.low_pass_2(flt_size, flt_size, bw, tb, atten, ...) else: # 升采样:防镜像,halfband = 0.5

4.2mmse_resampler:Farrow / MMSE 插值

用于符号定时恢复:输入率与输出率接近 1:1,只需微调相位 (\mu)。

while (idx_out < noutput_items && idx_in < max_input_index) { out[idx_out++] = d_resamp.interpolate(&in[idx_in], static_cast<float>(d_mu)); d_mu += d_delta_mu; idx_in += static_cast<int>(floor(d_mu)); d_mu -= floor(d_mu); }
  • d_delta_mu= 重采样比(输出/输入,可 <1 或 >1)
  • mmse_fir_interpolator预存129 组FIR(NSTEPS+1),(\mu) 量化到最近步进:
int imu = (int)rint(mu * NSTEPS); return filters[imu].filter(input);

支持第二路输入动态比率,以及 PMT 消息改resamp_ratio/mu

4.3 两种任意重采样对比

pfb_arb_resamplermmse_resampler
典型 (r)任意(如 2.5、0.73)≈1 ± 小偏差
抗混叠有(完整 LPF)弱(短 MMSE FIR)
用途脉冲成形、速率匹配symbol_sync、Gardner 后微调
延迟较大(原型 FIR 群时延)较小

4.4 接口示例

fromgnuradioimportfilter# 8000 → 20000 Hz,等价 rate=2.5rate=20000.0/8000.0resamp=filter.pfb.arb_resampler_ccf(rate,taps=None,flt_size=32)# 符号同步:timing error 反馈到 resamp_ratiommse=filter.mmse_resampler_cc(phase_shift=0.0,resamp_ratio=1.0+epsilon)

5. 通信系统中重采样工程应用

5.1 发射链:成形 + 整数/任意上采样

generic_mod_demod.py标准做法:

self.rrc_taps = filter.firdes.root_raised_cosine( nfilts, nfilts, 1.0, self._excess_bw, ntaps) self.rrc_filter = filter.pfb_arb_resampler_ccf( self._samples_per_symbol, self.rrc_taps)

流程位置

比特 → 映射 → 符号 → [pfb_arb_resampler @ sps] → USRP/DAC ↑ RRC 内置,同时完成 sps 倍上采样
  • RRC taps 按nfilts=32为虚拟采样率设计(见注释),与 PFB 的 32 相结构匹配
  • skiphead去掉 FIR 群时延引入的瞬态

5.2 接收链:多级速率变换

典型接收机:

USRP (高 fs) → [可选 rational_resampler 或 pfb_decimator] 粗降到几 MHz → AGC / FLL → symbol_sync (内部 mmse_resampler_cc) 细调 TO → 判决
  • 粗匹配rational_resampler(3,2)pfb_decimator_ccf
  • 细同步mmse_resampler_cc+ Gardner / PFB 时钟同步(qa_pfb_clock_sync.pypfb_arb_resampler做 RRC 匹配滤波)

5.3 分组 / 突发通信

gr-digital/examples/packet/tx_stage6.grc

burst_shaper → pfb_arb_resampler → fir_filter → USRP

突发成形后按信道带宽重采样,再经额外 FIR 整形。

5.4 多载波 / 频谱分析

fromgnuradio.filterimportpfb ch=pfb.channelizer_ccf(numchans=8,oversample_rate=2)

8 路并行子信道,每路 (f_s/8),用于多信号并行解调或窄带 DDC。

5.5 工程选型建议

场景推荐块
(L/M) 固定有理数rational_resampler
整数 (L) 上采样 + 自定义 tapsinterp_fir_filterpfb.interpolator_ccf
整数 (M) 下采样 + 选频pfb.decimator_ccf
任意实数比 + 抗混叠pfb.arb_resampler_ccf
符号时钟跟踪mmse_resampler_cc
多信道并行pfb.channelizer_ccf

5.6 完整 Python 流图示例

参考gr-filter/examples/resampler.py

rerate=fs_out/fs_in taps=filter.firdes.low_pass_2(32,32,0.25,0.1,80)self.resamp=filter.pfb.arb_resampler_ccf(rerate,taps,flt_size=32)self.connect(src,head,self.resamp,sink)

语法知识汇总

层级知识点
GNU Radio 块模型sync_block/sync_interpolator/general_work+forecast+consume_each
C++ 模板rational_resampler<IN_T,OUT_T,TAP_T>多类型导出
Kernel 层kernel::fir_filterkernel::pfb_arb_resampler_*可被 block 复用
Pythonfilter.pfb.*hier_block2 包装;firdes/optfir设计 taps
性能VOLK SIMD、set_output_multiple批量对齐
线程安全scoped_lock+d_updated延迟重装 taps

小结

GNU Radio 多速率处理的统一思想是:用Noble 恒等式把“插零→FIR→抽取”折叠成多相 FIR 阵列 + 指针调度;有理数倍用rational_resamplerctr状态机,任意实数倍用pfb_arb_resampler的 (N/D) 步进 + 差分线性插值,符号级微调用mmse_resampler的 (\mu) accumulator。抗混叠/抗镜像由firdes::low_pass或 Pythonpfb.create_taps按 (r) 与 Nyquist 约束自动(或手动)设计。

http://www.jsqmd.com/news/899840/

相关文章:

  • CAPL脚本自动化测试进阶 ———— 活用Test Step函数提升测试报告可读性与精准度
  • 2026年北京鸿博志远教育深度解析:军队文职培训赛道竞争加剧与用户选择痛点 - 品牌推荐
  • LeetCode 189 · 轮转数组:三次翻转,原地搞定的神仙操作
  • 2026年论文怎么降低AI率?学长教你3招免费降AI,亲测5款AIGC降重工具 - 降AI实验室
  • 软件定义汽车安全新范式:SHIFTGUARD任务迁移技术深度解析
  • 数据库技术:Redis缓存与分布式锁
  • CUDA编程:Shared Memory Bank Conflict 与 Padding 优化
  • 为内部知识库问答系统接入Taotoken提供多模型后备支持
  • 2026年 工业热电偶十大品牌推荐榜单:铠装/K型/装配式/手持式/铂铑热电偶源头厂家与高精度测温方案深度解析 - 品牌企业推荐师(官方)
  • 终极免费文档下载脚本指南:如何一键获取百度文库等30+平台资源
  • 从数据手册到实战:剖析74HC4052模拟开关的选型与电路设计
  • 2026年 背景板/气球/桁架/注水旗租赁服务排行榜:快展搭建与舞台活动的专业口碑精选 - 品牌企业推荐师(官方)
  • 如何用Python自动化COMSOL仿真:MPh完整指南
  • 技术写作:如何写出高质量技术文章
  • 使用taotoken聚合api为个人项目构建智能问答助手
  • 融合聚焦深度与单目深度估计:测试时优化提升度量深度精度
  • IntelliJ IDEA 2026.2 EAP 启动:平衡 AI 与传统开发,多维度功能升级
  • 都在说油车不行,可是经销商倒闭、夸张的1亿订单都与电车有关!
  • C语言--day20
  • 观察大模型API调用成本,Taotoken用量看板如何助力企业预算管理
  • 深度指南:2026现阶段河北地区专业阳光房实力厂商选择全解析 - 2026年企业资讯
  • 维普4月升级降AI失效?2026年5月仍有效的4款降AI软件实测
  • 对比自行维护多个API与使用Taotoken聚合在运维上的差异
  • 靠谱的17-4Ph不锈钢厂商推荐:高硬度耐磨不锈钢厂商联系方式 - 品牌2025
  • 实测HS0038红外接收头:3.3V和5V都能用,STM32F103直接驱动避坑指南
  • AI预约聊天机器人实战:从自然语言理解到GDPR合规部署
  • SAP FI 深度解析:OBCY配置下的会计凭证行项目合并实战与风险规避
  • 小白/程序员必备:收藏!轻松学会使用大模型进行数据验证
  • ChatGPT企业客户画像生成实录(脱敏版):金融/教育/医疗三大行业差异化建模路径对比
  • 物流系统如何打通信息孤岛?哲盟软件系统:一键打通内外部数据壁垒