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

如何用scipy.fsolve限制变量范围求解纳米光纤HE11模式方程

限制bsk范围求解纳米光纤HE11模式的β值

我来帮你解决这个问题——你需要限制bsk的范围在n2到n1之间,因为你的目标函数在这个区间外要么无定义,要么会产生复数,导致fsolve无法正常工作。咱们一步步来调整你的代码:

先修正原代码的几个关键问题

首先你的代码里有几个容易导致错误的细节:

  • 波长单位转换错误:纳米转米应该是lamb_m = lamb_nm * 1e-9,而不是lamb_nm*1,否则波数k的计算完全不对
  • 变量名冲突:func2里的k0=k和你导入的修正贝塞尔函数k0重名,会覆盖函数引用,导致后续计算出错
  • 初始猜测值可能踩边界:比如循环里初始bskg=1.000刚好等于n2,容易触发平方根的边界问题

方法一:修改目标函数,强制限制bsk范围

我们可以在目标函数里加入判断:如果bsk超出[n2, n1]区间,就返回一个极大的数值,让fsolve自动往有效区间内搜索。同时确保初始猜测值落在有效区间内。

修改后的完整代码:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from scipy.special import jv, kn, jvp, kvp, j0, j1, k0, k1
from scipy.optimize import fsolve
import numpy as np
from numpy.lib import scimath as SM
import matplotlib.pyplot as plt

knp = kvp
kv = kn

def getBeta(a=125, n1=1.4, n2=1, lamb_nm=500, bskg=1.2):
    # 修正波长单位转换:纳米转米
    lamb_m = lamb_nm * 1e-9
    k = 2 * np.pi / lamb_m

    def func2(bsk):
        nu = 1
        # 重命名变量,避免和导入的k0函数冲突
        k0_val = k
        # 先判断bsk是否在有效区间内
        if bsk <= n2 or bsk >= n1:
            # 超出范围返回极大值,引导求解器往有效区间走
            return 1e10
        
        X = a * np.sqrt(k0_val**2 * (n1**2 - bsk**2))
        Y = a * np.sqrt((bsk**2 - n2**2) * k0_val**2)
        V = np.sqrt(X**2 + Y**2)
        
        # 计算目标函数
        term1 = -(n1**2 + n2**2)/(2*n1**2) * kvp(1, Y)/(Y * k1(Y))
        term2 = 1 / X**2
        sqrt_term = np.sqrt(
            ((n1**2 - n2**2)/(2*n1**2) * kvp(1, Y)/(Y * k1(Y)))**2 
            + (bsk**2 / n1**2) * (1/X**2 + 1/Y**2) * 2
        )
        term3 = j0(X)/(X * j1(X))
        
        result = term1 + term2 - sqrt_term - term3
        return result

    # 确保初始猜测值在有效区间内
    if not (n2 < bskg < n1):
        bskg = (n1 + n2) / 2  # 如果初始值无效,用区间中点替代
    beta = fsolve(func2, bskg)
    return beta[0]  # fsolve返回数组,取第一个元素

plt.figure()
plt.title("β vs Fiber Radius (HE11 Mode)")
x = np.arange(100, 1000)  # 光纤半径,单位nm
bskg = 1.1  # 初始猜测值落在1到1.4之间
y = np.array([], dtype=float)

for i in x:
    beta = getBeta(lamb_nm=500, a=i, bskg=bskg)
    y = np.append(y, beta)
    bskg = beta  # 用前一次的结果作为下一次的初始猜测,加速收敛

plt.plot(x, y)
plt.xlabel("Fiber Radius (nm)")
plt.ylabel("β (Propagation Constant)")
plt.show()

方法二:使用带边界约束的优化方法

fsolve本身不支持边界约束,如果你想更严格地限制bsk的范围,可以用scipy.optimize.minimize,把问题转化为最小化目标函数的平方,同时设置边界条件:

修改getBeta函数中的求解部分:

from scipy.optimize import minimize

def getBeta(a=125, n1=1.4, n2=1, lamb_nm=500, bskg=1.2):
    # ... 前面的代码和方法一一致,省略 ...
    
    # 定义最小化的目标:函数值的平方
    def min_func(bsk):
        return func2(bsk)**2
    
    # 设置边界:bsk必须在(n2, n1)之间,加小偏移避免边界上的复数问题
    bounds = [(n2 + 1e-6, n1 - 1e-6)]
    # 使用L-BFGS-B方法,支持边界约束
    res = minimize(min_func, x0=bskg, bounds=bounds, method='L-BFGS-B')
    
    if res.success:
        return res.x[0]
    else:
        # 如果求解失败,返回区间中点或者抛出警告
        print(f"求解失败: {res.message}")
        return (n1 + n2)/2

这种方法更可靠,因为求解器会严格在你指定的边界内搜索,不会出现超出范围的情况。

关键说明

  • 有效区间:因为n1=1.4,n2=1,所以bsk必须满足1 < bsk < 1.4,否则X或Y会出现复数,导致目标函数无意义
  • 初始猜测值:尽量落在有效区间内,这样求解器收敛更快,也更容易找到正确的解
  • 波长单位:一定要确保单位转换正确,否则波数k的计算会完全错误,导致整个求解结果无效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 11:07:42