1. 课程导入与仿真环境搭建

水声OFDM(正交频分复用)技术把高速数据分散到大量相互正交的子载波上传输,既能对抗水声信道的多径扩展,又能通过循环前缀(CP)吸收码间干扰,是当前水声通信研究中最常用的宽带传输方案之一。本课程的目标不是停留在公式推导,而是从零搭建一条可运行、可观测、可修改的水声OFDM收发链路仿真:从比特流出发,经过信道编码、调制映射、串并变换、IFFT、加CP、上变频,进入水声信道模型,再在接收端完成同步、去CP、FFT、信道估计与均衡、解映射与译码,最终统计误码率(BER)与误块率(BLER)。

在动手写第一行代码之前,先把整条链路的信号流向和每一级的数据形态看清楚,是后续所有章节的共同基础。下图给出了本课程采用的收发链路整体架构,标注了各节点的关键参数与数据维度,后续章节将逐级展开。

水声OFDM收发链路整体架构(示例参数:带宽 4 kHz,子载波数 N=1024,CP 长度 256) 发射端(Tx) 信源比特 随机/文件 信道编码 卷积/LDPC 星座映射 QPSK/16QAM 串并变换 → N 路 IFFT N=1024 加CP+上变频 CP=256 水声信道 多径扩展 τmax 多普勒/时变 环境噪声 + 衰落 接收端(Rx) 同步 定时/频偏 去CP+FFT N=1024 信道估计 导频/均衡 解映射+译码 BER/BLER 关键采样与参数关系(示例) 采样率 fs = 12 kHz | 子载波间隔 Δf = fs/N ≈ 11.72 Hz | 符号长度 T = N/fs ≈ 85.3 ms | CP 时长 Tcp = 256/12k ≈ 21.3 ms 有效带宽 B ≈ 4 kHz(占用子载波数约 342) | CP 需覆盖最大多径时延扩展 τmax,否则产生 ISI/ICI 建议设置的观测点(每级保存一份中间变量,便于逐级排障) ① 编码后比特 ② 映射后复符号 ③ IFFT 后时域波形 ④ 加CP后帧结构 ⑤ 信道输出(含噪声) ⑥ 均衡后星座 ⑦ 判决比特与误码位置 原则:先确认每一级维度与能量正确,再比较相邻两级差异,避免在整链路黑箱中盲目调参。

为什么选择 MATLAB 与 Python 双工具

本课程同时给出 MATLAB 与 Python 两套实现,原因在于二者在水声仿真中的分工不同。MATLAB 的通信工具箱、信号处理工具箱提供了现成的 comm.OFDMModulator、comm.RayleighChannel、berawgn 等对象,适合快速验证算法思路、绘制标准星座与误码曲线;Python 则依托 NumPy/SciPy/Matplotlib 生态,便于与深度学习框架、开源水声信道模型(如 Bellhop 的 Python 封装)以及版本管理工具衔接,适合做可复现的工程化仿真。两套代码在关键参数上保持一致,读者可对照阅读。

工具选择的一个实用判断是:如果本节任务以“验证公式与曲线形态”为主,优先 MATLAB;如果以“批量扫参、生成数据集、接入后续处理链”为主,优先 Python。本课程前段以 MATLAB 讲清原理,后段用 Python 完成参数扫描与结果汇总。

基础环境配置

MATLAB 侧建议 R2021a 及以上版本,安装 Communications Toolbox 与 Signal Processing Toolbox;Python 侧建议 3.9~3.11,核心依赖为 numpy、scipy、matplotlib,可选 scikit-commpy 用于卷积码与维特比译码。下面给出可直接执行的 Python 环境检查脚本,运行后应打印各库版本并完成一次最小 OFDM 调制解调自检:

import numpy as np, scipy, matplotlib
print("numpy", np.__version__, "| scipy", scipy.__version__)

N, CP = 1024, 256
rng = np.random.default_rng(2024)
X = (rng.integers(0, 2, N//2)*2-1) + 1j*(rng.integers(0, 2, N//2)*2-1)  # QPSK 半谱
Xf = np.concatenate([X, np.conj(X[::-1])])          # 构造共轭对称,保证实信号
x = np.fft.ifft(Xf).real
tx = np.concatenate([x[-CP:], x])                    # 加 CP
rx = tx[CP:CP+N]                                     # 理想信道:去 CP
Y = np.fft.fft(rx)
err = np.max(np.abs(Y[:N//2] - Xf[:N//2]))
print("IFFT/FFT 往返最大误差:", err)                 # 应接近 1e-12 量级

这段自检的意义在于:它把“共轭对称构造实信号—IFFT—加CP—去CP—FFT”这条最容易出维度错误和共轭错误的路径先跑通。若误差在 1e-10 以下,说明 FFT 长度、CP 截取位置、共轭对称拼接三处均正确,后续再叠加信道与噪声就不会把基础错误误判为算法问题。

仿真参数约定与首个可运行帧

为避免全文符号混乱,先固定参照约定:时间以秒为单位,频率以赫兹为单位,采样率 fs 为 12 kHz;一个 OFDM 符号含 N=1024 个采样点,CP 取 256 点;子载波间隔 Δf = fs/N ≈ 11.72 Hz,符号周期约 85.3 ms,CP 时长约 21.3 ms。CP 时长必须大于信道最大多径时延扩展 τmax,这是水声 OFDM 设计的硬约束——浅海多径常达数十毫秒,因此 CP 往往占到符号长度的 20%~25%,频谱效率的牺牲是必要代价。

建议的第一个可运行帧规模为:信息比特 4096 个,QPSK 映射后 2048 个复符号,占用约 342 个有效子载波、约 6 个 OFDM 符号。这个规模小到可以在命令行逐级打印维度,又足以观察 CP 与导频插入后的帧结构。下表给出建议的初始参数集,可直接作为配置文件起点:

参数建议值说明与判断依据
采样率 fs12 kHz需大于 2 倍最高子载波频率,留出上变频余量
FFT 点数 N1024决定 Δf 与符号长度,兼顾时频分辨率
CP 长度256须大于 τmax,示例对应约 21.3 ms
调制方式QPSK首帧用低阶调制,便于星座判读
导频间隔每 8 个子载波 1 个梳状导频,兼顾估计精度与开销
信道模型3 径 + AWGN先验证均衡,再引入时变多普勒
信噪比扫描0~20 dB,步长 2 dB每点至少 100 帧统计 BER
建议在项目根目录建立 config/、tx/、ch/、rx/、results/ 五个目录,所有参数集中写入一个配置文件,禁止在函数内部硬编码 N、CP、fs。这样后续做参数扫描时只需改配置,不必逐文件搜索替换。
常见起步错误:一是 IFFT 后未做共轭对称就直接取实部,导致频谱折叠;二是加 CP 时误取头部而非尾部,接收端去 CP 后相位全乱;三是统计 BER 时把导频位置也算进信息比特。建议每级都打印数组形状与平均功率,功率在 IFFT 前后应基本守恒(仅差 N 倍归一化因子)。