首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用广义的已知公式拟合截面表面轮廓,得到系数并建立曲面的数学模型

用广义的已知公式拟合截面表面轮廓,得到系数并建立曲面的数学模型
EN

Stack Overflow用户
提问于 2017-01-25 21:23:36
回答 1查看 745关注 0票数 0

我设计了一个球面轮廓的光学系统.然后我制造和测量了这个镜头。我得到了一个横截面图,从测量制造的表面轮廓。(表面保持旋转对称性)

用于模拟所述非球面的公式是:

如何用横截面曲线拟合这个广义方程,得到相应的alpha系数?(alpha系数是指所提供的公式中的系数),我知道曲面的曲率半径。

我可以访问Python和Matlab (没有工具箱)来实现这一点。我也可以从曲线中获得数字化的、表格化的数据点。

EN

回答 1

Stack Overflow用户

发布于 2019-03-09 19:10:27

假设您有一个discreet数组,并且对于这个数组的每个值z(r)。你想要拟合一条曲线来估计非球面透镜的参数。我将像前面提到的那样使用lmfit来演示使用python的一种方法。

导入用于此操作的模块:

代码语言:javascript
运行
复制
import numpy as np
import matplotlib.pyplot as plt
from lmfit import Model, Parameters

定义凹凸棒透镜的功能:

代码语言:javascript
运行
复制
def asphere_complete(x, r0, k, a2, a4, a6, a8, a10, a12):
    r_squared = x ** 2.
    z_even_r = r_squared * (a2 + (r_squared * (a4 + r_squared * (a6 + r_squared * (a8 + r_squared * (a10 + (r_squared * a12)))))))

    square_root_term = 1 - (1 + k) * ((x / r0) ** 2)
    zg = (x ** 2) / (r0 * (1 + np.sqrt(square_root_term)))
    return z_even_r + zg

由于您没有提供任何数据,我将使用以下方法创建一些示例数据,包括人工噪声:

代码语言:javascript
运行
复制
def generate_dummy_data(x, asphere_parameters, noise_sigma, seed=12345):
    np.random.seed(seed)
    return asphere_complete(x, **asphere_parameters) + noise_sigma * np.random.randn(x.shape[0])

以下函数进行拟合并绘制结果曲线:

代码语言:javascript
运行
复制
def fit_asphere(r, z, fit_parameters):
    # create two subplots to plot the original data and the fit in one plot and the residual in another
    fig, axarr = plt.subplots(1, 2, figsize=(10, 5))
    fit_plot = axarr[0]
    residuum_plot = axarr[1]

    # configure first plot:
    fit_plot.set_xlabel("r")
    fit_plot.set_ylabel("z")
    fit_plot.grid()

    # configure second plot:
    residuum_plot.set_xlabel("r")
    residuum_plot.set_ylabel("$\Delta$z")
    residuum_plot.grid()

    # plot original data
    fit_plot.plot(r, z, label="Input")

    # create an lmfit model and the parameters
    function_model = Model(asphere_complete)

    # The fitting procedure may throw ValueErrors, if the radicand gets negative
    try:
        result = function_model.fit(z, fit_parameters, x=r)

        # To plot the resulting curve remove the parameters which were just used for the constraints
        opt_parameters = dict(result.values)
        opt_parameters.pop('r_max', None)
        opt_parameters.pop('radicand', None)

        # calculate z-values of fitted curve:
        z_fitted = asphere_complete(r, **opt_parameters)

        # calculate residual values
        z_residual = z - z_fitted

        # plot fit and residual:
        fit_plot.plot(r, z_fitted, label="Fit")
        residuum_plot.plot(r, z_residual, label="Residual")

        # legends:
        fit_plot.legend(loc="best")
        residuum_plot.legend(loc="best")

        print(result.fit_report())
    except ValueError as val_error:
        print("Fit Failed: ")
        print(val_error)

要设置示例数据的参数,我使用lmfitlmfit对象

代码语言:javascript
运行
复制
if __name__ == "__main__":
    parameters_dummy = Parameters()
    parameters_dummy.add('r0', value=-34.4)
    parameters_dummy.add('k', value=-0.98)
    parameters_dummy.add('a2', value=0)
    parameters_dummy.add('a4', value=-9.67e-9)
    parameters_dummy.add('a6', value=1.59e-10)
    parameters_dummy.add('a8', value=-5.0e-12)
    parameters_dummy.add('a10', value=0)
    parameters_dummy.add('a12', value=-1.0e-19)

创建示例数据:

代码语言:javascript
运行
复制
r = np.linspace(0, 35, 1000)
z = generate_dummy_data(r, parameters_dummy, 0.00001)

使用lmfit而不是scipy's curve_fit的原因是,平方根的根和平方根可能变成否定的。我们需要确保:

为此,我们需要像提到的here那样定义一个约束。让我们开始定义我们想要在拟合中使用的参数。基本半径是直接添加的:

代码语言:javascript
运行
复制
parameters = Parameters()
parameters.add('r0', value=-30, vary=True)

若要服从不等式,请添加一个不允许小于零的变量radicand。与其让k参与合适的常态,不如让它完全依赖于r0r_maxradicand。我们需要使用r_max,因为这个不等式对于极大的r是最有问题的。

它在下面用作expr。我使用bool标志来打开/关闭约束:

代码语言:javascript
运行
复制
keep_radicand_safe = True
if keep_radicand_safe:
    r_max = np.max(r)
    parameters.add('r_max', r_max, vary=False)
    parameters.add('radicand', value=0.98, vary=True, min=0)
    parameters.add('k', expr='(r0/r_max)**2*(1-radicand)-1')
else:
    parameters.add('k', value=-0.98, vary=True)

其余参数是直接添加的:

代码语言:javascript
运行
复制
parameters.add('a2', value=0, vary=False)
parameters.add('a4', value=0, vary=True)
parameters.add('a6', value=0, vary=True)
parameters.add('a8', value=0, vary=True)
parameters.add('a10', value=0, vary=False)
parameters.add('a12', value=0, vary=True)

现在,我们已经准备好开始并取得成果:

代码语言:javascript
运行
复制
fit_asphere(r, z, parameters)
plt.show()

在控制台上,您应该看到输出:

代码语言:javascript
运行
复制
[[Variables]]
    r0:       -34.3999435 +/- 6.1027e-05 (0.00%) (init = -30)
    r_max:     35 (fixed)
    radicand:  0.71508611 +/- 0.09385813 (13.13%) (init = 0.98)
    k:        -0.72477176 +/- 0.09066656 (12.51%) == '(r0/r_max)**2*(1-radicand)-1'
    a2:        0 (fixed)
    a4:        7.7436e-07 +/- 2.7872e-07 (35.99%) (init = 0)
    a6:        2.5547e-10 +/- 6.3330e-11 (24.79%) (init = 0)
    a8:       -4.9832e-12 +/- 1.7115e-14 (0.34%) (init = 0)
    a10:       0 (fixed)
    a12:      -9.8670e-20 +/- 2.0716e-21 (2.10%) (init = 0)

使用上面使用的数据,如果将keep_radicand_safe设置为False,您将看到fit失败。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41861911

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档