简介:这是面向无线通信与射频工程领域的DPD数字预失真学习与仿真资料,围绕功率放大器非线性失真、带宽预补偿等核心问题,提供从理论讲解到Matlab仿真的完整参考,适合通信专业学生、算法工程师和基站研发人员使用。资料共237个文件,压缩包大小约7.63MB,核心为127个.m源文件,涵盖DPD算法实现、PA非线性建模、Saleh模型参数等仿真脚本,另有txt说明、doc文档和mat数据文件辅助理解,可支撑实际建模与算法验证。目前已有325人学习/下载。通过该资料,读者可以掌握DPD信号处理框架与逆失真生成思路,理解大带宽场景下的预失真补偿策略,并基于参考代码进行二次开发与参数调优,从而提升无线基站功放线性化设计能力。
1. 数字预失真(DPD)到底在补偿什么
运营商验收 5G 基站时,第一眼看的往往不是吞吐率,而是发射频谱能否压进 ACLR 模板。功放推得越深,效率越高,邻道泄漏就越重,留给系统的回退空间常常只有两三个 dB。数字预失真(DPD)在数字域预先叠加一个与功放失真方向相反的非线性补偿,让信号经过功放后输出重新逼近线性。
完整的 DPD 设计要同时回答三个问题:用什么模型描述功放失真,这是 dpd 算法理论的核心;需要多宽的带宽承载失真谱扩展,这是带宽预补偿的由来;以及如何在 FPGA 里落地,对应数字预失真的工程实现。工程师手里的参考包也大多按这三块组织:模型公式、仿真脚本、指标模板。
内容按建模、辨识、带宽设计、IP 落地、验证的顺序展开,前两章把理论和仿真讲透,第三章专门处理带宽预补偿,第四章落到 Xilinx DPD IP Core 的参数设置,最后一章给三个上板后快速定位问题的验证手法。
2. dpd 算法理论的选择:从无记忆模型到记忆多项式
功放建模是 DPD 的第一块地基。模型选得太简单,补偿残差会一直压在指标上;选得太复杂,系数辨识矩阵病态、FPGA 资源翻倍。常见的选择路径是从无记忆模型出发,遇到频谱不对称或宽带信号再升级到记忆多项式。
2.1 为什么 AM/AM、AM/PM 曲线救不了宽带信号
教科书里最直观的功放非线性是 AM/AM 与 AM/PM 特性:输入功率增大时,增益压缩、相位偏移,曲线一旦标定,查表就能做反相补偿。这种无记忆模型对窄带信号有效,因为在一个符号周期内功放的工作点基本不变。问题出在宽带场景:100 MHz 的 5G 信号包络变化速度快于功放的偏置网络和热时间常数,输出不仅取决于当前输入,还取决于前几个采样周期内的输入,表现为记忆效应。
记忆效应在频谱上的典型特征是上下边带的不对称泄漏。无记忆模型无论怎么调参数都只能给出对称补偿,于是工程师会发现 ACPR 改善到一定程度就停住,两侧模板一边过一边差十几个 dB。判断是否需要上记忆模型的工程方法很简单:把功放输出的上下边带 ACPR 分别读出来,差超过 3 dB,就需要在模型里加入记忆项。
提示:记忆效应强不强,和功放类型直接相关。Doherty 功放在回退区的相移变化大,记忆效应通常比单管 AB 类更明显,宽带场景下建模时要把记忆深度当作第一优先项。
2.2 记忆多项式模型:数学形式与系数规模
记忆多项式(Memory Polynomial, MP)是 Volterra 级数的最常用简化,只保留对角项,公式写成:
y(n) = Σ a(k,m) · x(n−m) · |x(n−m)|^(k−1),其中 k 取奇数,m 从 0 到 M。
x(n) 是当前基带输入,x(n−m) 是往前 m 个采样时刻的输入,k 是非线性阶数,M 是记忆深度。|x|^(k−1) 是幅度相关的权重,这说明 DPD 的补偿量既和当前信号大小有关,也和信号历史有关。k 只取奇数是工程惯例,因为 PA 产生的交调主要落在奇数次谐波附近,偶次项容易在数字域引入直流分量和本振泄漏,对 ACPR 贡献很小且会恶化数值稳定性。
系数个数等于奇数阶数量乘以 (M+1)。常用组合和适用场景如下:
| 非线性阶数 K | 记忆深度 M | 待辨识系数个数 | 典型场景 |
|---|---|---|---|
| 5 | 2 | 9 | 窄带、回退较深的功放 |
| 7 | 3 | 16 | 100 MHz 以下常规基站 PA |
| 9 | 5 | 30 | 5G NR 宽带、Doherty 功放 |
系数个数直接决定辨识矩阵的尺寸和 FPGA 里乘法器的数量。K 从 7 提到 9,系数涨了接近一倍,但高阶项对 ACPR 的边际贡献通常只有 1~2 dB,资源却要成倍增加。设计时先定 M 再定 K,记忆深度不够时提高 K 是没用的,这一点在实际项目中反复被验证。
2.3 最小二乘辨识系数:对齐、建矩阵、解方程
系数辨识的本质是系统辨识:给功放灌一段已知的宽带激励 x,用反馈通路采回输出 y,假设 y 是 x 经过 MP 模型产生的,求一组系数让模型输出尽量逼近 y。常见做法是最小二乘(LS),离线用 MATLAB 或 Python 一次算完,上板后 FPGA 再用 LMS 递归自适应。
辨识的第一步是延时对齐。反馈通路有模拟滤波器和 ADC 的固定延时,没对齐的 x 和 y 在数学上没有任何对应关系,算出来的系数全是噪声。对齐方法是用互相关找峰值位置:把 y 做整数倍样本移位,计算与 x 的互相关,峰值对应的移位就是整数延时,残余小数延时用分数延时滤波器补。
import numpy as np def align_delay(x, y, search_range=64): """用互相关估计 x 与 y 之间的整数采样延时""" best_d, best_corr = 0, -1 for d in range(-search_range, search_range): yd = np.roll(y, d) c = np.abs(np.vdot(x, yd)) # 复信号内积,取幅度 if c > best_corr: best_corr, best_d = c, d return best_d def build_mp_matrix(x, K, M): """构造记忆多项式回归矩阵,列顺序为按 (m, k) 展开""" N = len(x) cols = [] for m in range(M + 1): xm = np.roll(x, m) xm[:m] = 0 # 头部补零,避免循环移位伪造历史数据 for k in range(1, K + 1, 2): cols.append(xm * (np.abs(xm) ** (k - 1))) return np.stack(cols, axis=1) def ls_identify(x, y, K, M): Xmat = build_mp_matrix(x, K, M) coeff, *_ = np.linalg.lstsq(Xmat, y, rcond=None) # 复数最小二乘 return coeffbuild_mp_matrix 里外层循环先固定记忆深度 m,内层循环再遍历奇数阶 k,列顺序要和上板后硬件展开的顺序保持一致,否则查表索引对不上。np.roll 是循环移位,所以头部 m 个样本要补零,防止把序列尾部的数据卷到开头变成假历史。lstsq 对复数矩阵一样适用,X 列数远小于行数时速度可接受。
注意:参与辨识的数据长度至少要达到系数个数的 10 倍,否则矩阵欠定,正规方程的条件数恶化,算出的系数在带外表现为毛刺。反馈信号还要做功率归一化,让 y 的平均功率和 x 一致,否则解出来的系数幅度整体偏移。
辨识完成后用测试序列验证,模型输出与真实反馈的 NMSE 通常要做到 -35 dB 以下才算建模充分。如果 NMSE 上不去,先回头查对齐误差,再考虑把 M 加 1,而不是盲目增加 K,这是调 DPD 模型参数时最容易被忽略的顺序。
3. 带宽预补偿:DPD 采样率与频响设计
DPD 能补偿多宽的失真,决定了它能改善多少 ACPR。带宽预补偿有两层含义:一是数字域的采样率要覆盖到失真谱扩展后的带宽,二是在这段扩展带宽内把发射链路的频响做平,避免模拟通道的滚降被 DPD 误当成非线性去补偿。
3.1 失真谱扩展:k 阶非线性对应 k 倍带宽
功放的非线性会产生交调分量。两个相距 Δf 的单音经过三阶非线性,会在 2f1−f2 和 2f2−f1 位置产生新分量,落在以两音为中心的 ±Δf 范围;对连续的调制信号,三阶失真谱宽度是信号带宽的 3 倍,五阶是 5 倍。DPD 要修正这些分量,自身就必须有能力在这些频点上产生反相信号,因此 DPD 工作采样率至少是信号带宽的 3 倍,常用到 4~5 倍。
如果采样率不够,问题不是"补偿不完全",而是混叠:超出奈奎斯特区的失真谱会折回带内,与真实失真叠加,自适应算法无论怎么迭代都无法收敛,频谱上表现为始终消不掉的杂散。判断采样率是否够用的土办法是看反馈采样的频谱:在信号带宽的 3 倍范围内如果有周期性重复的谱峰,就是混叠,需要先提高反馈采样率再谈算法。
3.2 TX 通路与反馈通路的采样率预算
实际系统里两条通路的采样率要求不同。TX 侧 DPD 内核工作在 2~4 倍符号率,Xilinx DPD IP Core 通常要求输入采样率是被补偿信号带宽的整数倍,典型配置如下:
| 信号带宽 | TX DPD 采样率 | 反馈 ADC 采样率 | 备注 |
|---|---|---|---|
| 20 MHz LTE | 122.88 MHz | 245.76 MSPS | 3 倍以上即可 |
| 100 MHz 5G NR | 491.52 MHz | 1966.08 MSPS | 反馈需覆盖 5 阶失真 |
| 200 MHz 多载波 | 983.04 MHz | 2949.12 MSPS | 对 DAC/ADC 的模拟带宽要求高 |
反馈通路要比 TX 更宽,原因是自适应算法要同时"看到"带内信号和带外交调,才能算出正确的补偿系数。反馈窄了,带外信息被滤波掉,辨识结果天然缺频段。模拟前端的设计顺序应该是先定反馈带宽,再反推 TX 侧 DPD 采样率,最后确定 DAC 的插值倍数,这个顺序倒了,后面所有指标都要返工。
3.3 用 MATLAB 设计带宽预补偿滤波器
带宽预补偿的另一个任务是压平 DAC、驱动放大器和 PA 输入端在扩展带宽内的幅度/相位响应。典型实现是在 DPD 内核前加一个复数 FIR 预均衡器,用训练序列测出通路的幅相响应后取逆。MATLAB 里的滤波器设计:
% 带宽预补偿滤波器设计 % fs_dpd:DPD 工作采样率,fpass:信号有效带宽,fstop:要补偿到的失真带宽 fs_dpd = 491.52e6; fpass = 100e6; fstop = 250e6; % 覆盖到失真带宽,避免滤波器拐点落在补偿带内 d = fdesign.lowpass('Fp,Fst,Ap,Ast', fpass, fstop, 0.1, 60, fs_dpd); Hd = design(d, 'equiripple'); fvtool(Hd); % 查看幅频/相频响应 % 群延时检查:DPD 内核希望通带内群延时波动尽量小 grpdelay(Hd, 1024, fs_dpd);fpass 取信号有效带宽,fstop 取需要补偿的失真带宽。Ast 设 60 dB 是为了让带外衰减远高于 DPD 的补偿能力,否则滤波器的残余旁瓣会变成新的失真源。grpdelay 检查的是群延时平坦度,预均衡器如果本身群延时波动超过一个采样周期,反而会给 DPD 反馈通路引入新的记忆效应,这时要放宽 fpass 或改用线性相位设计。
注意:带宽预补偿滤波器不是 DPD 模型的一部分,它修正的是模拟链路的线性失真。如果把它放进 DPD 自适应环内迭代,辨识矩阵会混入线性项,系数解不稳定,典型的故障现象是收敛后 EVM 好但 ACPR 抖动。
4. 用 Xilinx DPD IP Core 落地:参数设置与离线预验证
算法仿真通过后,上板实现通常会选 Xilinx DPD IP Core 而不是自己写自适应引擎。IP 核把 LMS 迭代、系数更新和 LUT 查表固化在硬件里,用户主要工作集中在配置模型阶数、记忆深度和采样率,以及把离线辨识结果作为初始系数导入。
4.1 IP Core 的组成与不做什么
Xilinx DPD IP 核支持 Memory Polynomial 和 GMP 两种模型 profile,内部包含预失真执行通路和自适应更新通路。用户给它的输入是被补偿的基带信号和经过反馈 ADC 的功放输出采样,它输出的是预失真后的信号给 DAC。核外还需要自己部署三样东西:CFR 削峰、反馈通路的下变频/同步、以及带宽预补偿滤波器。
功放 DPD 的收敛质量大概七成取决于反馈数据质量。IP 核不负责解决模拟问题:反馈通路的延时对齐在核内有专门的 sync 逻辑,但如果反馈信号本身被滤波器压低或混叠,核内自适应一样发散。设计分工上,IP 核解决"系数怎么收敛",工程师解决"喂给它的数据是否干净",后者通常决定最终 ACPR 能不能达标。
4.2 参数表:阶数、记忆深度、LUT 与采样率
IP 配置界面的参数和仿真模型一一对应,设置顺序建议从采样率开始,再逐级提高模型阶数:
| 参数 | 推荐范围 | 设置依据 |
|---|---|---|
| DPD Sample Rate | 3~5 倍信号带宽 | 由带宽预补偿预算决定 |
| Static Order | 5~9(奇数) | 从 7 起步,ACPR 不足再升 |
| Dynamic Order | 3~5 | 对应记忆效应的交叉项,别超 Static |
| Memory Depth | 2~5 | 先用 3,看频谱对称性 |
| LUT Size | 按 IP 建议值 | Doherty 功放出厂差异大时可加大 |
| Feedback ADC Bits | 14~16 bit | 位数不够时带外底噪压不下去 |
Static Order 对应公式里的 K,Dynamic Order 是 GMP 里的交叉项阶数,Memory Depth 对应 M。给 Xilinx 平台配参数时先设 Static Order 7、Memory Depth 3 跑一轮,看反馈的 NMSE 再决定是否提阶。直接上 9 阶 5 深度的组合会让 IP 内部加法树延迟变大,同时系数辨识矩阵的条件数上升,收敛速度反而不如低阶配置。
4.3 上板前用 host 端离线预验证
上板联调之前,先用上板抓的回波数据在 host 端算一遍 NMSE,能过滤掉大部分配置错误。抓数方法:用 Vivado 的 ILA 或芯片内部的 debug 口同时抓 DPD 输入和反馈 ADC 输出各 65536 点,导出成 CSV 后在 Python 里处理:
import numpy as np def calc_nmse(x_ref, y_fb, shift=0): """计算反馈信号相对参考信号的归一化误差""" y = np.roll(y_fb, shift) # 粗对齐 gain = np.vdot(x_ref, y) / np.vdot(y, y) # 最小二乘增益归一 err = x_ref - gain * y nmse_db = 10 * np.log10(np.mean(np.abs(err)**2) / np.mean(np.abs(x_ref)**2)) return nmse_db # x_ref: ILA 抓到的 DPD 输入,y_fb: 反馈 ADC 解调后数据 print(calc_nmse(x_ref, y_fb))NMSE 低于 -35 dB 表示反馈通路干净,可以直接把离线 LS 辨识的系数写入 IP 核做初始值。NMSE 在 -25 dB 附近徘徊时,先别调模型参数,回头检查 ILA 抓数的触发位置和反馈数据的相位旋转,这两处是抓数和计算里最常见的错误来源。
5. 上板后的 DPD 验证技巧:频谱对称性、收敛曲线与双音测试
5.1 ACPR 不对称优先加大记忆深度
上板灌入宽带信号,把频谱仪的 Span 开到 DPD 补偿带宽。上下边带 ACPR 差超过 3 dB,优先把 Memory Depth 从 3 加到 4 或 5,而不是提升 Static Order。记忆深度每加 1,IP 核延迟增加一个采样周期,重跑自适应前记得重新做反馈对齐,否则收敛曲线会反弹。
5.2 收敛曲线出现平台期时检查延时
用 IP 核的 debug 总线读出每轮迭代的 NMSE 曲线。曲线前几百次迭代快速下降后停在平台,且平台值高于仿真值 10 dB 以上,常见原因是反馈数据存在残留延时或幅度不归一。Vivado 例程里有时钟周期数可调的 sync 参数,把它改成抓数互相关算出的整数延时值再跑一轮。
5.3 双音测试验证带宽预补偿是否到位
双音测试用来做边界验证:两个相距 80 MHz 的单音,总功率推到额定回退点,观察 3 阶和 5 阶交调产物。如果距离主音 80 MHz 和 160 MHz 处的交调分量不对称,说明 DPD 采样率或带宽预补偿滤波器的 fstop 设窄了,把 fstop 提到失真带宽的 1.2 倍、同时把 DPD 采样率提高一档重测;交调两侧底噪一致抬升时,问题在反馈 ADC 的噪声系数,不在算法链路。具体操作时记录三个读数:左交调与右交调的差值、交调相对主音的 dBc、以及开启 DPD 前后的 NMSE 跳变,这三个数组合起来,就能判断到底是模型阶数、记忆深度还是带宽预算的问题。
本文还有配套的精品资源,点击获取