4. mc()函数详解:语法、参数与高斯分布的关系
好,咱们今天来聊聊蒙特卡洛分析里最核心的一个工具——mc()函数。
说实话,我刚开始用LTspice做蒙特卡洛时,第一反应是:这不就是个随机数生成器吗?后来踩了几个坑才发现,这里面的门道比想象中多得多。尤其是mc()和高斯分布的关系,很多人理解错了,结果仿真出来的良率数据完全不能用。
4.1 mc()函数的语法
先看最基本的语法格式:
mc(标称值, 容差)
就这么简单。两个参数,一个逗号隔开。
举个例子:
R1 1 0 {mc(10k, 0.01)}
这表示一个标称10kΩ的电阻,容差是±1%。每次蒙特卡洛运行时,LTspice会从这个范围内随机取一个值。
嗯,这里要注意:容差是相对值,不是绝对值。0.01就是1%,不是1Ω。我见过有人写mc(10k, 100),以为容差是100Ω,结果跑出来的电阻值从负的到几万欧都有,完全乱套了。
mc(10k, 0.1)表示±10%,写成mc(10k, 1)表示±100%。千万别搞反了。
4.2 mc()函数的参数详解
咱们把两个参数拆开细说。
第一个参数:标称值
这个好理解,就是你期望的典型值。可以是数字,也可以是表达式。比如:
mc(1.2V, 0.05) ; 1.2V基准电压,±5%容差
mc(100e3, 0.01) ; 100kΩ电阻,±1%容差
mc({Vref}, 0.02) ; 引用变量Vref,±2%容差
我个人习惯把标称值写成表达式,这样方便统一调整。比如在.spice文件里定义一个.param Vref=1.2,然后所有地方都用{Vref}引用。改一个地方,全局生效。
第二个参数:容差
这个参数决定了随机值的散布范围。但注意——这个散布不是均匀分布,而是高斯分布。
什么意思呢?
假设你写mc(10k, 0.01),LTspice会生成一个高斯分布,其均值是10k,标准差是10k × 0.01 = 100Ω。也就是说,大约68%的样本落在10k ± 100Ω范围内,95%落在±200Ω范围内。
我当年第一次用的时候,以为mc()是均匀分布,结果算良率时发现怎么都不对。后来查手册才明白,mc()默认就是高斯分布,而且容差参数对应的是3σ。
4.3 mc()函数与高斯分布的关系
这里我展开讲讲,因为很多人在这里栽跟头。
高斯分布的概率密度函数是:
f(x) = (1/(σ√(2π))) * exp(-(x-μ)²/(2σ²))
在mc()函数里:
- μ = 标称值
- σ = 标称值 × 容差 / 3
举个例子,mc(10k, 0.01):
- μ = 10000
- σ = 10000 × 0.01 / 3 ≈ 33.33
- 3σ = 100,正好是容差范围
为什么会这样设计?
因为实际元器件的参数分布通常服从高斯分布,而且厂商给出的容差一般对应3σ。比如一个±1%的电阻,意思是99.7%的产品误差在±1%以内。LTspice的mc()就是模拟这个物理现实。
flat()函数。但说实话,我在实际项目中几乎不用flat(),因为真实元器件很少是均匀分布的。高斯分布更贴近物理世界。
4.4 实际应用中的注意事项
讲几个我踩过的坑。
第一,容差不能太大。 如果你写mc(10k, 0.5),σ = 10k × 0.5 / 3 ≈ 1667,这意味着有些样本会跑到负值去。虽然高斯分布理论上可以取任何值,但负电阻在物理上不存在。LTspice不会报错,但仿真结果会莫名其妙。
第二,多次调用同一个mc()。 如果你在电路里多次使用mc(10k, 0.01),每次调用都会生成独立的随机值。这模拟的是不同电阻之间的失配。但如果你想要所有10k电阻都取同一个随机值,需要用mc()配合.param定义全局变量。
第三,种子值的影响。 LTspice的随机数生成器有默认种子。每次运行蒙特卡洛,随机序列都不同。如果你想要可重复的结果,可以在仿真命令里加seed=12345。我曾经调试一个良率问题,每次跑结果都不一样,加了固定种子后才找到bug。
.step param run 1 100 1
.tran 1m
.param Rval=mc(10k, 0.01)
.backanno
.option seed=42
这样每次跑100次蒙特卡洛,随机序列都是固定的,方便调试。
4.5 一个完整的例子
最后给个完整的例子,你们可以自己跑跑看。
* 分压电路蒙特卡洛分析
V1 1 0 5
R1 1 2 {mc(10k, 0.01)}
R2 2 0 {mc(10k, 0.01)}
.tran 1m
.step param run 1 1000 1
.meas Vout AVG V(2)
.backanno
.option seed=12345
这个电路里,两个电阻都是10kΩ ±1%。理论上分压应该是2.5V。但实际因为电阻容差,Vout会在2.475V到2.525V之间波动(3σ范围)。跑1000次蒙特卡洛,你就能看到Vout的分布直方图,基本就是高斯分布。
嗯,说到这里,我想起一个项目。当时设计一个电压基准,要求输出精度±0.5%。我用了mc()做良率分析,发现怎么都达不到要求。后来发现是电阻的容差模型设错了——我用的是均匀分布,但实际电阻是高斯分布。改成mc()后,良率从60%跳到了85%。你看,一个函数用对用错,差别就这么大。
好了,mc()函数就讲到这里。下一节咱们聊聊gauss()函数,它和mc()很像,但用法完全不同。到时候我会对比着讲,你们会更容易理解。