gr-analog 模拟信号模块完整源码分析

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 块。常用方案:

  1. gr-blocksvco_f:控制输入接线性 ramp
  2. sig_source 的 message port cmd:动态改频率
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)

流程作用

  • 发射端:无外部输入时的测试源
  • 接收端:已知单音做校准/环路测试
  • CTCSSnbfm_tx.pysig_source_f 生成亚音频导频

涉及语法

  • 模板特化(sig_source<gr_complex> 单独 work()
  • std::fill_n 批量填充
  • PMT message handler + lambda
  • gr::thread::scoped_lock 线程安全

5.3.3 各类噪声模块源码

文件noise_source_impl.ccfastnoise_source_impl.ccrandom_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_rxquadrature_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.hagc2.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-blocksvco_fvco_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.ccpll_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}))
  • 核心关系:控制电压越大 → 振荡频率越高

实际作用举例

  1. FM 发射 :音频 → VCO → 频率随音频变化 → FM 波

    gr-analogfrequency_modulator_fc 是"积分 + 振荡",效果类似 VCO)

  2. Chirp 雷达/扫频:线性 ramp 接 VCO 输入 → 频率线性升高

  3. 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}

双线性变换步骤:

  1. (\omega_c = 1/\tau)
  2. 预畸变:(\omega_{ca} = 2f_s\tan(\omega_c/2f_s))
  3. 得 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.cculaw_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)
相关推荐
计算机安禾12 小时前
【算法分析与设计】第8篇:贪心策略的理论基础与拟阵模型
算法
手写码匠12 小时前
手写 MoE(混合专家模型):从零实现大模型的稀疏激活架构
人工智能·深度学习·算法·aigc
MediaTea12 小时前
PyTorch:主要模块简介
人工智能·pytorch·python·深度学习·机器学习
技术小猪猪12 小时前
PromptOps:用Python构建生产级提示词工程体系
人工智能·python·ai·自动化·prompt
Black蜡笔小新12 小时前
自动化AI算法训练服务器/企业AI算力工作站DLTM赋能产业智能数字化升级
人工智能·算法·自动化
玖釉-13 小时前
「接雨水」问题的算法建模与双指针优化分析
c++·windows·算法
工业互联网专业13 小时前
国潮男装微博评论数据分析系统的设计与实现 _flask+spider
python·flask·毕业设计·源码·课程设计·spider
计算机安禾13 小时前
【算法设计与分析】第7篇:01背包问题的动态规划建模与空间优化
算法
程序员牛奶13 小时前
[Algo-3]前缀和秒杀两道区间求和题:一维 + 二维统一模板
后端·算法