很多刚开始用 Virtuoso 做模拟仿真的人,第一次在 analogLib 里看到 vcvs 这个元件时,多半是直接翻过去的——毕竟 schematic 里摆的大多是 nmos、pmos、电阻电容,一个看起来没有任何模型参数的“大方块”确实让人摸不着头脑。但你要是做过几轮项目就会发现,VCVS(Voltage-Controlled Voltage Source,压控电压源)其实是把“架构验证”和“电路设计”解耦开来的利器。它能在你还没有把运放、基准源这类模块画出来之前,先把整个系统的信号链、反馈关系、环路特性验证清楚。
这篇文章我按自己平时在 Cadence Virtuoso ADE 环境里实际操作的路径来写,覆盖 VCVS 的原理、调用方法、参数配置、典型仿真场景,以及我踩过的一些坑。适合刚开始接触 Virtuoso 仿真的学生,也适合在项目早期阶段需要快速搭行为级模型验证架构的工程师参考。
1. 为什么要在原理图里用 VCVS:它到底解决什么问题
1.1 受控源家族里,VCVS 的角色
很多人第一次接触“受控源”是在电路理论课上,四种理想受控源——压控电压源(VCVS)、压控电流源(VCCS)、流控电压源(CCVS)、流控电流源(CCCS)。在 Virtuoso 的 analogLib 库里,这四种源都能找到,名字分别是vcvs、vccs、ccvs、cccs。它们都是“理想”元件,没有寄生电容、没有压摆率限制、没有输出电阻、没有电源电压轨限制,完全是数学传输函数的电路化。
VCVS 的输出电压等于控制端电压差乘以一个固定增益:
V(out+) - V(out-) = Gain * (V(p) - V(n))从控制理论的角度看,VCVS 就是电路图上最纯粹的一个比例环节。它的价值不在于精确复现某个真实器件,而在于用极低的成本把“理想行为”摆进仿真电路里。你在做反馈系统、开关电源补偿网络、ADC 前端采样保持链路的时候,常常会遇到“运放还没设计完”或者“比较器还在调管子尺寸”的阶段。这时候硬等模块画完再仿系统,效率太低。用 VCVS 搭一个理想增益级,先把外围反馈网络、带宽分配跑通,再逐个替换成真实电路,这是很标准的自顶向下设计流程。
1.2 VCVS 在模拟设计里的典型应用场景
VCVS 最常见的用途有三个:理想运放宏模型、环路增益注入探针、行为级信号链验证。
先说理想运放。一个真实运放如果只关注线性放大区,它的高频主极点、低频增益、输出阻抗都可以暂时忽略,此时用 VCVS 加一个高增益就能模拟“无限增益运放”的开环特性。在拉扎维那本经典教材的习题里,很多题目背后的仿真验证其实都可以用 VCVS 快速搭出来。配合外部电阻反馈网络,你能马上看到闭环增益、虚短虚断这些理论分析结果在仿真器里是什么表现。
再说环路稳定性分析。在电源管理、LDO、开关电源这类带强反馈的电路里,你要在仿真里“打破环路”看开环增益和相位裕度。常用的方法是加iprobe或者用 STB 仿真(Loop Gain 分析)。但某些老版本或特定仿真器配置下,直接加电压源、电流源做交流注入可能会破坏直流工作点。这时候在断点处插入一个 Gain=1 的 VCVS 缓冲器,既可以保持前后级直流电平不变,又能给环路注入交流扰动,是我个人很常用的一种折中办法。
第三类是行为级验证。比如整个信号链是“传感器 -> 放大器 -> 采样保持 -> ADC -> 数字处理”,放大器还没设计完成前,可以用 VCVS 先占位,配合理想开关(analogLib 里的switch)和理想电容,把采样保持的时序、建立时间、电荷共享问题先验证一遍。等到放大器模块就绪,再一对一替换,整个项目节奏会舒服很多。
2. 在 Virtuoso 中调出并配置 VCVS:实操全程
2.1 调用 VCVS:两种常用方式
在 Virtuoso Schematic Editor 里调 VCVS 的方法很简单,记一个快捷键i就能搞定。按i会弹出Add Instance对话框,然后在 Library 栏选择analogLib,在 Cell 栏查找vcvs。这个库在 Virtuoso 安装时就会自带,里面存放的全是理想电压源、电流源、接地符号、电阻电容等基础模拟元件。
如果你对库名不确定,可以在 Library Manager 中先确认工作目录下有没有analogLib。有些项目环境会自定义库路径,导致打开原理图时看不到 analogLib 里的器件。确定路径没问题后,选中vcvs,Symbol 预览窗口会显示一个方框型符号。我用的版本里,它左右两侧各有两个小引脚,输入端的标注通常是p和n,输出端是out+和out-。
放置完 vcvs 后,按下Esc退出放置模式,再用快捷键w画线连接。接法上要特别注意:输入控制端正负不要接反,输出端的out+和out-是真正的信号输出。如果你只是想把某个节点电压按比例搬到另一个地方,就把n端接地、out-端接地,这样输出就变成了单端对地的比例电压。这一点新手最容易搞混,因为 vcvs 看起来像两个独立的端口对,实际却是一对信号去控制另一对信号。
2.2 引脚识别与连线方法
对于 analogLib 中的 vcvs,symbol 上通常标有四个引脚:
| 引脚名称 | 方向 | 作用 |
|---|---|---|
| p | 输入 | 控制端正节点 |
| n | 输入 | 控制端负节点 |
| out+ | 输出 | 输出电压正端 |
| out- | 输出 | 输出电压负端 |
不同版本符号标注可能略有差异,有的版本里输入引脚标成+和-,有的旧版工艺库会自带增强型受控源,名字前面加个e(比如e_vcvs)。所以在连线前先按q查看一下元件属性,确认端口名再动手,别凭记忆硬接。
连线时我的习惯是:
- 控制端从测试节点拉线出来,不要让控制端悬空。悬空节点在 spectre 里有时会被自动接地,有时会直接报
floating node警告,结果很隐蔽。 - 输出端的负载一定要有,即使只是一个大电阻到地。因为 VCVS 是理想源,输出阻抗为零,如果你让
out+和out-断开什么都不接,仿真器虽然能算出电压,但这个电压对电路没有任何影响,容易让人误以为“输出一直是错的”。 - 如果被控节点是高阻点,最好在控制端并联一个非常大的电阻(比如 1G 欧姆)到地,给仿真器一个直流路径,能显著减少直流不收敛的概率。
2.3 属性参数详解:Gain 和它背后的网表
放好 vcvs 后,按下q打开 Edit Object Properties,你会看到它的核心参数只有一个:Gain。默认值是 1,单位是 V/V。这个值可以直接填一个数,也可以写表达式,比如10k、1e5,甚至写2.5k这种带后缀的写法。仿真器解析时会自动把 k 换算成 1000。
在 spectre 网表里,一个 Gain=100 的 vcvs 会被翻译成类似这样的一行:
e1 (out+ out- p n) vcvs gain=100e1是仿真器自动生成的实例名,前面括号内依次是输出端和输入端的节点名。如果原理图里有多个 vcvs,网表里就会出现e1、e2、e3等多个实例。这个细节在排查网表报错时很有用——当你看到错误信息里出现e5之类的名字,直接回原理图按e定位(Find 功能搜 instance 名)就能找到对应的那个元件。
需要注意,VCVS 的 Gain 参数是无量纲的,不要填成100kohm或者带电阻单位的东西,否则仿真器会直接拒绝解析或默认当成 1 处理。另外在 Spectre 和 Hspice 两种仿真器下,受控源的语法和模型名会有差异,如果你把同一个原理图切到 Hspice 仿真器跑,VCVS 能不能直接跑通取决于工艺库和 model 文件是否兼容。我的经验是:在 Virtuoso ADE 里老老实实用 spectre 跑,受控源的处理最省心。
3. VCVS 在不同仿真中的表现与使用方法
3.1 DC 仿真:从传输函数看工作点
DC 仿真是验证 VCVS 连接正确与否最直接的手段。你可以在输入端加一个直流电压源vdc,然后把 vcvs 的输出接到一个电阻负载上,跑 DC 扫描(dc分析,扫描输入电压从 -1V 到 1V),查看输出曲线。
如果 Gain 设成 2,输入 0.5V 时输出应当是 1V。如果结果不是这个值,优先检查是不是控制端正负接反了。接反的情况下输出会变成负的,曲线整体翻转,这条规律比任何调试手段都快。
做 DC 仿真时还有一个容易忽略的点:VCVS 是理想线性元件,它的输出不受电源电压限制。你给它输入 1V、增益 100,输出就是 100V。这在真实电路里是不可能的,因为运放输出不可能超过电源轨。所以当你用 VCVS 搭理想运放时,一定记住它“没有电源轨”,输出飞到几百伏都是正常现象。这个行为不影响小信号 AC 验证,但在大信号瞬态仿真里会引发严重问题,后面会专门说。
另外,如果 VCVS 的输出直接驱动一个二极管或 MOS 管栅极这种非线性负载,输出 100V 可能让仿真器算出非常离谱的电流,甚至触发器件模型电流超限报错。解决办法是给 VCVS 输出端并联一个箝位网络,或者用一个带限幅的宏模型替代。最简单的限幅做法是输出端接两个背靠背稳压管(analogLib 里有理想齐纳模型),但这个做法会让仿真变慢,我一般只在需要大信号闭环验证时才加。
3.2 AC 仿真:理想增益级与扫频
AC 仿真是 VCVS 用得最顺手的地方。因为 VCVS 本身没有极点、没有零点,频率响应是一条平直线——增益恒定、相位恒为 0(反相接法则为 180 度)。这意味着,你在闭环系统里看到的任何频率特性,全部由外围电阻电容决定。这对验证反馈网络的传函推导极其有利。
举一个我常做的例子:搭一个理想反相放大器,开环增益 A=100000,输入电阻 Ri=1k,反馈电阻 Rf=9k。理论闭环增益是 -Rf/Ri = -9。用 VCVS 搭出来后跑 AC 仿真,你会发现低频增益非常接近 -9,但高频段由于 VCVS 没有主极点,相位裕度曲线和真实运放会有区别。这个实验最适合用来理解“有限开环增益对闭环精度的影响”——你把 A 从 10 改到 100000,观察闭环增益误差随 A 的变化,理论和仿真能对得严丝合缝。
做 AC 仿真时,激励源要选ac源,在 vdc 的 AC Magnitude 栏填 1(表示扫频时输入幅度为 1V),扫描范围根据外围元件决定,一般从 1Hz 扫到 1GHz。此时观察 vcvs 输出,你看到的频响就是整个系统的传输函数。有一些工程师会在这个阶段顺手做一下反馈网络的零点、极点分析,看看补偿电容加多大能获得足够的相位裕度。这些工作完全可以全部建立在 VCVS 理想模型之上,等真实运放模块完成后,再回到同一个 testbench 里替换元件,对比理想模型和真实模型的差距,能很快定位问题是出在运放本身还是外围反馈网络。
3.3 瞬态仿真:代数环与大信号跳变的坑
瞬态仿真里用 VCVS 最容易踩坑,主要问题集中在两个地方:代数环和大信号非物理跳变。
先说代数环。当你用两个 vcvs 互相反馈,比如e1的输出接到e2的输入,e2的输出又接回e1的输入,这就形成了一个没有延时、没有滤波的纯代数环。spectre 求解器在处理这种结构时,要么得到不可预测的初始值,要么直接报singular matrix或者迭代不收敛。实际电路里信号传播总有一点延迟,但理想受控源没有。解决方法是打破环路,最常见的方式是在反馈路径上并联一个非常小的电容(比如 1fF 到 100fF),给仿真器一个时间常数,把代数环变成微分方程;或者用一个大电阻(比如 1G 欧姆)跨接,给直流工作点一个确定路径。
再说非物理跳变。真实运放压摆率受限,输出从 -1V 跳到 +1V 需要几微秒;VCVS 不需要,它在一个仿真步长内就能完成跳变。如果系统里还有其他理想开关、比较器这类元件,这些瞬态跳变可能引起振铃,甚至让仿真器以为电路在产生高频振荡,然后自动缩小步长,导致仿真速度急剧下降。碰到这种情况,我的做法是在 VCVS 输出端串联一个理想电阻(比如 100 欧姆)到负载电容,人为加一个极点,把非物理的高频分量滤掉。这个 RC 组合只影响高频行为,对低频环路增益几乎没有影响。
3.4 进阶:用 VCVS 搭一个带限幅的宏模型
如果你需要 VCVS 提供接近真实运放的大信号行为,有个很实用的搭法:VCVS 高增益级 + 输出限幅网络。具体做法是让 VCVS 的输出经过两个背靠背二极管和一个电阻分压网络,把输出电压钳制在设定范围内。这样既能保留理想增益级的线性精度,又能模拟输出轨的饱和特性。
我在做 ADC 比较器行为级建模时,就常用 VCVS 加限幅的方式替代真实锁存比较器。VCVS 增益设成 1000,输出再接两个限幅二极管,把输出限制在 0 到 3.3V 之间。这一级就能模拟比较器的“高电平/低电平”输出。后续再配合理想开关和电容,就能搭出一个完整的采样比较器宏模型。用这种方式跑整个 ADC 的瞬态仿真,速度比用真实比较器电路快好几倍,而且因为模型简单,查错也容易——输出不对,要么是 VCVS 增益算错,要么是限幅网络参数写错,基本不会有三极管模型没收敛这种玄学问题。
4. 常见问题排查与避坑实录
4.1 器件未定义 / 符号丢失
在原理图里放好 vcvs,一仿真却报ERROR (SFE-23): "input.scs" 2: e1: undefined symbol,这类报错十有八九是analogLib 库没有被仿真器加载。Virtuoso 的原理图库里能看到符号,不代表 spectre 能直接拿到模型定义。解决办法是检查lib.defs或者 cds.lib 文件中是否包含了analogLib的路径。如果你用 Library Manager 新建库时把 attach 关系搞错了,或者项目根目录的cds.lib被覆盖过,都会导致这个问题。
还有一种情况是:你在同一个原理图里删除再重新放置 vcvs,但原理图符号缓存没有更新,仿真时用了旧的网表文件。遇到这种情况,先把 ADE 里的网表目录清掉(通常是~SIM开头的目录),再重新生成网表,问题基本能解决。仿真器偶发的undefined symbol报错,很多时候和库路径无关,就是网表缓存作祟。
4.2 瞬态仿真不收敛
VCVS 相关的不收敛,排在第一位的原因是上文提到的代数环。两个以上理想受控源互相反馈,或者理想受控源连着一个没有直流路径的电容孤岛,仿真器算直流工作点时就会发散。排障时先用dc仿真单独算一遍工作点,如果 DC 都不收敛,把环路里受控源的输出端断开,分段检查,就能快速定位是哪一段形成了死循环。
第二位原因是输入信号变化太快。VCVS 没有压摆率限制,输入一个上升沿 1ps 的脉冲,输出也跟着瞬间跳变,整个电路出现极窄的高频脉冲。仿真器为了追踪这个脉冲,会把步长压到飞秒量级,仿真时间爆炸,有时还会因为矩阵条件数太大报数值错误。处理方式就是给 VCVS 输出加 RC 低通,人为限制变化率,前面已经说过,这里不再赘述。
第三位原因是单位写错。我在 VCVS 增益栏里填过100u,本意是 100,结果被解析成 0.0001,整个反馈系统瞬态波形全乱。后来养成一个习惯:受控源参数一律用纯数字和科学计数法,不用单位后缀,比如写1e5,不写100k,能少很多歧义。
4.3 看不见输出波形 / 电阻不显示阻值
放好 vcvs 后跑完仿真,输出结果是平的或者完全没有信号,我会按下面顺序排查:
- 检查控制端是否接到了真正的信号源节点。用
v看节点电压,控制端有电压变化而输出没有,问题一定出在元件本身或连线。 - 检查输出端有没有负载。VCVS 输出悬空时,电压有值但不驱动任何东西,你在 testbench 里看不到有意义的结果。
- 检查 ADE 里选择的输出变量是不是你关心的节点电压。有些人建了多个 cellview,仿真的却是旧版本,输出当然对不上。
关于“Virtuoso 电阻不显示阻值”这个高频问题,虽然直接和 VCVS 无关,但排查思路可以类比。电阻不显示阻值,通常是在 Edit Object Properties 里改了r参数但没有勾选显示选项,或者在 schematic 上放置后没有刷新视图。按一下Ctrl+Shift+F或者重开 cellview,一般就能看到。这类显示问题的核心是:属性值和显示属性是两回事,改完 CDF 参数后要在 Display 选项里确认是否勾选了 visible,仿真器做不做得到是另一码事。
4.4 常见问题速查表
| 现象 | 可能的根因 | 解决办法 |
|---|---|---|
| 仿真报 undefined symbol | analogLib 库路径缺失 | 检查 cds.lib / lib.defs,刷新库路径 |
| DC 不收敛 | 两个 VCVS 形成代数环 | 在反馈环上并联小电容或大电阻,打破死循环 |
| 瞬态仿真极慢 | VCVS 输出跳变无压摆率限制 | 输出端加 RC 低通,限制高频分量 |
| 输出幅值离谱 | VCVS 无电源轨限制 | 加限幅二极管 / 齐纳网络 |
| 输出一点信号都没有 | 输出端悬空或没加负载 | 接负载电阻,检查引脚名是否接反 |
| 参数解析不对 | 写了带单位的增益 | 用纯数字或科学计数法填 Gain |
| 电阻不显示阻值 | 属性显示未开启 | 按 q 检查 CDF 参数,勾选 visible 后刷新 |
5. 实操心得与扩展建议
用 VCVS 这么多年,我的总体体会是:它是一个“信任成本”很低的理想元件,但必须限定在合适场景里用。架构探索、环路稳定性预判、行为级模型验证,这些都是它非常擅长的领域。可一旦进入版图前仿真阶段,VCVS 的“理想性”就变成了一种缺陷——没有输出阻抗、没有失调、没有噪声,任何基于 VCVS 的性能指标都只能当作理想极限参考,不能当作真实流片预期。
在 Virtuoso 里我还有一个使用习惯:给每个 VCVS 的 instance 起一个有意义的名字,比如vcvs_preamp、vcvs_lpf_buffer,而不是让它自动生成e1、e2。这样在网表定位问题、在波形图里区分关键是哪条曲线时,一秒钟就能对上号。特别是项目做到后期,一个 testbench 里有三四个 vcvs 的时候,命名规范带来的收益非常明显。
后续你如果想进一步扩展,可以尝试在 Cadence 里用 verilog-a 写一个带限压、带极点、带噪声的运放宏模型,把 VCVS 替换成你自己定义的可控源。这样做的好处是:模型参数可以是带宽、压摆率、输出噪声谱密度这些和真实运放 datasheet 对应的物理量,整个行为级验证的置信度会再上一个台阶。从 VCVS 起步,逐步建立属于自己的宏模型库,是一条很值得投入的技术路线。