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Ω,结果跑出来的电阻值从负的到几万欧都有,完全乱套了。

警告:容差参数必须是0到1之间的小数。写成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σ

关键点:mc(标称值, 容差) 生成的是高斯分布,容差 = 3σ / 标称值。也就是说,99.7%的样本会落在标称值 ± 容差范围内。

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()很像,但用法完全不同。到时候我会对比着讲,你们会更容易理解。