我正在尝试使用 FiPy 来模拟太阳能电池,但即使对于简单的测试用例,我也很难获得合理的结果。
我的测试问题是在黑暗中平衡的突然 1D pn 同质结。方程的控制系统是没有额外生成或重组的半导体方程。
泊松方程用介电常数ε确定半导体中的电场 ( φ ),给定电子 ( n )、空穴 ( p )、施主 ( N D ) 和受主 ( N A )的密度,其中电子是q:
∇² φ = q ( p - n + N D - N A ) / ε
电子和空穴随电流密度J漂移和扩散,这取决于它们的迁移率 ( μ ) 和扩散常数 ( D ):
J n = qμ n n E + qD n ∇n
J p = qμ p p E - qD p ∇n
系统中电荷的演变由电子和空穴连续方程解释:
∂n/∂t = (∇· J n ) / q
∂p/∂t = - (∇· J p ) / q
可以用 FiPy 规范形式表示为:
∂n/∂t = μ n ∇·(− n ∇ φ ) + D n ∇² n
∂p/∂t = − ( μ p ∇·(− p ∇ φ ) − D p ∇² n )
为了尝试解决 FiPy 中的问题,我首先导入模块并定义物理参数。
from __future__ import print_function, division
import fipy
import numpy as np
import matplotlib.pyplot as plt
eps_0 = 8.8542e-12 # Permittivity of free space, F/m
q = 1.6022e-19 # Charge of an electron, C
k = 1.3807e-23 # Boltzmann constant, J/K
T = 300 # Temperature, K
Vth = (k*T)/q # Thermal voltage, eV
N_ap = 1e22 # Acceptor density in p-type layer, m^-3
N_an = 0 # Acceptor density in n-type layer, m^-3
N_dp = 0 # Donor density in p-type layer, m^-3
N_dn = 1e22 # Donor density in n-type layer, m^-3
mu_n = 1400.0e-4 # Mobilty of electrons, m^2/Vs
mu_p = 450.0e-4 # Mobilty of holes, m^2/Vs
D_p = k*T*mu_p/q # Hole diffusion constant, m^2/s
D_n = k*T*mu_n/q # Electron diffusion constant, m^2/s
eps_r = 11.8 # Relative dielectric constant
n_i = (5.29e19 * (T/300)**2.54 * np.exp(-6726/T))*1e6
V_bias = 0
然后创建网格、解决方案变量和掺杂配置文件。
nx = 20000
dx = 0.1e-9
mesh = fipy.Grid1D(dx=dx, nx=nx)
Ln = Lp = (nx/2) * dx
phi = fipy.CellVariable(mesh=mesh, hasOld=True, name='phi')
n = fipy.CellVariable(mesh=mesh, hasOld=True, name='n')
p = fipy.CellVariable(mesh=mesh, hasOld=True, name='p')
Na = fipy.CellVariable(mesh=mesh, name='Na')
Nd = fipy.CellVariable(mesh=mesh, name='Nd')
然后我在单元中心上设置一些初始值,并对所有参数施加狄利克雷边界条件。
x = mesh.cellCenters[0]
n0 = n_i**2 / N_ap
nL = N_dn
p0 = N_ap
pL = n_i**2 / N_dn
phi_min = -(Vth)*np.log(p0/n_i)
phi_max = (Vth)*np.log(nL/n_i) + V_bias
Na.setValue(N_an, where=(x >= Lp))
Na.setValue(N_ap, where=(x < Lp))
Nd.setValue(N_dn, where=(x >= Lp))
Nd.setValue(N_dp, where=(x < Lp))
n.setValue(N_dn, where=(x > Lp))
n.setValue(n_i**2 / N_ap, where=(x < Lp))
p.setValue(n_i**2 / N_dn, where=(x >= Lp))
p.setValue(N_ap, where=(x < Lp))
phi.setValue((phi_max - phi_min)*x/((Ln + Lp)) + phi_min)
phi.constrain(phi_min, mesh.facesLeft)
phi.constrain(phi_max, mesh.facesRight)
n.constrain(nL, mesh.facesRight)
n.constrain(n_i**2 / p0, mesh.facesLeft)
p.constrain(n_i**2 / nL, mesh.facesRight)
p.constrain(p0, mesh.facesLeft)
我将泊松方程表示为
eps = eps_0*eps_r
rho = q * (p - n + Nd - Na)
rho.name = 'rho'
poisson = fipy.ImplicitDiffusionTerm(coeff=eps, var=phi) == -rho
连续性方程为
cont_eqn_n = (fipy.TransientTerm(var=n) ==
(fipy.ExponentialConvectionTerm(coeff=-phi.faceGrad*mu_n, var=n)
+ fipy.ImplicitDiffusionTerm(coeff=D_n, var=n)))
cont_eqn_p = (fipy.TransientTerm(var=p) ==
- (fipy.ExponentialConvectionTerm(coeff=-phi.faceGrad*mu_p, var=p)
- fipy.ImplicitDiffusionTerm(coeff=D_p, var=p)))
并通过耦合方程和扫描求解:
eqn = poisson & cont_eqn_n & cont_eqn_p
dt = 1e-12
steps = 50
sweeps = 10
for step in range(steps):
phi.updateOld()
n.updateOld()
p.updateOld()
for sweep in range(sweeps):
eqn.sweep(dt=dt)
我已经尝试过网格大小、时间步长、时间步长数、扫描次数等的不同值。我看到了一些变化,但没有找到一组给我一个现实解决方案的条件。我认为问题可能在于当前术语的表达方式。
通常在求解这些方程时,电流密度是使用 Scharfetter-Gummel (SG) 离散化方案来近似的,而不是直接离散化。在 SG 方案中,通过电池面的电子电流密度 ( J ) 近似为定义在电池K和L两侧的中心的电势 ( φ ) 和电荷密度 ( n ) 值的函数
J n,KL = qμ n V T [ B ( δφ/V T ) n L - B (- δφ/V T ) n K )
其中q是电子上的电荷,μ n是电子迁移率,V T是热电压,δφ = φ L - φ K,B ( x ) 是伯努利函数x /( e x -1)。
如何在 FiPy 中实施该方案对我来说并不明显。我已经看到有一个scharfetterGummelFaceVariable
,但我无法从文档中确定它是否适合或打算解决这个问题。查看代码,它似乎只计算伯努利函数乘以因子e φ L。是否可以直接使用scharfetterGummelFaceVariable
来解决此类问题?如果是这样,怎么做?如果没有,是否有替代方法可以让我使用 FiPy 模拟半导体设备?