【问题标题】:Model I-V in PythonPython 中的模型 I-V
【发布时间】:2013-02-03 06:06:16
【问题描述】:

模型 I-V。

方法: 执行积分,作为 E 的函数,它为每个使用的电压值输出电流。这对 v_values 数组重复。公式如下。

虽然此等式中的限制范围从-infinf,但必须限制限制,以便 (E+eV)^2-\Delta^2>0 和 E^2-\Delta^2> 0、避免两极。 (\Delta_1 = \Delta_2)。因此,目前有两个积分,限制从-inf-gap-e*vgapinf

但是,我一直返回math range error,尽管我相信我已经通过使用上述限制排除了麻烦的 E 值。错误粘贴:http://pastie.org/private/o3ugxtxai8zbktyxtxuvg

对于这个问题的含糊之处深表歉意。但是,任何人都可以看到明显的错误或代码滥用吗?

我的尝试:

from scipy import integrate
from numpy import *
import scipy as sp
import pylab as pl
import numpy as np
import math

e = 1.60217646*10**(-19)
r = 3000
gap = 400*10**(-6)*e
g = (gap)**2
t = 0.02
k = 1.3806503*10**(-23)
kt = k*t

v_values = np.arange(0,0.001,0.0001)

I=[]
for v in v_values:
    val, err = integrate.quad(lambda E:(1/(e*r))*(abs(E)/np.sqrt(abs(E**2-g)))*(abs(E+e*v)/(np.sqrt(abs((E+e*v)**2-g))))*((1/(1+math.exp((E+e*v)/kt)))-(1/(1+math.exp(E/k*t)))),-inf,(-gap-e*v)*0.9)
    I.append(val)
I = array(I)

I2=[]
for v in v_values:
    val2, err = integrate.quad(lambda E:(1/(e*r))*(abs(E)/np.sqrt(abs(E**2-g)))*(abs(E+e*v)/(np.sqrt(abs((E+e*v)**2-g))))*((1/(1+math.exp((E+e*v)/kt)))-(1/(1+math.exp(E/k*t)))),gap*0.9,inf)
    I2.append(val2)
I2 = array(I2)

I[np.isnan(I)] = 0
I[np.isnan(I2)] = 0

pl.plot(v_values,I,'-b',v_values,I2,'-b')
pl.show()

【问题讨论】:

  • 如果轴上有极点,难道你真的不想用复分析做这个积分吗?计算残差要容易得多。
  • 重新调整您的变量,以便 数值计算 不涉及非常小的浮点数,例如 ke 等。在进行纯数学时一切都很好,但数值算法当浮点数很小时,通常不能很好地工作。
  • 您在第二个玻尔兹曼项中exp 的参数的分母中缺少大括号,或者您只是忘记将k*t 替换为kt。此外,您正在整合[0.9*gap-ev, 0.9*gap]。也许你想把它分成两个积分:一个在(-inf,-0.9*gap-ev],一个在[0.9*gap, inf)
  • 此外,被积函数的前两项的分母中没有abs。将它们放在那里会隐藏错误的集成范围。
  • 让您的代码更易于阅读和调试的风格提示: (1) 将长行拆分为多个较短的行; (2) 使用def而不是lambda,除非功能极其简单; (3) 将复杂的公式拆分为多个步骤(例如将 f(E) 定义为单独的函数)。 :-D

标签: python numpy scipy integration physics


【解决方案1】:

这个问题更适合Computational Science 网站。仍然有一些要点供您考虑。

首先,积分范围是(-oo, -eV-gap) U (-eV+gap, +oo)(-oo, -gap) U (gap, +oo)的交集。有两种可能的情况:

  • 如果eV < 2*gap 则允许的能量值在(-oo, -eV-gap) U (gap, +oo) 中;
  • 如果eV > 2*gap 则允许的能量值在(-oo, -eV-gap) U (-eV+gap, -gap) U (gap, +oo) 中。

其次,您在非常低的温度区域工作。当t 等于 0.02 K 时,玻尔兹曼因子的分母为 1.7 µeV,而能隙为 400 µeV。在这种情况下,指数的值对于正能量来说是巨大的,它很快就会超出 Python 使用的双精度浮点数的限制。由于这是最小可能的正能量,因此在更高的能量下事情不会变得更好。对于负能量,该值将始终非常接近于零。请注意,在此温度下,费米-狄拉克分布具有非常尖锐的边缘,类似于反射的 theta 函数。在E = gap,您将拥有大约 6.24E+100 的 exp(E/kT)。当E/kT > 709.78E > 3.06*gap 时,您将超出范围。

然而,使用这样的能量是没有意义的,因为在那个温度下,两个费米函数之间的差异在[-eV, 0] 区间之外很快变为零,当V < (2*gap)/e(0.8毫伏)。这就是为什么人们会期望当偏置电压小于 0.8 mV 时电流会非常接近于零。当大于 0.8 mV 时,积分的主要值将来自 (-eV+gap, -gap) 中的被积函数,尽管一些非零值将来自靠近奇点的区域 E = gap 和一些来自靠近E = -eV-gap 处的奇点。 您不应该避免 DoS 中的奇点,否则您将无法在 I(V) 曲线中获得预期的不连续性(垂直线)(图片取自 Wikipedia):

相反,您必须在每个奇点附近导出等效的近似表达式并将它们整合。

如您所见,被积函数的值有许多特殊情况,在进行数值计算时必须将它们全部考虑在内。如果您不想这样做,您可能应该求助于其他一些数学软件包,例如 Maple 或 Mathematica。这些具有更复杂的数值积分例程,并且可能能够直接处理您的公式。

请注意,这不是试图回答您的问题,而是很长的评论,不适合任何评论字段。

【讨论】:

    【解决方案2】:

    数学范围错误的原因是您的指数趋于无穷大。以v = 0.0009E = 5.18e-23 为例,表达式exp((E + e*v) / kt)(我更正了Hristo Liev 在您的Python 表达式中指出的错字)是exp(709.984..),这超出了您可以用双精度数字表示的范围(最多约100 万)。 1E308)。

    两个附加说明:

    • 正如其他人所指出的,您可能应该使用提供较小范围内的数字的单位系统来重新调整方程式。也许,原子单位是一个可能的选择,因为它会设置e = 1,但我没有尝试将你的方程转换成它。 (可能你的时间步长会变得相当大,因为在原子单位中时间单位大约是 1/40 fs)。

    • 通常,浮点数使用指数表示法:e = 1.60217E-19 而不是e = 1.60217*10**(-19)

    【讨论】:

    • (E+e*v)/kt 是无量纲的(能量除以能量),无论选择何种单位,其值都是相同的。对于整个被积函数也是如此,因为其他两个表达式也是无量纲的。该问题的唯一正确解决方案是将积分范围拆分为多个区间,并为每个区间推导出一个不会导致上溢/下溢的适当近似表达式(例如,使用泰勒级数)。
    • 当然是这样。我更多地指的是诸如 SI 单位中的电子电荷之类的先决因素,这是可以摆脱的。但我同意,这并不能解决指数函数的问题。
    【解决方案3】:

    最终解决此问题的最佳方法是使用重载函数来防止E 变量超过\Delta 变量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-03
      • 1970-01-01
      • 1970-01-01
      • 2021-07-15
      • 1970-01-01
      • 2020-08-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多