How to Fit a decay exponential function in Matlab - matlab

I have to fit the dots, results of measurements, by an exponential function on Matlab. My profesor asked me to use only
fminsearch
polyval
polyfit
One of them or both. I have to find the parameters a and b (the value) which are fitting it.
There is the lines I wrote :
x=[1:10:70]
y=[0:10:70]
x=[12.5,11.8,10.8,10.9,6.5,6.2,6.1,5.423,4.625]
y=[0,0.61,1.3,1.4,14.9,18.5,20.1,29.7,58.2]
xlabel('Conductivité')
ylabel('Inductance')
The function has the form a*e^(-b*x) +c

Well polyfit and polyval are only usefull for working with polynomials. So you would have to write a minimization problem of the form min(f(x)).
functionToMinimize = #(pars, x, y)(norm(pars(1).*exp(-pars(2).*x) - y));
targetFunctionForFminseardch = #(pars)(functionToMinimize(pars, x, y));
minPars = fminsearch(targetFunctionForFminseardch, [0, 1])
Read up on anonymous functions and the use of vector norms if you have questions how to construct such a minimization problem.
Your code also has some flaws. Why are you defining x and y twice when you only want to use the actual measured data?

Related

How to solve equations with complex coefficients using ode45 in MATLAB?

I am trying to solve two equations with complex coefficients using ode45.
But iam getting an error message as "Inputs must be floats, namely single or
double."
X = sym(['[',sprintf('X(%d) ',1:2),']']);
Eqns=[-(X(1)*23788605396486326904946699391889*1i)/38685626227668133590597632 + (X(2)*23788605396486326904946699391889*1i)/38685626227668133590597632; (X(2)*23788605396486326904946699391889*1i)/38685626227668133590597632 + X(1)*(- 2500000 + (5223289665997855453060886952725538686654593059791*1i)/324518553658426726783156020576256)] ;
f=#(t,X)[Eqns];
[t,Xabc]=ode45(f,[0 300*10^-6],[0 1])
How can i fix this ? Can somebody can help me ?
Per the MathWorks Support Team, the "ODE solvers in MATLAB 5 (R12) and later releases properly handle complex valued systems." So the complex numbers are the not the issue.
The error "Inputs must be floats, namely single or double." stems from your definition of f using Symbolic Variables that are, unlike complex numbers, not floats. The easiest way to get around this is to not use the Symbolic Toolbox at all; just makes Eqns an anonymous function:
Eqns= #(t,X) [-(X(1)*23788605396486326904946699391889*1i)/38685626227668133590597632 + (X(2)*23788605396486326904946699391889*1i)/38685626227668133590597632; (X(2)*23788605396486326904946699391889*1i)/38685626227668133590597632 + X(1)*(- 2500000 + (5223289665997855453060886952725538686654593059791*1i)/324518553658426726783156020576256)] ;
[t,Xabc]=ode45(Eqns,[0 300*10^-6],[0 1]);
That being said, I'd like to point out that numerically time integrating this system over 300 microseconds (I assume without units given) will take a long time since your coefficient matrix has imaginary eigenvalues on the order of 10E+10. The extremely short wavelength of those oscillations will more than likely be resolved by Matlab's adaptive methods, and that will take a while to solve for a time span just a few orders greater than the wavelength.
I'd, therefore, suggest an analytical approach to this problem; unless it is a stepping stone another problem that is non-analytically solvable.
Systems of ordinary differential equations of the form
,
which is a linear, homogenous system with a constant coefficient matrix, has the general solution
,
where the m-subscripted exponential function is the matrix exponential.
Therefore, the analytical solution to the system can be calculated exactly assuming the matrix exponential can be calculated.
In Matlab, the matrix exponential is calculate via the expm function.
The following code computes the analytical solution and compares it to the numerical one for a short time span:
% Set-up
A = [-23788605396486326904946699391889i/38685626227668133590597632,23788605396486326904946699391889i/38685626227668133590597632;...
-2500000+5223289665997855453060886952725538686654593059791i/324518553658426726783156020576256,23788605396486326904946699391889i/38685626227668133590597632];
Eqns = #(t,X) A*X;
X0 = [0;1];
% Numerical
options = odeset('RelTol',1E-8,'AbsTol',1E-8);
[t,Xabc]=ode45(Eqns,[0 1E-9],X0,options);
% Analytical
Xana = cell2mat(arrayfun(#(tk) expm(A*tk)*X0,t,'UniformOutput',false)')';
k = 1;
% Plots
figure(1);
subplot(3,1,1)
plot(t,abs(Xana(:,k)),t,abs(Xabc(:,k)),'--');
title('Magnitude');
subplot(3,1,2)
plot(t,real(Xana(:,k)),t,real(Xabc(:,k)),'--');
title('Real');
ylabel('Values');
subplot(3,1,3)
plot(t,imag(Xana(:,k)),t,imag(Xabc(:,k)),'--');
title('Imaginary');
xlabel('Time');
The comparison plot is:
The output of ode45 matches the magnitude and real parts of the solution very well, but the imaginary portion is out-of-phase by exactly π.
However, since ode45's error estimator only looks at norms, the phase difference is not noticed which may lead to problems depending on the application.
It will be noted that while the matrix exponential solution is far more costly than ode45 for the same number of time vector elements, the analytical solution will produce the exact solution for any time vector of any density given to it. So for long time solutions, the matrix exponential can be viewed as an improvement in some sense.

Curve Fitting for equation with two parameters

I have two arrays:
E= [6656400;
13322500;
19980900;
26625600;
33292900;
39942400;
46648900;
53290000]
and
J=[0.0000000021;
0.0000000047;
0.0000000128;
0.0000000201;
0.0000000659;
0.0000000748;
0.0000001143;
0.0000001397]
I want to find the appropriate curve fitting for the above data by applying this equation:
J=A0.*(298).^2.*exp(-(W-((((1.6e-19)^3)/(4*pi*2.3*8.854e-12))^0.5).*E.^0.5)./((1.38e-23).*298))
I want to select the starting value of W from 1e-19
I have tried the curve fitting tools but it is not helping me to solve it!
Then, I selected some random values of A0=1.2e9 and W=2.243e-19, it gave me a better results. But I want to find the right values by using the code (not the curve fitting Apps)
Can you help me please?
A quick (and potentially easy) solution method would be to pose the curve fit as a minimization problem.
Define a correlation function that takes the fit parameters as an argument:
% x(1) == A0; x(2) == W
Jfunc = #(x) x(1).*(298).^2.*exp(-(x(2)-((((1.6e-19)^3)/(4*pi*2.3*8.854e-12))^0.5).*E.^0.5)./((1.38e-23).*298));
Then a objective function to minimize. Since you have data J we'll minimize the sum-of-squares of the difference between the data and the correlation:
Objective = #(x) sum((Jfunc(x) - J).^2);
And then attempt to minimize the objective using fminsearch:
x0 = [1.2E9;2.243E-19];
sol = fminsearch(Objective,x0);
I used the guesses you gave. For nonlinear solutions, a good first guess is often important for convergence.
If you have the Optimization Toolbox, you can also try lsqcurvefit or lsqnonlin (fminsearch is vanilla MATLAB).

Numerical integration Legendre Polynomials MATLAB

The Legendre polynomials are implemented in MATLAB as vectors, where you also get all the associated Legendre polynomials evaluated at a particular point x. Thus, I don't know how I can use these functions inside an integral. My question is:
How can I evaluate the (NUMERICALLY CALCUALTED(!)) integral from -1 to 1 over the n-th Legendre polynomial in Matlab?
EDIT: As I received an answer that is really not what I want: I want to use the implementation of the Legendre polynomials in MATLAB cause other suggestions may be highly unstable.
n=3 % degree of Legendre polynomial
step=0.1 % integration step
trapz(legendre(n,-1:step:1)')*step
this should do what you want
As #thewaywewalk mentionned, you can use trapz to numerically integrate.
Legendre polynomials of degree n are defined as:
Therefore you can define them in Matlab like so:
sym x % You probably have to define x as being symbolic since you integrate as a function of x.
x = -1:0.1:1;
n = 1; Change according to the degree of the polynomial.
F = (x.^2)-1).^n;
Pol_n = (1./((2.^n).*factorial(n))).*diff(F,x,n) % n is the degree of the polynomial
Then using trapz :
Output = trapz(x,Pol_n)
That should get you going.

weighted curve fitting with lsqcurvefit

I wanted to fit an arbitrary function to my data set. Therefore, I used lsqcurvefit in MATLAB. Now I want to give weight to the fit procedure, meaning when curve fitting function (lsqcurvefit) is calculating the residue of the fit, some data point are more important than the others. To be more specific I want to use statistical weighting method.
w=1/y(x),
where w is a matrix contains the weight of each data point and y is the data set.
I cannot find anyway to make weighted curve fitting with lsqcurvefit. Is there any trick I should follow or is there any other function rather than lsqcurvefit which do it for me?
For doing weighting, I find it much easier to use lsqnonlin which is the function that lsqcurvefit calls to do the actual fitting.
You first have to define a function that you are trying to minimize, ie. a cost function. You need to pass in your weighting function as an extra parameter to your function as a vector:
x = yourIndependentVariable;
y = yourData;
weightVector = sqrt(abs(1./y));
costFunction = #(A) weightVector.*(yourModelFunction(A) - y);
aFit = lsqnonlin(costFunction,aGuess);
The reason for the square root in the weighting function definition is that lsqnonlin requires the residuals, not the squared residuals or their sum, so you need to pre-unsquare the weights.
Alternatively, if you have the Statistics Toolbox, you can use nlinfit which will accept a weighting vector/matrix as one of the optional inputs.

Find approximation of sine using least squares

I am doing a project where i find an approximation of the Sine function, using the Least Squares method. Also i can use 12 values of my own choice.Since i couldn't figure out how to solve it i thought of using Taylor's series for Sine and then solving it as a polynomial of order 5. Here is my code :
%% Find the sine of the 12 known values
x=[0,pi/8,pi/4,7*pi/2,3*pi/4,pi,4*pi/11,3*pi/2,2*pi,5*pi/4,3*pi/8,12*pi/20];
y=zeros(12,1);
for i=1:12
y=sin(x);
end
n=12;
j=5;
%% Find the sums to populate the matrix A and matrix B
s1=sum(x);s2=sum(x.^2);
s3=sum(x.^3);s4=sum(x.^4);
s5=sum(x.^5);s6=sum(x.^6);
s7=sum(x.^7);s8=sum(x.^8);
s9=sum(x.^9);s10=sum(x.^10);
sy=sum(y);
sxy=sum(x.*y);
sxy2=sum( (x.^2).*y);
sxy3=sum( (x.^3).*y);
sxy4=sum( (x.^4).*y);
sxy5=sum( (x.^5).*y);
A=[n,s1,s2,s3,s4,s5;s1,s2,s3,s4,s5,s6;s2,s3,s4,s5,s6,s7;
s3,s4,s5,s6,s7,s8;s4,s5,s6,s7,s8,s9;s5,s6,s7,s8,s9,s10];
B=[sy;sxy;sxy2;sxy3;sxy4;sxy5];
Then at matlab i get this result
>> a=A^-1*B
a =
-0.0248
1.2203
-0.2351
-0.1408
0.0364
-0.0021
However when i try to replace the values of a in the taylor series and solve f.e t=pi/2 i get wrong results
>> t=pi/2;
fun=t-t^3*a(4)+a(6)*t^5
fun =
2.0967
I am doing something wrong when i replace the values of a matrix in the Taylor series or is my initial thought flawed ?
Note: i can't use any built-in function
If you need a least-squares approximation, simply decide on a fixed interval that you want to approximate on and generate some x abscissae on that interval (possibly equally spaced abscissae using linspace - or non-uniformly spaced as you have in your example). Then evaluate your sine function at each point such that you have
y = sin(x)
Then simply use the polyfit function (documented here) to obtain least squares parameters
b = polyfit(x,y,n)
where n is the degree of the polynomial you want to approximate. You can then use polyval (documented here) to obtain the values of your approximation at other values of x.
EDIT: As you can't use polyfit you can generate the Vandermonde matrix for the least-squares approximation directly (the below assumes x is a row vector).
A = ones(length(x),1);
x = x';
for i=1:n
A = [A x.^i];
end
then simply obtain the least squares parameters using
b = A\y;
You can clearly optimise the clumsy Vandermonde generation loop above I have just written to illustrate the concept. For better numerical stability you would also be better to use a nice orthogonal polynomial system like Chebyshev polynomials of the first kind. If you are not even allowed to use the matrix divide \ function then you will need to code up your own implementation of a QR factorisation and solve the system that way (or some other numerically stable method).