Matlab - Fit a Curve with Constrained Parameters - matlab

For a (x,y) dataset, let have a curve given by an expression in a, b,c... etc, such as f='a*exp(b*x)+c', to be fitted as cfit=fit(x,y,f).
Suppose we have a set of constraint such as b>0, c+b>a/2. How should i use the fit command in this case?.

While you could set a lower boundary to enforce b>0, I don't think it is somehow possible to properly enforce c+b>a/2 with fit(). But ultimately every fitting problem can also be regarded as a "minimize the distance from the curve to the data" problem, so fmincon() can be used to achieve your goal:
%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)

For constraints that are just numeric values, such as b > 0, you can use the '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 James suggests, setting the function output to a high value like flintmax to generate a large error. For example, let's say I define my function like this:
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
I can create a set of noisy test data as follows:
a = 4;
b = 2;
c = 1;
x = (0:0.01:2).';
y = my_fcn(a, b, c, x) + 40.*(rand(size(x))-0.5);
And then fit a curve (note you have to use an anonymous function, since a function handle won't work for some reason):
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)
Note that the fitted values are close to the original values, but don't match exactly due to the noise. We can visualize the fit like so:
plot(x, y);
hold on;
plot(x, my_fcn(params.a, params.b, params.c, x), 'r');

One simplistic method is to have the fitted function return a very large value, with resulting very large error, if the parameter values are outside of the constraints. This "brick wall" method is not optimal and will cause problems when the fitted parameter values are close to the boundary conditions. It is worth a try because it is quick to implement and can work in simple cases. Take care to start with initial parameter values within the boundary limits.

Related

Calculate percentiles? (Or more generally, evaluate function implicitly defined by 2 vectors x and y at many values z)

Let's say you have some vector z and you compute [f, x] = ecdf(z);, hence your empirical CDF can be plotted with stairs(x, f).
Is there a simple way to compute what all the percentile scores are for z?
I could do something like:
Loop through z, that is for each entry z(i) of z
Binary search through sorted vector x to find where z(i) is. (find index j such that x(j) = z(i))
Find the corresponding value f(j)
It feels like there should be a simpler, already implemented way to do this...
Let f be a monotone function defined at values x, for which you want to compute the inverse function at values p. In your case f is monotone because it is a CDF; and the values p define the desired quantiles. Then you can simply use interp1 to interpolate x, considered as a function of f, at values p:
z = randn(1,1e5); % example data: normalized Gaussian distribution
[f, x] = ecdf(z); % compute empirical CDF
p = [0.5 0.9 0.95]; % desired values for quantiles
result = interp1(f, x, p);
In an example run of the above code, this produces
result =
0.001706069265714 1.285514249607186 1.647546848952448
For the specific case of computing quantiles p from data z, you can directly use quantile and thus avoid computing the empirical CDF:
result = quantile(z, p)
The results may be slightly different depending on how the empirical CDF has been computed in the first method:
>> quantile(z, p)
ans =
0.001706803588857 1.285515826972878 1.647582486507752
For comparison, the theoretical values for the above example (Gaussian distribution) are
>> norminv(p)
ans =
0 1.281551565544601 1.644853626951472

USE DIFFERENTIAL MATRIX OPERATOR TO SOLVE ODE

We were asked to define our own differential operators on MATLAB, and I did it following a series of steps, and then we should use the differential operators to solve a boundary value problem:
-y'' + 2y' - y = x, y(0) = y(1) =0
my code was as follows, it was used to compute this (first and second derivative)
h = 2;
x = 2:h:50;
y = x.^2 ;
n=length(x);
uppershift = 1;
U = diag(ones(n-abs(uppershift),1),uppershift);
lowershift = -1;
L= diag(ones(n-abs(lowershift),1),lowershift);
% the code above creates the upper and lower shift matrix
D = ((U-L))/(2*h); %first differential operator
D2 = (full (gallery('tridiag',n)))/ -(h^2); %second differential operator
d1= D*y.'
d2= ((D2)*y.')
then I changed it to this after posting it here and getting one response that encouraged the usage of Identity Matrix, however I still seem to be getting no where.
h = 2;
n=10;
uppershift = 1;
U = diag(ones(n-abs(uppershift),1),uppershift);
lowershift = -1;
L= diag(ones(n-abs(lowershift),1),lowershift);
D = ((U-L))/(2*h); %first differential operator
D2 = (full (gallery('tridiag',n)))/ -(h^2); %second differential operator
I= eye(n);
eqn=(-D2 + 2*D - I)*y == x
solve(eqn,y)
I am not sure how to proceed with this, like should I define y and x, or what exactly? I am clueless!
Because this is a numerical approximation to the solution of the ODE, you are seeking to find a numerical vector that is representative of the solution to this ODE from time x=0 to x=1. This means that your boundary conditions make it so that the solution is only valid between 0 and 1.
Also this is now the reverse problem. In the previous post we did together, you know what the input vector was, and doing a matrix-vector multiplication produced the output derivative operation on that input vector. Now, you are given the output of the derivative and you are now seeking what the original input was. This now involves solving a linear system of equations.
Essentially, your problem is now this:
YX = F
Y are the coefficients from the matrix derivative operators that you derived, which is a n x n matrix, X would be the solution to the ODE, which is a n x 1 vector and F would be the function you are associating the ODE with, also a n x 1 vector. In our case, that would be x. To find Y, you've pretty much done that already in your code. You simply take each matrix operator (first and second derivative) and you add them together with the proper signs and scales to respect the left-hand side of the ODE. BTW, your first derivative and second derivative matrices are correct. What's left is adding the -y term to the mix, and that is accomplished by -eye(n) as you have found out in your code.
Once you formulate your Y and F, you can use the mldivide or \ operator and solve for X and get the solution to this linear system via:
X = Y \ F;
The above essentially solves the linear system of equations formed by Y and F and will be stored in X.
The first thing you need to do is define a vector of points going from x=0 to x=1. linspace is probably the most suitable where you can specify how many points we want. Let's assume 100 points for now:
x = linspace(0,1,100);
Therefore, h in our case is just 1/100. In general, if you want to solve from the starting point x = a up to the end point x = b, the step size h is defined as h = (b - a)/n where n is the total number of points you want to solve for in the ODE.
Now, we have to include the boundary conditions. This simply means that we know the beginning and ending of the solution of the ODE. This means that y(0) = y(1) = 0. As such, we make sure that the first row of Y has only the first column set to 1 and the last row of Y has only the last column set to 1, and we'll set the output position in F to both be 0. This symbolizes that we already know the solution at these points.
Therefore, your final code to solve is just:
%// Setup
a = 0; b = 1; n = 100;
x = linspace(a,b,n);
h = (b-a)/n;
%// Your code
uppershift = 1;
U = diag(ones(n-abs(uppershift),1),uppershift);
lowershift = -1;
L= diag(ones(n-abs(lowershift),1),lowershift);
D = ((U-L))/(2*h); %first differential operator
D2 = (full (gallery('tridiag',n)))/ -(h^2);
%// New code - Create differential equation matrix
Y = (-D2 + 2*D - eye(n));
%// Set boundary conditions on system
Y(1,:) = 0; Y(1,1) = 1;
Y(end,:) = 0; Y(end,end) = 1;
%// New code - Create F vector and set boundary conditions
F = x.';
F(1) = 0; F(end) = 0;
%// Solve system
X = Y \ F;
X should now contain your numerical approximation to the ODE in steps of h = 1/100 starting from x=0 up to x=1.
Now let's see what this looks like:
figure;
plot(x, X);
title('Solution to ODE');
xlabel('x'); ylabel('y');
You can see that y(0) = y(1) = 0 as per the boundary conditions.
Hope this helps, and good luck!

Matlab find the best constants for a fitting model

Please find the data in the link below, or if you can send me your private email, I can send you the data
https://dl.dropboxusercontent.com/u/5353938/test_matlab_lefou.xlsx
In the excel sheet, the first column is y, the second is x and the third is t, I hope this will make things much more clear, and many thanks for the help.
I need to use the following model because it is the one that fits best my data, but what I don't know is how to find the best values of a and b, that will allow me to get the best fit, (I can attach a file if you need the values), I already have the values of y, x and t:
y= a*sqrt(x).exp(b.t)
Thanks
Without the dependency on the curve fitting toolbox, this problem can also be solved by using fminsearch. I first generate some data, which you already have but didn't share with us. An initial guess on the parameters a and b must be made (p0). Then I do the optimiziation by minizmizing the squared errors between data and fit resulting in the vector p_fit, which contains the optimized parameters for a and b. In the end, the result is visualized.
% ----- Generating some data for x, y and t (which you already got)
N = 10; % num of data points
x = linspace(0,5,N);
t = linspace(0,10,N);
% random parameters
a = rand()*5; % a between 0 and 5
b = (rand()-1); % b between -1 and 0
y = a*sqrt(x).*exp(b*t) + rand(size(x))*0.1; % noisy data
% ----- YOU START HERE WITH YOUR PROBLEM -----
% put x and t into a 2 row matrix for simplicity
D(1,:) = x;
D(2,:) = t;
% create model function with parameters p(1) = a and p(2) = b
model = #(p, D) p(1)*sqrt(D(1,:)).*exp(p(2)*D(2,:));
e = #(p) sum((y - model(p,D)).^2); % minimize squared errors
p0 = [1,-1]; % an initial guess (positive a and probably negative b for a decay)
[p_fit, r1] = fminsearch(e, p0); % Optimize
% ----- VISUALIZATION ----
figure
plot(x,y,'ko')
hold on
X = linspace(min(x), max(x), 100);
T = linspace(min(t), max(t), 100);
plot(X, model(p_fit, [X; T]), 'r--')
legend('data', sprintf('fit: y(t,x) = %.2f*sqrt(x)*exp(%.2f*t)', p_fit))
The result can look like
UPDATE AFTER MANY MANY COMMENTS
Your data are column vectors, my solution used row vectors. The error occured when the errorfunction tryed to compute the difference of a column vector (y) and a row-vector (result of the model-function). Easy hack: make them all to row vectors and use my approach. The result is: a = 0.5296 and b = 0.0013.
However, the Optimization depends on the initial guess p0, you might want to play around with it a little bit.
clear variables
load matlab.mat
% put x and t into a 2 row matrix for simplicity
D(1,:) = x;
D(2,:) = t;
y = reshape(y, 1, length(y)); % <-- also y is a row vector, now
% create model function with parameters p(1) = a and p(2) = b
model = #(p, D) p(1)*sqrt(D(1,:)).*exp(p(2)*D(2,:));
e = #(p) sum((y - model(p,D)).^2); % minimize squared errors
p0 = [1,0]; % an initial guess (positive a and probably negative b for a decay)
[p_fit, r1] = fminsearch(e, p0); % Optimize
% p_fit = nlinfit(D, y, model, p0) % as a working alternative with dependency on the statistics toolbox
% ----- VISUALIZATION ----
figure
plot(x,y,'ko', 'markerfacecolor', 'black', 'markersize',5)
hold on
X = linspace(min(x), max(x), 100);
T = linspace(min(t), max(t), 100);
plot(X, model(p_fit, [X; T]), 'r-', 'linewidth', 2)
legend('data', sprintf('fit: y(t,x) = %.2f*sqrt(x)*exp(%.2f*t)', p_fit))
The result doesn't look too satisfying though. But that mainly is because of your data. Have a look here:
With the cftool-command (curve fitting toolbox) you can fit to your own functions, returning the variables that you need (a,b). Make sure your x-data and y-data are in separate variables. you can also specify weights for your measurements.

Convert data to fuzzy data

I am beginner. I have a matrix in matlab and I want Convert matrix's number to fuzzy number and use these fuzzy number for my function's input .how can I do this?
is it correct to Convert number to double number between 0,1 by Dividing numbers by 1000 like this?
[256,12;3,56]--->[0.256,0.12;0.003,0.056]
but for double number what should I do?
What do you mean by fuzzy number?!! as far as I know MATLAB uses normal numbers for Fuzzy system. After that there are fuzzifiers that change the real numbers to the points on the membership functions. And then the fuzzy logic decides that how the number have to be selected, and so on...!
On the other hand, If you want to change the scale of the number to be in the range [-1 1] or [0 1] then it has nothing to do with fuzzy.
and to change from the range [0 1] to [a b] use this line of code:
r = a + (b-a)*z;
where the z is in the range [0 1], and the r is in the range [a b]
for example, changing z=0.5 from [0 1] to the range [0 10], r becomes:
r = 0 + (10-0)*0.5 = 5
to change from [a b] to [0 1] also you can do this:
z = (r - a)/(b-a);
so if r = 5 in the range [0 10], then z = 0.5 in the range [0 1];
In addition, for the real fuzzy operation, try something like this:
point_n = 101; % Determines MF's resolution
min_x = -20; max_x = 20; % Universe is [min_x, max_x]
x = linspace(min_x, max_x, point_n)';
A = trapmf(x, [-10 -2 1 3]); % Trapezoidal fuzzy set A
B = gaussmf(x, [2 5]); % Gaussian fuzzy set B
C1 = fuzarith(x, A, B, 'sum');
subplot(2,1,1);
plot(x, A, 'b--', x, B, 'm:', x, C1, 'c');
title('fuzzy addition A+B');
C2 = fuzarith(x, A, B, 'sub');
subplot(2,1,2);
plot(x, A, 'b--', x, B, 'm:', x, C2, 'c');
title('fuzzy subtraction A-B');
C3 = fuzarith(x, A, B, 'prod');
That's how you perform fuzzy arithmetic. According to MathWorks:
Using interval arithmetic, C = fuzarith(X, A, B, operator) returns a fuzzy set C as the result of applying the function represented by the string, operator, which performs a binary operation on the sampled convex fuzzy sets A and B. The elements of A and B are derived from convex functions of the sampled universe, X:
A, B, and X are vectors of the same dimension.
operator is one of the following strings: 'sum', 'sub', 'prod', and
'div'.
The returned fuzzy set C is a column vector with the same length as
X.
And Finally you can perform fuzzy inference calculation using 'evalfis' function in MATLAB. The inputs and outputs to this function are real numbers as well:
fismat = readfis('tipper');
out = evalfis([2 1; 4 9],fismat)
This syntax generates the response
out =
7.0169
19.6810

Polynomial fit matlab with some constraints on the coefficients

I have data that I should interpolate with a function which must be of the following kind:
f(x) = ax4 + bx2 + c
with a > 0 and b ≤ 0. Unfortunately, MATLAB's polyfit does not allow any constraints on the coefficients of the polynomial. Does anybody know if there is a MATLAB function to do this? Otherwise, how can I implement it?
Thank you very much in advance,
Elisabetta
You can try using fminsearch, fminunc defining your objective function manually.
Alternatively, you can define your problem slightly different:
f(x) = a2x4 - b2x2 + c
Now, the new a and b can be optimized for without constraints, while ensuring that the final a and b you are looking for are positive (negative resp.).
Without constraints, the problem can be written and solved as a simple linear system:
% Your design matrix ([4 2 0] are the powers of the polynomial)
A = bsxfun(#power, your_X_data(:), [4 2 0]);
% Best estimate for the coefficients, [a b c], found by
% solving A*[a b c]' = y in a least-squares sense
abc = A\your_Y_data(:)
Those constraints will of course automatically be satisfied iff that constrained model indeed underlies your data. For example,
% some example factors
a = +23.9;
b = -15.75;
c = 4;
% Your model
f = #(x, F) F(1)*x.^4 + F(2)*x.^2 + F(3);
% generate some noisy XY data
x = -1:0.01:1;
y = f(x, [a b c]) + randn(size(x));
% Best unconstrained estimate a, b and c from the data
A = bsxfun(#power, x(:), [4 2 0]);
abc = A\y(:);
% Plot results
plot(x,y, 'b'), hold on
plot(x, f(x, abc), 'r')
xlabel('x (nodes)'), ylabel('y (data)')
However, if you impose constraints on data that are not accurately described by that constrained model, things might go wrong:
% Note: same data, but flipped signs
a = -23.9;
b = +15.75;
c = 4;
f = #(x, F) F(1)*x.^4 + F(2)*x.^2 + F(3);
% generate some noisy XY data
x = -1:0.01:1;
y = f(x, [a b c]) + randn(size(x));
% Estimate a, b and c from the data, Forcing a>0 and b<0
abc = fmincon(#(Y) sum((f(x,Y)-y).^2), [0 0 0], [-1 0 0; 0 +1 0; 0 0 0], zeros(3,1));
% Plot results
plot(x,y, 'b'), hold on
plot(x, f(x, abc), 'r')
xlabel('x (nodes)'), ylabel('y (data)')
(this solution has a == 0, indicative of an incorrect model choice).
If the exact equality of a == 0 is a problem: there is of course no difference if you set a == eps(0). Numerically, this will not be noticeable for real-world data, but it's nonzero nonetheless.
Anyway, I have a suspicion that your model is not well chosen and the constraints are a "fix" to get everything to work, or your data should actually be unbiased/rescaled before trying to make any fit, or that some similar preconditions apply (I've often seen people do this sort of thing, so yes, I'm a bit biased in this respect :).
So...what are the real reasons behind those constraints?
If you have the curve fitting toolbox then fit does allow for setting constraints using the 'upper' and 'lower' options. You would want something like.
M=fit(x, f, 'poly4', 'upper', [-inf, 0, -inf, 0, -inf], 'lower', [0, 0, 0, 0, -inf]);
Note use -inf to set a particular coefficient to be unconstrained.
This will give a cfit object with the relevant coefficients. You can access these using for example M.p1 for the x^4 term. Alternatively you can evaluate the function at whatever points you want using feval.
I think you can do a similar thing using lsqcurvefit in the optimization toolbox as well.