4. 理想开关模型:Verilog-A建模、导通电阻与关断电容、仿真验证

好,咱们进入第四章。前面聊了采样电路的基本概念和失真来源,现在得动真格的了——搭模型。

你可能会问:「理想开关嘛,不就是一根导线连过去、断开就完事了?」嗯,我刚开始也这么想。直到有一次做高速ADC的前端设计,用理想开关仿出来的SFDR漂亮得不行,结果流片回来一测,直接掉了20dB。问题出在哪?就是开关模型太「理想」了,忽略了导通电阻和关断电容这些寄生参数。

所以这一章,咱们就好好聊聊怎么用Verilog-A给理想开关建模,把导通电阻、关断电容这些「不理想」的东西加进去,最后再验证模型对不对。

4.1 为什么需要Verilog-A模型?

说白了,SPICE自带的开关模型(比如sw或vswitch)太粗糙了。它们只能模拟通断,没法精确控制导通电阻随电压、温度的变化,更别提关断电容的非线性了。

我个人习惯用Verilog-A来做行为级建模。原因有三:

  • 精度可控:你可以把导通电阻写成电压的函数,模拟沟道调制效应。
  • 参数化:一个模型调几个参数,就能适配不同工艺、不同尺寸的开关。
  • 仿真速度快:比全晶体管级模型快一个数量级,适合做系统级仿真。

小提示:Verilog-A模型虽然快,但别用它做精确的噪声仿真。噪声分析还是得靠晶体管级模型。

4.2 理想开关的Verilog-A建模

咱们先搭一个最基础的理想开关模型。它有三个端口:输入in、输出out、控制ctrl。控制信号为高时导通,为低时关断。

下面是我常用的模板:

// 理想开关 Verilog-A 模型
`include "disciplines.vams"
`include "constants.vams"

module ideal_switch (in, out, ctrl);
    inout in, out;
    input ctrl;
    electrical in, out, ctrl;

    parameter real Ron = 1.0;      // 导通电阻,单位 Ohm
    parameter real Roff = 1.0e9;   // 关断电阻,单位 Ohm
    parameter real Vth = 0.5;      // 阈值电压,单位 V

    real R;

    analog begin
        // 控制信号判断
        if (V(ctrl) > Vth)
            R = Ron;
        else
            R = Roff;

        // 通过欧姆定律描述开关行为
        I(in, out) <+ (V(in) - V(out)) / R;
    end
endmodule

这个模型很简单,但已经能用了。Ron和Roff分别控制导通和关断时的电阻。你想想看,如果Ron设成1Ω,Roff设成1GΩ,那这个开关在导通时几乎没压降,关断时漏电流可以忽略。

注意:实际仿真时,Roff别设太大,否则会导致收敛问题。我一般设到1e9就够用了,再大仿真器容易报错。

4.3 加入导通电阻的非线性

实际MOS开关的导通电阻不是常数。它会随输入电压变化,尤其是在深亚微米工艺下,沟道调制效应很明显。

我在项目中遇到过一个问题:一个采样开关在输入电压接近VDD/2时,导通电阻突然变大,导致采样时间常数变化,引入谐波失真。后来我在模型里加了电压依赖项,才把这个问题复现出来。

改进后的模型如下:

// 非线性导通电阻 Verilog-A 模型
module switch_nonlinear (in, out, ctrl);
    inout in, out;
    input ctrl;
    electrical in, out, ctrl;

    parameter real Ron0 = 1.0;     // 零偏导通电阻,单位 Ohm
    parameter real K_v = 0.1;      // 电压依赖系数
    parameter real Roff = 1.0e9;   // 关断电阻
    parameter real Vth = 0.5;

    real R, Vx;

    analog begin
        Vx = (V(in) + V(out)) / 2.0;  // 取平均电压

        if (V(ctrl) > Vth) begin
            // 导通电阻随电压变化
            R = Ron0 * (1.0 + K_v * (Vx - 0.5));
            if (R < 0.1) R = 0.1;  // 防止电阻为负
        end else begin
            R = Roff;
        end

        I(in, out) <+ (V(in) - V(out)) / R;
    end
endmodule

这里我用了K_v系数来模拟电阻随电压的变化。实际工艺中,这个系数可以从晶体管级仿真提取出来。

4.4 关断电容的影响

很多人只关注导通电阻,忽略了关断电容。其实,关断电容会引入电荷注入和时钟馈通,严重时会让采样值偏移好几个LSB。

我记得有一次做12位SAR ADC,采样开关关断后,输出总有一个固定的偏移。查了半天,发现是开关的关断电容和采样电容形成了分压,导致电荷重新分配。

所以,模型里必须加上关断电容。下面是我常用的做法:

// 带关断电容的开关模型
module switch_with_cap (in, out, ctrl);
    inout in, out;
    input ctrl;
    electrical in, out, ctrl;

    parameter real Ron = 1.0;
    parameter real Roff = 1.0e9;
    parameter real Coff = 1.0e-15;  // 关断电容,单位 F
    parameter real Vth = 0.5;

    real R;

    analog begin
        if (V(ctrl) > Vth)
            R = Ron;
        else
            R = Roff;

        // 主开关路径
        I(in, out) <+ (V(in) - V(out)) / R;

        // 关断电容:只在关断时接入
        if (V(ctrl) < Vth) begin
            I(in, out) <+ Coff * ddt(V(in) - V(out));
        end
    end
endmodule

注意,这里我用ddt()函数来描述电容的电流-电压关系。只在关断时接入电容,这样导通时不会影响速度。

关键点:关断电容的值通常很小(fF量级),但在高频采样时,它的影响会被放大。如果你的采样率超过100MHz,一定要把这个参数加进去。

4.5 模型验证:仿真与对比

模型搭好了,怎么验证对不对?我的做法是三步走:

  1. 直流扫描:看导通电阻随输入电压的变化是否符合预期。
  2. 瞬态响应:给一个阶跃信号,看开关的开启和关断时间。
  3. 谐波分析:用正弦波输入,看输出信号的THD。

下面是一个典型的验证电路设置:

参数 值 说明
输入信号 正弦波,1Vpp,10MHz 测试线性度
控制信号 方波,0~1.8V,50MHz 模拟采样时钟
负载电容 1pF 模拟采样电容
导通电阻 10Ω 理想值
关断电容 10fF 典型值

仿真结果出来后,我会对比理想模型和非线性模型的THD。如果非线性模型的THD比理想模型高了10dB以上,那就说明你的模型成功复现了实际电路的问题。

4.6 知识体系总览

下面这张图总结了本章的核心逻辑:

理想开关模型知识体系 Verilog-A 开关建模目标 导通电阻 (Ron) 关断电阻 (Roff) 关断电容 (Coff) 线性/非线性电阻模型 理想关断/高阻态 ddt() 电容行为建模 验证:直流扫描 → 瞬态响应 → 谐波分析 (THD) 核心思路:从理想到非理想,逐步增加寄生参数,逼近真实电路行为

4.7 避坑指南

最后,分享几个我踩过的坑:

  • 收敛问题:关断电阻别设太大,超过1e10就容易不收敛。我一般用1e9。
  • 电容初始条件:带电容的模型,仿真时记得设ic参数,否则第一个仿真点可能出错。
  • 控制信号斜率:实际时钟信号有上升时间,模型里最好用transition函数模拟,别用理想阶跃。

经验之谈:如果你在做混合信号仿真,建议把开关模型单独放在一个cell里,方便替换。从理想模型到晶体管级模型,一步到位,不用改testbench。