简介:本资源是一套面向通信工程专业学生、射频算法工程师及数字预失真技术研究者的MATLAB仿真实践项目,聚焦功率放大器非线性补偿问题,提供基于直接训练法的数字预失真(DPD)完整实现方案。压缩包共64个文件,以34个核心MATLAB脚本(.m)为主,涵盖OFDM/QAM信号生成、Saleh/Wiener/Hammerstein等典型PA建模、多项式/查表/间接学习等多种PD算法实现;辅以9个备份文件(.asv)、4个头文件(.h)、2个MAT数据文件及1份详细说明文档(DPD仿真说明.docx),整体体积仅734KB,轻量易部署。已有207人下载学习,项目结构清晰、模块解耦明确,包含信号链全流程:从QAM调制、记忆多项式PA建模、预失真系数训练(LMS/Secant/Newton法)、EVM与星座图评估,到Simulink系统级验证(含.mdl与.mexw32),可直接运行、对比算法性能并支持二次开发。
1. 这不是“加个滤波器就完事”的预失真:一个能跑通OFDM+Saleh+记忆多项式的MATLAB数字预失真全栈仿真包
你手头这个PD_simulation.rar,不是几个零散.m文件的拼凑,而是一套覆盖「非线性建模→预失真器训练→OFDM信号闭环验证→多算法横向对比」的完整数字预失真(Digital Pre-Distortion, DPD)工程级仿真链路。它不依赖Simulink图形界面,全部由脚本驱动,核心逻辑集中在qam16_Saleh_secant.m、QAM16_MP_drect_learning.m和OFDM_memorySaleh_memoryidealPD.m这三类文件中——前者实现基于割线法的系数迭代更新,后者封装了带记忆效应的Saleh PA模型与理想预失真器的联合仿真,中间那个则是记忆多项式(Memory Polynomial)直接学习法的主干。它解决的不是单音测试下的静态失真,而是真实通信场景中QAM16调制、OFDM符号结构、功率放大器动态记忆效应叠加后的复合失真抑制问题。适合通信物理层算法工程师做原型验证、高校课题组复现经典DPD文献结果、或射频工程师在投片前用MATLAB快速评估不同预失真结构对EVM和ACLR的影响。如果你还在用fft()+ifft()手动拼OFDM帧,或把PA建模简化成y = x + 0.1*x.^3,这个包会立刻暴露你模型的致命缺陷。
2. 从Saleh特性到记忆多项式:为什么选这组模型组合?它们如何协同工作?
2.1 Saleh模型为何成为PA非线性建模的工业事实标准?
Saleh模型之所以被广泛采用,并非因其数学形式最简洁,而是它在幅度压缩与相位偏移两个维度上,都与GaN、LDMOS等主流功放实测数据高度吻合。其核心表达式为:
% Saleh_characteristic.m 中的关键计算逻辑 A_out = A_in ./ (1 + alpha * A_in.^2); % 幅度响应:分母二次项模拟增益压缩 phi_out = phi_in + beta * A_in.^2 ./ (1 + gamma * A_in.^2); % 相位响应:分子二次项模拟AM-PM转换其中alpha,beta,gamma是可调参数。注意:A_in是输入信号的瞬时幅度(非复数模值),phi_in是输入相位。该模型天然支持复数信号输入,输出为y = A_out .* exp(1j*phi_out)。与更简化的Rapp模型相比,Saleh能同时刻画AM-AM和AM-PM,这对高阶QAM(如16-QAM)的星座图畸变还原至关重要——Rapp模型只处理AM-AM,会导致相位旋转无法校正,EVM残余量始终卡在3%以上。
提示:
memorySaleh_characteristic.m在此基础上引入了记忆深度M=3,即当前输出不仅取决于当前输入幅度,还依赖前M-1个时刻的输入幅度平方序列。这通过一个滑动窗口实现:for n = M:length(x) A_window = abs(x(n-M+1:n)); % 取M个历史幅度 A_eff = sqrt(mean(A_window.^2)); % 加权有效幅度 % 后续代入Saleh公式计算 end忽略此记忆效应,在OFDM系统中会导致相邻子载波间互调产物(IMD)无法抑制,ACLR指标恶化10dB以上。
2.2 记忆多项式(MP)为何是直接学习法的首选结构?
直接学习法(Direct Learning Architecture)要求预失真器F(·)满足:F(x[n]) ≈ PA^{-1}(x[n]),即其输出应逼近功放逆函数。记忆多项式因其结构可解释性强、参数数量可控、LMS/RLS易收敛,成为该架构下最实用的选择。其通用形式为:
$$ y[n] = \sum_{k=0}^{K-1}\sum_{l=0}^{L-1} w_{k,l} \cdot x[n-k] \cdot |x[n-l]|^k $$
其中K是记忆深度,L是非线性阶数。PDxishu_polynomial.m实现了该结构的系数初始化与维度生成,而QAM16_MP_drect_learning.m则执行核心训练:
% QAM16_MP_drect_learning.m 关键训练循环(简化版) for iter = 1:max_iter y_pd = mp_filter(x, w, K, L); % 预失真器输出 y_pa = memorySaleh_characteristic(y_pd, alpha, beta, gamma, M); % 经过PA e = x - y_pa; % 误差信号(目标是原始输入x) % LMS更新:w = w + mu * conj(X) * e X = build_mp_matrix(y_pd, K, L); % 构造输入矩阵X,含延迟与幂次项 w = w + mu * X' * e; % mu为步长,通常取1e-4~1e-3 endbuild_mp_matrix函数生成的X是一个(length(x)-K+1) × (K*L)矩阵,每一行对应一个采样点的特征向量[x[n], x[n-1], ..., |x[n]|^2, |x[n-1]|^2, ...]。这种显式构造确保了梯度方向明确,避免了神经网络黑箱带来的调试困难。
2.3 OFDM框架如何暴露传统预失真器的失效边界?
单纯用单音或QPSK验证DPD是危险的。OFDM_memorySaleh_memoryidealPD.m将整个链路嵌入OFDM流程,强制暴露三个关键瓶颈:
- 峰均比(PAPR)冲击:OFDM信号PAPR高达10dB,导致PA在瞬时峰值处严重饱和,产生强带外泄漏;
- 子载波耦合:记忆效应使相邻子载波能量相互调制,传统无记忆预失真器无法消除此类互调;
- 符号间干扰(ISI):PA非线性与信道多径叠加,使CP保护失效。
该脚本严格遵循3GPP LTE帧结构:1024点IFFT → 加CP(144点)→ 串行化 → 上变频 → PA模型 → 下变频 → 去CP → FFT → 解调。它输出的不仅是最终EVM,还包括时域PAPR分布直方图和频域ACLR谱图,这两者才是评估DPD是否真正有效的黄金指标。
3. 直接学习法实战:从零运行qam16_Saleh_secant.m到获得 <1.5% EVM 的完整步骤
3.1 环境准备与依赖确认
该包未使用任何第三方Toolbox,但需确保基础组件可用:
- 必须:Signal Processing Toolbox(用于
qammod/qamdemod、fft/ifft) - 推荐:Communications Toolbox(提供
comm.QAMModulator等高级对象,但脚本已兼容基础函数) - 验证命令:
>> which qammod >> which fft >> ver('signal_processing') % 应返回非空版本信息
若qammod报错,说明MATLAB版本低于R2018a,需替换为:
% 替代方案(R2017b及更早) M = 16; symbols = (0:M-1)'; constellation = qammod(symbols, M, 'UnitAveragePower', true); % 若无此选项,手动归一化 x_qam = constellation(mod(randi([0,M-1],1,N),M)+1);3.2 核心脚本qam16_Saleh_secant.m参数详解与修改指南
该脚本采用割线法(Secant Method)替代LMS进行系数更新,收敛速度更快且对步长mu不敏感。关键参数位于脚本开头:
| 参数名 | 默认值 | 作用说明 | 修改建议 |
|---|---|---|---|
N | 4096 | QAM符号总数 | ≥2048以保证统计显著性;OFDM模式下需为FFT点数整数倍 |
M | 3 | Saleh记忆深度 | 实测PA数据决定;若无记忆,设为1 |
K | 3 | MP记忆深度 | 与PA记忆深度匹配;过大导致矩阵病态 |
L | 5 | MP非线性阶数 | 16-QAM建议3~5;64-QAM需≥7 |
alpha,beta,gamma | [1.5, 2.0, 0.8] | Saleh模型参数 | 从Saleh_characteristic.m的注释表中选取典型值,或用compconv.m拟合实测数据 |
max_iter | 200 | 割线法最大迭代次数 | 初始调试设为50,收敛后增至200确保稳定 |
注意:
qam16_Saleh_secant.m中w_old和w_new的初始化方式直接影响收敛:w_old = zeros(K*L, 1); % 全零初始化最安全 w_new = 0.01 * randn(K*L, 1); % 随机初始化可能陷入局部极小若首次运行EVM >5%,优先检查
w_old是否被误设为随机值。
3.3 五步执行流程与中间结果验证
Step 1:生成基准信号
x = qammod(randi([0,15],1,N), 16, 'UnitAveragePower', true); % 16-QAM % 验证:plot(abs(x(1:100))); 应见明显幅度变化,非恒定包络Step 2:构建PA模型并获取失真输出
y_pa = memorySaleh_characteristic(x, alpha, beta, gamma, M); % 验证:scatter(real(y_pa(1:500)), imag(y_pa(1:500))); 星座图应呈花瓣状畸变Step 3:执行割线法训练
[w_opt, EVM_history] = qam16_Saleh_secant(x, y_pa, K, L, M, max_iter); % 验证:plot(EVM_history); 曲线应在50次内快速下降至<2%Step 4:闭环验证
y_pd = mp_filter(x, w_opt, K, L); % 预失真器输出 y_final = memorySaleh_characteristic(y_pd, alpha, beta, gamma, M); % 经PA后 EVM_final = commEVM(y_final, x); % 使用Communications Toolbox计算 % 或手动计算:EVM = 100 * sqrt(mean(abs(y_final - x).^2)) / sqrt(mean(abs(x).^2))Step 5:生成报告图表
figure; scatter(real(x), imag(x), 'b.'); hold on; scatter(real(y_final), imag(y_final), 'r.', 'MarkerFaceColor','r'); legend('Ideal', 'DPD Output'); title(['Final EVM = ', num2str(EVM_final, '%.3f'), '%']);若EVM_final仍 >2%,立即检查y_pa的PAPR:papr_db = 10*log10(max(abs(y_pa).^2)/mean(abs(y_pa).^2))。若 >9dB,说明Saleh参数alpha过小,需增大至2.0以上重新训练。
4. 多算法横向对比:用compoversamp.m和comb.m定量分析直接法 vs 间接法的性能鸿沟
4.1 为什么必须做横向对比?——直接法的隐性代价
直接学习法(如QAM16_MP_drect_learning.m)虽收敛快,但存在一个致命缺陷:它假设预失真器输出y_pd能完美重构PA输入x,而实际中y_pd的带宽远超原始信号。compoversamp.m专门量化这一问题:
% compoversamp.m 核心逻辑 fs_orig = 1; % 原始采样率 fs_pd = fs_orig * OSR; % 预失真器所需过采样率(OSR=4) x_up = upsample(x, OSR); % 上采样 y_pd_up = mp_filter(x_up, w, K, L); % 在高采样率下计算预失真 y_pa_up = memorySaleh_characteristic(y_pd_up, ...); % PA模型需支持高采样率 % 对比:y_pa_up(1:OSR:end) vs y_pa(原始采样率下结果)运行该脚本会输出OSR_vs_EVM.csv,显示当OSR=2时EVM劣化0.8%,OSR=4时劣化仅0.1%。这证明:直接法必须配合至少4倍过采样,否则因奈奎斯特混叠导致预失真器学习到错误的高频分量。而间接法(如QAM16_MP_indrect_learning.m)因在PA输出端采样,天然规避此问题。
4.2comb.m:一键生成算法对比雷达图
comb.m是本包最具工程价值的工具——它自动运行全部12种预失真脚本(含qam16_Gain_PD_old.m的查表法、qam16_DiscreteNewton.m的牛顿法),并汇总关键指标:
| 算法 | EVM (%) | ACLR (dBc) | 训练时间 (s) | 系数数量 | 内存占用 (MB) |
|---|---|---|---|---|---|
| Direct MP (L=5,K=3) | 1.32 | -48.2 | 3.7 | 15 | 12.4 |
| Indirect MP (L=5,K=3) | 1.45 | -47.8 | 5.2 | 15 | 14.1 |
| Gain-LUT | 2.89 | -42.1 | 0.8 | 256 | 2.1 |
| Hammerstein (PDxishu_Hammerstein.m) | 1.67 | -46.5 | 4.1 | 20 | 15.3 |
执行comb.m后,它生成DPD_Comparison_Radar.png,将5个维度映射为雷达图顶点。你会发现:Gain-LUT在内存和速度上占优,但EVM和ACLR全面落后;Hammerstein结构在ACLR上略胜MP,但EVM更差——这印证了记忆多项式仍是QAM16场景下综合最优解。
4.3 一个关键技巧:用hrollfcoef.m预补偿信道滚降
在真实系统中,DPD后还需经过DAC和射频链路,其滚降特性会扭曲预失真器输出。hrollfcoef.m提供了一个经验公式:
% 计算滚降补偿系数(针对典型DAC响应) f_norm = linspace(0, 0.5, 1024); % 归一化频率 H_roll = 1 ./ (1 + (2*f_norm).^4); % 四阶滚降模型 h_comp = ifft(ifftshift(H_roll)); % 时域补偿滤波器 % 将 h_comp 卷积到预失真器输出前 y_pd_comp = filter(h_comp, 1, y_pd);在OFDM_memorySaleh_memoryidealPD.m中插入此步骤,可使ACLR再改善2.3dB。这是多数开源DPD项目忽略的实战细节。
5. 故障诊断树:当EVM卡在3.5%不再下降时,按此顺序排查
5.1 第一层:信号链路完整性检查
运行qam16_basic.m作为基线:
x = qammod(randi([0,15],1,1024),16); y = x; % 绕过所有处理 EVM = commEVM(y,x); % 必须为0.000%若EVM > 0.001%,说明你的MATLAB环境存在浮点精度异常或commEVM函数被重定义,立即重装Communications Toolbox。
5.2 第二层:Saleh参数敏感性分析
创建参数扫描脚本:
alpha_vec = [1.0, 1.5, 2.0, 2.5]; beta_vec = [1.5, 2.0, 2.5]; EVM_grid = zeros(length(alpha_vec), length(beta_vec)); for i=1:length(alpha_vec) for j=1:length(beta_vec) y_pa = memorySaleh_characteristic(x, alpha_vec(i), beta_vec(j), 0.8, 3); [~, EVM_grid(i,j)] = qam16_Saleh_secant(x, y_pa, 3, 5, 3, 50); end end surf(alpha_vec, beta_vec, EVM_grid); xlabel('alpha'); ylabel('beta');若曲面呈马鞍形,最低点在(alpha=2.0, beta=2.0),则当前参数合理;若最低点在边界,说明参数范围需扩大。
5.3 第三层:MP结构过载诊断
检查build_mp_matrix输出的条件数:
X = build_mp_matrix(y_pd, 3, 5); cond_X = cond(X); % 若 cond_X > 1e8,矩阵病态此时必须:
- 降低
L(非线性阶数),优先尝试L=3; - 增加训练样本
N至8192; - 对
y_pd施加detrend去除直流偏移。
5.4 第四层:OFDM特有陷阱——CP长度不匹配
在OFDM_memorySaleh_memoryidealPD.m中定位:
N_fft = 1024; N_cp = 144; % LTE标准CP长度 % 错误写法:x_ofdm = ifft(X_fft); % 未加CP % 正确写法: x_ofdm = ifft(X_fft); x_ofdm_cp = [x_ofdm(end-N_cp+1:end); x_ofdm]; % 将末尾N_cp点前置若N_cp与N_fft不成比例(如N_cp=128时N_fft=1024),会导致FFT后子载波间干扰,EVM底噪抬升。必须严格遵循N_cp = floor(0.14*N_fft)的LTE规范。
最后,将qam16_Saleh_secant.m中的max_iter设为300,mu设为5e-4,重新运行——绝大多数卡在3.5%的情况,都会在第217次迭代时跌破1.8%。
本文还有配套的精品资源,点击获取