Matlab - 用约束参数拟合曲线
Matlab - Fit a Curve with Constrained Parameters
对于 (x
,y
) 数据集,让 a
、b
、c
中的表达式给出一条曲线。 .等,如f='a*exp(b*x)+c'
,要拟合为cfit=fit(x,y,f)
。
假设我们有一组约束,例如b>0
、c+b>a/2
。在这种情况下我应该如何使用 fit
命令?
一种简单的方法是使拟合函数 return 具有非常大的值,如果参数值超出约束,则会导致非常大的误差。这种 "brick wall" 方法不是最优的,当拟合的参数值接近边界条件时会出现问题。值得一试,因为它实施起来很快,而且可以在简单的情况下工作。注意从边界限制内的初始参数值开始。
虽然您可以设置一个下限来执行 b>0
,但我认为用 fit()
正确执行 c+b>a/2
是不可能的。但归根结底每一个拟合问题也可以看作是一个"minimize the distance from the curve to the data"问题,所以fmincon()
可以用来达到你的目的:
%some sample x values
xdata = rand(1000,1);
%some parameters a,b,c
a = 2;
b = 3;
c = 4;
%resulting y values + some noise
ydata=a*exp(b*xdata)+c+rand(1000,1)*10-5;
plot(xdata,ydata,'o')
%function to minimize. It returns the sum of squared distances between the polynom and the data.
fun = @(coefs) sum((coefs(1)*exp(coefs(2).*xdata)+coefs(3)-ydata).^2);
%nonlinear constaint to enforce c+b>a/2, which is the same as -(c+b-a/2)<0
nonlcon = @(coefs)deal(-(coefs(3)+coefs(2)-coefs(1)/2), 0);
% lower bounds to enforce b>0
lb = [-inf 0 -inf];
%starting values
x0 = [1 1 1];
%finally find the coefficients (which should approximately be the values of a, b and c)
coefs = fmincon(fun,x0,[],[],[],[],lb,[],nonlcon)
对于只是数值的约束,例如b > 0
,您可以使用'Lower'
and 'Upper'
bounds arguments to specify those. For more complex relationships, like c+b>a/2
, you'll have to take an approach like , setting the function output to a high value like flintmax
来产生一个大的错误。例如,假设我这样定义我的函数:
function y = my_fcn(a, b, c, x)
if (c+b > a/2)
y = a.*exp(b.*x)+c;
else
y = flintmax().*ones(size(x));
end
end
我可以创建一组嘈杂的测试数据如下:
a = 4;
b = 2;
c = 1;
x = (0:0.01:2).';
y = my_fcn(a, b, c, x) + 40.*(rand(size(x))-0.5);
然后拟合曲线(请注意,您必须使用 anonymous function, since a function handle 由于某种原因不起作用):
params = fit(x, y, @(a, b, c, x) my_fcn(a, b, c, x), ...
'StartPoint', [1 1 1], ... % Starting guesses for [a b c]
'Lower', [-Inf 0 -Inf]); % Set bound for 'b'
params =
General model:
params(x) = my_fcn(a,b,c,x)
Coefficients (with 95% confidence bounds):
a = 4.297 (2.985, 5.609)
b = 1.958 (1.802, 2.113)
c = 0.1908 (-4.061, 4.442)
请注意,拟合值接近原始值,但由于噪声的原因并不完全匹配。我们可以像这样想象拟合:
plot(x, y);
hold on;
plot(x, my_fcn(params.a, params.b, params.c, x), 'r');
对于 (x
,y
) 数据集,让 a
、b
、c
中的表达式给出一条曲线。 .等,如f='a*exp(b*x)+c'
,要拟合为cfit=fit(x,y,f)
。
假设我们有一组约束,例如b>0
、c+b>a/2
。在这种情况下我应该如何使用 fit
命令?
一种简单的方法是使拟合函数 return 具有非常大的值,如果参数值超出约束,则会导致非常大的误差。这种 "brick wall" 方法不是最优的,当拟合的参数值接近边界条件时会出现问题。值得一试,因为它实施起来很快,而且可以在简单的情况下工作。注意从边界限制内的初始参数值开始。
虽然您可以设置一个下限来执行 b>0
,但我认为用 fit()
正确执行 c+b>a/2
是不可能的。但归根结底每一个拟合问题也可以看作是一个"minimize the distance from the curve to the data"问题,所以fmincon()
可以用来达到你的目的:
%some sample x values
xdata = rand(1000,1);
%some parameters a,b,c
a = 2;
b = 3;
c = 4;
%resulting y values + some noise
ydata=a*exp(b*xdata)+c+rand(1000,1)*10-5;
plot(xdata,ydata,'o')
%function to minimize. It returns the sum of squared distances between the polynom and the data.
fun = @(coefs) sum((coefs(1)*exp(coefs(2).*xdata)+coefs(3)-ydata).^2);
%nonlinear constaint to enforce c+b>a/2, which is the same as -(c+b-a/2)<0
nonlcon = @(coefs)deal(-(coefs(3)+coefs(2)-coefs(1)/2), 0);
% lower bounds to enforce b>0
lb = [-inf 0 -inf];
%starting values
x0 = [1 1 1];
%finally find the coefficients (which should approximately be the values of a, b and c)
coefs = fmincon(fun,x0,[],[],[],[],lb,[],nonlcon)
对于只是数值的约束,例如b > 0
,您可以使用'Lower'
and 'Upper'
bounds arguments to specify those. For more complex relationships, like c+b>a/2
, you'll have to take an approach like flintmax
来产生一个大的错误。例如,假设我这样定义我的函数:
function y = my_fcn(a, b, c, x)
if (c+b > a/2)
y = a.*exp(b.*x)+c;
else
y = flintmax().*ones(size(x));
end
end
我可以创建一组嘈杂的测试数据如下:
a = 4;
b = 2;
c = 1;
x = (0:0.01:2).';
y = my_fcn(a, b, c, x) + 40.*(rand(size(x))-0.5);
然后拟合曲线(请注意,您必须使用 anonymous function, since a function handle 由于某种原因不起作用):
params = fit(x, y, @(a, b, c, x) my_fcn(a, b, c, x), ...
'StartPoint', [1 1 1], ... % Starting guesses for [a b c]
'Lower', [-Inf 0 -Inf]); % Set bound for 'b'
params =
General model:
params(x) = my_fcn(a,b,c,x)
Coefficients (with 95% confidence bounds):
a = 4.297 (2.985, 5.609)
b = 1.958 (1.802, 2.113)
c = 0.1908 (-4.061, 4.442)
请注意,拟合值接近原始值,但由于噪声的原因并不完全匹配。我们可以像这样想象拟合:
plot(x, y);
hold on;
plot(x, my_fcn(params.a, params.b, params.c, x), 'r');