Nonlinear Curve fitting with integrals
显示 更早的评论
I encountered a nonlinear fitting problem, and the fitting formula is shown in Equation (1), which includes two infinite integrals (in practice, the integration range can be set from 0.01E-6 to 200E-6).

In these formulas, except for x and y being vectors, all other variables are scalars, and Rmedian and sigma are the parameters to be fitted.

I found a related post and tried to write the code based on it, but it keeps reporting errors. The error message seems to indicate that the vector dimensions are inconsistent, preventing the operation from proceeding. However, these functions are all calculations for individual scalars.
Error using /
Matrix dimensions must agree.
Error in dsdmain>@(r)1/(2*r*sigma*sqrt(2*pi))*exp(-(log(2*r)-log(2*Rmean)^2)/(2*sigma^2)) (line 13)
gauss = @(r) 1/(2*r*sigma*sqrt(2*pi))* exp( -(log(2*r)-log(2*Rmean)^2)/(2*sigma^2) );
My question is: Can I refer to the content of this post to solve my problem? If yes, what does this error message mean? If not, how should I resolve my problem? (Note: The range of Rmedian is 1E-6 to 5E-6)
After modifying the code according to Walter Roberson and Torsten's suggestion, the program no longer throws errors. But no matter how I set the initial values on my end, it always prompts:
Initial point is a local minimum.
Optimization completed because the size of the gradient at the initial point
is less than the default value of the optimality tolerance.
<stopping criteria details>
theta = initial point
1.0e-05 *
0.2000
0.1000
Optimization completed: The final point is the initial point.
The first-order optimality measure, 0.000000e+00, is less than
options.OptimalityTolerance = 1.000000e-06.
Optimization Metric Options
relative first-order optimality = 0.00e+00 OptimalityTolerance = 1e-06 (default)
I have checked all the formulas and the units of the variables, and I didn't find any problems.
-------------------------------------- Beblow is my code for issue reproduction ----------------------------------------------------------
function testmain()
clc
function Kvec = model(param,xdata)
% Vector of Kd for every xdata:
Kvec = zeros(size(xdata));
Rmean = param(1);
Rstd = param(2);
for i = 1:length(xdata)
model = @(r) unified(xdata(i),r,Rmean,Rstd,delta,Delta,D,lambda);
Kvec(i) = integral(model,0.01E-6,200E-6);
end
end
function s = unified(g,R,Rmean,Rstd,delta,Delta,D,lambda)
%unified Unified fitting model for DSD
% exponentional combined
factor = 1./(2*R*Rstd*sqrt(2*pi)) *2 ; % int(P(r)) = 0.5,1/0.5=2
p1 = -(log(2*R)-log(2*Rmean)).^2/(2*Rstd^2);
c = -2*2.675E8^2*g.^2/D;
tmp = 0;
for il = 1:length(lambda)
a2 = (lambda(il)./R).^2;
an4 = (R/lambda(il)).^4;
Psi = 2+exp(-a2*D*(Delta-delta))-2*exp(-a2*D*delta)-2*exp(-a2*D*Delta)+exp(-a2*D*(Delta+delta));
tmp = tmp+an4./(a2.*R.*R-2).*(2*delta-Psi./(a2*D));
end
p2 = c*tmp;
s = factor.*exp(p1+p2);
end
Delta = 0.075;
delta = 0.002;
D = 0.098E-9;
lambda = [2.0816 5.9404 9.2058 12.4044 15.5792 18.7426 21.8997 25.0528 28.2034 31.3521];
g = [ 0.300616, 0.53884, 0.771392, 1.009616, 1.24784, 1.480392, 1.718616, 1.95684, 2.189392, 2.427616, 2.66584, 2.898392 ];
xdata = g;
ydata = [100, 91.16805426, 80.52955192, 67.97705378, 55.1009735,41.87307917, 30.39638776, 21.13515607, 13.7125649, 8.33083767, 5.146756077, 2.79768609];
ydata = ydata/ydata(1); % normalize
% Inital guess for parameters:
Rmean0 = 2E-6;
Rstd0 = 1E-6;
p0 = [Rmean0;Rstd0];
% lsqcurvefit is in the optimization toolbox.
% fit, from the curve fitting toolbox may be an alternative
theta = lsqcurvefit(@model,p0,xdata,ydata,[0.01E-6;0.1E-6],[10E-6,2E-6])
end
采纳的回答
更多回答(2 个)
Walter Roberson
2025-4-3
integral() always passes in a vector of locations to calculate at, unless you use the 'ArrayValued', true option.
sig = integral(f,0.01E-6,200E-6)/integral(gauss,0.01E-6,200E-6);
refers to
f = @(r) gauss(r)*kernel(r,delta,Delta,D)*2;
with the input r being a vector, gauss( r) can be expected to be a vector and kernal(...) can be expected to be a vector, so you have set up for two vectors to be "*" together. As the two vectors are likely the same size, you can expect problems from the * operator which does algebraic matrix multiplication for which the "inner dimensions" must match. You need to use the .* operator.
Meanwhile,
gauss = @(r) 1/(2*r*sigma*sqrt(2*pi))* exp( -(log(2*r)-log(2*Rmean)^2)/(2*sigma^2) );
with the input r being a vector, the 1/(2*r*sigma*sqrt(2*pi)) component is 1/(vector) which is going to fail because the / operator is the matrix-right-divide operator in which the number of columns on the two sides must match. You need to use the ./ operator.
Then the exp() is going to be a vector and you have a * operator again, and that's going to fail because the inner dimensions must be the same size... again you need to be using the .* operator instead of the * operator.
15 个评论
Shannon
2025-4-3
Shannon
2025-4-7
p1 is in the order of -1e13. This makes s = 0 for all values of r and thus Kvec identically 0. So lsqcurvefit does not notice any change in the y-values you return when it varies the parameters to be optimized and consequently stops the optimization. Thus my advice: Check your model and your model parameters for validity.
Shannon
2025-4-7
Shannon
2025-4-7
Torsten
2025-4-7
But you see that giving sigma an initial value of 1e-6 gives a value for P(R) = 0 because you divide by 2*1e-12 in the exp() expression ?
Walter Roberson
2025-4-7
That's what the 'waypoints' option is for.
Shannon
2025-4-7
It doesn't help if your function is different from 0 in only one point - the numerical value of the integral will remain 0. If you really expect "sigma" in the order of magnitude of 1e-6, then it is impossible to use a numerical integrator for your task. If you try to plot P(r), you will see that you almost get the dirac distribution that is Inf at r = Rmean and 0 else.
Go one step back and try plotting P(r)*E(r,x,delta,s,D) over r for some of your x-values and see up to which value of "sigma" you get a reasonable function that you think MATLAB could successfully integrate. Then see if this value is still acceptable for your fitting task to start with.
Just a sidenote: Are you sure about the 2 in the denominator of the prefactor for P(R) ? The integral evaluates to 0.5 whereas I think it should evaluate to 1 as the probability density function for a lognormal distribution.
On Mathematics Stack Exchange you write
αm is the positive root of the equation J3/2(αmR)=αmRJ5/2(αmR)
So you mean that for each value of R, you get a different vector αm with the first 10 positive roots of the above equation ?
Maybe you could give a link to a publication where the above model has been used successfully to fit the parameters sigma and Rmedian.
Shannon
2025-4-8
Shannon
2025-4-8
Shannon
2025-4-9
It takes too long to run the code online - try if it produces reasonable results. Maybe you have to set lower and upper bounds for the parameters in "lsqcurvefit".
Note that "mu" and "sigma" are not the expected value and the standard deviation of the Lognormal Distribution. Further I think that "sigma" is dimensionless.
Delta = 0.075;
delta = 0.002;
D = 0.098E-9;
gamma = 2.675E8;
Rmin = 0.01e-6;
Rmax = 200e-6;
lambda = [2.0816 5.9404 9.2058 12.4044 15.5792 18.7426 21.8997 25.0528 28.2034 31.3521];
xdata = [ 0.300616, 0.53884, 0.771392, 1.009616, 1.24784, 1.480392, 1.718616, 1.95684, 2.189392, 2.427616, 2.66584, 2.898392 ];
ydata = [100,91.16805426,80.52955192,67.97705378,55.1009735,41.87307917,30.39638776,21.13515607,13.7125649,8.33083767,5.146756077,2.79768609]/100;
mu0 = (Rmin + Rmax)/2;
sigma0 = 0.2;
% Plot integrand for initial values for mu and sigma
N = 100;
r = linspace(Rmin,Rmax,N);
I = arrayfun(@(x)fun_int(r,x,Delta,delta,D,gamma,Rmin,Rmax,lambda,mu0,sigma0),xdata,'UniformOutput',0);
plot(r,cell2mat(I))
grid on
% Optimize mu and sigma
p0 = [mu0,sigma0];
p = lsqcurvefit(@(p,xdata)fun(p,xdata,Delta,delta,D,gamma,Rmin,Rmax,lambda),p0,xdata,ydata)
function y = fun(p,xdata,Delta,delta,D,gamma,Rmin,Rmax,lambda)
mu = p(1);
sigma = p(2);
y = zeros(numel(xdata),1);
for i = 1:numel(xdata)
F = @(r) fun_int(r,xdata(i),Delta,delta,D,gamma,Rmin,Rmax,lambda,mu,sigma);
y(i) = integral(F,Rmin,Rmax);
end
end
function I = fun_int(r,x,Delta,delta,D,gamma,Rmin,Rmax,lambda,mu,sigma)
I = zeros(numel(r),1);
for i = 1:numel(r)
alpha = lambda/r(i);
Psi = 2 + exp(-alpha.^2*D*(Delta-delta))-...
2*(exp(-alpha.^2*D*Delta)+exp(-alpha.^2*D*delta))+...
exp(-alpha.^2*D*(Delta+delta));
lnE = -2*(gamma*x)^2/D*sum(alpha.^(-4)./(alpha.^2*r(i)^2).*(2*delta-Psi./(alpha.^2*D)));
E = exp(lnE);
P = 1./(2*r(i)*sigma*sqrt(2*pi))*exp(-log(r(i)/mu).^2/(2*sigma^2));
I(i) = 2*E*P;
end
end
7 个评论
Shannon
2025-4-9
Walter Roberson
2025-4-9
Delta = 0.075;
delta = 0.002;
D = 0.098E-9;
gamma = 2.675E8;
Rmin = 0.01e-6;
Rmax = 200e-6;
lambda = [2.0816 5.9404 9.2058 12.4044 15.5792 18.7426 21.8997 25.0528 28.2034 31.3521];
xdata = [ 0.300616, 0.53884, 0.771392, 1.009616, 1.24784, 1.480392, 1.718616, 1.95684, 2.189392, 2.427616, 2.66584, 2.898392 ];
ydata = [100,91.16805426,80.52955192,67.97705378,55.1009735,41.87307917,30.39638776,21.13515607,13.7125649,8.33083767,5.146756077,2.79768609]/100;
mu0 = (Rmin + Rmax)/2;
sigma0 = 0.2;
% Plot integrand for initial values for mu and sigma
N = 100;
r = linspace(Rmin,Rmax,N);
I = arrayfun(@(x)fun_int(r,x,Delta,delta,D,gamma,Rmin,Rmax,lambda,mu0,sigma0),xdata,'UniformOutput',0);
whos r I
size(I{1})
plot(r,cell2mat(I(:)))
grid on
% Optimize mu and sigma
p0 = [mu0,sigma0];
p = lsqcurvefit(@(p,xdata)fun(p,xdata,Delta,delta,D,gamma,Rmin,Rmax,lambda),p0,xdata,ydata)
function y = fun(p,xdata,Delta,delta,D,gamma,Rmin,Rmax,lambda)
mu = p(1);
sigma = p(2);
y = zeros('like',xdata);
for i = 1:numel(xdata)
F = @(r) fun_int(r,xdata(i),Delta,delta,D,gamma,Rmin,Rmax,lambda,mu,sigma);
y(i) = integral(F,Rmin,Rmax);
end
end
function I = fun_int(r,x,Delta,delta,D,gamma,Rmin,Rmax,lambda,mu,sigma)
I = zeros('like', r);
for i = 1:numel(r)
alpha = lambda/r(i);
Psi = 2 + exp(-alpha.^2*D*(Delta-delta))-...
2*(exp(-alpha.^2*D*Delta)+exp(-alpha.^2*D*delta))+...
exp(-alpha.^2*D*(Delta+delta));
lnE = -2*(gamma*x)^2/D*sum(alpha.^(-4)./(alpha.^2*r(i)^2).*(2*delta-Psi./(alpha.^2*D)));
E = exp(lnE);
P = 1./(2*r(i)*sigma*sqrt(2*pi))*exp(-log(r(i)/mu).^2/(2*sigma^2));
I(i) = 2*E*P;
end
end
However, running this generates a long list of messages similar to
Warning: Reached the limit on the maximum number of intervals in use. Approximate bound on error is 9.3e+45. The integral may not exist, or it may be difficult to approximate numerically to the requested accuracy.
> In integralCalc>iterateScalarValued (line 393)
In
integralCalc>vadapt (line 148)
In
integralCalc (line 77)
In
integral (line 87)
In
q2175948>fun (line 32)
In
q2175948>@(p,xdata)fun(p,xdata,Delta,delta,D,gamma,Rmin,Rmax,lambda) (line 24)
In
lsqcurvefit/objective (line 314)
In finDiffEvalAndChkErr
In finitedifferences
In computeFinDiffGradAndJac
In
sfdnls (line 51)
In
snls (line 345)
In
lsqncommon (line 178)
In
lsqcurvefit (line 299)
In
q2175948 (line 24)
Notice how large the error bound is. There is no hope of fixing error bounds that large with small tweaks.
@Shannon Walter Roberson corrected the problem with your error message (y and I were column instead of row vectors), but the integration seems to be unsuccessful with the new suggested parameters for mu and sigma by "lsqcurvefit" after the first optimization step. If mu, e.g., becomes negative, do as I suggested and impose bounds in the parameters. I don't know if it helps. If you look at the plot of the integrand over r for xdata(end), e.g., it just looks like a peak - thus almost impossible to integrate with numerical methods.
I forgot to subtract 2 here, but I think this won't change much:
lnE = -2*(gamma*x)^2/D*sum(alpha.^(-4)./(alpha.^2*r(i)^2-2).*(2*delta-Psi./(alpha.^2*D)));
instead of
lnE = -2*(gamma*x)^2/D*sum(alpha.^(-4)./(alpha.^2*r(i)^2).*(2*delta-Psi./(alpha.^2*D)));
Shannon
2025-4-10
Shannon
2025-4-11
Shannon
2025-4-11
类别
在 帮助中心 和 File Exchange 中查找有关 Numerical Integration and Differentiation 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!


