简介:面向射频与通信电路设计者的一份应用笔记,聚焦如何在Keysight ADS中借助Ptolemy协同仿真完成ACPR、EVM与PAE三项指标的评估,适合已具备一定功放设计基础、需要把仿真流程落到实处的工程师与相关专业学习者。文档以EDGE调制信号驱动待测功率放大器为主线,说明如何用符合规范的接收端测量邻道与次邻道功率比、误差矢量幅度及平均发射载波功率,并通过监测偏置电压电流推算平均直流功耗与效率;同时介绍自动验证建模如何以谐波平衡特征数据替代逐点全电路仿真,从而加快功率扫描与蒙特卡洛统计分析。压缩包仅1个PDF文件,约1.8MB,篇幅紧凑,便于按主题查阅原理说明与仿真设置思路。目前已有2775人学习,可作为功放线性度与效率联合评估的入门参考。
1. 先建表再跑时域:ACPR、EVM、PAE 为什么能在一次协同仿真里算全
很多人第一次在 ADS 里验证功放,直觉都是"把电路丢进时域,一个点一个点算"。真按这条路走,一段 EDGE 调制信号就够你泡三杯咖啡——每个时间步都要解一遍非线性电路。反直觉的地方在于:想又快又准地拿到 ACPR、EVM、PAE,恰恰要先放弃"每点都算电路"。Ptolemy 协同仿真的做法是,在时域仿真启动之前,先用谐波平衡把功放子电路特性化一遍,建一张输入输出响应的表;之后成千上万个时间点只做查表和插值。省下来的算力不是拿去喝茶的,而是拿来跑功率扫描、扫设计参数、跑蒙特卡洛——而这三件事,才是判断一个功放能不能交付的真正依据。
2. 协同仿真的分工:包络步长、控制器边界与测量接收机怎么对齐
2.1 顶层数据流与子电路求解器的边界在哪
这套拓扑分成两层。顶层是 Ptolemy 域,负责信号产生、调度和测量;功放子电路则挂在 Circuit Envelope 求解器上,负责把当前时刻的输入包络变成一个真实的电路响应。两层之间传递的唯一东西是时间网格上的包络采样:Ptolemy 在时刻 t 把一个复数包络值交给子电路,子电路在这个激励下求解,再把输出包络还回去。
这个边界决定了三件必须遵守的事。第一,子电路里必须放一个 Envelope 控制器或者 Transient 控制器,没有它协同仿真根本起不来,因为子电路需要一个"怎么解"的顶层指令。第二,控制器上的 Stop 参数在协同仿真里是被忽略的,仿真什么时候结束由顶层的测量接收机说了算——测量接收机收够了时隙,整个仿真就停。第三,Step 参数必须由人来设,而且必须和顶层源的时间步严格一致。这三条里前两条是"不这么设就报错",第三条是"不这么设不报错但结果悄悄错",后者更麻烦。
从测量链路看,顶层做的事情其实很朴素:EDGE_Signal_Source 按 EDGE 规范生成调制信号,输入功率由变量 Pin 控制,从 -20 dBm 扫到 +16 dBm;信号进入 Power_Amp_Subcircuit;输出同时送给三个测量接收机。EDGE_EVM_Meas 算误差矢量幅度,EDGE_4CH_ACP_Mod_Meas 算相邻信道和交替信道功率比,EDGE_Pwr_Meas_Local 算平均发射载波功率。输出功率、增益、增益压缩都能从这几路数据里推出来,不需要额外仪表。
2.2 Envelope 控制器的 Step 为什么必须由源来定
包络仿真的时间步不是随便取的,它由调制信号的符号率和过采样倍数决定。以 EDGE 为例,符号率是 270.833 kS/s,源内部用一组方程把符号率、过采样倍数换算成时间步,再赋给采样时钟。子电路里的 Envelope 控制器必须用同一个数,做法也很直接:把那组方程原样复制到功放子电路里,让 Step 由同一套参数算出来,而不是手填一个看起来差不多的数。
常见的实现思路可以写成这样一段换算,用来核对两边是否真的对齐:
# 从符号率和过采样倍数反推包络时间步,用来核对源与子电路是否一致 symbol_rate = 270.833e3 # EDGE 符号率,单位 Hz oversample = 8 # 源里的过采样倍数,按实际设置填 step = 1.0 / (symbol_rate * oversample) print(f"step = {step:.6e} s") # 这个值要同时出现在源和 Envelope 控制器里symbol_rate 是标准给的,oversample 是源里自己设的,两者相乘取倒数就是包络步长。真正容易出问题的是"源里改过采样、子电路没跟着改":顶层波形看着还是 EDGE,频谱形状也没明显崩,但子电路实际上在自己的时间网格上被重采样了一遍,等效于给信号加了一次非理想的插值滤波。这种误差不会报警,只会让 EVM 莫名其妙偏高零点几个百分点、ACPR 在远端信道上偏得更离谱,然后你在电路上找一整天问题。
提示:每次改动源里的过采样或符号率参数,都要回头确认子电路 Envelope 控制器的 Step 表达式是否同步,这是这套流程里最容易被忽略的一致性约束。
2.3 三个测量接收机:EVM、ACPR 与平均载波功率各管什么
三个测量件各有分工,不能互相替代。EVM 衡量的是星座点上实际矢量与理想矢量的偏差,它把功放的非线性、记忆效应、本振相位噪声统统折算成一个百分比;ACPR 衡量的是主信道功率泄漏到相邻信道和交替信道的比例,它对应的是频谱再生,对三阶、五阶交调特别敏感;平均发射载波功率则是把包络功率在一段时间上取平均,用来定增益、定增益压缩、也用来算 PAE 里的射频功率项。ACPR 和 ACLR 在文献里经常混用,这里指的是同一件事。
两个测量件被改过,改动的原因都指向仿真速度。EDGE_4CH_ACP_Mod_Meas 是从标准的 EDGE_TxORFS_Modulation_Meas 改出来的,把测量范围收敛到四个信道,够判断相邻和交替信道就行。EDGE_Pwr_Meas_Local 则是标准功率测量件的一份本地拷贝,独立出来的唯一目的是方便把测量的时隙数压到最低——平均功率本来就不需要那么多时隙去平均,少测几个时隙,仿真时间直接按比例往下掉。这种"改测量件而不是改电路"的思路在这套流程里反复出现:精度损失可控,速度收益立竿见影。
功放本身的特性化用不着等到时域跑完才看。增益就是输出功率减输入功率,增益压缩是小信号增益相对当前增益的下降量,两条曲线都从同一批扫描数据里出。换句话说,跑一次协同仿真,你拿到的是 ACPR、EVM、平均功率、增益、增益压缩、PAE 六条曲线,而不是一条。
3. Fast Cosim:谐波平衡特性化表如何替代逐点电路仿真
3.1 特性化表怎么建:谐波平衡跑在时域之前
Fast Cosim 是这套流程的性能核心,本质是把"在线算电路"换成"离线建表、在线查表"。具体顺序是:Ptolemy 仿真一启动,先对功放子电路跑一轮谐波平衡仿真,在若干个输入功率点和频率点上求出稳态响应,把这些响应组织成一个行为模型;等真正的时域仿真开始,每个时间步不再调用完整的电路方程,而是拿当前包络值去这个模型里插值,直接得到输出。
这个替换之所以成立,是因为功放在一个调制周期内的"电路状态"变化远慢于包络变化。偏置点、匹配网络、晶体管的工作区在一个符号内基本不变,变化的只是激励幅度和相位。谐波平衡求的正是"给定激励下的稳态响应",把这层映射预先算好,时域里剩下的就只是沿着这条映射曲线走一遍。代价是模型只在特性化覆盖的范围内可信,超出范围就得外推,而外推的质量没人能保证。
建表的精度取决于特性化点的密度和插值方式。点太稀,AM-AM 曲线的拐点会被抹平,增益压缩算不准;点太密,建表本身的时间又上去了。工程上的做法是按输入功率范围均匀铺点,在高功率段适当加密,因为拐点都集中在那儿。
3.2 Build model 与 Use previous data 的分界线
Envelope 控制器的 Fast Cosim 页上有个 Characterization 选项,两个值:Build model 和 Use previous data。这条分界线的判断标准只有一句话——子电路本身在这次仿真里会不会变。
如果只扫顶层 Pin,功放的偏置、匹配、器件参数全都没动,那模型在上一轮就已经建好了,这次直接 Use previous data,省掉建表时间,结果完全有效。但只要你扫了子电路内部的任何一个参数,或者跑了蒙特卡洛让器件参数按分布抽样,模型就必须重建,因为旧模型是旧参数点上的快照,拿它算新参数等于刻舟求剑。这一步翻车的典型症状是:参数明明扫了,曲线纹丝不动,你以为这个参数不影响性能,其实是根本没生效。
蒙特卡洛场景下这条尤其致命。统计变量定义在子电路内部——比如 eps_nominal、按 ±10% 高斯分布的器件参数、偏置电压、传输线宽度——每一次抽样都是一个新的电路状态,必须 Build model。这也是为什么蒙特卡洛跑起来比单次扫描慢得多:慢的不是时域,是每抽样一次就要重建一次表。
3.3 Max input power:平均功率、峰值功率与外推的边界
Fast Cosim 设置里最容易被随手填错的是 Max input power (dBm)。直觉上你会把它设成扫描上限,也就是 16 dBm,反正 Pin 最大就到这儿。这个直觉错在一个地方:Pin 是平均功率,而放大器看到的瞬时包络峰值远高于平均值。
调制信号有峰均比。EDGE 用的是 8PSK,包络不是恒定的,峰值功率比平均功率高出几个 dB。当 Pin 扫到 16 dBm 时,包络峰值可能已经顶到 19 甚至 20 dBm,如果特性化表只覆盖到 16 dBm,峰值那部分就在做外推。外推的结果不一定离谱到不能用,但你没有理由相信它,而 ACPR 恰恰对峰值附近的压缩最敏感——误差会集中体现在邻道泄漏上。
# 估算 Fast Cosim 的 Max input power 下限:按峰值而不是平均功率来设 pin_max_avg_dbm = 16.0 # 顶层 Pin 扫描上限 papr_db = 3.2 # 调制信号峰均比量级,以实际波形统计为准 headroom_db = 1.0 # 留一点余量,避免边界上插值 max_input_power = pin_max_avg_dbm + papr_db + headroom_db print(f"Max input power 至少设到 {max_input_power:.1f} dBm")pin_max_avg_dbm 来自顶层扫描设置,papr_db 要按你实际用的调制信号统计,headroom_db 是给插值留的缓冲。这个和值就是应该填进 Fast Cosim 的数。原文里给的判断方法更直接:把顶层扫描关掉,Pin 固定成扫描上限跑一次;再把 Pin 往上顶一格(比如设成 17),如果这时候冒出外推告警,说明特性化范围不够,Max input power 得往上加。这个单点验证很便宜,但能挡住后面一整轮白跑的扫描。
注意:峰均比越高的调制信号,Max input power 相对扫描上限要抬得越多。恒包络信号可以贴着上限设,OFDM 类信号就得留出十几个 dB 的余量,否则整条 ACPR 曲线的高功率段都是外推出来的。
4. PAE 的直流半边:CCVS、全局节点与基带功率平均
4.1 为什么协同仿真里拿不到支路电流
算 PAE 需要平均直流功耗,而平均直流功耗需要偏置电压和偏置电流两路数据。问题在于,Ptolemy 域是一个信号流图,它没有"节点电压"和"支路电流"的概念——那里流动的是数据流,不是物理量。子电路内部的节点默认对顶层不可见,支路电流更是完全无从导出。
这是协同仿真架构层面的限制,不是设置没设对。绕过去的办法是把"不可见"变成"可见":节点可以提升为全局节点,一旦成为全局节点,顶层就能像访问普通信号一样访问它。电压好办,偏置电压本来就是节点量;电流麻烦,电流不是节点量,得先想办法把它转成一个电压。
4.2 CCVS 加全局节点:把电流搬成电压
子电路里在偏置线上串一个 CCVS(电流控制电压源),让它输出一个正比于偏置电流的电压,这个输出节点就叫 ID_Bias。偏置电压节点直接命名为 VD_Bias。两个节点都在顶层被声明为全局节点,于是它们从"子电路内部状态"变成了"顶层可见信号"。
接下来是取哪一段频谱的问题。包络仿真里,每个节点上的波形是"载波上的包络",频谱从零频一直铺到 0.5 除以时间步。直流功耗对应的是零频那一项,也就是基带分量。所以顶层用 EnvOutSelector 接这两个全局节点,把 OutFreq 设成 Lowpass,只保留基带部分,高次分量全部丢掉。这一步不做,后面乘出来的就不是直流功率,而是包含了射频摆幅的瞬时功率,平均值会明显偏大。
# 等价的离线计算:EnvOutSelector(Lowpass) 之后,VItoPower 做的就是这件事 import numpy as np v_bias = np.asarray(env_vd_bias) # 基带采样后的偏置电压序列 i_bias = np.asarray(env_id_bias) # 由 CCVS 转换得到的偏置电流序列 p_dc_avg = float(np.mean(v_bias * i_bias)) # 平均直流功耗 p_out_w = 10 ** ((pout_dbm - 30) / 10) # 平均载波功率转瓦 p_in_w = 10 ** ((pin_dbm - 30) / 10) pae = (p_out_w - p_in_w) / p_dc_avg # 严格定义的 PAE print(f"Pdc = {p_dc_avg*1e3:.1f} mW, PAE = {pae*100:.1f}%")v_bias 和 i_bias 必须是 Lowpass 之后的基带序列,长度与包络采样点数一致;pout_dbm 来自 EDGE_Pwr_Meas_Local 测得的平均载波功率,pin_dbm 就是扫描变量 Pin。PAE 的严格定义是输出射频功率减去输入射频功率,再除以平均直流功耗;有些场合图省事用 Pout 除以 Pdc,小信号下两者差别不大,接近压缩点时输入功率已经不可忽略,用简化式会高估效率。
4.3 VItoPower 与 NumericSink:平均和瘦身
相乘和取平均这两步由 VItoPower 一个器件完成:两路输入相乘,再在时间上求平均,输出一个标量,就是平均直流功耗。这个标量送给 P_DC_1 这个 NumericSink 存下来。
NumericSink 的默认行为是把整段波形都存进数据集,而这里只需要一个数。做法是把 Start 和 Stop 设成同一个值,都指向最后一个采样点的序号。这样数据集里每个扫描点只留一个数,而不是几万个采样点乘以几十个扫描点。别小看这一步:一次功率扫描加参数扫描,如果每个点都存全波形,数据集几个 GB 很正常,打开图形界面就能卡到你怀疑人生,而真正要用的只有最后一个数。
平均载波功率那一路也一样。EDGE_Pwr_Meas_Local 之所以做成独立拷贝,就是为了能把测量的时隙数往下压。平均功率本身是个统计量,多测几个时隙不会让结果更可信多少,但仿真时间会线性往上涨。把时隙数减到刚好够平均,是这套流程里性价比最高的一处提速。
5. 常见问题排查:外推告警、模型复用与数据集膨胀
5.1 模型与外推类问题
现象一:仿真结束前冒出外推告警,ACPR 曲线在最高功率点突然往上翘。原因是 Fast Cosim 的 Max input power 设得贴着平均功率扫描上限,而调制信号的包络峰值早超过去了,最高那几个扫描点全程在做外推。解决办法是按"扫描上限加峰均比再加余量"重设这个参数,然后用单点验证确认:关掉扫描、Pin 固定在上限、再故意往上顶一格,如果不再报警,说明覆盖够了。血泪经验是别偷懒把这个值设成两倍上限了事——设太高会让特性化在无用区间铺点,建表时间白白变长。
现象二:扫了子电路里的参数,六条曲线一动不动,结论是"这个参数没影响"。原因是 Characterization 还停在 Use previous data,模型是上一轮参数点上的快照,新的参数根本没进模型。解决办法是只要子电路内部有任何参数在变——包括参数扫描和蒙特卡洛抽样——一律切回 Build model。判断标准很简单:问自己"这次仿真里功放本身变没变",变了就重建。
现象三:蒙特卡洛结果的相关性看着很干净,但和手工改参数的结果对不上。原因是统计变量定义在子电路内部,而模型没有随抽样重建,等于所有抽样共用了一个标称模型,散点图上自然看不到相关性。解决办法同上,蒙特卡洛必须 Build model;另外建议先跑一次小样本(十几个点)确认散点图有正常散布,再放开跑几百次,别等跑完一夜才发现全是同一个点。
5.2 时间网格与数据集类问题
现象四:波形形状没问题,但 EVM 比预期高、ACPR 远端信道偏差大,怎么调匹配都压不下去。原因是子电路 Envelope 控制器的 Step 和顶层源的时间步不一致。源那边改了过采样或者符号率,子电路这边还留着旧值,协同仿真在两层之间做了一次隐式重采样。解决办法是把源里算时间步的那组方程复制进子电路,让 Step 由同一套参数推导,改一处两边同步。这个坑不报警、不报错,只能靠一致性检查挡。
现象五:数据集几个 GB,画图卡死,实际要看的只有每个扫描点的一个数。原因是 NumericSink 存了完整波形。解决办法是把 P_DC 那一路 NumericSink 的 Start 和 Stop 设成同一个值并指向最后一个采样点;同时把功率测量件的时隙数压到刚好够平均。存储量下来之后,插值、直方图、散点图这些后处理才跑得动。
注意:全局节点没设、或者 EnvOutSelector 的 OutFreq 没设成 Lowpass,症状是 P_DC 不随输入功率变化、或者算出来的 PAE 明显偏低。先查这两处,再去怀疑电路。
6. 设计取舍:插值边界、参数扫描与蒙特卡洛相关性给出的答案
拿到曲线之后,真正要回答的是"参数往哪调"。这一步靠的是数据后处理,而最容易翻车的地方在插值函数。interpolate_swept_data(original_data_Y_vs_X, desired_X, interpStepSize, interpType) 的语义是:在原始曲线里插值,返回最接近 desired_X 的那个 X 对应的 Y,返回值维度跟着输入走。它有一个硬性边界——不做外推。desired_X 超出原始 X 的范围时,它直接把端点上的 Y 还给你,不报错、不警告。
# 用目标输出功率去插值,取各指标在该点的分布 y_at_target = interpolate_swept_data(acpr_vs_pout, desired_Pout_dBm, interpStepSize, interpType) # 若 desired_Pout_dBm 超出曲线 X 轴范围,这里拿到的是端点值,不是目标点后果很具体:如果你把 desired_Pout_dBm 设得比数据里最大输出功率还高,直方图上标着"目标功率"的那组分布,其实是最大功率点的分布,目标值和插值后的均值会差出一截。所以设完目标功率要回头核一下两者是否吻合,不吻合就是越界了。
参数扫描给出的取舍很典型。扫功放子电路里一段传输线的长度,长度增加时 ACPR、EVM、增益都往好的方向走,唯独 PAE 变差。这不是仿真误差,是电路层面的必然:改善匹配、压低谐波、提高线性度,往往意味着更多的直流功耗被丢在无源网络上。三条指标不可能同时最优,扫描的价值就在于把这条取舍曲线画出来,让你知道每换 1 dB 的 ACPR 要付多少效率。
蒙特卡洛把这个问题推到了统计层面。散点图显示 ACLR 与高电源电压之间有明显负相关——电源电压越高,线性度越好,邻道泄漏越低,这符合预期。有意思的是 PAE 与较低的那路偏置电压正相关,而这路偏置电压与 ACLR 的相关性很弱。这意味着偏置电压是一个相对独立的可调维度:压它,效率上来,邻道泄漏基本不动。这类"低相关"的发现比任何单点优化都值钱,因为它告诉你哪些参数可以分开调、哪些必须一起妥协。
| 调节手段 | ACPR/ACLR | EVM | PAE | 可独立性 |
|---|---|---|---|---|
| 传输线长度增加 | 改善 | 改善 | 变差 | 与其他指标强耦合 |
| 电源电压升高 | 改善(强负相关) | 改善 | 略降 | 与效率耦合 |
| 偏置电压降低 | 基本不变(弱相关) | 略变差 | 改善 | 相对独立 |
我自己在这套流程上栽得最惨的一次,是把 Max input power 和扫描上限设成同一个数,跑完一整轮参数扫描,ACPR 高功率段的曲线漂亮得不像话,直到拿单点大信号仿真去对,才发现那一段全是外推出来的。从那以后我每次开跑之前,都会强制走一遍那个单点验证:关扫描、Pin 顶到上限再往上加一格、看有没有告警。这个动作花不到一分钟,但它决定了后面几小时的扫描结果是不是废数据。希望帮到你。
本文还有配套的精品资源,点击获取