AFDM波形原理与仿真:用DFnT啁啾基对抗双选信道
简介围绕AFDM波形理论解析的项目源码包面向无线通信、信号处理与6G技术研究者聚焦高多普勒频移和大时延扩展场景下传统OFDM性能下降的替代方案。压缩包共8个文件以Python仿真脚本为核心配有3张图表、2个文本文件及工程配置整体仅306KB体积小巧便于直接运行。目前已有248人浏览学习适合从事波形设计与链路仿真的读者。通过该源码可复现AFDM的连续时间建模、离散化、矩阵表示及子载波干扰分析结合时延-多普勒域特性并配合时域波形图与收发端星座图直观验证仿射变换在时频平面上的资源重排效果同时涵盖发射机/接收机的符号映射与调制解调流程为后续参数优化、低复杂度算法和面向6G的波形融合研究提供了可扩展实验平台。1. AFDM不是OFDM的升级版而是把信号写到“斜着的格子”里第一次接触 AFDM 波形的人最容易先入为主地把它当成 OFDM 的某种改版。这个判断方向是错的。OFDM 在高速移动场景下翻车是因为时变信道让子载波之间的正交性失效OTFS 把符号铺到时延-多普勒域能顶住双选信道但工程实现和导频设计绕了一大圈。AFDMAffine Frequency Division Multiplexing仿射频分复用的思路是把基带符号放进一组带啁啾相位chirp的正交基里收发各做一次离散仿射傅里叶变换DFnT让时延在接收端表现为一个循环移位、多普勒表现为一个相位旋转。这两件事在变换域里能被同时“拉直”。换句话说AFDM 不是 OFDM 加了个前缀而是把信号写到一张斜着的格子里让双选信道的干扰正好落在格子对角线上。这篇笔记我会带着你从理论推导到源码运行再讲清楚参数怎么设、那些一眼看不出来的坑都在哪。适合给正在做 6G 物理层算法仿真、以及想快速把 AFDM 跑出第一条 BER 曲线的工程师和研究生看。2. AFDM 波形理论框架DFnT 把时延和多普勒同时收进一张网格2.1 离散仿射傅里叶变换的数学定义与啁啾基的物理直觉AFDM 的数学底座是离散仿射傅里叶变换Discrete Affine Fourier TransformDFnT。它和 DFT 最大的区别在于相位项里多出两个关于索引的二次项。对于一个长度 N 的向量 xDFnT 正变换定义如下import numpy as np def make_dftn(N, c1, c2): 构造 N 点离散仿射傅里叶变换矩阵 A。 A[m, n] 1/sqrt(N) * exp(-j * 2pi * (c1*m^2 c2*n^2 m*n) / N) 参数: N: 符号块长度对应子载波数 c1, c2: 啁啾参数chirp parameters通常取整数 返回: A: 形状为 (N, N) 的复矩阵 n np.arange(N).reshape(N, 1) m np.arange(N).reshape(1, N) phase -2j * np.pi * (c1 * m**2 c2 * n**2 m * n) / N A np.exp(phase) / np.sqrt(N) return A这段代码里 m 是行索引对应变换后的输出序号n 是列索引对应原始时域符号序号。相位项分解成三部分c1m^2 是输出域啁啾、c2n^2 是输入域啁啾、m*n 是经典的傅里叶内核。除以 sqrt(N) 是为了保持能量不变保证 A 是酉矩阵。c1 和 c2 的取值直接决定这张“斜着的格子”倾斜成什么样后面第 4 章的调参会专门讨论。物理直觉可以这样看OFDM 的每个子载波是单一频率的复指数在时域里是一条匀速转动的指针AFDM 的每个基向量是频率随时间线性变化的啁啾信号在时域里是一条加速度转动的指针。当无线信道的多普勒效应给信号叠加一个频率偏移时OFDM 的子载波间距会被这种偏移破坏而 AFDM 的啁啾基因为本身就在扫频对多普勒的容忍度更高。同时时延在仿射傅里叶域会表现为一个与 c2 有关的循环位移而不是简单的相位旋转。这种“时延变位移、多普勒变相位”的结构才是 AFDM 在高动态场景下比 OFDM 稳的根因。2.2 发射机与接收机的信号流从调制符号到检测符号完整链条可以压缩成一句话发端把 QAM 符号做逆 DFnT 变成时域波形过信道后收端做正 DFnT 再均衡。把每一步拆开信号流是这样的。# 发射端 X np.array([11j, -11j, 1-1j, -1-1j]) # 举例4 个 QPSK 符号 N len(X) A make_dftn(N, c11, c21) x A.conj().T X # 逆 DFnT频域符号转时域波形逆变换用的是 A 的共轭转置而不是直接取逆。由于 A 是酉矩阵A^H 就是 A 的逆这一步在工程实现上非常便宜——不需要做矩阵求逆。x 就是最终要加循环前缀、做射频发射的时域采样点。接收端把收到的时域信号 y 做正 DFnT变回调制符号域r A y # 正 DFnT时域采样转回调制符号这里 r 是变换域接收符号。如果信道是理想的没有噪声、没有时延和多普勒r 应该等于 X。实际信道会让 r 变成 X 的某种加权叠加但只要时延抽头和多普勒抽头落在整数网格上这个叠加在变换域里会保持一种稀疏的对角占优结构。换句话说AFDM 不需要像 OFDM 那样对每个子载波做一个独立的单抽头均衡器也不需要像 OTFS 那样做二维均衡它把双选信道转成一个近似对角阵线性均衡就能拿到不差的误码性能。这也是源码里接收机通常写得比 OTFS 短的原因。2.3 AFDM、OFDM、OTFS 的选型对照对比项OFDMOTFSAFDM调制域频域时延-多普勒域仿射傅里叶域啁啾基双选信道适应性差多普勒破坏正交性好二维网格匹配信道好靠 chirp 参数搬移干扰收发变换DFT / IDFT二维辛傅里叶变换DFnT / IDFnT均衡复杂度每子载波单抽头需要二维迭代均衡近似对角化线性均衡可接受参数设计自由度子载波间隔、CP 长度网格维度、导频间隔子载波间隔、CP、c1、c2导频与信道估计成熟导频在二维网格上稀疏放置导频设计仍在快速演进从这张表能看出选型逻辑。如果你的信道近似时不变、多普勒很弱OFDM 依然是最划算的如果你的信道极度稀疏、时延和多普勒同时很强OTFS 在理论上最漂亮但均衡器迭代收敛问题在低信噪比区容易让人头疼AFDM 恰好站在中间它不像 OTFS 那样需要重新发明整个接收机也不像 OFDM 那样在高速移动下性能断崖。我在实际项目里选 AFDM多半是看中它的数学结构可以在现有 FFT 硬件上改造实现而不是彻底推翻基带架构。3. 拿到 AFDM 源码先跑通基线最小仿真链路与文件结构解析3.1 典型源码包的模块划分从一个可运行的 Demo 说起很多开源 AFDM 仿真包的代码组织方式大同小异源头大多来自某高校实验室或某公司研究院放出的仿真 Demo。我一般拿到代码后会先看四个模块而不是急着跑 main。第一个是变换模块负责构造 DFnT 矩阵第二个是信道模块负责生成时延-多普勒抽头第三个是收发主链路把调制、加 CP、过信道、去 CP、解调串起来第四个是绘图与指标模块负责输出 BER 曲线和星座图。下面这份伪代码对应一个最小可运行的链路# 模拟项目X 的 AFDM 基线仿真结构如下 # make_dftn(N, c1, c2) 构造 DFnT 矩阵 # build_channel(N, taps) 构造时域信道矩阵 # simulate_ber(snr_db, N, taps) 跑一组信噪比下的误比特率不要一上来就改参数先把默认配置跑完。默认配置通常是很小的 N64 或 128抽头数 2 到 4 个调制方式 QPSK这样单次 BER 仿真只需要几十秒方便你确认链路没断。3.2 从零跑通最小仿真链路DFnT 矩阵 时域信道 ZF 均衡下面是一段可以直接运行的 AFDM 最小链路脚本我按“变换构造、信道构造、仿真循环”三个步骤拆开讲。import numpy as np def build_channel(N, taps): 构造循环时延 多普勒的时域信道矩阵 H。 输入: N: 符号块长度 taps: 列表元素为 (增益, 时延抽头, 归一化多普勒) 返回: H: (N, N) 复数矩阵y H x H np.zeros((N, N), dtypecomplex) for gain, delay, doppler in taps: for n in range(N): out_idx (n delay) % N # 循环时延 H[out_idx, n] gain * np.exp(-1j * 2 * np.pi * doppler * n / N) return H这段信道构造是理解 AFDM 仿真最关键的环节。时延不是简单把采样点往后推而是做循环移位多普勒不是乘一个固定复数而是对每个时间采样点 n 乘一个随 n 线性变化的相位项 exp(-j2π f_d n / N)。物理含义是一个频率偏移会在离散时间轴上表现为相位随时间旋转。这里的 doppler 是归一化多普勒等于实际多普勒频率除以子载波间隔然后乘上符号块长度 N再做归一化。很多新手在这里直接写 np.exp(-1j * 2 * np.pi * f_d * n / fs)结果相位转得太快或太慢BER 曲线完全乱掉。这段代码的复杂度是 O(N^2 * P)N 小于 256 时完全够用如果要仿真 1024 点以上的大块建议改成稀疏矩阵存储。主仿真循环如下def afdm_ber_sim(N, c1, c2, taps, snr_db, trials500): A make_dftn(N, c1, c2) A_H A.conj().T H build_channel(N, taps) Heff A H A_H # 变换域等效信道矩阵 diag_heff np.diag(Heff) # 近对角取对角做 ZF rng np.random.default_rng(42) bits rng.integers(0, 2, (N, 2 * trials)) symbols (bits[:, 0::2] * 2 - 1) 1j * (bits[:, 1::2] * 2 - 1) symbols / np.sqrt(2) # 归一化 QPSK 能量 errors 0 for t in range(trials): x A_H symbols[:, t] # 发射端逆 DFnT noise_var 10**(-snr_db / 10) noise (rng.normal(0, np.sqrt(noise_var / 2), N) 1j * rng.normal(0, np.sqrt(noise_var / 2), N)) y H x noise r A y z r / diag_heff # 迫零均衡 rx_bits_1 np.real(z) 0 rx_bits_2 np.imag(z) 0 errors np.sum(rx_bits_1 ! (bits[:, 2*t] 0)) errors np.sum(rx_bits_2 ! (bits[:, 2*t1] 0)) return errors / (N * 2 * trials)这里最值得注意的参数是 Heff。H 是时域信道矩阵A 和 A_H 分别把信号从时域搬进搬出变换域三者相乘得到的是整个链路的等效信道。理想情况下 Heff 应该是对角阵但因为多普勒和时延抽头落点不一定完美对齐网格非对角项会有残余。直接取 diag(Heff) 做除法是最朴素的 ZF 均衡代码里的 r / diag_heff 一定要用逐元素除法不要写成矩阵求逆。矩阵求逆在 N 大的时候不仅慢还会放大噪声对演示链路没必要。3.3 输出怎么读BER 曲线、变换域信道热力图、星座图跑通之后不要只看一眼 BER 就收工。我习惯先画三张图第一张是 BER 对 SNR确认曲线在高信噪比区域没有掉头向上第二张是 abs(Heff) 的热力图看能量是否集中在对角线附近对角线越亮说明 AFDM 的双选信道对抗能力越强第三张是接收均衡后的星座图QPSK 的四个簇应该清晰分离。这三张图里热力图最能说明问题——如果对角线的亮度只有 60% 左右说明 c1、c2 或网格配置不匹配信道需要回头调参。BER 曲线则适合做横向比较OFDM、OTFS、AFDM 放在同一坐标系里横轴是 SNR纵轴是 BER。AFDM 在中高 SNR 区间通常能比 OFDM 好 3 到 5 dB这是它在 6G 候选波形讨论里最直观的本钱。4. 参数配置与调优N、c1、c2 和网格选择背后的逻辑4.1 AFDM 核心参数表每个旋钮管什么参数作用典型值约束与影响NDFnT 点数 / 符号块长度64~1024越大频谱效率越高但均衡和仿真越慢c1输出域啁啾参数整数常见 1影响多普勒搬移取非整数易混叠c2输入域啁啾参数整数常见 1决定时延在变换域的位移量关键旋钮CP 长度循环前缀采样点数N/8 ~ N/4必须大于最大时延抽头否则丢符号抽头数 P信道多径数量2~8越多非对角项越强均衡压力越大归一化多普勒f_d / Δf 再乘 N0.1~2超过 N 会混叠需要折叠c1 和 c2 是 AFDM 手里最独特的两个旋钮。c1 主要影响发射端啁啾基的扫频方向c2 影响接收端时延向变换域位移的系数。把 c2 调大时延抽头在变换域里会“跑”得更远不同时延的抽头被分得更开但开得太大超过 N/2 以后多普勒和时延的贡献会互相折返产生混叠。c2 的取值应该和最大时延、最大多普勒一起联调不要单独拍脑袋设一个数。4.2 按信道场景选网格与啁啾参数高铁信道和市区信道是两套玩法我一般把场景分成两类。第一类是高铁场景多普勒大、时延小。此时归一化多普勒可能到 1 以上但最大时延只有几个采样点。c2 不需要太大因为时延抽头本来就很集中选 c21 或 2 足够把时延映射到不同变换域位置重点是 N 要够大把多普勒分辨率做细否则两个多普勒抽头在区间内靠得太近均衡器分不开。第二类是市区多径场景时延大、多普勒中等。最大时延可能到 20 个采样点以上这时 c2 就要适当调大比如取 3 或 4让时延抽头在变换域里拉开距离。一个实用的经验是先跑一次无噪声仿真画出 Heff 热力图看非对角能量集中在哪些位置再反推 c1、c2 的取值方向。# 一块 128 点 AFDM市区多径信道参数示例 N 128 c1, c2 1, 3 # c2 调大分离时延抽头 cp_len 32 # 大于最大时延 20 taps [(1.0, 0, 0.0), # 主径 (0.7, 5, 0.2), # 时延 5多普勒 0.2 (0.4, 14, -0.3), # 时延 14多普勒 -0.3 (0.2, 20, 0.1)]这里是经典做法的示例。时延零点表示主径其他抽头的增益按功率递减多普勒符号随机取正负模拟真实的移动环境。CP 长度 32 留了 12 个采样点余量避免抽头恰好压在 CP 边界上导致符号间干扰。如果你的链路里 CP 不够长会在 BER 高信噪比区出现一个怎么都压不下去的地板那是时延超出 CP 的标志。4.3 参数敏感性验证三个十分钟小实验调参不能靠感觉我每次拿到新信道配置都会做三个快速实验。第一个固定 N 和信道c2 从 1 扫到 8画一条 BERc2曲线。你会看到一个明显的 U 形小 c2 时不同时延抽头挤在一起大 c2 时混叠回绕中间某个值最优。第二个固定 c2把 N 从 64 扫到 512看 BER 改善幅度。N 增大通常带来性能提升但超过某个阈值后提升变缓而仿真时间指数上升。第三个在无噪声条件下测 BER它应该严格为 0。如果无噪声 BER 不为 0说明变换矩阵、信道或均衡的某一步相位不对先修链路再谈调参。这三个实验加在一起不会超过半小时能帮你避开“参数乱调、曲线乱跳”的玄学状态。5. AFDM 仿真避坑指南五个我踩过的翻车现场5.1 DFnT 矩阵相位符号写反整个链路静默失败现象无噪声下 BER 不是 0而是稳定在某个错误率附近比如 0.25 或 0.5。原因正变换用 exp(-jθ)逆变换用了 exp(-jθ) 而不是 exp(jθ)。DFnT 不是对称变换正逆相位必须相反。这类错误不会让程序报错因为矩阵尺寸和数值范围全对只有结果错最容易变成“找不到 bug 的 bug”。解决构造完 A 之后立刻验证 A^H A 是否等于单位阵再做一个长度为 N 的随机向量 v检查 A^H (A v) 是否等于 v。这两条检查写成断言放进代码以后任何改动只要跑一次就能兜住。5.2 时延用线性移位而不是循环移位边界样本悄悄丢掉现象BER 曲线在高信噪比区下不去并且 CP 越长反而越差。原因仿真里用 np.roll 或循环移位做时延是标准做法但有人图省事写成 out_idx n delay不加取模。这样最后一个 delay 个符号会被推到块外丢失相当于人为制造了一个时延超过 CP 的信道。更隐蔽的是这种截断在变换域里表现为能量泄漏Heff 对角线上会出现额外噪声。解决信道构造里强制对输出索引取模并且把“时延最大值 多普勒扩展”与 CP 长度放在同一个断言里校验。如果时延超过 CP不是修代码而是改参数。5.3 整数多普勒与分数多普勒混为一谈现象把归一化多普勒设成 0.5、0.3 这类小数后BER 曲线在中高 SNR 出现抖动热力图对角线出现块状模糊。原因AFDM 在理论推导里经常假设多普勒落在整数网格上此时变换域等效信道是严格对角的。分数多普勒会破坏对角化非对角能量扩散到附近的子载波位置。这是物理现象不是代码错误。解决先用整数多普勒0、1、2跑通链路确认性能和理论一致再引入分数多普勒同时把均衡器从纯 ZF 换成最小均方误差MMSE估计即 z (diag_heff.conj() * r) / (abs(diag_heff)**2 sigma2)而不是简单除法。MMSE 对分数多普勒泄漏有压制作用能换回 1 到 2 dB 性能。5.4 c1、c2 取非整数时延多普勒落点互相碰撞现象固定信道不变只把 c2 从 1 改成 0.5BER 直接恶化几个数量级。原因c2 非整数时时延在变换域产生位移不再对齐采样网格不同抽头的能量会在相邻整数索引之间弥散等效信道的对角占优结构被破坏。这个坑在论文推导里很少被强调因为论文通常假设 c1、c2 是整数。解决c1、c2 一律取整数。如果确实需要小数精度的啁啾配置接收端必须用完整的 Heff 做最小二乘均衡而不是只取对角同时保证时间带宽积满足网格设计约束否则性能没有保障。5.5 跟 OFDM 对比时“分子分母不干净”现象AFDM 的 BER 曲线比 OFDM 差甚至误码率高于 0.1和论文趋势相反。原因对比实验里 OFDM 没加信道编码、CP 长度不一致、调制方式不同或者 OFDM 符号块长度与 AFDM 的 N 不相等。这类不公平对比让 OFDM 在 CP 开销上吃亏或者让 AFDM 在高谱效配置下优势被掩盖。解决对比前把三个变量锁死相同的信息比特数、相同的 CP 占总符号比例、相同的调制方式。AFDM 的优势体现在双选信道下的整体链路收益不是在单个模块上碾压 OFDM。对比实验的完整配置应该写进仿真脚本的注释里防止一周后自己都忘了当时比的是什么。6. 验证与进阶双正交残差、信道热力图与实现正确性的自检习惯所有 AFDM 仿真代码到手后我做的第一件事不是看 BER 曲线而是跑一遍双正交残差检验这是区分“看似正常”和“真正常”的分水岭。A make_dftn(N64, c11, c21) residual np.linalg.norm(A.conj().T A - np.eye(64), ordfro) print(residual) # 应该在 1e-12 左右超过 1e-8 就说明矩阵构造有相位问题残差量级在 1e-12 左右说明 A 是严格酉阵正逆变换可以互逆这是后续一切仿真的前提。如果残差到了 1e-6 以上不要继续调信道参数回头检查 DFnT 矩阵的归一化因子和相位符号。第二个进阶验证是把 Heff 热力图可视化并计算对角能量占比diagonal_energy_ratio np.sum(abs(np.diag(Heff))**2) / np.sum(abs(Heff)**2)。这个比值在整数时延多普勒信道下应该高于 0.9低于 0.8 说明网格设计不匹配信道需要回到第 4 章调 c2 和 N。再往深走一步可以尝试把 AFDM 的导频序列铺在变换域网格的稀疏位置上做一次最小二乘信道估计再把估计出的信道矩阵代回均衡器。你会发现 AFDM 的信道估计比 OTFS 简单的地方在于时延和多普勒在变换域各自对应一个方向的位移导频位置可以沿着这两个方向的交叉点放置不需要遍历整个二维平面。这一步做通之后AFDM 的工程可行性才算真正落地而不仅仅是仿真好看。我个人的习惯是每次改完参数先跑无噪声 BER 和双正交残差再跑低信噪比和高信噪比两个点确认曲线趋势正常然后才放全 SNR 扫点“过夜跑”。这个动作帮我省掉了至少十次“曲线又乱了、不知道改了什么”的返工。AFDM 的坑不在原理多深而在实现细节够不够较真把 DFnT 矩阵、循环时延、整数网格这三个地方盯死你的仿真就稳了一大半。希望帮到你。本文还有配套的精品资源点击获取