Matlab曲线拟合不适用于小值(1e-12),该怎么办? [英] Matlab curve-fitting won't work for small values (1e-12), what can I do?

查看:106
本文介绍了Matlab曲线拟合不适用于小值(1e-12),该怎么办?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经安装了曲线拟合"工具箱,并且正在尝试将扩散数据拟合为特定函数.

I have the Curve Fitting toolbox installed and I'm trying to fit diffusion-data to a specific function.

该函数是以下形式的错误函数:

The function is an error-function of the form:

y = 3500 - 2500 * erf( ( x-x0 ) / ( 2 * sqrt( D * t )) )

我希望该应用为我提供 D x0 的合理值,而t是一个预定义的常数.拟合所基于的数据点包括x和y的值.

I want the app to give me reasonable values for D and x0, while t is a predefined constant. The data-points, which the fitting is based on include values for x and y.

我知道 D应该在1e-11 附近,而 x0在0.0014附近,但是该函数无法自行找到这些解决方案.尝试使用曲线拟合应用程序的默认参数时,Matlab输出错误"输入必须是真实且完整的.". 当我将 x0 的起始猜测值设置为0.0014或0.0015时,它将找到正确的解决方案.但是只有这两个值.为了找到 D 的正确解决方案,我需要在方程式中设置一个前置因子,例如本例( 1e-12 ):

I know that D should be around 1e-11 and x0 is around 0.0014 but the function won't find these solutions on its own. Matlab outputs the error "Input must be real and full." when trying with the default parameters of the curve fitting app. When I set the starting guess of x0 to 0.0014 or 0.0015, it will find the correct solution. But only with those two values. To find the correct solution for D I need to set a pre-factor in the equation, like in this example (1e-12):

y = erf( ( x-x0 ) / ( 2 * sqrt( 1e-12 * D * t )) )

通过这种方式,matlab可以找到正确的解决方案,但仅适用于1e-10到1e-13之间的系数.

In this way matlab finds the correct solution but only for pre-factors between 1e-10 to 1e-13.

这是个很大的问题,因为D的正确解决方案将在1e-3和1e-15之间变化,具体取决于我要使用的数据集. x0的值也将变化.因此,以这种方式,我无法实现一般的解决方案.

This is highly problematic as the correct solutions for D will vary between 1e-3 and 1e-15, depending on the datasets I am going to use. Also the values for x0 will vary. So in this way I cannot implement a general solution.

您对如何处理此问题有建议吗?我不敢相信Matlab无法解决这个问题,必须有一种方法.是因为值太小了吗?

Do you have suggestions how to handle this issue? I cannot believe that matlab isn't able to solve this, there must be a way. Is it because the values are so small?

这是我正在使用的示例数据集:

Here is an example dataset I'm working with:

y = [6000 6000 6000 6000 6000 6000 6000 6000 6000 5750 5500 5250 5000 4500 4000 3250 2750 2250 1750 1500 1400 1250 1250 1150];
x = [0:0.0001:0.0023];

在方程式中使用以下固定参数时,所得行非常适合数据点.但是matlab找不到它们.

When using the following fixed parameters in the equation, the resulting line fits the data-points very good. But matlab won't find them.

D = 7.1e-11;
t = 900;
x0 = 0.0015;

(请记住,这些参数是基于比我在此提供的更大,更准确的数据集)

(Keep in mind that these parameters are based on a larger and more accurate dataset than those I provided here)

任何帮助都会很棒!非常感谢你.

Any help would be great! Thank you very much.

这是一个具有所有预定义参数的工作示例,可以使拟合工作.代码是由曲线拟合"工具(cftool)生成的:

Here's a working example with all predefined parameters to get the fit working. Code was generated by the Curve Fitting tool (cftool):

%% Fit: 'untitled fit 1'.

   % Input data
    C = [6000 6000 6000 6000 6000 6000 6000 6000 6000 5750 5500 5250 5000 4500 4000 3250 2750 2250 1750 1500 1400 1250 1250 1150]';
    x = [0:0.0001:0.0023]';

    [xData, yData] = prepareCurveData( x, C );

    % Set up fittype and options.
    ft = fittype( '3500-2500*erf((x-x0)/(2*sqrt(1e-10*D*900)))', 'independent', 'x', 'dependent', 'y' );
    opts = fitoptions( 'Method', 'NonlinearLeastSquares' );
    opts.Display = 'Off';
    opts.MaxIter = 4000;
    opts.StartPoint = [0.5 0.0014];
    opts.Upper = [1 Inf];

    % Fit model to data.
    [fitresult, gof] = fit( xData, yData, ft, opts )

    % Plot fit with data.
    figure( 'Name', 'untitled fit 1' );
    h = plot( fitresult, xData, yData );
    legend( h, 'C vs. x', 'untitled fit 1', 'Location', 'NorthEast' );
    % Label axes
    xlabel x
    ylabel C
    grid on

(仅为方便起见而绘制)

(Plot only for convenience)

请注意,我在sqrt()项中包括了因子1e-10,并且我将0.0014用作x0的初始猜测,否则拟合将不起作用.

Please note that I included the pre-factor 1e-10 in the sqrt()-term, and that I used 0.0014 as a starting guess for x0, otherwise the fit won't work.

推荐答案

似乎有2个问题:

  1. 您的函数未为每个实数值定义.假设您只对Dx0的正值感兴趣,则可以通过将下限指定为[0 0]

  1. Your function is not defined for every real value. Assuming you are only interested in positive values for D and x0, you can simply bound the search range to positive number by specifying the lower bounds as [0 0]

由于非常小的值,Matlab在数字上评估函数的导数方面存在问题.因此,最好的解决方案是象征性地计算函数的雅可比.可以使用符号工具箱完成此操作:

Matlab has problems to evaluate the derivative of your function numerically due to the very small values. Therefore, the best solution is to calculate the jacobian of your function symbolically. This can be done using the symbolic toolbox:

syms x x0 D t real;

y = 3500 - 2500 * erf( ( x-x0 ) / ( 2 * sqrt( D * t )) )
J = jacobian(y, [D, x0]);

您可以使用 matlabFunction 将其转换为普通的matlab函数,或者只需将结果复制并粘贴到脚本中,这样就不必在每次迭代中都以符号方式计算jacobian.

You can use matlabFunction to convert it to an ordinary matlab function or just copy and paste the result in your script, so that you do not have to calculate the jacobian symbolically in each iteration.

您应该设置选项 'SpecifyObjectiveGradient',true 告诉Matlab使用确切的雅各布.

You should set the option 'SpecifyObjectiveGradient',true to tell matlab to use your exact jacobian.


实施这两种解决方案将导致以下代码:


Implementing both solutions results in the following code:

ydata = [6000 6000 6000 6000 6000 6000 6000 6000 6000 5750 5500 5250 5000 4500 4000 3250 2750 2250 1750 1500 1400 1250 1250 1150];
xdata = 0:0.0001:0.0023;
t = 900;

D = 0.1;
x0 = 0.1;

options = optimoptions('lsqcurvefit', 'SpecifyObjectiveGradient',true);
X = lsqcurvefit(@(x, xdata) y(x(1), x(2), t, xdata),[D, x0], xdata, ydata, [0 0], [], options);

D = X(1); % 6.4833e-11
x0 = X(2); % 0.0015

figure
hold on
plot(xdata, ydata);
plot(xdata, y(D, x0, t, xdata));

function [F, J] = y(D, x0, t, x)
  F = 3500 - 2500 * erf( ( x-x0 ) / ( 2 * sqrt( D * t )) );
  J =  [(1250.*t.*exp(-(x - x0).^2/(4.*D.*t)).*(x - x0))/(pi^(1/2).*conj((D.*t).^(3/2))); ...
            (2500.*exp(-(x - x0).^2/(4.*D.*t)))/(pi.^(1/2).*conj((D.*t).^(1/2)))]';
end

这篇关于Matlab曲线拟合不适用于小值(1e-12),该怎么办?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆