Verilog-A/AMS建模基础
好,咱们进入第四章。这一章讲的是Verilog-A和AMS建模基础。说实话,很多做射频芯片的工程师对Verilog-A有点怵,觉得它是个新语言。其实不然,你只要有Verilog基础,上手Verilog-A就是分分钟的事。
我个人习惯把Verilog-A看作是「模拟世界的Verilog」。它保留了数字Verilog的模块化思想,但加入了连续时间、连续值的描述能力。说白了,就是让你能用代码描述一个运放、一个混频器、甚至一个完整的锁相环。
Verilog-A语言简介
Verilog-A是Verilog-AMS的一个子集,专门用来描述模拟和混合信号系统。它诞生于90年代,后来被Accellera标准化。我记得刚入行那会儿,大家还在用SPICE跑整个收发机,跑一次要三天。后来用了Verilog-A建模,仿真速度提升了两个数量级。
它的核心特点就三个:
- 连续时间:不像数字Verilog只在时钟边沿变化,Verilog-A的信号是随时间连续变化的
- 守恒系统:支持基尔霍夫定律,电流电压都能描述
- 行为级描述:用数学表达式代替晶体管级电路
关键点:Verilog-A不是用来替代SPICE的,而是用来做系统级验证的。你想想看,一个完整的射频收发机,用晶体管级仿真要跑一周,用Verilog-A模型可能只要一小时。
模块定义与端口声明
模块定义这块,和数字Verilog很像,但有个关键区别——端口类型。数字Verilog只有input、output、inout,而Verilog-A多了电气端口(electrical)。
来看个例子:
// 一个简单的放大器模块
module amplifier (vin, vout);
// 电气端口声明
electrical vin, vout;
// 参数定义
parameter real gain = 10.0;
parameter real rin = 1e6; // 输入阻抗
parameter real rout = 50; // 输出阻抗
// 内部节点
electrical vmid;
// 模拟行为描述
analog begin
// 输入阻抗
I(vin) <+ V(vin) / rin;
// 增益级
V(vmid) <+ gain * V(vin);
// 输出阻抗
V(vout) <+ V(vmid) - I(vout) * rout;
end
endmodule
这里有几个地方要注意:
electrical是Verilog-A特有的类型,代表一个电气节点analog begin ... end是模拟行为块的标志<+是贡献操作符,表示「把右边的值赋给左边的量」
我的经验:刚开始写Verilog-A时,最容易犯的错误是把<+写成=。这两个完全不一样。<+是连续贡献,=是瞬态赋值。我曾经因为这个bug查了整整两天,最后发现就是少了个尖括号。
模拟行为描述
模拟行为描述是Verilog-A最强大的地方。你可以用数学公式直接描述电路行为,而不需要关心晶体管级的实现。
基本操作符
| 操作符 | 含义 | 示例 |
|---|---|---|
| V(net) | 获取节点电压 | V(vin) 表示输入电压 |
| I(net) | 获取流入节点的电流 | I(vout) 表示输出电流 |
| ddt(x) | 对x求时间导数 | ddt(V(cap)) 表示电容电流 |
| idt(x) | 对x求时间积分 | idt(I(ind)) 表示电感磁通 |
一个混频器的例子
咱们写个吉尔伯特混频器的行为模型。这东西在射频里太常见了:
module mixer (rf, lo, if_out);
electrical rf, lo, if_out;
parameter real conv_gain = 1.0;
parameter real nf = 10.0; // 噪声系数,单位dB
real gain_linear;
real noise_power;
analog begin
// 把dB值转成线性
gain_linear = pow(10, conv_gain / 20);
// 理想混频:乘法器
V(if_out) <+ gain_linear * V(rf) * V(lo);
// 加噪声(简化模型)
noise_power = pow(10, nf/10) * `P_K * $temperature;
V(if_out) <+ white_noise(noise_power, "thermal");
end
endmodule
注意:这里的噪声模型是简化的。实际项目中,噪声系数会随频率变化,还要考虑1/f噪声。我曾经在一个接收机项目中用了这个简化模型,结果系统仿真和实测差了3dB。后来加了频率相关的噪声模型才对上。
非线性行为描述
射频电路最头疼的就是非线性。Verilog-A可以用多项式或查表来描述:
// 用多项式描述放大器非线性
module pa_nonlinear (vin, vout);
electrical vin, vout;
parameter real a1 = 10.0; // 线性增益
parameter real a2 = 0.5; // 二阶系数
parameter real a3 = -0.1; // 三阶系数(负值表示压缩)
analog begin
V(vout) <+ a1 * V(vin) + a2 * pow(V(vin), 2) + a3 * pow(V(vin), 3);
end
endmodule
你想想看,用这个模型跑IM3仿真,几秒钟就出结果。要是用晶体管级,光DC仿真就要跑半天。
条件语句与事件检测
Verilog-A也支持条件判断,但和数字Verilog不太一样:
module comparator (vin, vref, vout);
electrical vin, vref, vout;
parameter real voh = 1.8; // 输出高电平
parameter real vol = 0.0; // 输出低电平
parameter real slew_rate = 1e6; // 压摆率
real vout_int;
analog begin
// 比较器核心
if (V(vin) > V(vref)) begin
vout_int = voh;
end else begin
vout_int = vol;
end
// 限制压摆率
V(vout) <+ slew_rate * idt(vout_int - V(vout));
end
endmodule
避坑指南:我曾经在比较器模型里直接用阶跃函数,结果仿真器不收敛。后来加了压摆率限制,问题就解决了。记住,模拟世界里没有完美的阶跃,一定要考虑转换速率。
写在后面
Verilog-A建模的核心思想就八个字:用数学代替电路。你不需要知道每个晶体管怎么偏置,只需要知道输入输出关系。这对于系统级仿真来说,效率提升是巨大的。
下一章咱们会深入讲Verilog-AMS,也就是把数字和模拟混合在一起建模。到时候你会看到,一个完整的射频收发机,用Verilog-AMS描述起来有多优雅。
嗯,今天就到这儿。记住,多写多练,Verilog-A其实没那么神秘。