我设计了一个球面轮廓的光学系统.然后我制造和测量了这个镜头。我得到了一个横截面图,从测量制造的表面轮廓。(表面保持旋转对称性)
用于模拟所述非球面的公式是:
如何用横截面曲线拟合这个广义方程,得到相应的alpha
系数?(alpha
系数是指所提供的公式中的系数),我知道曲面的曲率半径。
我可以访问Python和Matlab (没有工具箱)来实现这一点。我也可以从曲线中获得数字化的、表格化的数据点。
发布于 2019-03-09 19:10:27
假设您有一个discreet数组,并且对于这个数组的每个值z(r)。你想要拟合一条曲线来估计非球面透镜的参数。我将像前面提到的那样使用lmfit
来演示使用python的一种方法。
导入用于此操作的模块:
import numpy as np
import matplotlib.pyplot as plt
from lmfit import Model, Parameters
定义凹凸棒透镜的功能:
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
由于您没有提供任何数据,我将使用以下方法创建一些示例数据,包括人工噪声:
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])
以下函数进行拟合并绘制结果曲线:
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)
要设置示例数据的参数,我使用lmfit
的lmfit
对象
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)
创建示例数据:
r = np.linspace(0, 35, 1000)
z = generate_dummy_data(r, parameters_dummy, 0.00001)
使用lmfit
而不是scipy
's curve_fit
的原因是,平方根的根和平方根可能变成否定的。我们需要确保:
为此,我们需要像提到的here那样定义一个约束。让我们开始定义我们想要在拟合中使用的参数。基本半径是直接添加的:
parameters = Parameters()
parameters.add('r0', value=-30, vary=True)
若要服从不等式,请添加一个不允许小于零的变量radicand
。与其让k
参与合适的常态,不如让它完全依赖于r0
、r_max
和radicand
。我们需要使用r_max
,因为这个不等式对于极大的r是最有问题的。
它在下面用作expr
。我使用bool标志来打开/关闭约束:
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)
其余参数是直接添加的:
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)
现在,我们已经准备好开始并取得成果:
fit_asphere(r, z, parameters)
plt.show()
在控制台上,您应该看到输出:
[[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失败。
https://stackoverflow.com/questions/41861911
复制相似问题