Non Linear Fit help?

Asked by Adam Parry on 20 Jul 2012
Latest activity Commented on by Star Strider on 3 Aug 2012

I have been trying to fit some data with a model for some time now and am getting fairly close. In origin pro the fit seems to work ok and I get reasonable parameters back albeit the residuals are a little funny. Unfortunately in Matlab the fit is not so good. Could I send some one my code my function and some data to take a look at?

Oh and also there are imaginary numbers!

    clear all;
    close all
    close all hidden
    A = uiimport;
     clear xdata;
     clear ydata;
     xdata = A.data(:,1);
     ydata = A.data(:,2);
     Vg = xdata;
     Id = abs(ydata);
    x0 = [8.6E-10;1.7;0.8;5E6];
    options = optimset('Display','iter',...
             'TolFun',1E-100,'TolX',1E-100,'MaxIter',1000);
    [beta,resid,J,COVB,mse] = nlinfit(Vg,Id,@RcFun,[x0],options);
    [ci se] = nlparci(real(beta),resid,'covar',COVB);
    Id_new = ((((real(beta(1))*((Vg-real(beta(2))).^(real(beta(3))+1))).^(-1))+real(beta(4))).^(-1));
    plot(Vg,Id_new,'r',Vg,Id,'o');
    hold on;
    plot(Vg,resid,'+');
 function F = Rcfun(a,Vg)
  K = real(a(1));
  V = real(a(2));
  b = real(a(3));
  R = real(a(4));
F = (((K.*(Vg-V).^(b+1)).^(-1))+R).^(-1);
 end

Data

A	B
0	3.03E-12
1	1.5E-13
2	1.58E-12
3	2.81E-12
4	2.55E-12
5	2.31E-12
6	4.13E-12
7	2.89E-12
8	4.99E-12
9	6.38E-12
10	1.068E-11
11	1.96E-11
12	5.343E-11
13	5.405E-11
14	5.347E-11
15	5.142E-11
16	2.4139E-10
17	7.4428E-10
18	1.5752E-9
19	2.7328E-9
20	4.3347E-9
21	6.5506E-9
22	9.5258E-9
23	1.31356E-8
24	1.72672E-8
25	2.17876E-8
26	2.66302E-8
27	3.18252E-8
28	3.7101E-8
29	4.23594E-8
30	4.78078E-8
31	5.32604E-8
32	5.86136E-8
33	6.39262E-8
34	6.93234E-8
35	7.47466E-8
36	8.01152E-8
37	8.54398E-8
38	9.08214E-8
39	9.62598E-8
40	1.0184E-7
41	1.074E-7
42	1.1322E-7
43	1.1876E-7
44	1.2432E-7
45	1.299E-7
46	1.3534E-7
47	1.4062E-7
48	1.4596E-7
49	1.5096E-7
50	1.558E-7
51	1.6118E-7
52	1.6616E-7
53	1.7064E-7
54	1.7546E-7
55	1.7946E-7
56	1.8402E-7
57	1.8776E-7
58	1.9138E-7
59	1.9584E-7
60	1.9992E-7

7 Comments

Adam Parry on 22 Jul 2012

I think in the data I gave above it dows not matter that I have taken the absolute, I don't think that it really matters. I changed myfun to Rcfun just copied the wrong file.

Teja Muppirala on 24 Jul 2012

Just curious, but, what are the good values of K,V,b,R that you obtained through origin?

Teja Muppirala on 24 Jul 2012

Ah. Sorry. You had it down below and I missed it. k = 8.6E-10 V = 17.3 b = 0.618 R = 2.3E6

Adam Parry

Products

No products are associated with this question.

6 Answers

Answer by Star Strider on 22 Jul 2012
Edited by Star Strider on 22 Jul 2012
Accepted answer

Thank you for clarifying ‘RcFun’. After working with your code for a bit, the problem definitely seems to be the ‘(Vg-V)’ term. The only way I am able to get a decent fit without complex parameters is to use ‘lsqcurvefit’ and constraining ‘V’ to not be greater than zero, but then ‘nlparci’ wouldn't calculate confidence intervals on the parameter estimates. [I was able to get a good fit with ‘nlinfit’ by redefining that term to ‘abs(Vg-V)’, but that changed your function.] With ‘lsqcurvefit’, your ‘options’ statement and structure remains the same, although I increased ‘MaxIter’ and ‘MaxFunEvals’ in mine for diagnostic purposes. I also made ‘RcFun’ a single-line anonymous function for convenience:

RcFun = @(a,Vg) 1./(1./(a(1).*(Vg-a(2)).^(a(3)+1)) + a(4));
Lobnd = [];
Upbnd = ones(4,1)*realmax;
Upbnd(2) = 0;        % Constrain ‘V’ to not be greater than zero
[beta,resnrm,resid,xitflg,outpt,lmda,J] = lsqcurvefit(RcFun,x0,Vg,Id,Lobnd,Upbnd,options);  % NOTE: ‘Answers’ wrapped this line

and got an acceptable fit with these parameters:

 K =     35.6744e-012
 V =    -32.7518e-003
 b =      1.1302e+000
 R =    145.7789e-003

The norm of the residuals was 5.2916E-015. I'm not certain what you're doing or what data you're modeling, so I can't interpret these or their validity.

In spite of the decent fit, the residuals had a definite oscillating trend.

7 Comments

Star Strider on 22 Jul 2012

I negated the function:

RcFun = @(a,Vg) -(1./(1./(a(1).*(Vg-a(2)).^(a(3)+1)) + a(4)));

as well as negating ‘Vg’. (I copied it here so you can check it to be sure that's what you intended. The extra parentheses in it are likely not necessary, but I want to be sure it's doing what I want it to do. At this point, I'm taking no chances!)

The parameter estimates with those changes were:

beta_est =
     282.3452e-012 -335.6849e-012i
     -10.2542e+000 -  1.6440e+000i
     444.5718e-003 -125.7975e-003i
     845.8825e+003                

with ‘abs(beta_est)’ for information purposes only:

absbeta_est =
     438.6378e-012
      10.3851e+000
     462.0272e-003
     845.8825e+003

With a decent-looking fit of real(Id_new) as well as abs(Id_new).

I did a search on MOSFET models this afternoon (GMT-7) in order to understand a bit more precisely what you're doing. Unfortunately, I didn't learn much. I'd appreciate your providing me with an open-source PDF or website that can explain what you're doing if that's an option. I'm sensitive to your doing research and that you would likely not want to divulge too much to competing investigators.

Adam Parry on 23 Jul 2012

I could send you a couple of PDF's over dropbox if you like? The fitting procedure and model is not confidential in anyway so that should be fine.

Could You post the whole of the code that you are using for me to have a look at?

Thanks

Star Strider on 23 Jul 2012

I would appreciate the PDFs. My circuit analysis and synthesis knowledge is relatively basic, but they could help me understand what you're doing.

This is the code snippet I've used:

        RcFun = @(a,Vg) -(1./(1./(a(1).*(Vg-a(2)).^(a(3)+1)) + a(4)));
        % RcFun = @(a,Vg) 1./(1./(a(1).*abs(Vg-a(2)).^(a(3)+1)) + a(4));
        Vg = -Data(:,1);
        Id = Data(:,2);
        % x0 = [8.6E-10;1.7;0.8;5E6];
        x0 = rand(4,1).*[1E-10;  1;  1;  1E+6];
        % x0 = rand(4,1).*1E-1;
        % options = optimset('Display','iter', 'TolFun',1E-100,'TolX',1E-100,'MaxIter',5000, 'MaxFunEvals', 2500);    
        options = optimset('Display','final', 'TolFun',1E-100,'TolX',1E-100,'MaxIter',5000, 'MaxFunEvals', 2500);    
        [beta,resid,J,COVB,mse] = nlinfit(Vg,Id,RcFun,[x0],options);
        % Lobnd = [];
        % Upbnd = ones(4,1)*realmax;
        % Upbnd(2) = 0;
        % [beta,resnrm,resid,xitflg,outpt,lmda,J] = lsqcurvefit(RcFun,x0,Vg,Id,Lobnd,Upbnd,options);
        beta_est = beta 
        absbeta_est = abs(beta)
        se = sqrt(diag(COVB/size(Data,1)));
        if isreal(beta)
            ci = nlparci(beta,resid,'covar',COVB);
            % ci = nlparci(beta,resid,'jacobian',J);
        end
        Id_new = RcFun(beta,Vg);
        figure(4096)
        plot(Vg,real(Id_new),'r',Vg,Id,'o')
        hold on
        plot(Vg,imag(Id_new),'--r',Vg,Id,'o')
        plot(Vg,real(resid),'+')
        plot(Vg,imag(resid),'x')
        hold off
        grid
        figure(4097)
        plot(Vg,abs(Id_new),'r',Vg,Id,'o')
        hold on
        plot(Vg,abs(resid),'+')
        hold off
        grid

I didn't include the code and data I copied from your original post. I decided to keep in the lines I used for various diagnostic options, including my call to ‘lsqcurvefit’ and a variation on the objective function I tried.

Star Strider
Answer by Adam Parry on 23 Jul 2012
Edited by Walter Roberson on 25 Jul 2012

19 Comments

Adam Parry on 24 Jul 2012

I'm intrigued to know how origin decides to cut off the plot below Vg-V>Vd without it being specified. And manages it in only 18 or so iterations. In fact origin is able to get almost exactly the same parameters even setting the initial guesses quite far out....

Adam Parry on 24 Jul 2012

so i tried a few things that maybe i shouldn't

I changed nlinfit.m so that the nlrobustfit function included an if else statement making it do a normal weighted robustfit if x-beta(2)>1 but would call a function in statrobustfit.m that set w = 0 when x-beta(2)<=1.

Where x is Vg and beta(2) is V

But that didn't really seem to do anything

Also I'm still getting the problem with beta(4) (which is R) not changing?

Do you think there is an easier way to implement the weighted fit?

Star Strider on 24 Jul 2012

I gave it some thought too overnight. (However I'm reluctant to change nlinfit or the others.) I thought about the weighting vector, and am considering:

WgtV = sqrt(Id);

thus forcing the routine to ignore the region where (Id = 0). I've done this successfully in the past with other functions and data, but in those situations using the usual inverse-variance weighting vectors, (clearly inappropriate here since there are no variances on the measurements).

The other thing I thought of is that since I have the Global Optimization Toolbox and a fair amount of experience with genetic algorithms (GA), I'm going to give that a go. We already have a good start on the fitness function (the objective function you derived), and setting up a weighted metric [to avoid the (Vg < V) and (Id = 0) problems]. An Euclidean distance measure is probably the easiest, although we can get creative and use something more robust if necessary. The problem is that GAs usually take a while to converge, but have the significant benefit that they are essentially immune to the response surface because they completely ignore it.

If we're not happy with the GA results, we'll give GlobalSearch a go, even though that may take longer than GA to converge. It is the most likely to produce the best solution. With luck, we'll have its results today or tomorrow.

These are problems I'll have to solve for my own applications in the not distant future, so I'm interested in learning about their solutions.

Adam Parry
Answer by Teja Muppirala on 24 Jul 2012

This problem is clearly difficult. It has multiple minima, and a strong dependence on initial conditions. Instead of NLINFIT, I tried two different approaches which both give me good fits for values of Vg > 18.

In both cases, since it seems this equation can't really model the Vg < 18 region, I weighted that region to be zero. Also, just to scale things better, I am working with the log10's of K and R.

Option 1: Pattern Search Algorithm from the Global Optimization Toolbox

This gives a solution that is almost identical to the one that you found from your other software.

G = @(X) (((10.^(X(1)).*(Vg-X(2)).^(X(3)+1)).^(-1))+10.^(X(4))).^(-1);
E = @(X) ( sum(((real(G(X)) - Id)).^2 .* (Vg >= 18)) );
opts = psoptimset;
opts.Display = 'iter';
opts.MaxIter = realmax;
opts.MaxFunEvals = realmax;
X0 = [log10(8.6E-10);1.7;0.8;log10(5E6)];
X = patternsearch(E,X0,[],[],[],[],[],[],[],opts);
% Your previous answer
K = 8.6E-10; V = 17.3; b = 0.618; R = 2.3E6;
F0 = (((K.*(Vg-V).^(b+1)).^(-1))+R).^(-1);
% Comparing results: They are virtually identical
plot(Vg, Id);hold all; plot(Vg, G(X)); plot(Vg,F0);

Option 2: Simply using FMINSEARCH from various starting points

Again, identical to the previous results.

G = @(X) (((10.^(X(1)).*(Vg-X(2)).^(X(3)+1)).^(-1))+10.^(X(4))).^(-1);
E = @(X) ( sum(((real(G(X)) - Id)).^2 .* (Vg >= 18)) ); 
opts = optimset('fminsearch');
opts.MaxIter = realmax;
opts.MaxFunEvals = realmax;
options.TolFun = realmin;
options.TolX = realmin;
X0 = [log10(8.6E-10);1.7;0.8;log10(5E6)];
Emin = Inf;
for n = 1:100
    disp(n)
    [Xn, err(n)] = fminsearch(E,X0.*(1+0.01*randn(size(X0))),opts);
    if err(n) < Emin
        Emin = err(n);
        X = Xn;
    end
end
% Your previous answer
K = 8.6E-10; V = 17.3; b = 0.618; R = 2.3E6;
F0 = (((K.*(Vg-V).^(b+1)).^(-1))+R).^(-1);
% Comparing results: They are virtually identical
plot(Vg, Id);hold all; plot(Vg, G(X)); plot(Vg,F0);

2 Comments

Adam Parry on 24 Jul 2012

Although I don't have global optimisation toolbox and don't full understand whats going on, it looks like it could be on the right track.

What I would like to know is.

1. Is it possible to change the code so it can work for different data that will have a different V and so may work at Vg < 18. I.e can we ad a statement that confines Vg-V < Vd (Vd = 1 in the data I have provided but could be different for other data)

2. Being useless at statistics etc. How do I go about getting errors on the parameters and on the fit?

Kind Regards

Could you explain the

 Emin = Inf;
 for n = 1:100
    disp(n)
    [Xn, err(n)] = fminsearch(E,X0.*(1+0.01*randn(size(X0))),opts);
    if err(n) < Emin
        Emin = err(n);
        X = Xn;
    end
 end
Teja Muppirala on 24 Jul 2012

Are you using MATLAB R2012a?

Teja Muppirala
Answer by Teja Muppirala on 24 Jul 2012

Ah! Sorry sorry sorry. There's actually a MUCH easier way to make all of this work. The important point is to set the model equal to zero whenever it goes imaginary. I bet your other software probably was doing this automatically; MATLAB does not. See how I modified rcfun below to include this line:

F = F.*(~imag(F));

This sets F to be identically zero whenever it has an imaginary component.

Anyways, copy the entire function below into a file and run it from the command line:

>> [BETA,Rout,J,COVB,MSE] = domyfit

and it will work perfectly (and it should work for other data in general). The standard errors on your coefficients are given by diag(COVB).

function [BETA,Rout,J,COVB,MSE] = domyfit
A = struct;
A.data = [0	3.03E-12
1	1.5E-13
2	1.58E-12
3	2.81E-12
4	2.55E-12
5	2.31E-12
6	4.13E-12
7	2.89E-12
8	4.99E-12
9	6.38E-12
10	1.068E-11
11	1.96E-11
12	5.343E-11
13	5.405E-11
14	5.347E-11
15	5.142E-11
16	2.4139E-10
17	7.4428E-10
18	1.5752E-9
19	2.7328E-9
20	4.3347E-9
21	6.5506E-9
22	9.5258E-9
23	1.31356E-8
24	1.72672E-8
25	2.17876E-8
26	2.66302E-8
27	3.18252E-8
28	3.7101E-8
29	4.23594E-8
30	4.78078E-8
31	5.32604E-8
32	5.86136E-8
33	6.39262E-8
34	6.93234E-8
35	7.47466E-8
36	8.01152E-8
37	8.54398E-8
38	9.08214E-8
39	9.62598E-8
40	1.0184E-7
41	1.074E-7
42	1.1322E-7
43	1.1876E-7
44	1.2432E-7
45	1.299E-7
46	1.3534E-7
47	1.4062E-7
48	1.4596E-7
49	1.5096E-7
50	1.558E-7
51	1.6118E-7
52	1.6616E-7
53	1.7064E-7
54	1.7546E-7
55	1.7946E-7
56	1.8402E-7
57	1.8776E-7
58	1.9138E-7
59	1.9584E-7
60	1.9992E-7];
xdata = A.data(:,1);
ydata = A.data(:,2);
Vg = xdata;
Id = abs(ydata);
X0 = [log10(8.6E-10);1.7;0.8;log10(5E6)];
[BETA,Rout,J,COVB,MSE] = nlinfit(Vg,Id,@rcfun,X0);
K = 8.6E-10; V = 17.3; b = 0.618; R = 2.3E6;
F0 = (((K.*(Vg-V).^(b+1)).^(-1))+R).^(-1);
plot(Vg, Id);hold all; plot(Vg,rcfun(BETA,Vg)); plot(Vg,F0);
function F = rcfun(X,Vg)
F = (((10.^(X(1)).*(Vg-X(2)).^(X(3)+1)).^(-1))+10.^(X(4))).^(-1);
F = F.*(~imag(F));

9 Comments

Star Strider on 24 Jul 2012

I'm going to continue experimenting with GlobalSearch, since your problem is likely the best test for it that I've encountered. The Origin fit didn't give much oscillation in the residuals if I remember correctly.

As for the fit being good enough to use — that's definitely your call! I'm going to see what GlobalSearch comes up with. That's likely as close to a definitive set of parameter estimates as is possible. (I'm not happy with the fits the curve-fitting routines have come up with so far.) They may be the set that Origin estimates, but at least we'll know.

I suggest continuing to use RobustWgtFun and the Jacobian. If you use the Jacobian with ‘lsqcurvefit’, insert this line before you calculate the Jacobian in RcFun:

Vg = Vg';

The MATLAB convention is column-major order, and nlinfit passes column vectors (as I would expect) to its objective functions, so I have no idea why lsqcurvefit passes row vectors. (I figured this out myself by experimenting with it.)

I've successfully estimated equivalent circuit models (to physiological problems) with pF capacitances, mH inductances, and MOhm resistances with MATLAB curve-fitting routines without having problems (although it usually took several guesses of initial parameters to get them to fit), so I doubt parameter magnitude ranges are the problem. My data oscillated so were not as challenging to fit as yours are.

Adam Parry on 24 Jul 2012

I'm quite enjoying this.

What is it you mean by experimeting with GlobalSearch, i assume (by looking into it abit) that it finds global minima in a problem?

Could you use MultiStart?

Also (to Teja in particular) how do you go from log10 parameters to estimating the error in the parameter itself using COVB?? I just cannot work it out

Star Strider on 25 Jul 2012

SUCCESS!

After all that, it came down to the initial conditions, although I also made some changes to ‘RcFun’ to make it work seamlessly with both ‘nlinfit’ and ‘lsqcurvefit’.

The new initial conditions:

x0 = rand(4,1).*[1E-13;  1;  1;  1E+7];  

and the new objective function:

function [F,J] = RdFun(a,Vg)
% Adam Parry’s Organic FET Function
% DATE: 2012 07 23
%
%
%
% F = (((K.*(Vg-V).^(b+1)).^(-1))+R).^(-1)
% 	      w.r.t:             K,     V,     b,     R
%         respectively       a(1),  a(2),  a(3),  a(4)
% x0 = [                 8.6E-10   ;1.7   ;0.8   ;5E6];
if a(2) > Vg
    F = 0;
    return
end
F = a(1)./(a(1).*a(4) + 1./(Vg - a(2)).^(a(3) + 1));
Jfcn = @(a,Vg) [1./(a(1).*a(4) + 1./(Vg - a(2)).^(a(3) + 1)) - (a(1).*a(4))./(a(1).*a(4) + 1./(Vg - a(2)).^(a(3) + 1)).^2;  -(a(1).*(a(3) + 1))./((Vg - a(2)).^(a(3) + 2).*(a(1).*a(4) + 1./(Vg - a(2)).^(a(3) + 1)).^2);  (a(1).*log(Vg - a(2)))./((Vg - a(2)).^(a(3) + 1).*(a(1).*a(4) + 1./(Vg - a(2)).^(a(3) + 1)).^2);  -a(1).^2./(a(1).*a(4) + 1./(Vg - a(2)).^(a(3) + 1)).^2]';
if nargout > 1
    J = Jfcn(a,Vg);
    if any(size(J) == 1)
        J = Jfcn(a,Vg');
    elseif ~any(size(J) == 1)
        return
    end
end
% =========================  END: RcFun.m  =========================

produces the parameters:

	Parameter Estimates:
		K =   3.254448861356919E-10    0.000000000000000E+00j
		V =   1.559046341560319E+01    0.000000000000000E+00j
		b =   9.096959820500091E-01    0.000000000000000E+00j
		R =   2.828879053496115E+06    0.000000000000000E+00j
	Parameter Estimates:
		|K| =   3.254448861356919E-10
		|V| =   1.559046341560319E+01
		|b| =   9.096959820500091E-01
		|R| =   2.828879053496115E+06

and it only took ‘nlinfit’ 2.075 seconds to converge.

However they do not appear to be unique because these produce and equivalently close fit:

	Parameter Estimates:
		K =   6.692378493392830E-10    0.000000000000000E+00j
		V =   1.685567986182001E+01    0.000000000000000E+00j
		b =   6.960550385747625E-01    0.000000000000000E+00j
		R =   2.476857099346900E+06    0.000000000000000E+00j
	Parameter Estimates:
		|K| =   6.692378493392830E-10
		|V| =   1.685567986182001E+01
		|b| =   6.960550385747625E-01
		|R| =   2.476857099346900E+06

as do these:

	Parameter Estimates:
		K =   3.054487171664253E-10    0.000000000000000E+00j
		V =   1.547909799526304E+01    0.000000000000000E+00j
		b =   9.280342803415647E-01    0.000000000000000E+00j
		R =   2.854955008915018E+06    0.000000000000000E+00j
	Parameter Estimates:
		|K| =   3.054487171664253E-10
		|V| =   1.547909799526304E+01
		|b| =   9.280342803415647E-01
		|R| =   2.854955008915018E+06

that produced these 95% confidence intervals:

     137.6613e-012   473.2361e-012
      14.4356e+000    16.5226e+000
     772.1086e-003     1.0840e+000
       2.6426e+006     3.0673e+006

and this covariance matrix:

       8.2089e-021    49.8600e-012    -7.6134e-012    -9.6597e-006
      49.8600e-012   317.5260e-003   -45.6541e-003   -54.6273e+003
      -7.6134e-012   -45.6541e-003     7.0893e-003     9.1732e+003
      -9.6597e-006   -54.6273e+003     9.1732e+003    13.1525e+009

although sometimes it still had a bit of a problem converging. The residuals were reasonably flat with no significant trend, at least in my opinion. I guess that's the result of the ‘rand’ component of the initial parameter guess vector. I'm still going to work on the GlobalSearch, but I feel reasonably confident about these, considering the fit and the residuals. Unfortunately, ‘lsqcurvefit’ consistently failed to find a fit with the same initial parameter guesses. I'll let you know what GlobalSearch comes up with. It may take a few days for me to learn about and successfully run it.

You might want to experiment a bit with it yourself to see what the various parameter estimates look like. That will give you a better idea than even the confidence intervals will about the region of fit.

Teja Muppirala
Answer by Teja Muppirala on 25 Jul 2012

"How do you go from log10 parameters to estimating the error in the parameter itself using COVB??"

It's very easy, you just use the chain rule.

My change of coordinates was y = 10^x

So then dy/dx = 10^x * log(10)

Let A = Covariance in regular coordinates (this is what you want) and B = Covariance in log coordinates (this is what you have)

Then you can find A as

A = 10.^(B) * log(10)

In hindsight, I think this was all a bad idea, and you should just do it without any rescaling, so you don't have to worry about these kinds of things.

17 Comments

Star Strider on 26 Jul 2012

Do you mean ‘other method’ of device fabrication or parameter estimation?

I would be interested in other data to fit, yes.

I finally gave up on GlobalSearch, at least for now. I've since set a two-hour time limit on it. I would have done that earlier but I had no idea it would still be running after 18 hours!

Out of sheer desperation, I asked the Symbolic Math Toolbox to calculate a second-order Taylor series approximation of your function to see if that would make it easier to estimate the parameters, at least initially. The problem is that the Taylor series wants to calculate (-V).^b, guaranteeing a complex result. Here's the Taylor series, formatted by the Symbolic Math Toolbox as an anonymous function:

Taylr_Id = @(K,R,V,Vg,b)K.*(-V).^b.*1.0./(K.*R.*V.*(-V).^b-1.0).^2.*(-V+Vg+Vg.*b+K.*R.*V.^2.*(-V).^b)

that after this substitution: {K V b R}, {'a(1)' 'a(2)' 'a(3)' 'a(4)'} (and apparently some rearranging) becomes:

Taylr_Id = @(a,Vg) (a(1).*(-a(2)).^a(3).*(Vg - a(2) + Vg.*a(3) + a(1).*(-a(2)).^(a(3) + 2).*a(4)))./(a(1).*(-a(2)).^(a(3) + 1).*a(4) + 1).^2

I doubt if it contributes anything of significance to the effort, but so long as I have it I'll send it along for you to experiment with.

Adam Parry on 27 Jul 2012

Yeah there is another method for parameter estimatio, but it involves taking some other measurements, but it may only require fitting straight lines, which would be nice. I'll have to look into it.

In other news I still can't get rid of this error without using log10(parameters). aAnd I still can't figure out how to get the correct errors from them.

Warning: Rank deficient, rank = 2, tol = 2.661976e-08. > In nlinfit>LMfit at 351 In nlinfit>nlrobustfit at 532 In nlinfit at 215 In nlinfitRc at 22

I'm managing to get fits with your code but they never see to give me residuals that are random, and the fits are still a little off in comparison to origin. Am I doing this right?

Star Strider on 27 Jul 2012

The nice thing is that fitting straight lines only require two parameters. However you have four in your model, so I don't see what the advantage is in that unless you can ignore two of them. When I did this just now, I got estimates for R of 195.8839E+006 and for V of 19.9989E+000.

I believe the nature of your data and the nature of your model make fitting your data difficult. The model doesn't really account for the sharp discontinuity where Vg=V, or for the very small oscillations in the Id data, that are likely real although quantitatively unimportant. (When I looked at them on the model I estimated from the parameter sets I posted, the magnitude of the oscillations with the best parameter estimates was about 1% of the value of the function at that point.)

The problem is that taking the logs of the parameters and then reconsituting them in the model changes the model. It's easier to see if instead of using 10.^a(1) and 10.^a(4) you substitute exp(a(1)) and exp(a(4)). That's not the model you specified and it doesn't make any sense in the context of the papers you referred me to, so I am not using the parameter transformation.

A Taylor series approximation might still be the way to go initially to get a good start on the parameter estimates, but you will have to change your data and model to avoid the possiblity of ‘(-V).^p’. Changing ‘(Vg-V)’ to ‘(V-Vg)’ does this, and likely only requires changing the Vg data to -Vg. In the Taylor series I sent along, to make that transformation simply change the signs of ‘V’ (a(2)) and ‘Vg’. I suggest that only for the Taylor approximation in order to get a good initial set of stable parameter estimates.

The parameter estimates I posted earlier are among the best I got. You can plug them in directly and calculate the relevant statistics. There is a small oscillation in the residuals, but it is barely discernable. This set took less than three seconds to converge and produced an MSE = 1.3182E-018:

	Parameter Estimates:
		|K| =   2.627883069159599E-10
		|V| =   1.521501224663270E+01
		|b| =   9.713005068703799E-01
		|R| =   2.914483559512664E+06

I gave up on GlobalSearch because GlobalSearch either didn't find a global minimum or got caught in a loop that required me to either stop or completely exit MATLAB, and so about which it gave me no informaton. It seemed to have the most trouble fitting ‘R’ (it seemed to persisstently underestimate it), but didn't seem to have trouble with the other parameters.

I suggest you go with the parameter estimates that make the most sense and that you are the most comfortable with. I know nothing about Origin, how it decides the region to fit, or how it calculates its parameters, so I can't advise you on what parameter set is best.

I'll be glad to continue to provide what help I can.

Teja Muppirala
Answer by Adam Parry on 30 Jul 2012

Hi

Long time

To be honest. I think that I am just about understanding the statistical things that you are doing in order to get a good fit. But my main problem is actually writing the code that does the same job as yours is doing. I am still unable to get lsqcurvefit to work with Jacobian on and nlin fit still gives me Rank deficient warnings. The main problem that I have though is that no matter waht initial parameters I start with R does not change. You mentioned a similar thing you noticed with R above and I just wonder how I can overcome it?

I know this is not exactly what you want to do, but could you walk me through the code. I can show you what I've got so far if that helps?

Thank you

24 Comments

Adam Parry on 3 Aug 2012

Ok, thats fine, do you know anyway that Matlab could work out for itself when not to take into account data?

Like if I test a device that has a threshold voltage (V) around 0.5, i'm going to want most of the data up until 0 aren't I?

Adam Parry on 3 Aug 2012

This is going to be a bit cheeky, but could you tell me if this jacobian is right, I'm getting an error telling me it is the wrong size

F = (a(1).*((VgX-a(2)).^(a(3)+1)));
J = [(VgX-a(2)).^(a(3)+1),...
  -(a(1).*((VgX-a(2)).^a(3)).*(a(3)+1)),...
  a(1).*log(VgX-a(2)).*((VgX-a(2)).^(a(3)+1))];
Star Strider on 3 Aug 2012

I don't know how MATLAB routines could decide for themselves what part of the data to use. I have no idea how Origin managed to fit your function as well as it did and only over the linear region of fit that produced real parameters, assuming you gave it and MATLAB the same function and data.

I don't know the data you're commenting on. Since I know only the data from the present problem, I suggest you start the fit with the greatest ‘Id’ data, take a range of those data, do the fit, and estimate ‘V’. Then take the data greater than the estimated ‘V’ and fit all of it. If your parameters are linear functions of your data (as ‘K’ and ‘R’ were here), and if your ‘Id’ data are again on the order of 1E-7, you can scale the ‘Id’ data and then ‘un-scale’ ‘K’ and ‘R’ by the same factor. Since ‘V’ and ‘b’ are not linear functions of either variable, you have to fit them as they are. So you can't scale ‘Vg’.

Your Jacobian looks fine to me. The Optimization and Statistics Toolboxes use different conventions — Statistics uses column-major, Optimization row-major — so to get your Jacobian to work with both, you have to transpose your ‘VgX’ vector to use the Optimization functions. If your data are column vectors, the Jacobian as listed should work with Statistics Toolbox functions, but you'll have to transpose the ‘VgX’ vector to make it work with Optimization Toolbox functions. Take the ‘RcFun.m’ I sent you, rename it to your present problem, then paste your ‘F’ and ‘J’ functions in it in place of the ones I provided. It should work fine. Note that my variable ‘Jcbn’ is an anonymous function, so be sure to paste your ‘J’ expression there and change the argument from ‘Vg’ to ‘VgX’.

That should work.

Adam Parry

Contact us