从电磁波到比特:用具体数字读懂 FM 与 WiFi 的 IQ 解调

从电磁波到比特:用具体数字读懂 FM 与 WiFi 的 IQ 解调

一篇面向 SDR 初学者与爱好者的文章。通篇用"具体数字 + 手算"代替抽象公式,把 FM 收音、I/Q、PCM,以及 WiFi beacon / QAM / 5G 这几件看似不相干的事,串成同一条主线:原始 IQ 是通用货币,解调是把这串数字翻译成含义。


摘要

软件定义无线电(SDR)最常见的困惑是:明明天线收到了信号,为什么还要额外的"解码器"才能听懂?本文以一个 HackRF 为例,从最基本的"频率是什么"讲起,用一组傻瓜数字手算:

  • FM 发射端如何把音频变成电磁波(调制);
  • 接收端如何把 IQ 样本变回声波(解调、PCM);
  • WiFi 的 beacon 为何能被"听"出来,以及它和 FM 的本质异同;
  • 一个 IQ 点 (0.8, 0.2) 在 BPSK 与 16-QAM 下为何解出完全不同的比特;
  • 5G 为何是同一套思想的翻版;
  • 最关键的一点:HackRF 是"哑"的,它只产 IQ,从不解析协议。

读完你应能建立一句核心直觉:IQ 文件 ≈ 原始采样流(像 PCM/WAV),但解码出的产物取决于你用什么协议去解释它。


一、先建立直觉:频率、混频与 I/Q

1.1 频率是什么

一个正弦波 s(t) = cos(2π f t)。频率 f 决定"每秒转多少圈"。相位 φ(t) = 2π f t 是转过的总角度;频率就是相位对时间的导数:

复制代码
f(t) = (1 / 2π) · dφ/dt

记住这句:"频率 = 相位变化有多快"。后面 FM 调制与解调全靠它。

1.2 本振(LO)与混频:把"中心频点搬到 0"

真实电台在 100 MHz 这种高频,ADC 采样不了那么快。SDR 的做法是用一个本振(LO) 产生同频余弦/正弦,与接收信号相乘(混频),把高频"搬"到基带(中心频点附近 ≈ 0 Hz)。

  • 混频后得到 I(同相,乘 cos)Q(正交,乘 sin) 两路。
  • 复数基带信号就是 x = I + jQ,这就是 IQ 样本

HackRF 每采样一次,就吐出一对 (I, Q) 浮点数。这一对数字就是后面一切的起点。

1.3 负频率为啥存在

基带里会出现"负频率",它只是复数表示下的数学产物:一个旋转向量顺时针转,频率记负;逆时针转记正。对理解解调不碍事,记住"IQ 平面上的一个点 = 当前这一刻的波形状态"即可。


二、FM 调制:音频如何"爬"上载波(发)

2.1 核心公式

调频(FM)的本质:瞬时频率随音频 m(t) 上下摆动

复制代码
f_inst(t) = f_c + k · m(t)
  • f_c:载波中心频率(如 103 MHz)
  • k:灵敏度
  • m(t):音频,范围约 [-1, +1]

因为频率是相位的导数,对时间积分得到相位:

复制代码
φ(t) = 2π f_c t + 2π k ∫ m(t) dt
s(t) = cos( φ(t) )      # 这就是 antennae 上发出的电磁波(基带复数形式)

关键直觉 :音频 m(t) 是 sin,进到相位里变成 -β·cos(sin 积分是 -cos)。这就是"音频的瞬时值影响频率大小"的数学来源。

2.2 手算示例(常量音频,看疏密)

为便于手算,下面把"频率"定义为每采样步推进的圈数(cycles/sample) ,不是 Hz。设 f_c = 0.15k = 0.05

  • 音频 m = +1f = 0.20 圈/步 → 每步相位前进 360° × 0.20 = 72°
  • 音频 m = -1f = 0.10 圈/步 → 每步前进 36°

从相位 0 开始累加,算波形 s = cos(φ)

音频 m 每步相位前进 累计相位 φ 波形 s = cos φ
0 +1 72° 1.000
1 +1 72° 72° 0.309
2 +1 72° 144° -0.809
3 +1 72° 216° -0.809
4 +1 72° 288° 0.309
5 +1 72° 360° 1.000 ← 5 步一圈(密)

同一个表,但音频 m = -1(每步只前进 36°):

音频 m 每步相位前进 累计相位 φ 波形 s = cos φ
0 -1 36° 1.000
1 -1 36° 36° 0.809
... -1 36° ... ...
10 -1 36° 360° 1.000 ← 10 步一圈(疏)

结论:音频大 → 频率高 → 波形一圈只用 5 步(密);音频小 → 频率低 → 一圈用 10 步(疏)。"调制"就是把声音的"大小"翻译成电波的"疏密"。

2.3 正弦音频的逐步手算

让音频是个正弦 m = [0, +0.7, +1.0, +0.7, 0, -0.7, -1.0, -0.7],仍用 f_c=0.15, k=0.05

音频 m 瞬时频率 f=0.15+0.05m 每步相位前进(=360f) 累计相位 波形 cos(累计)
0 0.0 0.150 54.0° 54° 0.588
1 +0.7 0.185 66.6° 120.6° -0.515
2 +1.0 0.200 72.0° 192.6° -0.976
3 +0.7 0.185 66.6° 259.2° -0.190
4 0.0 0.150 54.0° 313.2° 0.687
5 -0.7 0.115 41.4° 354.6° 0.997
6 -1.0 0.100 36.0° 390.6° 0.771
7 -0.7 0.115 41.4° 432.0° 0.809

数一数波形的"摆动快慢":第 1~3 步(音频为正,频率 0.185~0.200)相位每步跳 ~70°,波形猛变 → 频率高;第 5~6 步(音频为负,频率 0.10~0.115)相位每步只跳 ~40°,波形慢变 → 频率低。

2.4 一张图看疏密

把上面这种波形画出来(蓝线是电波 s(t),橙线是音频 m(t)):

盯着看:橙线往上爬(音频大)时,蓝线挤成一簇一簇(密 = 频率高);橙线往下掉(音频小/负)时,蓝线拉开变疏(频率低)。这就是 FM 调制的全部秘密。


三、FM 解调:IQ 如何变回音频(收)

接收端先把射频下变频成复数基带 x = cos φ + j sin φ,然后解调。核心模块 quadrature_demod_cf 干的事,就是下面这行:

复制代码
Δφ[n] = arg( x[n] · conj(x[n-1]) )      # 相邻样本的相位差
音频 = Δφ[n] × gain

conj(x[n-1]) 是取共轭;两复数相乘的辐角 恰好等于"从 xn-1 转到 xn 转过的角度",即相位差。arg 就是 atan2

3.1 手算:相邻样本相位差 → 音频

用第 2.3 节那组 IQ(取 I=cosφ, Q=sinφ),对每对算 x[n]·conj(x[n-1]) 再取 arg

n=2x[2]=(cos120.6°, sin120.6°)=(−0.515, 0.857)x[1]=(0.588, 0.809) 的共轭 (0.588, −0.809)

复制代码
乘积 = (−0.515·0.588 − 0.857·(−0.809)) + j(0.857·0.588 − (−0.515)·0.809)
     = (−0.303 + 0.693) + j(0.504 + 0.417)
     = (0.390, 0.921)
arg = atan2(0.921, 0.390) ≈ 67°   → 音频为正 ✓(对应 m=+0.7 附近)

全部结果(节选过渡):

过渡 arg(Δφ) 还原的音频趋势
0→1 +67° 正(音频上升)
1→2 +72° 正(峰值)
2→3 +67°
3→4 +54° 回落到 0
4→5 +41° 负(音频转负)
5→6 +36° 负(谷值)

还原出的相位差序列,和你发射前喂进去的音频 m 完全同向------这就是解调

3.2 相位差 → 频率 → PCM(真实参数)

上面是玩具"圈/步",现在接回真实 FM 链路。设:

  • 采样率 samp_rate = 240000 Hz(resampler 输出的 quad rate)
  • 最大频偏 max_dev = 75000 Hz
  • 灵敏度 k = 75000(PCM=±1 时频偏 ±75k)

两向公式:

复制代码
发:  Δf = k · m              (m 即归一化 PCM,范围 ±1)
     Δφ = 2π · Δf / samp_rate

收:  Δf = Δφ · samp_rate / 2π
     m  = Δf / k

取音频 PCM m = [0, +0.5, +0.5, 0, −0.5, −0.5, 0],算成数字:

音频 PCM m 频偏 Δf=75000·m 相位差 Δφ=2π·Δf/240k 收端还原 Δf 还原 m 16-bit PCM=round(m·32767)
0 0 Hz 0 Hz 0.0 0
+0.5 +37500 Hz +56.25° +37500 Hz +0.5 +16383
+0.5 +37500 Hz +56.25° +37500 Hz +0.5 +16383
0 0 Hz 0 Hz 0.0 0
−0.5 −37500 Hz −56.25° −37500 Hz −0.5 −16383
−0.5 −37500 Hz −56.25° −37500 Hz −0.5 −16383
0 0 Hz 0 Hz 0.0 0

那个 gain 现在也对上了:quadrature_demod_cf 的增益 gain = samp_rate/(2π·max_dev) = 240000/(2π·75000) ≈ 0.5093

复制代码
还原 PCM m = Δφ(弧度) × 0.5093 = (2π·37500/240000) × 0.5093 = 37500/75000 = +0.5  ✓

3.3 音频即 PCM:float 与 int16

解调出来的"音频数据"就是 PCM------一串按采样时刻排列的振幅数字。

  • GNU Radio 的 audio_sink[-1, 1]float PCM
  • .wav 文件里存 [-32768, 32767]int16 PCM,就是 float 乘以 32767;
  • 所以"音频数据" = 这串 PCM 数字。

完整闭环:

复制代码
[发射] WAV(int16) ─/32767→ m(PCM ±1) ─FM调制→ IQ → 电波
[接收] 电波 → IQ ─quadrature_demod(gain)→ m(PCM ±1) ─×32767→ WAV(int16)

四、音色与音高:同一结论的两个视角

两个人音高相同、音色不同,频谱图一看就懂:

  • 200 Hz 那根基频杆一样高 → 基频相同 → 大脑判"音高一样"(音高 = 基频位置)。
  • 400/600 Hz 谐波杆高度不同 → 音色不同(音色 = 谐波的相对能量,即波形包络)。

时域看"由哪些频率组成摆动"(音色),频域看"这些频率怎么随时间摆"(音高+音色),FM 把时域摆动原样搬上载波、解调再原样搬回。


五、转到 WiFi:同样的 IQ,不同的故事

5.1 频谱监听与 beacon

HackRF 调到 2.4 GHz(如信道 6 = 2.437 GHz),采样率 20 MHz(刚好罩住一个 20 MHz WiFi 信道),用 QT GUI 的频谱+瀑布图就能看到 WiFi 活动:突发传输在瀑布图里是一条条亮纹。beacon 是 AP 明文广播的管理帧(SSID 就写在里面)。

5.2 IQ 是原料,不携带调制标签

你存的 IQ 文件(wifi_iq.cfile)只是长串 (I, Q) 数字,不记录用了哪种调制。它和 raw PCM/WAV 是同一类东西------都是"还没解码的采样流"。调制方式既不写在文件里,HackRF 也不知道。

5.3 WiFi 数据不是 PCM,是比特/帧

FM 音频 WiFi
原始 IQ 文件 复数采样流 复数采样流(同一类原料)
解调第一脚 相位差 → 频率 同步 → FFT(OFDM) → 均衡
一个采样代表啥 频率偏移 ∝ 一个音频振幅(PCM) 星座点(QAM) ∝ 几个比特
解码最终输出 PCM 数字(声音振幅) 比特 / 802.11 帧(SSID 等)

WiFi 用 QAM 星座把比特映射到 IQ 平面。以 QPSK 为例,一个符号(一个 IQ 点)携带 2 比特:

复制代码
(0.707, 0.707) → 00      (−0.707, 0.707) → 01
(−0.707,−0.707) → 11      (0.707,−0.707) → 10

FM:一个 IQ 样本 → 一个音频振幅数字(PCM);WiFi:一个 IQ 符号 → 几个比特。 根本差别在这。


六、WiFi 怎么知道用哪种调制:前导码 + SIGNAL + 自适应

6.1 帧结构(802.11a/g OFDM)

复制代码
┌──────────┬──────────┬───────────────────┐
│ 前导码    │ SIGNAL   │ 数据正文            │
│ STF+LTF   │ 字段     │ (按字段里的速率解)   │
└──────────┴──────────┴───────────────────┘
  已知序列      固定 BPSK     变化(QPSK/16-QAM/64-QAM)
 (同步/估信道)   (速率/长度)
  • 前导码(STF+LTF):收发双方约定好的已知序列,用于同步、信道估计,是"标尺",不携带速率。
  • SIGNAL 字段固定用 BPSK、编码率 1/2,里面写着"本帧正文用哪种调制、多长"。

6.2 为什么 SIGNAL 必须固定 BPSK

帧一开始,接收端还不知道这帧的调制。所以"速率说明"本身必须用一种双方永远约定好、无需先验知识的最稳调制来发 → BPSK。否则接收端连"该用什么调制解 SIGNAL"都不知道,会死锁。

6.3 具体例子:(0.8, 0.2) 用 BPSK 解 vs 用 16-QAM 解

假设解码器同步好,知道这是 SIGNAL 的一个 BPSK 符号。BPSK 星座只有 (+1,0)(-1,0)。收到 (0.8, 0.2) 是带噪声的 (+1,0)

复制代码
到 (+1, 0):√((0.8−1)² + (0.2−0)²) = √(0.04+0.04) = √0.08 ≈ 0.283
到 (−1, 0):√((0.8+1)² + 0.2²)     = √(3.24+0.04) = √3.28 ≈ 1.811

(+1,0)解出 bit = 0

同一个 (0.8, 0.2),若这帧正文是 16-QAM(星座 16 点,坐标在 ±0.316、±0.949 附近):

复制代码
离 (0.8,0.2) 最近的是 (0.949, 0.316) → 对应某个 4-bit 模式(如 1010)

于是 (0.8, 0.2) 在 16-QAM 下解出 4 个比特,不是 1 个。

用哪种调制解 (0.8, 0.2) 得到
BPSK 1 比特:0
16-QAM 4 比特:1010(举例)

这就是为什么调制必须先在 SIGNAL 里"自报":解码器先老实用 BPSK 解 SIGNAL,读到"正文用 16-QAM",才切换过去解正文。


七、5G 也如此:换名字,同原理

5G NR 完全同一思想,只是更名、更复杂:

WiFi (802.11) 5G NR 作用
前导码 STF/LTF PSS / SSS 小区搜索、同步
SIGNAL 字段(BPSK) PBCH(在 SSB 内,QPSK) 发 MIB:最基础系统参数
数据正文(自适应 QPSK→64-QAM) PDSCH(自适应 QPSK→256-QAM) 真正数据
(速率在 SIGNAL 写明) DCI(PDCCH 上) "你这段数据用 256-QAM、占哪些资源块"

5G 的"beacon" = SSB(Synchronization Signal Block),周期广播,里面含 PSS+SSS+PBCH。PBCH 用固定 QPSK 发 MIB,手机先读到 MIB,才知道后续怎么收。之后正文按信道质量自适应选 QPSK / 16 / 64 / 256-QAM------和 WiFi 自适应调制一模一样。

不同点:5G 在授权频段(sub-6G、甚至 24G+ 毫米波),HackRF 撑不住其带宽与 mmWave;结构上有可变子载波间隔、波束赋形,复杂得多。


八、谁来决定"怎么解析":HackRF 是哑的,软件才懂

回到最常见的误解:HackRF 不知道、也不决定用什么解析 beacon。

角色 干什么 知道调制吗
你(操作员) 把 HackRF 设到 2.437G/20M 存 IQ;再选"用 802.11 解码器" 你告诉软件"当 WiFi 解"
HackRF(硬件) 调频 + 混频 + 采样 → 输出 I/Q 完全不知道,不关心
gr-ieee802-11(软件) 跑 802.11 PHY,解帧 逐帧从 SIGNAL 字段自己读出
  • HackRF 只把波形点原样记成 (0.8, 0.2)(这是采样不是解析)。
  • "这是 WiFi"是告诉软件的(你跑的是 802.11 解码器,不是 FM 解调器)。
  • 软件也不是开头就知道每帧调制------它先拿已知前导码同步,再用固定 BPSK 读 SIGNAL,才知道正文调制。

类比:HackRF 是麦克风/录音笔(录下波形,听不懂语言);gr-ieee802-11 是懂 802.11 的翻译官(你请它来,它按 WiFi 语法翻译成文字)。麦克风永远不会自己说"这是 WiFi"。


九、动手实验与踩坑(真实可复现)

用 HackRF + GNU Radio(gr-soapy)可完整复现上述链路,几个关键经验:

  1. FM 接收端soapy_hackrf_source(1M) → rational_resampler_ccc(25/6 → 240k) → analog_wfm_rcv(240k/5 → 48k) → audio_sink。频率用 variable_qtgui_range 做成滑块(88--108 MHz)。
  2. FM 发射端wav_source(48k) → analog_wfm_tx(→240k) → rational_resampler_ccc(25/3 → 2M) → soapy_hackrf_sink(2M @ 103 MHz)。
  3. 踩坑(重要) :gr-soapy 的 HackRF 发射在 1 MHz 采样率下会持续 Soapy sink error: TIMEOUT ------这是 soapy 封装层在 1M 不把 TX key 起的 bug,与硬件无关(hackrf_transfer 在 1M 正常)。解决办法:把发射采样率提到 2 MHz 即可 ,接收端仍可用 1M。另需给 sink 的 stream_argsbuffers=64(gr-soapy 的 .grc 块不暴露该参数,需改生成的 .py)。
  4. WiFi 监听soapy_hackrf_source(20M @ 2.437G, LNA 增益 ~32) → qtgui_sink_x(频谱+瀑布) + file_sink(存 wifi_iq.cfile)。用 blocks_head 限制样本数可实现"采 N 秒自动停"。
  5. WiFi 解码wifi_iq.cfile 交给 gr-ieee802-11(需另行编译安装),其 wifi_phy 块读 IQ → 解出 beacon 的 SSID/BSSID。

合法边界:接收/观测 ISM 频段与广播 beacon、SSB/MIB 属被动频谱观察;解密他人加密流量、deauth 攻击、握手包破解等不在本文范围。


十、结语:IQ 是通用货币

把全篇收成一句:

  • IQ 样本 = 电磁波在基带的原始采样,和 PCM/WAV 一样是"一串数字",但它不标协议、不标调制。
  • FM 解调:IQ 的相位差 → 频率 → PCM(一串能播放的振幅数字)。
  • WiFi 解码:IQ 的星座点 → 最近调制点 → 比特 → 帧(能解析的文字字段,不是声音)。
  • 谁懂:HackRF 只产 IQ(哑);软件解码器按协议规范,从帧头固定的已知/稳健调制(BPSK/QPSK)逐帧读出后续调制,才解得对。

无论 FM、WiFi 还是 5G,链路都是"哑硬件采 IQ → 智能软件按协议解释" 。你存的每一份 cfile,都是同一类原料;最后长出声音还是长出 beacon,取决于你请来哪位"翻译官"。


参考配图(与本文同目录)

  • fm_modulated_wave.png --- FM 调制波形:音频(橙)与电波疏密(蓝)
  • fm_spectrum_compare.png --- 音高相同、音色不同的频谱对比
  • constellation_bpsk_16qam.png --- 同一 IQ 点 (0.8,0.2) 在 BPSK 与 16-QAM 下解出不同比特

参考实现

  • GNU Radio 3.10 + gr-soapy(soapy_hackrf_source / soapy_hackrf_sink
  • gr-ieee802-11(Bastian Bloessl):802.11 接收机,用于从 IQ 文件解码 beacon
  • hackrf_transfer:原生 libhackrf 工具,用于发射自检(验证硬件正常)
相关推荐
珠***格2 小时前
通信链路全打通:西格电力四可装置的 4G/5G + 加密认证技术详解
大数据·数据库·分布式·5g·架构·能源
纽格立科技20 小时前
5G广播 vs DRM/CDR——车载场景下的技术对比
5g
youngerwang1 天前
【从“聊天“到“执行“:MATLAB Agentic AI + MCP Server 实战——以 5G NR PDSCH 波形仿真为例】
人工智能·5g·matlab
星恒讯工业路由器2 天前
5G LAN + Wi-Fi 6融合组网:工业路由器如何为柔性产线“剪掉辫子”
网络·5g·工业路由器·工业物联网·5g la·柔性产线·5g工业路由
南京码讯光电技术有限公司3 天前
4G/5G工业CPE选型指南
5g
putItInYourHand4 天前
注入井场数据采集解决方案:LoRa + 5G边缘计算赋能智慧油田
人工智能·5g·能源·边缘计算·制造·交通物流
星恒讯工业路由器5 天前
MIMO与多天线技术:从5G到WiFi的工程解析
数据库·mysql·5g·工业物联网·mimo技术·天线隔离度·5g/wifi多天线
szarron5 天前
HT666 0.6-6GHz 定向高增益手持天线:EMC 测试与频谱定位实战指南
网络·算法·5g·信号处理·射频工程·频谱仪
youngerwang6 天前
【3GPP TS 38.104 深度解读 — NR 基站射频发射与接收】
5g·3gpp·nr基站射频发射与接收指标·协议解读