3. OFDM基带信号生成

水声OFDM发射端的基带信号生成,本质上是把一串频域上的QAM/PSK符号“搬”到时域波形上,再为它加上抵抗多途扩展的保护结构。这一节我们沿着数据流走一遍:从比特映射出的频域符号如何排进子载波、IFFT如何完成频域到时域的变换、循环前缀为什么能对抗水声信道的长时延扩展,以及最终一帧基带波形由哪些部分组成。理解这条链路,是后续加同步前导、上变频和信道仿真的前提。

一、子载波分配:哪些“格子”放数据,哪些留空

设系统采用 \(N\) 点IFFT,则可用子载波编号为 \(0 \sim N-1\)。实际水声OFDM不会把全部子载波都用于承载数据,通常要做三类划分:数据子载波用于承载调制符号;导频子载波按固定间隔插入已知符号,供接收端做信道估计与相位跟踪;保护子载波(空子载波)放在频带两端和直流附近,置零不用,用于抑制带外泄漏、避开换能器低频响应差和直流泄漏的区域。

以一个教学示例为例:取 \(N=1024\),采样率 \(f_s=48\,\text{kHz}\),子载波间隔 \(\Delta f = f_s/N \approx 46.9\,\text{Hz}\)。若有效带宽取 \(6\,\text{kHz}\),则占用约 \(128\) 个子载波。可规定:直流子载波 \(k=0\) 置零;低频端 \(k=1\sim4\) 与高频端对应位置作为保护;中间每隔 8 个子载波放 1 个导频,其余为数据子载波。分配结果可以用一个长度为 \(N\) 的频域向量 \(X[k]\) 表示,数据位置填调制符号,导频位置填已知符号(如BPSK的 \(+1\)),其余填 0。

需要特别注意共轭对称性:若希望IFFT输出为实信号,频域向量必须满足 \(X[N-k]=X^*[k]\)。水声OFDM常在中频或复基带处理,此时输出复信号即可,不必强制共轭对称;但若直接驱动D/A产生实通带信号,就必须构造厄米特对称,否则会出现镜像干扰。这一点在仿真中要作为明确的约定写进代码注释。

二、IFFT调制:从频域符号到时域样点

OFDM的调制就是一次 \(N\) 点IFFT。按常用定义(含 \(1/N\) 归一化):

\[ x[n]=\frac{1}{N}\sum_{k=0}^{N-1}X[k]\,e^{j2\pi kn/N},\quad n=0,1,\dots,N-1 \]

工程实现上直接调用FFT库的逆变换即可,但要注意库函数的归一化因子和正负号约定。MATLAB中 ifft(X, N) 自带 \(1/N\);Python的 numpy.fft.ifft 同样含 \(1/N\)。若自行用 fft 加共轭实现,需写成 conj(fft(conj(X)))/N,否则幅度会差一个 \(N\) 倍,导致后续功率归一化和峰均比统计全部失真。

IFFT之后得到的是一个OFDM符号的 \(N\) 个时域样点。此时应检查两个量:一是峰均功率比(PAPR),水声发射机功率受限,PAPR过高会迫使功放回退,降低效率;二是样点功率,便于后续统一归一化到D/A满量程的合适比例。教学示例中可对一帧内所有符号统计PAPR,观察其随子载波数和调制阶数的变化趋势。

三、循环前缀插入:把“尾巴”搬到“头上”

水声信道多途扩展可达数毫秒到数十毫秒。设最大时延扩展为 \(\tau_{\max}\),则循环前缀长度 \(N_{cp}\) 应满足 \(N_{cp}/f_s \ge \tau_{\max}\),并留一定余量。仍以上述参数为例,若 \(\tau_{\max}=10\,\text{ms}\),则 \(N_{cp}\ge 480\) 点,取 \(N_{cp}=512\) 点,对应约 \(10.7\,\text{ms}\) 保护间隔。

循环前缀的构造非常直接:取IFFT输出 \(x[n]\) 的末尾 \(N_{cp}\) 个样点,复制到该符号的最前面,形成长度 \(N+N_{cp}\) 的扩展符号。其物理意义是:只要信道时延扩展不超过CP长度,前一符号的拖尾只会落入后一符号的CP区间,而不会污染后一符号的有效数据段;同时,线性卷积在有效区间内等效为循环卷积,接收端一次FFT即可完成均衡,把频域信道变成一个子载波一个复系数。

代价也要说清楚:CP不携带新信息,带来 \(N_{cp}/(N+N_{cp})\) 的速率与功率开销。上例中开销约 \(33\%\),这是水声OFDM为对抗长多途必须付出的代价,也是水声系统带宽效率普遍低于射频OFDM的原因之一。

四、帧结构设计:把符号组织成可被接收端识别的整体

单个OFDM符号无法独立完成同步与信道估计,需要把若干符号组织成一帧。典型水声OFDM帧由三部分组成:前导(同步序列)、导频/数据符号区、可选的保护间隔。前导常用线性调频(LFM)或伪随机序列,用于帧检测、定时同步和多普勒粗估计;数据区由若干带CP的OFDM符号串联,其中按子载波插入的导频用于信道估计与残余多普勒的相位补偿。

设计帧结构时要回答几个具体问题:一帧包含多少个OFDM符号(影响时变信道下的信道估计更新率);导频在频域和时域上的密度(频域间隔应小于信道相干带宽,时域间隔应小于相干时间);前导长度与数据长度的比例。教学示例可设一帧 = 1个LFM前导 + 20个OFDM符号,每个符号 \(N+N_{cp}=1536\) 点,则一帧基带样点数约为 \(20\times1536\) 加上前导长度,可直接算出帧时长,用于和信道相干时间对比,判断导频密度是否合理。

发射端基带信号生成链路(N=1024,fs=48 kHz,Ncp=512) ① 子载波分配 数据子载波:QAM/PSK符号 导频子载波:已知符号 保护/直流:置零 得到 X[k],长度 N ② N点IFFT x[n]=1/N·ΣX[k]e^(j2πkn/N) 注意归一化因子 1/N 输出 N 个时域样点 ③ 循环前缀插入 复制末尾 Ncp 点至符号头 Ncp/fs ≥ τmax(留余量) 符号长度 N+Ncp=1536 ④ 帧组装 前导 + 数据符号 串行基带波形 送D/A或上变频 频域子载波分配示意(X[k]) 保护 直流0 数据 导频 数据 数据 导频 数据 保护 …… 共约128个有效子载波,导频间隔8 …… 时域帧结构(一帧 = 前导 + 20个带CP的OFDM符号) LFM前导 定时同步/多普勒粗估 CP 数据 CP 数据 CP 数据 …… CP 数据 单个OFDM符号放大 循环前缀 512点 ≈ 10.7 ms 有效数据段(IFFT输出) 1024点 ≈ 21.3 ms 关键约束与检查点 • CP长度:Ncp/fs ≥ τmax,示例 512/48000 ≈ 10.7 ms,需覆盖最大多途扩展并留余量 • 归一化:IFFT含1/N,幅度与PAPR统计前须统一功率基准 • 实信号需求:若直接D/A输出,频域须满足 X[N−k]=X*[k] 的厄米特对称 • 开销:Ncp/(N+Ncp) ≈ 33% • 导频密度:频域间隔 < 相干带宽 • 时域间隔 < 信道相干时间

五、仿真实现要点与结果判读

把上述四步写成代码时,建议按“频域向量—IFFT—加CP—串接成帧”的顺序组织,每一步都保留中间变量便于检查。下面给出核心片段(Python/NumPy,参数与上文示例一致):

import numpy as np

N, Ncp, fs = 1024, 512, 48000
n_sym = 20                      # 一帧内OFDM符号数
data_idx = np.arange(5, 133)    # 示例:有效子载波范围
pilot_idx = data_idx[::8]       # 每8个取1个导频
data_idx = np.setdiff1d(data_idx, pilot_idx)

frame = []
for s in range(n_sym):
    X = np.zeros(N, dtype=complex)
    X[pilot_idx] = 1.0 + 0j                       # 导频:已知BPSK符号
    X[data_idx] = (np.random.randint(0,4,len(data_idx))  # 示例QPSK
                   - 1.5) * 1.0
    X[data_idx] = (np.sign(X[data_idx].real)
                   + 1j*np.sign(X[data_idx].imag)) / np.sqrt(2)
    x = np.fft.ifft(X)                            # 含1/N归一化
    x_cp = np.concatenate([x[-Ncp:], x])          # 循环前缀
    frame.append(x_cp)

frame = np.concatenate(frame)
print("单符号样点数:", N+Ncp, " 帧样点数:", frame.size)
print("CP时长(ms):", Ncp/fs*1e3)

运行后应核对三件事。第一,单符号样点数是否为 \(N+N_{cp}=1536\),帧样点数是否为 \(20\times1536\) 加上前导长度;第二,CP时长是否覆盖设定的最大多途扩展,示例中约 \(10.7\,\text{ms}\),若信道实测多途达 \(15\,\text{ms}\),就必须增大 \(N_{cp}\) 或降低符号率;第三,频谱形状,对一帧做FFT观察,应看到有效子载波带内平坦、带外因保护子载波而快速滚降,若带外泄漏明显,说明保护子载波留得不够或存在未置零的直流分量。

另一个容易被忽略的检查点是循环前缀的正确性:把加CP后的符号末尾 \(N\) 点取出做FFT,应与原始 \(X[k]\) 在数值上一致(在浮点误差范围内)。这一步能同时验证IFFT归一化、CP复制位置和索引是否写错,是调试发射链路时性价比最高的自检。

建议在仿真脚本中把 \(N\)、\(N_{cp}\)、有效子载波范围、导频间隔、调制阶数集中定义为参数区,帧结构由这些参数自动推导。这样在后续章节调整带宽或多途条件时,只需改参数而不必重写链路,也便于对比不同CP长度下的传输效率与抗多途能力。

至此,发射端基带信号已经具备完整的帧形态:频域上数据、导频、保护各就其位,时域上每个符号带CP,整帧以前导开头。它既是后续信道仿真和接收端处理的输入,也是判断系统参数设计是否合理的第一道关口。