7
votes

I have an array of data which, when plotted, looks like this.

http://s12.postimg.org/7ja47a6b1/temp.jpg

I need to use the polyfit command to determine the best fitting exponential for the time roughly between 1.7 and 2.3. I must also compare this exponential fit to a simple linear fit.

I'm given the equation Temp(t) = Temp0 * exp(-(t-t0)/tau), where t0 is the time corresponding to temperature Temp0 (I can select where to begin my curve-fitting, but it must be confined to the area roughly between 1.7 and 2.3). Here is my attempt.

% Arbitrarily defined starting point
t0 = 1.71;

%Exponential fit
p = polyfit(time, log(Temp), 1)
tau = -1./p(1)
Temp0 = exp(p(2))

tm = 1.8:0.01:2.3;
Temp_t = Temp0*exp(-(tm)/tau);
plot(time, Temp, tm, Temp_t)

figure(2)

%Linear fit
p2 = polyfit(time, Temp, 1);
Temp_p = p2(1)*tm + p2(2);
plot(time, Temp, tm, Temp_p)

My exponential fit ends up looking like exponential fit. My linear fit looks like linear fit. (virtually identical). What am I doing incorrectly? Should the two fits be so similar? I am told that circshift may help, but I couldn't grasp the applicability of the command after reading the help file.

4
Link from @Amro appears to have been broken by The MathWorks. Updated version is here.horchler
Thanks @horchler, here is the updated link to the example I had previously mentioned: Pitfalls in Fitting Nonlinear Models by Transforming to LinearityAmro

4 Answers

4
votes

Things are behaving just as you are expecting. The problem is that the function you are trying to fit is not a very good approximation of the data. Eyeballing the curve, it seems that the exponential part of the curve tends asymptotically to a value around 16; but the function you are using will eventually tend to a temperature of 0. Thus, fitting to a part that's going from 22 to 16 will give you an almost linear relationship. To illustrate this I wrote a few lines of code that approximately match the data points you have - and that show how different functions (one that tends to 0, and another that tends to 16) will give you a very different shape of the curve. The first (your original function) is almost linear between T values of 22 and 16 - so it will look like the linear fit.

I suggest that you think about the "right" shape of the function to fit - what is the underlying physics that makes you choose a particular form? Getting that right is essential...

Here is the code:

time = linspace(1.5, 2.5, 200);
t0 = 1.7;
t1 = 2.3;
tau = 2.0;

% define three sections of the function:
s1 = find(time < t0);
s2 = find(time >= t0 & time < t1);
s3 = find(time > 2.3);

% compute a shape for the function in each section:
tData(s1) = 28 - 50*(time(s1)-1.5).^2;
tData(s2) = 22*exp(-(time(s2)-t0)/tau);
tData(s3) = tData(s2(end)) + (s3 - s3(1))*12 / numel(s3);

figure
plot(time, tData)

% modify the equation slightly: assume equilibrium temperature is 16
% with a bit of effort one could fit for this as a second parameter
Teq = 16;
tData2 = tData;
tau2 = tau / 8; % decay more strongly to get down to approx the same value by t1
tData2(s2) = (22 - Teq) * exp( - (time(s2) - t0) / tau2) + Teq;
tData2(s3) = tData2(s2(end)) + (s3 - s3(1))*12 / numel(s3);

hold on;
plot(time, tData2, 'r')

This results in the following plot:

enter image description here

I conclude from this that the main reason your plots look so similar is that the function you are trying to fit is almost linear over the domain you are choosing - a different choice of function will be a better match.

4
votes

As I mentioned in the comments, there is a difference between fitting a linear model in log-space vs. fitting a non-linear model (both in the least-squares sense).

There a nice demo in the Statistics toolbox that explains the situation. I'm adapting the code below:

%# sample data
x = [5.72 4.22 5.72 3.59 5.04 2.66 5.02 3.11 0.13 2.26 ...
     5.39 2.57 1.20 1.82 3.23 5.46 3.15 1.84 0.21 4.29 ...
     4.61 0.36 3.76 1.59 1.87 3.14 2.45 5.36 3.44 3.41]';
y = [2.66 2.91 0.94 4.28 1.76 4.08 1.11 4.33 8.94 5.25 ...
     0.02 3.88 6.43 4.08 4.90 1.33 3.63 5.49 7.23 0.88 ...
     3.08 8.12 1.22 4.24 6.21 5.48 4.89 2.30 4.13 2.17]';

xx = linspace(min(x), max(x), 100);

%# linear regression in log-space
%#           y = p2 * exp(p1*x)
%#   => log(y) = log(p2) + p1*x
p_exp = polyfit(x, log(y), 1);
yy1 = exp(p_exp(2)) .* exp(xx .* p_exp(1));

%# linear regression
p_lin = polyfit(x, y, 1);
yy2 = polyval(p_lin, xx);

%# non-linear regression (using previous result as initial coeff)
f = @(p,x) p(2)*exp(p(1)*x);
p_nonlin = nlinfit(x, y, f, [p_exp(1) exp(p_exp(2))]);
yy3 = f(p_nonlin, xx);

plot(x,y,'o', xx,yy1,'-', xx,yy2,'-', xx,yy3,'-')
legend({'data points','linear in log-space','linear','non-linear'})

regression

2
votes

If i understand correctly, the variables time and Temp that you are using in the polyfit contain all the value (from 1.5 to 2.5). So you might want to limit the value of time and Temp to 1.71 to 2.3 before calculating the polyfit (right now it's calculating the polyfit from 1.5 to 2.5, hence why the line is not aligned with the data points).

p = polyfit(time, log(Temp), 1)
0
votes

Use

polyfit(x,y,n)

function in Matlab curve fitting toolbox.