You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合scipy interp1d与mpmath quadosc实现高振荡积分

解决方案:高振荡球贝塞尔函数与衰减密度函数的积分计算

针对你遇到的mpmath.quadosc不支持数组输出的问题,以及高振荡积分失效的情况,提供以下几种可行方案:

方案1:逐个计算每个q对应的积分(适配mpmath.quadosc)

quadosc不支持返回数组类型的结果,因此可以循环遍历每个q值,单独计算积分。这样既利用了quadosc的振荡积分优化,又避开了数组输出的限制。

修改后的代码示例:

import numpy as np
from mpmath import besselj, sqrt, pi, besseljzero, inf, quadosc
from scipy.interpolate import interp1d

n = 1
q = np.geomspace(1e-7, 500, 1000)
# 构造模拟密度函数
x = np.geomspace(1e-7, 10, 1000)
y = np.exp(-(x-5)**2)
density = interp1d(x, y, kind='cubic', fill_value=0, bounds_error=False)

def spherical_jn_density_single(x, q_val, n=n):
    arg = q_val * x
    return besselj(n + 1/2, arg) * sqrt(pi / (2 * arg)) * density(x)

# 逐个计算每个q对应的积分
vals_density = []
for q_val in q:
    val = quadosc(
        lambda x: spherical_jn_density_single(x, q_val),
        [0, inf],
        zeros=lambda m: besseljzero(n + 1/2, m)
    )
    vals_density.append(float(val))
vals_density = np.array(vals_density)

方案2:使用SciPy的向量值振荡积分(更高效)

SciPy的scipy.integrate.quad_vec支持向量值被积函数,且可以通过指定振荡函数的零点来优化积分精度。结合scipy.special.jn_zeros获取球贝塞尔函数的零点,替代mpmath的实现:

import numpy as np
from scipy.integrate import quad_vec
from scipy.interpolate import interp1d
from scipy.special import jn, jn_zeros

n = 1
q = np.geomspace(1e-7, 500, 1000)
x = np.geomspace(1e-7, 10, 1000)
y = np.exp(-(x-5)**2)
density = interp1d(x, y, kind='cubic', fill_value=0, bounds_error=False)

# 用SciPy实现球贝塞尔函数(避免mpmath的类型问题)
def spherical_jn(x, n=n):
    return np.sqrt(np.pi/(2*x)) * jn(n + 1/2, x)

def integrand(x):
    arg = q[:, None] * x
    return spherical_jn(arg) * density(x)

# 获取球贝塞尔函数的前N个零点(用于振荡积分优化)
num_zeros = 200
zeros = jn_zeros(n + 1/2, num_zeros)
# 由于积分区间是[0, inf],截断到密度函数可忽略的区间(比如x=10,因为你的密度在x>10时几乎为0)
truncated_zeros = zeros[zeros <= 10 * q.max()]  # 对应x=zeros/q <=10

# 执行向量积分,指定振荡零点
result, error = quad_vec(
    integrand,
    0, 10,  # 截断区间,因为密度在x>10时已衰减到0
    points=truncated_zeros / q.max()  # 转换为x区间的零点
)

方案3:利用密度衰减特性截断积分区间+自适应振荡积分

由于密度函数在超过阈值后快速衰减,可以直接截断积分区间(比如x=10),然后使用SciPy的quad手动处理振荡特性,对每个q单独计算:

import numpy as np
from scipy.integrate import quad
from scipy.interpolate import interp1d
from scipy.special import jn

n = 1
q = np.geomspace(1e-7, 500, 1000)
x = np.geomspace(1e-7, 10, 1000)
y = np.exp(-(x-5)**2)
density = interp1d(x, y, kind='cubic', fill_value=0, bounds_error=False)

def spherical_jn(x, q_val, n=n):
    arg = q_val * x
    return np.sqrt(np.pi/(2*arg)) * jn(n + 1/2, arg)

vals_density = []
for q_val in q:
    # 截断积分区间到x=10,因为密度在此处已可忽略
    val, err = quad(
        lambda x: spherical_jn(x, q_val) * density(x),
        0, 10,
        epsabs=1e-8, epsrel=1e-8
    )
    vals_density.append(val)
vals_density = np.array(vals_density)

关键说明

  • 方案1兼容mpmath的quadosc,但循环计算效率较低,适合q数量不多的场景。
  • 方案2使用SciPy的向量积分,效率更高,适合大规模q网格,且利用零点优化振荡积分精度。
  • 方案3最简单,利用密度衰减截断区间,适合密度衰减极快的场景,精度依赖截断区间的选择。

内容的提问来源于stack exchange,提问作者Zezhong Zhang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 19:31:22