5.4 FM 广播接收机流图实战


5.4 FM 广播接收机流图实战

本节摘要:本节把第 4.2 节的 Python FM 解调逐行翻译成 GRC 流图:RTL-SDR Source、RF 与 IF 滤波、WBFM Receive 模块、重采样、音频输出,外加 Variable 与 Slider 实现的实时调谐。每个模块的参数都给出推荐值与理由,并对照第 4 章代码建立"模块与代码行"的映射表。

从代码到流图:一张映射表

先把 4.2 节脚本与流图模块对应起来,你会发现翻译几乎是一对一的:

4.2 节代码 GNU Radio 模块 关键参数
np.fromfile 采集 SoapySDR Source driver=rtlsdr,samp_rate
firwin 200 kHz 低通 Low Pass Filter cutoff 200 kHz,transition 20 kHz
angle 共轭乘积 WBFM Receive quad_rate 与 audio_rate
demod[::42] 抽取 Rational Resampler 内插 1,抽取 42
去加重 lfilter (WBFM Receive 内置) tau 75e-6
wave 写文件 Audio Sink 48000 Hz

注意去加重与鉴频在 GNU Radio 里被打包进 WBFM Receive 一个模块——工程封装常把"总是同时出现"的步骤合并。模块的 quad_rate 参数(鉴频前速率)应设为 200 kHz 左右,audio_rate 设 48 kHz,比例由模块内部的重采样自动完成。

完整流图清单

按顺序搭建(括号内为参数要点):

  1. Variable samp_rate = 2048000(全图速率基准)。
  2. SoapySDR Source(driver=rtlsdr;Freq 用变量 freq;Gain 30 dB,Manual 模式)。
  3. Low Pass Filter(Decimation 设 10:输出降到 204.8 kSPS;cutoff 100 kHz,transition 10 kHz。对称带宽下 100 kHz 截止即保留正负 100 kHz,覆盖 FM 信号)。
  4. WBFM Receive(quad_rate 204800,audio_rate 48000;内部完成鉴频、抽取与去加重)。
  5. Rational Resampler(204800 到 48000 非整数比:Interpolation 30,Decimation 128,即 0.2344 倍;若 WBFM 已出 48 kHz 则本块可省)。
  6. Audio Sink(48000 Hz,设备选系统默认)。
  7. QT GUI Frequency Sink(挂在 Source 后,Center Frequency 绑 freq 变量,用于实时看信号位置)。
  8. Variable 与 QT GUI Range(新建 id 为 freq 的 Range 控件:起点 87.5e6,终点 108e6,步进 100e3——拖动滑块即可全频段调谐)。

运行后拖动调谐滑块:频谱窗口里整片频段横向滚动(实际是中心频率在动),听到下一个电台时停住,微调增益到音质最干净。一台可以用旋钮操作的软件收音机完成。

图:FM 广播接收机的完整流图结构

图:FM 广播接收机的完整流图结构

调试实录:三类典型故障

**故障一,无声但频谱正常。**按链路逐块排查速率:Source 2.048 MSPS、滤波后 204.8 kSPS、WBFM 输出 48 kHz——任一处断言失败(比如 WBFM 的 quad_rate 填了 2.048e6 而上游实际已是 204.8 kSPS),音频就是静音或纯噪声。速率是流图的血压,第一件事就是量它。

**故障二,声音有周期性抽搐。**这是音频设备与样本速率不匹配的典型表现:重采样后实际速率与 Audio Sink 声明的 48 kHz 有偏差,缓冲周期性空转。解法是统一用 Rational Resampler 精确换算,或在 WBFM 参数里直接对齐 48000。

**故障三,噪声底极高且不受增益影响。**八成是天线附近有强干扰源(USB 3.0 口、显示器电源),或者是过增益导致 ADC 削顶——削顶把宽带噪声"焊死"在信号里。把增益从 40 降到 25,噪声底应明显变化;不动则是环境干扰,换 USB 2.0 口或加磁环。

变式扩展

流图搭通后有三个自然的进阶方向:加 RDS 模块(RTL-SDR 的 FM 广播带数字副载波,台名与电台文本可解码显示);加 QT GUI Sink 的偏移参数绕开直流尖峰;把 Audio Sink 换成 File Sink 录制 WAV,做无人值守定时录音。每个方向都只加一个块——流图架构的扩展性就体现在这里。

对照一下 4.2 节的手写代码:三十行 Python 一次成型、但改参数要重跑;GRC 流图拖了十来个块、却换来实时调参与旋钮交互。两种形态是同一门技术的两种性格——理解靠前者,生产靠后者。

常见问题

问题:WBFM Receive 和第 4 章手写的鉴频结果一样吗?

数值上略有差异,感知上无区别。GNU Radio 的实现是 90 度移相乘法鉴频(即正交鉴频的工程形态),与共轭乘积取辐角在数学上等价;模块内部还做了量化与查找表优化来省算力。这正是"原理与实现可以不同、输出语义一致"的典型例子。

问题:立体声广播的左右声道怎么分开?

FM 广播把左右声道的和信号(L 加 R)放主信道,差信号(L 减 R)调制到 38 kHz 的副载波上。接收端用 19 kHz 导频恢复副载波、解出差信号、加减还原左右声道——加一个 Stereo Demod 相关的模块链即可。主信道只有和信号,这就是 5.4 节的单声道输出听起来正常但无立体感的原因。

问题:为什么我的流图 CPU 占用比 SDR# 高很多?

GRC 默认参数偏保守:滤波器过渡带窄、FFT 显示点数多、块缓冲大。按第 6 章账本放宽过渡带、降低显示刷新率、合并抽取级,占用通常能降一半。另外 Python 生成的流图比手写 C++ 的调度开销略高,属正常代价。

本节要点回顾

  • 模块与代码一一对应:Source 采集、LPF 限带、WBFM 鉴频加重、Resampler 速率、Audio Sink 输出。
  • 速率一致性是第一调试对象:逐块核对 MSPS 到 kSPS 的递减链条。
  • 抽搐与高噪底:分别是速率失配与环境干扰或削顶的指纹。
  • 流图的扩展性:RDS、录制、频偏绕开直流尖峰都是加一个块的事。

到此为止,滤波都只是"拿来就用"的模块。下一章打开滤波器本身:抽头、响应、设计工具,让你知道 Low Pass Filter 块里住着什么。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U