gr-analog 模拟信号模块完整源码分析
1 gr-analog 模块整体功能定位与源码架构
功能定位
gr-analog 负责模拟调制/解调、波形与噪声生成、电平控制、PLL 同步,是 GNU Radio 中离"真实无线电波形"最近的一层。
| 依赖 | 作用 |
|---|---|
gnuradio-runtime |
NCO/VCO、random、块基类、调度 |
gr-blocks |
AM 检波 complex_to_mag、PLL 基类 control_loop |
gr-filter |
NBFM/WBFM 音频 FIR/IIR 滤波 |
源码架构
gr-analog/
├── include/gnuradio/analog/ # 公开 API(约 35 个头文件)
├── lib/*_impl.cc # C++ 实现 → libgnuradio-analog.so
├── python/analog/ # PyBind11 + 层次收发机(wfm_tx/rx 等)
└── grc/ # GRC 可视化块
块分类(信号处理流程中的位置)
接收链
信道/测试
发射链
sig_source / noise_source
frequency_modulator / phase_modulator
fm_preemph
noise_source
agc / rail_ff
pll_carriertracking
quadrature_demod / fmdet
fm_deemph
am_demod_cf
涉及语法
- C++ 模板类 +
template class显式实例化 - 工厂模式
make()+std::shared_ptr - 继承
sync_block/block - Python 层次块
gr.hier_block2拼装子块
接口调用
python
from gnuradio import gr, analog
tb = gr.top_block()
src = analog.sig_source_f(samp_rate, analog.GR_COS_WAVE, 1000, 1.0)
tb.connect(src, ...)
tb.start()
cpp
#include <gnuradio/analog/sig_source.h>
auto src = gr::analog::sig_source<float>::make(
samp_rate, gr::analog::GR_COS_WAVE, 1000, 1.0);
5.3.2 基础信号源底层源码
核心文件 :gr-analog/lib/sig_source_impl.cc,底层 gr::fxpt_nco(定点 NCO)。
各波形实现
| 波形 | 枚举 | 公式 | 流程作用 |
|---|---|---|---|
| 常数 | GR_CONST_WAVE |
(y = A + \text{offset}) | 直流偏置、测试常量 |
| 正弦 | GR_SIN_WAVE |
(y[n] = A\sin(\phi[n])+\text{offset}) | 单音测试、本振(LO) |
| 余弦 | GR_COS_WAVE |
(y[n] = A\cos(\phi[n])+\text{offset}) | 同上(相位差 90°) |
| 方波/脉冲 | GR_SQR_WAVE |
相位 (\phi[n] < 0) 为高电平 (A),否则为 offset | 数字时钟、50% 占空比脉冲 |
| 三角/锯齿 | GR_TRI_WAVE / GR_SAW_WAVE |
分段线性函数(三角波对称,锯齿波单调) | 扫频测试、波形分析、函数发生器 |
说明:
- 相位更新:(\phi[n+1] = \phi[n] + \frac{2\pi f}{f_s}),其中 (f_s) 为采样率。
- 常数波 常用于产生固定直流偏置或作为测试信号源。
- 正弦/余弦波 是射频系统中最基本的单音信号,用于本振、载波生成。
- 方波 在数字系统中作为时钟信号,在模拟系统中可模拟理想开关。
- 三角/锯齿波 常用于扫频测试(如 VCO 线性度测试)或作为调制信号的基带波形。
相位更新:
\\phi\[n+1\] = \\phi\[n\] + \\frac{2\\pi f}{f_s}, \\quad f_s = \\text{sampling_freq}
314:318:e:\Code\suanfa\gnuradio-main\gnuradio-main\gr-analog\lib\sig_source_impl.cc
void sig_source_impl<T>::set_frequency(double frequency)
{
d_frequency = frequency;
d_nco.set_freq(2 * GR_M_PI * this->d_frequency / this->d_sampling_freq);
}
Chirp 扫频
gr-analog 无内置 Chirp 块。常用方案:
gr-blocks的vco_f:控制输入接线性 rampsig_source的 message portcmd:动态改频率
python
# 常数源(GRC 中 const_source 即 sig_source 特例)
src = analog.sig_source_f(0, analog.GR_CONST_WAVE, 0, 0, 1.5)
# 1 kHz 余弦
src = analog.sig_source_f(
samp_rate=1e6,
waveform=analog.GR_COS_WAVE,
freq=1000,
ampl=1.0,
offset=0,
phase=0
)
# 动态改频(message port)
import pmt
msg = pmt.cons(pmt.intern("freq"), pmt.from_double(2000))
src.to_basic_block().message_port_pub(pmt.intern("cmd"), msg)
流程作用
- 发射端:无外部输入时的测试源
- 接收端:已知单音做校准/环路测试
- CTCSS :
nbfm_tx.py中sig_source_f生成亚音频导频
涉及语法
- 模板特化(
sig_source<gr_complex>单独work()) std::fill_n批量填充- PMT message handler + lambda
gr::thread::scoped_lock线程安全
5.3.3 各类噪声模块源码
文件 :noise_source_impl.cc、fastnoise_source_impl.cc、random_uniform_source_impl.cc
随机数引擎 :gnuradio-runtime/lib/math/random.cc
噪声类型与公式
| 类型 | 枚举 | 生成公式 | 流程作用 |
|---|---|---|---|
| 均匀 | GR_UNIFORM |
(x = A(2U-1), U\sim[0,1)) | 量化噪声、通用测试 |
| 高斯 | GR_GAUSSIAN |
Marsaglia 极坐标法 → (N(0,1)) 再 ×A | AWGN 信道仿真 |
| 拉普拉斯 | GR_LAPLACIAN |
(x=\ln(2U)) 或 (-\ln(2(1-U))) | 脉冲噪声、非高斯信道 |
| 脉冲 | GR_IMPULSE |
稀疏大尖峰 | 突发干扰仿真 |
高斯(Marsaglia):
s = x^2+y^2 \< 1 \\Rightarrow z = x\\sqrt{\\frac{-2\\ln s}{s}}, \\quad y\\sqrt{\\frac{-2\\ln s}{s}}
拉普拉斯(逆变换):
f(x) = \\frac{1}{2}e\^{-\|x\|} \\Rightarrow X = \\pm\\ln(2U)
复数高斯:rayleigh_complex() = gr_complex(gasdev(), gasdev()),幅度除以 (\sqrt{2}) 保证总功率。
fastnoise_source 加速
- 构造时预生成样本池
d_samples - 运行时用
xoroshiro128p随机索引取样本 - 适合高吞吐、对实时性要求高的仿真
接口调用
python
# 实时高斯噪声
noise = analog.noise_source_f(analog.GR_GAUSSIAN, ampl=0.1, seed=42)
# 预生成池(更快)
fast_noise = analog.fastnoise_source_f(
analog.GR_GAUSSIAN, ampl=0.1, seed=42, samples=8192)
# 整数均匀随机
rand_int = analog.random_uniform_source_i(minimum=0, maximum=256, seed=0)
流程作用
信号源 → [+] ← 噪声源 → 被测模块(解调器/AGC)
用于 BER 测试、灵敏度评估、算法鲁棒性验证。
涉及语法
switch(d_type)多态分支- 模板 + 复数特化构造函数
uint64_t seed、Boost/Mersenne Twister 随机引擎- 位掩码加速:
idx = xoroshiro128p_next(d_state) & d_bitmask
5.3.4 AM 调幅 / 包络检波 / 平方检波
AM 解调不在 C++ 单块中 ,而是 Python 层次块 am_demod.py。
AM 数学模型
发射:(s(t) = A_c[1 + m(t)]\cos(\omega_c t)),(m(t)) 为音频。
包络检波(GNU Radio 实现)
37:48:e:\Code\suanfa\gnuradio-main\gnuradio-main\gr-analog\python\analog\am_demod.py
MAG = blocks.complex_to_mag()
DCR = blocks.add_const_ff(-1.0)
LPF = filter.fir_filter_fff(audio_decim, audio_taps)
self.connect(self, MAG, DCR, LPF, self)
| 步骤 | 公式 | 作用 |
|---|---|---|
| 下变频后复基带 | (z(t)=A_c(1+m(t))e^{j\phi}) | 输入 |
| 包络检波 | (|z| \approx A_c(1+m(t))) | 去相位 |
| 去载波 DC | (|z|-1 \approx m(t)) | 恢复调制 |
| 低通滤波 | 滤除高频 | 得音频 |
平方检波(原理对比,非默认实现)
\|z\|\^2 = A_c^2(1+m(t))^2 \\approx A_c\^2(1+2m(t))
低通后可得 (m(t)),但存在二次失真 。GNU Radio 用 blocks.complex_to_mag(线性包络),不用 complex_to_mag_squared。
流程位置
天线 → 下变频 → [am_demod_cf] → 音频输出
↑ 包络检波链
接口调用
python
from gnuradio import analog
# 通用 AM 解调
demod = analog.am_demod_cf(
channel_rate=48000,
audio_decim=4,
audio_pass=5000,
audio_stop=5500
)
# 广播 AM 标准 10K0A3E
demod = analog.demod_10k0a3e_cf(channel_rate=48000, audio_decim=4)
涉及语法
- Python 层次块
gr.hier_block2 filter.optfir.low_pass设计 FIR- 块连接
self.connect(self, MAG, DCR, LPF, self)
5.3.5 FM 宽带/窄带、正交解调、延迟相乘解调
FM 调制器
文件 :frequency_modulator_fc_impl.cc
y\[n\] = e\^{j\\phi\[n\]}, \\quad \\phi\[n\] = \\phi\[n-1\] + k\\cdot x\[n\], \\quad k = 2\\pi\\frac{f_\\Delta}{f_s}
| 模式 | 最大频偏 (f_\Delta) | 典型用途 |
|---|---|---|
| NBFM | 5 kHz | 对讲机 |
| WBFM | 75 kHz | 广播 FM |
正交解调 quadrature_demod_cf
文件 :quadrature_demod_cf_impl.cc
d\[n\] = z\[n\]\\cdot z\^\*\[n-1\], \\quad y\[n\] = G\\cdot\\arg(d\[n\]) = G\\cdot\\mathrm{atan2}(\\Im d, \\Re d)
增益:(G = \frac{f_s}{2\pi f_\Delta}),将 rad/sample 转为归一化基带。
流程作用:FM 接收核心,输出近似音频 (m(t))。
延迟相乘解调 fmdet_cf
文件 :fmdet_cf_impl.cc
用 5 点滑动窗口做数值微分 (\dot{S}),再算瞬时频率:
\\hat{f} = \\frac{\\Re(S)\\Im(\\dot{S}) - \\Im(S)\\Re(\\dot{S})}{\|S\|\^2}
流程作用 :WBFM 立体声接收(wfm_rcv_fmdet),对宽频偏更稳健。
NBFM vs WBFM 收发链
| 发射 | 接收 | |
|---|---|---|
| NBFM | nbfm_tx:preemph + frequency_modulator_fc(k=2π·5k/fs) |
nbfm_rx:quadrature_demod + deemph + LPF |
| WBFM | wfm_tx:k=2π·75k/fs |
wfm_rcv:quad_demod + audio_filter + deemph |
接口调用
python
import math
from gnuradio import analog
# FM 调制
k_tx = 2 * math.pi * 5000 / samp_rate
mod = analog.frequency_modulator_fc(k_tx)
# FM 解调
k_rx = samp_rate / (2 * math.pi * 5000)
demod = analog.quadrature_demod_cf(k_rx)
# 完整 NBFM 接收
rx = analog.nbfm_rx(audio_rate=48000, quad_rate=240000)
# 完整 WBFM 接收
rx = analog.wfm_rcv(quad_rate=240000, audio_decimation=10)
# fmdet 解调(宽频偏/立体声)
det = analog.fmdet_cf(samplerate=fs, freq_low=-125e3, freq_high=125e3, scl=0.05)
涉及语法
set_history(2)访问前一采样- VOLK:
volk_32fc_x2_multiply_conjugate_32fc gr::fxpt::sincos定点三角函数std::fmod相位折叠到 ([-\pi,\pi))
5.3.6 PM 调相调制解调
文件 :phase_modulator_fc_impl.cc
PM 与 FM 核心区别
| FM | PM | |
|---|---|---|
| 相位 | 累积 (\phi[n]=\phi[n-1]+kx[n]) | 瞬时 (\phi[n]=kx[n]) |
| 公式 | (y=e^{j\phi[n]}) | (y=e^{jkx[n]}) |
| 对 DC | 恒定频偏 | 恒定相位偏移 |
46:50:e:\Code\suanfa\gnuradio-main\gnuradio-main\gr-analog\lib\phase_modulator_fc_impl.cc
for (int i = 0; i < noutput_items; i++) {
d_phase = d_sensitivity * in[i];
gr::sincosf(d_phase, &oq, &oi);
out[i] = gr_complex(oi, oq);
}
PM 解调
gr-analog 无专用 PM 解调块 。可复用 quadrature_demod_cf,但输出是 (m[n]-m[n-1])(相位差分),需积分恢复 (m[n])。
流程作用
- PM 调制:数字 PM 通信、某些卫星链路
- 相位偏移:
phase_modulator直接映射基带→相位
接口调用
python
pm_mod = analog.phase_modulator_fc(sensitivity=1.0)
pm_mod.set_sensitivity(2.0)
pm_mod.set_phase(0.0)
5.3.7 AGC 自动增益控制
GNU Radio 提供 4 种 AGC ,核心在 include/gnuradio/analog/agc.h、agc2.h。
单速率反馈 AGC(agc_cc)
y\[n\] = G\[n\]\\cdot x\[n
]
G\[n+1\] = G\[n\] + \\alpha\\big(\\text{ref} - \|y\[n\]\|\\big)
幅值稳定原理:输出低于参考值 → 增益增大;反之减小,最终 (|y|\approx\text{ref})。
双速率 AGC(agc2_cc)
- 信号变强:
attack_rate快速降增益 - 信号变弱:
decay_rate慢速升增益
AGC3(agc3_cc_impl.cc)
每 iir_update_decim 个样本更新一次:
G \\leftarrow G(1-\\text{rate}) + \\frac{\\text{ref}}{\\text{mag}}\\cdot\\text{rate}
前馈 AGC(feedforward_agc_cc)
G = \\frac{\\text{ref}}{\\max(\|x\[n-N+1\]\|,\\ldots,\|x\[n\]\|)}
无反馈环路,延迟 = 窗口长度。
流程作用
弱信号输入 → [AGC] → 稳定幅度 → 解调器/ADC
放在解调前或 IQ 校正后,防止大信号饱和、小信号淹没。
接口调用
python
# 反馈 AGC
agc = analog.agc_cc(rate=1e-4, reference=1.0, gain=1.0, max_gain=0)
agc = analog.agc_ff(rate=1e-4, reference=1.0, gain=1.0)
# 双速率
agc2 = analog.agc2_cc(
attack_rate=1e-1, decay_rate=1e-2,
reference=1.0, gain=1.0, max_gain=0)
# AGC3
agc3 = analog.agc3_cc(
attack_rate=1e-1, decay_rate=1e-2,
reference=1.0, gain=1.0,
iir_update_decim=1, max_gain=0)
# 前馈
ff_agc = analog.feedforward_agc_cc(nsamples=1024, reference=1.0)
涉及语法
- Kernel 类内联 (header 中实现
scale()) - 块类多重继承:
class agc_cc_impl : public agc_cc, kernel::agc_cc - VOLK 批量缩放
5.3.8 VCO 与 NCO
NCO(数控振荡器)--- 固定频率
文件 :gnuradio-runtime/include/gnuradio/nco.h
用于 sig_source、PLL 参考输出。
\\phi\[n+1\] = \\phi\[n\] + \\omega, \\quad \\omega = \\frac{2\\pi f}{f_s}\\ \\text{(固定)}
VCO(压控振荡器)--- 输入控制频率
文件 :gnuradio-runtime/lib/math/vco.h
块在 gr-blocks :vco_f、vco_c。
\\phi\[n+1\] = \\phi\[n\] + k\\cdot x\[n\], \\quad y\[n\] = A\\cos\\phi\[n\]\\ \\text{或}\\ Ae\^{j\\phi\[n\]}
frequency_modulator 与 VCO 关系
FM 调制器 = 积分器 + NCO:
\\phi\[n\] = \\sum kx\[i\] \\Rightarrow y\[n\]=e\^{j\\phi\[n\]}
效果等价于 VCO,但实现在 gr-analog。
PLL 中的 VCO
文件 :pll_refout_cc_impl.cc、pll_carriertracking_cc_impl.cc
继承 blocks::control_loop,二阶环路:
f \\leftarrow f + \\beta e, \\quad \\phi \\leftarrow \\phi + f + \\alpha e
(e) 为相位误差,输出 (e^{j\phi}) 作本地振荡。
VCO = Voltage Controlled Oscillator(压控振荡器)
- 输入:控制电压(在软件里是一般 float 样本流)
- 输出:振荡波形(正弦或复指数 (e^{j\phi}))
- 核心关系:控制电压越大 → 振荡频率越高
实际作用举例
-
FM 发射 :音频 → VCO → 频率随音频变化 → FM 波
(
gr-analog的frequency_modulator_fc是"积分 + 振荡",效果类似 VCO) -
Chirp 雷达/扫频:线性 ramp 接 VCO 输入 → 频率线性升高
-
PLL 内部:环路根据误差调整 VCO 频率,锁定输入信号
一句话:VCO 就是**"输入什么电压/数值,就振荡什么频率"**的振荡器;在 SDR 里用相位累加 + sin/cos 软件实现。
对比与流程
| NCO | VCO | |
|---|---|---|
| 频率 | 参数固定 | 随输入变 |
| 所在 | runtime + gr-analog | gr-blocks |
| 用途 | 本振、测试音 | Chirp、FM、PLL |
接口调用
python
# NCO 信号源(gr-analog)
src = analog.sig_source_c(samp_rate, analog.GR_COS_WAVE, 1e6, 1.0)
# VCO(gr-blocks)
from gnuradio import blocks
vco = blocks.vco_f(sampling_rate=samp_rate, sensitivity=1.0, amplitude=1.0)
# PLL 载波跟踪(gr-analog)
pll = analog.pll_carriertracking_cc(loop_bw=0.01, max_freq=0.5, min_freq=-0.5)
pll_freq = analog.pll_freqdet_cf(loop_bw=0.01, max_freq=0.5, min_freq=-0.5)
pll_ref = analog.pll_refout_cc(loop_bw=0.01, max_freq=0.5, min_freq=-0.5)
5.3.9 WBFM:限幅与去加重
宽带 FM 发射链 wfm_tx.py
音频 → [插值] → fm_preemph → frequency_modulator_fc → 复基带
预加重传递函数(模拟):
H(s) = \\frac{s + 1/\\tau}{s + 1/\\tau_2}, \\quad \\tau=75\\mu s\\ \\text{(美式)}
数字实现:双线性变换,6 dB/oct 提升高频,补偿信道高频损耗。
限幅 rail_ff
文件 :rail_ff_impl.cc
y = \\text{mid} + \\mathrm{clip}(x - \\text{mid}, \\text{clip})
流程作用:调制前防止过调制/削波,保护 FM 频偏不超限。
去加重 fm_deemph
文件 :fm_emph.py
H(s) = \\frac{1/\\tau}{s + 1/\\tau}
双线性变换步骤:
- (\omega_c = 1/\tau)
- 预畸变:(\omega_{ca} = 2f_s\tan(\omega_c/2f_s))
- 得 IIR 系数
btaps/ataps
流程作用:接收端补偿发射预加重,恢复平坦音频频响(-6 dB/oct 滚降)。
WBFM 接收链 wfm_rcv.py
IQ → quadrature_demod_cf → audio_filter(decim) → fm_deemph → 音频
接口调用
python
# 完整 WBFM 发射/接收
tx = analog.wfm_tx(audio_rate=48000, quad_rate=240000, max_dev=75e3)
rx = analog.wfm_rcv(quad_rate=240000, audio_decimation=10, deemph_tau=75e-6)
# 单独预/去加重
from gnuradio.analog.fm_emph import fm_preemph, fm_deemph
pre = fm_preemph(fs=240000, tau=75e-6)
de = fm_deemph(fs=48000, tau=75e-6)
# 限幅
rail = analog.rail_ff(lo=-1.0, hi=1.0)
5.3.10 μ律/A律压扩
重要:不在 gr-analog,在 gr-vocoder。
原理
压扩(Companding)在量化前压缩动态范围,扩大量化后小信号 SNR:
μ律(北美):
F(x) = \\mathrm{sgn}(x)\\frac{\\ln(1+\\mu\|x\|)}{\\ln(1+\\mu)}, \\quad \\mu=255
A律(欧洲):
分段线性近似对数曲线,13 bit → 8 bit PCM。
实现
文件 :gr-vocoder/lib/alaw_encode_sb_impl.cc、ulaw_encode_sb_impl.cc
调用 ITU-T G.711 库 g7xx/g72x.h:
cpp
out[i] = linear2alaw(in[i]); // 或 linear2ulaw
流程作用
语音 float → [μ/A 编码] → 8bit PCM → 信道/存储
↓
[μ/A 解码] → 恢复语音
用于电话系统、VoIP、G.711 语音链路,不是 FM/AM 射频链路的标准环节。
接口调用
python
from gnuradio import vocoder
enc = vocoder.ulaw_encode_sb()
dec = vocoder.ulaw_decode_bs()
# 或
enc = vocoder.alaw_encode_sb()
dec = vocoder.alaw_decode_bs()
总览:完整广播 FM 收发与模块对应
WBFM 接收
信道测试
WBFM 发射
麦克风 float
fm_preemph
rail_ff 可选限幅
frequency_modulator_fc
复基带 IQ
noise_source AWGN
AGC 可选
quadrature_demod_cf
FIR 音频滤波
fm_deemph
扬声器 float
语法知识汇总
| 语法/模式 | 出现位置 | 用途 |
|---|---|---|
| C++ 模板 + 特化 | sig_source<T>、noise_source<T> |
多数据类型 |
工厂 make() + sptr |
所有块 | 统一创建接口 |
sync_block / general_work |
大部分块 | 1:1 或变比率 |
| Kernel 内联类 | kernel::agc_cc |
高性能核心算法 |
| VOLK SIMD | quadrature_demod、AGC |
向量加速 |
fxpt_nco / fxpt::sincos |
sig_source、FM 调制 | 定点快速三角 |
| PMT + message port | sig_source、delay 类 | 运行时改参数 |
| Python hier_block2 | am_demod、wfm_tx/rx | 拼装完整收发机 |
| 双线性变换 IIR | fm_emph.py | 预/去加重滤波器设计 |
Python 快速参考表
| 功能 | 调用 |
|---|---|
| 正弦源 | analog.sig_source_f(fs, analog.GR_COS_WAVE, freq, amp) |
| 高斯噪声 | analog.noise_source_f(analog.GR_GAUSSIAN, ampl, seed) |
| AM 解调 | analog.am_demod_cf(...) 或 demod_10k0a3e_cf(...) |
| FM 调制 | analog.frequency_modulator_fc(k) |
| FM 解调 | analog.quadrature_demod_cf(gain) |
| PM 调制 | analog.phase_modulator_fc(sensitivity) |
| AGC | analog.agc_cc(...) / agc2_cc(...) |
| NBFM 收发 | analog.nbfm_tx(...) / analog.nbfm_rx(...) |
| WBFM 收发 | analog.wfm_tx(...) / analog.wfm_rcv(...) |
| 限幅 | analog.rail_ff(lo, hi) |
| 去加重 | from gnuradio.analog.fm_emph import fm_deemph |
| VCO | blocks.vco_f(fs, sens, amp)(gr-blocks) |
| μ/A 律 | vocoder.ulaw_encode_sb()(gr-vocoder) |