编程函数包含负虚轴的切割
最终更新
我给论文的作者发了邮件,结果发现sigma的公式有个错误。我给pv的回答打了最高分,因为他们确实帮助我解决了问题。
第一次尝试
我正在尝试编写一个程序,用来数值表示下面这个函数:
,
这里的'+'和'-'上标表示当z接近分支切割线时的极限,这条切割线位于负虚数半轴上。H和J分别是汉克尔函数和贝塞尔函数。其余的变量(n_r, m, R)则与问题的几何形状有关。我希望在负虚数半轴上绘制这个函数关于k的图。我的当前代码(包含pv的修改)如下:
import scipy as sp
import numpy as np
import matplotlib.pyplot as plt
from numpy import pi
from scipy.special import jv, iv, kv, jvp, ivp, kvp
m = 11 # Mode number
nr = 2 # Index of refraction
R = 1 # Radius of cylinder
eps = 10e-8
def yv_imcut(n, z):
return -2/(pi*(1j)**n)*kv(n, -1j*z) + 2*(1j)**n/pi * (0.5j*pi) * iv(n,-1j*z)
def yvp_imcut(n, z):
return (n/z)*yv_imcut(n,z) - yv_imcut(n+1,z)
def hankel1_imcut(n, z):
return jv(n, z) + 1j*yv_imcut(n, z)
def h1vp_imcut(n, z):
return jvp(n, z, 1) + 1j*yvp_imcut(n, z)
# Define the characteristic equation
def Dm(n, z):
return nr*jvp(n, nr*z, 1) * hankel1_imcut(n, z) - jv(n, nr*z)*h1vp_imcut(n,z)
# Define the cut pole density function
def sigma(k,n):
return 4*(nr**2 - 1)*jv(n,nr*k*R)/(pi**2 * k * ((Dm(n, k*R-eps).real)**2 + (Dm(n, k*R+eps).imag)**2))
k = np.linspace(-eps*1j, -15j,1000)
y = sigma(k,m)
x = np.linspace(0,15,1000)
plt.plot(x, y.imag)
plt.show()
这是我在负虚数轴上绘制的sigma.imag的图:
这个图应该是这样的(看右边的m = 11曲线):
用户pv帮助我把汉克尔函数的切割线移到了负虚数半轴上,但我的sigma图还是不对。我在论文中注意到,sigma被描述为“纯虚数”(第五页顶部,第一列)。
这些公式和图来自这篇文章的第四页:http://arxiv.org/pdf/1302.0245v1.pdf
第二次尝试
文章的附录B说明了汉克尔函数在切割线两侧的差异:
根据这个关系,我们还可以找到汉克尔函数一阶导数在切割线两侧的差异:
我用这些公式写了一个脚本:
def hankel1_minus(n,z):
return hankel1(n,z) - 4*jv(n,z)
def h1vp_minus(n,z):
return (n/z)*hankel1_minus(n,z) - hankel1_minus(n+1,z)
def Dm_plus(n, z):
return nr *jvp(n, nr*z, 1) * hankel1(n, z) - jv(n, nr*z)*h1vp(n,z)
def Dm_minus(n, z):
return nr *jvp(n, nr*z, 1) * hankel1_minus(n,z) - jv(n, nr*z)*h1vp_minus(n,z)
def sigma(k,n):
return 4*(nr**2 - 1)*jv(n,nr*k*R)/(pi**2 * k * (Dm_plus(n, k*R) * Dm_minus(n,k*R)).real)
绘制这个sigma的结果与第一种方法是一样的。
1 个回答
在scipy中,H1的分支切割是在(-inf, 0)这个区间,而不是你引用的论文中提到的(-1j*inf, 0)。这就是你得到错误结果的原因。
我们可以通过一些巧妙的方法来解决这个问题,比如使用Y_nu的参数变换,正如我在评论中提到的。
假设我们考虑的是整数阶的n。我们有:
hankel1(n, z) = jv(n, z) + 1j*yv(n, z)
jv没有分支切割(因为是整数阶),但yv有。变换公式是:
yv(n, 1j*z) = -2/(pi*(1j)**n)*kv(n, z) + 2*(1j)**n/pi * (log(1j*z) - log(z))*iv(n,z)
换句话说,
yv(n, z) = -2/(pi*(1j)**n)*kv(n, -1j*z) + 2*(1j)**n/pi * (log(z) - log(-1j*z))*iv(n,-1j*z)
在Scipy中,kv(n,z)的分支切割是在(-inf, 0),而iv(n,z)没有分支切割(也是整数阶)。除了对数项,右边的分支切割正好是在(-1j*inf, 0),这正是我们想要的地方。剩下的就是要适当地选择对数项的分支切割。
正确的解析延续,其分支切割在(-1j*inf, 0)的形式是:
def yv_imcut(n, z):
return -2/(pi*(1j)**n)*kv(n, -1j*z) + 2*(1j)**n/pi * (0.5j*pi) * iv(n,-1j*z)
这在四个象限中的三个象限与yv(n, z)
完全一致。它的分支切割在(-1j*inf, 0)。而且,显然它是一个解析函数。因此,它与yv
是相同的,只是选择了不同的分支切割。
所以我们有:
def hankel1_imcut(n, z):
return jv(n, z) + 1j*yv_imcut(n, z)
显然这是一个在(-1j*inf, 0)有分支切割的汉克尔函数。
基于这个,你也可以计算出它的导数。